blob: 9ad628bfdde74a67e7d8f9dba499e7c400200c4a [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
Gulsum Aticibb0b7b92023-02-13 21:45:08 +0300939 Return a dict with the fields at filter_dict (see get_network_list) plus some VIM specific>}, ...]
940 """
bayramovef390722016-09-27 03:34:46 -0700941 try:
beierlb22ce2d2019-12-12 12:09:51 -0500942 _, vdc = self.get_vdc_details()
sousaedu80135b92021-02-17 15:05:18 +0100943 vdc_id = vdc.get("id").split(":")[3]
944
kasarc5bf2932018-03-09 04:15:22 -0800945 if self.client._session:
sousaedu80135b92021-02-17 15:05:18 +0100946 headers = {
947 "Accept": "application/*+xml;version=" + API_VERSION,
948 "x-vcloud-authorization": self.client._session.headers[
949 "x-vcloud-authorization"
950 ],
951 }
952 response = self.perform_request(
953 req_type="GET", url=vdc.get("href"), headers=headers
954 )
955
kasarc5bf2932018-03-09 04:15:22 -0800956 if response.status_code != 200:
957 self.logger.error("Failed to get vdc content")
tierno72774862020-05-04 11:44:15 +0000958 raise vimconn.VimConnNotFoundException("Failed to get vdc content")
kasarc5bf2932018-03-09 04:15:22 -0800959 else:
beierl26fec002019-12-06 17:06:40 -0500960 content = XmlElementTree.fromstring(response.text)
bhangarebfdca492017-03-11 01:32:46 -0800961
bhangarebfdca492017-03-11 01:32:46 -0800962 filter_dict = {}
963
kasarc5bf2932018-03-09 04:15:22 -0800964 for item in content:
sousaedu80135b92021-02-17 15:05:18 +0100965 if item.tag.split("}")[-1] == "AvailableNetworks":
kasarc5bf2932018-03-09 04:15:22 -0800966 for net in item:
sousaedu80135b92021-02-17 15:05:18 +0100967 response = self.perform_request(
968 req_type="GET", url=net.get("href"), headers=headers
969 )
kasarc30a04e2017-08-24 05:58:18 -0700970
kasarc5bf2932018-03-09 04:15:22 -0800971 if response.status_code != 200:
972 self.logger.error("Failed to get network content")
sousaedu80135b92021-02-17 15:05:18 +0100973 raise vimconn.VimConnNotFoundException(
974 "Failed to get network content"
975 )
kasarc5bf2932018-03-09 04:15:22 -0800976 else:
beierl26fec002019-12-06 17:06:40 -0500977 net_details = XmlElementTree.fromstring(response.text)
kasarc5bf2932018-03-09 04:15:22 -0800978
sousaedu80135b92021-02-17 15:05:18 +0100979 vdc_network_id = net_details.get("id").split(":")
kasarc5bf2932018-03-09 04:15:22 -0800980 if len(vdc_network_id) == 4 and vdc_network_id[3] == net_id:
sousaedu80135b92021-02-17 15:05:18 +0100981 filter_dict["name"] = net_details.get("name")
kasarc5bf2932018-03-09 04:15:22 -0800982 filter_dict["id"] = vdc_network_id[3]
sousaedu80135b92021-02-17 15:05:18 +0100983
984 if [
985 i.text
986 for i in net_details
987 if i.tag.split("}")[-1] == "IsShared"
988 ][0] == "true":
kasarc5bf2932018-03-09 04:15:22 -0800989 shared = True
990 else:
991 shared = False
sousaedu80135b92021-02-17 15:05:18 +0100992
kasarc5bf2932018-03-09 04:15:22 -0800993 filter_dict["shared"] = shared
994 filter_dict["tenant_id"] = vdc_id
sousaedu80135b92021-02-17 15:05:18 +0100995
996 if int(net_details.get("status")) == 1:
kasarc5bf2932018-03-09 04:15:22 -0800997 filter_dict["admin_state_up"] = True
998 else:
999 filter_dict["admin_state_up"] = False
sousaedu80135b92021-02-17 15:05:18 +01001000
kasarc5bf2932018-03-09 04:15:22 -08001001 filter_dict["status"] = "ACTIVE"
1002 filter_dict["type"] = "bridge"
1003 self.logger.debug("Returning {}".format(filter_dict))
sousaedu80135b92021-02-17 15:05:18 +01001004
kasarc5bf2932018-03-09 04:15:22 -08001005 return filter_dict
bayramovef390722016-09-27 03:34:46 -07001006 else:
sousaedu80135b92021-02-17 15:05:18 +01001007 raise vimconn.VimConnNotFoundException(
1008 "Network {} not found".format(net_id)
1009 )
kasarc30a04e2017-08-24 05:58:18 -07001010 except Exception as e:
bayramovef390722016-09-27 03:34:46 -07001011 self.logger.debug("Error in get_network")
1012 self.logger.debug(traceback.format_exc())
sousaedu80135b92021-02-17 15:05:18 +01001013
tierno72774862020-05-04 11:44:15 +00001014 if isinstance(e, vimconn.VimConnException):
kasarc30a04e2017-08-24 05:58:18 -07001015 raise
1016 else:
sousaedu80135b92021-02-17 15:05:18 +01001017 raise vimconn.VimConnNotFoundException(
1018 "Failed : Network not found {} ".format(e)
1019 )
bayramovef390722016-09-27 03:34:46 -07001020
1021 return filter_dict
bayramov325fa1c2016-09-08 01:42:46 -07001022
garciadeblasebd66722019-01-31 16:01:31 +00001023 def delete_network(self, net_id, created_items=None):
bayramovef390722016-09-27 03:34:46 -07001024 """
garciadeblasebd66722019-01-31 16:01:31 +00001025 Removes a tenant network from VIM and its associated elements
1026 :param net_id: VIM identifier of the network, provided by method new_network
1027 :param created_items: dictionary with extra items to be deleted. provided by method new_network
1028 Returns the network identifier or raises an exception upon error or when network is not found
bayramovef390722016-09-27 03:34:46 -07001029 """
1030
kateac1e3792017-04-01 02:16:39 -07001031 # ############# Stub code for SRIOV #################
sousaedu80135b92021-02-17 15:05:18 +01001032 # dvport_group = self.get_dvport_group(net_id)
1033 # if dvport_group:
1034 # #delete portgroup
1035 # status = self.destroy_dvport_group(net_id)
1036 # if status:
1037 # # Remove vlanID from persistent info
1038 # if net_id in self.persistent_info["used_vlanIDs"]:
1039 # del self.persistent_info["used_vlanIDs"][net_id]
1040 #
1041 # return net_id
kateac1e3792017-04-01 02:16:39 -07001042
bayramovfe3f3c92016-10-04 07:53:41 +04001043 vcd_network = self.get_vcd_network(network_uuid=net_id)
1044 if vcd_network is not None and vcd_network:
1045 if self.delete_network_action(network_uuid=net_id):
1046 return net_id
bayramovef390722016-09-27 03:34:46 -07001047 else:
sousaedu80135b92021-02-17 15:05:18 +01001048 raise vimconn.VimConnNotFoundException(
1049 "Network {} not found".format(net_id)
1050 )
bayramov325fa1c2016-09-08 01:42:46 -07001051
1052 def refresh_nets_status(self, net_list):
bayramovbd6160f2016-09-28 04:12:05 +04001053 """Get the status of the networks
sousaedu80135b92021-02-17 15:05:18 +01001054 Params: the list of network identifiers
1055 Returns a dictionary with:
1056 net_id: #VIM id of this network
1057 status: #Mandatory. Text with one of:
1058 # DELETED (not found at vim)
1059 # VIM_ERROR (Cannot connect to VIM, VIM response error, ...)
1060 # OTHER (Vim reported other status not understood)
1061 # ERROR (VIM indicates an ERROR status)
1062 # ACTIVE, INACTIVE, DOWN (admin down),
1063 # BUILD (on building process)
1064 #
1065 error_msg: #Text with VIM error message, if any. Or the VIM connection ERROR
1066 vim_info: #Text with plain information obtained from vim (yaml.safe_dump)
bayramov325fa1c2016-09-08 01:42:46 -07001067
bayramovbd6160f2016-09-28 04:12:05 +04001068 """
bayramovef390722016-09-27 03:34:46 -07001069 dict_entry = {}
1070 try:
1071 for net in net_list:
sousaedu80135b92021-02-17 15:05:18 +01001072 errormsg = ""
bayramovef390722016-09-27 03:34:46 -07001073 vcd_network = self.get_vcd_network(network_uuid=net)
bayramovfe3f3c92016-10-04 07:53:41 +04001074 if vcd_network is not None and vcd_network:
sousaedu80135b92021-02-17 15:05:18 +01001075 if vcd_network["status"] == "1":
1076 status = "ACTIVE"
bayramovef390722016-09-27 03:34:46 -07001077 else:
sousaedu80135b92021-02-17 15:05:18 +01001078 status = "DOWN"
bayramovef390722016-09-27 03:34:46 -07001079 else:
sousaedu80135b92021-02-17 15:05:18 +01001080 status = "DELETED"
1081 errormsg = "Network not found."
bayramovfe3f3c92016-10-04 07:53:41 +04001082
sousaedu80135b92021-02-17 15:05:18 +01001083 dict_entry[net] = {
1084 "status": status,
1085 "error_msg": errormsg,
1086 "vim_info": yaml.safe_dump(vcd_network),
1087 }
beierlb22ce2d2019-12-12 12:09:51 -05001088 except Exception:
bayramovef390722016-09-27 03:34:46 -07001089 self.logger.debug("Error in refresh_nets_status")
1090 self.logger.debug(traceback.format_exc())
1091
1092 return dict_entry
1093
bayramovbd6160f2016-09-28 04:12:05 +04001094 def get_flavor(self, flavor_id):
bayramovef390722016-09-27 03:34:46 -07001095 """Obtain flavor details from the VIM
sousaedu80135b92021-02-17 15:05:18 +01001096 Returns the flavor dict details {'id':<>, 'name':<>, other vim specific } #TODO to concrete
bayramovef390722016-09-27 03:34:46 -07001097 """
kateeb044522017-03-06 23:54:39 -08001098 if flavor_id not in vimconnector.flavorlist:
tierno72774862020-05-04 11:44:15 +00001099 raise vimconn.VimConnNotFoundException("Flavor not found.")
sousaedu80135b92021-02-17 15:05:18 +01001100
kateeb044522017-03-06 23:54:39 -08001101 return vimconnector.flavorlist[flavor_id]
bayramov325fa1c2016-09-08 01:42:46 -07001102
1103 def new_flavor(self, flavor_data):
bayramovef390722016-09-27 03:34:46 -07001104 """Adds a tenant flavor to VIM
bayramov325fa1c2016-09-08 01:42:46 -07001105 flavor_data contains a dictionary with information, keys:
1106 name: flavor name
1107 ram: memory (cloud type) in MBytes
1108 vpcus: cpus (cloud type)
1109 extended: EPA parameters
1110 - numas: #items requested in same NUMA
1111 memory: number of 1G huge pages memory
beierlb22ce2d2019-12-12 12:09:51 -05001112 paired-threads|cores|threads: number of paired hyperthreads, complete cores OR individual
1113 threads
bayramov325fa1c2016-09-08 01:42:46 -07001114 interfaces: # passthrough(PT) or SRIOV interfaces attached to this numa
1115 - name: interface name
1116 dedicated: yes|no|yes:sriov; for PT, SRIOV or only one SRIOV for the physical NIC
1117 bandwidth: X Gbps; requested guarantee bandwidth
bayramovef390722016-09-27 03:34:46 -07001118 vpci: requested virtual PCI address
bayramov325fa1c2016-09-08 01:42:46 -07001119 disk: disk size
1120 is_public:
bayramov325fa1c2016-09-08 01:42:46 -07001121 #TODO to concrete
bayramovef390722016-09-27 03:34:46 -07001122 Returns the flavor identifier"""
bayramov325fa1c2016-09-08 01:42:46 -07001123
bayramovef390722016-09-27 03:34:46 -07001124 # generate a new uuid put to internal dict and return it.
bhangarea92ae392017-01-12 22:30:29 -08001125 self.logger.debug("Creating new flavor - flavor_data: {}".format(flavor_data))
beierlb22ce2d2019-12-12 12:09:51 -05001126 new_flavor = flavor_data
bhangarea92ae392017-01-12 22:30:29 -08001127 ram = flavor_data.get(FLAVOR_RAM_KEY, 1024)
1128 cpu = flavor_data.get(FLAVOR_VCPUS_KEY, 1)
garciadeblas79d1a1a2017-12-11 16:07:07 +01001129 disk = flavor_data.get(FLAVOR_DISK_KEY, 0)
bhangarea92ae392017-01-12 22:30:29 -08001130
kasarfeaaa052017-06-08 03:46:18 -07001131 if not isinstance(ram, int):
tierno72774862020-05-04 11:44:15 +00001132 raise vimconn.VimConnException("Non-integer value for ram")
kasarfeaaa052017-06-08 03:46:18 -07001133 elif not isinstance(cpu, int):
tierno72774862020-05-04 11:44:15 +00001134 raise vimconn.VimConnException("Non-integer value for cpu")
kasarfeaaa052017-06-08 03:46:18 -07001135 elif not isinstance(disk, int):
tierno72774862020-05-04 11:44:15 +00001136 raise vimconn.VimConnException("Non-integer value for disk")
kasarfeaaa052017-06-08 03:46:18 -07001137
bhangarea92ae392017-01-12 22:30:29 -08001138 extended_flv = flavor_data.get("extended")
1139 if extended_flv:
beierlb22ce2d2019-12-12 12:09:51 -05001140 numas = extended_flv.get("numas")
bhangarea92ae392017-01-12 22:30:29 -08001141 if numas:
1142 for numa in numas:
beierlb22ce2d2019-12-12 12:09:51 -05001143 # overwrite ram and vcpus
sousaedu80135b92021-02-17 15:05:18 +01001144 if "memory" in numa:
1145 ram = numa["memory"] * 1024
1146
1147 if "paired-threads" in numa:
1148 cpu = numa["paired-threads"] * 2
1149 elif "cores" in numa:
1150 cpu = numa["cores"]
1151 elif "threads" in numa:
1152 cpu = numa["threads"]
bhangarea92ae392017-01-12 22:30:29 -08001153
1154 new_flavor[FLAVOR_RAM_KEY] = ram
1155 new_flavor[FLAVOR_VCPUS_KEY] = cpu
1156 new_flavor[FLAVOR_DISK_KEY] = disk
1157 # generate a new uuid put to internal dict and return it.
bayramovef390722016-09-27 03:34:46 -07001158 flavor_id = uuid.uuid4()
kateeb044522017-03-06 23:54:39 -08001159 vimconnector.flavorlist[str(flavor_id)] = new_flavor
bhangarea92ae392017-01-12 22:30:29 -08001160 self.logger.debug("Created flavor - {} : {}".format(flavor_id, new_flavor))
bayramov325fa1c2016-09-08 01:42:46 -07001161
bayramovef390722016-09-27 03:34:46 -07001162 return str(flavor_id)
bayramov325fa1c2016-09-08 01:42:46 -07001163
1164 def delete_flavor(self, flavor_id):
bayramovef390722016-09-27 03:34:46 -07001165 """Deletes a tenant flavor from VIM identify by its id
bayramov325fa1c2016-09-08 01:42:46 -07001166
sousaedu80135b92021-02-17 15:05:18 +01001167 Returns the used id or raise an exception
bayramovef390722016-09-27 03:34:46 -07001168 """
kateeb044522017-03-06 23:54:39 -08001169 if flavor_id not in vimconnector.flavorlist:
tierno72774862020-05-04 11:44:15 +00001170 raise vimconn.VimConnNotFoundException("Flavor not found.")
bayramovef390722016-09-27 03:34:46 -07001171
kateeb044522017-03-06 23:54:39 -08001172 vimconnector.flavorlist.pop(flavor_id, None)
sousaedu80135b92021-02-17 15:05:18 +01001173
bayramovef390722016-09-27 03:34:46 -07001174 return flavor_id
1175
1176 def new_image(self, image_dict):
bayramov5761ad12016-10-04 09:00:30 +04001177 """
bayramov325fa1c2016-09-08 01:42:46 -07001178 Adds a tenant image to VIM
1179 Returns:
1180 200, image-id if the image is created
1181 <0, message if there is an error
bayramov5761ad12016-10-04 09:00:30 +04001182 """
sousaedu80135b92021-02-17 15:05:18 +01001183 return self.get_image_id_from_path(image_dict["location"])
bayramov325fa1c2016-09-08 01:42:46 -07001184
1185 def delete_image(self, image_id):
bayramovfe3f3c92016-10-04 07:53:41 +04001186 """
sousaedu80135b92021-02-17 15:05:18 +01001187 Deletes a tenant image from VIM
1188 Args:
1189 image_id is ID of Image to be deleted
1190 Return:
1191 returns the image identifier in UUID format or raises an exception on error
bayramovfe3f3c92016-10-04 07:53:41 +04001192 """
kasarc5bf2932018-03-09 04:15:22 -08001193 conn = self.connect_as_admin()
sousaedu80135b92021-02-17 15:05:18 +01001194
kasarc5bf2932018-03-09 04:15:22 -08001195 if not conn:
tierno72774862020-05-04 11:44:15 +00001196 raise vimconn.VimConnConnectionException("Failed to connect vCD")
sousaedu80135b92021-02-17 15:05:18 +01001197
kated47ad5f2017-08-03 02:16:13 -07001198 # Get Catalog details
sousaedu80135b92021-02-17 15:05:18 +01001199 url_list = [self.url, "/api/catalog/", image_id]
1200 catalog_herf = "".join(url_list)
kasarc5bf2932018-03-09 04:15:22 -08001201
sousaedu80135b92021-02-17 15:05:18 +01001202 headers = {
1203 "Accept": "application/*+xml;version=" + API_VERSION,
1204 "x-vcloud-authorization": conn._session.headers["x-vcloud-authorization"],
1205 }
kasarc5bf2932018-03-09 04:15:22 -08001206
sousaedu80135b92021-02-17 15:05:18 +01001207 response = self.perform_request(
1208 req_type="GET", url=catalog_herf, headers=headers
1209 )
bayramovfe3f3c92016-10-04 07:53:41 +04001210
kated47ad5f2017-08-03 02:16:13 -07001211 if response.status_code != requests.codes.ok:
sousaedu80135b92021-02-17 15:05:18 +01001212 self.logger.debug(
1213 "delete_image():GET REST API call {} failed. "
1214 "Return status code {}".format(catalog_herf, response.status_code)
1215 )
1216
1217 raise vimconn.VimConnNotFoundException(
1218 "Fail to get image {}".format(image_id)
1219 )
kated47ad5f2017-08-03 02:16:13 -07001220
beierl01bd6692019-12-09 17:06:20 -05001221 lxmlroot_respond = lxmlElementTree.fromstring(response.content)
sousaedu80135b92021-02-17 15:05:18 +01001222 namespaces = {
1223 prefix: uri for prefix, uri in lxmlroot_respond.nsmap.items() if prefix
1224 }
beierl01bd6692019-12-09 17:06:20 -05001225 namespaces["xmlns"] = "http://www.vmware.com/vcloud/v1.5"
kated47ad5f2017-08-03 02:16:13 -07001226
beierl01bd6692019-12-09 17:06:20 -05001227 catalogItems_section = lxmlroot_respond.find("xmlns:CatalogItems", namespaces)
1228 catalogItems = catalogItems_section.iterfind("xmlns:CatalogItem", namespaces)
kated47ad5f2017-08-03 02:16:13 -07001229
sousaedu80135b92021-02-17 15:05:18 +01001230 for catalogItem in catalogItems:
1231 catalogItem_href = catalogItem.attrib["href"]
1232
1233 response = self.perform_request(
1234 req_type="GET", url=catalogItem_href, headers=headers
1235 )
kated47ad5f2017-08-03 02:16:13 -07001236
1237 if response.status_code != requests.codes.ok:
sousaedu80135b92021-02-17 15:05:18 +01001238 self.logger.debug(
1239 "delete_image():GET REST API call {} failed. "
1240 "Return status code {}".format(catalog_herf, response.status_code)
1241 )
1242 raise vimconn.VimConnNotFoundException(
1243 "Fail to get catalogItem {} for catalog {}".format(
1244 catalogItem, image_id
1245 )
1246 )
kated47ad5f2017-08-03 02:16:13 -07001247
beierl01bd6692019-12-09 17:06:20 -05001248 lxmlroot_respond = lxmlElementTree.fromstring(response.content)
sousaedu80135b92021-02-17 15:05:18 +01001249 namespaces = {
1250 prefix: uri for prefix, uri in lxmlroot_respond.nsmap.items() if prefix
1251 }
beierl01bd6692019-12-09 17:06:20 -05001252 namespaces["xmlns"] = "http://www.vmware.com/vcloud/v1.5"
sousaedu80135b92021-02-17 15:05:18 +01001253 catalogitem_remove_href = lxmlroot_respond.find(
1254 "xmlns:Link[@rel='remove']", namespaces
1255 ).attrib["href"]
kated47ad5f2017-08-03 02:16:13 -07001256
beierl01bd6692019-12-09 17:06:20 -05001257 # Remove catalogItem
sousaedu80135b92021-02-17 15:05:18 +01001258 response = self.perform_request(
1259 req_type="DELETE", url=catalogitem_remove_href, headers=headers
1260 )
1261
kated47ad5f2017-08-03 02:16:13 -07001262 if response.status_code == requests.codes.no_content:
1263 self.logger.debug("Deleted Catalog item {}".format(catalogItem))
1264 else:
sousaedu80135b92021-02-17 15:05:18 +01001265 raise vimconn.VimConnException(
1266 "Fail to delete Catalog Item {}".format(catalogItem)
1267 )
kated47ad5f2017-08-03 02:16:13 -07001268
beierl01bd6692019-12-09 17:06:20 -05001269 # Remove catalog
sousaedu80135b92021-02-17 15:05:18 +01001270 url_list = [self.url, "/api/admin/catalog/", image_id]
1271 catalog_remove_herf = "".join(url_list)
1272 response = self.perform_request(
1273 req_type="DELETE", url=catalog_remove_herf, headers=headers
1274 )
kated47ad5f2017-08-03 02:16:13 -07001275
1276 if response.status_code == requests.codes.no_content:
1277 self.logger.debug("Deleted Catalog {}".format(image_id))
sousaedu80135b92021-02-17 15:05:18 +01001278
kated47ad5f2017-08-03 02:16:13 -07001279 return image_id
1280 else:
tierno72774862020-05-04 11:44:15 +00001281 raise vimconn.VimConnException("Fail to delete Catalog {}".format(image_id))
kated47ad5f2017-08-03 02:16:13 -07001282
bayramov325fa1c2016-09-08 01:42:46 -07001283 def catalog_exists(self, catalog_name, catalogs):
bayramovfe3f3c92016-10-04 07:53:41 +04001284 """
1285
1286 :param catalog_name:
1287 :param catalogs:
1288 :return:
1289 """
bayramov325fa1c2016-09-08 01:42:46 -07001290 for catalog in catalogs:
sousaedu80135b92021-02-17 15:05:18 +01001291 if catalog["name"] == catalog_name:
1292 return catalog["id"]
bayramov325fa1c2016-09-08 01:42:46 -07001293
bayramovb6ffe792016-09-28 11:50:56 +04001294 def create_vimcatalog(self, vca=None, catalog_name=None):
sousaedu80135b92021-02-17 15:05:18 +01001295 """Create new catalog entry in vCloud director.
bayramovb6ffe792016-09-28 11:50:56 +04001296
sousaedu80135b92021-02-17 15:05:18 +01001297 Args
1298 vca: vCloud director.
1299 catalog_name catalog that client wish to create. Note no validation done for a name.
1300 Client must make sure that provide valid string representation.
bayramovb6ffe792016-09-28 11:50:56 +04001301
sousaedu80135b92021-02-17 15:05:18 +01001302 Returns catalog id if catalog created else None.
bayramovb6ffe792016-09-28 11:50:56 +04001303
1304 """
1305 try:
Ananda Baitharu319c26f2019-03-05 17:34:31 +00001306 lxml_catalog_element = vca.create_catalog(catalog_name, catalog_name)
sousaedu80135b92021-02-17 15:05:18 +01001307
Ananda Baitharu319c26f2019-03-05 17:34:31 +00001308 if lxml_catalog_element:
sousaedu80135b92021-02-17 15:05:18 +01001309 id_attr_value = lxml_catalog_element.get("id")
1310 return id_attr_value.split(":")[-1]
1311
kasarc5bf2932018-03-09 04:15:22 -08001312 catalogs = vca.list_catalogs()
Ananda Baitharu319c26f2019-03-05 17:34:31 +00001313 except Exception as ex:
1314 self.logger.error(
sousaedu80135b92021-02-17 15:05:18 +01001315 'create_vimcatalog(): Creation of catalog "{}" failed with error: {}'.format(
1316 catalog_name, ex
1317 )
1318 )
Ananda Baitharu319c26f2019-03-05 17:34:31 +00001319 raise
bayramov325fa1c2016-09-08 01:42:46 -07001320 return self.catalog_exists(catalog_name, catalogs)
1321
bayramov5761ad12016-10-04 09:00:30 +04001322 # noinspection PyIncorrectDocstring
sousaedu80135b92021-02-17 15:05:18 +01001323 def upload_ovf(
1324 self,
1325 vca=None,
1326 catalog_name=None,
1327 image_name=None,
1328 media_file_name=None,
1329 description="",
1330 progress=False,
1331 chunk_bytes=128 * 1024,
1332 ):
bayramov325fa1c2016-09-08 01:42:46 -07001333 """
1334 Uploads a OVF file to a vCloud catalog
1335
bayramov5761ad12016-10-04 09:00:30 +04001336 :param chunk_bytes:
1337 :param progress:
1338 :param description:
1339 :param image_name:
1340 :param vca:
bayramov325fa1c2016-09-08 01:42:46 -07001341 :param catalog_name: (str): The name of the catalog to upload the media.
bayramov325fa1c2016-09-08 01:42:46 -07001342 :param media_file_name: (str): The name of the local media file to upload.
1343 :return: (bool) True if the media file was successfully uploaded, false otherwise.
1344 """
1345 os.path.isfile(media_file_name)
1346 statinfo = os.stat(media_file_name)
bayramov325fa1c2016-09-08 01:42:46 -07001347
1348 # find a catalog entry where we upload OVF.
1349 # create vApp Template and check the status if vCD able to read OVF it will respond with appropirate
1350 # status change.
1351 # if VCD can parse OVF we upload VMDK file
bhangarebfdca492017-03-11 01:32:46 -08001352 try:
kasarc5bf2932018-03-09 04:15:22 -08001353 for catalog in vca.list_catalogs():
sousaedu80135b92021-02-17 15:05:18 +01001354 if catalog_name != catalog["name"]:
bhangarebfdca492017-03-11 01:32:46 -08001355 continue
sousaedu80135b92021-02-17 15:05:18 +01001356 catalog_href = "{}/api/catalog/{}/action/upload".format(
1357 self.url, catalog["id"]
1358 )
bhangarebfdca492017-03-11 01:32:46 -08001359 data = """
beierlb22ce2d2019-12-12 12:09:51 -05001360 <UploadVAppTemplateParams name="{}"
1361 xmlns="http://www.vmware.com/vcloud/v1.5"
1362 xmlns:ovf="http://schemas.dmtf.org/ovf/envelope/1">
1363 <Description>{} vApp Template</Description>
1364 </UploadVAppTemplateParams>
sousaedu80135b92021-02-17 15:05:18 +01001365 """.format(
1366 catalog_name, description
1367 )
kasarc5bf2932018-03-09 04:15:22 -08001368
1369 if self.client:
sousaedu80135b92021-02-17 15:05:18 +01001370 headers = {
1371 "Accept": "application/*+xml;version=" + API_VERSION,
1372 "x-vcloud-authorization": self.client._session.headers[
1373 "x-vcloud-authorization"
1374 ],
1375 }
1376 headers[
1377 "Content-Type"
1378 ] = "application/vnd.vmware.vcloud.uploadVAppTemplateParams+xml"
kasarc5bf2932018-03-09 04:15:22 -08001379
sousaedu80135b92021-02-17 15:05:18 +01001380 response = self.perform_request(
1381 req_type="POST", url=catalog_href, headers=headers, data=data
1382 )
kasarc5bf2932018-03-09 04:15:22 -08001383
bhangarebfdca492017-03-11 01:32:46 -08001384 if response.status_code == requests.codes.created:
beierl26fec002019-12-06 17:06:40 -05001385 catalogItem = XmlElementTree.fromstring(response.text)
sousaedu80135b92021-02-17 15:05:18 +01001386 entity = [
1387 child
1388 for child in catalogItem
1389 if child.get("type")
1390 == "application/vnd.vmware.vcloud.vAppTemplate+xml"
1391 ][0]
1392 href = entity.get("href")
bhangarebfdca492017-03-11 01:32:46 -08001393 template = href
kasarc5bf2932018-03-09 04:15:22 -08001394
sousaedu80135b92021-02-17 15:05:18 +01001395 response = self.perform_request(
1396 req_type="GET", url=href, headers=headers
1397 )
bhangarebfdca492017-03-11 01:32:46 -08001398
1399 if response.status_code == requests.codes.ok:
sousaedu80135b92021-02-17 15:05:18 +01001400 headers["Content-Type"] = "Content-Type text/xml"
1401 result = re.search(
1402 'rel="upload:default"\shref="(.*?\/descriptor.ovf)"',
1403 response.text,
1404 )
1405
kasarc5bf2932018-03-09 04:15:22 -08001406 if result:
1407 transfer_href = result.group(1)
1408
sousaedu80135b92021-02-17 15:05:18 +01001409 response = self.perform_request(
1410 req_type="PUT",
1411 url=transfer_href,
1412 headers=headers,
1413 data=open(media_file_name, "rb"),
1414 )
1415
bhangarebfdca492017-03-11 01:32:46 -08001416 if response.status_code != requests.codes.ok:
1417 self.logger.debug(
sousaedu80135b92021-02-17 15:05:18 +01001418 "Failed create vApp template for catalog name {} and image {}".format(
1419 catalog_name, media_file_name
1420 )
1421 )
bhangarebfdca492017-03-11 01:32:46 -08001422 return False
1423
1424 # TODO fix this with aync block
1425 time.sleep(5)
1426
sousaedu80135b92021-02-17 15:05:18 +01001427 self.logger.debug(
1428 "vApp template for catalog name {} and image {}".format(
1429 catalog_name, media_file_name
1430 )
1431 )
bhangarebfdca492017-03-11 01:32:46 -08001432
1433 # uploading VMDK file
1434 # check status of OVF upload and upload remaining files.
sousaedu80135b92021-02-17 15:05:18 +01001435 response = self.perform_request(
1436 req_type="GET", url=template, headers=headers
1437 )
bhangarebfdca492017-03-11 01:32:46 -08001438
1439 if response.status_code == requests.codes.ok:
sousaedu80135b92021-02-17 15:05:18 +01001440 result = re.search(
1441 'rel="upload:default"\s*href="(.*?vmdk)"', response.text
1442 )
1443
kasarc5bf2932018-03-09 04:15:22 -08001444 if result:
1445 link_href = result.group(1)
sousaedu80135b92021-02-17 15:05:18 +01001446
kasarc5bf2932018-03-09 04:15:22 -08001447 # we skip ovf since it already uploaded.
sousaedu80135b92021-02-17 15:05:18 +01001448 if "ovf" in link_href:
kasarc5bf2932018-03-09 04:15:22 -08001449 continue
sousaedu80135b92021-02-17 15:05:18 +01001450
kasarc5bf2932018-03-09 04:15:22 -08001451 # The OVF file and VMDK must be in a same directory
beierlb22ce2d2019-12-12 12:09:51 -05001452 head, _ = os.path.split(media_file_name)
sousaedu80135b92021-02-17 15:05:18 +01001453 file_vmdk = head + "/" + link_href.split("/")[-1]
1454
kasarc5bf2932018-03-09 04:15:22 -08001455 if not os.path.isfile(file_vmdk):
1456 return False
sousaedu80135b92021-02-17 15:05:18 +01001457
kasarc5bf2932018-03-09 04:15:22 -08001458 statinfo = os.stat(file_vmdk)
1459 if statinfo.st_size == 0:
1460 return False
sousaedu80135b92021-02-17 15:05:18 +01001461
kasarc5bf2932018-03-09 04:15:22 -08001462 hrefvmdk = link_href
1463
1464 if progress:
sousaedu80135b92021-02-17 15:05:18 +01001465 widgets = [
1466 "Uploading file: ",
1467 Percentage(),
1468 " ",
1469 Bar(),
1470 " ",
1471 ETA(),
1472 " ",
1473 FileTransferSpeed(),
1474 ]
1475 progress_bar = ProgressBar(
1476 widgets=widgets, maxval=statinfo.st_size
1477 ).start()
kasarc5bf2932018-03-09 04:15:22 -08001478
1479 bytes_transferred = 0
sousaedu80135b92021-02-17 15:05:18 +01001480 f = open(file_vmdk, "rb")
1481
kasarc5bf2932018-03-09 04:15:22 -08001482 while bytes_transferred < statinfo.st_size:
1483 my_bytes = f.read(chunk_bytes)
1484 if len(my_bytes) <= chunk_bytes:
sousaedu80135b92021-02-17 15:05:18 +01001485 headers["Content-Range"] = "bytes {}-{}/{}".format(
1486 bytes_transferred,
1487 len(my_bytes) - 1,
1488 statinfo.st_size,
1489 )
1490 headers["Content-Length"] = str(len(my_bytes))
1491 response = requests.put(
1492 url=hrefvmdk,
1493 headers=headers,
1494 data=my_bytes,
1495 verify=False,
1496 )
1497
kasarc5bf2932018-03-09 04:15:22 -08001498 if response.status_code == requests.codes.ok:
1499 bytes_transferred += len(my_bytes)
1500 if progress:
1501 progress_bar.update(bytes_transferred)
1502 else:
1503 self.logger.debug(
sousaedu80135b92021-02-17 15:05:18 +01001504 "file upload failed with error: [{}] {}".format(
1505 response.status_code, response.text
1506 )
1507 )
kasarc5bf2932018-03-09 04:15:22 -08001508
1509 f.close()
sousaedu80135b92021-02-17 15:05:18 +01001510
bhangarebfdca492017-03-11 01:32:46 -08001511 return False
sousaedu80135b92021-02-17 15:05:18 +01001512
kasarc5bf2932018-03-09 04:15:22 -08001513 f.close()
1514 if progress:
1515 progress_bar.finish()
1516 time.sleep(10)
sousaedu80135b92021-02-17 15:05:18 +01001517
kasarc5bf2932018-03-09 04:15:22 -08001518 return True
1519 else:
sousaedu80135b92021-02-17 15:05:18 +01001520 self.logger.debug(
1521 "Failed retrieve vApp template for catalog name {} for OVF {}".format(
1522 catalog_name, media_file_name
1523 )
1524 )
kasarc5bf2932018-03-09 04:15:22 -08001525 return False
bhangarebfdca492017-03-11 01:32:46 -08001526 except Exception as exp:
sousaedu80135b92021-02-17 15:05:18 +01001527 self.logger.debug(
1528 "Failed while uploading OVF to catalog {} for OVF file {} with Exception {}".format(
1529 catalog_name, media_file_name, exp
1530 )
1531 )
bayramov325fa1c2016-09-08 01:42:46 -07001532
sousaedu80135b92021-02-17 15:05:18 +01001533 raise vimconn.VimConnException(
1534 "Failed while uploading OVF to catalog {} for OVF file {} with Exception {}".format(
1535 catalog_name, media_file_name, exp
1536 )
1537 )
1538
1539 self.logger.debug(
1540 "Failed retrieve catalog name {} for OVF file {}".format(
1541 catalog_name, media_file_name
1542 )
1543 )
1544
bayramov325fa1c2016-09-08 01:42:46 -07001545 return False
1546
sousaedu80135b92021-02-17 15:05:18 +01001547 def upload_vimimage(
1548 self,
1549 vca=None,
1550 catalog_name=None,
1551 media_name=None,
1552 medial_file_name=None,
1553 progress=False,
1554 ):
bayramov325fa1c2016-09-08 01:42:46 -07001555 """Upload media file"""
bayramovfe3f3c92016-10-04 07:53:41 +04001556 # TODO add named parameters for readability
sousaedu80135b92021-02-17 15:05:18 +01001557 return self.upload_ovf(
1558 vca=vca,
1559 catalog_name=catalog_name,
1560 image_name=media_name.split(".")[0],
1561 media_file_name=medial_file_name,
1562 description="medial_file_name",
1563 progress=progress,
1564 )
bayramov325fa1c2016-09-08 01:42:46 -07001565
bayramovb6ffe792016-09-28 11:50:56 +04001566 def validate_uuid4(self, uuid_string=None):
sousaedu80135b92021-02-17 15:05:18 +01001567 """Method validate correct format of UUID.
bayramovb6ffe792016-09-28 11:50:56 +04001568
1569 Return: true if string represent valid uuid
1570 """
1571 try:
beierlb22ce2d2019-12-12 12:09:51 -05001572 uuid.UUID(uuid_string, version=4)
bayramovb6ffe792016-09-28 11:50:56 +04001573 except ValueError:
1574 return False
sousaedu80135b92021-02-17 15:05:18 +01001575
bayramovb6ffe792016-09-28 11:50:56 +04001576 return True
1577
1578 def get_catalogid(self, catalog_name=None, catalogs=None):
sousaedu80135b92021-02-17 15:05:18 +01001579 """Method check catalog and return catalog ID in UUID format.
bayramovb6ffe792016-09-28 11:50:56 +04001580
1581 Args
1582 catalog_name: catalog name as string
1583 catalogs: list of catalogs.
1584
1585 Return: catalogs uuid
1586 """
bayramov325fa1c2016-09-08 01:42:46 -07001587 for catalog in catalogs:
sousaedu80135b92021-02-17 15:05:18 +01001588 if catalog["name"] == catalog_name:
1589 catalog_id = catalog["id"]
kasarc5bf2932018-03-09 04:15:22 -08001590 return catalog_id
sousaedu80135b92021-02-17 15:05:18 +01001591
bayramov325fa1c2016-09-08 01:42:46 -07001592 return None
1593
bayramovb6ffe792016-09-28 11:50:56 +04001594 def get_catalogbyid(self, catalog_uuid=None, catalogs=None):
sousaedu80135b92021-02-17 15:05:18 +01001595 """Method check catalog and return catalog name lookup done by catalog UUID.
bayramovb6ffe792016-09-28 11:50:56 +04001596
1597 Args
1598 catalog_name: catalog name as string
1599 catalogs: list of catalogs.
1600
1601 Return: catalogs name or None
1602 """
bayramovb6ffe792016-09-28 11:50:56 +04001603 if not self.validate_uuid4(uuid_string=catalog_uuid):
1604 return None
1605
bayramov325fa1c2016-09-08 01:42:46 -07001606 for catalog in catalogs:
sousaedu80135b92021-02-17 15:05:18 +01001607 catalog_id = catalog.get("id")
1608
bayramovb6ffe792016-09-28 11:50:56 +04001609 if catalog_id == catalog_uuid:
sousaedu80135b92021-02-17 15:05:18 +01001610 return catalog.get("name")
1611
bayramov325fa1c2016-09-08 01:42:46 -07001612 return None
1613
bhangare06312472017-03-30 05:49:07 -07001614 def get_catalog_obj(self, catalog_uuid=None, catalogs=None):
sousaedu80135b92021-02-17 15:05:18 +01001615 """Method check catalog and return catalog name lookup done by catalog UUID.
bhangare06312472017-03-30 05:49:07 -07001616
1617 Args
1618 catalog_name: catalog name as string
1619 catalogs: list of catalogs.
1620
1621 Return: catalogs name or None
1622 """
bhangare06312472017-03-30 05:49:07 -07001623 if not self.validate_uuid4(uuid_string=catalog_uuid):
1624 return None
1625
1626 for catalog in catalogs:
sousaedu80135b92021-02-17 15:05:18 +01001627 catalog_id = catalog.get("id")
1628
bhangare06312472017-03-30 05:49:07 -07001629 if catalog_id == catalog_uuid:
1630 return catalog
sousaedu80135b92021-02-17 15:05:18 +01001631
bhangare06312472017-03-30 05:49:07 -07001632 return None
1633
bayramovfe3f3c92016-10-04 07:53:41 +04001634 def get_image_id_from_path(self, path=None, progress=False):
sousaedu80135b92021-02-17 15:05:18 +01001635 """Method upload OVF image to vCloud director.
bayramov325fa1c2016-09-08 01:42:46 -07001636
bayramovb6ffe792016-09-28 11:50:56 +04001637 Each OVF image represented as single catalog entry in vcloud director.
1638 The method check for existing catalog entry. The check done by file name without file extension.
1639
1640 if given catalog name already present method will respond with existing catalog uuid otherwise
1641 it will create new catalog entry and upload OVF file to newly created catalog.
1642
1643 If method can't create catalog entry or upload a file it will throw exception.
1644
bayramovfe3f3c92016-10-04 07:53:41 +04001645 Method accept boolean flag progress that will output progress bar. It useful method
1646 for standalone upload use case. In case to test large file upload.
1647
bayramovb6ffe792016-09-28 11:50:56 +04001648 Args
bayramovfe3f3c92016-10-04 07:53:41 +04001649 path: - valid path to OVF file.
1650 progress - boolean progress bar show progress bar.
bayramovb6ffe792016-09-28 11:50:56 +04001651
1652 Return: if image uploaded correct method will provide image catalog UUID.
1653 """
kate15f1c382016-12-15 01:12:40 -08001654 if not path:
tierno72774862020-05-04 11:44:15 +00001655 raise vimconn.VimConnException("Image path can't be None.")
bayramovfe3f3c92016-10-04 07:53:41 +04001656
1657 if not os.path.isfile(path):
tierno72774862020-05-04 11:44:15 +00001658 raise vimconn.VimConnException("Can't read file. File not found.")
bayramovfe3f3c92016-10-04 07:53:41 +04001659
1660 if not os.access(path, os.R_OK):
sousaedu80135b92021-02-17 15:05:18 +01001661 raise vimconn.VimConnException(
1662 "Can't read file. Check file permission to read."
1663 )
bayramovfe3f3c92016-10-04 07:53:41 +04001664
1665 self.logger.debug("get_image_id_from_path() client requesting {} ".format(path))
bayramov325fa1c2016-09-08 01:42:46 -07001666
beierlb22ce2d2019-12-12 12:09:51 -05001667 _, filename = os.path.split(path)
1668 _, file_extension = os.path.splitext(path)
sousaedu80135b92021-02-17 15:05:18 +01001669 if file_extension != ".ovf":
1670 self.logger.debug(
1671 "Wrong file extension {} connector support only OVF container.".format(
1672 file_extension
1673 )
1674 )
1675
1676 raise vimconn.VimConnException(
1677 "Wrong container. vCloud director supports only OVF."
1678 )
kate15f1c382016-12-15 01:12:40 -08001679
bayramov325fa1c2016-09-08 01:42:46 -07001680 catalog_name = os.path.splitext(filename)[0]
sousaedu80135b92021-02-17 15:05:18 +01001681 catalog_md5_name = hashlib.md5(path.encode("utf-8")).hexdigest()
1682 self.logger.debug(
1683 "File name {} Catalog Name {} file path {} "
1684 "vdc catalog name {}".format(filename, catalog_name, path, catalog_md5_name)
1685 )
bayramov325fa1c2016-09-08 01:42:46 -07001686
bhangarebfdca492017-03-11 01:32:46 -08001687 try:
beierlb22ce2d2019-12-12 12:09:51 -05001688 org, _ = self.get_vdc_details()
kasarc5bf2932018-03-09 04:15:22 -08001689 catalogs = org.list_catalogs()
bhangarebfdca492017-03-11 01:32:46 -08001690 except Exception as exp:
1691 self.logger.debug("Failed get catalogs() with Exception {} ".format(exp))
sousaedu80135b92021-02-17 15:05:18 +01001692
1693 raise vimconn.VimConnException(
1694 "Failed get catalogs() with Exception {} ".format(exp)
1695 )
bhangarebfdca492017-03-11 01:32:46 -08001696
bayramov325fa1c2016-09-08 01:42:46 -07001697 if len(catalogs) == 0:
sousaedu80135b92021-02-17 15:05:18 +01001698 self.logger.info(
1699 "Creating a new catalog entry {} in vcloud director".format(
1700 catalog_name
1701 )
1702 )
kasarc5bf2932018-03-09 04:15:22 -08001703
sousaedu80135b92021-02-17 15:05:18 +01001704 if self.create_vimcatalog(org, catalog_md5_name) is None:
1705 raise vimconn.VimConnException(
1706 "Failed create new catalog {} ".format(catalog_md5_name)
1707 )
1708
1709 result = self.upload_vimimage(
1710 vca=org,
1711 catalog_name=catalog_md5_name,
1712 media_name=filename,
1713 medial_file_name=path,
1714 progress=progress,
1715 )
1716
bayramov325fa1c2016-09-08 01:42:46 -07001717 if not result:
sousaedu80135b92021-02-17 15:05:18 +01001718 raise vimconn.VimConnException(
1719 "Failed create vApp template for catalog {} ".format(catalog_name)
1720 )
1721
kasarc5bf2932018-03-09 04:15:22 -08001722 return self.get_catalogid(catalog_name, catalogs)
bayramov325fa1c2016-09-08 01:42:46 -07001723 else:
1724 for catalog in catalogs:
1725 # search for existing catalog if we find same name we return ID
1726 # TODO optimize this
sousaedu80135b92021-02-17 15:05:18 +01001727 if catalog["name"] == catalog_md5_name:
1728 self.logger.debug(
1729 "Found existing catalog entry for {} "
1730 "catalog id {}".format(
1731 catalog_name, self.get_catalogid(catalog_md5_name, catalogs)
1732 )
1733 )
1734
kasarc5bf2932018-03-09 04:15:22 -08001735 return self.get_catalogid(catalog_md5_name, catalogs)
bayramov325fa1c2016-09-08 01:42:46 -07001736
bayramovfe3f3c92016-10-04 07:53:41 +04001737 # if we didn't find existing catalog we create a new one and upload image.
sousaedu80135b92021-02-17 15:05:18 +01001738 self.logger.debug(
1739 "Creating new catalog entry {} - {}".format(catalog_name, catalog_md5_name)
1740 )
Ananda Baitharu319c26f2019-03-05 17:34:31 +00001741 if self.create_vimcatalog(org, catalog_md5_name) is None:
sousaedu80135b92021-02-17 15:05:18 +01001742 raise vimconn.VimConnException(
1743 "Failed create new catalog {} ".format(catalog_md5_name)
1744 )
bayramovfe3f3c92016-10-04 07:53:41 +04001745
sousaedu80135b92021-02-17 15:05:18 +01001746 result = self.upload_vimimage(
1747 vca=org,
1748 catalog_name=catalog_md5_name,
1749 media_name=filename,
1750 medial_file_name=path,
1751 progress=progress,
1752 )
bayramov325fa1c2016-09-08 01:42:46 -07001753 if not result:
sousaedu80135b92021-02-17 15:05:18 +01001754 raise vimconn.VimConnException(
1755 "Failed create vApp template for catalog {} ".format(catalog_md5_name)
1756 )
bayramov325fa1c2016-09-08 01:42:46 -07001757
kasarc5bf2932018-03-09 04:15:22 -08001758 return self.get_catalogid(catalog_md5_name, org.list_catalogs())
bayramov325fa1c2016-09-08 01:42:46 -07001759
kate8fc61fc2017-01-23 19:57:06 -08001760 def get_image_list(self, filter_dict={}):
sousaedu80135b92021-02-17 15:05:18 +01001761 """Obtain tenant images from VIM
kate8fc61fc2017-01-23 19:57:06 -08001762 Filter_dict can be:
1763 name: image name
1764 id: image uuid
1765 checksum: image checksum
1766 location: image path
1767 Returns the image list of dictionaries:
1768 [{<the fields at Filter_dict plus some VIM specific>}, ...]
1769 List can be empty
sousaedu80135b92021-02-17 15:05:18 +01001770 """
kate8fc61fc2017-01-23 19:57:06 -08001771 try:
beierlb22ce2d2019-12-12 12:09:51 -05001772 org, _ = self.get_vdc_details()
kate8fc61fc2017-01-23 19:57:06 -08001773 image_list = []
kasarc5bf2932018-03-09 04:15:22 -08001774 catalogs = org.list_catalogs()
sousaedu80135b92021-02-17 15:05:18 +01001775
kate8fc61fc2017-01-23 19:57:06 -08001776 if len(catalogs) == 0:
1777 return image_list
1778 else:
1779 for catalog in catalogs:
sousaedu80135b92021-02-17 15:05:18 +01001780 catalog_uuid = catalog.get("id")
1781 name = catalog.get("name")
kate8fc61fc2017-01-23 19:57:06 -08001782 filtered_dict = {}
sousaedu80135b92021-02-17 15:05:18 +01001783
kate34718682017-01-24 03:20:43 -08001784 if filter_dict.get("name") and filter_dict["name"] != name:
1785 continue
sousaedu80135b92021-02-17 15:05:18 +01001786
kate34718682017-01-24 03:20:43 -08001787 if filter_dict.get("id") and filter_dict["id"] != catalog_uuid:
1788 continue
sousaedu80135b92021-02-17 15:05:18 +01001789
beierlb22ce2d2019-12-12 12:09:51 -05001790 filtered_dict["name"] = name
1791 filtered_dict["id"] = catalog_uuid
kate34718682017-01-24 03:20:43 -08001792 image_list.append(filtered_dict)
kate8fc61fc2017-01-23 19:57:06 -08001793
sousaedu80135b92021-02-17 15:05:18 +01001794 self.logger.debug(
1795 "List of already created catalog items: {}".format(image_list)
1796 )
1797
kate8fc61fc2017-01-23 19:57:06 -08001798 return image_list
1799 except Exception as exp:
sousaedu80135b92021-02-17 15:05:18 +01001800 raise vimconn.VimConnException(
1801 "Exception occured while retriving catalog items {}".format(exp)
1802 )
kate8fc61fc2017-01-23 19:57:06 -08001803
bayramovef390722016-09-27 03:34:46 -07001804 def get_vappid(self, vdc=None, vapp_name=None):
sousaedu80135b92021-02-17 15:05:18 +01001805 """Method takes vdc object and vApp name and returns vapp uuid or None
bayramovef390722016-09-27 03:34:46 -07001806
1807 Args:
bayramovef390722016-09-27 03:34:46 -07001808 vdc: The VDC object.
1809 vapp_name: is application vappp name identifier
1810
bayramovb6ffe792016-09-28 11:50:56 +04001811 Returns:
bayramovef390722016-09-27 03:34:46 -07001812 The return vApp name otherwise None
1813 """
bayramovef390722016-09-27 03:34:46 -07001814 if vdc is None or vapp_name is None:
1815 return None
sousaedu80135b92021-02-17 15:05:18 +01001816
bayramovef390722016-09-27 03:34:46 -07001817 # UUID has following format https://host/api/vApp/vapp-30da58a3-e7c7-4d09-8f68-d4c8201169cf
bayramov325fa1c2016-09-08 01:42:46 -07001818 try:
sousaedu80135b92021-02-17 15:05:18 +01001819 refs = [
1820 ref
1821 for ref in vdc.ResourceEntities.ResourceEntity
1822 if ref.name == vapp_name
1823 and ref.type_ == "application/vnd.vmware.vcloud.vApp+xml"
1824 ]
1825
bayramov325fa1c2016-09-08 01:42:46 -07001826 if len(refs) == 1:
1827 return refs[0].href.split("vapp")[1][1:]
bayramovef390722016-09-27 03:34:46 -07001828 except Exception as e:
1829 self.logger.exception(e)
1830 return False
sousaedu80135b92021-02-17 15:05:18 +01001831
bayramovef390722016-09-27 03:34:46 -07001832 return None
1833
bayramovfe3f3c92016-10-04 07:53:41 +04001834 def check_vapp(self, vdc=None, vapp_uuid=None):
sousaedu80135b92021-02-17 15:05:18 +01001835 """Method Method returns True or False if vapp deployed in vCloud director
bayramovef390722016-09-27 03:34:46 -07001836
sousaedu80135b92021-02-17 15:05:18 +01001837 Args:
1838 vca: Connector to VCA
1839 vdc: The VDC object.
1840 vappid: vappid is application identifier
bayramovef390722016-09-27 03:34:46 -07001841
sousaedu80135b92021-02-17 15:05:18 +01001842 Returns:
1843 The return True if vApp deployed
1844 :param vdc:
1845 :param vapp_uuid:
bayramovef390722016-09-27 03:34:46 -07001846 """
1847 try:
sousaedu80135b92021-02-17 15:05:18 +01001848 refs = [
1849 ref
1850 for ref in vdc.ResourceEntities.ResourceEntity
1851 if ref.type_ == "application/vnd.vmware.vcloud.vApp+xml"
1852 ]
1853
bayramovef390722016-09-27 03:34:46 -07001854 for ref in refs:
1855 vappid = ref.href.split("vapp")[1][1:]
1856 # find vapp with respected vapp uuid
sousaedu80135b92021-02-17 15:05:18 +01001857
bayramovfe3f3c92016-10-04 07:53:41 +04001858 if vappid == vapp_uuid:
bayramovef390722016-09-27 03:34:46 -07001859 return True
1860 except Exception as e:
1861 self.logger.exception(e)
sousaedu80135b92021-02-17 15:05:18 +01001862
bayramovef390722016-09-27 03:34:46 -07001863 return False
sousaedu80135b92021-02-17 15:05:18 +01001864
bayramovef390722016-09-27 03:34:46 -07001865 return False
1866
kasarc5bf2932018-03-09 04:15:22 -08001867 def get_namebyvappid(self, vapp_uuid=None):
bayramovef390722016-09-27 03:34:46 -07001868 """Method returns vApp name from vCD and lookup done by vapp_id.
1869
1870 Args:
bayramovfe3f3c92016-10-04 07:53:41 +04001871 vapp_uuid: vappid is application identifier
bayramovef390722016-09-27 03:34:46 -07001872
1873 Returns:
1874 The return vApp name otherwise None
1875 """
bayramovef390722016-09-27 03:34:46 -07001876 try:
kasarc5bf2932018-03-09 04:15:22 -08001877 if self.client and vapp_uuid:
1878 vapp_call = "{}/api/vApp/vapp-{}".format(self.url, vapp_uuid)
sousaedu80135b92021-02-17 15:05:18 +01001879 headers = {
1880 "Accept": "application/*+xml;version=" + API_VERSION,
1881 "x-vcloud-authorization": self.client._session.headers[
1882 "x-vcloud-authorization"
1883 ],
1884 }
bhangare1a0b97c2017-06-21 02:20:15 -07001885
sousaedu80135b92021-02-17 15:05:18 +01001886 response = self.perform_request(
1887 req_type="GET", url=vapp_call, headers=headers
1888 )
1889
beierlb22ce2d2019-12-12 12:09:51 -05001890 # Retry login if session expired & retry sending request
kasarc5bf2932018-03-09 04:15:22 -08001891 if response.status_code == 403:
sousaedu80135b92021-02-17 15:05:18 +01001892 response = self.retry_rest("GET", vapp_call)
bhangare1a0b97c2017-06-21 02:20:15 -07001893
beierl26fec002019-12-06 17:06:40 -05001894 tree = XmlElementTree.fromstring(response.text)
sousaedu80135b92021-02-17 15:05:18 +01001895
1896 return tree.attrib["name"] if "name" in tree.attrib else None
bayramovef390722016-09-27 03:34:46 -07001897 except Exception as e:
1898 self.logger.exception(e)
sousaedu80135b92021-02-17 15:05:18 +01001899
bayramov325fa1c2016-09-08 01:42:46 -07001900 return None
sousaedu80135b92021-02-17 15:05:18 +01001901
bayramov325fa1c2016-09-08 01:42:46 -07001902 return None
1903
sousaedu80135b92021-02-17 15:05:18 +01001904 def new_vminstance(
1905 self,
1906 name=None,
1907 description="",
1908 start=False,
1909 image_id=None,
1910 flavor_id=None,
Alexis Romerob70f4ed2022-03-11 18:00:49 +01001911 affinity_group_list=[],
sousaedu80135b92021-02-17 15:05:18 +01001912 net_list=[],
1913 cloud_config=None,
1914 disk_list=None,
1915 availability_zone_index=None,
1916 availability_zone_list=None,
1917 ):
bayramov325fa1c2016-09-08 01:42:46 -07001918 """Adds a VM instance to VIM
1919 Params:
tierno19860412017-10-03 10:46:46 +02001920 'start': (boolean) indicates if VM must start or created in pause mode.
1921 'image_id','flavor_id': image and flavor VIM id to use for the VM
1922 'net_list': list of interfaces, each one is a dictionary with:
1923 'name': (optional) name for the interface.
1924 'net_id': VIM network id where this interface must be connect to. Mandatory for type==virtual
beierlb22ce2d2019-12-12 12:09:51 -05001925 'vpci': (optional) virtual vPCI address to assign at the VM. Can be ignored depending on VIM
1926 capabilities
garciadeblasc4f4d732018-10-25 18:17:24 +02001927 'model': (optional and only have sense for type==virtual) interface model: virtio, e1000, ...
tierno19860412017-10-03 10:46:46 +02001928 'mac_address': (optional) mac address to assign to this interface
beierlb22ce2d2019-12-12 12:09:51 -05001929 #TODO: CHECK if an optional 'vlan' parameter is needed for VIMs when type if VF and net_id is not
1930 provided, the VLAN tag to be used. In case net_id is provided, the internal network vlan is used
1931 for tagging VF
tierno19860412017-10-03 10:46:46 +02001932 'type': (mandatory) can be one of:
1933 'virtual', in this case always connected to a network of type 'net_type=bridge'
beierlb22ce2d2019-12-12 12:09:51 -05001934 'PCI-PASSTHROUGH' or 'PF' (passthrough): depending on VIM capabilities it can be connected to a
1935 data/ptp network or it can created unconnected
tierno66eba6e2017-11-10 17:09:18 +01001936 'SR-IOV' or 'VF' (SRIOV with VLAN tag): same as PF for network connectivity.
tierno19860412017-10-03 10:46:46 +02001937 'VFnotShared'(SRIOV without VLAN tag) same as PF for network connectivity. VF where no other VFs
1938 are allocated on the same physical NIC
1939 'bw': (optional) only for PF/VF/VFnotShared. Minimal Bandwidth required for the interface in GBPS
1940 'port_security': (optional) If False it must avoid any traffic filtering at this interface. If missing
1941 or True, it must apply the default VIM behaviour
1942 After execution the method will add the key:
1943 'vim_id': must be filled/added by this method with the VIM identifier generated by the VIM for this
1944 interface. 'net_list' is modified
1945 'cloud_config': (optional) dictionary with:
1946 'key-pairs': (optional) list of strings with the public key to be inserted to the default user
1947 'users': (optional) list of users to be inserted, each item is a dict with:
1948 'name': (mandatory) user name,
1949 'key-pairs': (optional) list of strings with the public key to be inserted to the user
1950 'user-data': (optional) can be a string with the text script to be passed directly to cloud-init,
1951 or a list of strings, each one contains a script to be passed, usually with a MIMEmultipart file
1952 'config-files': (optional). List of files to be transferred. Each item is a dict with:
1953 'dest': (mandatory) string with the destination absolute path
1954 'encoding': (optional, by default text). Can be one of:
1955 'b64', 'base64', 'gz', 'gz+b64', 'gz+base64', 'gzip+b64', 'gzip+base64'
1956 'content' (mandatory): string with the content of the file
1957 'permissions': (optional) string with file permissions, typically octal notation '0644'
1958 'owner': (optional) file owner, string with the format 'owner:group'
1959 'boot-data-drive': boolean to indicate if user-data must be passed using a boot drive (hard disk)
1960 'disk_list': (optional) list with additional disks to the VM. Each item is a dict with:
1961 'image_id': (optional). VIM id of an existing image. If not provided an empty disk must be mounted
1962 'size': (mandatory) string with the size of the disk in GB
1963 availability_zone_index: Index of availability_zone_list to use for this this VM. None if not AV required
1964 availability_zone_list: list of availability zones given by user in the VNFD descriptor. Ignore if
1965 availability_zone_index is None
tierno98e909c2017-10-14 13:27:03 +02001966 Returns a tuple with the instance identifier and created_items or raises an exception on error
1967 created_items can be None or a dictionary where this method can include key-values that will be passed to
1968 the method delete_vminstance and action_vminstance. Can be used to store created ports, volumes, etc.
1969 Format is vimconnector dependent, but do not use nested dictionaries and a value of None should be the same
1970 as not present.
bayramov325fa1c2016-09-08 01:42:46 -07001971 """
kate15f1c382016-12-15 01:12:40 -08001972 self.logger.info("Creating new instance for entry {}".format(name))
sousaedu80135b92021-02-17 15:05:18 +01001973 self.logger.debug(
1974 "desc {} boot {} image_id: {} flavor_id: {} net_list: {} cloud_config {} disk_list {} "
1975 "availability_zone_index {} availability_zone_list {}".format(
1976 description,
1977 start,
1978 image_id,
1979 flavor_id,
1980 net_list,
1981 cloud_config,
1982 disk_list,
1983 availability_zone_index,
1984 availability_zone_list,
1985 )
1986 )
bayramov325fa1c2016-09-08 01:42:46 -07001987
beierlb22ce2d2019-12-12 12:09:51 -05001988 # new vm name = vmname + tenant_id + uuid
sousaedu80135b92021-02-17 15:05:18 +01001989 new_vm_name = [name, "-", str(uuid.uuid4())]
1990 vmname_andid = "".join(new_vm_name)
bayramov5761ad12016-10-04 09:00:30 +04001991
kasarc5bf2932018-03-09 04:15:22 -08001992 for net in net_list:
sousaedu80135b92021-02-17 15:05:18 +01001993 if net["type"] == "PCI-PASSTHROUGH":
tierno72774862020-05-04 11:44:15 +00001994 raise vimconn.VimConnNotSupportedException(
sousaedu80135b92021-02-17 15:05:18 +01001995 "Current vCD version does not support type : {}".format(net["type"])
1996 )
bayramov325fa1c2016-09-08 01:42:46 -07001997
kasarc5bf2932018-03-09 04:15:22 -08001998 if len(net_list) > 10:
tierno72774862020-05-04 11:44:15 +00001999 raise vimconn.VimConnNotSupportedException(
sousaedu80135b92021-02-17 15:05:18 +01002000 "The VM hardware versions 7 and above support upto 10 NICs only"
2001 )
kasarc5bf2932018-03-09 04:15:22 -08002002
2003 # if vm already deployed we return existing uuid
bayramovef390722016-09-27 03:34:46 -07002004 # we check for presence of VDC, Catalog entry and Flavor.
kasarc5bf2932018-03-09 04:15:22 -08002005 org, vdc = self.get_vdc_details()
bayramovef390722016-09-27 03:34:46 -07002006 if vdc is None:
tierno72774862020-05-04 11:44:15 +00002007 raise vimconn.VimConnNotFoundException(
sousaedu80135b92021-02-17 15:05:18 +01002008 "new_vminstance(): Failed create vApp {}: (Failed retrieve VDC information)".format(
2009 name
2010 )
2011 )
2012
kasarc5bf2932018-03-09 04:15:22 -08002013 catalogs = org.list_catalogs()
bhangare1a0b97c2017-06-21 02:20:15 -07002014 if catalogs is None:
beierlb22ce2d2019-12-12 12:09:51 -05002015 # Retry once, if failed by refreshing token
bhangare1a0b97c2017-06-21 02:20:15 -07002016 self.get_token()
kasarc5bf2932018-03-09 04:15:22 -08002017 org = Org(self.client, resource=self.client.get_org())
2018 catalogs = org.list_catalogs()
sousaedu80135b92021-02-17 15:05:18 +01002019
bayramovef390722016-09-27 03:34:46 -07002020 if catalogs is None:
tierno72774862020-05-04 11:44:15 +00002021 raise vimconn.VimConnNotFoundException(
sousaedu80135b92021-02-17 15:05:18 +01002022 "new_vminstance(): Failed create vApp {}: (Failed retrieve catalogs list)".format(
2023 name
2024 )
2025 )
bayramovbd6160f2016-09-28 04:12:05 +04002026
sousaedu80135b92021-02-17 15:05:18 +01002027 catalog_hash_name = self.get_catalogbyid(
2028 catalog_uuid=image_id, catalogs=catalogs
2029 )
kate15f1c382016-12-15 01:12:40 -08002030 if catalog_hash_name:
sousaedu80135b92021-02-17 15:05:18 +01002031 self.logger.info(
2032 "Found catalog entry {} for image id {}".format(
2033 catalog_hash_name, image_id
2034 )
2035 )
kate15f1c382016-12-15 01:12:40 -08002036 else:
sousaedu80135b92021-02-17 15:05:18 +01002037 raise vimconn.VimConnNotFoundException(
2038 "new_vminstance(): Failed create vApp {}: "
2039 "(Failed retrieve catalog information {})".format(name, image_id)
2040 )
kate15f1c382016-12-15 01:12:40 -08002041
kate15f1c382016-12-15 01:12:40 -08002042 # Set vCPU and Memory based on flavor.
bayramovb6ffe792016-09-28 11:50:56 +04002043 vm_cpus = None
2044 vm_memory = None
bhangarea92ae392017-01-12 22:30:29 -08002045 vm_disk = None
bhangare68e73e62017-07-04 22:44:01 -07002046 numas = None
kateac1e3792017-04-01 02:16:39 -07002047
bayramovb6ffe792016-09-28 11:50:56 +04002048 if flavor_id is not None:
kateeb044522017-03-06 23:54:39 -08002049 if flavor_id not in vimconnector.flavorlist:
sousaedu80135b92021-02-17 15:05:18 +01002050 raise vimconn.VimConnNotFoundException(
2051 "new_vminstance(): Failed create vApp {}: "
2052 "Failed retrieve flavor information "
2053 "flavor id {}".format(name, flavor_id)
2054 )
bayramovb6ffe792016-09-28 11:50:56 +04002055 else:
2056 try:
kateeb044522017-03-06 23:54:39 -08002057 flavor = vimconnector.flavorlist[flavor_id]
kate15f1c382016-12-15 01:12:40 -08002058 vm_cpus = flavor[FLAVOR_VCPUS_KEY]
2059 vm_memory = flavor[FLAVOR_RAM_KEY]
bhangarea92ae392017-01-12 22:30:29 -08002060 vm_disk = flavor[FLAVOR_DISK_KEY]
bhangarefda5f7c2017-01-12 23:50:34 -08002061 extended = flavor.get("extended", None)
sousaedu80135b92021-02-17 15:05:18 +01002062
bhangarefda5f7c2017-01-12 23:50:34 -08002063 if extended:
beierlb22ce2d2019-12-12 12:09:51 -05002064 numas = extended.get("numas", None)
kateeb044522017-03-06 23:54:39 -08002065 except Exception as exp:
sousaedu80135b92021-02-17 15:05:18 +01002066 raise vimconn.VimConnException(
2067 "Corrupted flavor. {}.Exception: {}".format(flavor_id, exp)
2068 )
bayramov325fa1c2016-09-08 01:42:46 -07002069
bayramovef390722016-09-27 03:34:46 -07002070 # image upload creates template name as catalog name space Template.
kate15f1c382016-12-15 01:12:40 -08002071 templateName = self.get_catalogbyid(catalog_uuid=image_id, catalogs=catalogs)
beierlb22ce2d2019-12-12 12:09:51 -05002072 # power_on = 'false'
2073 # if start:
2074 # power_on = 'true'
bayramovef390722016-09-27 03:34:46 -07002075
2076 # client must provide at least one entry in net_list if not we report error
beierlb22ce2d2019-12-12 12:09:51 -05002077 # If net type is mgmt, then configure it as primary net & use its NIC index as primary NIC
beierl26fec002019-12-06 17:06:40 -05002078 # If no mgmt, then the 1st NN in netlist is considered as primary net.
bhangare0e571a92017-01-12 04:02:23 -08002079 primary_net = None
kate15f1c382016-12-15 01:12:40 -08002080 primary_netname = None
Ravi Chamarty1fdf9992018-10-07 15:45:44 +00002081 primary_net_href = None
beierlb22ce2d2019-12-12 12:09:51 -05002082 # network_mode = 'bridged'
bayramovb6ffe792016-09-28 11:50:56 +04002083 if net_list is not None and len(net_list) > 0:
bhangare0e571a92017-01-12 04:02:23 -08002084 for net in net_list:
sousaedu80135b92021-02-17 15:05:18 +01002085 if "use" in net and net["use"] == "mgmt" and not primary_net:
bhangare0e571a92017-01-12 04:02:23 -08002086 primary_net = net
sousaedu80135b92021-02-17 15:05:18 +01002087
bayramovb6ffe792016-09-28 11:50:56 +04002088 if primary_net is None:
bhangare0e571a92017-01-12 04:02:23 -08002089 primary_net = net_list[0]
2090
2091 try:
sousaedu80135b92021-02-17 15:05:18 +01002092 primary_net_id = primary_net["net_id"]
2093 url_list = [self.url, "/api/network/", primary_net_id]
2094 primary_net_href = "".join(url_list)
bhangare0e571a92017-01-12 04:02:23 -08002095 network_dict = self.get_vcd_network(network_uuid=primary_net_id)
bhangare0e571a92017-01-12 04:02:23 -08002096
sousaedu80135b92021-02-17 15:05:18 +01002097 if "name" in network_dict:
2098 primary_netname = network_dict["name"]
bhangare0e571a92017-01-12 04:02:23 -08002099 except KeyError:
sousaedu80135b92021-02-17 15:05:18 +01002100 raise vimconn.VimConnException(
2101 "Corrupted flavor. {}".format(primary_net)
2102 )
bhangare0e571a92017-01-12 04:02:23 -08002103 else:
sousaedu80135b92021-02-17 15:05:18 +01002104 raise vimconn.VimConnUnexpectedResponse(
2105 "new_vminstance(): Failed network list is empty."
2106 )
bayramovef390722016-09-27 03:34:46 -07002107
2108 # use: 'data', 'bridge', 'mgmt'
2109 # create vApp. Set vcpu and ram based on flavor id.
bhangarebfdca492017-03-11 01:32:46 -08002110 try:
kasarc5bf2932018-03-09 04:15:22 -08002111 vdc_obj = VDC(self.client, resource=org.get_vdc(self.tenant_name))
2112 if not vdc_obj:
sousaedu80135b92021-02-17 15:05:18 +01002113 raise vimconn.VimConnNotFoundException(
2114 "new_vminstance(): Failed to get VDC object"
2115 )
bhangare1a0b97c2017-06-21 02:20:15 -07002116
beierl26fec002019-12-06 17:06:40 -05002117 for retry in (1, 2):
kasarc5bf2932018-03-09 04:15:22 -08002118 items = org.get_catalog_item(catalog_hash_name, catalog_hash_name)
2119 catalog_items = [items.attrib]
2120
2121 if len(catalog_items) == 1:
2122 if self.client:
sousaedu80135b92021-02-17 15:05:18 +01002123 headers = {
2124 "Accept": "application/*+xml;version=" + API_VERSION,
2125 "x-vcloud-authorization": self.client._session.headers[
2126 "x-vcloud-authorization"
2127 ],
2128 }
kasarc5bf2932018-03-09 04:15:22 -08002129
sousaedu80135b92021-02-17 15:05:18 +01002130 response = self.perform_request(
2131 req_type="GET",
2132 url=catalog_items[0].get("href"),
2133 headers=headers,
2134 )
beierl26fec002019-12-06 17:06:40 -05002135 catalogItem = XmlElementTree.fromstring(response.text)
sousaedu80135b92021-02-17 15:05:18 +01002136 entity = [
2137 child
2138 for child in catalogItem
2139 if child.get("type")
2140 == "application/vnd.vmware.vcloud.vAppTemplate+xml"
2141 ][0]
kasarc5bf2932018-03-09 04:15:22 -08002142 vapp_tempalte_href = entity.get("href")
sbhangarea8e5b782018-06-21 02:10:03 -07002143
sousaedu80135b92021-02-17 15:05:18 +01002144 response = self.perform_request(
2145 req_type="GET", url=vapp_tempalte_href, headers=headers
2146 )
2147
kasarc5bf2932018-03-09 04:15:22 -08002148 if response.status_code != requests.codes.ok:
sousaedu80135b92021-02-17 15:05:18 +01002149 self.logger.debug(
2150 "REST API call {} failed. Return status code {}".format(
2151 vapp_tempalte_href, response.status_code
2152 )
2153 )
kasarc5bf2932018-03-09 04:15:22 -08002154 else:
beierl26fec002019-12-06 17:06:40 -05002155 result = (response.text).replace("\n", " ")
kasarc5bf2932018-03-09 04:15:22 -08002156
beierl26fec002019-12-06 17:06:40 -05002157 vapp_template_tree = XmlElementTree.fromstring(response.text)
sousaedu80135b92021-02-17 15:05:18 +01002158 children_element = [
2159 child for child in vapp_template_tree if "Children" in child.tag
2160 ][0]
2161 vm_element = [child for child in children_element if "Vm" in child.tag][
2162 0
2163 ]
2164 vm_name = vm_element.get("name")
2165 vm_id = vm_element.get("id")
2166 vm_href = vm_element.get("href")
kasarc5bf2932018-03-09 04:15:22 -08002167
beierlb22ce2d2019-12-12 12:09:51 -05002168 # cpus = re.search('<rasd:Description>Number of Virtual CPUs</.*?>(\d+)</rasd:VirtualQuantity>',
2169 # result).group(1)
sousaedu80135b92021-02-17 15:05:18 +01002170 memory_mb = re.search(
2171 "<rasd:Description>Memory Size</.*?>(\d+)</rasd:VirtualQuantity>",
2172 result,
2173 ).group(1)
beierlb22ce2d2019-12-12 12:09:51 -05002174 # cores = re.search('<vmw:CoresPerSocket ovf:required.*?>(\d+)</vmw:CoresPerSocket>', result).group(1)
kasarc5bf2932018-03-09 04:15:22 -08002175
sousaedu80135b92021-02-17 15:05:18 +01002176 headers[
2177 "Content-Type"
2178 ] = "application/vnd.vmware.vcloud.instantiateVAppTemplateParams+xml"
2179 vdc_id = vdc.get("id").split(":")[-1]
2180 instantiate_vapp_href = (
2181 "{}/api/vdc/{}/action/instantiateVAppTemplate".format(
2182 self.url, vdc_id
2183 )
2184 )
2185
2186 with open(
2187 os.path.join(
2188 os.path.dirname(__file__), "InstantiateVAppTemplateParams.xml"
2189 ),
2190 "r",
2191 ) as f:
beierl26fec002019-12-06 17:06:40 -05002192 template = f.read()
2193
sousaedu80135b92021-02-17 15:05:18 +01002194 data = template.format(
2195 vmname_andid,
2196 primary_netname,
2197 primary_net_href,
2198 vapp_tempalte_href,
2199 vm_href,
2200 vm_id,
2201 vm_name,
2202 primary_netname,
2203 cpu=vm_cpus,
2204 core=1,
2205 memory=vm_memory,
2206 )
kasarc5bf2932018-03-09 04:15:22 -08002207
sousaedu80135b92021-02-17 15:05:18 +01002208 response = self.perform_request(
2209 req_type="POST",
2210 url=instantiate_vapp_href,
2211 headers=headers,
2212 data=data,
2213 )
kasarc5bf2932018-03-09 04:15:22 -08002214
2215 if response.status_code != 201:
sousaedu80135b92021-02-17 15:05:18 +01002216 self.logger.error(
2217 "REST call {} failed reason : {}"
2218 "status code : {}".format(
2219 instantiate_vapp_href, response.text, response.status_code
2220 )
2221 )
2222 raise vimconn.VimConnException(
2223 "new_vminstance(): Failed to create"
2224 "vAapp {}".format(vmname_andid)
2225 )
kasarc5bf2932018-03-09 04:15:22 -08002226 else:
beierl26fec002019-12-06 17:06:40 -05002227 vapptask = self.get_task_from_response(response.text)
kasarc5bf2932018-03-09 04:15:22 -08002228
beierlb22ce2d2019-12-12 12:09:51 -05002229 if vapptask is None and retry == 1:
2230 self.get_token() # Retry getting token
bhangare68e73e62017-07-04 22:44:01 -07002231 continue
2232 else:
2233 break
2234
bhangare1a0b97c2017-06-21 02:20:15 -07002235 if vapptask is None or vapptask is False:
tierno72774862020-05-04 11:44:15 +00002236 raise vimconn.VimConnUnexpectedResponse(
sousaedu80135b92021-02-17 15:05:18 +01002237 "new_vminstance(): failed to create vApp {}".format(vmname_andid)
2238 )
kasarc5bf2932018-03-09 04:15:22 -08002239
sbhangarea8e5b782018-06-21 02:10:03 -07002240 # wait for task to complete
kasarc5bf2932018-03-09 04:15:22 -08002241 result = self.client.get_task_monitor().wait_for_success(task=vapptask)
2242
sousaedu80135b92021-02-17 15:05:18 +01002243 if result.get("status") == "success":
2244 self.logger.debug(
2245 "new_vminstance(): Sucessfully created Vapp {}".format(vmname_andid)
2246 )
kasarc5bf2932018-03-09 04:15:22 -08002247 else:
tierno72774862020-05-04 11:44:15 +00002248 raise vimconn.VimConnUnexpectedResponse(
sousaedu80135b92021-02-17 15:05:18 +01002249 "new_vminstance(): failed to create vApp {}".format(vmname_andid)
2250 )
bhangarebfdca492017-03-11 01:32:46 -08002251 except Exception as exp:
tierno72774862020-05-04 11:44:15 +00002252 raise vimconn.VimConnUnexpectedResponse(
sousaedu80135b92021-02-17 15:05:18 +01002253 "new_vminstance(): failed to create vApp {} with Exception:{}".format(
2254 vmname_andid, exp
2255 )
2256 )
bayramovef390722016-09-27 03:34:46 -07002257
2258 # we should have now vapp in undeployed state.
bhangarebfdca492017-03-11 01:32:46 -08002259 try:
sousaedu80135b92021-02-17 15:05:18 +01002260 vdc_obj = VDC(self.client, href=vdc.get("href"))
kasarc5bf2932018-03-09 04:15:22 -08002261 vapp_resource = vdc_obj.get_vapp(vmname_andid)
sousaedu80135b92021-02-17 15:05:18 +01002262 vapp_uuid = vapp_resource.get("id").split(":")[-1]
kasarc5bf2932018-03-09 04:15:22 -08002263 vapp = VApp(self.client, resource=vapp_resource)
bhangarebfdca492017-03-11 01:32:46 -08002264 except Exception as exp:
tierno72774862020-05-04 11:44:15 +00002265 raise vimconn.VimConnUnexpectedResponse(
sousaedu80135b92021-02-17 15:05:18 +01002266 "new_vminstance(): Failed to retrieve vApp {} after creation: Exception:{}".format(
2267 vmname_andid, exp
2268 )
2269 )
bhangarebfdca492017-03-11 01:32:46 -08002270
bhangare1a0b97c2017-06-21 02:20:15 -07002271 if vapp_uuid is None:
tierno72774862020-05-04 11:44:15 +00002272 raise vimconn.VimConnUnexpectedResponse(
sousaedu80135b92021-02-17 15:05:18 +01002273 "new_vminstance(): Failed to retrieve vApp {} after creation".format(
2274 vmname_andid
2275 )
2276 )
bhangarea92ae392017-01-12 22:30:29 -08002277
beierl26fec002019-12-06 17:06:40 -05002278 # Add PCI passthrough/SRIOV configrations
kateac1e3792017-04-01 02:16:39 -07002279 pci_devices_info = []
kateac1e3792017-04-01 02:16:39 -07002280 reserve_memory = False
2281
2282 for net in net_list:
tierno66eba6e2017-11-10 17:09:18 +01002283 if net["type"] == "PF" or net["type"] == "PCI-PASSTHROUGH":
kateac1e3792017-04-01 02:16:39 -07002284 pci_devices_info.append(net)
sousaedu80135b92021-02-17 15:05:18 +01002285 elif (
2286 net["type"] == "VF"
2287 or net["type"] == "SR-IOV"
2288 or net["type"] == "VFnotShared"
2289 ) and "net_id" in net:
Ravi Chamartye21c9cc2018-10-24 02:14:53 +00002290 reserve_memory = True
kateac1e3792017-04-01 02:16:39 -07002291
beierl26fec002019-12-06 17:06:40 -05002292 # Add PCI
bhangarefda5f7c2017-01-12 23:50:34 -08002293 if len(pci_devices_info) > 0:
sousaedu80135b92021-02-17 15:05:18 +01002294 self.logger.info(
2295 "Need to add PCI devices {} into VM {}".format(
2296 pci_devices_info, vmname_andid
2297 )
2298 )
2299 PCI_devices_status, _, _ = self.add_pci_devices(
2300 vapp_uuid, pci_devices_info, vmname_andid
2301 )
2302
beierl26fec002019-12-06 17:06:40 -05002303 if PCI_devices_status:
sousaedu80135b92021-02-17 15:05:18 +01002304 self.logger.info(
2305 "Added PCI devives {} to VM {}".format(
2306 pci_devices_info, vmname_andid
2307 )
2308 )
kateac1e3792017-04-01 02:16:39 -07002309 reserve_memory = True
bhangarefda5f7c2017-01-12 23:50:34 -08002310 else:
sousaedu80135b92021-02-17 15:05:18 +01002311 self.logger.info(
2312 "Fail to add PCI devives {} to VM {}".format(
2313 pci_devices_info, vmname_andid
2314 )
2315 )
bhangare1a0b97c2017-06-21 02:20:15 -07002316
beierl26fec002019-12-06 17:06:40 -05002317 # Add serial console - this allows cloud images to boot as if we are running under OpenStack
2318 self.add_serial_device(vapp_uuid)
2319
bhangarea92ae392017-01-12 22:30:29 -08002320 if vm_disk:
beierl26fec002019-12-06 17:06:40 -05002321 # Assuming there is only one disk in ovf and fast provisioning in organization vDC is disabled
bhangarea92ae392017-01-12 22:30:29 -08002322 result = self.modify_vm_disk(vapp_uuid, vm_disk)
beierl26fec002019-12-06 17:06:40 -05002323 if result:
bhangarea92ae392017-01-12 22:30:29 -08002324 self.logger.debug("Modified Disk size of VM {} ".format(vmname_andid))
bayramovef390722016-09-27 03:34:46 -07002325
beierlb22ce2d2019-12-12 12:09:51 -05002326 # Add new or existing disks to vApp
bhangare06312472017-03-30 05:49:07 -07002327 if disk_list:
2328 added_existing_disk = False
2329 for disk in disk_list:
sousaedu80135b92021-02-17 15:05:18 +01002330 if "device_type" in disk and disk["device_type"] == "cdrom":
2331 image_id = disk["image_id"]
kasar0c007d62017-05-19 03:13:57 -07002332 # Adding CD-ROM to VM
2333 # will revisit code once specification ready to support this feature
2334 self.insert_media_to_vm(vapp, image_id)
2335 elif "image_id" in disk and disk["image_id"] is not None:
sousaedu80135b92021-02-17 15:05:18 +01002336 self.logger.debug(
2337 "Adding existing disk from image {} to vm {} ".format(
2338 disk["image_id"], vapp_uuid
2339 )
2340 )
2341 self.add_existing_disk(
2342 catalogs=catalogs,
2343 image_id=disk["image_id"],
2344 size=disk["size"],
2345 template_name=templateName,
2346 vapp_uuid=vapp_uuid,
2347 )
bhangare06312472017-03-30 05:49:07 -07002348 added_existing_disk = True
2349 else:
beierlb22ce2d2019-12-12 12:09:51 -05002350 # Wait till added existing disk gets reflected into vCD database/API
bhangare06312472017-03-30 05:49:07 -07002351 if added_existing_disk:
2352 time.sleep(5)
2353 added_existing_disk = False
sousaedu80135b92021-02-17 15:05:18 +01002354 self.add_new_disk(vapp_uuid, disk["size"])
bhangare06312472017-03-30 05:49:07 -07002355
kasarde691232017-03-25 03:37:31 -07002356 if numas:
2357 # Assigning numa affinity setting
2358 for numa in numas:
sousaedu80135b92021-02-17 15:05:18 +01002359 if "paired-threads-id" in numa:
2360 paired_threads_id = numa["paired-threads-id"]
kasarde691232017-03-25 03:37:31 -07002361 self.set_numa_affinity(vapp_uuid, paired_threads_id)
2362
bhangare0e571a92017-01-12 04:02:23 -08002363 # add NICs & connect to networks in netlist
bayramovef390722016-09-27 03:34:46 -07002364 try:
sousaedu80135b92021-02-17 15:05:18 +01002365 vdc_obj = VDC(self.client, href=vdc.get("href"))
Ravi Chamarty5b2d5c12018-10-22 23:59:10 +00002366 vapp_resource = vdc_obj.get_vapp(vmname_andid)
2367 vapp = VApp(self.client, resource=vapp_resource)
sousaedu80135b92021-02-17 15:05:18 +01002368 vapp_id = vapp_resource.get("id").split(":")[-1]
Ravi Chamarty5b2d5c12018-10-22 23:59:10 +00002369
2370 self.logger.info("Removing primary NIC: ")
2371 # First remove all NICs so that NIC properties can be adjusted as needed
2372 self.remove_primary_network_adapter_from_all_vms(vapp)
2373
kate15f1c382016-12-15 01:12:40 -08002374 self.logger.info("Request to connect VM to a network: {}".format(net_list))
bhangare0e571a92017-01-12 04:02:23 -08002375 primary_nic_index = 0
Ravi Chamarty1fdf9992018-10-07 15:45:44 +00002376 nicIndex = 0
bayramovef390722016-09-27 03:34:46 -07002377 for net in net_list:
2378 # openmano uses network id in UUID format.
2379 # vCloud Director need a name so we do reverse operation from provided UUID we lookup a name
kate15f1c382016-12-15 01:12:40 -08002380 # [{'use': 'bridge', 'net_id': '527d4bf7-566a-41e7-a9e7-ca3cdd9cef4f', 'type': 'virtual',
2381 # 'vpci': '0000:00:11.0', 'name': 'eth0'}]
2382
sousaedu80135b92021-02-17 15:05:18 +01002383 if "net_id" not in net:
kate15f1c382016-12-15 01:12:40 -08002384 continue
2385
beierlb22ce2d2019-12-12 12:09:51 -05002386 # Using net_id as a vim_id i.e. vim interface id, as do not have saperate vim interface id
2387 # Same will be returned in refresh_vms_status() as vim_interface_id
sousaedu80135b92021-02-17 15:05:18 +01002388 net["vim_id"] = net[
2389 "net_id"
2390 ] # Provide the same VIM identifier as the VIM network
tierno19860412017-10-03 10:46:46 +02002391
sousaedu80135b92021-02-17 15:05:18 +01002392 interface_net_id = net["net_id"]
2393 interface_net_name = self.get_network_name_by_id(
2394 network_uuid=interface_net_id
2395 )
2396 interface_network_mode = net["use"]
bayramovef390722016-09-27 03:34:46 -07002397
sousaedu80135b92021-02-17 15:05:18 +01002398 if interface_network_mode == "mgmt":
bhangare0e571a92017-01-12 04:02:23 -08002399 primary_nic_index = nicIndex
2400
kate15f1c382016-12-15 01:12:40 -08002401 """- POOL (A static IP address is allocated automatically from a pool of addresses.)
2402 - DHCP (The IP address is obtained from a DHCP service.)
2403 - MANUAL (The IP address is assigned manually in the IpAddress element.)
2404 - NONE (No IP addressing mode specified.)"""
2405
2406 if primary_netname is not None:
sousaedu80135b92021-02-17 15:05:18 +01002407 self.logger.debug(
2408 "new_vminstance(): Filtering by net name {}".format(
2409 interface_net_name
2410 )
2411 )
2412 nets = [
2413 n
2414 for n in self.get_network_list()
2415 if n.get("name") == interface_net_name
2416 ]
2417
bayramovef390722016-09-27 03:34:46 -07002418 if len(nets) == 1:
sousaedu80135b92021-02-17 15:05:18 +01002419 self.logger.info(
2420 "new_vminstance(): Found requested network: {}".format(
2421 nets[0].get("name")
2422 )
2423 )
bhangare1a0b97c2017-06-21 02:20:15 -07002424
Ravi Chamarty5b2d5c12018-10-22 23:59:10 +00002425 if interface_net_name != primary_netname:
2426 # connect network to VM - with all DHCP by default
sousaedu80135b92021-02-17 15:05:18 +01002427 self.logger.info(
2428 "new_vminstance(): Attaching net {} to vapp".format(
2429 interface_net_name
2430 )
2431 )
2432 self.connect_vapp_to_org_vdc_network(
2433 vapp_id, nets[0].get("name")
2434 )
kasar3ac5dc42017-03-15 06:28:22 -07002435
sousaedu80135b92021-02-17 15:05:18 +01002436 type_list = ("PF", "PCI-PASSTHROUGH", "VFnotShared")
2437 nic_type = "VMXNET3"
2438 if "type" in net and net["type"] not in type_list:
kasar3ac5dc42017-03-15 06:28:22 -07002439 # fetching nic type from vnf
sousaedu80135b92021-02-17 15:05:18 +01002440 if "model" in net:
2441 if net["model"] is not None:
2442 if (
2443 net["model"].lower() == "paravirt"
2444 or net["model"].lower() == "virtio"
2445 ):
2446 nic_type = "VMXNET3"
kasar204e39e2018-01-25 00:57:02 -08002447 else:
sousaedu80135b92021-02-17 15:05:18 +01002448 nic_type = net["model"]
kasar204e39e2018-01-25 00:57:02 -08002449
sousaedu80135b92021-02-17 15:05:18 +01002450 self.logger.info(
2451 "new_vminstance(): adding network adapter "
2452 "to a network {}".format(nets[0].get("name"))
2453 )
2454 self.add_network_adapter_to_vms(
2455 vapp,
2456 nets[0].get("name"),
2457 primary_nic_index,
2458 nicIndex,
2459 net,
2460 nic_type=nic_type,
2461 )
kasar3ac5dc42017-03-15 06:28:22 -07002462 else:
sousaedu80135b92021-02-17 15:05:18 +01002463 self.logger.info(
2464 "new_vminstance(): adding network adapter "
2465 "to a network {}".format(nets[0].get("name"))
2466 )
2467
2468 if net["type"] in ["SR-IOV", "VF"]:
2469 nic_type = net["type"]
2470 self.add_network_adapter_to_vms(
2471 vapp,
2472 nets[0].get("name"),
2473 primary_nic_index,
2474 nicIndex,
2475 net,
2476 nic_type=nic_type,
2477 )
bhangare0e571a92017-01-12 04:02:23 -08002478 nicIndex += 1
bayramovef390722016-09-27 03:34:46 -07002479
kasardc1f02e2017-03-25 07:20:30 -07002480 # cloud-init for ssh-key injection
2481 if cloud_config:
Ananda Baitharu319c26f2019-03-05 17:34:31 +00002482 # Create a catalog which will be carrying the config drive ISO
2483 # This catalog is deleted during vApp deletion. The catalog name carries
2484 # vApp UUID and thats how it gets identified during its deletion.
sousaedu80135b92021-02-17 15:05:18 +01002485 config_drive_catalog_name = "cfg_drv-" + vapp_uuid
2486 self.logger.info(
2487 'new_vminstance(): Creating catalog "{}" to carry config drive ISO'.format(
2488 config_drive_catalog_name
2489 )
2490 )
2491 config_drive_catalog_id = self.create_vimcatalog(
2492 org, config_drive_catalog_name
2493 )
2494
Ananda Baitharu319c26f2019-03-05 17:34:31 +00002495 if config_drive_catalog_id is None:
sousaedu80135b92021-02-17 15:05:18 +01002496 error_msg = (
2497 "new_vminstance(): Failed to create new catalog '{}' to carry the config drive "
2498 "ISO".format(config_drive_catalog_name)
2499 )
Ananda Baitharu319c26f2019-03-05 17:34:31 +00002500 raise Exception(error_msg)
2501
2502 # Create config-drive ISO
2503 _, userdata = self._create_user_data(cloud_config)
2504 # self.logger.debug('new_vminstance(): The userdata for cloud-init: {}'.format(userdata))
2505 iso_path = self.create_config_drive_iso(userdata)
sousaedu80135b92021-02-17 15:05:18 +01002506 self.logger.debug(
2507 "new_vminstance(): The ISO is successfully created. Path: {}".format(
2508 iso_path
2509 )
2510 )
Ananda Baitharu319c26f2019-03-05 17:34:31 +00002511
sousaedu80135b92021-02-17 15:05:18 +01002512 self.logger.info(
2513 "new_vminstance(): uploading iso to catalog {}".format(
2514 config_drive_catalog_name
2515 )
2516 )
Ananda Baitharu319c26f2019-03-05 17:34:31 +00002517 self.upload_iso_to_catalog(config_drive_catalog_id, iso_path)
2518 # Attach the config-drive ISO to the VM
sousaedu80135b92021-02-17 15:05:18 +01002519 self.logger.info(
2520 "new_vminstance(): Attaching the config-drive ISO to the VM"
2521 )
Ananda Baitharu319c26f2019-03-05 17:34:31 +00002522 self.insert_media_to_vm(vapp, config_drive_catalog_id)
2523 shutil.rmtree(os.path.dirname(iso_path), ignore_errors=True)
kasardc1f02e2017-03-25 07:20:30 -07002524
kateac1e3792017-04-01 02:16:39 -07002525 # If VM has PCI devices or SRIOV reserve memory for VM
2526 if reserve_memory:
Ravi Chamartye21c9cc2018-10-24 02:14:53 +00002527 self.reserve_memory_for_all_vms(vapp, memory_mb)
bhangarefda5f7c2017-01-12 23:50:34 -08002528
sousaedu80135b92021-02-17 15:05:18 +01002529 self.logger.debug(
2530 "new_vminstance(): starting power on vApp {} ".format(vmname_andid)
2531 )
bhangare1a0b97c2017-06-21 02:20:15 -07002532
kasarc5bf2932018-03-09 04:15:22 -08002533 poweron_task = self.power_on_vapp(vapp_id, vmname_andid)
2534 result = self.client.get_task_monitor().wait_for_success(task=poweron_task)
sousaedu80135b92021-02-17 15:05:18 +01002535 if result.get("status") == "success":
2536 self.logger.info(
2537 "new_vminstance(): Successfully power on "
2538 "vApp {}".format(vmname_andid)
2539 )
kasarc5bf2932018-03-09 04:15:22 -08002540 else:
sousaedu80135b92021-02-17 15:05:18 +01002541 self.logger.error(
2542 "new_vminstance(): failed to power on vApp "
2543 "{}".format(vmname_andid)
2544 )
bhangarebfdca492017-03-11 01:32:46 -08002545
Ananda Baitharu319c26f2019-03-05 17:34:31 +00002546 except Exception as exp:
2547 try:
2548 self.delete_vminstance(vapp_uuid)
2549 except Exception as exp2:
2550 self.logger.error("new_vminstance rollback fail {}".format(exp2))
bhangarebfdca492017-03-11 01:32:46 -08002551 # it might be a case if specific mandatory entry in dict is empty or some other pyVcloud exception
sousaedu80135b92021-02-17 15:05:18 +01002552 self.logger.error(
2553 "new_vminstance(): Failed create new vm instance {} with exception {}".format(
2554 name, exp
2555 )
2556 )
2557 raise vimconn.VimConnException(
2558 "new_vminstance(): Failed create new vm instance {} with exception {}".format(
2559 name, exp
2560 )
2561 )
bayramovef390722016-09-27 03:34:46 -07002562 # check if vApp deployed and if that the case return vApp UUID otherwise -1
kate13ab2c42016-12-23 01:34:24 -08002563 wait_time = 0
2564 vapp_uuid = None
2565 while wait_time <= MAX_WAIT_TIME:
bhangarebfdca492017-03-11 01:32:46 -08002566 try:
kasarc5bf2932018-03-09 04:15:22 -08002567 vapp_resource = vdc_obj.get_vapp(vmname_andid)
sbhangarea8e5b782018-06-21 02:10:03 -07002568 vapp = VApp(self.client, resource=vapp_resource)
bhangarebfdca492017-03-11 01:32:46 -08002569 except Exception as exp:
tierno72774862020-05-04 11:44:15 +00002570 raise vimconn.VimConnUnexpectedResponse(
sousaedu80135b92021-02-17 15:05:18 +01002571 "new_vminstance(): Failed to retrieve vApp {} after creation: Exception:{}".format(
2572 vmname_andid, exp
2573 )
2574 )
bhangarebfdca492017-03-11 01:32:46 -08002575
beierlb22ce2d2019-12-12 12:09:51 -05002576 # if vapp and vapp.me.deployed:
sousaedu80135b92021-02-17 15:05:18 +01002577 if vapp and vapp_resource.get("deployed") == "true":
2578 vapp_uuid = vapp_resource.get("id").split(":")[-1]
kate13ab2c42016-12-23 01:34:24 -08002579 break
2580 else:
sousaedu80135b92021-02-17 15:05:18 +01002581 self.logger.debug(
2582 "new_vminstance(): Wait for vApp {} to deploy".format(name)
2583 )
kate13ab2c42016-12-23 01:34:24 -08002584 time.sleep(INTERVAL_TIME)
2585
beierlb22ce2d2019-12-12 12:09:51 -05002586 wait_time += INTERVAL_TIME
kate13ab2c42016-12-23 01:34:24 -08002587
beierlb22ce2d2019-12-12 12:09:51 -05002588 # SET Affinity Rule for VM
2589 # Pre-requisites: User has created Hosh Groups in vCenter with respective Hosts to be used
2590 # While creating VIM account user has to pass the Host Group names in availability_zone list
2591 # "availability_zone" is a part of VIM "config" parameters
2592 # For example, in VIM config: "availability_zone":["HG_170","HG_174","HG_175"]
2593 # Host groups are referred as availability zones
2594 # With following procedure, deployed VM will be added into a VM group.
2595 # Then A VM to Host Affinity rule will be created using the VM group & Host group.
sousaedu80135b92021-02-17 15:05:18 +01002596 if availability_zone_list:
2597 self.logger.debug(
2598 "Existing Host Groups in VIM {}".format(
2599 self.config.get("availability_zone")
2600 )
2601 )
beierlb22ce2d2019-12-12 12:09:51 -05002602 # Admin access required for creating Affinity rules
sbhangarea8e5b782018-06-21 02:10:03 -07002603 client = self.connect_as_admin()
sousaedu80135b92021-02-17 15:05:18 +01002604
sbhangarea8e5b782018-06-21 02:10:03 -07002605 if not client:
sousaedu80135b92021-02-17 15:05:18 +01002606 raise vimconn.VimConnConnectionException(
2607 "Failed to connect vCD as admin"
2608 )
sbhangarea8e5b782018-06-21 02:10:03 -07002609 else:
2610 self.client = client
sousaedu80135b92021-02-17 15:05:18 +01002611
sbhangarea8e5b782018-06-21 02:10:03 -07002612 if self.client:
sousaedu80135b92021-02-17 15:05:18 +01002613 headers = {
2614 "Accept": "application/*+xml;version=27.0",
2615 "x-vcloud-authorization": self.client._session.headers[
2616 "x-vcloud-authorization"
2617 ],
2618 }
2619
beierlb22ce2d2019-12-12 12:09:51 -05002620 # Step1: Get provider vdc details from organization
sbhangarea8e5b782018-06-21 02:10:03 -07002621 pvdc_href = self.get_pvdc_for_org(self.tenant_name, headers)
2622 if pvdc_href is not None:
beierlb22ce2d2019-12-12 12:09:51 -05002623 # Step2: Found required pvdc, now get resource pool information
sbhangarea8e5b782018-06-21 02:10:03 -07002624 respool_href = self.get_resource_pool_details(pvdc_href, headers)
2625 if respool_href is None:
beierlb22ce2d2019-12-12 12:09:51 -05002626 # Raise error if respool_href not found
sousaedu80135b92021-02-17 15:05:18 +01002627 msg = "new_vminstance():Error in finding resource pool details in pvdc {}".format(
2628 pvdc_href
2629 )
sbhangarea8e5b782018-06-21 02:10:03 -07002630 self.log_message(msg)
2631
beierlb22ce2d2019-12-12 12:09:51 -05002632 # Step3: Verify requested availability zone(hostGroup) is present in vCD
sbhangarea8e5b782018-06-21 02:10:03 -07002633 # get availability Zone
sousaedu80135b92021-02-17 15:05:18 +01002634 vm_az = self.get_vm_availability_zone(
2635 availability_zone_index, availability_zone_list
2636 )
2637
sbhangarea8e5b782018-06-21 02:10:03 -07002638 # check if provided av zone(hostGroup) is present in vCD VIM
2639 status = self.check_availibility_zone(vm_az, respool_href, headers)
2640 if status is False:
sousaedu80135b92021-02-17 15:05:18 +01002641 msg = (
2642 "new_vminstance(): Error in finding availability zone(Host Group): {} in "
2643 "resource pool {} status: {}"
2644 ).format(vm_az, respool_href, status)
sbhangarea8e5b782018-06-21 02:10:03 -07002645 self.log_message(msg)
2646 else:
sousaedu80135b92021-02-17 15:05:18 +01002647 self.logger.debug(
2648 "new_vminstance(): Availability zone {} found in VIM".format(vm_az)
2649 )
sbhangarea8e5b782018-06-21 02:10:03 -07002650
beierlb22ce2d2019-12-12 12:09:51 -05002651 # Step4: Find VM group references to create vm group
sbhangarea8e5b782018-06-21 02:10:03 -07002652 vmgrp_href = self.find_vmgroup_reference(respool_href, headers)
beierlb22ce2d2019-12-12 12:09:51 -05002653 if vmgrp_href is None:
sbhangarea8e5b782018-06-21 02:10:03 -07002654 msg = "new_vminstance(): No reference to VmGroup found in resource pool"
2655 self.log_message(msg)
2656
beierlb22ce2d2019-12-12 12:09:51 -05002657 # Step5: Create a VmGroup with name az_VmGroup
sousaedu80135b92021-02-17 15:05:18 +01002658 vmgrp_name = (
2659 vm_az + "_" + name
2660 ) # Formed VM Group name = Host Group name + VM name
sbhangarea8e5b782018-06-21 02:10:03 -07002661 status = self.create_vmgroup(vmgrp_name, vmgrp_href, headers)
2662 if status is not True:
sousaedu80135b92021-02-17 15:05:18 +01002663 msg = "new_vminstance(): Error in creating VM group {}".format(
2664 vmgrp_name
2665 )
sbhangarea8e5b782018-06-21 02:10:03 -07002666 self.log_message(msg)
2667
beierlb22ce2d2019-12-12 12:09:51 -05002668 # VM Group url to add vms to vm group
2669 vmgrpname_url = self.url + "/api/admin/extension/vmGroup/name/" + vmgrp_name
sbhangarea8e5b782018-06-21 02:10:03 -07002670
beierlb22ce2d2019-12-12 12:09:51 -05002671 # Step6: Add VM to VM Group
2672 # Find VM uuid from vapp_uuid
sbhangarea8e5b782018-06-21 02:10:03 -07002673 vm_details = self.get_vapp_details_rest(vapp_uuid)
sousaedu80135b92021-02-17 15:05:18 +01002674 vm_uuid = vm_details["vmuuid"]
sbhangarea8e5b782018-06-21 02:10:03 -07002675
2676 status = self.add_vm_to_vmgroup(vm_uuid, vmgrpname_url, vmgrp_name, headers)
2677 if status is not True:
sousaedu80135b92021-02-17 15:05:18 +01002678 msg = "new_vminstance(): Error in adding VM to VM group {}".format(
2679 vmgrp_name
2680 )
sbhangarea8e5b782018-06-21 02:10:03 -07002681 self.log_message(msg)
2682
beierlb22ce2d2019-12-12 12:09:51 -05002683 # Step7: Create VM to Host affinity rule
2684 addrule_href = self.get_add_rule_reference(respool_href, headers)
sbhangarea8e5b782018-06-21 02:10:03 -07002685 if addrule_href is None:
sousaedu80135b92021-02-17 15:05:18 +01002686 msg = "new_vminstance(): Error in finding href to add rule in resource pool: {}".format(
2687 respool_href
2688 )
sbhangarea8e5b782018-06-21 02:10:03 -07002689 self.log_message(msg)
2690
sousaedu80135b92021-02-17 15:05:18 +01002691 status = self.create_vm_to_host_affinity_rule(
2692 addrule_href, vmgrp_name, vm_az, "Affinity", headers
2693 )
sbhangarea8e5b782018-06-21 02:10:03 -07002694 if status is False:
sousaedu80135b92021-02-17 15:05:18 +01002695 msg = "new_vminstance(): Error in creating affinity rule for VM {} in Host group {}".format(
2696 name, vm_az
2697 )
sbhangarea8e5b782018-06-21 02:10:03 -07002698 self.log_message(msg)
2699 else:
sousaedu80135b92021-02-17 15:05:18 +01002700 self.logger.debug(
2701 "new_vminstance(): Affinity rule created successfully. Added {} in Host group {}".format(
2702 name, vm_az
2703 )
2704 )
beierlb22ce2d2019-12-12 12:09:51 -05002705 # Reset token to a normal user to perform other operations
sbhangarea8e5b782018-06-21 02:10:03 -07002706 self.get_token()
2707
bayramovef390722016-09-27 03:34:46 -07002708 if vapp_uuid is not None:
tierno98e909c2017-10-14 13:27:03 +02002709 return vapp_uuid, None
bayramovbd6160f2016-09-28 04:12:05 +04002710 else:
sousaedu80135b92021-02-17 15:05:18 +01002711 raise vimconn.VimConnUnexpectedResponse(
2712 "new_vminstance(): Failed create new vm instance {}".format(name)
2713 )
bayramov325fa1c2016-09-08 01:42:46 -07002714
Ananda Baitharu319c26f2019-03-05 17:34:31 +00002715 def create_config_drive_iso(self, user_data):
2716 tmpdir = tempfile.mkdtemp()
sousaedu80135b92021-02-17 15:05:18 +01002717 iso_path = os.path.join(tmpdir, "ConfigDrive.iso")
2718 latest_dir = os.path.join(tmpdir, "openstack", "latest")
Ananda Baitharu319c26f2019-03-05 17:34:31 +00002719 os.makedirs(latest_dir)
sousaedu80135b92021-02-17 15:05:18 +01002720 with open(
2721 os.path.join(latest_dir, "meta_data.json"), "w"
2722 ) as meta_file_obj, open(
2723 os.path.join(latest_dir, "user_data"), "w"
2724 ) as userdata_file_obj:
Ananda Baitharu319c26f2019-03-05 17:34:31 +00002725 userdata_file_obj.write(user_data)
sousaedu80135b92021-02-17 15:05:18 +01002726 meta_file_obj.write(
2727 json.dumps(
2728 {
2729 "availability_zone": "nova",
2730 "launch_index": 0,
2731 "name": "ConfigDrive",
2732 "uuid": str(uuid.uuid4()),
2733 }
2734 )
2735 )
2736 genisoimage_cmd = (
2737 "genisoimage -J -r -V config-2 -o {iso_path} {source_dir_path}".format(
2738 iso_path=iso_path, source_dir_path=tmpdir
2739 )
2740 )
2741 self.logger.info(
2742 'create_config_drive_iso(): Creating ISO by running command "{}"'.format(
2743 genisoimage_cmd
2744 )
2745 )
2746
Ananda Baitharu319c26f2019-03-05 17:34:31 +00002747 try:
sousaedu80135b92021-02-17 15:05:18 +01002748 FNULL = open(os.devnull, "w")
Ananda Baitharu319c26f2019-03-05 17:34:31 +00002749 subprocess.check_call(genisoimage_cmd, shell=True, stdout=FNULL)
2750 except subprocess.CalledProcessError as e:
2751 shutil.rmtree(tmpdir, ignore_errors=True)
sousaedu80135b92021-02-17 15:05:18 +01002752 error_msg = "create_config_drive_iso(): Exception while running genisoimage command: {}".format(
2753 e
2754 )
Ananda Baitharu319c26f2019-03-05 17:34:31 +00002755 self.logger.error(error_msg)
2756 raise Exception(error_msg)
sousaedu80135b92021-02-17 15:05:18 +01002757
Ananda Baitharu319c26f2019-03-05 17:34:31 +00002758 return iso_path
2759
2760 def upload_iso_to_catalog(self, catalog_id, iso_file_path):
2761 if not os.path.isfile(iso_file_path):
sousaedu80135b92021-02-17 15:05:18 +01002762 error_msg = "upload_iso_to_catalog(): Given iso file is not present. Given path: {}".format(
2763 iso_file_path
2764 )
Ananda Baitharu319c26f2019-03-05 17:34:31 +00002765 self.logger.error(error_msg)
2766 raise Exception(error_msg)
sousaedu80135b92021-02-17 15:05:18 +01002767
Ananda Baitharu319c26f2019-03-05 17:34:31 +00002768 iso_file_stat = os.stat(iso_file_path)
sousaedu80135b92021-02-17 15:05:18 +01002769 xml_media_elem = """<?xml version="1.0" encoding="UTF-8"?>
Ananda Baitharu319c26f2019-03-05 17:34:31 +00002770 <Media
2771 xmlns="http://www.vmware.com/vcloud/v1.5"
2772 name="{iso_name}"
2773 size="{iso_size}"
2774 imageType="iso">
2775 <Description>ISO image for config-drive</Description>
sousaedu80135b92021-02-17 15:05:18 +01002776 </Media>""".format(
2777 iso_name=os.path.basename(iso_file_path), iso_size=iso_file_stat.st_size
2778 )
2779 headers = {
2780 "Accept": "application/*+xml;version=" + API_VERSION,
2781 "x-vcloud-authorization": self.client._session.headers[
2782 "x-vcloud-authorization"
2783 ],
2784 }
2785 headers["Content-Type"] = "application/vnd.vmware.vcloud.media+xml"
2786 catalog_href = self.url + "/api/catalog/" + catalog_id + "/action/upload"
2787 response = self.perform_request(
2788 req_type="POST", url=catalog_href, headers=headers, data=xml_media_elem
2789 )
Ananda Baitharu319c26f2019-03-05 17:34:31 +00002790
2791 if response.status_code != 201:
sousaedu80135b92021-02-17 15:05:18 +01002792 error_msg = "upload_iso_to_catalog(): Failed to POST an action/upload request to {}".format(
2793 catalog_href
2794 )
Ananda Baitharu319c26f2019-03-05 17:34:31 +00002795 self.logger.error(error_msg)
2796 raise Exception(error_msg)
2797
beierl26fec002019-12-06 17:06:40 -05002798 catalogItem = XmlElementTree.fromstring(response.text)
sousaedu80135b92021-02-17 15:05:18 +01002799 entity = [
2800 child
2801 for child in catalogItem
2802 if child.get("type") == "application/vnd.vmware.vcloud.media+xml"
2803 ][0]
2804 entity_href = entity.get("href")
Ananda Baitharu319c26f2019-03-05 17:34:31 +00002805
sousaedu80135b92021-02-17 15:05:18 +01002806 response = self.perform_request(
2807 req_type="GET", url=entity_href, headers=headers
2808 )
Ananda Baitharu319c26f2019-03-05 17:34:31 +00002809 if response.status_code != 200:
sousaedu80135b92021-02-17 15:05:18 +01002810 raise Exception(
2811 "upload_iso_to_catalog(): Failed to GET entity href {}".format(
2812 entity_href
2813 )
2814 )
Ananda Baitharu319c26f2019-03-05 17:34:31 +00002815
sousaedu80135b92021-02-17 15:05:18 +01002816 match = re.search(
2817 r'<Files>\s+?<File.+?href="(.+?)"/>\s+?</File>\s+?</Files>',
2818 response.text,
2819 re.DOTALL,
2820 )
Ananda Baitharu319c26f2019-03-05 17:34:31 +00002821 if match:
2822 media_upload_href = match.group(1)
2823 else:
sousaedu80135b92021-02-17 15:05:18 +01002824 raise Exception(
2825 "Could not parse the upload URL for the media file from the last response"
2826 )
beierl26fec002019-12-06 17:06:40 -05002827 upload_iso_task = self.get_task_from_response(response.text)
sousaedu80135b92021-02-17 15:05:18 +01002828 headers["Content-Type"] = "application/octet-stream"
2829 response = self.perform_request(
2830 req_type="PUT",
2831 url=media_upload_href,
2832 headers=headers,
2833 data=open(iso_file_path, "rb"),
2834 )
Ananda Baitharu319c26f2019-03-05 17:34:31 +00002835
2836 if response.status_code != 200:
2837 raise Exception('PUT request to "{}" failed'.format(media_upload_href))
sousaedu80135b92021-02-17 15:05:18 +01002838
Ananda Baitharub23558c2019-06-18 13:53:37 +00002839 result = self.client.get_task_monitor().wait_for_success(task=upload_iso_task)
sousaedu80135b92021-02-17 15:05:18 +01002840 if result.get("status") != "success":
2841 raise Exception(
2842 "The upload iso task failed with status {}".format(result.get("status"))
2843 )
sbhangarea8e5b782018-06-21 02:10:03 -07002844
beierlb22ce2d2019-12-12 12:09:51 -05002845 def get_vcd_availibility_zones(self, respool_href, headers):
sousaedu80135b92021-02-17 15:05:18 +01002846 """Method to find presence of av zone is VIM resource pool
sbhangarea8e5b782018-06-21 02:10:03 -07002847
sousaedu80135b92021-02-17 15:05:18 +01002848 Args:
2849 respool_href - resource pool href
2850 headers - header information
sbhangarea8e5b782018-06-21 02:10:03 -07002851
sousaedu80135b92021-02-17 15:05:18 +01002852 Returns:
2853 vcd_az - list of azone present in vCD
sbhangarea8e5b782018-06-21 02:10:03 -07002854 """
2855 vcd_az = []
beierlb22ce2d2019-12-12 12:09:51 -05002856 url = respool_href
sousaedu80135b92021-02-17 15:05:18 +01002857 resp = self.perform_request(req_type="GET", url=respool_href, headers=headers)
sbhangarea8e5b782018-06-21 02:10:03 -07002858
2859 if resp.status_code != requests.codes.ok:
sousaedu80135b92021-02-17 15:05:18 +01002860 self.logger.debug(
2861 "REST API call {} failed. Return status code {}".format(
2862 url, resp.status_code
2863 )
2864 )
sbhangarea8e5b782018-06-21 02:10:03 -07002865 else:
beierlb22ce2d2019-12-12 12:09:51 -05002866 # Get the href to hostGroups and find provided hostGroup is present in it
sbhangarea8e5b782018-06-21 02:10:03 -07002867 resp_xml = XmlElementTree.fromstring(resp.content)
2868 for child in resp_xml:
sousaedu80135b92021-02-17 15:05:18 +01002869 if "VMWProviderVdcResourcePool" in child.tag:
sbhangarea8e5b782018-06-21 02:10:03 -07002870 for schild in child:
sousaedu80135b92021-02-17 15:05:18 +01002871 if "Link" in schild.tag:
2872 if (
2873 schild.attrib.get("type")
2874 == "application/vnd.vmware.admin.vmwHostGroupsType+xml"
2875 ):
2876 hostGroup = schild.attrib.get("href")
2877 hg_resp = self.perform_request(
2878 req_type="GET", url=hostGroup, headers=headers
2879 )
2880
sbhangarea8e5b782018-06-21 02:10:03 -07002881 if hg_resp.status_code != requests.codes.ok:
sousaedu80135b92021-02-17 15:05:18 +01002882 self.logger.debug(
2883 "REST API call {} failed. Return status code {}".format(
2884 hostGroup, hg_resp.status_code
2885 )
2886 )
sbhangarea8e5b782018-06-21 02:10:03 -07002887 else:
sousaedu80135b92021-02-17 15:05:18 +01002888 hg_resp_xml = XmlElementTree.fromstring(
2889 hg_resp.content
2890 )
sbhangarea8e5b782018-06-21 02:10:03 -07002891 for hostGroup in hg_resp_xml:
sousaedu80135b92021-02-17 15:05:18 +01002892 if "HostGroup" in hostGroup.tag:
beierlb22ce2d2019-12-12 12:09:51 -05002893 # append host group name to the list
sbhangarea8e5b782018-06-21 02:10:03 -07002894 vcd_az.append(hostGroup.attrib.get("name"))
sousaedu80135b92021-02-17 15:05:18 +01002895
sbhangarea8e5b782018-06-21 02:10:03 -07002896 return vcd_az
2897
sbhangarea8e5b782018-06-21 02:10:03 -07002898 def set_availability_zones(self):
2899 """
2900 Set vim availability zone
2901 """
sbhangarea8e5b782018-06-21 02:10:03 -07002902 vim_availability_zones = None
2903 availability_zone = None
sousaedu80135b92021-02-17 15:05:18 +01002904
2905 if "availability_zone" in self.config:
2906 vim_availability_zones = self.config.get("availability_zone")
2907
sbhangarea8e5b782018-06-21 02:10:03 -07002908 if isinstance(vim_availability_zones, str):
2909 availability_zone = [vim_availability_zones]
2910 elif isinstance(vim_availability_zones, list):
2911 availability_zone = vim_availability_zones
2912 else:
2913 return availability_zone
2914
2915 return availability_zone
2916
sbhangarea8e5b782018-06-21 02:10:03 -07002917 def get_vm_availability_zone(self, availability_zone_index, availability_zone_list):
2918 """
2919 Return the availability zone to be used by the created VM.
2920 returns: The VIM availability zone to be used or None
2921 """
2922 if availability_zone_index is None:
sousaedu80135b92021-02-17 15:05:18 +01002923 if not self.config.get("availability_zone"):
sbhangarea8e5b782018-06-21 02:10:03 -07002924 return None
sousaedu80135b92021-02-17 15:05:18 +01002925 elif isinstance(self.config.get("availability_zone"), str):
2926 return self.config["availability_zone"]
sbhangarea8e5b782018-06-21 02:10:03 -07002927 else:
sousaedu80135b92021-02-17 15:05:18 +01002928 return self.config["availability_zone"][0]
sbhangarea8e5b782018-06-21 02:10:03 -07002929
2930 vim_availability_zones = self.availability_zone
2931
2932 # check if VIM offer enough availability zones describe in the VNFD
sousaedu80135b92021-02-17 15:05:18 +01002933 if vim_availability_zones and len(availability_zone_list) <= len(
2934 vim_availability_zones
2935 ):
sbhangarea8e5b782018-06-21 02:10:03 -07002936 # check if all the names of NFV AV match VIM AV names
2937 match_by_index = False
2938 for av in availability_zone_list:
2939 if av not in vim_availability_zones:
2940 match_by_index = True
2941 break
sousaedu80135b92021-02-17 15:05:18 +01002942
sbhangarea8e5b782018-06-21 02:10:03 -07002943 if match_by_index:
sousaedu80135b92021-02-17 15:05:18 +01002944 self.logger.debug(
2945 "Required Availability zone or Host Group not found in VIM config"
2946 )
2947 self.logger.debug(
2948 "Input Availability zone list: {}".format(availability_zone_list)
2949 )
2950 self.logger.debug(
2951 "VIM configured Availability zones: {}".format(
2952 vim_availability_zones
2953 )
2954 )
sbhangarea8e5b782018-06-21 02:10:03 -07002955 self.logger.debug("VIM Availability zones will be used by index")
2956 return vim_availability_zones[availability_zone_index]
2957 else:
2958 return availability_zone_list[availability_zone_index]
2959 else:
sousaedu80135b92021-02-17 15:05:18 +01002960 raise vimconn.VimConnConflictException(
2961 "No enough availability zones at VIM for this deployment"
2962 )
sbhangarea8e5b782018-06-21 02:10:03 -07002963
sousaedu80135b92021-02-17 15:05:18 +01002964 def create_vm_to_host_affinity_rule(
2965 self, addrule_href, vmgrpname, hostgrpname, polarity, headers
2966 ):
2967 """Method to create VM to Host Affinity rule in vCD
sbhangarea8e5b782018-06-21 02:10:03 -07002968
2969 Args:
2970 addrule_href - href to make a POST request
2971 vmgrpname - name of the VM group created
2972 hostgrpnmae - name of the host group created earlier
2973 polarity - Affinity or Anti-affinity (default: Affinity)
2974 headers - headers to make REST call
2975
2976 Returns:
2977 True- if rule is created
2978 False- Failed to create rule due to some error
2979
2980 """
2981 task_status = False
2982 rule_name = polarity + "_" + vmgrpname
2983 payload = """<?xml version="1.0" encoding="UTF-8"?>
2984 <vmext:VMWVmHostAffinityRule
2985 xmlns:vmext="http://www.vmware.com/vcloud/extension/v1.5"
2986 xmlns:vcloud="http://www.vmware.com/vcloud/v1.5"
2987 type="application/vnd.vmware.admin.vmwVmHostAffinityRule+xml">
2988 <vcloud:Name>{}</vcloud:Name>
2989 <vcloud:IsEnabled>true</vcloud:IsEnabled>
2990 <vcloud:IsMandatory>true</vcloud:IsMandatory>
2991 <vcloud:Polarity>{}</vcloud:Polarity>
2992 <vmext:HostGroupName>{}</vmext:HostGroupName>
2993 <vmext:VmGroupName>{}</vmext:VmGroupName>
sousaedu80135b92021-02-17 15:05:18 +01002994 </vmext:VMWVmHostAffinityRule>""".format(
2995 rule_name, polarity, hostgrpname, vmgrpname
2996 )
sbhangarea8e5b782018-06-21 02:10:03 -07002997
sousaedu80135b92021-02-17 15:05:18 +01002998 resp = self.perform_request(
2999 req_type="POST", url=addrule_href, headers=headers, data=payload
3000 )
sbhangarea8e5b782018-06-21 02:10:03 -07003001
3002 if resp.status_code != requests.codes.accepted:
sousaedu80135b92021-02-17 15:05:18 +01003003 self.logger.debug(
3004 "REST API call {} failed. Return status code {}".format(
3005 addrule_href, resp.status_code
3006 )
3007 )
sbhangarea8e5b782018-06-21 02:10:03 -07003008 task_status = False
sousaedu80135b92021-02-17 15:05:18 +01003009
sbhangarea8e5b782018-06-21 02:10:03 -07003010 return task_status
3011 else:
3012 affinity_task = self.get_task_from_response(resp.content)
beierlb22ce2d2019-12-12 12:09:51 -05003013 self.logger.debug("affinity_task: {}".format(affinity_task))
sousaedu80135b92021-02-17 15:05:18 +01003014
sbhangarea8e5b782018-06-21 02:10:03 -07003015 if affinity_task is None or affinity_task is False:
tierno72774862020-05-04 11:44:15 +00003016 raise vimconn.VimConnUnexpectedResponse("failed to find affinity task")
sbhangarea8e5b782018-06-21 02:10:03 -07003017 # wait for task to complete
3018 result = self.client.get_task_monitor().wait_for_success(task=affinity_task)
sousaedu80135b92021-02-17 15:05:18 +01003019
3020 if result.get("status") == "success":
3021 self.logger.debug(
3022 "Successfully created affinity rule {}".format(rule_name)
3023 )
sbhangarea8e5b782018-06-21 02:10:03 -07003024 return True
3025 else:
tierno72774862020-05-04 11:44:15 +00003026 raise vimconn.VimConnUnexpectedResponse(
sousaedu80135b92021-02-17 15:05:18 +01003027 "failed to create affinity rule {}".format(rule_name)
3028 )
sbhangarea8e5b782018-06-21 02:10:03 -07003029
beierlb22ce2d2019-12-12 12:09:51 -05003030 def get_add_rule_reference(self, respool_href, headers):
sousaedu80135b92021-02-17 15:05:18 +01003031 """This method finds href to add vm to host affinity rule to vCD
sbhangarea8e5b782018-06-21 02:10:03 -07003032
3033 Args:
3034 respool_href- href to resource pool
3035 headers- header information to make REST call
3036
3037 Returns:
3038 None - if no valid href to add rule found or
3039 addrule_href - href to add vm to host affinity rule of resource pool
3040 """
3041 addrule_href = None
sousaedu80135b92021-02-17 15:05:18 +01003042 resp = self.perform_request(req_type="GET", url=respool_href, headers=headers)
sbhangarea8e5b782018-06-21 02:10:03 -07003043
3044 if resp.status_code != requests.codes.ok:
sousaedu80135b92021-02-17 15:05:18 +01003045 self.logger.debug(
3046 "REST API call {} failed. Return status code {}".format(
3047 respool_href, resp.status_code
3048 )
3049 )
sbhangarea8e5b782018-06-21 02:10:03 -07003050 else:
sbhangarea8e5b782018-06-21 02:10:03 -07003051 resp_xml = XmlElementTree.fromstring(resp.content)
3052 for child in resp_xml:
sousaedu80135b92021-02-17 15:05:18 +01003053 if "VMWProviderVdcResourcePool" in child.tag:
sbhangarea8e5b782018-06-21 02:10:03 -07003054 for schild in child:
sousaedu80135b92021-02-17 15:05:18 +01003055 if "Link" in schild.tag:
3056 if (
3057 schild.attrib.get("type")
3058 == "application/vnd.vmware.admin.vmwVmHostAffinityRule+xml"
3059 and schild.attrib.get("rel") == "add"
3060 ):
3061 addrule_href = schild.attrib.get("href")
sbhangarea8e5b782018-06-21 02:10:03 -07003062 break
3063
3064 return addrule_href
3065
sbhangarea8e5b782018-06-21 02:10:03 -07003066 def add_vm_to_vmgroup(self, vm_uuid, vmGroupNameURL, vmGroup_name, headers):
sousaedu80135b92021-02-17 15:05:18 +01003067 """Method to add deployed VM to newly created VM Group.
sbhangarea8e5b782018-06-21 02:10:03 -07003068 This is required to create VM to Host affinity in vCD
3069
3070 Args:
3071 vm_uuid- newly created vm uuid
3072 vmGroupNameURL- URL to VM Group name
3073 vmGroup_name- Name of VM group created
3074 headers- Headers for REST request
3075
3076 Returns:
3077 True- if VM added to VM group successfully
3078 False- if any error encounter
3079 """
sousaedu80135b92021-02-17 15:05:18 +01003080 addvm_resp = self.perform_request(
3081 req_type="GET", url=vmGroupNameURL, headers=headers
3082 ) # , data=payload)
sbhangarea8e5b782018-06-21 02:10:03 -07003083
3084 if addvm_resp.status_code != requests.codes.ok:
sousaedu80135b92021-02-17 15:05:18 +01003085 self.logger.debug(
3086 "REST API call to get VM Group Name url {} failed. Return status code {}".format(
3087 vmGroupNameURL, addvm_resp.status_code
3088 )
3089 )
sbhangarea8e5b782018-06-21 02:10:03 -07003090 return False
3091 else:
3092 resp_xml = XmlElementTree.fromstring(addvm_resp.content)
3093 for child in resp_xml:
sousaedu80135b92021-02-17 15:05:18 +01003094 if child.tag.split("}")[1] == "Link":
sbhangarea8e5b782018-06-21 02:10:03 -07003095 if child.attrib.get("rel") == "addVms":
beierlb22ce2d2019-12-12 12:09:51 -05003096 addvmtogrpURL = child.attrib.get("href")
sbhangarea8e5b782018-06-21 02:10:03 -07003097
beierlb22ce2d2019-12-12 12:09:51 -05003098 # Get vm details
sousaedu80135b92021-02-17 15:05:18 +01003099 url_list = [self.url, "/api/vApp/vm-", vm_uuid]
3100 vmdetailsURL = "".join(url_list)
sbhangarea8e5b782018-06-21 02:10:03 -07003101
sousaedu80135b92021-02-17 15:05:18 +01003102 resp = self.perform_request(req_type="GET", url=vmdetailsURL, headers=headers)
sbhangarea8e5b782018-06-21 02:10:03 -07003103
3104 if resp.status_code != requests.codes.ok:
sousaedu80135b92021-02-17 15:05:18 +01003105 self.logger.debug(
3106 "REST API call {} failed. Return status code {}".format(
3107 vmdetailsURL, resp.status_code
3108 )
3109 )
sbhangarea8e5b782018-06-21 02:10:03 -07003110 return False
3111
beierlb22ce2d2019-12-12 12:09:51 -05003112 # Parse VM details
sbhangarea8e5b782018-06-21 02:10:03 -07003113 resp_xml = XmlElementTree.fromstring(resp.content)
sousaedu80135b92021-02-17 15:05:18 +01003114 if resp_xml.tag.split("}")[1] == "Vm":
sbhangarea8e5b782018-06-21 02:10:03 -07003115 vm_id = resp_xml.attrib.get("id")
3116 vm_name = resp_xml.attrib.get("name")
3117 vm_href = resp_xml.attrib.get("href")
beierlb22ce2d2019-12-12 12:09:51 -05003118 # print vm_id, vm_name, vm_href
sousaedu80135b92021-02-17 15:05:18 +01003119
beierlb22ce2d2019-12-12 12:09:51 -05003120 # Add VM into VMgroup
sbhangarea8e5b782018-06-21 02:10:03 -07003121 payload = """<?xml version="1.0" encoding="UTF-8"?>\
3122 <ns2:Vms xmlns:ns2="http://www.vmware.com/vcloud/v1.5" \
3123 xmlns="http://www.vmware.com/vcloud/versions" \
3124 xmlns:ns3="http://schemas.dmtf.org/ovf/envelope/1" \
3125 xmlns:ns4="http://schemas.dmtf.org/wbem/wscim/1/cim-schema/2/CIM_VirtualSystemSettingData" \
3126 xmlns:ns5="http://schemas.dmtf.org/wbem/wscim/1/common" \
3127 xmlns:ns6="http://schemas.dmtf.org/wbem/wscim/1/cim-schema/2/CIM_ResourceAllocationSettingData" \
3128 xmlns:ns7="http://www.vmware.com/schema/ovf" \
3129 xmlns:ns8="http://schemas.dmtf.org/ovf/environment/1" \
3130 xmlns:ns9="http://www.vmware.com/vcloud/extension/v1.5">\
3131 <ns2:VmReference href="{}" id="{}" name="{}" \
3132 type="application/vnd.vmware.vcloud.vm+xml" />\
sousaedu80135b92021-02-17 15:05:18 +01003133 </ns2:Vms>""".format(
3134 vm_href, vm_id, vm_name
3135 )
sbhangarea8e5b782018-06-21 02:10:03 -07003136
sousaedu80135b92021-02-17 15:05:18 +01003137 addvmtogrp_resp = self.perform_request(
3138 req_type="POST", url=addvmtogrpURL, headers=headers, data=payload
3139 )
sbhangarea8e5b782018-06-21 02:10:03 -07003140
3141 if addvmtogrp_resp.status_code != requests.codes.accepted:
sousaedu80135b92021-02-17 15:05:18 +01003142 self.logger.debug(
3143 "REST API call {} failed. Return status code {}".format(
3144 addvmtogrpURL, addvmtogrp_resp.status_code
3145 )
3146 )
3147
sbhangarea8e5b782018-06-21 02:10:03 -07003148 return False
3149 else:
sousaedu80135b92021-02-17 15:05:18 +01003150 self.logger.debug(
3151 "Done adding VM {} to VMgroup {}".format(vm_name, vmGroup_name)
3152 )
3153
sbhangarea8e5b782018-06-21 02:10:03 -07003154 return True
3155
sbhangarea8e5b782018-06-21 02:10:03 -07003156 def create_vmgroup(self, vmgroup_name, vmgroup_href, headers):
3157 """Method to create a VM group in vCD
3158
sousaedu80135b92021-02-17 15:05:18 +01003159 Args:
3160 vmgroup_name : Name of VM group to be created
3161 vmgroup_href : href for vmgroup
3162 headers- Headers for REST request
sbhangarea8e5b782018-06-21 02:10:03 -07003163 """
beierlb22ce2d2019-12-12 12:09:51 -05003164 # POST to add URL with required data
sbhangarea8e5b782018-06-21 02:10:03 -07003165 vmgroup_status = False
3166 payload = """<VMWVmGroup xmlns="http://www.vmware.com/vcloud/extension/v1.5" \
3167 xmlns:vcloud_v1.5="http://www.vmware.com/vcloud/v1.5" name="{}">\
3168 <vmCount>1</vmCount>\
sousaedu80135b92021-02-17 15:05:18 +01003169 </VMWVmGroup>""".format(
3170 vmgroup_name
3171 )
3172 resp = self.perform_request(
3173 req_type="POST", url=vmgroup_href, headers=headers, data=payload
3174 )
sbhangarea8e5b782018-06-21 02:10:03 -07003175
3176 if resp.status_code != requests.codes.accepted:
sousaedu80135b92021-02-17 15:05:18 +01003177 self.logger.debug(
3178 "REST API call {} failed. Return status code {}".format(
3179 vmgroup_href, resp.status_code
3180 )
3181 )
3182
sbhangarea8e5b782018-06-21 02:10:03 -07003183 return vmgroup_status
3184 else:
3185 vmgroup_task = self.get_task_from_response(resp.content)
3186 if vmgroup_task is None or vmgroup_task is False:
tierno72774862020-05-04 11:44:15 +00003187 raise vimconn.VimConnUnexpectedResponse(
sousaedu80135b92021-02-17 15:05:18 +01003188 "create_vmgroup(): failed to create VM group {}".format(
3189 vmgroup_name
3190 )
3191 )
sbhangarea8e5b782018-06-21 02:10:03 -07003192
3193 # wait for task to complete
3194 result = self.client.get_task_monitor().wait_for_success(task=vmgroup_task)
3195
sousaedu80135b92021-02-17 15:05:18 +01003196 if result.get("status") == "success":
3197 self.logger.debug(
3198 "create_vmgroup(): Successfully created VM group {}".format(
3199 vmgroup_name
3200 )
3201 )
beierlb22ce2d2019-12-12 12:09:51 -05003202 # time.sleep(10)
sbhangarea8e5b782018-06-21 02:10:03 -07003203 vmgroup_status = True
sousaedu80135b92021-02-17 15:05:18 +01003204
sbhangarea8e5b782018-06-21 02:10:03 -07003205 return vmgroup_status
3206 else:
tierno72774862020-05-04 11:44:15 +00003207 raise vimconn.VimConnUnexpectedResponse(
sousaedu80135b92021-02-17 15:05:18 +01003208 "create_vmgroup(): failed to create VM group {}".format(
3209 vmgroup_name
3210 )
3211 )
sbhangarea8e5b782018-06-21 02:10:03 -07003212
3213 def find_vmgroup_reference(self, url, headers):
sousaedu80135b92021-02-17 15:05:18 +01003214 """Method to create a new VMGroup which is required to add created VM
3215 Args:
3216 url- resource pool href
3217 headers- header information
sbhangarea8e5b782018-06-21 02:10:03 -07003218
sousaedu80135b92021-02-17 15:05:18 +01003219 Returns:
3220 returns href to VM group to create VM group
sbhangarea8e5b782018-06-21 02:10:03 -07003221 """
beierlb22ce2d2019-12-12 12:09:51 -05003222 # Perform GET on resource pool to find 'add' link to create VMGroup
3223 # https://vcd-ip/api/admin/extension/providervdc/<providervdc id>/resourcePools
sbhangarea8e5b782018-06-21 02:10:03 -07003224 vmgrp_href = None
sousaedu80135b92021-02-17 15:05:18 +01003225 resp = self.perform_request(req_type="GET", url=url, headers=headers)
sbhangarea8e5b782018-06-21 02:10:03 -07003226
3227 if resp.status_code != requests.codes.ok:
sousaedu80135b92021-02-17 15:05:18 +01003228 self.logger.debug(
3229 "REST API call {} failed. Return status code {}".format(
3230 url, resp.status_code
3231 )
3232 )
sbhangarea8e5b782018-06-21 02:10:03 -07003233 else:
beierlb22ce2d2019-12-12 12:09:51 -05003234 # Get the href to add vmGroup to vCD
sbhangarea8e5b782018-06-21 02:10:03 -07003235 resp_xml = XmlElementTree.fromstring(resp.content)
3236 for child in resp_xml:
sousaedu80135b92021-02-17 15:05:18 +01003237 if "VMWProviderVdcResourcePool" in child.tag:
sbhangarea8e5b782018-06-21 02:10:03 -07003238 for schild in child:
sousaedu80135b92021-02-17 15:05:18 +01003239 if "Link" in schild.tag:
beierlb22ce2d2019-12-12 12:09:51 -05003240 # Find href with type VMGroup and rel with add
sousaedu80135b92021-02-17 15:05:18 +01003241 if (
3242 schild.attrib.get("type")
3243 == "application/vnd.vmware.admin.vmwVmGroupType+xml"
3244 and schild.attrib.get("rel") == "add"
3245 ):
3246 vmgrp_href = schild.attrib.get("href")
3247
sbhangarea8e5b782018-06-21 02:10:03 -07003248 return vmgrp_href
3249
sbhangarea8e5b782018-06-21 02:10:03 -07003250 def check_availibility_zone(self, az, respool_href, headers):
sousaedu80135b92021-02-17 15:05:18 +01003251 """Method to verify requested av zone is present or not in provided
3252 resource pool
sbhangarea8e5b782018-06-21 02:10:03 -07003253
sousaedu80135b92021-02-17 15:05:18 +01003254 Args:
3255 az - name of hostgroup (availibility_zone)
3256 respool_href - Resource Pool href
3257 headers - Headers to make REST call
3258 Returns:
3259 az_found - True if availibility_zone is found else False
sbhangarea8e5b782018-06-21 02:10:03 -07003260 """
3261 az_found = False
sousaedu80135b92021-02-17 15:05:18 +01003262 headers["Accept"] = "application/*+xml;version=27.0"
3263 resp = self.perform_request(req_type="GET", url=respool_href, headers=headers)
sbhangarea8e5b782018-06-21 02:10:03 -07003264
3265 if resp.status_code != requests.codes.ok:
sousaedu80135b92021-02-17 15:05:18 +01003266 self.logger.debug(
3267 "REST API call {} failed. Return status code {}".format(
3268 respool_href, resp.status_code
3269 )
3270 )
sbhangarea8e5b782018-06-21 02:10:03 -07003271 else:
beierlb22ce2d2019-12-12 12:09:51 -05003272 # Get the href to hostGroups and find provided hostGroup is present in it
sbhangarea8e5b782018-06-21 02:10:03 -07003273 resp_xml = XmlElementTree.fromstring(resp.content)
3274
3275 for child in resp_xml:
sousaedu80135b92021-02-17 15:05:18 +01003276 if "VMWProviderVdcResourcePool" in child.tag:
sbhangarea8e5b782018-06-21 02:10:03 -07003277 for schild in child:
sousaedu80135b92021-02-17 15:05:18 +01003278 if "Link" in schild.tag:
3279 if (
3280 schild.attrib.get("type")
3281 == "application/vnd.vmware.admin.vmwHostGroupsType+xml"
3282 ):
3283 hostGroup_href = schild.attrib.get("href")
3284 hg_resp = self.perform_request(
3285 req_type="GET", url=hostGroup_href, headers=headers
3286 )
3287
sbhangarea8e5b782018-06-21 02:10:03 -07003288 if hg_resp.status_code != requests.codes.ok:
beierlb22ce2d2019-12-12 12:09:51 -05003289 self.logger.debug(
sousaedu80135b92021-02-17 15:05:18 +01003290 "REST API call {} failed. Return status code {}".format(
3291 hostGroup_href, hg_resp.status_code
3292 )
3293 )
sbhangarea8e5b782018-06-21 02:10:03 -07003294 else:
sousaedu80135b92021-02-17 15:05:18 +01003295 hg_resp_xml = XmlElementTree.fromstring(
3296 hg_resp.content
3297 )
sbhangarea8e5b782018-06-21 02:10:03 -07003298 for hostGroup in hg_resp_xml:
sousaedu80135b92021-02-17 15:05:18 +01003299 if "HostGroup" in hostGroup.tag:
sbhangarea8e5b782018-06-21 02:10:03 -07003300 if hostGroup.attrib.get("name") == az:
3301 az_found = True
3302 break
sousaedu80135b92021-02-17 15:05:18 +01003303
sbhangarea8e5b782018-06-21 02:10:03 -07003304 return az_found
3305
sbhangarea8e5b782018-06-21 02:10:03 -07003306 def get_pvdc_for_org(self, org_vdc, headers):
sousaedu80135b92021-02-17 15:05:18 +01003307 """This method gets provider vdc references from organisation
sbhangarea8e5b782018-06-21 02:10:03 -07003308
sousaedu80135b92021-02-17 15:05:18 +01003309 Args:
3310 org_vdc - name of the organisation VDC to find pvdc
3311 headers - headers to make REST call
sbhangarea8e5b782018-06-21 02:10:03 -07003312
sousaedu80135b92021-02-17 15:05:18 +01003313 Returns:
3314 None - if no pvdc href found else
3315 pvdc_href - href to pvdc
sbhangarea8e5b782018-06-21 02:10:03 -07003316 """
beierlb22ce2d2019-12-12 12:09:51 -05003317 # Get provider VDC references from vCD
sbhangarea8e5b782018-06-21 02:10:03 -07003318 pvdc_href = None
beierlb22ce2d2019-12-12 12:09:51 -05003319 # url = '<vcd url>/api/admin/extension/providerVdcReferences'
sousaedu80135b92021-02-17 15:05:18 +01003320 url_list = [self.url, "/api/admin/extension/providerVdcReferences"]
3321 url = "".join(url_list)
sbhangarea8e5b782018-06-21 02:10:03 -07003322
sousaedu80135b92021-02-17 15:05:18 +01003323 response = self.perform_request(req_type="GET", url=url, headers=headers)
sbhangarea8e5b782018-06-21 02:10:03 -07003324 if response.status_code != requests.codes.ok:
sousaedu80135b92021-02-17 15:05:18 +01003325 self.logger.debug(
3326 "REST API call {} failed. Return status code {}".format(
3327 url, response.status_code
3328 )
3329 )
sbhangarea8e5b782018-06-21 02:10:03 -07003330 else:
beierl26fec002019-12-06 17:06:40 -05003331 xmlroot_response = XmlElementTree.fromstring(response.text)
sbhangarea8e5b782018-06-21 02:10:03 -07003332 for child in xmlroot_response:
sousaedu80135b92021-02-17 15:05:18 +01003333 if "ProviderVdcReference" in child.tag:
3334 pvdc_href = child.attrib.get("href")
beierlb22ce2d2019-12-12 12:09:51 -05003335 # Get vdcReferences to find org
sousaedu80135b92021-02-17 15:05:18 +01003336 pvdc_resp = self.perform_request(
3337 req_type="GET", url=pvdc_href, headers=headers
3338 )
3339
sbhangarea8e5b782018-06-21 02:10:03 -07003340 if pvdc_resp.status_code != requests.codes.ok:
sousaedu80135b92021-02-17 15:05:18 +01003341 raise vimconn.VimConnException(
3342 "REST API call {} failed. "
3343 "Return status code {}".format(url, pvdc_resp.status_code)
3344 )
sbhangarea8e5b782018-06-21 02:10:03 -07003345
3346 pvdc_resp_xml = XmlElementTree.fromstring(pvdc_resp.content)
3347 for child in pvdc_resp_xml:
sousaedu80135b92021-02-17 15:05:18 +01003348 if "Link" in child.tag:
3349 if (
3350 child.attrib.get("type")
3351 == "application/vnd.vmware.admin.vdcReferences+xml"
3352 ):
3353 vdc_href = child.attrib.get("href")
sbhangarea8e5b782018-06-21 02:10:03 -07003354
beierlb22ce2d2019-12-12 12:09:51 -05003355 # Check if provided org is present in vdc
sousaedu80135b92021-02-17 15:05:18 +01003356 vdc_resp = self.perform_request(
3357 req_type="GET", url=vdc_href, headers=headers
3358 )
3359
sbhangarea8e5b782018-06-21 02:10:03 -07003360 if vdc_resp.status_code != requests.codes.ok:
sousaedu80135b92021-02-17 15:05:18 +01003361 raise vimconn.VimConnException(
3362 "REST API call {} failed. "
3363 "Return status code {}".format(
3364 url, vdc_resp.status_code
3365 )
3366 )
3367 vdc_resp_xml = XmlElementTree.fromstring(
3368 vdc_resp.content
3369 )
3370
sbhangarea8e5b782018-06-21 02:10:03 -07003371 for child in vdc_resp_xml:
sousaedu80135b92021-02-17 15:05:18 +01003372 if "VdcReference" in child.tag:
3373 if child.attrib.get("name") == org_vdc:
sbhangarea8e5b782018-06-21 02:10:03 -07003374 return pvdc_href
3375
sbhangarea8e5b782018-06-21 02:10:03 -07003376 def get_resource_pool_details(self, pvdc_href, headers):
sousaedu80135b92021-02-17 15:05:18 +01003377 """Method to get resource pool information.
3378 Host groups are property of resource group.
3379 To get host groups, we need to GET details of resource pool.
sbhangarea8e5b782018-06-21 02:10:03 -07003380
sousaedu80135b92021-02-17 15:05:18 +01003381 Args:
3382 pvdc_href: href to pvdc details
3383 headers: headers
sbhangarea8e5b782018-06-21 02:10:03 -07003384
sousaedu80135b92021-02-17 15:05:18 +01003385 Returns:
3386 respool_href - Returns href link reference to resource pool
sbhangarea8e5b782018-06-21 02:10:03 -07003387 """
3388 respool_href = None
sousaedu80135b92021-02-17 15:05:18 +01003389 resp = self.perform_request(req_type="GET", url=pvdc_href, headers=headers)
sbhangarea8e5b782018-06-21 02:10:03 -07003390
3391 if resp.status_code != requests.codes.ok:
sousaedu80135b92021-02-17 15:05:18 +01003392 self.logger.debug(
3393 "REST API call {} failed. Return status code {}".format(
3394 pvdc_href, resp.status_code
3395 )
3396 )
sbhangarea8e5b782018-06-21 02:10:03 -07003397 else:
3398 respool_resp_xml = XmlElementTree.fromstring(resp.content)
3399 for child in respool_resp_xml:
sousaedu80135b92021-02-17 15:05:18 +01003400 if "Link" in child.tag:
3401 if (
3402 child.attrib.get("type")
3403 == "application/vnd.vmware.admin.vmwProviderVdcResourcePoolSet+xml"
3404 ):
sbhangarea8e5b782018-06-21 02:10:03 -07003405 respool_href = child.attrib.get("href")
3406 break
sousaedu80135b92021-02-17 15:05:18 +01003407
sbhangarea8e5b782018-06-21 02:10:03 -07003408 return respool_href
3409
sbhangarea8e5b782018-06-21 02:10:03 -07003410 def log_message(self, msg):
3411 """
sousaedu80135b92021-02-17 15:05:18 +01003412 Method to log error messages related to Affinity rule creation
3413 in new_vminstance & raise Exception
3414 Args :
3415 msg - Error message to be logged
sbhangarea8e5b782018-06-21 02:10:03 -07003416
3417 """
beierlb22ce2d2019-12-12 12:09:51 -05003418 # get token to connect vCD as a normal user
sbhangarea8e5b782018-06-21 02:10:03 -07003419 self.get_token()
3420 self.logger.debug(msg)
sousaedu80135b92021-02-17 15:05:18 +01003421
tierno72774862020-05-04 11:44:15 +00003422 raise vimconn.VimConnException(msg)
sbhangarea8e5b782018-06-21 02:10:03 -07003423
beierlb22ce2d2019-12-12 12:09:51 -05003424 # #
3425 # #
3426 # # based on current discussion
3427 # #
3428 # #
3429 # # server:
bayramovef390722016-09-27 03:34:46 -07003430 # created: '2016-09-08T11:51:58'
3431 # description: simple-instance.linux1.1
3432 # flavor: ddc6776e-75a9-11e6-ad5f-0800273e724c
3433 # hostId: e836c036-74e7-11e6-b249-0800273e724c
3434 # image: dde30fe6-75a9-11e6-ad5f-0800273e724c
3435 # status: ACTIVE
3436 # error_msg:
3437 # interfaces: …
3438 #
bayramovfe3f3c92016-10-04 07:53:41 +04003439 def get_vminstance(self, vim_vm_uuid=None):
bayramov5761ad12016-10-04 09:00:30 +04003440 """Returns the VM instance information from VIM"""
bayramovef390722016-09-27 03:34:46 -07003441 self.logger.debug("Client requesting vm instance {} ".format(vim_vm_uuid))
bayramov325fa1c2016-09-08 01:42:46 -07003442
beierlb22ce2d2019-12-12 12:09:51 -05003443 _, vdc = self.get_vdc_details()
bayramovef390722016-09-27 03:34:46 -07003444 if vdc is None:
tierno72774862020-05-04 11:44:15 +00003445 raise vimconn.VimConnConnectionException(
sousaedu80135b92021-02-17 15:05:18 +01003446 "Failed to get a reference of VDC for a tenant {}".format(
3447 self.tenant_name
3448 )
3449 )
bayramov325fa1c2016-09-08 01:42:46 -07003450
bayramovfe3f3c92016-10-04 07:53:41 +04003451 vm_info_dict = self.get_vapp_details_rest(vapp_uuid=vim_vm_uuid)
3452 if not vm_info_dict:
sousaedu80135b92021-02-17 15:05:18 +01003453 self.logger.debug(
3454 "get_vminstance(): Failed to get vApp name by UUID {}".format(
3455 vim_vm_uuid
3456 )
3457 )
3458 raise vimconn.VimConnNotFoundException(
3459 "Failed to get vApp name by UUID {}".format(vim_vm_uuid)
3460 )
bayramov325fa1c2016-09-08 01:42:46 -07003461
sousaedu80135b92021-02-17 15:05:18 +01003462 status_key = vm_info_dict["status"]
3463 error = ""
bayramovef390722016-09-27 03:34:46 -07003464 try:
sousaedu80135b92021-02-17 15:05:18 +01003465 vm_dict = {
3466 "created": vm_info_dict["created"],
3467 "description": vm_info_dict["name"],
3468 "status": vcdStatusCode2manoFormat[int(status_key)],
3469 "hostId": vm_info_dict["vmuuid"],
3470 "error_msg": error,
3471 "vim_info": yaml.safe_dump(vm_info_dict),
3472 "interfaces": [],
3473 }
bayramovef390722016-09-27 03:34:46 -07003474
sousaedu80135b92021-02-17 15:05:18 +01003475 if "interfaces" in vm_info_dict:
3476 vm_dict["interfaces"] = vm_info_dict["interfaces"]
bayramovfe3f3c92016-10-04 07:53:41 +04003477 else:
sousaedu80135b92021-02-17 15:05:18 +01003478 vm_dict["interfaces"] = []
bayramovfe3f3c92016-10-04 07:53:41 +04003479 except KeyError:
sousaedu80135b92021-02-17 15:05:18 +01003480 vm_dict = {
3481 "created": "",
3482 "description": "",
3483 "status": vcdStatusCode2manoFormat[int(-1)],
3484 "hostId": vm_info_dict["vmuuid"],
3485 "error_msg": "Inconsistency state",
3486 "vim_info": yaml.safe_dump(vm_info_dict),
3487 "interfaces": [],
3488 }
bayramovef390722016-09-27 03:34:46 -07003489
3490 return vm_dict
3491
garciadeblase634e9e2022-06-30 13:57:43 +02003492 def delete_vminstance(self, vm_id, created_items=None, volumes_to_hold=None):
bayramovef390722016-09-27 03:34:46 -07003493 """Method poweroff and remove VM instance from vcloud director network.
3494
3495 Args:
garciadeblase634e9e2022-06-30 13:57:43 +02003496 vm_id: VM UUID
bayramovef390722016-09-27 03:34:46 -07003497
3498 Returns:
3499 Returns the instance identifier
3500 """
garciadeblase634e9e2022-06-30 13:57:43 +02003501 self.logger.debug("Client requesting delete vm instance {} ".format(vm_id))
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:
garciadeblase634e9e2022-06-30 13:57:43 +02003518 vapp_name = self.get_namebyvappid(vm_id)
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(
garciadeblase634e9e2022-06-30 13:57:43 +02003522 vm_id
sousaedu80135b92021-02-17 15:05:18 +01003523 )
3524 )
3525
3526 return (
3527 -1,
3528 "delete_vminstance(): Failed to get vm by given {} vm uuid".format(
garciadeblase634e9e2022-06-30 13:57:43 +02003529 vm_id
sousaedu80135b92021-02-17 15:05:18 +01003530 ),
3531 )
3532
garciadeblase634e9e2022-06-30 13:57:43 +02003533 self.logger.info("Deleting vApp {} and UUID {}".format(vapp_name, vm_id))
Ravi Chamarty41840092018-10-31 16:12:38 +00003534 vapp_resource = vdc_obj.get_vapp(vapp_name)
3535 vapp = VApp(self.client, resource=vapp_resource)
bayramov325fa1c2016-09-08 01:42:46 -07003536
bayramovef390722016-09-27 03:34:46 -07003537 # Delete vApp and wait for status change if task executed and vApp is None.
kate13ab2c42016-12-23 01:34:24 -08003538 if vapp:
sousaedu80135b92021-02-17 15:05:18 +01003539 if vapp_resource.get("deployed") == "true":
kate13ab2c42016-12-23 01:34:24 -08003540 self.logger.info("Powering off vApp {}".format(vapp_name))
beierl01bd6692019-12-09 17:06:20 -05003541 # Power off vApp
kate13ab2c42016-12-23 01:34:24 -08003542 powered_off = False
3543 wait_time = 0
sousaedu80135b92021-02-17 15:05:18 +01003544
kate13ab2c42016-12-23 01:34:24 -08003545 while wait_time <= MAX_WAIT_TIME:
kasarc5bf2932018-03-09 04:15:22 -08003546 power_off_task = vapp.power_off()
sousaedu80135b92021-02-17 15:05:18 +01003547 result = self.client.get_task_monitor().wait_for_success(
3548 task=power_off_task
3549 )
bayramovef390722016-09-27 03:34:46 -07003550
sousaedu80135b92021-02-17 15:05:18 +01003551 if result.get("status") == "success":
kasarc5bf2932018-03-09 04:15:22 -08003552 powered_off = True
3553 break
kate13ab2c42016-12-23 01:34:24 -08003554 else:
sousaedu80135b92021-02-17 15:05:18 +01003555 self.logger.info(
3556 "Wait for vApp {} to power off".format(vapp_name)
3557 )
kate13ab2c42016-12-23 01:34:24 -08003558 time.sleep(INTERVAL_TIME)
3559
beierl01bd6692019-12-09 17:06:20 -05003560 wait_time += INTERVAL_TIME
sousaedu80135b92021-02-17 15:05:18 +01003561
kate13ab2c42016-12-23 01:34:24 -08003562 if not powered_off:
beierl01bd6692019-12-09 17:06:20 -05003563 self.logger.debug(
sousaedu80135b92021-02-17 15:05:18 +01003564 "delete_vminstance(): Failed to power off VM instance {} ".format(
garciadeblase634e9e2022-06-30 13:57:43 +02003565 vm_id
sousaedu80135b92021-02-17 15:05:18 +01003566 )
3567 )
kate13ab2c42016-12-23 01:34:24 -08003568 else:
sousaedu80135b92021-02-17 15:05:18 +01003569 self.logger.info(
3570 "delete_vminstance(): Powered off VM instance {} ".format(
garciadeblase634e9e2022-06-30 13:57:43 +02003571 vm_id
sousaedu80135b92021-02-17 15:05:18 +01003572 )
3573 )
kate13ab2c42016-12-23 01:34:24 -08003574
beierl01bd6692019-12-09 17:06:20 -05003575 # Undeploy vApp
kate13ab2c42016-12-23 01:34:24 -08003576 self.logger.info("Undeploy vApp {}".format(vapp_name))
3577 wait_time = 0
3578 undeployed = False
3579 while wait_time <= MAX_WAIT_TIME:
sbhangarea8e5b782018-06-21 02:10:03 -07003580 vapp = VApp(self.client, resource=vapp_resource)
kate13ab2c42016-12-23 01:34:24 -08003581 if not vapp:
beierl01bd6692019-12-09 17:06:20 -05003582 self.logger.debug(
sousaedu80135b92021-02-17 15:05:18 +01003583 "delete_vminstance(): Failed to get vm by given {} vm uuid".format(
garciadeblase634e9e2022-06-30 13:57:43 +02003584 vm_id
sousaedu80135b92021-02-17 15:05:18 +01003585 )
3586 )
kate13ab2c42016-12-23 01:34:24 -08003587
sousaedu80135b92021-02-17 15:05:18 +01003588 return (
3589 -1,
3590 "delete_vminstance(): Failed to get vm by given {} vm uuid".format(
garciadeblase634e9e2022-06-30 13:57:43 +02003591 vm_id
sousaedu80135b92021-02-17 15:05:18 +01003592 ),
3593 )
3594
3595 undeploy_task = vapp.undeploy()
3596 result = self.client.get_task_monitor().wait_for_success(
3597 task=undeploy_task
3598 )
3599
3600 if result.get("status") == "success":
kasarc5bf2932018-03-09 04:15:22 -08003601 undeployed = True
3602 break
kate13ab2c42016-12-23 01:34:24 -08003603 else:
sousaedu80135b92021-02-17 15:05:18 +01003604 self.logger.debug(
3605 "Wait for vApp {} to undeploy".format(vapp_name)
3606 )
kate13ab2c42016-12-23 01:34:24 -08003607 time.sleep(INTERVAL_TIME)
3608
beierl01bd6692019-12-09 17:06:20 -05003609 wait_time += INTERVAL_TIME
kate13ab2c42016-12-23 01:34:24 -08003610
3611 if not undeployed:
sousaedu80135b92021-02-17 15:05:18 +01003612 self.logger.debug(
3613 "delete_vminstance(): Failed to undeploy vApp {} ".format(
garciadeblase634e9e2022-06-30 13:57:43 +02003614 vm_id
sousaedu80135b92021-02-17 15:05:18 +01003615 )
3616 )
kate13ab2c42016-12-23 01:34:24 -08003617
3618 # delete vapp
3619 self.logger.info("Start deletion of vApp {} ".format(vapp_name))
kate13ab2c42016-12-23 01:34:24 -08003620 if vapp is not None:
3621 wait_time = 0
3622 result = False
3623
3624 while wait_time <= MAX_WAIT_TIME:
kasarc5bf2932018-03-09 04:15:22 -08003625 vapp = VApp(self.client, resource=vapp_resource)
kate13ab2c42016-12-23 01:34:24 -08003626 if not vapp:
beierl01bd6692019-12-09 17:06:20 -05003627 self.logger.debug(
sousaedu80135b92021-02-17 15:05:18 +01003628 "delete_vminstance(): Failed to get vm by given {} vm uuid".format(
garciadeblase634e9e2022-06-30 13:57:43 +02003629 vm_id
sousaedu80135b92021-02-17 15:05:18 +01003630 )
3631 )
3632
3633 return (
3634 -1,
3635 "delete_vminstance(): Failed to get vm by given {} vm uuid".format(
garciadeblase634e9e2022-06-30 13:57:43 +02003636 vm_id
sousaedu80135b92021-02-17 15:05:18 +01003637 ),
3638 )
kate13ab2c42016-12-23 01:34:24 -08003639
kasarc5bf2932018-03-09 04:15:22 -08003640 delete_task = vdc_obj.delete_vapp(vapp.name, force=True)
sousaedu80135b92021-02-17 15:05:18 +01003641 result = self.client.get_task_monitor().wait_for_success(
3642 task=delete_task
3643 )
3644 if result.get("status") == "success":
kasarc5bf2932018-03-09 04:15:22 -08003645 break
kate13ab2c42016-12-23 01:34:24 -08003646 else:
sousaedu80135b92021-02-17 15:05:18 +01003647 self.logger.debug(
3648 "Wait for vApp {} to delete".format(vapp_name)
3649 )
kate13ab2c42016-12-23 01:34:24 -08003650 time.sleep(INTERVAL_TIME)
3651
beierl01bd6692019-12-09 17:06:20 -05003652 wait_time += INTERVAL_TIME
kate13ab2c42016-12-23 01:34:24 -08003653
kasarc5bf2932018-03-09 04:15:22 -08003654 if result is None:
sousaedu80135b92021-02-17 15:05:18 +01003655 self.logger.debug(
garciadeblase634e9e2022-06-30 13:57:43 +02003656 "delete_vminstance(): Failed delete uuid {} ".format(vm_id)
sousaedu80135b92021-02-17 15:05:18 +01003657 )
kasarc5bf2932018-03-09 04:15:22 -08003658 else:
sousaedu80135b92021-02-17 15:05:18 +01003659 self.logger.info(
garciadeblase634e9e2022-06-30 13:57:43 +02003660 "Deleted vm instance {} successfully".format(vm_id)
sousaedu80135b92021-02-17 15:05:18 +01003661 )
3662 config_drive_catalog_name, config_drive_catalog_id = (
garciadeblase634e9e2022-06-30 13:57:43 +02003663 "cfg_drv-" + vm_id,
sousaedu80135b92021-02-17 15:05:18 +01003664 None,
3665 )
Ananda Baitharu319c26f2019-03-05 17:34:31 +00003666 catalog_list = self.get_image_list()
sousaedu80135b92021-02-17 15:05:18 +01003667
Ananda Baitharu319c26f2019-03-05 17:34:31 +00003668 try:
sousaedu80135b92021-02-17 15:05:18 +01003669 config_drive_catalog_id = [
3670 catalog_["id"]
3671 for catalog_ in catalog_list
3672 if catalog_["name"] == config_drive_catalog_name
3673 ][0]
Ananda Baitharu319c26f2019-03-05 17:34:31 +00003674 except IndexError:
3675 pass
sousaedu80135b92021-02-17 15:05:18 +01003676
Ananda Baitharu319c26f2019-03-05 17:34:31 +00003677 if config_drive_catalog_id:
sousaedu80135b92021-02-17 15:05:18 +01003678 self.logger.debug(
3679 "delete_vminstance(): Found a config drive catalog {} matching "
3680 'vapp_name"{}". Deleting it.'.format(
3681 config_drive_catalog_id, vapp_name
3682 )
3683 )
Ananda Baitharu319c26f2019-03-05 17:34:31 +00003684 self.delete_image(config_drive_catalog_id)
sousaedu80135b92021-02-17 15:05:18 +01003685
garciadeblase634e9e2022-06-30 13:57:43 +02003686 return vm_id
beierl01bd6692019-12-09 17:06:20 -05003687 except Exception:
bayramovef390722016-09-27 03:34:46 -07003688 self.logger.debug(traceback.format_exc())
sousaedu80135b92021-02-17 15:05:18 +01003689
3690 raise vimconn.VimConnException(
garciadeblase634e9e2022-06-30 13:57:43 +02003691 "delete_vminstance(): Failed delete vm instance {}".format(vm_id)
sousaedu80135b92021-02-17 15:05:18 +01003692 )
bayramovef390722016-09-27 03:34:46 -07003693
bayramov325fa1c2016-09-08 01:42:46 -07003694 def refresh_vms_status(self, vm_list):
bayramovef390722016-09-27 03:34:46 -07003695 """Get the status of the virtual machines and their interfaces/ports
sousaedu80135b92021-02-17 15:05:18 +01003696 Params: the list of VM identifiers
3697 Returns a dictionary with:
3698 vm_id: #VIM id of this Virtual Machine
3699 status: #Mandatory. Text with one of:
3700 # DELETED (not found at vim)
3701 # VIM_ERROR (Cannot connect to VIM, VIM response error, ...)
3702 # OTHER (Vim reported other status not understood)
3703 # ERROR (VIM indicates an ERROR status)
3704 # ACTIVE, PAUSED, SUSPENDED, INACTIVE (not running),
3705 # CREATING (on building process), ERROR
3706 # ACTIVE:NoMgmtIP (Active but any of its interface has an IP address
3707 #
3708 error_msg: #Text with VIM error message, if any. Or the VIM connection ERROR
3709 vim_info: #Text with plain information obtained from vim (yaml.safe_dump)
3710 interfaces:
3711 - vim_info: #Text with plain information obtained from vim (yaml.safe_dump)
3712 mac_address: #Text format XX:XX:XX:XX:XX:XX
3713 vim_net_id: #network id where this interface is connected
3714 vim_interface_id: #interface/port VIM id
3715 ip_address: #null, or text with IPv4, IPv6 address
bayramovef390722016-09-27 03:34:46 -07003716 """
bayramovef390722016-09-27 03:34:46 -07003717 self.logger.debug("Client requesting refresh vm status for {} ".format(vm_list))
bhangare985a1fd2017-01-31 01:53:21 -08003718
beierlb22ce2d2019-12-12 12:09:51 -05003719 _, vdc = self.get_vdc_details()
bayramovef390722016-09-27 03:34:46 -07003720 if vdc is None:
sousaedu80135b92021-02-17 15:05:18 +01003721 raise vimconn.VimConnException(
3722 "Failed to get a reference of VDC for a tenant {}".format(
3723 self.tenant_name
3724 )
3725 )
bayramovef390722016-09-27 03:34:46 -07003726
3727 vms_dict = {}
kasarde691232017-03-25 03:37:31 -07003728 nsx_edge_list = []
bayramovef390722016-09-27 03:34:46 -07003729 for vmuuid in vm_list:
kasarc5bf2932018-03-09 04:15:22 -08003730 vapp_name = self.get_namebyvappid(vmuuid)
3731 if vapp_name is not None:
bayramovef390722016-09-27 03:34:46 -07003732 try:
bhangare1a0b97c2017-06-21 02:20:15 -07003733 vm_pci_details = self.get_vm_pci_details(vmuuid)
sousaedu80135b92021-02-17 15:05:18 +01003734 vdc_obj = VDC(self.client, href=vdc.get("href"))
kasarc5bf2932018-03-09 04:15:22 -08003735 vapp_resource = vdc_obj.get_vapp(vapp_name)
3736 the_vapp = VApp(self.client, resource=vapp_resource)
bhangarebfdca492017-03-11 01:32:46 -08003737
kasarc5bf2932018-03-09 04:15:22 -08003738 vm_details = {}
3739 for vm in the_vapp.get_all_vms():
sousaedu80135b92021-02-17 15:05:18 +01003740 headers = {
3741 "Accept": "application/*+xml;version=" + API_VERSION,
3742 "x-vcloud-authorization": self.client._session.headers[
3743 "x-vcloud-authorization"
3744 ],
3745 }
3746 response = self.perform_request(
3747 req_type="GET", url=vm.get("href"), headers=headers
3748 )
bhangarebfdca492017-03-11 01:32:46 -08003749
kasarc5bf2932018-03-09 04:15:22 -08003750 if response.status_code != 200:
sousaedu80135b92021-02-17 15:05:18 +01003751 self.logger.error(
3752 "refresh_vms_status : REST call {} failed reason : {}"
3753 "status code : {}".format(
3754 vm.get("href"), response.text, response.status_code
3755 )
3756 )
3757 raise vimconn.VimConnException(
3758 "refresh_vms_status : Failed to get VM details"
3759 )
kasarde691232017-03-25 03:37:31 -07003760
sousaedu80135b92021-02-17 15:05:18 +01003761 xmlroot = XmlElementTree.fromstring(response.text)
beierl26fec002019-12-06 17:06:40 -05003762 result = response.text.replace("\n", " ")
beierlb22ce2d2019-12-12 12:09:51 -05003763 hdd_match = re.search(
sousaedu80135b92021-02-17 15:05:18 +01003764 'vcloud:capacity="(\d+)"\svcloud:storageProfileOverrideVmDefault=',
3765 result,
3766 )
3767
Ravi Chamarty1fdf9992018-10-07 15:45:44 +00003768 if hdd_match:
3769 hdd_mb = hdd_match.group(1)
sousaedu80135b92021-02-17 15:05:18 +01003770 vm_details["hdd_mb"] = int(hdd_mb) if hdd_mb else None
3771
beierlb22ce2d2019-12-12 12:09:51 -05003772 cpus_match = re.search(
sousaedu80135b92021-02-17 15:05:18 +01003773 "<rasd:Description>Number of Virtual CPUs</.*?>(\d+)</rasd:VirtualQuantity>",
3774 result,
3775 )
3776
Ravi Chamarty1fdf9992018-10-07 15:45:44 +00003777 if cpus_match:
3778 cpus = cpus_match.group(1)
sousaedu80135b92021-02-17 15:05:18 +01003779 vm_details["cpus"] = int(cpus) if cpus else None
3780
beierlb22ce2d2019-12-12 12:09:51 -05003781 memory_mb = re.search(
sousaedu80135b92021-02-17 15:05:18 +01003782 "<rasd:Description>Memory Size</.*?>(\d+)</rasd:VirtualQuantity>",
3783 result,
3784 ).group(1)
3785 vm_details["memory_mb"] = int(memory_mb) if memory_mb else None
3786 vm_details["status"] = vcdStatusCode2manoFormat[
3787 int(xmlroot.get("status"))
3788 ]
3789 vm_details["id"] = xmlroot.get("id")
3790 vm_details["name"] = xmlroot.get("name")
kasarc5bf2932018-03-09 04:15:22 -08003791 vm_info = [vm_details]
sousaedu80135b92021-02-17 15:05:18 +01003792
kasarc5bf2932018-03-09 04:15:22 -08003793 if vm_pci_details:
sbhangarea8e5b782018-06-21 02:10:03 -07003794 vm_info[0].update(vm_pci_details)
kasarc5bf2932018-03-09 04:15:22 -08003795
sousaedu80135b92021-02-17 15:05:18 +01003796 vm_dict = {
3797 "status": vcdStatusCode2manoFormat[
3798 int(vapp_resource.get("status"))
3799 ],
3800 "error_msg": vcdStatusCode2manoFormat[
3801 int(vapp_resource.get("status"))
3802 ],
3803 "vim_info": yaml.safe_dump(vm_info),
3804 "interfaces": [],
3805 }
kasarc5bf2932018-03-09 04:15:22 -08003806
3807 # get networks
sbhangarea8e5b782018-06-21 02:10:03 -07003808 vm_ip = None
kasar1b7b9522018-05-15 06:15:07 -07003809 vm_mac = None
sousaedu80135b92021-02-17 15:05:18 +01003810 networks = re.findall(
3811 "<NetworkConnection needsCustomization=.*?</NetworkConnection>",
3812 result,
3813 )
3814
kasar1b7b9522018-05-15 06:15:07 -07003815 for network in networks:
sousaedu80135b92021-02-17 15:05:18 +01003816 mac_s = re.search("<MACAddress>(.*?)</MACAddress>", network)
kasar1b7b9522018-05-15 06:15:07 -07003817 vm_mac = mac_s.group(1) if mac_s else None
sousaedu80135b92021-02-17 15:05:18 +01003818 ip_s = re.search("<IpAddress>(.*?)</IpAddress>", network)
kasar1b7b9522018-05-15 06:15:07 -07003819 vm_ip = ip_s.group(1) if ip_s else None
kasarc5bf2932018-03-09 04:15:22 -08003820
kasar1b7b9522018-05-15 06:15:07 -07003821 if vm_ip is None:
3822 if not nsx_edge_list:
3823 nsx_edge_list = self.get_edge_details()
3824 if nsx_edge_list is None:
sousaedu80135b92021-02-17 15:05:18 +01003825 raise vimconn.VimConnException(
3826 "refresh_vms_status:"
3827 "Failed to get edge details from NSX Manager"
3828 )
3829
kasar1b7b9522018-05-15 06:15:07 -07003830 if vm_mac is not None:
sousaedu80135b92021-02-17 15:05:18 +01003831 vm_ip = self.get_ipaddr_from_NSXedge(
3832 nsx_edge_list, vm_mac
3833 )
kasarc5bf2932018-03-09 04:15:22 -08003834
beierlb22ce2d2019-12-12 12:09:51 -05003835 net_s = re.search('network="(.*?)"', network)
kasarabac1e22018-05-17 02:44:39 -07003836 network_name = net_s.group(1) if net_s else None
kasar1b7b9522018-05-15 06:15:07 -07003837 vm_net_id = self.get_network_id_by_name(network_name)
sousaedu80135b92021-02-17 15:05:18 +01003838 interface = {
3839 "mac_address": vm_mac,
3840 "vim_net_id": vm_net_id,
3841 "vim_interface_id": vm_net_id,
3842 "ip_address": vm_ip,
3843 }
kasar1b7b9522018-05-15 06:15:07 -07003844 vm_dict["interfaces"].append(interface)
kasarc5bf2932018-03-09 04:15:22 -08003845
bayramovef390722016-09-27 03:34:46 -07003846 # add a vm to vm dict
3847 vms_dict.setdefault(vmuuid, vm_dict)
kasarc5bf2932018-03-09 04:15:22 -08003848 self.logger.debug("refresh_vms_status : vm info {}".format(vm_dict))
bhangarebfdca492017-03-11 01:32:46 -08003849 except Exception as exp:
3850 self.logger.debug("Error in response {}".format(exp))
bayramovef390722016-09-27 03:34:46 -07003851 self.logger.debug(traceback.format_exc())
3852
3853 return vms_dict
3854
kasarde691232017-03-25 03:37:31 -07003855 def get_edge_details(self):
3856 """Get the NSX edge list from NSX Manager
sousaedu80135b92021-02-17 15:05:18 +01003857 Returns list of NSX edges
kasarde691232017-03-25 03:37:31 -07003858 """
3859 edge_list = []
sousaedu80135b92021-02-17 15:05:18 +01003860 rheaders = {"Content-Type": "application/xml"}
3861 nsx_api_url = "/api/4.0/edges"
kasarde691232017-03-25 03:37:31 -07003862
sousaedu80135b92021-02-17 15:05:18 +01003863 self.logger.debug(
3864 "Get edge details from NSX Manager {} {}".format(
3865 self.nsx_manager, nsx_api_url
3866 )
3867 )
kasarde691232017-03-25 03:37:31 -07003868
3869 try:
sousaedu80135b92021-02-17 15:05:18 +01003870 resp = requests.get(
3871 self.nsx_manager + nsx_api_url,
3872 auth=(self.nsx_user, self.nsx_password),
3873 verify=False,
3874 headers=rheaders,
3875 )
kasarde691232017-03-25 03:37:31 -07003876 if resp.status_code == requests.codes.ok:
3877 paged_Edge_List = XmlElementTree.fromstring(resp.text)
3878 for edge_pages in paged_Edge_List:
sousaedu80135b92021-02-17 15:05:18 +01003879 if edge_pages.tag == "edgePage":
kasarde691232017-03-25 03:37:31 -07003880 for edge_summary in edge_pages:
sousaedu80135b92021-02-17 15:05:18 +01003881 if edge_summary.tag == "pagingInfo":
kasarde691232017-03-25 03:37:31 -07003882 for element in edge_summary:
sousaedu80135b92021-02-17 15:05:18 +01003883 if (
3884 element.tag == "totalCount"
3885 and element.text == "0"
3886 ):
tierno72774862020-05-04 11:44:15 +00003887 raise vimconn.VimConnException(
sousaedu80135b92021-02-17 15:05:18 +01003888 "get_edge_details: No NSX edges details found: {}".format(
3889 self.nsx_manager
3890 )
3891 )
kasarde691232017-03-25 03:37:31 -07003892
sousaedu80135b92021-02-17 15:05:18 +01003893 if edge_summary.tag == "edgeSummary":
kasarde691232017-03-25 03:37:31 -07003894 for element in edge_summary:
sousaedu80135b92021-02-17 15:05:18 +01003895 if element.tag == "id":
kasarde691232017-03-25 03:37:31 -07003896 edge_list.append(element.text)
3897 else:
sousaedu80135b92021-02-17 15:05:18 +01003898 raise vimconn.VimConnException(
3899 "get_edge_details: No NSX edge details found: {}".format(
3900 self.nsx_manager
3901 )
3902 )
kasarde691232017-03-25 03:37:31 -07003903
3904 if not edge_list:
sousaedu80135b92021-02-17 15:05:18 +01003905 raise vimconn.VimConnException(
3906 "get_edge_details: "
3907 "No NSX edge details found: {}".format(self.nsx_manager)
3908 )
kasarde691232017-03-25 03:37:31 -07003909 else:
sousaedu80135b92021-02-17 15:05:18 +01003910 self.logger.debug(
3911 "get_edge_details: Found NSX edges {}".format(edge_list)
3912 )
3913
kasarde691232017-03-25 03:37:31 -07003914 return edge_list
3915 else:
sousaedu80135b92021-02-17 15:05:18 +01003916 self.logger.debug(
3917 "get_edge_details: "
3918 "Failed to get NSX edge details from NSX Manager: {}".format(
3919 resp.content
3920 )
3921 )
3922
kasarde691232017-03-25 03:37:31 -07003923 return None
3924
3925 except Exception as exp:
sousaedu80135b92021-02-17 15:05:18 +01003926 self.logger.debug(
3927 "get_edge_details: "
3928 "Failed to get NSX edge details from NSX Manager: {}".format(exp)
3929 )
3930 raise vimconn.VimConnException(
3931 "get_edge_details: "
3932 "Failed to get NSX edge details from NSX Manager: {}".format(exp)
3933 )
kasarde691232017-03-25 03:37:31 -07003934
kasarde691232017-03-25 03:37:31 -07003935 def get_ipaddr_from_NSXedge(self, nsx_edges, mac_address):
3936 """Get IP address details from NSX edges, using the MAC address
sousaedu80135b92021-02-17 15:05:18 +01003937 PARAMS: nsx_edges : List of NSX edges
3938 mac_address : Find IP address corresponding to this MAC address
3939 Returns: IP address corrresponding to the provided MAC address
kasarde691232017-03-25 03:37:31 -07003940 """
kasarde691232017-03-25 03:37:31 -07003941 ip_addr = None
sousaedu80135b92021-02-17 15:05:18 +01003942 rheaders = {"Content-Type": "application/xml"}
kasarde691232017-03-25 03:37:31 -07003943
3944 self.logger.debug("get_ipaddr_from_NSXedge: Finding IP addr from NSX edge")
3945
3946 try:
3947 for edge in nsx_edges:
sousaedu80135b92021-02-17 15:05:18 +01003948 nsx_api_url = "/api/4.0/edges/" + edge + "/dhcp/leaseInfo"
kasarde691232017-03-25 03:37:31 -07003949
sousaedu80135b92021-02-17 15:05:18 +01003950 resp = requests.get(
3951 self.nsx_manager + nsx_api_url,
3952 auth=(self.nsx_user, self.nsx_password),
3953 verify=False,
3954 headers=rheaders,
3955 )
kasarde691232017-03-25 03:37:31 -07003956
3957 if resp.status_code == requests.codes.ok:
3958 dhcp_leases = XmlElementTree.fromstring(resp.text)
3959 for child in dhcp_leases:
sousaedu80135b92021-02-17 15:05:18 +01003960 if child.tag == "dhcpLeaseInfo":
kasarde691232017-03-25 03:37:31 -07003961 dhcpLeaseInfo = child
3962 for leaseInfo in dhcpLeaseInfo:
3963 for elem in leaseInfo:
sousaedu80135b92021-02-17 15:05:18 +01003964 if (elem.tag) == "macAddress":
kasarde691232017-03-25 03:37:31 -07003965 edge_mac_addr = elem.text
sousaedu80135b92021-02-17 15:05:18 +01003966
3967 if (elem.tag) == "ipAddress":
kasarde691232017-03-25 03:37:31 -07003968 ip_addr = elem.text
sousaedu80135b92021-02-17 15:05:18 +01003969
kasarde691232017-03-25 03:37:31 -07003970 if edge_mac_addr is not None:
3971 if edge_mac_addr == mac_address:
sousaedu80135b92021-02-17 15:05:18 +01003972 self.logger.debug(
3973 "Found ip addr {} for mac {} at NSX edge {}".format(
3974 ip_addr, mac_address, edge
3975 )
3976 )
3977
kasarde691232017-03-25 03:37:31 -07003978 return ip_addr
3979 else:
sousaedu80135b92021-02-17 15:05:18 +01003980 self.logger.debug(
3981 "get_ipaddr_from_NSXedge: "
3982 "Error occurred while getting DHCP lease info from NSX Manager: {}".format(
3983 resp.content
3984 )
3985 )
kasarde691232017-03-25 03:37:31 -07003986
sousaedu80135b92021-02-17 15:05:18 +01003987 self.logger.debug(
3988 "get_ipaddr_from_NSXedge: No IP addr found in any NSX edge"
3989 )
3990
kasarde691232017-03-25 03:37:31 -07003991 return None
3992
3993 except XmlElementTree.ParseError as Err:
sousaedu80135b92021-02-17 15:05:18 +01003994 self.logger.debug(
3995 "ParseError in response from NSX Manager {}".format(Err.message),
3996 exc_info=True,
3997 )
kasarde691232017-03-25 03:37:31 -07003998
garciadeblase634e9e2022-06-30 13:57:43 +02003999 def action_vminstance(self, vm_id=None, action_dict=None, created_items={}):
bayramovef390722016-09-27 03:34:46 -07004000 """Send and action over a VM instance from VIM
4001 Returns the vm_id if the action was successfully sent to the VIM"""
4002
sousaedu80135b92021-02-17 15:05:18 +01004003 self.logger.debug(
garciadeblase634e9e2022-06-30 13:57:43 +02004004 "Received action for vm {} and action dict {}".format(vm_id, action_dict)
sousaedu80135b92021-02-17 15:05:18 +01004005 )
4006
garciadeblase634e9e2022-06-30 13:57:43 +02004007 if vm_id is None or action_dict is None:
tierno72774862020-05-04 11:44:15 +00004008 raise vimconn.VimConnException("Invalid request. VM id or action is None.")
bayramovef390722016-09-27 03:34:46 -07004009
beierlb22ce2d2019-12-12 12:09:51 -05004010 _, vdc = self.get_vdc_details()
bayramovef390722016-09-27 03:34:46 -07004011 if vdc is None:
sousaedu80135b92021-02-17 15:05:18 +01004012 raise vimconn.VimConnException(
4013 "Failed to get a reference of VDC for a tenant {}".format(
4014 self.tenant_name
4015 )
4016 )
bayramovef390722016-09-27 03:34:46 -07004017
garciadeblase634e9e2022-06-30 13:57:43 +02004018 vapp_name = self.get_namebyvappid(vm_id)
bayramovef390722016-09-27 03:34:46 -07004019 if vapp_name is None:
sousaedu80135b92021-02-17 15:05:18 +01004020 self.logger.debug(
4021 "action_vminstance(): Failed to get vm by given {} vm uuid".format(
garciadeblase634e9e2022-06-30 13:57:43 +02004022 vm_id
sousaedu80135b92021-02-17 15:05:18 +01004023 )
4024 )
4025
4026 raise vimconn.VimConnException(
garciadeblase634e9e2022-06-30 13:57:43 +02004027 "Failed to get vm by given {} vm uuid".format(vm_id)
sousaedu80135b92021-02-17 15:05:18 +01004028 )
bayramovef390722016-09-27 03:34:46 -07004029 else:
sousaedu80135b92021-02-17 15:05:18 +01004030 self.logger.info(
garciadeblase634e9e2022-06-30 13:57:43 +02004031 "Action_vminstance vApp {} and UUID {}".format(vapp_name, vm_id)
sousaedu80135b92021-02-17 15:05:18 +01004032 )
bayramovef390722016-09-27 03:34:46 -07004033
4034 try:
sousaedu80135b92021-02-17 15:05:18 +01004035 vdc_obj = VDC(self.client, href=vdc.get("href"))
kasarc5bf2932018-03-09 04:15:22 -08004036 vapp_resource = vdc_obj.get_vapp(vapp_name)
sbhangarea8e5b782018-06-21 02:10:03 -07004037 vapp = VApp(self.client, resource=vapp_resource)
sousaedu80135b92021-02-17 15:05:18 +01004038
bayramovef390722016-09-27 03:34:46 -07004039 if "start" in action_dict:
sousaedu80135b92021-02-17 15:05:18 +01004040 self.logger.info(
4041 "action_vminstance: Power on vApp: {}".format(vapp_name)
4042 )
garciadeblase634e9e2022-06-30 13:57:43 +02004043 poweron_task = self.power_on_vapp(vm_id, vapp_name)
sousaedu80135b92021-02-17 15:05:18 +01004044 result = self.client.get_task_monitor().wait_for_success(
4045 task=poweron_task
4046 )
kasarc5bf2932018-03-09 04:15:22 -08004047 self.instance_actions_result("start", result, vapp_name)
kasar3ac5dc42017-03-15 06:28:22 -07004048 elif "rebuild" in action_dict:
sousaedu80135b92021-02-17 15:05:18 +01004049 self.logger.info(
4050 "action_vminstance: Rebuild vApp: {}".format(vapp_name)
4051 )
kasarc5bf2932018-03-09 04:15:22 -08004052 rebuild_task = vapp.deploy(power_on=True)
sousaedu80135b92021-02-17 15:05:18 +01004053 result = self.client.get_task_monitor().wait_for_success(
4054 task=rebuild_task
4055 )
kasar3ac5dc42017-03-15 06:28:22 -07004056 self.instance_actions_result("rebuild", result, vapp_name)
bayramovef390722016-09-27 03:34:46 -07004057 elif "pause" in action_dict:
kasar3ac5dc42017-03-15 06:28:22 -07004058 self.logger.info("action_vminstance: pause vApp: {}".format(vapp_name))
sousaedu80135b92021-02-17 15:05:18 +01004059 pause_task = vapp.undeploy(action="suspend")
4060 result = self.client.get_task_monitor().wait_for_success(
4061 task=pause_task
4062 )
kasar3ac5dc42017-03-15 06:28:22 -07004063 self.instance_actions_result("pause", result, vapp_name)
bayramovef390722016-09-27 03:34:46 -07004064 elif "resume" in action_dict:
kasar3ac5dc42017-03-15 06:28:22 -07004065 self.logger.info("action_vminstance: resume vApp: {}".format(vapp_name))
garciadeblase634e9e2022-06-30 13:57:43 +02004066 poweron_task = self.power_on_vapp(vm_id, vapp_name)
sousaedu80135b92021-02-17 15:05:18 +01004067 result = self.client.get_task_monitor().wait_for_success(
4068 task=poweron_task
4069 )
kasar3ac5dc42017-03-15 06:28:22 -07004070 self.instance_actions_result("resume", result, vapp_name)
bayramovef390722016-09-27 03:34:46 -07004071 elif "shutoff" in action_dict or "shutdown" in action_dict:
beierlb22ce2d2019-12-12 12:09:51 -05004072 action_name, _ = list(action_dict.items())[0]
sousaedu80135b92021-02-17 15:05:18 +01004073 self.logger.info(
4074 "action_vminstance: {} vApp: {}".format(action_name, vapp_name)
4075 )
kasarc5bf2932018-03-09 04:15:22 -08004076 shutdown_task = vapp.shutdown()
sousaedu80135b92021-02-17 15:05:18 +01004077 result = self.client.get_task_monitor().wait_for_success(
4078 task=shutdown_task
4079 )
kasar3ac5dc42017-03-15 06:28:22 -07004080 if action_name == "shutdown":
4081 self.instance_actions_result("shutdown", result, vapp_name)
bhangare985a1fd2017-01-31 01:53:21 -08004082 else:
kasar3ac5dc42017-03-15 06:28:22 -07004083 self.instance_actions_result("shutoff", result, vapp_name)
bayramovef390722016-09-27 03:34:46 -07004084 elif "forceOff" in action_dict:
sousaedu80135b92021-02-17 15:05:18 +01004085 result = vapp.undeploy(action="powerOff")
kasar3ac5dc42017-03-15 06:28:22 -07004086 self.instance_actions_result("forceOff", result, vapp_name)
4087 elif "reboot" in action_dict:
4088 self.logger.info("action_vminstance: reboot vApp: {}".format(vapp_name))
kasarc5bf2932018-03-09 04:15:22 -08004089 reboot_task = vapp.reboot()
sbhangarea8e5b782018-06-21 02:10:03 -07004090 self.client.get_task_monitor().wait_for_success(task=reboot_task)
bayramovef390722016-09-27 03:34:46 -07004091 else:
tierno72774862020-05-04 11:44:15 +00004092 raise vimconn.VimConnException(
sousaedu80135b92021-02-17 15:05:18 +01004093 "action_vminstance: Invalid action {} or action is None.".format(
4094 action_dict
4095 )
4096 )
4097
garciadeblase634e9e2022-06-30 13:57:43 +02004098 return vm_id
beierlb22ce2d2019-12-12 12:09:51 -05004099 except Exception as exp:
bhangarebfdca492017-03-11 01:32:46 -08004100 self.logger.debug("action_vminstance: Failed with Exception {}".format(exp))
sousaedu80135b92021-02-17 15:05:18 +01004101
4102 raise vimconn.VimConnException(
4103 "action_vminstance: Failed with Exception {}".format(exp)
4104 )
bayramovef390722016-09-27 03:34:46 -07004105
kasar3ac5dc42017-03-15 06:28:22 -07004106 def instance_actions_result(self, action, result, vapp_name):
sousaedu80135b92021-02-17 15:05:18 +01004107 if result.get("status") == "success":
4108 self.logger.info(
4109 "action_vminstance: Sucessfully {} the vApp: {}".format(
4110 action, vapp_name
4111 )
4112 )
kasar3ac5dc42017-03-15 06:28:22 -07004113 else:
sousaedu80135b92021-02-17 15:05:18 +01004114 self.logger.error(
4115 "action_vminstance: Failed to {} vApp: {}".format(action, vapp_name)
4116 )
kasar3ac5dc42017-03-15 06:28:22 -07004117
kasarcf655072019-03-20 01:40:05 -07004118 def get_vminstance_console(self, vm_id, console_type="novnc"):
bayramovef390722016-09-27 03:34:46 -07004119 """
bayramov325fa1c2016-09-08 01:42:46 -07004120 Get a console for the virtual machine
4121 Params:
4122 vm_id: uuid of the VM
4123 console_type, can be:
bayramovef390722016-09-27 03:34:46 -07004124 "novnc" (by default), "xvpvnc" for VNC types,
bayramov325fa1c2016-09-08 01:42:46 -07004125 "rdp-html5" for RDP types, "spice-html5" for SPICE types
4126 Returns dict with the console parameters:
4127 protocol: ssh, ftp, http, https, ...
bayramovef390722016-09-27 03:34:46 -07004128 server: usually ip address
4129 port: the http, ssh, ... port
4130 suffix: extra text, e.g. the http path and query string
4131 """
kasarcf655072019-03-20 01:40:05 -07004132 console_dict = {}
4133
sousaedu80135b92021-02-17 15:05:18 +01004134 if console_type is None or console_type == "novnc":
4135 url_rest_call = "{}/api/vApp/vm-{}/screen/action/acquireMksTicket".format(
4136 self.url, vm_id
4137 )
4138 headers = {
4139 "Accept": "application/*+xml;version=" + API_VERSION,
4140 "x-vcloud-authorization": self.client._session.headers[
4141 "x-vcloud-authorization"
4142 ],
4143 }
4144 response = self.perform_request(
4145 req_type="POST", url=url_rest_call, headers=headers
4146 )
kasarcf655072019-03-20 01:40:05 -07004147
4148 if response.status_code == 403:
sousaedu80135b92021-02-17 15:05:18 +01004149 response = self.retry_rest("GET", url_rest_call)
kasarcf655072019-03-20 01:40:05 -07004150
4151 if response.status_code != 200:
sousaedu80135b92021-02-17 15:05:18 +01004152 self.logger.error(
4153 "REST call {} failed reason : {}"
4154 "status code : {}".format(
4155 url_rest_call, response.text, response.status_code
4156 )
4157 )
4158 raise vimconn.VimConnException(
4159 "get_vminstance_console : Failed to get " "VM Mks ticket details"
4160 )
4161
beierl26fec002019-12-06 17:06:40 -05004162 s = re.search("<Host>(.*?)</Host>", response.text)
sousaedu80135b92021-02-17 15:05:18 +01004163 console_dict["server"] = s.group(1) if s else None
beierl26fec002019-12-06 17:06:40 -05004164 s1 = re.search("<Port>(\d+)</Port>", response.text)
sousaedu80135b92021-02-17 15:05:18 +01004165 console_dict["port"] = s1.group(1) if s1 else None
4166 url_rest_call = "{}/api/vApp/vm-{}/screen/action/acquireTicket".format(
4167 self.url, vm_id
4168 )
4169 headers = {
4170 "Accept": "application/*+xml;version=" + API_VERSION,
4171 "x-vcloud-authorization": self.client._session.headers[
4172 "x-vcloud-authorization"
4173 ],
4174 }
4175 response = self.perform_request(
4176 req_type="POST", url=url_rest_call, headers=headers
4177 )
kasarcf655072019-03-20 01:40:05 -07004178
4179 if response.status_code == 403:
sousaedu80135b92021-02-17 15:05:18 +01004180 response = self.retry_rest("GET", url_rest_call)
kasarcf655072019-03-20 01:40:05 -07004181
4182 if response.status_code != 200:
sousaedu80135b92021-02-17 15:05:18 +01004183 self.logger.error(
4184 "REST call {} failed reason : {}"
4185 "status code : {}".format(
4186 url_rest_call, response.text, response.status_code
4187 )
4188 )
4189 raise vimconn.VimConnException(
4190 "get_vminstance_console : Failed to get " "VM console details"
4191 )
4192
beierl26fec002019-12-06 17:06:40 -05004193 s = re.search(">.*?/(vm-\d+.*)</", response.text)
sousaedu80135b92021-02-17 15:05:18 +01004194 console_dict["suffix"] = s.group(1) if s else None
4195 console_dict["protocol"] = "https"
kasarcf655072019-03-20 01:40:05 -07004196
4197 return console_dict
bayramov325fa1c2016-09-08 01:42:46 -07004198
bayramovef390722016-09-27 03:34:46 -07004199 # NOT USED METHODS in current version
bayramov325fa1c2016-09-08 01:42:46 -07004200
4201 def host_vim2gui(self, host, server_dict):
bayramov5761ad12016-10-04 09:00:30 +04004202 """Transform host dictionary from VIM format to GUI format,
bayramov325fa1c2016-09-08 01:42:46 -07004203 and append to the server_dict
bayramov5761ad12016-10-04 09:00:30 +04004204 """
tierno72774862020-05-04 11:44:15 +00004205 raise vimconn.VimConnNotImplemented("Should have implemented this")
bayramov325fa1c2016-09-08 01:42:46 -07004206
4207 def get_hosts_info(self):
bayramov5761ad12016-10-04 09:00:30 +04004208 """Get the information of deployed hosts
4209 Returns the hosts content"""
tierno72774862020-05-04 11:44:15 +00004210 raise vimconn.VimConnNotImplemented("Should have implemented this")
bayramov325fa1c2016-09-08 01:42:46 -07004211
4212 def get_hosts(self, vim_tenant):
bayramov5761ad12016-10-04 09:00:30 +04004213 """Get the hosts and deployed instances
4214 Returns the hosts content"""
tierno72774862020-05-04 11:44:15 +00004215 raise vimconn.VimConnNotImplemented("Should have implemented this")
bayramov325fa1c2016-09-08 01:42:46 -07004216
4217 def get_processor_rankings(self):
bayramov5761ad12016-10-04 09:00:30 +04004218 """Get the processor rankings in the VIM database"""
tierno72774862020-05-04 11:44:15 +00004219 raise vimconn.VimConnNotImplemented("Should have implemented this")
bayramov325fa1c2016-09-08 01:42:46 -07004220
4221 def new_host(self, host_data):
bayramov5761ad12016-10-04 09:00:30 +04004222 """Adds a new host to VIM"""
sousaedu80135b92021-02-17 15:05:18 +01004223 """Returns status code of the VIM response"""
tierno72774862020-05-04 11:44:15 +00004224 raise vimconn.VimConnNotImplemented("Should have implemented this")
bayramov325fa1c2016-09-08 01:42:46 -07004225
4226 def new_external_port(self, port_data):
bayramov5761ad12016-10-04 09:00:30 +04004227 """Adds a external port to VIM"""
sousaedu80135b92021-02-17 15:05:18 +01004228 """Returns the port identifier"""
tierno72774862020-05-04 11:44:15 +00004229 raise vimconn.VimConnNotImplemented("Should have implemented this")
bayramov325fa1c2016-09-08 01:42:46 -07004230
bayramovef390722016-09-27 03:34:46 -07004231 def new_external_network(self, net_name, net_type):
bayramov5761ad12016-10-04 09:00:30 +04004232 """Adds a external network to VIM (shared)"""
sousaedu80135b92021-02-17 15:05:18 +01004233 """Returns the network identifier"""
tierno72774862020-05-04 11:44:15 +00004234 raise vimconn.VimConnNotImplemented("Should have implemented this")
bayramov325fa1c2016-09-08 01:42:46 -07004235
4236 def connect_port_network(self, port_id, network_id, admin=False):
bayramov5761ad12016-10-04 09:00:30 +04004237 """Connects a external port to a network"""
sousaedu80135b92021-02-17 15:05:18 +01004238 """Returns status code of the VIM response"""
tierno72774862020-05-04 11:44:15 +00004239 raise vimconn.VimConnNotImplemented("Should have implemented this")
bayramov325fa1c2016-09-08 01:42:46 -07004240
4241 def new_vminstancefromJSON(self, vm_data):
bayramov5761ad12016-10-04 09:00:30 +04004242 """Adds a VM instance to VIM"""
sousaedu80135b92021-02-17 15:05:18 +01004243 """Returns the instance identifier"""
tierno72774862020-05-04 11:44:15 +00004244 raise vimconn.VimConnNotImplemented("Should have implemented this")
bayramov325fa1c2016-09-08 01:42:46 -07004245
kate15f1c382016-12-15 01:12:40 -08004246 def get_network_name_by_id(self, network_uuid=None):
bayramovef390722016-09-27 03:34:46 -07004247 """Method gets vcloud director network named based on supplied uuid.
4248
4249 Args:
kate15f1c382016-12-15 01:12:40 -08004250 network_uuid: network_id
bayramovef390722016-09-27 03:34:46 -07004251
4252 Returns:
4253 The return network name.
4254 """
4255
kate15f1c382016-12-15 01:12:40 -08004256 if not network_uuid:
bayramovef390722016-09-27 03:34:46 -07004257 return None
4258
4259 try:
kate15f1c382016-12-15 01:12:40 -08004260 org_dict = self.get_org(self.org_uuid)
sousaedu80135b92021-02-17 15:05:18 +01004261 if "networks" in org_dict:
4262 org_network_dict = org_dict["networks"]
4263
kate15f1c382016-12-15 01:12:40 -08004264 for net_uuid in org_network_dict:
4265 if net_uuid == network_uuid:
4266 return org_network_dict[net_uuid]
beierlb22ce2d2019-12-12 12:09:51 -05004267 except Exception:
bayramovef390722016-09-27 03:34:46 -07004268 self.logger.debug("Exception in get_network_name_by_id")
4269 self.logger.debug(traceback.format_exc())
4270
4271 return None
4272
bhangare2c855072016-12-27 01:41:28 -08004273 def get_network_id_by_name(self, network_name=None):
4274 """Method gets vcloud director network uuid based on supplied name.
4275
4276 Args:
4277 network_name: network_name
4278 Returns:
4279 The return network uuid.
4280 network_uuid: network_id
4281 """
bhangare2c855072016-12-27 01:41:28 -08004282 if not network_name:
4283 self.logger.debug("get_network_id_by_name() : Network name is empty")
4284 return None
4285
4286 try:
4287 org_dict = self.get_org(self.org_uuid)
sousaedu80135b92021-02-17 15:05:18 +01004288 if org_dict and "networks" in org_dict:
4289 org_network_dict = org_dict["networks"]
4290
tierno1b856002019-11-07 16:28:54 +00004291 for net_uuid, net_name in org_network_dict.items():
bhangare2c855072016-12-27 01:41:28 -08004292 if net_name == network_name:
4293 return net_uuid
4294
4295 except KeyError as exp:
4296 self.logger.debug("get_network_id_by_name() : KeyError- {} ".format(exp))
4297
4298 return None
4299
kbsuba85c54d2019-10-17 16:30:32 +00004300 def get_physical_network_by_name(self, physical_network_name):
sousaedu80135b92021-02-17 15:05:18 +01004301 """
kbsuba85c54d2019-10-17 16:30:32 +00004302 Methos returns uuid of physical network which passed
4303 Args:
4304 physical_network_name: physical network name
4305 Returns:
4306 UUID of physical_network_name
sousaedu80135b92021-02-17 15:05:18 +01004307 """
kbsuba85c54d2019-10-17 16:30:32 +00004308 try:
4309 client_as_admin = self.connect_as_admin()
sousaedu80135b92021-02-17 15:05:18 +01004310
kbsuba85c54d2019-10-17 16:30:32 +00004311 if not client_as_admin:
tierno72774862020-05-04 11:44:15 +00004312 raise vimconn.VimConnConnectionException("Failed to connect vCD.")
sousaedu80135b92021-02-17 15:05:18 +01004313
4314 url_list = [self.url, "/api/admin/vdc/", self.tenant_id]
4315 vm_list_rest_call = "".join(url_list)
kbsuba85c54d2019-10-17 16:30:32 +00004316
4317 if client_as_admin._session:
sousaedu80135b92021-02-17 15:05:18 +01004318 headers = {
4319 "Accept": "application/*+xml;version=" + API_VERSION,
4320 "x-vcloud-authorization": client_as_admin._session.headers[
4321 "x-vcloud-authorization"
4322 ],
4323 }
4324 response = self.perform_request(
4325 req_type="GET", url=vm_list_rest_call, headers=headers
4326 )
kbsuba85c54d2019-10-17 16:30:32 +00004327 provider_network = None
4328 available_network = None
beierlb22ce2d2019-12-12 12:09:51 -05004329 # add_vdc_rest_url = None
kbsuba85c54d2019-10-17 16:30:32 +00004330
4331 if response.status_code != requests.codes.ok:
sousaedu80135b92021-02-17 15:05:18 +01004332 self.logger.debug(
4333 "REST API call {} failed. Return status code {}".format(
4334 vm_list_rest_call, response.status_code
4335 )
4336 )
kbsuba85c54d2019-10-17 16:30:32 +00004337 return None
4338 else:
4339 try:
beierl26fec002019-12-06 17:06:40 -05004340 vm_list_xmlroot = XmlElementTree.fromstring(response.text)
kbsuba85c54d2019-10-17 16:30:32 +00004341 for child in vm_list_xmlroot:
sousaedu80135b92021-02-17 15:05:18 +01004342 if child.tag.split("}")[1] == "ProviderVdcReference":
4343 provider_network = child.attrib.get("href")
kbsuba85c54d2019-10-17 16:30:32 +00004344 # application/vnd.vmware.admin.providervdc+xml
sousaedu80135b92021-02-17 15:05:18 +01004345
4346 if child.tag.split("}")[1] == "Link":
4347 if (
4348 child.attrib.get("type")
4349 == "application/vnd.vmware.vcloud.orgVdcNetwork+xml"
4350 and child.attrib.get("rel") == "add"
4351 ):
4352 child.attrib.get("href")
beierlb22ce2d2019-12-12 12:09:51 -05004353 except Exception:
sousaedu80135b92021-02-17 15:05:18 +01004354 self.logger.debug(
4355 "Failed parse respond for rest api call {}".format(
4356 vm_list_rest_call
4357 )
4358 )
beierl26fec002019-12-06 17:06:40 -05004359 self.logger.debug("Respond body {}".format(response.text))
sousaedu80135b92021-02-17 15:05:18 +01004360
kbsuba85c54d2019-10-17 16:30:32 +00004361 return None
4362
4363 # find pvdc provided available network
sousaedu80135b92021-02-17 15:05:18 +01004364 response = self.perform_request(
4365 req_type="GET", url=provider_network, headers=headers
4366 )
kbsuba85c54d2019-10-17 16:30:32 +00004367
4368 if response.status_code != requests.codes.ok:
sousaedu80135b92021-02-17 15:05:18 +01004369 self.logger.debug(
4370 "REST API call {} failed. Return status code {}".format(
4371 vm_list_rest_call, response.status_code
4372 )
4373 )
4374
kbsuba85c54d2019-10-17 16:30:32 +00004375 return None
4376
4377 try:
beierl26fec002019-12-06 17:06:40 -05004378 vm_list_xmlroot = XmlElementTree.fromstring(response.text)
kbsuba85c54d2019-10-17 16:30:32 +00004379 for child in vm_list_xmlroot.iter():
sousaedu80135b92021-02-17 15:05:18 +01004380 if child.tag.split("}")[1] == "AvailableNetworks":
kbsuba85c54d2019-10-17 16:30:32 +00004381 for networks in child.iter():
sousaedu80135b92021-02-17 15:05:18 +01004382 if (
4383 networks.attrib.get("href") is not None
4384 and networks.attrib.get("name") is not None
4385 ):
4386 if (
4387 networks.attrib.get("name")
4388 == physical_network_name
4389 ):
4390 network_url = networks.attrib.get("href")
4391 available_network = network_url[
4392 network_url.rindex("/") + 1 :
4393 ]
kbsuba85c54d2019-10-17 16:30:32 +00004394 break
sousaedu80135b92021-02-17 15:05:18 +01004395 except Exception:
kbsuba85c54d2019-10-17 16:30:32 +00004396 return None
4397
4398 return available_network
4399 except Exception as e:
4400 self.logger.error("Error while getting physical network: {}".format(e))
4401
bayramovef390722016-09-27 03:34:46 -07004402 def list_org_action(self):
4403 """
4404 Method leverages vCloud director and query for available organization for particular user
4405
4406 Args:
4407 vca - is active VCA connection.
4408 vdc_name - is a vdc name that will be used to query vms action
4409
4410 Returns:
4411 The return XML respond
4412 """
sousaedu80135b92021-02-17 15:05:18 +01004413 url_list = [self.url, "/api/org"]
4414 vm_list_rest_call = "".join(url_list)
bayramovef390722016-09-27 03:34:46 -07004415
kasarc5bf2932018-03-09 04:15:22 -08004416 if self.client._session:
sousaedu80135b92021-02-17 15:05:18 +01004417 headers = {
4418 "Accept": "application/*+xml;version=" + API_VERSION,
4419 "x-vcloud-authorization": self.client._session.headers[
4420 "x-vcloud-authorization"
4421 ],
4422 }
kasarc5bf2932018-03-09 04:15:22 -08004423
sousaedu80135b92021-02-17 15:05:18 +01004424 response = self.perform_request(
4425 req_type="GET", url=vm_list_rest_call, headers=headers
4426 )
bhangare1a0b97c2017-06-21 02:20:15 -07004427
4428 if response.status_code == 403:
sousaedu80135b92021-02-17 15:05:18 +01004429 response = self.retry_rest("GET", vm_list_rest_call)
bhangare1a0b97c2017-06-21 02:20:15 -07004430
bayramovef390722016-09-27 03:34:46 -07004431 if response.status_code == requests.codes.ok:
beierl26fec002019-12-06 17:06:40 -05004432 return response.text
bayramovef390722016-09-27 03:34:46 -07004433
4434 return None
4435
4436 def get_org_action(self, org_uuid=None):
4437 """
kasarc5bf2932018-03-09 04:15:22 -08004438 Method leverages vCloud director and retrieve available object for organization.
bayramovef390722016-09-27 03:34:46 -07004439
4440 Args:
kasarc5bf2932018-03-09 04:15:22 -08004441 org_uuid - vCD organization uuid
4442 self.client - is active connection.
bayramovef390722016-09-27 03:34:46 -07004443
4444 Returns:
4445 The return XML respond
4446 """
4447
bayramovef390722016-09-27 03:34:46 -07004448 if org_uuid is None:
4449 return None
4450
sousaedu80135b92021-02-17 15:05:18 +01004451 url_list = [self.url, "/api/org/", org_uuid]
4452 vm_list_rest_call = "".join(url_list)
bayramovef390722016-09-27 03:34:46 -07004453
sbhangarea8e5b782018-06-21 02:10:03 -07004454 if self.client._session:
sousaedu80135b92021-02-17 15:05:18 +01004455 headers = {
4456 "Accept": "application/*+xml;version=" + API_VERSION,
4457 "x-vcloud-authorization": self.client._session.headers[
4458 "x-vcloud-authorization"
4459 ],
4460 }
bhangare1a0b97c2017-06-21 02:20:15 -07004461
beierlb22ce2d2019-12-12 12:09:51 -05004462 # response = requests.get(vm_list_rest_call, headers=headers, verify=False)
sousaedu80135b92021-02-17 15:05:18 +01004463 response = self.perform_request(
4464 req_type="GET", url=vm_list_rest_call, headers=headers
4465 )
4466
bhangare1a0b97c2017-06-21 02:20:15 -07004467 if response.status_code == 403:
sousaedu80135b92021-02-17 15:05:18 +01004468 response = self.retry_rest("GET", vm_list_rest_call)
bhangare1a0b97c2017-06-21 02:20:15 -07004469
bayramovef390722016-09-27 03:34:46 -07004470 if response.status_code == requests.codes.ok:
beierl26fec002019-12-06 17:06:40 -05004471 return response.text
sousaedu80135b92021-02-17 15:05:18 +01004472
bayramovef390722016-09-27 03:34:46 -07004473 return None
4474
4475 def get_org(self, org_uuid=None):
4476 """
4477 Method retrieves available organization in vCloud Director
4478
4479 Args:
bayramovb6ffe792016-09-28 11:50:56 +04004480 org_uuid - is a organization uuid.
bayramovef390722016-09-27 03:34:46 -07004481
4482 Returns:
bayramovb6ffe792016-09-28 11:50:56 +04004483 The return dictionary with following key
4484 "network" - for network list under the org
4485 "catalogs" - for network list under the org
4486 "vdcs" - for vdc list under org
bayramovef390722016-09-27 03:34:46 -07004487 """
4488
4489 org_dict = {}
bayramovef390722016-09-27 03:34:46 -07004490
4491 if org_uuid is None:
4492 return org_dict
4493
4494 content = self.get_org_action(org_uuid=org_uuid)
4495 try:
4496 vdc_list = {}
4497 network_list = {}
4498 catalog_list = {}
4499 vm_list_xmlroot = XmlElementTree.fromstring(content)
4500 for child in vm_list_xmlroot:
sousaedu80135b92021-02-17 15:05:18 +01004501 if child.attrib["type"] == "application/vnd.vmware.vcloud.vdc+xml":
4502 vdc_list[child.attrib["href"].split("/")[-1:][0]] = child.attrib[
4503 "name"
4504 ]
4505 org_dict["vdcs"] = vdc_list
4506
4507 if (
4508 child.attrib["type"]
4509 == "application/vnd.vmware.vcloud.orgNetwork+xml"
4510 ):
4511 network_list[
4512 child.attrib["href"].split("/")[-1:][0]
4513 ] = child.attrib["name"]
4514 org_dict["networks"] = network_list
4515
4516 if child.attrib["type"] == "application/vnd.vmware.vcloud.catalog+xml":
4517 catalog_list[
4518 child.attrib["href"].split("/")[-1:][0]
4519 ] = child.attrib["name"]
4520 org_dict["catalogs"] = catalog_list
beierlb22ce2d2019-12-12 12:09:51 -05004521 except Exception:
bayramovef390722016-09-27 03:34:46 -07004522 pass
4523
4524 return org_dict
4525
4526 def get_org_list(self):
4527 """
4528 Method retrieves available organization in vCloud Director
4529
4530 Args:
4531 vca - is active VCA connection.
4532
4533 Returns:
4534 The return dictionary and key for each entry VDC UUID
4535 """
bayramovef390722016-09-27 03:34:46 -07004536 org_dict = {}
bayramovef390722016-09-27 03:34:46 -07004537
4538 content = self.list_org_action()
4539 try:
4540 vm_list_xmlroot = XmlElementTree.fromstring(content)
sousaedu80135b92021-02-17 15:05:18 +01004541
bayramovef390722016-09-27 03:34:46 -07004542 for vm_xml in vm_list_xmlroot:
sousaedu80135b92021-02-17 15:05:18 +01004543 if vm_xml.tag.split("}")[1] == "Org":
4544 org_uuid = vm_xml.attrib["href"].split("/")[-1:]
4545 org_dict[org_uuid[0]] = vm_xml.attrib["name"]
beierlb22ce2d2019-12-12 12:09:51 -05004546 except Exception:
bayramovef390722016-09-27 03:34:46 -07004547 pass
4548
4549 return org_dict
4550
4551 def vms_view_action(self, vdc_name=None):
sousaedu80135b92021-02-17 15:05:18 +01004552 """Method leverages vCloud director vms query call
bayramovef390722016-09-27 03:34:46 -07004553
4554 Args:
4555 vca - is active VCA connection.
4556 vdc_name - is a vdc name that will be used to query vms action
4557
4558 Returns:
4559 The return XML respond
4560 """
4561 vca = self.connect()
4562 if vdc_name is None:
4563 return None
4564
sousaedu80135b92021-02-17 15:05:18 +01004565 url_list = [vca.host, "/api/vms/query"]
4566 vm_list_rest_call = "".join(url_list)
bayramovef390722016-09-27 03:34:46 -07004567
4568 if not (not vca.vcloud_session or not vca.vcloud_session.organization):
sousaedu80135b92021-02-17 15:05:18 +01004569 refs = [
4570 ref
4571 for ref in vca.vcloud_session.organization.Link
4572 if ref.name == vdc_name
4573 and ref.type_ == "application/vnd.vmware.vcloud.vdc+xml"
4574 ]
4575
bayramovef390722016-09-27 03:34:46 -07004576 if len(refs) == 1:
sousaedu80135b92021-02-17 15:05:18 +01004577 response = self.perform_request(
4578 req_type="GET",
4579 url=vm_list_rest_call,
4580 headers=vca.vcloud_session.get_vcloud_headers(),
4581 verify=vca.verify,
4582 logger=vca.logger,
4583 )
4584
bayramovef390722016-09-27 03:34:46 -07004585 if response.status_code == requests.codes.ok:
beierl26fec002019-12-06 17:06:40 -05004586 return response.text
bayramovef390722016-09-27 03:34:46 -07004587
4588 return None
4589
4590 def get_vapp_list(self, vdc_name=None):
4591 """
4592 Method retrieves vApp list deployed vCloud director and returns a dictionary
4593 contains a list of all vapp deployed for queried VDC.
4594 The key for a dictionary is vApp UUID
4595
4596
4597 Args:
4598 vca - is active VCA connection.
4599 vdc_name - is a vdc name that will be used to query vms action
4600
4601 Returns:
4602 The return dictionary and key for each entry vapp UUID
4603 """
bayramovef390722016-09-27 03:34:46 -07004604 vapp_dict = {}
sousaedu80135b92021-02-17 15:05:18 +01004605
bayramovef390722016-09-27 03:34:46 -07004606 if vdc_name is None:
4607 return vapp_dict
4608
4609 content = self.vms_view_action(vdc_name=vdc_name)
4610 try:
4611 vm_list_xmlroot = XmlElementTree.fromstring(content)
4612 for vm_xml in vm_list_xmlroot:
sousaedu80135b92021-02-17 15:05:18 +01004613 if vm_xml.tag.split("}")[1] == "VMRecord":
4614 if vm_xml.attrib["isVAppTemplate"] == "true":
4615 rawuuid = vm_xml.attrib["container"].split("/")[-1:]
4616 if "vappTemplate-" in rawuuid[0]:
bayramovef390722016-09-27 03:34:46 -07004617 # vm in format vappTemplate-e63d40e7-4ff5-4c6d-851f-96c1e4da86a5 we remove
4618 # vm and use raw UUID as key
4619 vapp_dict[rawuuid[0][13:]] = vm_xml.attrib
beierlb22ce2d2019-12-12 12:09:51 -05004620 except Exception:
bayramovef390722016-09-27 03:34:46 -07004621 pass
4622
4623 return vapp_dict
4624
4625 def get_vm_list(self, vdc_name=None):
4626 """
4627 Method retrieves VM's list deployed vCloud director. It returns a dictionary
4628 contains a list of all VM's deployed for queried VDC.
4629 The key for a dictionary is VM UUID
4630
4631
4632 Args:
4633 vca - is active VCA connection.
4634 vdc_name - is a vdc name that will be used to query vms action
4635
4636 Returns:
4637 The return dictionary and key for each entry vapp UUID
4638 """
4639 vm_dict = {}
4640
4641 if vdc_name is None:
4642 return vm_dict
4643
4644 content = self.vms_view_action(vdc_name=vdc_name)
4645 try:
4646 vm_list_xmlroot = XmlElementTree.fromstring(content)
4647 for vm_xml in vm_list_xmlroot:
sousaedu80135b92021-02-17 15:05:18 +01004648 if vm_xml.tag.split("}")[1] == "VMRecord":
4649 if vm_xml.attrib["isVAppTemplate"] == "false":
4650 rawuuid = vm_xml.attrib["href"].split("/")[-1:]
4651 if "vm-" in rawuuid[0]:
bayramovef390722016-09-27 03:34:46 -07004652 # vm in format vm-e63d40e7-4ff5-4c6d-851f-96c1e4da86a5 we remove
4653 # vm and use raw UUID as key
4654 vm_dict[rawuuid[0][3:]] = vm_xml.attrib
beierlb22ce2d2019-12-12 12:09:51 -05004655 except Exception:
bayramovef390722016-09-27 03:34:46 -07004656 pass
4657
4658 return vm_dict
4659
4660 def get_vapp(self, vdc_name=None, vapp_name=None, isuuid=False):
4661 """
bayramovb6ffe792016-09-28 11:50:56 +04004662 Method retrieves VM deployed vCloud director. It returns VM attribute as dictionary
bayramovef390722016-09-27 03:34:46 -07004663 contains a list of all VM's deployed for queried VDC.
4664 The key for a dictionary is VM UUID
4665
4666
4667 Args:
4668 vca - is active VCA connection.
4669 vdc_name - is a vdc name that will be used to query vms action
4670
4671 Returns:
4672 The return dictionary and key for each entry vapp UUID
4673 """
4674 vm_dict = {}
4675 vca = self.connect()
sousaedu80135b92021-02-17 15:05:18 +01004676
bayramovef390722016-09-27 03:34:46 -07004677 if not vca:
tierno72774862020-05-04 11:44:15 +00004678 raise vimconn.VimConnConnectionException("self.connect() is failed")
bayramovef390722016-09-27 03:34:46 -07004679
4680 if vdc_name is None:
4681 return vm_dict
4682
4683 content = self.vms_view_action(vdc_name=vdc_name)
4684 try:
4685 vm_list_xmlroot = XmlElementTree.fromstring(content)
4686 for vm_xml in vm_list_xmlroot:
sousaedu80135b92021-02-17 15:05:18 +01004687 if (
4688 vm_xml.tag.split("}")[1] == "VMRecord"
4689 and vm_xml.attrib["isVAppTemplate"] == "false"
4690 ):
bayramovb6ffe792016-09-28 11:50:56 +04004691 # lookup done by UUID
bayramovef390722016-09-27 03:34:46 -07004692 if isuuid:
sousaedu80135b92021-02-17 15:05:18 +01004693 if vapp_name in vm_xml.attrib["container"]:
4694 rawuuid = vm_xml.attrib["href"].split("/")[-1:]
4695 if "vm-" in rawuuid[0]:
bayramovef390722016-09-27 03:34:46 -07004696 vm_dict[rawuuid[0][3:]] = vm_xml.attrib
bayramovb6ffe792016-09-28 11:50:56 +04004697 break
4698 # lookup done by Name
4699 else:
sousaedu80135b92021-02-17 15:05:18 +01004700 if vapp_name in vm_xml.attrib["name"]:
4701 rawuuid = vm_xml.attrib["href"].split("/")[-1:]
4702 if "vm-" in rawuuid[0]:
bayramovb6ffe792016-09-28 11:50:56 +04004703 vm_dict[rawuuid[0][3:]] = vm_xml.attrib
4704 break
beierlb22ce2d2019-12-12 12:09:51 -05004705 except Exception:
bayramovef390722016-09-27 03:34:46 -07004706 pass
4707
4708 return vm_dict
4709
4710 def get_network_action(self, network_uuid=None):
4711 """
4712 Method leverages vCloud director and query network based on network uuid
4713
4714 Args:
4715 vca - is active VCA connection.
4716 network_uuid - is a network uuid
4717
4718 Returns:
4719 The return XML respond
4720 """
bayramovef390722016-09-27 03:34:46 -07004721 if network_uuid is None:
4722 return None
4723
sousaedu80135b92021-02-17 15:05:18 +01004724 url_list = [self.url, "/api/network/", network_uuid]
4725 vm_list_rest_call = "".join(url_list)
bayramovef390722016-09-27 03:34:46 -07004726
kasarc5bf2932018-03-09 04:15:22 -08004727 if self.client._session:
sousaedu80135b92021-02-17 15:05:18 +01004728 headers = {
4729 "Accept": "application/*+xml;version=" + API_VERSION,
4730 "x-vcloud-authorization": self.client._session.headers[
4731 "x-vcloud-authorization"
4732 ],
4733 }
4734 response = self.perform_request(
4735 req_type="GET", url=vm_list_rest_call, headers=headers
4736 )
bhangare1a0b97c2017-06-21 02:20:15 -07004737
beierlb22ce2d2019-12-12 12:09:51 -05004738 # Retry login if session expired & retry sending request
bhangare1a0b97c2017-06-21 02:20:15 -07004739 if response.status_code == 403:
sousaedu80135b92021-02-17 15:05:18 +01004740 response = self.retry_rest("GET", vm_list_rest_call)
bhangare1a0b97c2017-06-21 02:20:15 -07004741
bayramovef390722016-09-27 03:34:46 -07004742 if response.status_code == requests.codes.ok:
beierl26fec002019-12-06 17:06:40 -05004743 return response.text
bayramovef390722016-09-27 03:34:46 -07004744
4745 return None
4746
4747 def get_vcd_network(self, network_uuid=None):
4748 """
4749 Method retrieves available network from vCloud Director
4750
4751 Args:
4752 network_uuid - is VCD network UUID
4753
4754 Each element serialized as key : value pair
4755
4756 Following keys available for access. network_configuration['Gateway'}
4757 <Configuration>
4758 <IpScopes>
4759 <IpScope>
4760 <IsInherited>true</IsInherited>
4761 <Gateway>172.16.252.100</Gateway>
4762 <Netmask>255.255.255.0</Netmask>
4763 <Dns1>172.16.254.201</Dns1>
4764 <Dns2>172.16.254.202</Dns2>
4765 <DnsSuffix>vmwarelab.edu</DnsSuffix>
4766 <IsEnabled>true</IsEnabled>
4767 <IpRanges>
4768 <IpRange>
4769 <StartAddress>172.16.252.1</StartAddress>
4770 <EndAddress>172.16.252.99</EndAddress>
4771 </IpRange>
4772 </IpRanges>
4773 </IpScope>
4774 </IpScopes>
4775 <FenceMode>bridged</FenceMode>
4776
4777 Returns:
4778 The return dictionary and key for each entry vapp UUID
4779 """
bayramovef390722016-09-27 03:34:46 -07004780 network_configuration = {}
sousaedu80135b92021-02-17 15:05:18 +01004781
bayramovef390722016-09-27 03:34:46 -07004782 if network_uuid is None:
4783 return network_uuid
4784
bayramovef390722016-09-27 03:34:46 -07004785 try:
bhangarebfdca492017-03-11 01:32:46 -08004786 content = self.get_network_action(network_uuid=network_uuid)
kbsub3de27d62019-12-05 17:20:18 +00004787 if content is not None:
4788 vm_list_xmlroot = XmlElementTree.fromstring(content)
sousaedu80135b92021-02-17 15:05:18 +01004789 network_configuration["status"] = vm_list_xmlroot.get("status")
4790 network_configuration["name"] = vm_list_xmlroot.get("name")
4791 network_configuration["uuid"] = vm_list_xmlroot.get("id").split(":")[3]
bayramovef390722016-09-27 03:34:46 -07004792
kbsub3de27d62019-12-05 17:20:18 +00004793 for child in vm_list_xmlroot:
sousaedu80135b92021-02-17 15:05:18 +01004794 if child.tag.split("}")[1] == "IsShared":
4795 network_configuration["isShared"] = child.text.strip()
4796
4797 if child.tag.split("}")[1] == "Configuration":
kbsub3de27d62019-12-05 17:20:18 +00004798 for configuration in child.iter():
4799 tagKey = configuration.tag.split("}")[1].strip()
4800 if tagKey != "":
sousaedu80135b92021-02-17 15:05:18 +01004801 network_configuration[
4802 tagKey
4803 ] = configuration.text.strip()
beierlb22ce2d2019-12-12 12:09:51 -05004804 except Exception as exp:
bhangarebfdca492017-03-11 01:32:46 -08004805 self.logger.debug("get_vcd_network: Failed with Exception {}".format(exp))
sousaedu80135b92021-02-17 15:05:18 +01004806
4807 raise vimconn.VimConnException(
4808 "get_vcd_network: Failed with Exception {}".format(exp)
4809 )
bayramovef390722016-09-27 03:34:46 -07004810
4811 return network_configuration
4812
4813 def delete_network_action(self, network_uuid=None):
4814 """
4815 Method delete given network from vCloud director
4816
4817 Args:
4818 network_uuid - is a network uuid that client wish to delete
4819
4820 Returns:
4821 The return None or XML respond or false
4822 """
kasarc5bf2932018-03-09 04:15:22 -08004823 client = self.connect_as_admin()
sousaedu80135b92021-02-17 15:05:18 +01004824
kasarc5bf2932018-03-09 04:15:22 -08004825 if not client:
tierno72774862020-05-04 11:44:15 +00004826 raise vimconn.VimConnConnectionException("Failed to connect vCD as admin")
sousaedu80135b92021-02-17 15:05:18 +01004827
bayramovef390722016-09-27 03:34:46 -07004828 if network_uuid is None:
4829 return False
4830
sousaedu80135b92021-02-17 15:05:18 +01004831 url_list = [self.url, "/api/admin/network/", network_uuid]
4832 vm_list_rest_call = "".join(url_list)
bayramovef390722016-09-27 03:34:46 -07004833
kasarc5bf2932018-03-09 04:15:22 -08004834 if client._session:
sousaedu80135b92021-02-17 15:05:18 +01004835 headers = {
4836 "Accept": "application/*+xml;version=" + API_VERSION,
4837 "x-vcloud-authorization": client._session.headers[
4838 "x-vcloud-authorization"
4839 ],
4840 }
4841 response = self.perform_request(
4842 req_type="DELETE", url=vm_list_rest_call, headers=headers
4843 )
4844
bayramovef390722016-09-27 03:34:46 -07004845 if response.status_code == 202:
4846 return True
4847
4848 return False
4849
sousaedu80135b92021-02-17 15:05:18 +01004850 def create_network(
4851 self,
4852 network_name=None,
4853 net_type="bridge",
4854 parent_network_uuid=None,
4855 ip_profile=None,
4856 isshared="true",
4857 ):
bayramovef390722016-09-27 03:34:46 -07004858 """
4859 Method create network in vCloud director
4860
4861 Args:
4862 network_name - is network name to be created.
bhangare0e571a92017-01-12 04:02:23 -08004863 net_type - can be 'bridge','data','ptp','mgmt'.
4864 ip_profile is a dict containing the IP parameters of the network
4865 isshared - is a boolean
bayramovef390722016-09-27 03:34:46 -07004866 parent_network_uuid - is parent provider vdc network that will be used for mapping.
4867 It optional attribute. by default if no parent network indicate the first available will be used.
4868
4869 Returns:
4870 The return network uuid or return None
4871 """
sousaedu80135b92021-02-17 15:05:18 +01004872 new_network_name = [network_name, "-", str(uuid.uuid4())]
4873 content = self.create_network_rest(
4874 network_name="".join(new_network_name),
4875 ip_profile=ip_profile,
4876 net_type=net_type,
4877 parent_network_uuid=parent_network_uuid,
4878 isshared=isshared,
4879 )
bayramovef390722016-09-27 03:34:46 -07004880
bayramovef390722016-09-27 03:34:46 -07004881 if content is None:
4882 self.logger.debug("Failed create network {}.".format(network_name))
sousaedu80135b92021-02-17 15:05:18 +01004883
bayramovef390722016-09-27 03:34:46 -07004884 return None
4885
4886 try:
4887 vm_list_xmlroot = XmlElementTree.fromstring(content)
sousaedu80135b92021-02-17 15:05:18 +01004888 vcd_uuid = vm_list_xmlroot.get("id").split(":")
bayramovef390722016-09-27 03:34:46 -07004889 if len(vcd_uuid) == 4:
sousaedu80135b92021-02-17 15:05:18 +01004890 self.logger.info(
4891 "Created new network name: {} uuid: {}".format(
4892 network_name, vcd_uuid[3]
4893 )
4894 )
4895
bayramovef390722016-09-27 03:34:46 -07004896 return vcd_uuid[3]
beierlb22ce2d2019-12-12 12:09:51 -05004897 except Exception:
bayramovef390722016-09-27 03:34:46 -07004898 self.logger.debug("Failed create network {}".format(network_name))
sousaedu80135b92021-02-17 15:05:18 +01004899
bayramovef390722016-09-27 03:34:46 -07004900 return None
4901
sousaedu80135b92021-02-17 15:05:18 +01004902 def create_network_rest(
4903 self,
4904 network_name=None,
4905 net_type="bridge",
4906 parent_network_uuid=None,
4907 ip_profile=None,
4908 isshared="true",
4909 ):
bayramovef390722016-09-27 03:34:46 -07004910 """
4911 Method create network in vCloud director
4912
4913 Args:
4914 network_name - is network name to be created.
bhangare0e571a92017-01-12 04:02:23 -08004915 net_type - can be 'bridge','data','ptp','mgmt'.
4916 ip_profile is a dict containing the IP parameters of the network
4917 isshared - is a boolean
bayramovef390722016-09-27 03:34:46 -07004918 parent_network_uuid - is parent provider vdc network that will be used for mapping.
4919 It optional attribute. by default if no parent network indicate the first available will be used.
4920
4921 Returns:
4922 The return network uuid or return None
4923 """
kasarc5bf2932018-03-09 04:15:22 -08004924 client_as_admin = self.connect_as_admin()
sousaedu80135b92021-02-17 15:05:18 +01004925
kasarc5bf2932018-03-09 04:15:22 -08004926 if not client_as_admin:
tierno72774862020-05-04 11:44:15 +00004927 raise vimconn.VimConnConnectionException("Failed to connect vCD.")
sousaedu80135b92021-02-17 15:05:18 +01004928
bayramovef390722016-09-27 03:34:46 -07004929 if network_name is None:
4930 return None
4931
sousaedu80135b92021-02-17 15:05:18 +01004932 url_list = [self.url, "/api/admin/vdc/", self.tenant_id]
4933 vm_list_rest_call = "".join(url_list)
kasarc5bf2932018-03-09 04:15:22 -08004934
4935 if client_as_admin._session:
sousaedu80135b92021-02-17 15:05:18 +01004936 headers = {
4937 "Accept": "application/*+xml;version=" + API_VERSION,
4938 "x-vcloud-authorization": client_as_admin._session.headers[
4939 "x-vcloud-authorization"
4940 ],
4941 }
4942 response = self.perform_request(
4943 req_type="GET", url=vm_list_rest_call, headers=headers
4944 )
bayramovef390722016-09-27 03:34:46 -07004945 provider_network = None
4946 available_networks = None
4947 add_vdc_rest_url = None
4948
4949 if response.status_code != requests.codes.ok:
sousaedu80135b92021-02-17 15:05:18 +01004950 self.logger.debug(
4951 "REST API call {} failed. Return status code {}".format(
4952 vm_list_rest_call, response.status_code
4953 )
4954 )
4955
bayramovef390722016-09-27 03:34:46 -07004956 return None
4957 else:
4958 try:
beierl26fec002019-12-06 17:06:40 -05004959 vm_list_xmlroot = XmlElementTree.fromstring(response.text)
bayramovef390722016-09-27 03:34:46 -07004960 for child in vm_list_xmlroot:
sousaedu80135b92021-02-17 15:05:18 +01004961 if child.tag.split("}")[1] == "ProviderVdcReference":
4962 provider_network = child.attrib.get("href")
bayramovef390722016-09-27 03:34:46 -07004963 # application/vnd.vmware.admin.providervdc+xml
sousaedu80135b92021-02-17 15:05:18 +01004964
4965 if child.tag.split("}")[1] == "Link":
4966 if (
4967 child.attrib.get("type")
4968 == "application/vnd.vmware.vcloud.orgVdcNetwork+xml"
4969 and child.attrib.get("rel") == "add"
4970 ):
4971 add_vdc_rest_url = child.attrib.get("href")
beierlb22ce2d2019-12-12 12:09:51 -05004972 except Exception:
sousaedu80135b92021-02-17 15:05:18 +01004973 self.logger.debug(
4974 "Failed parse respond for rest api call {}".format(
4975 vm_list_rest_call
4976 )
4977 )
beierl26fec002019-12-06 17:06:40 -05004978 self.logger.debug("Respond body {}".format(response.text))
sousaedu80135b92021-02-17 15:05:18 +01004979
bayramovef390722016-09-27 03:34:46 -07004980 return None
4981
4982 # find pvdc provided available network
sousaedu80135b92021-02-17 15:05:18 +01004983 response = self.perform_request(
4984 req_type="GET", url=provider_network, headers=headers
4985 )
kbsuba85c54d2019-10-17 16:30:32 +00004986
bayramovef390722016-09-27 03:34:46 -07004987 if response.status_code != requests.codes.ok:
sousaedu80135b92021-02-17 15:05:18 +01004988 self.logger.debug(
4989 "REST API call {} failed. Return status code {}".format(
4990 vm_list_rest_call, response.status_code
4991 )
4992 )
4993
bayramovef390722016-09-27 03:34:46 -07004994 return None
4995
bayramovef390722016-09-27 03:34:46 -07004996 if parent_network_uuid is None:
4997 try:
beierl26fec002019-12-06 17:06:40 -05004998 vm_list_xmlroot = XmlElementTree.fromstring(response.text)
bayramovef390722016-09-27 03:34:46 -07004999 for child in vm_list_xmlroot.iter():
sousaedu80135b92021-02-17 15:05:18 +01005000 if child.tag.split("}")[1] == "AvailableNetworks":
bayramovef390722016-09-27 03:34:46 -07005001 for networks in child.iter():
5002 # application/vnd.vmware.admin.network+xml
sousaedu80135b92021-02-17 15:05:18 +01005003 if networks.attrib.get("href") is not None:
5004 available_networks = networks.attrib.get("href")
bayramovef390722016-09-27 03:34:46 -07005005 break
beierlb22ce2d2019-12-12 12:09:51 -05005006 except Exception:
bayramovef390722016-09-27 03:34:46 -07005007 return None
5008
bhangarebfdca492017-03-11 01:32:46 -08005009 try:
beierlb22ce2d2019-12-12 12:09:51 -05005010 # Configure IP profile of the network
sousaedu80135b92021-02-17 15:05:18 +01005011 ip_profile = (
5012 ip_profile if ip_profile is not None else DEFAULT_IP_PROFILE
5013 )
bhangare0e571a92017-01-12 04:02:23 -08005014
sousaedu80135b92021-02-17 15:05:18 +01005015 if (
5016 "subnet_address" not in ip_profile
5017 or ip_profile["subnet_address"] is None
5018 ):
kasarde691232017-03-25 03:37:31 -07005019 subnet_rand = random.randint(0, 255)
5020 ip_base = "192.168.{}.".format(subnet_rand)
sousaedu80135b92021-02-17 15:05:18 +01005021 ip_profile["subnet_address"] = ip_base + "0/24"
kasarde691232017-03-25 03:37:31 -07005022 else:
sousaedu80135b92021-02-17 15:05:18 +01005023 ip_base = ip_profile["subnet_address"].rsplit(".", 1)[0] + "."
kasarde691232017-03-25 03:37:31 -07005024
sousaedu80135b92021-02-17 15:05:18 +01005025 if (
5026 "gateway_address" not in ip_profile
5027 or ip_profile["gateway_address"] is None
5028 ):
5029 ip_profile["gateway_address"] = ip_base + "1"
bhangare0e571a92017-01-12 04:02:23 -08005030
sousaedu80135b92021-02-17 15:05:18 +01005031 if "dhcp_count" not in ip_profile or ip_profile["dhcp_count"] is None:
5032 ip_profile["dhcp_count"] = DEFAULT_IP_PROFILE["dhcp_count"]
bhangare0e571a92017-01-12 04:02:23 -08005033
sousaedu80135b92021-02-17 15:05:18 +01005034 if (
5035 "dhcp_enabled" not in ip_profile
5036 or ip_profile["dhcp_enabled"] is None
5037 ):
5038 ip_profile["dhcp_enabled"] = DEFAULT_IP_PROFILE["dhcp_enabled"]
5039
5040 if (
5041 "dhcp_start_address" not in ip_profile
5042 or ip_profile["dhcp_start_address"] is None
5043 ):
5044 ip_profile["dhcp_start_address"] = ip_base + "3"
5045
5046 if "ip_version" not in ip_profile or ip_profile["ip_version"] is None:
5047 ip_profile["ip_version"] = DEFAULT_IP_PROFILE["ip_version"]
5048
5049 if "dns_address" not in ip_profile or ip_profile["dns_address"] is None:
5050 ip_profile["dns_address"] = ip_base + "2"
5051
5052 gateway_address = ip_profile["gateway_address"]
5053 dhcp_count = int(ip_profile["dhcp_count"])
5054 subnet_address = self.convert_cidr_to_netmask(
5055 ip_profile["subnet_address"]
5056 )
5057
5058 if ip_profile["dhcp_enabled"] is True:
5059 dhcp_enabled = "true"
bhangarebfdca492017-03-11 01:32:46 -08005060 else:
sousaedu80135b92021-02-17 15:05:18 +01005061 dhcp_enabled = "false"
5062
5063 dhcp_start_address = ip_profile["dhcp_start_address"]
bhangare0e571a92017-01-12 04:02:23 -08005064
beierlb22ce2d2019-12-12 12:09:51 -05005065 # derive dhcp_end_address from dhcp_start_address & dhcp_count
bhangarebfdca492017-03-11 01:32:46 -08005066 end_ip_int = int(netaddr.IPAddress(dhcp_start_address))
5067 end_ip_int += dhcp_count - 1
5068 dhcp_end_address = str(netaddr.IPAddress(end_ip_int))
5069
beierlb22ce2d2019-12-12 12:09:51 -05005070 # ip_version = ip_profile['ip_version']
sousaedu80135b92021-02-17 15:05:18 +01005071 dns_address = ip_profile["dns_address"]
bhangarebfdca492017-03-11 01:32:46 -08005072 except KeyError as exp:
5073 self.logger.debug("Create Network REST: Key error {}".format(exp))
sousaedu80135b92021-02-17 15:05:18 +01005074
5075 raise vimconn.VimConnException(
5076 "Create Network REST: Key error{}".format(exp)
5077 )
bhangare0e571a92017-01-12 04:02:23 -08005078
bayramovef390722016-09-27 03:34:46 -07005079 # either use client provided UUID or search for a first available
5080 # if both are not defined we return none
5081 if parent_network_uuid is not None:
Ravi Chamartyb0ab2c02018-10-26 01:40:50 +00005082 provider_network = None
5083 available_networks = None
5084 add_vdc_rest_url = None
sousaedu80135b92021-02-17 15:05:18 +01005085 url_list = [self.url, "/api/admin/vdc/", self.tenant_id, "/networks"]
5086 add_vdc_rest_url = "".join(url_list)
5087 url_list = [self.url, "/api/admin/network/", parent_network_uuid]
5088 available_networks = "".join(url_list)
Ravi Chamartyb0ab2c02018-10-26 01:40:50 +00005089
beierlb22ce2d2019-12-12 12:09:51 -05005090 # Creating all networks as Direct Org VDC type networks.
5091 # Unused in case of Underlay (data/ptp) network interface.
5092 fence_mode = "isolated"
sousaedu80135b92021-02-17 15:05:18 +01005093 is_inherited = "false"
tierno455612d2017-05-30 16:40:10 +02005094 dns_list = dns_address.split(";")
5095 dns1 = dns_list[0]
5096 dns2_text = ""
sousaedu80135b92021-02-17 15:05:18 +01005097
tierno455612d2017-05-30 16:40:10 +02005098 if len(dns_list) >= 2:
sousaedu80135b92021-02-17 15:05:18 +01005099 dns2_text = "\n <Dns2>{}</Dns2>\n".format(
5100 dns_list[1]
5101 )
5102
kbsuba85c54d2019-10-17 16:30:32 +00005103 if net_type == "isolated":
beierlb22ce2d2019-12-12 12:09:51 -05005104 fence_mode = "isolated"
kbsuba85c54d2019-10-17 16:30:32 +00005105 data = """ <OrgVdcNetwork name="{0:s}" xmlns="http://www.vmware.com/vcloud/v1.5">
5106 <Description>Openmano created</Description>
5107 <Configuration>
5108 <IpScopes>
5109 <IpScope>
5110 <IsInherited>{1:s}</IsInherited>
5111 <Gateway>{2:s}</Gateway>
5112 <Netmask>{3:s}</Netmask>
5113 <Dns1>{4:s}</Dns1>{5:s}
5114 <IsEnabled>{6:s}</IsEnabled>
5115 <IpRanges>
5116 <IpRange>
5117 <StartAddress>{7:s}</StartAddress>
5118 <EndAddress>{8:s}</EndAddress>
5119 </IpRange>
5120 </IpRanges>
5121 </IpScope>
5122 </IpScopes>
5123 <FenceMode>{9:s}</FenceMode>
5124 </Configuration>
5125 <IsShared>{10:s}</IsShared>
sousaedu80135b92021-02-17 15:05:18 +01005126 </OrgVdcNetwork> """.format(
5127 escape(network_name),
5128 is_inherited,
5129 gateway_address,
5130 subnet_address,
5131 dns1,
5132 dns2_text,
5133 dhcp_enabled,
5134 dhcp_start_address,
5135 dhcp_end_address,
5136 fence_mode,
5137 isshared,
5138 )
kbsuba85c54d2019-10-17 16:30:32 +00005139 else:
5140 fence_mode = "bridged"
5141 data = """ <OrgVdcNetwork name="{0:s}" xmlns="http://www.vmware.com/vcloud/v1.5">
5142 <Description>Openmano created</Description>
5143 <Configuration>
5144 <IpScopes>
5145 <IpScope>
5146 <IsInherited>{1:s}</IsInherited>
5147 <Gateway>{2:s}</Gateway>
5148 <Netmask>{3:s}</Netmask>
5149 <Dns1>{4:s}</Dns1>{5:s}
5150 <IsEnabled>{6:s}</IsEnabled>
5151 <IpRanges>
5152 <IpRange>
5153 <StartAddress>{7:s}</StartAddress>
5154 <EndAddress>{8:s}</EndAddress>
5155 </IpRange>
5156 </IpRanges>
5157 </IpScope>
5158 </IpScopes>
5159 <ParentNetwork href="{9:s}"/>
5160 <FenceMode>{10:s}</FenceMode>
5161 </Configuration>
5162 <IsShared>{11:s}</IsShared>
sousaedu80135b92021-02-17 15:05:18 +01005163 </OrgVdcNetwork> """.format(
5164 escape(network_name),
5165 is_inherited,
5166 gateway_address,
5167 subnet_address,
5168 dns1,
5169 dns2_text,
5170 dhcp_enabled,
5171 dhcp_start_address,
5172 dhcp_end_address,
5173 available_networks,
5174 fence_mode,
5175 isshared,
5176 )
bayramovef390722016-09-27 03:34:46 -07005177
sousaedu80135b92021-02-17 15:05:18 +01005178 headers["Content-Type"] = "application/vnd.vmware.vcloud.orgVdcNetwork+xml"
bhangare0e571a92017-01-12 04:02:23 -08005179 try:
sousaedu80135b92021-02-17 15:05:18 +01005180 response = self.perform_request(
5181 req_type="POST", url=add_vdc_rest_url, headers=headers, data=data
5182 )
bayramovef390722016-09-27 03:34:46 -07005183
bhangare0e571a92017-01-12 04:02:23 -08005184 if response.status_code != 201:
sousaedu80135b92021-02-17 15:05:18 +01005185 self.logger.debug(
5186 "Create Network POST REST API call failed. "
5187 "Return status code {}, response.text: {}".format(
5188 response.status_code, response.text
5189 )
5190 )
bhangare0e571a92017-01-12 04:02:23 -08005191 else:
beierl26fec002019-12-06 17:06:40 -05005192 network_task = self.get_task_from_response(response.text)
sousaedu80135b92021-02-17 15:05:18 +01005193 self.logger.debug(
5194 "Create Network REST : Waiting for Network creation complete"
5195 )
kasarc5bf2932018-03-09 04:15:22 -08005196 time.sleep(5)
sousaedu80135b92021-02-17 15:05:18 +01005197 result = self.client.get_task_monitor().wait_for_success(
5198 task=network_task
5199 )
5200
5201 if result.get("status") == "success":
beierl26fec002019-12-06 17:06:40 -05005202 return response.text
kasarc5bf2932018-03-09 04:15:22 -08005203 else:
sousaedu80135b92021-02-17 15:05:18 +01005204 self.logger.debug(
5205 "create_network_rest task failed. Network Create response : {}".format(
5206 response.text
5207 )
5208 )
bhangare0e571a92017-01-12 04:02:23 -08005209 except Exception as exp:
5210 self.logger.debug("create_network_rest : Exception : {} ".format(exp))
5211
5212 return None
5213
5214 def convert_cidr_to_netmask(self, cidr_ip=None):
5215 """
5216 Method sets convert CIDR netmask address to normal IP format
5217 Args:
5218 cidr_ip : CIDR IP address
5219 Returns:
5220 netmask : Converted netmask
5221 """
5222 if cidr_ip is not None:
sousaedu80135b92021-02-17 15:05:18 +01005223 if "/" in cidr_ip:
5224 _, net_bits = cidr_ip.split("/")
5225 netmask = socket.inet_ntoa(
5226 struct.pack(">I", (0xFFFFFFFF << (32 - int(net_bits))) & 0xFFFFFFFF)
5227 )
bhangare0e571a92017-01-12 04:02:23 -08005228 else:
5229 netmask = cidr_ip
sousaedu80135b92021-02-17 15:05:18 +01005230
bhangare0e571a92017-01-12 04:02:23 -08005231 return netmask
sousaedu80135b92021-02-17 15:05:18 +01005232
bayramovef390722016-09-27 03:34:46 -07005233 return None
5234
5235 def get_provider_rest(self, vca=None):
5236 """
5237 Method gets provider vdc view from vcloud director
5238
5239 Args:
5240 network_name - is network name to be created.
5241 parent_network_uuid - is parent provider vdc network that will be used for mapping.
5242 It optional attribute. by default if no parent network indicate the first available will be used.
5243
5244 Returns:
5245 The return xml content of respond or None
5246 """
sousaedu80135b92021-02-17 15:05:18 +01005247 url_list = [self.url, "/api/admin"]
bayramovef390722016-09-27 03:34:46 -07005248
kasarc5bf2932018-03-09 04:15:22 -08005249 if vca:
sousaedu80135b92021-02-17 15:05:18 +01005250 headers = {
5251 "Accept": "application/*+xml;version=" + API_VERSION,
5252 "x-vcloud-authorization": self.client._session.headers[
5253 "x-vcloud-authorization"
5254 ],
5255 }
5256 response = self.perform_request(
5257 req_type="GET", url="".join(url_list), headers=headers
5258 )
bayramovef390722016-09-27 03:34:46 -07005259
5260 if response.status_code == requests.codes.ok:
beierl26fec002019-12-06 17:06:40 -05005261 return response.text
sousaedu80135b92021-02-17 15:05:18 +01005262
bayramovef390722016-09-27 03:34:46 -07005263 return None
5264
5265 def create_vdc(self, vdc_name=None):
bayramovef390722016-09-27 03:34:46 -07005266 vdc_dict = {}
bayramovef390722016-09-27 03:34:46 -07005267 xml_content = self.create_vdc_from_tmpl_rest(vdc_name=vdc_name)
sousaedu80135b92021-02-17 15:05:18 +01005268
bayramovef390722016-09-27 03:34:46 -07005269 if xml_content is not None:
bayramovef390722016-09-27 03:34:46 -07005270 try:
5271 task_resp_xmlroot = XmlElementTree.fromstring(xml_content)
5272 for child in task_resp_xmlroot:
sousaedu80135b92021-02-17 15:05:18 +01005273 if child.tag.split("}")[1] == "Owner":
5274 vdc_id = child.attrib.get("href").split("/")[-1]
5275 vdc_dict[vdc_id] = task_resp_xmlroot.get("href")
5276
bayramovef390722016-09-27 03:34:46 -07005277 return vdc_dict
beierlb22ce2d2019-12-12 12:09:51 -05005278 except Exception:
bayramovef390722016-09-27 03:34:46 -07005279 self.logger.debug("Respond body {}".format(xml_content))
5280
5281 return None
5282
5283 def create_vdc_from_tmpl_rest(self, vdc_name=None):
5284 """
5285 Method create vdc in vCloud director based on VDC template.
kasarc5bf2932018-03-09 04:15:22 -08005286 it uses pre-defined template.
bayramovef390722016-09-27 03:34:46 -07005287
5288 Args:
5289 vdc_name - name of a new vdc.
5290
5291 Returns:
5292 The return xml content of respond or None
5293 """
kasarc5bf2932018-03-09 04:15:22 -08005294 # pre-requesite atleast one vdc template should be available in vCD
bayramovef390722016-09-27 03:34:46 -07005295 self.logger.info("Creating new vdc {}".format(vdc_name))
kasarc5bf2932018-03-09 04:15:22 -08005296 vca = self.connect_as_admin()
sousaedu80135b92021-02-17 15:05:18 +01005297
bayramovef390722016-09-27 03:34:46 -07005298 if not vca:
tierno72774862020-05-04 11:44:15 +00005299 raise vimconn.VimConnConnectionException("Failed to connect vCD")
sousaedu80135b92021-02-17 15:05:18 +01005300
bayramovef390722016-09-27 03:34:46 -07005301 if vdc_name is None:
5302 return None
5303
sousaedu80135b92021-02-17 15:05:18 +01005304 url_list = [self.url, "/api/vdcTemplates"]
5305 vm_list_rest_call = "".join(url_list)
5306 headers = {
5307 "Accept": "application/*+xml;version=" + API_VERSION,
5308 "x-vcloud-authorization": vca._session.headers["x-vcloud-authorization"],
5309 }
5310 response = self.perform_request(
5311 req_type="GET", url=vm_list_rest_call, headers=headers
5312 )
bayramovef390722016-09-27 03:34:46 -07005313
5314 # container url to a template
5315 vdc_template_ref = None
5316 try:
beierl26fec002019-12-06 17:06:40 -05005317 vm_list_xmlroot = XmlElementTree.fromstring(response.text)
bayramovef390722016-09-27 03:34:46 -07005318 for child in vm_list_xmlroot:
5319 # application/vnd.vmware.admin.providervdc+xml
5320 # we need find a template from witch we instantiate VDC
sousaedu80135b92021-02-17 15:05:18 +01005321 if child.tag.split("}")[1] == "VdcTemplate":
5322 if (
5323 child.attrib.get("type")
5324 == "application/vnd.vmware.admin.vdcTemplate+xml"
5325 ):
5326 vdc_template_ref = child.attrib.get("href")
beierlb22ce2d2019-12-12 12:09:51 -05005327 except Exception:
sousaedu80135b92021-02-17 15:05:18 +01005328 self.logger.debug(
5329 "Failed parse respond for rest api call {}".format(vm_list_rest_call)
5330 )
beierl26fec002019-12-06 17:06:40 -05005331 self.logger.debug("Respond body {}".format(response.text))
sousaedu80135b92021-02-17 15:05:18 +01005332
bayramovef390722016-09-27 03:34:46 -07005333 return None
5334
5335 # if we didn't found required pre defined template we return None
5336 if vdc_template_ref is None:
5337 return None
5338
5339 try:
5340 # instantiate vdc
sousaedu80135b92021-02-17 15:05:18 +01005341 url_list = [self.url, "/api/org/", self.org_uuid, "/action/instantiate"]
5342 vm_list_rest_call = "".join(url_list)
bayramovef390722016-09-27 03:34:46 -07005343 data = """<InstantiateVdcTemplateParams name="{0:s}" xmlns="http://www.vmware.com/vcloud/v1.5">
5344 <Source href="{1:s}"></Source>
5345 <Description>opnemano</Description>
sousaedu80135b92021-02-17 15:05:18 +01005346 </InstantiateVdcTemplateParams>""".format(
5347 vdc_name, vdc_template_ref
5348 )
5349 headers[
5350 "Content-Type"
5351 ] = "application/vnd.vmware.vcloud.instantiateVdcTemplateParams+xml"
5352 response = self.perform_request(
5353 req_type="POST", url=vm_list_rest_call, headers=headers, data=data
5354 )
beierl26fec002019-12-06 17:06:40 -05005355 vdc_task = self.get_task_from_response(response.text)
kasarc5bf2932018-03-09 04:15:22 -08005356 self.client.get_task_monitor().wait_for_success(task=vdc_task)
kated47ad5f2017-08-03 02:16:13 -07005357
bayramovef390722016-09-27 03:34:46 -07005358 # if we all ok we respond with content otherwise by default None
5359 if response.status_code >= 200 and response.status_code < 300:
beierl26fec002019-12-06 17:06:40 -05005360 return response.text
sousaedu80135b92021-02-17 15:05:18 +01005361
bayramovef390722016-09-27 03:34:46 -07005362 return None
beierlb22ce2d2019-12-12 12:09:51 -05005363 except Exception:
sousaedu80135b92021-02-17 15:05:18 +01005364 self.logger.debug(
5365 "Failed parse respond for rest api call {}".format(vm_list_rest_call)
5366 )
beierl26fec002019-12-06 17:06:40 -05005367 self.logger.debug("Respond body {}".format(response.text))
bayramovef390722016-09-27 03:34:46 -07005368
5369 return None
5370
5371 def create_vdc_rest(self, vdc_name=None):
5372 """
5373 Method create network in vCloud director
5374
5375 Args:
kasarc5bf2932018-03-09 04:15:22 -08005376 vdc_name - vdc name to be created
bayramovef390722016-09-27 03:34:46 -07005377 Returns:
kasarc5bf2932018-03-09 04:15:22 -08005378 The return response
bayramovef390722016-09-27 03:34:46 -07005379 """
bayramovef390722016-09-27 03:34:46 -07005380 self.logger.info("Creating new vdc {}".format(vdc_name))
bayramovef390722016-09-27 03:34:46 -07005381 vca = self.connect_as_admin()
sousaedu80135b92021-02-17 15:05:18 +01005382
bayramovef390722016-09-27 03:34:46 -07005383 if not vca:
tierno72774862020-05-04 11:44:15 +00005384 raise vimconn.VimConnConnectionException("Failed to connect vCD")
sousaedu80135b92021-02-17 15:05:18 +01005385
bayramovef390722016-09-27 03:34:46 -07005386 if vdc_name is None:
5387 return None
5388
sousaedu80135b92021-02-17 15:05:18 +01005389 url_list = [self.url, "/api/admin/org/", self.org_uuid]
5390 vm_list_rest_call = "".join(url_list)
kasarc5bf2932018-03-09 04:15:22 -08005391
5392 if vca._session:
sousaedu80135b92021-02-17 15:05:18 +01005393 headers = {
5394 "Accept": "application/*+xml;version=" + API_VERSION,
5395 "x-vcloud-authorization": self.client._session.headers[
5396 "x-vcloud-authorization"
5397 ],
5398 }
5399 response = self.perform_request(
5400 req_type="GET", url=vm_list_rest_call, headers=headers
5401 )
bayramovef390722016-09-27 03:34:46 -07005402 provider_vdc_ref = None
5403 add_vdc_rest_url = None
beierlb22ce2d2019-12-12 12:09:51 -05005404 # available_networks = None
bayramovef390722016-09-27 03:34:46 -07005405
5406 if response.status_code != requests.codes.ok:
sousaedu80135b92021-02-17 15:05:18 +01005407 self.logger.debug(
5408 "REST API call {} failed. Return status code {}".format(
5409 vm_list_rest_call, response.status_code
5410 )
5411 )
5412
bayramovef390722016-09-27 03:34:46 -07005413 return None
5414 else:
5415 try:
beierl26fec002019-12-06 17:06:40 -05005416 vm_list_xmlroot = XmlElementTree.fromstring(response.text)
bayramovef390722016-09-27 03:34:46 -07005417 for child in vm_list_xmlroot:
5418 # application/vnd.vmware.admin.providervdc+xml
sousaedu80135b92021-02-17 15:05:18 +01005419 if child.tag.split("}")[1] == "Link":
5420 if (
5421 child.attrib.get("type")
5422 == "application/vnd.vmware.admin.createVdcParams+xml"
5423 and child.attrib.get("rel") == "add"
5424 ):
5425 add_vdc_rest_url = child.attrib.get("href")
beierlb22ce2d2019-12-12 12:09:51 -05005426 except Exception:
sousaedu80135b92021-02-17 15:05:18 +01005427 self.logger.debug(
5428 "Failed parse respond for rest api call {}".format(
5429 vm_list_rest_call
5430 )
5431 )
beierl26fec002019-12-06 17:06:40 -05005432 self.logger.debug("Respond body {}".format(response.text))
sousaedu80135b92021-02-17 15:05:18 +01005433
bayramovef390722016-09-27 03:34:46 -07005434 return None
5435
5436 response = self.get_provider_rest(vca=vca)
bayramovef390722016-09-27 03:34:46 -07005437 try:
5438 vm_list_xmlroot = XmlElementTree.fromstring(response)
5439 for child in vm_list_xmlroot:
sousaedu80135b92021-02-17 15:05:18 +01005440 if child.tag.split("}")[1] == "ProviderVdcReferences":
bayramovef390722016-09-27 03:34:46 -07005441 for sub_child in child:
sousaedu80135b92021-02-17 15:05:18 +01005442 provider_vdc_ref = sub_child.attrib.get("href")
beierlb22ce2d2019-12-12 12:09:51 -05005443 except Exception:
sousaedu80135b92021-02-17 15:05:18 +01005444 self.logger.debug(
5445 "Failed parse respond for rest api call {}".format(
5446 vm_list_rest_call
5447 )
5448 )
bayramovef390722016-09-27 03:34:46 -07005449 self.logger.debug("Respond body {}".format(response))
sousaedu80135b92021-02-17 15:05:18 +01005450
bayramovef390722016-09-27 03:34:46 -07005451 return None
5452
bayramovef390722016-09-27 03:34:46 -07005453 if add_vdc_rest_url is not None and provider_vdc_ref is not None:
garciadeblasae7d1182022-08-04 15:33:12 +02005454 data = (
5455 ' <CreateVdcParams name="{0:s}" xmlns="http://www.vmware.com/vcloud/v1.5">'
5456 "<Description>{1:s}</Description>"
5457 "<AllocationModel>ReservationPool</AllocationModel>"
5458 "<ComputeCapacity><Cpu><Units>MHz</Units><Allocated>2048</Allocated><Limit>2048</Limit>"
5459 "</Cpu><Memory><Units>MB</Units><Allocated>2048</Allocated><Limit>2048</Limit></Memory>"
5460 "</ComputeCapacity><NicQuota>0</NicQuota><NetworkQuota>100</NetworkQuota>"
5461 "<VdcStorageProfile><Enabled>true</Enabled><Units>MB</Units><Limit>20480</Limit>"
5462 "<Default>true</Default></VdcStorageProfile>"
5463 '<ProviderVdcReference name="Main Provider" href="{2:s}" />'
5464 "<UsesFastProvisioning>true</UsesFastProvisioning></CreateVdcParams>"
5465 ).format(escape(vdc_name), escape(vdc_name), provider_vdc_ref)
sousaedu80135b92021-02-17 15:05:18 +01005466 headers[
5467 "Content-Type"
5468 ] = "application/vnd.vmware.admin.createVdcParams+xml"
5469 response = self.perform_request(
5470 req_type="POST",
5471 url=add_vdc_rest_url,
5472 headers=headers,
5473 data=data,
5474 )
bayramovef390722016-09-27 03:34:46 -07005475
bayramovef390722016-09-27 03:34:46 -07005476 # if we all ok we respond with content otherwise by default None
5477 if response.status_code == 201:
beierl26fec002019-12-06 17:06:40 -05005478 return response.text
sousaedu80135b92021-02-17 15:05:18 +01005479
bayramovef390722016-09-27 03:34:46 -07005480 return None
bayramovfe3f3c92016-10-04 07:53:41 +04005481
bhangarefda5f7c2017-01-12 23:50:34 -08005482 def get_vapp_details_rest(self, vapp_uuid=None, need_admin_access=False):
bayramovfe3f3c92016-10-04 07:53:41 +04005483 """
5484 Method retrieve vapp detail from vCloud director
5485
5486 Args:
5487 vapp_uuid - is vapp identifier.
5488
5489 Returns:
5490 The return network uuid or return None
5491 """
bayramovfe3f3c92016-10-04 07:53:41 +04005492 parsed_respond = {}
bhangarefda5f7c2017-01-12 23:50:34 -08005493 vca = None
bayramovfe3f3c92016-10-04 07:53:41 +04005494
bhangarefda5f7c2017-01-12 23:50:34 -08005495 if need_admin_access:
5496 vca = self.connect_as_admin()
5497 else:
sbhangarea8e5b782018-06-21 02:10:03 -07005498 vca = self.client
bhangarefda5f7c2017-01-12 23:50:34 -08005499
bayramovfe3f3c92016-10-04 07:53:41 +04005500 if not vca:
tierno72774862020-05-04 11:44:15 +00005501 raise vimconn.VimConnConnectionException("Failed to connect vCD")
bayramovfe3f3c92016-10-04 07:53:41 +04005502 if vapp_uuid is None:
5503 return None
5504
sousaedu80135b92021-02-17 15:05:18 +01005505 url_list = [self.url, "/api/vApp/vapp-", vapp_uuid]
5506 get_vapp_restcall = "".join(url_list)
bhangarefda5f7c2017-01-12 23:50:34 -08005507
kasarc5bf2932018-03-09 04:15:22 -08005508 if vca._session:
sousaedu80135b92021-02-17 15:05:18 +01005509 headers = {
5510 "Accept": "application/*+xml;version=" + API_VERSION,
5511 "x-vcloud-authorization": vca._session.headers[
5512 "x-vcloud-authorization"
5513 ],
5514 }
5515 response = self.perform_request(
5516 req_type="GET", url=get_vapp_restcall, headers=headers
5517 )
bayramovfe3f3c92016-10-04 07:53:41 +04005518
bhangare1a0b97c2017-06-21 02:20:15 -07005519 if response.status_code == 403:
beierlb22ce2d2019-12-12 12:09:51 -05005520 if need_admin_access is False:
sousaedu80135b92021-02-17 15:05:18 +01005521 response = self.retry_rest("GET", get_vapp_restcall)
bhangare1a0b97c2017-06-21 02:20:15 -07005522
bayramovfe3f3c92016-10-04 07:53:41 +04005523 if response.status_code != requests.codes.ok:
sousaedu80135b92021-02-17 15:05:18 +01005524 self.logger.debug(
5525 "REST API call {} failed. Return status code {}".format(
5526 get_vapp_restcall, response.status_code
5527 )
5528 )
5529
bayramovfe3f3c92016-10-04 07:53:41 +04005530 return parsed_respond
5531
5532 try:
beierl26fec002019-12-06 17:06:40 -05005533 xmlroot_respond = XmlElementTree.fromstring(response.text)
sousaedu80135b92021-02-17 15:05:18 +01005534 parsed_respond["ovfDescriptorUploaded"] = xmlroot_respond.attrib[
5535 "ovfDescriptorUploaded"
5536 ]
beierlb22ce2d2019-12-12 12:09:51 -05005537 namespaces = {
5538 "vssd": "http://schemas.dmtf.org/wbem/wscim/1/cim-schema/2/CIM_VirtualSystemSettingData",
sousaedu80135b92021-02-17 15:05:18 +01005539 "ovf": "http://schemas.dmtf.org/ovf/envelope/1",
5540 "vmw": "http://www.vmware.com/schema/ovf",
5541 "vm": "http://www.vmware.com/vcloud/v1.5",
5542 "rasd": "http://schemas.dmtf.org/wbem/wscim/1/cim-schema/2/CIM_ResourceAllocationSettingData",
beierlb22ce2d2019-12-12 12:09:51 -05005543 "vmext": "http://www.vmware.com/vcloud/extension/v1.5",
sousaedu80135b92021-02-17 15:05:18 +01005544 "xmlns": "http://www.vmware.com/vcloud/v1.5",
beierlb22ce2d2019-12-12 12:09:51 -05005545 }
bayramovfe3f3c92016-10-04 07:53:41 +04005546
sousaedu80135b92021-02-17 15:05:18 +01005547 created_section = xmlroot_respond.find("vm:DateCreated", namespaces)
bayramovfe3f3c92016-10-04 07:53:41 +04005548 if created_section is not None:
sousaedu80135b92021-02-17 15:05:18 +01005549 parsed_respond["created"] = created_section.text
bayramovfe3f3c92016-10-04 07:53:41 +04005550
sousaedu80135b92021-02-17 15:05:18 +01005551 network_section = xmlroot_respond.find(
5552 "vm:NetworkConfigSection/vm:NetworkConfig", namespaces
5553 )
5554 if (
5555 network_section is not None
5556 and "networkName" in network_section.attrib
5557 ):
5558 parsed_respond["networkname"] = network_section.attrib[
5559 "networkName"
5560 ]
bayramovfe3f3c92016-10-04 07:53:41 +04005561
sousaedu80135b92021-02-17 15:05:18 +01005562 ipscopes_section = xmlroot_respond.find(
5563 "vm:NetworkConfigSection/vm:NetworkConfig/vm:Configuration/vm:IpScopes",
5564 namespaces,
5565 )
bayramovfe3f3c92016-10-04 07:53:41 +04005566 if ipscopes_section is not None:
5567 for ipscope in ipscopes_section:
5568 for scope in ipscope:
5569 tag_key = scope.tag.split("}")[1]
sousaedu80135b92021-02-17 15:05:18 +01005570 if tag_key == "IpRanges":
bayramovfe3f3c92016-10-04 07:53:41 +04005571 ip_ranges = scope.getchildren()
5572 for ipblock in ip_ranges:
5573 for block in ipblock:
sousaedu80135b92021-02-17 15:05:18 +01005574 parsed_respond[
5575 block.tag.split("}")[1]
5576 ] = block.text
bayramovfe3f3c92016-10-04 07:53:41 +04005577 else:
5578 parsed_respond[tag_key] = scope.text
5579
5580 # parse children section for other attrib
sousaedu80135b92021-02-17 15:05:18 +01005581 children_section = xmlroot_respond.find("vm:Children/", namespaces)
bayramovfe3f3c92016-10-04 07:53:41 +04005582 if children_section is not None:
sousaedu80135b92021-02-17 15:05:18 +01005583 parsed_respond["name"] = children_section.attrib["name"]
5584 parsed_respond["nestedHypervisorEnabled"] = (
5585 children_section.attrib["nestedHypervisorEnabled"]
5586 if "nestedHypervisorEnabled" in children_section.attrib
5587 else None
5588 )
5589 parsed_respond["deployed"] = children_section.attrib["deployed"]
5590 parsed_respond["status"] = children_section.attrib["status"]
5591 parsed_respond["vmuuid"] = children_section.attrib["id"].split(":")[
5592 -1
5593 ]
5594 network_adapter = children_section.find(
5595 "vm:NetworkConnectionSection", namespaces
5596 )
bayramovfe3f3c92016-10-04 07:53:41 +04005597 nic_list = []
5598 for adapters in network_adapter:
5599 adapter_key = adapters.tag.split("}")[1]
sousaedu80135b92021-02-17 15:05:18 +01005600 if adapter_key == "PrimaryNetworkConnectionIndex":
5601 parsed_respond["primarynetwork"] = adapters.text
5602
5603 if adapter_key == "NetworkConnection":
bayramovfe3f3c92016-10-04 07:53:41 +04005604 vnic = {}
sousaedu80135b92021-02-17 15:05:18 +01005605 if "network" in adapters.attrib:
5606 vnic["network"] = adapters.attrib["network"]
bayramovfe3f3c92016-10-04 07:53:41 +04005607 for adapter in adapters:
5608 setting_key = adapter.tag.split("}")[1]
5609 vnic[setting_key] = adapter.text
5610 nic_list.append(vnic)
5611
5612 for link in children_section:
sousaedu80135b92021-02-17 15:05:18 +01005613 if link.tag.split("}")[1] == "Link" and "rel" in link.attrib:
5614 if link.attrib["rel"] == "screen:acquireTicket":
5615 parsed_respond["acquireTicket"] = link.attrib
bayramovfe3f3c92016-10-04 07:53:41 +04005616
sousaedu80135b92021-02-17 15:05:18 +01005617 if link.attrib["rel"] == "screen:acquireMksTicket":
5618 parsed_respond["acquireMksTicket"] = link.attrib
5619
5620 parsed_respond["interfaces"] = nic_list
5621 vCloud_extension_section = children_section.find(
5622 "xmlns:VCloudExtension", namespaces
5623 )
bhangarefda5f7c2017-01-12 23:50:34 -08005624 if vCloud_extension_section is not None:
5625 vm_vcenter_info = {}
sousaedu80135b92021-02-17 15:05:18 +01005626 vim_info = vCloud_extension_section.find(
5627 "vmext:VmVimInfo", namespaces
5628 )
5629 vmext = vim_info.find("vmext:VmVimObjectRef", namespaces)
5630
bhangarefda5f7c2017-01-12 23:50:34 -08005631 if vmext is not None:
sousaedu80135b92021-02-17 15:05:18 +01005632 vm_vcenter_info["vm_moref_id"] = vmext.find(
5633 "vmext:MoRef", namespaces
5634 ).text
5635
beierlb22ce2d2019-12-12 12:09:51 -05005636 parsed_respond["vm_vcenter_info"] = vm_vcenter_info
bayramovfe3f3c92016-10-04 07:53:41 +04005637
sousaedu80135b92021-02-17 15:05:18 +01005638 virtual_hardware_section = children_section.find(
5639 "ovf:VirtualHardwareSection", namespaces
5640 )
bhangarea92ae392017-01-12 22:30:29 -08005641 vm_virtual_hardware_info = {}
5642 if virtual_hardware_section is not None:
sousaedu80135b92021-02-17 15:05:18 +01005643 for item in virtual_hardware_section.iterfind(
5644 "ovf:Item", namespaces
5645 ):
5646 if (
5647 item.find("rasd:Description", namespaces).text
5648 == "Hard disk"
5649 ):
beierlb22ce2d2019-12-12 12:09:51 -05005650 disk_size = item.find(
sousaedu80135b92021-02-17 15:05:18 +01005651 "rasd:HostResource", namespaces
5652 ).attrib["{" + namespaces["vm"] + "}capacity"]
beierlb22ce2d2019-12-12 12:09:51 -05005653 vm_virtual_hardware_info["disk_size"] = disk_size
bhangarea92ae392017-01-12 22:30:29 -08005654 break
5655
5656 for link in virtual_hardware_section:
sousaedu80135b92021-02-17 15:05:18 +01005657 if (
5658 link.tag.split("}")[1] == "Link"
5659 and "rel" in link.attrib
5660 ):
5661 if link.attrib["rel"] == "edit" and link.attrib[
5662 "href"
5663 ].endswith("/disks"):
5664 vm_virtual_hardware_info[
5665 "disk_edit_href"
5666 ] = link.attrib["href"]
bhangarea92ae392017-01-12 22:30:29 -08005667 break
5668
beierlb22ce2d2019-12-12 12:09:51 -05005669 parsed_respond["vm_virtual_hardware"] = vm_virtual_hardware_info
5670 except Exception as exp:
sousaedu80135b92021-02-17 15:05:18 +01005671 self.logger.info(
5672 "Error occurred calling rest api for getting vApp details {}".format(
5673 exp
5674 )
5675 )
5676
bayramovfe3f3c92016-10-04 07:53:41 +04005677 return parsed_respond
5678
kasarc5bf2932018-03-09 04:15:22 -08005679 def acquire_console(self, vm_uuid=None):
bayramovfe3f3c92016-10-04 07:53:41 +04005680 if vm_uuid is None:
5681 return None
bayramovfe3f3c92016-10-04 07:53:41 +04005682
sousaedu80135b92021-02-17 15:05:18 +01005683 if self.client._session:
5684 headers = {
5685 "Accept": "application/*+xml;version=" + API_VERSION,
5686 "x-vcloud-authorization": self.client._session.headers[
5687 "x-vcloud-authorization"
5688 ],
5689 }
5690 vm_dict = self.get_vapp_details_rest(vapp_uuid=vm_uuid)
5691 console_dict = vm_dict["acquireTicket"]
5692 console_rest_call = console_dict["href"]
5693
5694 response = self.perform_request(
5695 req_type="POST", url=console_rest_call, headers=headers
5696 )
kasarc5bf2932018-03-09 04:15:22 -08005697
bhangare1a0b97c2017-06-21 02:20:15 -07005698 if response.status_code == 403:
sousaedu80135b92021-02-17 15:05:18 +01005699 response = self.retry_rest("POST", console_rest_call)
bayramovfe3f3c92016-10-04 07:53:41 +04005700
bayramov5761ad12016-10-04 09:00:30 +04005701 if response.status_code == requests.codes.ok:
beierl26fec002019-12-06 17:06:40 -05005702 return response.text
bayramovfe3f3c92016-10-04 07:53:41 +04005703
kate15f1c382016-12-15 01:12:40 -08005704 return None
kate13ab2c42016-12-23 01:34:24 -08005705
bhangarea92ae392017-01-12 22:30:29 -08005706 def modify_vm_disk(self, vapp_uuid, flavor_disk):
5707 """
5708 Method retrieve vm disk details
5709
5710 Args:
5711 vapp_uuid - is vapp identifier.
5712 flavor_disk - disk size as specified in VNFD (flavor)
5713
5714 Returns:
5715 The return network uuid or return None
5716 """
5717 status = None
5718 try:
beierlb22ce2d2019-12-12 12:09:51 -05005719 # Flavor disk is in GB convert it into MB
bhangarea92ae392017-01-12 22:30:29 -08005720 flavor_disk = int(flavor_disk) * 1024
5721 vm_details = self.get_vapp_details_rest(vapp_uuid)
sousaedu80135b92021-02-17 15:05:18 +01005722
bhangarea92ae392017-01-12 22:30:29 -08005723 if vm_details:
5724 vm_name = vm_details["name"]
beierlb22ce2d2019-12-12 12:09:51 -05005725 self.logger.info("VM: {} flavor_disk :{}".format(vm_name, flavor_disk))
bhangarea92ae392017-01-12 22:30:29 -08005726
5727 if vm_details and "vm_virtual_hardware" in vm_details:
5728 vm_disk = int(vm_details["vm_virtual_hardware"]["disk_size"])
5729 disk_edit_href = vm_details["vm_virtual_hardware"]["disk_edit_href"]
beierlb22ce2d2019-12-12 12:09:51 -05005730 self.logger.info("VM: {} VM_disk :{}".format(vm_name, vm_disk))
bhangarea92ae392017-01-12 22:30:29 -08005731
5732 if flavor_disk > vm_disk:
beierlb22ce2d2019-12-12 12:09:51 -05005733 status = self.modify_vm_disk_rest(disk_edit_href, flavor_disk)
sousaedu80135b92021-02-17 15:05:18 +01005734 self.logger.info(
5735 "Modify disk of VM {} from {} to {} MB".format(
5736 vm_name, vm_disk, flavor_disk
5737 )
5738 )
bhangarea92ae392017-01-12 22:30:29 -08005739 else:
5740 status = True
5741 self.logger.info("No need to modify disk of VM {}".format(vm_name))
5742
5743 return status
5744 except Exception as exp:
5745 self.logger.info("Error occurred while modifing disk size {}".format(exp))
5746
beierlb22ce2d2019-12-12 12:09:51 -05005747 def modify_vm_disk_rest(self, disk_href, disk_size):
bhangarea92ae392017-01-12 22:30:29 -08005748 """
5749 Method retrieve modify vm disk size
5750
5751 Args:
5752 disk_href - vCD API URL to GET and PUT disk data
5753 disk_size - disk size as specified in VNFD (flavor)
5754
5755 Returns:
5756 The return network uuid or return None
5757 """
bhangarea92ae392017-01-12 22:30:29 -08005758 if disk_href is None or disk_size is None:
5759 return None
5760
kasarc5bf2932018-03-09 04:15:22 -08005761 if self.client._session:
sousaedu80135b92021-02-17 15:05:18 +01005762 headers = {
5763 "Accept": "application/*+xml;version=" + API_VERSION,
5764 "x-vcloud-authorization": self.client._session.headers[
5765 "x-vcloud-authorization"
5766 ],
5767 }
5768 response = self.perform_request(
5769 req_type="GET", url=disk_href, headers=headers
5770 )
bhangare1a0b97c2017-06-21 02:20:15 -07005771
5772 if response.status_code == 403:
sousaedu80135b92021-02-17 15:05:18 +01005773 response = self.retry_rest("GET", disk_href)
bhangarea92ae392017-01-12 22:30:29 -08005774
5775 if response.status_code != requests.codes.ok:
sousaedu80135b92021-02-17 15:05:18 +01005776 self.logger.debug(
5777 "GET REST API call {} failed. Return status code {}".format(
5778 disk_href, response.status_code
5779 )
5780 )
5781
bhangarea92ae392017-01-12 22:30:29 -08005782 return None
sousaedu80135b92021-02-17 15:05:18 +01005783
bhangarea92ae392017-01-12 22:30:29 -08005784 try:
beierl01bd6692019-12-09 17:06:20 -05005785 lxmlroot_respond = lxmlElementTree.fromstring(response.content)
sousaedu80135b92021-02-17 15:05:18 +01005786 namespaces = {
5787 prefix: uri for prefix, uri in lxmlroot_respond.nsmap.items() if prefix
5788 }
beierlb22ce2d2019-12-12 12:09:51 -05005789 namespaces["xmlns"] = "http://www.vmware.com/vcloud/v1.5"
bhangarea92ae392017-01-12 22:30:29 -08005790
sousaedu80135b92021-02-17 15:05:18 +01005791 for item in lxmlroot_respond.iterfind("xmlns:Item", namespaces):
beierlb22ce2d2019-12-12 12:09:51 -05005792 if item.find("rasd:Description", namespaces).text == "Hard disk":
5793 disk_item = item.find("rasd:HostResource", namespaces)
bhangarea92ae392017-01-12 22:30:29 -08005794 if disk_item is not None:
sousaedu80135b92021-02-17 15:05:18 +01005795 disk_item.attrib["{" + namespaces["xmlns"] + "}capacity"] = str(
5796 disk_size
5797 )
bhangarea92ae392017-01-12 22:30:29 -08005798 break
5799
sousaedu80135b92021-02-17 15:05:18 +01005800 data = lxmlElementTree.tostring(
5801 lxmlroot_respond, encoding="utf8", method="xml", xml_declaration=True
5802 )
bhangarea92ae392017-01-12 22:30:29 -08005803
beierlb22ce2d2019-12-12 12:09:51 -05005804 # Send PUT request to modify disk size
sousaedu80135b92021-02-17 15:05:18 +01005805 headers[
5806 "Content-Type"
5807 ] = "application/vnd.vmware.vcloud.rasdItemsList+xml; charset=ISO-8859-1"
bhangarea92ae392017-01-12 22:30:29 -08005808
sousaedu80135b92021-02-17 15:05:18 +01005809 response = self.perform_request(
5810 req_type="PUT", url=disk_href, headers=headers, data=data
5811 )
bhangare1a0b97c2017-06-21 02:20:15 -07005812 if response.status_code == 403:
sousaedu80135b92021-02-17 15:05:18 +01005813 add_headers = {"Content-Type": headers["Content-Type"]}
5814 response = self.retry_rest("PUT", disk_href, add_headers, data)
bhangarea92ae392017-01-12 22:30:29 -08005815
5816 if response.status_code != 202:
sousaedu80135b92021-02-17 15:05:18 +01005817 self.logger.debug(
5818 "PUT REST API call {} failed. Return status code {}".format(
5819 disk_href, response.status_code
5820 )
5821 )
bhangarea92ae392017-01-12 22:30:29 -08005822 else:
beierl26fec002019-12-06 17:06:40 -05005823 modify_disk_task = self.get_task_from_response(response.text)
sousaedu80135b92021-02-17 15:05:18 +01005824 result = self.client.get_task_monitor().wait_for_success(
5825 task=modify_disk_task
5826 )
5827 if result.get("status") == "success":
kasarc5bf2932018-03-09 04:15:22 -08005828 return True
5829 else:
sbhangarea8e5b782018-06-21 02:10:03 -07005830 return False
bhangarea92ae392017-01-12 22:30:29 -08005831
sousaedu80135b92021-02-17 15:05:18 +01005832 return None
beierl26fec002019-12-06 17:06:40 -05005833 except Exception as exp:
sousaedu80135b92021-02-17 15:05:18 +01005834 self.logger.info(
5835 "Error occurred calling rest api for modifing disk size {}".format(exp)
5836 )
5837
5838 return None
bhangarea92ae392017-01-12 22:30:29 -08005839
beierl26fec002019-12-06 17:06:40 -05005840 def add_serial_device(self, vapp_uuid):
5841 """
sousaedu80135b92021-02-17 15:05:18 +01005842 Method to attach a serial device to a VM
beierl26fec002019-12-06 17:06:40 -05005843
sousaedu80135b92021-02-17 15:05:18 +01005844 Args:
5845 vapp_uuid - uuid of vApp/VM
beierl26fec002019-12-06 17:06:40 -05005846
sousaedu80135b92021-02-17 15:05:18 +01005847 Returns:
beierl26fec002019-12-06 17:06:40 -05005848 """
5849 self.logger.info("Add serial devices into vApp {}".format(vapp_uuid))
5850 _, content = self.get_vcenter_content()
5851 vm_moref_id = self.get_vm_moref_id(vapp_uuid)
sousaedu80135b92021-02-17 15:05:18 +01005852
beierl26fec002019-12-06 17:06:40 -05005853 if vm_moref_id:
5854 try:
5855 host_obj, vm_obj = self.get_vm_obj(content, vm_moref_id)
sousaedu80135b92021-02-17 15:05:18 +01005856 self.logger.info(
5857 "VM {} is currently on host {}".format(vm_obj, host_obj)
5858 )
beierl26fec002019-12-06 17:06:40 -05005859 if host_obj and vm_obj:
5860 spec = vim.vm.ConfigSpec()
5861 spec.deviceChange = []
5862 serial_spec = vim.vm.device.VirtualDeviceSpec()
sousaedu80135b92021-02-17 15:05:18 +01005863 serial_spec.operation = "add"
beierl26fec002019-12-06 17:06:40 -05005864 serial_port = vim.vm.device.VirtualSerialPort()
5865 serial_port.yieldOnPoll = True
5866 backing = serial_port.URIBackingInfo()
sousaedu80135b92021-02-17 15:05:18 +01005867 backing.serviceURI = "tcp://:65500"
5868 backing.direction = "server"
beierl26fec002019-12-06 17:06:40 -05005869 serial_port.backing = backing
5870 serial_spec.device = serial_port
5871 spec.deviceChange.append(serial_spec)
5872 vm_obj.ReconfigVM_Task(spec=spec)
beierl26fec002019-12-06 17:06:40 -05005873 self.logger.info("Adding serial device to VM {}".format(vm_obj))
5874 except vmodl.MethodFault as error:
5875 self.logger.error("Error occurred while adding PCI devices {} ", error)
5876
5877 def add_pci_devices(self, vapp_uuid, pci_devices, vmname_andid):
bhangarefda5f7c2017-01-12 23:50:34 -08005878 """
sousaedu80135b92021-02-17 15:05:18 +01005879 Method to attach pci devices to VM
bhangarefda5f7c2017-01-12 23:50:34 -08005880
sousaedu80135b92021-02-17 15:05:18 +01005881 Args:
5882 vapp_uuid - uuid of vApp/VM
5883 pci_devices - pci devices infromation as specified in VNFD (flavor)
bhangarefda5f7c2017-01-12 23:50:34 -08005884
sousaedu80135b92021-02-17 15:05:18 +01005885 Returns:
5886 The status of add pci device task , vm object and
5887 vcenter_conect object
bhangarefda5f7c2017-01-12 23:50:34 -08005888 """
5889 vm_obj = None
sousaedu80135b92021-02-17 15:05:18 +01005890 self.logger.info(
5891 "Add pci devices {} into vApp {}".format(pci_devices, vapp_uuid)
5892 )
bhangare06312472017-03-30 05:49:07 -07005893 vcenter_conect, content = self.get_vcenter_content()
5894 vm_moref_id = self.get_vm_moref_id(vapp_uuid)
kateeb044522017-03-06 23:54:39 -08005895
bhangare06312472017-03-30 05:49:07 -07005896 if vm_moref_id:
bhangarefda5f7c2017-01-12 23:50:34 -08005897 try:
5898 no_of_pci_devices = len(pci_devices)
5899 if no_of_pci_devices > 0:
beierlb22ce2d2019-12-12 12:09:51 -05005900 # Get VM and its host
bhangare06312472017-03-30 05:49:07 -07005901 host_obj, vm_obj = self.get_vm_obj(content, vm_moref_id)
sousaedu80135b92021-02-17 15:05:18 +01005902 self.logger.info(
5903 "VM {} is currently on host {}".format(vm_obj, host_obj)
5904 )
5905
bhangarefda5f7c2017-01-12 23:50:34 -08005906 if host_obj and vm_obj:
beierlb22ce2d2019-12-12 12:09:51 -05005907 # get PCI devies from host on which vapp is currently installed
sousaedu80135b92021-02-17 15:05:18 +01005908 avilable_pci_devices = self.get_pci_devices(
5909 host_obj, no_of_pci_devices
5910 )
bhangarefda5f7c2017-01-12 23:50:34 -08005911
5912 if avilable_pci_devices is None:
beierlb22ce2d2019-12-12 12:09:51 -05005913 # find other hosts with active pci devices
sousaedu80135b92021-02-17 15:05:18 +01005914 (
5915 new_host_obj,
5916 avilable_pci_devices,
5917 ) = self.get_host_and_PCIdevices(content, no_of_pci_devices)
5918
5919 if (
5920 new_host_obj is not None
5921 and avilable_pci_devices is not None
5922 and len(avilable_pci_devices) > 0
5923 ):
5924 # Migrate vm to the host where PCI devices are availble
5925 self.logger.info(
5926 "Relocate VM {} on new host {}".format(
5927 vm_obj, new_host_obj
5928 )
beierlb22ce2d2019-12-12 12:09:51 -05005929 )
bhangarefda5f7c2017-01-12 23:50:34 -08005930
bhangarefda5f7c2017-01-12 23:50:34 -08005931 task = self.relocate_vm(new_host_obj, vm_obj)
5932 if task is not None:
sousaedu80135b92021-02-17 15:05:18 +01005933 result = self.wait_for_vcenter_task(
5934 task, vcenter_conect
5935 )
5936 self.logger.info(
5937 "Migrate VM status: {}".format(result)
5938 )
bhangarefda5f7c2017-01-12 23:50:34 -08005939 host_obj = new_host_obj
5940 else:
sousaedu80135b92021-02-17 15:05:18 +01005941 self.logger.info(
5942 "Fail to migrate VM : {}".format(result)
5943 )
tierno72774862020-05-04 11:44:15 +00005944 raise vimconn.VimConnNotFoundException(
beierlb22ce2d2019-12-12 12:09:51 -05005945 "Fail to migrate VM : {} to host {}".format(
sousaedu80135b92021-02-17 15:05:18 +01005946 vmname_andid, new_host_obj
bhangarefda5f7c2017-01-12 23:50:34 -08005947 )
sousaedu80135b92021-02-17 15:05:18 +01005948 )
bhangarefda5f7c2017-01-12 23:50:34 -08005949
sousaedu80135b92021-02-17 15:05:18 +01005950 if (
5951 host_obj is not None
5952 and avilable_pci_devices is not None
5953 and len(avilable_pci_devices) > 0
5954 ):
beierlb22ce2d2019-12-12 12:09:51 -05005955 # Add PCI devices one by one
bhangarefda5f7c2017-01-12 23:50:34 -08005956 for pci_device in avilable_pci_devices:
5957 task = self.add_pci_to_vm(host_obj, vm_obj, pci_device)
5958 if task:
sousaedu80135b92021-02-17 15:05:18 +01005959 status = self.wait_for_vcenter_task(
5960 task, vcenter_conect
5961 )
5962
bhangarefda5f7c2017-01-12 23:50:34 -08005963 if status:
sousaedu80135b92021-02-17 15:05:18 +01005964 self.logger.info(
5965 "Added PCI device {} to VM {}".format(
5966 pci_device, str(vm_obj)
5967 )
5968 )
bhangarefda5f7c2017-01-12 23:50:34 -08005969 else:
sousaedu80135b92021-02-17 15:05:18 +01005970 self.logger.error(
5971 "Fail to add PCI device {} to VM {}".format(
5972 pci_device, str(vm_obj)
5973 )
5974 )
5975
bhangarefda5f7c2017-01-12 23:50:34 -08005976 return True, vm_obj, vcenter_conect
5977 else:
sousaedu80135b92021-02-17 15:05:18 +01005978 self.logger.error(
5979 "Currently there is no host with"
5980 " {} number of avaialble PCI devices required for VM {}".format(
5981 no_of_pci_devices, vmname_andid
5982 )
5983 )
5984
tierno72774862020-05-04 11:44:15 +00005985 raise vimconn.VimConnNotFoundException(
beierlb22ce2d2019-12-12 12:09:51 -05005986 "Currently there is no host with {} "
5987 "number of avaialble PCI devices required for VM {}".format(
sousaedu80135b92021-02-17 15:05:18 +01005988 no_of_pci_devices, vmname_andid
5989 )
5990 )
bhangarefda5f7c2017-01-12 23:50:34 -08005991 else:
sousaedu80135b92021-02-17 15:05:18 +01005992 self.logger.debug(
5993 "No infromation about PCI devices {} ", pci_devices
5994 )
bhangarefda5f7c2017-01-12 23:50:34 -08005995 except vmodl.MethodFault as error:
beierlb22ce2d2019-12-12 12:09:51 -05005996 self.logger.error("Error occurred while adding PCI devices {} ", error)
sousaedu80135b92021-02-17 15:05:18 +01005997
bhangarefda5f7c2017-01-12 23:50:34 -08005998 return None, vm_obj, vcenter_conect
5999
6000 def get_vm_obj(self, content, mob_id):
6001 """
sousaedu80135b92021-02-17 15:05:18 +01006002 Method to get the vsphere VM object associated with a given morf ID
6003 Args:
6004 vapp_uuid - uuid of vApp/VM
6005 content - vCenter content object
6006 mob_id - mob_id of VM
bhangarefda5f7c2017-01-12 23:50:34 -08006007
sousaedu80135b92021-02-17 15:05:18 +01006008 Returns:
6009 VM and host object
bhangarefda5f7c2017-01-12 23:50:34 -08006010 """
6011 vm_obj = None
6012 host_obj = None
sousaedu80135b92021-02-17 15:05:18 +01006013
beierlb22ce2d2019-12-12 12:09:51 -05006014 try:
sousaedu80135b92021-02-17 15:05:18 +01006015 container = content.viewManager.CreateContainerView(
6016 content.rootFolder, [vim.VirtualMachine], True
6017 )
bhangarefda5f7c2017-01-12 23:50:34 -08006018 for vm in container.view:
6019 mobID = vm._GetMoId()
sousaedu80135b92021-02-17 15:05:18 +01006020
bhangarefda5f7c2017-01-12 23:50:34 -08006021 if mobID == mob_id:
6022 vm_obj = vm
6023 host_obj = vm_obj.runtime.host
6024 break
6025 except Exception as exp:
6026 self.logger.error("Error occurred while finding VM object : {}".format(exp))
sousaedu80135b92021-02-17 15:05:18 +01006027
bhangarefda5f7c2017-01-12 23:50:34 -08006028 return host_obj, vm_obj
6029
6030 def get_pci_devices(self, host, need_devices):
6031 """
sousaedu80135b92021-02-17 15:05:18 +01006032 Method to get the details of pci devices on given host
6033 Args:
6034 host - vSphere host object
6035 need_devices - number of pci devices needed on host
bhangarefda5f7c2017-01-12 23:50:34 -08006036
sousaedu80135b92021-02-17 15:05:18 +01006037 Returns:
6038 array of pci devices
bhangarefda5f7c2017-01-12 23:50:34 -08006039 """
6040 all_devices = []
6041 all_device_ids = []
6042 used_devices_ids = []
6043
6044 try:
6045 if host:
6046 pciPassthruInfo = host.config.pciPassthruInfo
6047 pciDevies = host.hardware.pciDevice
6048
6049 for pci_status in pciPassthruInfo:
6050 if pci_status.passthruActive:
6051 for device in pciDevies:
6052 if device.id == pci_status.id:
6053 all_device_ids.append(device.id)
6054 all_devices.append(device)
6055
beierlb22ce2d2019-12-12 12:09:51 -05006056 # check if devices are in use
bhangarefda5f7c2017-01-12 23:50:34 -08006057 avalible_devices = all_devices
6058 for vm in host.vm:
6059 if vm.runtime.powerState == vim.VirtualMachinePowerState.poweredOn:
6060 vm_devices = vm.config.hardware.device
6061 for device in vm_devices:
6062 if type(device) is vim.vm.device.VirtualPCIPassthrough:
6063 if device.backing.id in all_device_ids:
6064 for use_device in avalible_devices:
6065 if use_device.id == device.backing.id:
6066 avalible_devices.remove(use_device)
sousaedu80135b92021-02-17 15:05:18 +01006067
bhangarefda5f7c2017-01-12 23:50:34 -08006068 used_devices_ids.append(device.backing.id)
sousaedu80135b92021-02-17 15:05:18 +01006069 self.logger.debug(
6070 "Device {} from devices {}"
6071 "is in use".format(device.backing.id, device)
6072 )
bhangarefda5f7c2017-01-12 23:50:34 -08006073 if len(avalible_devices) < need_devices:
sousaedu80135b92021-02-17 15:05:18 +01006074 self.logger.debug(
6075 "Host {} don't have {} number of active devices".format(
6076 host, need_devices
6077 )
6078 )
6079 self.logger.debug(
6080 "found only {} devices {}".format(
6081 len(avalible_devices), avalible_devices
6082 )
6083 )
6084
bhangarefda5f7c2017-01-12 23:50:34 -08006085 return None
6086 else:
6087 required_devices = avalible_devices[:need_devices]
sousaedu80135b92021-02-17 15:05:18 +01006088 self.logger.info(
6089 "Found {} PCI devices on host {} but required only {}".format(
6090 len(avalible_devices), host, need_devices
6091 )
6092 )
6093 self.logger.info(
6094 "Retruning {} devices as {}".format(need_devices, required_devices)
6095 )
bhangarefda5f7c2017-01-12 23:50:34 -08006096
sousaedu80135b92021-02-17 15:05:18 +01006097 return required_devices
bhangarefda5f7c2017-01-12 23:50:34 -08006098 except Exception as exp:
sousaedu80135b92021-02-17 15:05:18 +01006099 self.logger.error(
6100 "Error {} occurred while finding pci devices on host: {}".format(
6101 exp, host
6102 )
6103 )
bhangarefda5f7c2017-01-12 23:50:34 -08006104
6105 return None
6106
6107 def get_host_and_PCIdevices(self, content, need_devices):
6108 """
sousaedu80135b92021-02-17 15:05:18 +01006109 Method to get the details of pci devices infromation on all hosts
bhangarefda5f7c2017-01-12 23:50:34 -08006110
sousaedu80135b92021-02-17 15:05:18 +01006111 Args:
6112 content - vSphere host object
6113 need_devices - number of pci devices needed on host
bhangarefda5f7c2017-01-12 23:50:34 -08006114
sousaedu80135b92021-02-17 15:05:18 +01006115 Returns:
6116 array of pci devices and host object
bhangarefda5f7c2017-01-12 23:50:34 -08006117 """
6118 host_obj = None
6119 pci_device_objs = None
sousaedu80135b92021-02-17 15:05:18 +01006120
bhangarefda5f7c2017-01-12 23:50:34 -08006121 try:
6122 if content:
sousaedu80135b92021-02-17 15:05:18 +01006123 container = content.viewManager.CreateContainerView(
6124 content.rootFolder, [vim.HostSystem], True
6125 )
bhangarefda5f7c2017-01-12 23:50:34 -08006126 for host in container.view:
6127 devices = self.get_pci_devices(host, need_devices)
sousaedu80135b92021-02-17 15:05:18 +01006128
bhangarefda5f7c2017-01-12 23:50:34 -08006129 if devices:
6130 host_obj = host
6131 pci_device_objs = devices
6132 break
6133 except Exception as exp:
sousaedu80135b92021-02-17 15:05:18 +01006134 self.logger.error(
6135 "Error {} occurred while finding pci devices on host: {}".format(
6136 exp, host_obj
6137 )
6138 )
bhangarefda5f7c2017-01-12 23:50:34 -08006139
beierlb22ce2d2019-12-12 12:09:51 -05006140 return host_obj, pci_device_objs
bhangarefda5f7c2017-01-12 23:50:34 -08006141
beierlb22ce2d2019-12-12 12:09:51 -05006142 def relocate_vm(self, dest_host, vm):
bhangarefda5f7c2017-01-12 23:50:34 -08006143 """
sousaedu80135b92021-02-17 15:05:18 +01006144 Method to get the relocate VM to new host
bhangarefda5f7c2017-01-12 23:50:34 -08006145
sousaedu80135b92021-02-17 15:05:18 +01006146 Args:
6147 dest_host - vSphere host object
6148 vm - vSphere VM object
bhangarefda5f7c2017-01-12 23:50:34 -08006149
sousaedu80135b92021-02-17 15:05:18 +01006150 Returns:
6151 task object
bhangarefda5f7c2017-01-12 23:50:34 -08006152 """
6153 task = None
sousaedu80135b92021-02-17 15:05:18 +01006154
bhangarefda5f7c2017-01-12 23:50:34 -08006155 try:
6156 relocate_spec = vim.vm.RelocateSpec(host=dest_host)
6157 task = vm.Relocate(relocate_spec)
sousaedu80135b92021-02-17 15:05:18 +01006158 self.logger.info(
6159 "Migrating {} to destination host {}".format(vm, dest_host)
6160 )
bhangarefda5f7c2017-01-12 23:50:34 -08006161 except Exception as exp:
sousaedu80135b92021-02-17 15:05:18 +01006162 self.logger.error(
6163 "Error occurred while relocate VM {} to new host {}: {}".format(
6164 dest_host, vm, exp
6165 )
6166 )
6167
bhangarefda5f7c2017-01-12 23:50:34 -08006168 return task
6169
sousaedu80135b92021-02-17 15:05:18 +01006170 def wait_for_vcenter_task(self, task, actionName="job", hideResult=False):
bhangarefda5f7c2017-01-12 23:50:34 -08006171 """
6172 Waits and provides updates on a vSphere task
6173 """
6174 while task.info.state == vim.TaskInfo.State.running:
6175 time.sleep(2)
6176
6177 if task.info.state == vim.TaskInfo.State.success:
6178 if task.info.result is not None and not hideResult:
sousaedu80135b92021-02-17 15:05:18 +01006179 self.logger.info(
6180 "{} completed successfully, result: {}".format(
6181 actionName, task.info.result
6182 )
beierlb22ce2d2019-12-12 12:09:51 -05006183 )
sousaedu80135b92021-02-17 15:05:18 +01006184 else:
6185 self.logger.info("Task {} completed successfully.".format(actionName))
6186 else:
6187 self.logger.error(
6188 "{} did not complete successfully: {} ".format(
6189 actionName, task.info.error
6190 )
6191 )
bhangarefda5f7c2017-01-12 23:50:34 -08006192
6193 return task.info.result
6194
beierlb22ce2d2019-12-12 12:09:51 -05006195 def add_pci_to_vm(self, host_object, vm_object, host_pci_dev):
bhangarefda5f7c2017-01-12 23:50:34 -08006196 """
sousaedu80135b92021-02-17 15:05:18 +01006197 Method to add pci device in given VM
bhangarefda5f7c2017-01-12 23:50:34 -08006198
sousaedu80135b92021-02-17 15:05:18 +01006199 Args:
6200 host_object - vSphere host object
6201 vm_object - vSphere VM object
6202 host_pci_dev - host_pci_dev must be one of the devices from the
6203 host_object.hardware.pciDevice list
6204 which is configured as a PCI passthrough device
bhangarefda5f7c2017-01-12 23:50:34 -08006205
sousaedu80135b92021-02-17 15:05:18 +01006206 Returns:
6207 task object
bhangarefda5f7c2017-01-12 23:50:34 -08006208 """
6209 task = None
sousaedu80135b92021-02-17 15:05:18 +01006210
bhangarefda5f7c2017-01-12 23:50:34 -08006211 if vm_object and host_object and host_pci_dev:
beierlb22ce2d2019-12-12 12:09:51 -05006212 try:
6213 # Add PCI device to VM
sousaedu80135b92021-02-17 15:05:18 +01006214 pci_passthroughs = vm_object.environmentBrowser.QueryConfigTarget(
6215 host=None
6216 ).pciPassthrough
6217 systemid_by_pciid = {
6218 item.pciDevice.id: item.systemId for item in pci_passthroughs
6219 }
bhangarefda5f7c2017-01-12 23:50:34 -08006220
6221 if host_pci_dev.id not in systemid_by_pciid:
sousaedu80135b92021-02-17 15:05:18 +01006222 self.logger.error(
6223 "Device {} is not a passthrough device ".format(host_pci_dev)
6224 )
bhangarefda5f7c2017-01-12 23:50:34 -08006225 return None
6226
aticig2b24d622022-03-11 15:03:55 +03006227 deviceId = hex(host_pci_dev.deviceId % 2**16).lstrip("0x")
sousaedu80135b92021-02-17 15:05:18 +01006228 backing = vim.VirtualPCIPassthroughDeviceBackingInfo(
6229 deviceId=deviceId,
6230 id=host_pci_dev.id,
6231 systemId=systemid_by_pciid[host_pci_dev.id],
6232 vendorId=host_pci_dev.vendorId,
6233 deviceName=host_pci_dev.deviceName,
6234 )
bhangarefda5f7c2017-01-12 23:50:34 -08006235
6236 hba_object = vim.VirtualPCIPassthrough(key=-100, backing=backing)
bhangarefda5f7c2017-01-12 23:50:34 -08006237 new_device_config = vim.VirtualDeviceConfigSpec(device=hba_object)
6238 new_device_config.operation = "add"
6239 vmConfigSpec = vim.vm.ConfigSpec()
6240 vmConfigSpec.deviceChange = [new_device_config]
bhangarefda5f7c2017-01-12 23:50:34 -08006241 task = vm_object.ReconfigVM_Task(spec=vmConfigSpec)
sousaedu80135b92021-02-17 15:05:18 +01006242 self.logger.info(
6243 "Adding PCI device {} into VM {} from host {} ".format(
6244 host_pci_dev, vm_object, host_object
beierlb22ce2d2019-12-12 12:09:51 -05006245 )
sousaedu80135b92021-02-17 15:05:18 +01006246 )
bhangarefda5f7c2017-01-12 23:50:34 -08006247 except Exception as exp:
sousaedu80135b92021-02-17 15:05:18 +01006248 self.logger.error(
6249 "Error occurred while adding pci devive {} to VM {}: {}".format(
6250 host_pci_dev, vm_object, exp
6251 )
6252 )
6253
bhangarefda5f7c2017-01-12 23:50:34 -08006254 return task
6255
bhangare06312472017-03-30 05:49:07 -07006256 def get_vm_vcenter_info(self):
bhangarefda5f7c2017-01-12 23:50:34 -08006257 """
kateeb044522017-03-06 23:54:39 -08006258 Method to get details of vCenter and vm
bhangarefda5f7c2017-01-12 23:50:34 -08006259
6260 Args:
6261 vapp_uuid - uuid of vApp or VM
6262
6263 Returns:
6264 Moref Id of VM and deails of vCenter
6265 """
kateeb044522017-03-06 23:54:39 -08006266 vm_vcenter_info = {}
bhangarefda5f7c2017-01-12 23:50:34 -08006267
kateeb044522017-03-06 23:54:39 -08006268 if self.vcenter_ip is not None:
6269 vm_vcenter_info["vm_vcenter_ip"] = self.vcenter_ip
6270 else:
sousaedu80135b92021-02-17 15:05:18 +01006271 raise vimconn.VimConnException(
6272 message="vCenter IP is not provided."
6273 " Please provide vCenter IP while attaching datacenter "
6274 "to tenant in --config"
6275 )
6276
kateeb044522017-03-06 23:54:39 -08006277 if self.vcenter_port is not None:
6278 vm_vcenter_info["vm_vcenter_port"] = self.vcenter_port
6279 else:
sousaedu80135b92021-02-17 15:05:18 +01006280 raise vimconn.VimConnException(
6281 message="vCenter port is not provided."
6282 " Please provide vCenter port while attaching datacenter "
6283 "to tenant in --config"
6284 )
6285
kateeb044522017-03-06 23:54:39 -08006286 if self.vcenter_user is not None:
6287 vm_vcenter_info["vm_vcenter_user"] = self.vcenter_user
6288 else:
sousaedu80135b92021-02-17 15:05:18 +01006289 raise vimconn.VimConnException(
6290 message="vCenter user is not provided."
6291 " Please provide vCenter user while attaching datacenter "
6292 "to tenant in --config"
6293 )
bhangarefda5f7c2017-01-12 23:50:34 -08006294
kateeb044522017-03-06 23:54:39 -08006295 if self.vcenter_password is not None:
6296 vm_vcenter_info["vm_vcenter_password"] = self.vcenter_password
6297 else:
sousaedu80135b92021-02-17 15:05:18 +01006298 raise vimconn.VimConnException(
6299 message="vCenter user password is not provided."
6300 " Please provide vCenter user password while attaching datacenter "
6301 "to tenant in --config"
6302 )
bhangarefda5f7c2017-01-12 23:50:34 -08006303
bhangare06312472017-03-30 05:49:07 -07006304 return vm_vcenter_info
bhangarefda5f7c2017-01-12 23:50:34 -08006305
bhangarefda5f7c2017-01-12 23:50:34 -08006306 def get_vm_pci_details(self, vmuuid):
6307 """
sousaedu80135b92021-02-17 15:05:18 +01006308 Method to get VM PCI device details from vCenter
bhangarefda5f7c2017-01-12 23:50:34 -08006309
sousaedu80135b92021-02-17 15:05:18 +01006310 Args:
6311 vm_obj - vSphere VM object
bhangarefda5f7c2017-01-12 23:50:34 -08006312
sousaedu80135b92021-02-17 15:05:18 +01006313 Returns:
6314 dict of PCI devives attached to VM
bhangarefda5f7c2017-01-12 23:50:34 -08006315
6316 """
6317 vm_pci_devices_info = {}
sousaedu80135b92021-02-17 15:05:18 +01006318
bhangarefda5f7c2017-01-12 23:50:34 -08006319 try:
beierlb22ce2d2019-12-12 12:09:51 -05006320 _, content = self.get_vcenter_content()
bhangare06312472017-03-30 05:49:07 -07006321 vm_moref_id = self.get_vm_moref_id(vmuuid)
6322 if vm_moref_id:
beierlb22ce2d2019-12-12 12:09:51 -05006323 # Get VM and its host
kateeb044522017-03-06 23:54:39 -08006324 if content:
bhangare06312472017-03-30 05:49:07 -07006325 host_obj, vm_obj = self.get_vm_obj(content, vm_moref_id)
kateeb044522017-03-06 23:54:39 -08006326 if host_obj and vm_obj:
beierlb22ce2d2019-12-12 12:09:51 -05006327 vm_pci_devices_info["host_name"] = host_obj.name
sousaedu80135b92021-02-17 15:05:18 +01006328 vm_pci_devices_info["host_ip"] = host_obj.config.network.vnic[
6329 0
6330 ].spec.ip.ipAddress
6331
kateeb044522017-03-06 23:54:39 -08006332 for device in vm_obj.config.hardware.device:
6333 if type(device) == vim.vm.device.VirtualPCIPassthrough:
sousaedu80135b92021-02-17 15:05:18 +01006334 device_details = {
6335 "devide_id": device.backing.id,
6336 "pciSlotNumber": device.slotInfo.pciSlotNumber,
6337 }
6338 vm_pci_devices_info[
6339 device.deviceInfo.label
6340 ] = device_details
kateeb044522017-03-06 23:54:39 -08006341 else:
sousaedu80135b92021-02-17 15:05:18 +01006342 self.logger.error(
6343 "Can not connect to vCenter while getting "
6344 "PCI devices infromationn"
6345 )
6346
kateeb044522017-03-06 23:54:39 -08006347 return vm_pci_devices_info
bhangarefda5f7c2017-01-12 23:50:34 -08006348 except Exception as exp:
sousaedu80135b92021-02-17 15:05:18 +01006349 self.logger.error(
6350 "Error occurred while getting VM information" " for VM : {}".format(exp)
6351 )
6352
tierno72774862020-05-04 11:44:15 +00006353 raise vimconn.VimConnException(message=exp)
bhangare0e571a92017-01-12 04:02:23 -08006354
Ravi Chamartyb0ab2c02018-10-26 01:40:50 +00006355 def reserve_memory_for_all_vms(self, vapp, memory_mb):
6356 """
sousaedu80135b92021-02-17 15:05:18 +01006357 Method to reserve memory for all VMs
6358 Args :
6359 vapp - VApp
6360 memory_mb - Memory in MB
6361 Returns:
6362 None
Ravi Chamartyb0ab2c02018-10-26 01:40:50 +00006363 """
Ravi Chamartyb0ab2c02018-10-26 01:40:50 +00006364 self.logger.info("Reserve memory for all VMs")
sousaedu80135b92021-02-17 15:05:18 +01006365
Ravi Chamartyb0ab2c02018-10-26 01:40:50 +00006366 for vms in vapp.get_all_vms():
sousaedu80135b92021-02-17 15:05:18 +01006367 vm_id = vms.get("id").split(":")[-1]
6368 url_rest_call = "{}/api/vApp/vm-{}/virtualHardwareSection/memory".format(
6369 self.url, vm_id
6370 )
6371 headers = {
6372 "Accept": "application/*+xml;version=" + API_VERSION,
6373 "x-vcloud-authorization": self.client._session.headers[
6374 "x-vcloud-authorization"
6375 ],
6376 }
6377 headers["Content-Type"] = "application/vnd.vmware.vcloud.rasdItem+xml"
6378 response = self.perform_request(
6379 req_type="GET", url=url_rest_call, headers=headers
6380 )
Ravi Chamartyb0ab2c02018-10-26 01:40:50 +00006381
6382 if response.status_code == 403:
sousaedu80135b92021-02-17 15:05:18 +01006383 response = self.retry_rest("GET", url_rest_call)
Ravi Chamartyb0ab2c02018-10-26 01:40:50 +00006384
6385 if response.status_code != 200:
sousaedu80135b92021-02-17 15:05:18 +01006386 self.logger.error(
6387 "REST call {} failed reason : {}"
6388 "status code : {}".format(
6389 url_rest_call, response.text, response.status_code
6390 )
6391 )
6392 raise vimconn.VimConnException(
6393 "reserve_memory_for_all_vms : Failed to get " "memory"
6394 )
Ravi Chamartyb0ab2c02018-10-26 01:40:50 +00006395
sousaedu80135b92021-02-17 15:05:18 +01006396 bytexml = bytes(bytearray(response.text, encoding="utf-8"))
Ravi Chamartyb0ab2c02018-10-26 01:40:50 +00006397 contentelem = lxmlElementTree.XML(bytexml)
sousaedu80135b92021-02-17 15:05:18 +01006398 namespaces = {
6399 prefix: uri for prefix, uri in contentelem.nsmap.items() if prefix
6400 }
beierlb22ce2d2019-12-12 12:09:51 -05006401 namespaces["xmlns"] = "http://www.vmware.com/vcloud/v1.5"
Ravi Chamartyb0ab2c02018-10-26 01:40:50 +00006402
6403 # Find the reservation element in the response
6404 memelem_list = contentelem.findall(".//rasd:Reservation", namespaces)
6405 for memelem in memelem_list:
6406 memelem.text = str(memory_mb)
6407
6408 newdata = lxmlElementTree.tostring(contentelem, pretty_print=True)
6409
sousaedu80135b92021-02-17 15:05:18 +01006410 response = self.perform_request(
6411 req_type="PUT", url=url_rest_call, headers=headers, data=newdata
6412 )
Ravi Chamartyb0ab2c02018-10-26 01:40:50 +00006413
6414 if response.status_code == 403:
sousaedu80135b92021-02-17 15:05:18 +01006415 add_headers = {"Content-Type": headers["Content-Type"]}
6416 response = self.retry_rest("PUT", url_rest_call, add_headers, newdata)
Ravi Chamartyb0ab2c02018-10-26 01:40:50 +00006417
6418 if response.status_code != 202:
sousaedu80135b92021-02-17 15:05:18 +01006419 self.logger.error(
6420 "REST call {} failed reason : {}"
6421 "status code : {} ".format(
6422 url_rest_call, response.text, response.status_code
6423 )
6424 )
6425 raise vimconn.VimConnException(
6426 "reserve_memory_for_all_vms : Failed to update "
6427 "virtual hardware memory section"
6428 )
Ravi Chamartyb0ab2c02018-10-26 01:40:50 +00006429 else:
beierl26fec002019-12-06 17:06:40 -05006430 mem_task = self.get_task_from_response(response.text)
Ravi Chamartyb0ab2c02018-10-26 01:40:50 +00006431 result = self.client.get_task_monitor().wait_for_success(task=mem_task)
sousaedu80135b92021-02-17 15:05:18 +01006432
6433 if result.get("status") == "success":
6434 self.logger.info(
6435 "reserve_memory_for_all_vms(): VM {} succeeded ".format(vm_id)
6436 )
Ravi Chamartyb0ab2c02018-10-26 01:40:50 +00006437 else:
sousaedu80135b92021-02-17 15:05:18 +01006438 self.logger.error(
6439 "reserve_memory_for_all_vms(): VM {} failed ".format(vm_id)
6440 )
Ravi Chamartyb0ab2c02018-10-26 01:40:50 +00006441
6442 def connect_vapp_to_org_vdc_network(self, vapp_id, net_name):
6443 """
sousaedu80135b92021-02-17 15:05:18 +01006444 Configure VApp network config with org vdc network
6445 Args :
6446 vapp - VApp
6447 Returns:
6448 None
Ravi Chamartyb0ab2c02018-10-26 01:40:50 +00006449 """
6450
sousaedu80135b92021-02-17 15:05:18 +01006451 self.logger.info(
6452 "Connecting vapp {} to org vdc network {}".format(vapp_id, net_name)
6453 )
Ravi Chamartyb0ab2c02018-10-26 01:40:50 +00006454
sousaedu80135b92021-02-17 15:05:18 +01006455 url_rest_call = "{}/api/vApp/vapp-{}/networkConfigSection/".format(
6456 self.url, vapp_id
6457 )
Ravi Chamartyb0ab2c02018-10-26 01:40:50 +00006458
sousaedu80135b92021-02-17 15:05:18 +01006459 headers = {
6460 "Accept": "application/*+xml;version=" + API_VERSION,
6461 "x-vcloud-authorization": self.client._session.headers[
6462 "x-vcloud-authorization"
6463 ],
6464 }
6465 response = self.perform_request(
6466 req_type="GET", url=url_rest_call, headers=headers
6467 )
Ravi Chamartyb0ab2c02018-10-26 01:40:50 +00006468
6469 if response.status_code == 403:
sousaedu80135b92021-02-17 15:05:18 +01006470 response = self.retry_rest("GET", url_rest_call)
Ravi Chamartyb0ab2c02018-10-26 01:40:50 +00006471
6472 if response.status_code != 200:
sousaedu80135b92021-02-17 15:05:18 +01006473 self.logger.error(
6474 "REST call {} failed reason : {}"
6475 "status code : {}".format(
6476 url_rest_call, response.text, response.status_code
6477 )
6478 )
6479 raise vimconn.VimConnException(
6480 "connect_vapp_to_org_vdc_network : Failed to get "
6481 "network config section"
6482 )
Ravi Chamartyb0ab2c02018-10-26 01:40:50 +00006483
beierl26fec002019-12-06 17:06:40 -05006484 data = response.text
sousaedu80135b92021-02-17 15:05:18 +01006485 headers[
6486 "Content-Type"
6487 ] = "application/vnd.vmware.vcloud.networkConfigSection+xml"
Ravi Chamartyb0ab2c02018-10-26 01:40:50 +00006488 net_id = self.get_network_id_by_name(net_name)
6489 if not net_id:
sousaedu80135b92021-02-17 15:05:18 +01006490 raise vimconn.VimConnException(
6491 "connect_vapp_to_org_vdc_network : Failed to find " "existing network"
6492 )
Ravi Chamartyb0ab2c02018-10-26 01:40:50 +00006493
sousaedu80135b92021-02-17 15:05:18 +01006494 bytexml = bytes(bytearray(data, encoding="utf-8"))
Ravi Chamartyb0ab2c02018-10-26 01:40:50 +00006495 newelem = lxmlElementTree.XML(bytexml)
tierno7d782ef2019-10-04 12:56:31 +00006496 namespaces = {prefix: uri for prefix, uri in newelem.nsmap.items() if prefix}
Ravi Chamartyb0ab2c02018-10-26 01:40:50 +00006497 namespaces["xmlns"] = "http://www.vmware.com/vcloud/v1.5"
6498 nwcfglist = newelem.findall(".//xmlns:NetworkConfig", namespaces)
6499
Ravi Chamarty259aebc2019-06-05 17:06:39 +00006500 # VCD 9.7 returns an incorrect parentnetwork element. Fix it before PUT operation
6501 parentnetworklist = newelem.findall(".//xmlns:ParentNetwork", namespaces)
6502 if parentnetworklist:
6503 for pn in parentnetworklist:
6504 if "href" not in pn.keys():
6505 id_val = pn.get("id")
6506 href_val = "{}/api/network/{}".format(self.url, id_val)
6507 pn.set("href", href_val)
6508
Ravi Chamartyb0ab2c02018-10-26 01:40:50 +00006509 newstr = """<NetworkConfig networkName="{}">
6510 <Configuration>
6511 <ParentNetwork href="{}/api/network/{}"/>
6512 <FenceMode>bridged</FenceMode>
6513 </Configuration>
6514 </NetworkConfig>
sousaedu80135b92021-02-17 15:05:18 +01006515 """.format(
6516 net_name, self.url, net_id
6517 )
Ravi Chamartyb0ab2c02018-10-26 01:40:50 +00006518 newcfgelem = lxmlElementTree.fromstring(newstr)
6519 if nwcfglist:
6520 nwcfglist[0].addnext(newcfgelem)
6521
6522 newdata = lxmlElementTree.tostring(newelem, pretty_print=True)
6523
sousaedu80135b92021-02-17 15:05:18 +01006524 response = self.perform_request(
6525 req_type="PUT", url=url_rest_call, headers=headers, data=newdata
6526 )
Ravi Chamartyb0ab2c02018-10-26 01:40:50 +00006527
6528 if response.status_code == 403:
sousaedu80135b92021-02-17 15:05:18 +01006529 add_headers = {"Content-Type": headers["Content-Type"]}
6530 response = self.retry_rest("PUT", url_rest_call, add_headers, newdata)
Ravi Chamartyb0ab2c02018-10-26 01:40:50 +00006531
6532 if response.status_code != 202:
sousaedu80135b92021-02-17 15:05:18 +01006533 self.logger.error(
6534 "REST call {} failed reason : {}"
6535 "status code : {} ".format(
6536 url_rest_call, response.text, response.status_code
6537 )
6538 )
6539 raise vimconn.VimConnException(
6540 "connect_vapp_to_org_vdc_network : Failed to update "
6541 "network config section"
6542 )
Ravi Chamartyb0ab2c02018-10-26 01:40:50 +00006543 else:
beierl26fec002019-12-06 17:06:40 -05006544 vapp_task = self.get_task_from_response(response.text)
Ravi Chamartyb0ab2c02018-10-26 01:40:50 +00006545 result = self.client.get_task_monitor().wait_for_success(task=vapp_task)
sousaedu80135b92021-02-17 15:05:18 +01006546 if result.get("status") == "success":
6547 self.logger.info(
6548 "connect_vapp_to_org_vdc_network(): Vapp {} connected to "
6549 "network {}".format(vapp_id, net_name)
6550 )
Ravi Chamartyb0ab2c02018-10-26 01:40:50 +00006551 else:
sousaedu80135b92021-02-17 15:05:18 +01006552 self.logger.error(
6553 "connect_vapp_to_org_vdc_network(): Vapp {} failed to "
6554 "connect to network {}".format(vapp_id, net_name)
6555 )
Ravi Chamartyb0ab2c02018-10-26 01:40:50 +00006556
Ravi Chamarty5b2d5c12018-10-22 23:59:10 +00006557 def remove_primary_network_adapter_from_all_vms(self, vapp):
6558 """
sousaedu80135b92021-02-17 15:05:18 +01006559 Method to remove network adapter type to vm
6560 Args :
6561 vapp - VApp
6562 Returns:
6563 None
Ravi Chamarty5b2d5c12018-10-22 23:59:10 +00006564 """
Ravi Chamarty5b2d5c12018-10-22 23:59:10 +00006565 self.logger.info("Removing network adapter from all VMs")
sousaedu80135b92021-02-17 15:05:18 +01006566
Ravi Chamarty5b2d5c12018-10-22 23:59:10 +00006567 for vms in vapp.get_all_vms():
sousaedu80135b92021-02-17 15:05:18 +01006568 vm_id = vms.get("id").split(":")[-1]
Ravi Chamarty5b2d5c12018-10-22 23:59:10 +00006569
sousaedu80135b92021-02-17 15:05:18 +01006570 url_rest_call = "{}/api/vApp/vm-{}/networkConnectionSection/".format(
6571 self.url, vm_id
6572 )
Ravi Chamarty5b2d5c12018-10-22 23:59:10 +00006573
sousaedu80135b92021-02-17 15:05:18 +01006574 headers = {
6575 "Accept": "application/*+xml;version=" + API_VERSION,
6576 "x-vcloud-authorization": self.client._session.headers[
6577 "x-vcloud-authorization"
6578 ],
6579 }
6580 response = self.perform_request(
6581 req_type="GET", url=url_rest_call, headers=headers
6582 )
Ravi Chamarty5b2d5c12018-10-22 23:59:10 +00006583
6584 if response.status_code == 403:
sousaedu80135b92021-02-17 15:05:18 +01006585 response = self.retry_rest("GET", url_rest_call)
Ravi Chamarty5b2d5c12018-10-22 23:59:10 +00006586
6587 if response.status_code != 200:
sousaedu80135b92021-02-17 15:05:18 +01006588 self.logger.error(
6589 "REST call {} failed reason : {}"
6590 "status code : {}".format(
6591 url_rest_call, response.text, response.status_code
6592 )
6593 )
6594 raise vimconn.VimConnException(
6595 "remove_primary_network_adapter : Failed to get "
6596 "network connection section"
6597 )
Ravi Chamarty5b2d5c12018-10-22 23:59:10 +00006598
beierl26fec002019-12-06 17:06:40 -05006599 data = response.text
Ravi Chamarty5b2d5c12018-10-22 23:59:10 +00006600 data = data.split('<Link rel="edit"')[0]
6601
sousaedu80135b92021-02-17 15:05:18 +01006602 headers[
6603 "Content-Type"
6604 ] = "application/vnd.vmware.vcloud.networkConnectionSection+xml"
Ravi Chamarty5b2d5c12018-10-22 23:59:10 +00006605
6606 newdata = """<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
6607 <NetworkConnectionSection xmlns="http://www.vmware.com/vcloud/v1.5"
6608 xmlns:ovf="http://schemas.dmtf.org/ovf/envelope/1"
6609 xmlns:vssd="http://schemas.dmtf.org/wbem/wscim/1/cim-schema/2/CIM_VirtualSystemSettingData"
6610 xmlns:common="http://schemas.dmtf.org/wbem/wscim/1/common"
6611 xmlns:rasd="http://schemas.dmtf.org/wbem/wscim/1/cim-schema/2/CIM_ResourceAllocationSettingData"
6612 xmlns:vmw="http://www.vmware.com/schema/ovf"
6613 xmlns:ovfenv="http://schemas.dmtf.org/ovf/environment/1"
6614 xmlns:vmext="http://www.vmware.com/vcloud/extension/v1.5"
6615 xmlns:ns9="http://www.vmware.com/vcloud/versions"
beierlb22ce2d2019-12-12 12:09:51 -05006616 href="{url}" type="application/vnd.vmware.vcloud.networkConnectionSection+xml"
6617 ovf:required="false">
Ravi Chamarty5b2d5c12018-10-22 23:59:10 +00006618 <ovf:Info>Specifies the available VM network connections</ovf:Info>
6619 <PrimaryNetworkConnectionIndex>0</PrimaryNetworkConnectionIndex>
beierlb22ce2d2019-12-12 12:09:51 -05006620 <Link rel="edit" href="{url}"
6621 type="application/vnd.vmware.vcloud.networkConnectionSection+xml"/>
sousaedu80135b92021-02-17 15:05:18 +01006622 </NetworkConnectionSection>""".format(
6623 url=url_rest_call
6624 )
6625 response = self.perform_request(
6626 req_type="PUT", url=url_rest_call, headers=headers, data=newdata
6627 )
Ravi Chamarty5b2d5c12018-10-22 23:59:10 +00006628
6629 if response.status_code == 403:
sousaedu80135b92021-02-17 15:05:18 +01006630 add_headers = {"Content-Type": headers["Content-Type"]}
6631 response = self.retry_rest("PUT", url_rest_call, add_headers, newdata)
Ravi Chamarty5b2d5c12018-10-22 23:59:10 +00006632
6633 if response.status_code != 202:
sousaedu80135b92021-02-17 15:05:18 +01006634 self.logger.error(
6635 "REST call {} failed reason : {}"
6636 "status code : {} ".format(
6637 url_rest_call, response.text, response.status_code
6638 )
6639 )
6640 raise vimconn.VimConnException(
6641 "remove_primary_network_adapter : Failed to update "
6642 "network connection section"
6643 )
Ravi Chamarty5b2d5c12018-10-22 23:59:10 +00006644 else:
beierl26fec002019-12-06 17:06:40 -05006645 nic_task = self.get_task_from_response(response.text)
Ravi Chamarty5b2d5c12018-10-22 23:59:10 +00006646 result = self.client.get_task_monitor().wait_for_success(task=nic_task)
sousaedu80135b92021-02-17 15:05:18 +01006647 if result.get("status") == "success":
6648 self.logger.info(
6649 "remove_primary_network_adapter(): VM {} conneced to "
6650 "default NIC type".format(vm_id)
6651 )
Ravi Chamarty5b2d5c12018-10-22 23:59:10 +00006652 else:
sousaedu80135b92021-02-17 15:05:18 +01006653 self.logger.error(
6654 "remove_primary_network_adapter(): VM {} failed to "
6655 "connect NIC type".format(vm_id)
6656 )
Ravi Chamarty5b2d5c12018-10-22 23:59:10 +00006657
sousaedu80135b92021-02-17 15:05:18 +01006658 def add_network_adapter_to_vms(
6659 self, vapp, network_name, primary_nic_index, nicIndex, net, nic_type=None
6660 ):
kasar3ac5dc42017-03-15 06:28:22 -07006661 """
sousaedu80135b92021-02-17 15:05:18 +01006662 Method to add network adapter type to vm
6663 Args :
6664 network_name - name of network
6665 primary_nic_index - int value for primary nic index
6666 nicIndex - int value for nic index
6667 nic_type - specify model name to which add to vm
6668 Returns:
6669 None
kasar3ac5dc42017-03-15 06:28:22 -07006670 """
kasar3ac5dc42017-03-15 06:28:22 -07006671
sousaedu80135b92021-02-17 15:05:18 +01006672 self.logger.info(
6673 "Add network adapter to VM: network_name {} nicIndex {} nic_type {}".format(
6674 network_name, nicIndex, nic_type
6675 )
6676 )
kasar4cb6e902017-03-18 00:17:27 -07006677 try:
kasard2963622017-03-31 05:53:17 -07006678 ip_address = None
kasardc1f02e2017-03-25 07:20:30 -07006679 floating_ip = False
kasarc5bf2932018-03-09 04:15:22 -08006680 mac_address = None
sousaedu80135b92021-02-17 15:05:18 +01006681 if "floating_ip" in net:
6682 floating_ip = net["floating_ip"]
kasard2963622017-03-31 05:53:17 -07006683
6684 # Stub for ip_address feature
sousaedu80135b92021-02-17 15:05:18 +01006685 if "ip_address" in net:
6686 ip_address = net["ip_address"]
kasard2963622017-03-31 05:53:17 -07006687
sousaedu80135b92021-02-17 15:05:18 +01006688 if "mac_address" in net:
6689 mac_address = net["mac_address"]
kasarc5bf2932018-03-09 04:15:22 -08006690
kasard2963622017-03-31 05:53:17 -07006691 if floating_ip:
6692 allocation_mode = "POOL"
6693 elif ip_address:
6694 allocation_mode = "MANUAL"
6695 else:
6696 allocation_mode = "DHCP"
kasardc1f02e2017-03-25 07:20:30 -07006697
kasar3ac5dc42017-03-15 06:28:22 -07006698 if not nic_type:
kasarc5bf2932018-03-09 04:15:22 -08006699 for vms in vapp.get_all_vms():
sousaedu80135b92021-02-17 15:05:18 +01006700 vm_id = vms.get("id").split(":")[-1]
kasar3ac5dc42017-03-15 06:28:22 -07006701
sousaedu80135b92021-02-17 15:05:18 +01006702 url_rest_call = (
6703 "{}/api/vApp/vm-{}/networkConnectionSection/".format(
6704 self.url, vm_id
6705 )
6706 )
kasar3ac5dc42017-03-15 06:28:22 -07006707
sousaedu80135b92021-02-17 15:05:18 +01006708 headers = {
6709 "Accept": "application/*+xml;version=" + API_VERSION,
6710 "x-vcloud-authorization": self.client._session.headers[
6711 "x-vcloud-authorization"
6712 ],
6713 }
6714 response = self.perform_request(
6715 req_type="GET", url=url_rest_call, headers=headers
6716 )
bhangare1a0b97c2017-06-21 02:20:15 -07006717
6718 if response.status_code == 403:
sousaedu80135b92021-02-17 15:05:18 +01006719 response = self.retry_rest("GET", url_rest_call)
bhangare1a0b97c2017-06-21 02:20:15 -07006720
kasar3ac5dc42017-03-15 06:28:22 -07006721 if response.status_code != 200:
sousaedu80135b92021-02-17 15:05:18 +01006722 self.logger.error(
6723 "REST call {} failed reason : {}"
6724 "status code : {}".format(
6725 url_rest_call, response.text, response.status_code
6726 )
6727 )
6728 raise vimconn.VimConnException(
6729 "add_network_adapter_to_vms : Failed to get "
6730 "network connection section"
6731 )
kasar3ac5dc42017-03-15 06:28:22 -07006732
beierl26fec002019-12-06 17:06:40 -05006733 data = response.text
kasarc5bf2932018-03-09 04:15:22 -08006734 data = data.split('<Link rel="edit"')[0]
sousaedu80135b92021-02-17 15:05:18 +01006735 if "<PrimaryNetworkConnectionIndex>" not in data:
Ravi Chamarty5b2d5c12018-10-22 23:59:10 +00006736 self.logger.debug("add_network_adapter PrimaryNIC not in data")
kasar3ac5dc42017-03-15 06:28:22 -07006737 item = """<PrimaryNetworkConnectionIndex>{}</PrimaryNetworkConnectionIndex>
6738 <NetworkConnection network="{}">
6739 <NetworkConnectionIndex>{}</NetworkConnectionIndex>
6740 <IsConnected>true</IsConnected>
kasardc1f02e2017-03-25 07:20:30 -07006741 <IpAddressAllocationMode>{}</IpAddressAllocationMode>
sousaedu80135b92021-02-17 15:05:18 +01006742 </NetworkConnection>""".format(
6743 primary_nic_index, network_name, nicIndex, allocation_mode
6744 )
6745
kasard2963622017-03-31 05:53:17 -07006746 # Stub for ip_address feature
6747 if ip_address:
sousaedu80135b92021-02-17 15:05:18 +01006748 ip_tag = "<IpAddress>{}</IpAddress>".format(ip_address)
6749 item = item.replace(
6750 "</NetworkConnectionIndex>\n",
6751 "</NetworkConnectionIndex>\n{}\n".format(ip_tag),
6752 )
kasardc1f02e2017-03-25 07:20:30 -07006753
kasarc5bf2932018-03-09 04:15:22 -08006754 if mac_address:
sousaedu80135b92021-02-17 15:05:18 +01006755 mac_tag = "<MACAddress>{}</MACAddress>".format(mac_address)
6756 item = item.replace(
6757 "</IsConnected>\n",
6758 "</IsConnected>\n{}\n".format(mac_tag),
6759 )
kasarc5bf2932018-03-09 04:15:22 -08006760
sousaedu80135b92021-02-17 15:05:18 +01006761 data = data.replace(
6762 "</ovf:Info>\n",
6763 "</ovf:Info>\n{}\n</NetworkConnectionSection>".format(item),
6764 )
kasar3ac5dc42017-03-15 06:28:22 -07006765 else:
Ravi Chamarty5b2d5c12018-10-22 23:59:10 +00006766 self.logger.debug("add_network_adapter PrimaryNIC in data")
kasar3ac5dc42017-03-15 06:28:22 -07006767 new_item = """<NetworkConnection network="{}">
6768 <NetworkConnectionIndex>{}</NetworkConnectionIndex>
6769 <IsConnected>true</IsConnected>
kasardc1f02e2017-03-25 07:20:30 -07006770 <IpAddressAllocationMode>{}</IpAddressAllocationMode>
sousaedu80135b92021-02-17 15:05:18 +01006771 </NetworkConnection>""".format(
6772 network_name, nicIndex, allocation_mode
6773 )
6774
kasard2963622017-03-31 05:53:17 -07006775 # Stub for ip_address feature
6776 if ip_address:
sousaedu80135b92021-02-17 15:05:18 +01006777 ip_tag = "<IpAddress>{}</IpAddress>".format(ip_address)
6778 new_item = new_item.replace(
6779 "</NetworkConnectionIndex>\n",
6780 "</NetworkConnectionIndex>\n{}\n".format(ip_tag),
6781 )
kasardc1f02e2017-03-25 07:20:30 -07006782
kasarc5bf2932018-03-09 04:15:22 -08006783 if mac_address:
sousaedu80135b92021-02-17 15:05:18 +01006784 mac_tag = "<MACAddress>{}</MACAddress>".format(mac_address)
6785 new_item = new_item.replace(
6786 "</IsConnected>\n",
6787 "</IsConnected>\n{}\n".format(mac_tag),
6788 )
kasar3ac5dc42017-03-15 06:28:22 -07006789
sousaedu80135b92021-02-17 15:05:18 +01006790 data = data + new_item + "</NetworkConnectionSection>"
kasarc5bf2932018-03-09 04:15:22 -08006791
sousaedu80135b92021-02-17 15:05:18 +01006792 headers[
6793 "Content-Type"
6794 ] = "application/vnd.vmware.vcloud.networkConnectionSection+xml"
kasarc5bf2932018-03-09 04:15:22 -08006795
sousaedu80135b92021-02-17 15:05:18 +01006796 response = self.perform_request(
6797 req_type="PUT", url=url_rest_call, headers=headers, data=data
6798 )
bhangare1a0b97c2017-06-21 02:20:15 -07006799
6800 if response.status_code == 403:
sousaedu80135b92021-02-17 15:05:18 +01006801 add_headers = {"Content-Type": headers["Content-Type"]}
6802 response = self.retry_rest(
6803 "PUT", url_rest_call, add_headers, data
6804 )
bhangare1a0b97c2017-06-21 02:20:15 -07006805
kasar3ac5dc42017-03-15 06:28:22 -07006806 if response.status_code != 202:
sousaedu80135b92021-02-17 15:05:18 +01006807 self.logger.error(
6808 "REST call {} failed reason : {}"
6809 "status code : {} ".format(
6810 url_rest_call, response.text, response.status_code
6811 )
6812 )
6813 raise vimconn.VimConnException(
6814 "add_network_adapter_to_vms : Failed to update "
6815 "network connection section"
6816 )
kasar3ac5dc42017-03-15 06:28:22 -07006817 else:
beierl26fec002019-12-06 17:06:40 -05006818 nic_task = self.get_task_from_response(response.text)
sousaedu80135b92021-02-17 15:05:18 +01006819 result = self.client.get_task_monitor().wait_for_success(
6820 task=nic_task
6821 )
6822
6823 if result.get("status") == "success":
6824 self.logger.info(
6825 "add_network_adapter_to_vms(): VM {} conneced to "
6826 "default NIC type".format(vm_id)
6827 )
kasar3ac5dc42017-03-15 06:28:22 -07006828 else:
sousaedu80135b92021-02-17 15:05:18 +01006829 self.logger.error(
6830 "add_network_adapter_to_vms(): VM {} failed to "
6831 "connect NIC type".format(vm_id)
6832 )
kasar3ac5dc42017-03-15 06:28:22 -07006833 else:
kasarc5bf2932018-03-09 04:15:22 -08006834 for vms in vapp.get_all_vms():
sousaedu80135b92021-02-17 15:05:18 +01006835 vm_id = vms.get("id").split(":")[-1]
kasar3ac5dc42017-03-15 06:28:22 -07006836
sousaedu80135b92021-02-17 15:05:18 +01006837 url_rest_call = (
6838 "{}/api/vApp/vm-{}/networkConnectionSection/".format(
6839 self.url, vm_id
6840 )
6841 )
kasarc5bf2932018-03-09 04:15:22 -08006842
sousaedu80135b92021-02-17 15:05:18 +01006843 headers = {
6844 "Accept": "application/*+xml;version=" + API_VERSION,
6845 "x-vcloud-authorization": self.client._session.headers[
6846 "x-vcloud-authorization"
6847 ],
6848 }
6849 response = self.perform_request(
6850 req_type="GET", url=url_rest_call, headers=headers
6851 )
bhangare1a0b97c2017-06-21 02:20:15 -07006852
6853 if response.status_code == 403:
sousaedu80135b92021-02-17 15:05:18 +01006854 response = self.retry_rest("GET", url_rest_call)
bhangare1a0b97c2017-06-21 02:20:15 -07006855
kasar3ac5dc42017-03-15 06:28:22 -07006856 if response.status_code != 200:
sousaedu80135b92021-02-17 15:05:18 +01006857 self.logger.error(
6858 "REST call {} failed reason : {}"
6859 "status code : {}".format(
6860 url_rest_call, response.text, response.status_code
6861 )
6862 )
6863 raise vimconn.VimConnException(
6864 "add_network_adapter_to_vms : Failed to get "
6865 "network connection section"
6866 )
beierl26fec002019-12-06 17:06:40 -05006867 data = response.text
kasarc5bf2932018-03-09 04:15:22 -08006868 data = data.split('<Link rel="edit"')[0]
Ravi Chamartye21c9cc2018-10-24 02:14:53 +00006869 vcd_netadapter_type = nic_type
sousaedu80135b92021-02-17 15:05:18 +01006870
6871 if nic_type in ["SR-IOV", "VF"]:
Ravi Chamartye21c9cc2018-10-24 02:14:53 +00006872 vcd_netadapter_type = "SRIOVETHERNETCARD"
6873
sousaedu80135b92021-02-17 15:05:18 +01006874 if "<PrimaryNetworkConnectionIndex>" not in data:
6875 self.logger.debug(
6876 "add_network_adapter PrimaryNIC not in data nic_type {}".format(
6877 nic_type
6878 )
6879 )
kasar3ac5dc42017-03-15 06:28:22 -07006880 item = """<PrimaryNetworkConnectionIndex>{}</PrimaryNetworkConnectionIndex>
6881 <NetworkConnection network="{}">
6882 <NetworkConnectionIndex>{}</NetworkConnectionIndex>
6883 <IsConnected>true</IsConnected>
kasardc1f02e2017-03-25 07:20:30 -07006884 <IpAddressAllocationMode>{}</IpAddressAllocationMode>
kasar3ac5dc42017-03-15 06:28:22 -07006885 <NetworkAdapterType>{}</NetworkAdapterType>
sousaedu80135b92021-02-17 15:05:18 +01006886 </NetworkConnection>""".format(
6887 primary_nic_index,
6888 network_name,
6889 nicIndex,
6890 allocation_mode,
6891 vcd_netadapter_type,
6892 )
6893
kasard2963622017-03-31 05:53:17 -07006894 # Stub for ip_address feature
6895 if ip_address:
sousaedu80135b92021-02-17 15:05:18 +01006896 ip_tag = "<IpAddress>{}</IpAddress>".format(ip_address)
6897 item = item.replace(
6898 "</NetworkConnectionIndex>\n",
6899 "</NetworkConnectionIndex>\n{}\n".format(ip_tag),
6900 )
kasardc1f02e2017-03-25 07:20:30 -07006901
kasarc5bf2932018-03-09 04:15:22 -08006902 if mac_address:
sousaedu80135b92021-02-17 15:05:18 +01006903 mac_tag = "<MACAddress>{}</MACAddress>".format(mac_address)
6904 item = item.replace(
6905 "</IsConnected>\n",
6906 "</IsConnected>\n{}\n".format(mac_tag),
6907 )
kasarc5bf2932018-03-09 04:15:22 -08006908
sousaedu80135b92021-02-17 15:05:18 +01006909 data = data.replace(
6910 "</ovf:Info>\n",
6911 "</ovf:Info>\n{}\n</NetworkConnectionSection>".format(item),
6912 )
kasar3ac5dc42017-03-15 06:28:22 -07006913 else:
sousaedu80135b92021-02-17 15:05:18 +01006914 self.logger.debug(
6915 "add_network_adapter PrimaryNIC in data nic_type {}".format(
6916 nic_type
6917 )
6918 )
kasar3ac5dc42017-03-15 06:28:22 -07006919 new_item = """<NetworkConnection network="{}">
6920 <NetworkConnectionIndex>{}</NetworkConnectionIndex>
6921 <IsConnected>true</IsConnected>
kasardc1f02e2017-03-25 07:20:30 -07006922 <IpAddressAllocationMode>{}</IpAddressAllocationMode>
kasar3ac5dc42017-03-15 06:28:22 -07006923 <NetworkAdapterType>{}</NetworkAdapterType>
sousaedu80135b92021-02-17 15:05:18 +01006924 </NetworkConnection>""".format(
6925 network_name, nicIndex, allocation_mode, vcd_netadapter_type
6926 )
6927
kasard2963622017-03-31 05:53:17 -07006928 # Stub for ip_address feature
6929 if ip_address:
sousaedu80135b92021-02-17 15:05:18 +01006930 ip_tag = "<IpAddress>{}</IpAddress>".format(ip_address)
6931 new_item = new_item.replace(
6932 "</NetworkConnectionIndex>\n",
6933 "</NetworkConnectionIndex>\n{}\n".format(ip_tag),
6934 )
kasardc1f02e2017-03-25 07:20:30 -07006935
kasarc5bf2932018-03-09 04:15:22 -08006936 if mac_address:
sousaedu80135b92021-02-17 15:05:18 +01006937 mac_tag = "<MACAddress>{}</MACAddress>".format(mac_address)
6938 new_item = new_item.replace(
6939 "</IsConnected>\n",
6940 "</IsConnected>\n{}\n".format(mac_tag),
6941 )
kasar3ac5dc42017-03-15 06:28:22 -07006942
sousaedu80135b92021-02-17 15:05:18 +01006943 data = data + new_item + "</NetworkConnectionSection>"
kasarc5bf2932018-03-09 04:15:22 -08006944
sousaedu80135b92021-02-17 15:05:18 +01006945 headers[
6946 "Content-Type"
6947 ] = "application/vnd.vmware.vcloud.networkConnectionSection+xml"
kasarc5bf2932018-03-09 04:15:22 -08006948
sousaedu80135b92021-02-17 15:05:18 +01006949 response = self.perform_request(
6950 req_type="PUT", url=url_rest_call, headers=headers, data=data
6951 )
bhangare1a0b97c2017-06-21 02:20:15 -07006952
6953 if response.status_code == 403:
sousaedu80135b92021-02-17 15:05:18 +01006954 add_headers = {"Content-Type": headers["Content-Type"]}
6955 response = self.retry_rest(
6956 "PUT", url_rest_call, add_headers, data
6957 )
kasar3ac5dc42017-03-15 06:28:22 -07006958
6959 if response.status_code != 202:
sousaedu80135b92021-02-17 15:05:18 +01006960 self.logger.error(
6961 "REST call {} failed reason : {}"
6962 "status code : {}".format(
6963 url_rest_call, response.text, response.status_code
6964 )
6965 )
6966 raise vimconn.VimConnException(
6967 "add_network_adapter_to_vms : Failed to update "
6968 "network connection section"
6969 )
kasar3ac5dc42017-03-15 06:28:22 -07006970 else:
beierl26fec002019-12-06 17:06:40 -05006971 nic_task = self.get_task_from_response(response.text)
sousaedu80135b92021-02-17 15:05:18 +01006972 result = self.client.get_task_monitor().wait_for_success(
6973 task=nic_task
6974 )
6975
6976 if result.get("status") == "success":
6977 self.logger.info(
6978 "add_network_adapter_to_vms(): VM {} "
6979 "conneced to NIC type {}".format(vm_id, nic_type)
6980 )
kasar3ac5dc42017-03-15 06:28:22 -07006981 else:
sousaedu80135b92021-02-17 15:05:18 +01006982 self.logger.error(
6983 "add_network_adapter_to_vms(): VM {} "
6984 "failed to connect NIC type {}".format(vm_id, nic_type)
6985 )
kasar3ac5dc42017-03-15 06:28:22 -07006986 except Exception as exp:
sousaedu80135b92021-02-17 15:05:18 +01006987 self.logger.error(
6988 "add_network_adapter_to_vms() : exception occurred "
6989 "while adding Network adapter"
6990 )
6991
tierno72774862020-05-04 11:44:15 +00006992 raise vimconn.VimConnException(message=exp)
kasarde691232017-03-25 03:37:31 -07006993
kasarde691232017-03-25 03:37:31 -07006994 def set_numa_affinity(self, vmuuid, paired_threads_id):
6995 """
sousaedu80135b92021-02-17 15:05:18 +01006996 Method to assign numa affinity in vm configuration parammeters
6997 Args :
6998 vmuuid - vm uuid
6999 paired_threads_id - one or more virtual processor
7000 numbers
7001 Returns:
7002 return if True
kasarde691232017-03-25 03:37:31 -07007003 """
7004 try:
kasar204e39e2018-01-25 00:57:02 -08007005 vcenter_conect, content = self.get_vcenter_content()
7006 vm_moref_id = self.get_vm_moref_id(vmuuid)
beierlb22ce2d2019-12-12 12:09:51 -05007007 _, vm_obj = self.get_vm_obj(content, vm_moref_id)
sousaedu80135b92021-02-17 15:05:18 +01007008
kasar204e39e2018-01-25 00:57:02 -08007009 if vm_obj:
7010 config_spec = vim.vm.ConfigSpec()
7011 config_spec.extraConfig = []
7012 opt = vim.option.OptionValue()
sousaedu80135b92021-02-17 15:05:18 +01007013 opt.key = "numa.nodeAffinity"
kasar204e39e2018-01-25 00:57:02 -08007014 opt.value = str(paired_threads_id)
7015 config_spec.extraConfig.append(opt)
7016 task = vm_obj.ReconfigVM_Task(config_spec)
sousaedu80135b92021-02-17 15:05:18 +01007017
kasar204e39e2018-01-25 00:57:02 -08007018 if task:
beierlb22ce2d2019-12-12 12:09:51 -05007019 self.wait_for_vcenter_task(task, vcenter_conect)
kasar204e39e2018-01-25 00:57:02 -08007020 extra_config = vm_obj.config.extraConfig
7021 flag = False
sousaedu80135b92021-02-17 15:05:18 +01007022
kasar204e39e2018-01-25 00:57:02 -08007023 for opts in extra_config:
sousaedu80135b92021-02-17 15:05:18 +01007024 if "numa.nodeAffinity" in opts.key:
kasar204e39e2018-01-25 00:57:02 -08007025 flag = True
sousaedu80135b92021-02-17 15:05:18 +01007026 self.logger.info(
7027 "set_numa_affinity: Sucessfully assign numa affinity "
7028 "value {} for vm {}".format(opt.value, vm_obj)
7029 )
7030
kasar204e39e2018-01-25 00:57:02 -08007031 if flag:
7032 return
7033 else:
7034 self.logger.error("set_numa_affinity: Failed to assign numa affinity")
kasarde691232017-03-25 03:37:31 -07007035 except Exception as exp:
sousaedu80135b92021-02-17 15:05:18 +01007036 self.logger.error(
7037 "set_numa_affinity : exception occurred while setting numa affinity "
7038 "for VM {} : {}".format(vm_obj, vm_moref_id)
7039 )
7040
7041 raise vimconn.VimConnException(
7042 "set_numa_affinity : Error {} failed to assign numa "
7043 "affinity".format(exp)
7044 )
kasardc1f02e2017-03-25 07:20:30 -07007045
7046 def cloud_init(self, vapp, cloud_config):
7047 """
7048 Method to inject ssh-key
7049 vapp - vapp object
7050 cloud_config a dictionary with:
7051 'key-pairs': (optional) list of strings with the public key to be inserted to the default user
7052 'users': (optional) list of users to be inserted, each item is a dict with:
7053 'name': (mandatory) user name,
7054 'key-pairs': (optional) list of strings with the public key to be inserted to the user
tierno40e1bce2017-08-09 09:12:04 +02007055 'user-data': (optional) can be a string with the text script to be passed directly to cloud-init,
7056 or a list of strings, each one contains a script to be passed, usually with a MIMEmultipart file
kasardc1f02e2017-03-25 07:20:30 -07007057 'config-files': (optional). List of files to be transferred. Each item is a dict with:
7058 'dest': (mandatory) string with the destination absolute path
7059 'encoding': (optional, by default text). Can be one of:
7060 'b64', 'base64', 'gz', 'gz+b64', 'gz+base64', 'gzip+b64', 'gzip+base64'
7061 'content' (mandatory): string with the content of the file
7062 'permissions': (optional) string with file permissions, typically octal notation '0644'
7063 'owner': (optional) file owner, string with the format 'owner:group'
7064 'boot-data-drive': boolean to indicate if user-data must be passed using a boot drive (hard disk
7065 """
kasardc1f02e2017-03-25 07:20:30 -07007066 try:
kasar2aa50742017-08-08 02:11:22 -07007067 if not isinstance(cloud_config, dict):
sousaedu80135b92021-02-17 15:05:18 +01007068 raise Exception(
7069 "cloud_init : parameter cloud_config is not a dictionary"
7070 )
kasar2aa50742017-08-08 02:11:22 -07007071 else:
kasardc1f02e2017-03-25 07:20:30 -07007072 key_pairs = []
7073 userdata = []
sousaedu80135b92021-02-17 15:05:18 +01007074
kasardc1f02e2017-03-25 07:20:30 -07007075 if "key-pairs" in cloud_config:
7076 key_pairs = cloud_config["key-pairs"]
7077
7078 if "users" in cloud_config:
7079 userdata = cloud_config["users"]
7080
kasar2aa50742017-08-08 02:11:22 -07007081 self.logger.debug("cloud_init : Guest os customization started..")
sousaedu80135b92021-02-17 15:05:18 +01007082 customize_script = self.format_script(
7083 key_pairs=key_pairs, users_list=userdata
7084 )
beierlb22ce2d2019-12-12 12:09:51 -05007085 customize_script = customize_script.replace("&", "&amp;")
kasar2aa50742017-08-08 02:11:22 -07007086 self.guest_customization(vapp, customize_script)
kasardc1f02e2017-03-25 07:20:30 -07007087 except Exception as exp:
sousaedu80135b92021-02-17 15:05:18 +01007088 self.logger.error(
7089 "cloud_init : exception occurred while injecting " "ssh-key"
7090 )
7091
7092 raise vimconn.VimConnException(
7093 "cloud_init : Error {} failed to inject " "ssh-key".format(exp)
7094 )
bhangare06312472017-03-30 05:49:07 -07007095
kasar2aa50742017-08-08 02:11:22 -07007096 def format_script(self, key_pairs=[], users_list=[]):
kasarc5bf2932018-03-09 04:15:22 -08007097 bash_script = """#!/bin/sh
beierlb22ce2d2019-12-12 12:09:51 -05007098echo performing customization tasks with param $1 at `date "+DATE: %Y-%m-%d - TIME: %H:%M:%S"`>> /root/customization.log
7099if [ "$1" = "precustomization" ];then
7100 echo performing precustomization tasks on `date "+DATE: %Y-%m-%d - TIME: %H:%M:%S"` >> /root/customization.log
7101"""
kasar2aa50742017-08-08 02:11:22 -07007102
7103 keys = "\n".join(key_pairs)
7104 if keys:
7105 keys_data = """
7106 if [ ! -d /root/.ssh ];then
7107 mkdir /root/.ssh
7108 chown root:root /root/.ssh
7109 chmod 700 /root/.ssh
7110 touch /root/.ssh/authorized_keys
7111 chown root:root /root/.ssh/authorized_keys
7112 chmod 600 /root/.ssh/authorized_keys
7113 # make centos with selinux happy
7114 which restorecon && restorecon -Rv /root/.ssh
7115 else
7116 touch /root/.ssh/authorized_keys
7117 chown root:root /root/.ssh/authorized_keys
7118 chmod 600 /root/.ssh/authorized_keys
7119 fi
7120 echo '{key}' >> /root/.ssh/authorized_keys
sousaedu80135b92021-02-17 15:05:18 +01007121 """.format(
7122 key=keys
7123 )
kasar2aa50742017-08-08 02:11:22 -07007124
beierlb22ce2d2019-12-12 12:09:51 -05007125 bash_script += keys_data
kasar2aa50742017-08-08 02:11:22 -07007126
7127 for user in users_list:
sousaedu80135b92021-02-17 15:05:18 +01007128 if "name" in user:
7129 user_name = user["name"]
7130
7131 if "key-pairs" in user:
7132 user_keys = "\n".join(user["key-pairs"])
kasar2aa50742017-08-08 02:11:22 -07007133 else:
7134 user_keys = None
7135
7136 add_user_name = """
7137 useradd -d /home/{user_name} -m -g users -s /bin/bash {user_name}
sousaedu80135b92021-02-17 15:05:18 +01007138 """.format(
7139 user_name=user_name
7140 )
kasar2aa50742017-08-08 02:11:22 -07007141
beierlb22ce2d2019-12-12 12:09:51 -05007142 bash_script += add_user_name
kasar2aa50742017-08-08 02:11:22 -07007143
7144 if user_keys:
7145 user_keys_data = """
7146 mkdir /home/{user_name}/.ssh
7147 chown {user_name}:{user_name} /home/{user_name}/.ssh
7148 chmod 700 /home/{user_name}/.ssh
7149 touch /home/{user_name}/.ssh/authorized_keys
7150 chown {user_name}:{user_name} /home/{user_name}/.ssh/authorized_keys
7151 chmod 600 /home/{user_name}/.ssh/authorized_keys
7152 # make centos with selinux happy
7153 which restorecon && restorecon -Rv /home/{user_name}/.ssh
7154 echo '{user_key}' >> /home/{user_name}/.ssh/authorized_keys
sousaedu80135b92021-02-17 15:05:18 +01007155 """.format(
7156 user_name=user_name, user_key=user_keys
7157 )
beierlb22ce2d2019-12-12 12:09:51 -05007158 bash_script += user_keys_data
kasar2aa50742017-08-08 02:11:22 -07007159
beierlb22ce2d2019-12-12 12:09:51 -05007160 return bash_script + "\n\tfi"
kasar2aa50742017-08-08 02:11:22 -07007161
7162 def guest_customization(self, vapp, customize_script):
7163 """
7164 Method to customize guest os
7165 vapp - Vapp object
7166 customize_script - Customize script to be run at first boot of VM.
7167 """
kasarc5bf2932018-03-09 04:15:22 -08007168 for vm in vapp.get_all_vms():
sousaedu80135b92021-02-17 15:05:18 +01007169 vm_id = vm.get("id").split(":")[-1]
7170 vm_name = vm.get("name")
7171 vm_name = vm_name.replace("_", "-")
sbhangarea8e5b782018-06-21 02:10:03 -07007172
sousaedu80135b92021-02-17 15:05:18 +01007173 vm_customization_url = (
7174 "{}/api/vApp/vm-{}/guestCustomizationSection/".format(self.url, vm_id)
7175 )
7176 headers = {
7177 "Accept": "application/*+xml;version=" + API_VERSION,
7178 "x-vcloud-authorization": self.client._session.headers[
7179 "x-vcloud-authorization"
7180 ],
7181 }
kasarc5bf2932018-03-09 04:15:22 -08007182
sousaedu80135b92021-02-17 15:05:18 +01007183 headers[
7184 "Content-Type"
7185 ] = "application/vnd.vmware.vcloud.guestCustomizationSection+xml"
kasarc5bf2932018-03-09 04:15:22 -08007186
7187 data = """<GuestCustomizationSection
7188 xmlns="http://www.vmware.com/vcloud/v1.5"
7189 xmlns:ovf="http://schemas.dmtf.org/ovf/envelope/1"
beierlb22ce2d2019-12-12 12:09:51 -05007190 ovf:required="false" href="{}"
7191 type="application/vnd.vmware.vcloud.guestCustomizationSection+xml">
kasarc5bf2932018-03-09 04:15:22 -08007192 <ovf:Info>Specifies Guest OS Customization Settings</ovf:Info>
7193 <Enabled>true</Enabled>
7194 <ChangeSid>false</ChangeSid>
7195 <VirtualMachineId>{}</VirtualMachineId>
7196 <JoinDomainEnabled>false</JoinDomainEnabled>
7197 <UseOrgSettings>false</UseOrgSettings>
7198 <AdminPasswordEnabled>false</AdminPasswordEnabled>
7199 <AdminPasswordAuto>true</AdminPasswordAuto>
7200 <AdminAutoLogonEnabled>false</AdminAutoLogonEnabled>
7201 <AdminAutoLogonCount>0</AdminAutoLogonCount>
7202 <ResetPasswordRequired>false</ResetPasswordRequired>
7203 <CustomizationScript>{}</CustomizationScript>
7204 <ComputerName>{}</ComputerName>
beierlb22ce2d2019-12-12 12:09:51 -05007205 <Link href="{}"
7206 type="application/vnd.vmware.vcloud.guestCustomizationSection+xml" rel="edit"/>
sbhangarea8e5b782018-06-21 02:10:03 -07007207 </GuestCustomizationSection>
sousaedu80135b92021-02-17 15:05:18 +01007208 """.format(
7209 vm_customization_url,
7210 vm_id,
7211 customize_script,
7212 vm_name,
7213 vm_customization_url,
7214 )
kasarc5bf2932018-03-09 04:15:22 -08007215
sousaedu80135b92021-02-17 15:05:18 +01007216 response = self.perform_request(
7217 req_type="PUT", url=vm_customization_url, headers=headers, data=data
7218 )
kasarc5bf2932018-03-09 04:15:22 -08007219 if response.status_code == 202:
beierl26fec002019-12-06 17:06:40 -05007220 guest_task = self.get_task_from_response(response.text)
kasarc5bf2932018-03-09 04:15:22 -08007221 self.client.get_task_monitor().wait_for_success(task=guest_task)
sousaedu80135b92021-02-17 15:05:18 +01007222 self.logger.info(
7223 "guest_customization : customized guest os task "
7224 "completed for VM {}".format(vm_name)
7225 )
kasar2aa50742017-08-08 02:11:22 -07007226 else:
sousaedu80135b92021-02-17 15:05:18 +01007227 self.logger.error(
7228 "guest_customization : task for customized guest os"
7229 "failed for VM {}".format(vm_name)
7230 )
7231
7232 raise vimconn.VimConnException(
7233 "guest_customization : failed to perform"
7234 "guest os customization on VM {}".format(vm_name)
7235 )
bhangare06312472017-03-30 05:49:07 -07007236
bhangare1a0b97c2017-06-21 02:20:15 -07007237 def add_new_disk(self, vapp_uuid, disk_size):
bhangare06312472017-03-30 05:49:07 -07007238 """
sousaedu80135b92021-02-17 15:05:18 +01007239 Method to create an empty vm disk
bhangare06312472017-03-30 05:49:07 -07007240
sousaedu80135b92021-02-17 15:05:18 +01007241 Args:
7242 vapp_uuid - is vapp identifier.
7243 disk_size - size of disk to be created in GB
bhangare06312472017-03-30 05:49:07 -07007244
sousaedu80135b92021-02-17 15:05:18 +01007245 Returns:
7246 None
bhangare06312472017-03-30 05:49:07 -07007247 """
7248 status = False
7249 vm_details = None
7250 try:
beierlb22ce2d2019-12-12 12:09:51 -05007251 # Disk size in GB, convert it into MB
bhangare06312472017-03-30 05:49:07 -07007252 if disk_size is not None:
7253 disk_size_mb = int(disk_size) * 1024
7254 vm_details = self.get_vapp_details_rest(vapp_uuid)
7255
7256 if vm_details and "vm_virtual_hardware" in vm_details:
sousaedu80135b92021-02-17 15:05:18 +01007257 self.logger.info(
7258 "Adding disk to VM: {} disk size:{}GB".format(
7259 vm_details["name"], disk_size
7260 )
7261 )
bhangare06312472017-03-30 05:49:07 -07007262 disk_href = vm_details["vm_virtual_hardware"]["disk_edit_href"]
bhangare1a0b97c2017-06-21 02:20:15 -07007263 status = self.add_new_disk_rest(disk_href, disk_size_mb)
bhangare06312472017-03-30 05:49:07 -07007264 except Exception as exp:
7265 msg = "Error occurred while creating new disk {}.".format(exp)
7266 self.rollback_newvm(vapp_uuid, msg)
7267
7268 if status:
sousaedu80135b92021-02-17 15:05:18 +01007269 self.logger.info(
7270 "Added new disk to VM: {} disk size:{}GB".format(
7271 vm_details["name"], disk_size
7272 )
7273 )
bhangare06312472017-03-30 05:49:07 -07007274 else:
beierlb22ce2d2019-12-12 12:09:51 -05007275 # If failed to add disk, delete VM
sousaedu80135b92021-02-17 15:05:18 +01007276 msg = "add_new_disk: Failed to add new disk to {}".format(
7277 vm_details["name"]
7278 )
bhangare06312472017-03-30 05:49:07 -07007279 self.rollback_newvm(vapp_uuid, msg)
7280
bhangare1a0b97c2017-06-21 02:20:15 -07007281 def add_new_disk_rest(self, disk_href, disk_size_mb):
bhangare06312472017-03-30 05:49:07 -07007282 """
7283 Retrives vApp Disks section & add new empty disk
7284
7285 Args:
7286 disk_href: Disk section href to addd disk
7287 disk_size_mb: Disk size in MB
7288
7289 Returns: Status of add new disk task
7290 """
7291 status = False
kasarc5bf2932018-03-09 04:15:22 -08007292 if self.client._session:
sousaedu80135b92021-02-17 15:05:18 +01007293 headers = {
7294 "Accept": "application/*+xml;version=" + API_VERSION,
7295 "x-vcloud-authorization": self.client._session.headers[
7296 "x-vcloud-authorization"
7297 ],
7298 }
7299 response = self.perform_request(
7300 req_type="GET", url=disk_href, headers=headers
7301 )
bhangare1a0b97c2017-06-21 02:20:15 -07007302
7303 if response.status_code == 403:
sousaedu80135b92021-02-17 15:05:18 +01007304 response = self.retry_rest("GET", disk_href)
bhangare06312472017-03-30 05:49:07 -07007305
7306 if response.status_code != requests.codes.ok:
sousaedu80135b92021-02-17 15:05:18 +01007307 self.logger.error(
7308 "add_new_disk_rest: GET REST API call {} failed. Return status code {}".format(
7309 disk_href, response.status_code
7310 )
7311 )
7312
bhangare06312472017-03-30 05:49:07 -07007313 return status
sousaedu80135b92021-02-17 15:05:18 +01007314
bhangare06312472017-03-30 05:49:07 -07007315 try:
beierlb22ce2d2019-12-12 12:09:51 -05007316 # Find but type & max of instance IDs assigned to disks
beierl01bd6692019-12-09 17:06:20 -05007317 lxmlroot_respond = lxmlElementTree.fromstring(response.content)
sousaedu80135b92021-02-17 15:05:18 +01007318 namespaces = {
7319 prefix: uri for prefix, uri in lxmlroot_respond.nsmap.items() if prefix
7320 }
beierlb22ce2d2019-12-12 12:09:51 -05007321 namespaces["xmlns"] = "http://www.vmware.com/vcloud/v1.5"
bhangare06312472017-03-30 05:49:07 -07007322 instance_id = 0
sousaedu80135b92021-02-17 15:05:18 +01007323
7324 for item in lxmlroot_respond.iterfind("xmlns:Item", namespaces):
beierlb22ce2d2019-12-12 12:09:51 -05007325 if item.find("rasd:Description", namespaces).text == "Hard disk":
7326 inst_id = int(item.find("rasd:InstanceID", namespaces).text)
sousaedu80135b92021-02-17 15:05:18 +01007327
bhangare06312472017-03-30 05:49:07 -07007328 if inst_id > instance_id:
7329 instance_id = inst_id
beierlb22ce2d2019-12-12 12:09:51 -05007330 disk_item = item.find("rasd:HostResource", namespaces)
sousaedu80135b92021-02-17 15:05:18 +01007331 bus_subtype = disk_item.attrib[
7332 "{" + namespaces["xmlns"] + "}busSubType"
7333 ]
7334 bus_type = disk_item.attrib[
7335 "{" + namespaces["xmlns"] + "}busType"
7336 ]
bhangare06312472017-03-30 05:49:07 -07007337
7338 instance_id = instance_id + 1
beierlb22ce2d2019-12-12 12:09:51 -05007339 new_item = """<Item>
bhangare06312472017-03-30 05:49:07 -07007340 <rasd:Description>Hard disk</rasd:Description>
7341 <rasd:ElementName>New disk</rasd:ElementName>
7342 <rasd:HostResource
7343 xmlns:vcloud="http://www.vmware.com/vcloud/v1.5"
7344 vcloud:capacity="{}"
7345 vcloud:busSubType="{}"
7346 vcloud:busType="{}"></rasd:HostResource>
7347 <rasd:InstanceID>{}</rasd:InstanceID>
7348 <rasd:ResourceType>17</rasd:ResourceType>
sousaedu80135b92021-02-17 15:05:18 +01007349 </Item>""".format(
7350 disk_size_mb, bus_subtype, bus_type, instance_id
7351 )
bhangare06312472017-03-30 05:49:07 -07007352
beierl26fec002019-12-06 17:06:40 -05007353 new_data = response.text
beierlb22ce2d2019-12-12 12:09:51 -05007354 # Add new item at the bottom
sousaedu80135b92021-02-17 15:05:18 +01007355 new_data = new_data.replace(
7356 "</Item>\n</RasdItemsList>",
7357 "</Item>\n{}\n</RasdItemsList>".format(new_item),
7358 )
bhangare06312472017-03-30 05:49:07 -07007359
7360 # Send PUT request to modify virtual hardware section with new disk
sousaedu80135b92021-02-17 15:05:18 +01007361 headers[
7362 "Content-Type"
7363 ] = "application/vnd.vmware.vcloud.rasdItemsList+xml; charset=ISO-8859-1"
bhangare06312472017-03-30 05:49:07 -07007364
sousaedu80135b92021-02-17 15:05:18 +01007365 response = self.perform_request(
7366 req_type="PUT", url=disk_href, data=new_data, headers=headers
7367 )
bhangare1a0b97c2017-06-21 02:20:15 -07007368
7369 if response.status_code == 403:
sousaedu80135b92021-02-17 15:05:18 +01007370 add_headers = {"Content-Type": headers["Content-Type"]}
7371 response = self.retry_rest("PUT", disk_href, add_headers, new_data)
bhangare06312472017-03-30 05:49:07 -07007372
7373 if response.status_code != 202:
sousaedu80135b92021-02-17 15:05:18 +01007374 self.logger.error(
7375 "PUT REST API call {} failed. Return status code {}. response.text:{}".format(
7376 disk_href, response.status_code, response.text
7377 )
7378 )
bhangare06312472017-03-30 05:49:07 -07007379 else:
beierl26fec002019-12-06 17:06:40 -05007380 add_disk_task = self.get_task_from_response(response.text)
sousaedu80135b92021-02-17 15:05:18 +01007381 result = self.client.get_task_monitor().wait_for_success(
7382 task=add_disk_task
7383 )
7384
7385 if result.get("status") == "success":
kasarc5bf2932018-03-09 04:15:22 -08007386 status = True
7387 else:
sousaedu80135b92021-02-17 15:05:18 +01007388 self.logger.error(
7389 "Add new disk REST task failed to add {} MB disk".format(
7390 disk_size_mb
7391 )
7392 )
bhangare06312472017-03-30 05:49:07 -07007393 except Exception as exp:
sousaedu80135b92021-02-17 15:05:18 +01007394 self.logger.error(
7395 "Error occurred calling rest api for creating new disk {}".format(exp)
7396 )
bhangare06312472017-03-30 05:49:07 -07007397
7398 return status
7399
sousaedu80135b92021-02-17 15:05:18 +01007400 def add_existing_disk(
7401 self,
7402 catalogs=None,
7403 image_id=None,
7404 size=None,
7405 template_name=None,
7406 vapp_uuid=None,
7407 ):
bhangare06312472017-03-30 05:49:07 -07007408 """
sousaedu80135b92021-02-17 15:05:18 +01007409 Method to add existing disk to vm
7410 Args :
7411 catalogs - List of VDC catalogs
7412 image_id - Catalog ID
7413 template_name - Name of template in catalog
7414 vapp_uuid - UUID of vApp
7415 Returns:
7416 None
bhangare06312472017-03-30 05:49:07 -07007417 """
7418 disk_info = None
7419 vcenter_conect, content = self.get_vcenter_content()
beierlb22ce2d2019-12-12 12:09:51 -05007420 # find moref-id of vm in image
sousaedu80135b92021-02-17 15:05:18 +01007421 catalog_vm_info = self.get_vapp_template_details(
7422 catalogs=catalogs,
7423 image_id=image_id,
7424 )
bhangare06312472017-03-30 05:49:07 -07007425
7426 if catalog_vm_info and "vm_vcenter_info" in catalog_vm_info:
7427 if "vm_moref_id" in catalog_vm_info["vm_vcenter_info"]:
sousaedu80135b92021-02-17 15:05:18 +01007428 catalog_vm_moref_id = catalog_vm_info["vm_vcenter_info"].get(
7429 "vm_moref_id", None
7430 )
7431
bhangare06312472017-03-30 05:49:07 -07007432 if catalog_vm_moref_id:
sousaedu80135b92021-02-17 15:05:18 +01007433 self.logger.info(
7434 "Moref_id of VM in catalog : {}".format(catalog_vm_moref_id)
7435 )
beierlb22ce2d2019-12-12 12:09:51 -05007436 _, catalog_vm_obj = self.get_vm_obj(content, catalog_vm_moref_id)
sousaedu80135b92021-02-17 15:05:18 +01007437
bhangare06312472017-03-30 05:49:07 -07007438 if catalog_vm_obj:
beierlb22ce2d2019-12-12 12:09:51 -05007439 # find existing disk
bhangare06312472017-03-30 05:49:07 -07007440 disk_info = self.find_disk(catalog_vm_obj)
7441 else:
7442 exp_msg = "No VM with image id {} found".format(image_id)
7443 self.rollback_newvm(vapp_uuid, exp_msg, exp_type="NotFound")
7444 else:
7445 exp_msg = "No Image found with image ID {} ".format(image_id)
7446 self.rollback_newvm(vapp_uuid, exp_msg, exp_type="NotFound")
7447
7448 if disk_info:
7449 self.logger.info("Existing disk_info : {}".format(disk_info))
beierlb22ce2d2019-12-12 12:09:51 -05007450 # get VM
bhangare06312472017-03-30 05:49:07 -07007451 vm_moref_id = self.get_vm_moref_id(vapp_uuid)
beierlb22ce2d2019-12-12 12:09:51 -05007452 _, vm_obj = self.get_vm_obj(content, vm_moref_id)
sousaedu80135b92021-02-17 15:05:18 +01007453
bhangare06312472017-03-30 05:49:07 -07007454 if vm_obj:
sousaedu80135b92021-02-17 15:05:18 +01007455 status = self.add_disk(
7456 vcenter_conect=vcenter_conect,
7457 vm=vm_obj,
7458 disk_info=disk_info,
7459 size=size,
7460 vapp_uuid=vapp_uuid,
7461 )
7462
bhangare06312472017-03-30 05:49:07 -07007463 if status:
sousaedu80135b92021-02-17 15:05:18 +01007464 self.logger.info(
7465 "Disk from image id {} added to {}".format(
7466 image_id, vm_obj.config.name
7467 )
7468 )
bhangare06312472017-03-30 05:49:07 -07007469 else:
7470 msg = "No disk found with image id {} to add in VM {}".format(
sousaedu80135b92021-02-17 15:05:18 +01007471 image_id, vm_obj.config.name
7472 )
bhangare06312472017-03-30 05:49:07 -07007473 self.rollback_newvm(vapp_uuid, msg, exp_type="NotFound")
7474
bhangare06312472017-03-30 05:49:07 -07007475 def find_disk(self, vm_obj):
7476 """
sousaedu80135b92021-02-17 15:05:18 +01007477 Method to find details of existing disk in VM
7478 Args:
bhangare06312472017-03-30 05:49:07 -07007479 vm_obj - vCenter object of VM
bhangare06312472017-03-30 05:49:07 -07007480 Returns:
7481 disk_info : dict of disk details
7482 """
7483 disk_info = {}
7484 if vm_obj:
7485 try:
7486 devices = vm_obj.config.hardware.device
sousaedu80135b92021-02-17 15:05:18 +01007487
bhangare06312472017-03-30 05:49:07 -07007488 for device in devices:
7489 if type(device) is vim.vm.device.VirtualDisk:
aticig2b24d622022-03-11 15:03:55 +03007490 if isinstance(
7491 device.backing,
7492 vim.vm.device.VirtualDisk.FlatVer2BackingInfo,
7493 ) and hasattr(device.backing, "fileName"):
bhangare06312472017-03-30 05:49:07 -07007494 disk_info["full_path"] = device.backing.fileName
7495 disk_info["datastore"] = device.backing.datastore
7496 disk_info["capacityKB"] = device.capacityInKB
7497 break
7498 except Exception as exp:
sousaedu80135b92021-02-17 15:05:18 +01007499 self.logger.error(
7500 "find_disk() : exception occurred while "
7501 "getting existing disk details :{}".format(exp)
7502 )
7503
bhangare06312472017-03-30 05:49:07 -07007504 return disk_info
7505
sousaedu80135b92021-02-17 15:05:18 +01007506 def add_disk(
7507 self, vcenter_conect=None, vm=None, size=None, vapp_uuid=None, disk_info={}
7508 ):
bhangare06312472017-03-30 05:49:07 -07007509 """
sousaedu80135b92021-02-17 15:05:18 +01007510 Method to add existing disk in VM
7511 Args :
7512 vcenter_conect - vCenter content object
7513 vm - vCenter vm object
7514 disk_info : dict of disk details
7515 Returns:
7516 status : status of add disk task
bhangare06312472017-03-30 05:49:07 -07007517 """
7518 datastore = disk_info["datastore"] if "datastore" in disk_info else None
7519 fullpath = disk_info["full_path"] if "full_path" in disk_info else None
7520 capacityKB = disk_info["capacityKB"] if "capacityKB" in disk_info else None
7521 if size is not None:
beierlb22ce2d2019-12-12 12:09:51 -05007522 # Convert size from GB to KB
bhangare06312472017-03-30 05:49:07 -07007523 sizeKB = int(size) * 1024 * 1024
beierlb22ce2d2019-12-12 12:09:51 -05007524 # compare size of existing disk and user given size.Assign whicherver is greater
sousaedu80135b92021-02-17 15:05:18 +01007525 self.logger.info(
7526 "Add Existing disk : sizeKB {} , capacityKB {}".format(
7527 sizeKB, capacityKB
7528 )
7529 )
7530
bhangare06312472017-03-30 05:49:07 -07007531 if sizeKB > capacityKB:
7532 capacityKB = sizeKB
7533
7534 if datastore and fullpath and capacityKB:
7535 try:
7536 spec = vim.vm.ConfigSpec()
7537 # get all disks on a VM, set unit_number to the next available
7538 unit_number = 0
7539 for dev in vm.config.hardware.device:
sousaedu80135b92021-02-17 15:05:18 +01007540 if hasattr(dev.backing, "fileName"):
bhangare06312472017-03-30 05:49:07 -07007541 unit_number = int(dev.unitNumber) + 1
7542 # unit_number 7 reserved for scsi controller
sousaedu80135b92021-02-17 15:05:18 +01007543
bhangare06312472017-03-30 05:49:07 -07007544 if unit_number == 7:
7545 unit_number += 1
sousaedu80135b92021-02-17 15:05:18 +01007546
bhangare06312472017-03-30 05:49:07 -07007547 if isinstance(dev, vim.vm.device.VirtualDisk):
beierlb22ce2d2019-12-12 12:09:51 -05007548 # vim.vm.device.VirtualSCSIController
bhangare06312472017-03-30 05:49:07 -07007549 controller_key = dev.controllerKey
7550
sousaedu80135b92021-02-17 15:05:18 +01007551 self.logger.info(
7552 "Add Existing disk : unit number {} , controller key {}".format(
7553 unit_number, controller_key
7554 )
7555 )
bhangare06312472017-03-30 05:49:07 -07007556 # add disk here
7557 dev_changes = []
7558 disk_spec = vim.vm.device.VirtualDeviceSpec()
7559 disk_spec.operation = vim.vm.device.VirtualDeviceSpec.Operation.add
7560 disk_spec.device = vim.vm.device.VirtualDisk()
sousaedu80135b92021-02-17 15:05:18 +01007561 disk_spec.device.backing = (
bhangare06312472017-03-30 05:49:07 -07007562 vim.vm.device.VirtualDisk.FlatVer2BackingInfo()
sousaedu80135b92021-02-17 15:05:18 +01007563 )
bhangare06312472017-03-30 05:49:07 -07007564 disk_spec.device.backing.thinProvisioned = True
sousaedu80135b92021-02-17 15:05:18 +01007565 disk_spec.device.backing.diskMode = "persistent"
beierlb22ce2d2019-12-12 12:09:51 -05007566 disk_spec.device.backing.datastore = datastore
7567 disk_spec.device.backing.fileName = fullpath
bhangare06312472017-03-30 05:49:07 -07007568
7569 disk_spec.device.unitNumber = unit_number
7570 disk_spec.device.capacityInKB = capacityKB
7571 disk_spec.device.controllerKey = controller_key
7572 dev_changes.append(disk_spec)
7573 spec.deviceChange = dev_changes
7574 task = vm.ReconfigVM_Task(spec=spec)
7575 status = self.wait_for_vcenter_task(task, vcenter_conect)
sousaedu80135b92021-02-17 15:05:18 +01007576
bhangare06312472017-03-30 05:49:07 -07007577 return status
7578 except Exception as exp:
sousaedu80135b92021-02-17 15:05:18 +01007579 exp_msg = (
7580 "add_disk() : exception {} occurred while adding disk "
7581 "{} to vm {}".format(exp, fullpath, vm.config.name)
7582 )
bhangare06312472017-03-30 05:49:07 -07007583 self.rollback_newvm(vapp_uuid, exp_msg)
7584 else:
sousaedu80135b92021-02-17 15:05:18 +01007585 msg = "add_disk() : Can not add disk to VM with disk info {} ".format(
7586 disk_info
7587 )
bhangare06312472017-03-30 05:49:07 -07007588 self.rollback_newvm(vapp_uuid, msg)
7589
bhangare06312472017-03-30 05:49:07 -07007590 def get_vcenter_content(self):
7591 """
sousaedu80135b92021-02-17 15:05:18 +01007592 Get the vsphere content object
bhangare06312472017-03-30 05:49:07 -07007593 """
7594 try:
7595 vm_vcenter_info = self.get_vm_vcenter_info()
7596 except Exception as exp:
sousaedu80135b92021-02-17 15:05:18 +01007597 self.logger.error(
7598 "Error occurred while getting vCenter infromationn"
7599 " for VM : {}".format(exp)
7600 )
7601
tierno72774862020-05-04 11:44:15 +00007602 raise vimconn.VimConnException(message=exp)
bhangare06312472017-03-30 05:49:07 -07007603
7604 context = None
sousaedu80135b92021-02-17 15:05:18 +01007605 if hasattr(ssl, "_create_unverified_context"):
bhangare06312472017-03-30 05:49:07 -07007606 context = ssl._create_unverified_context()
7607
7608 vcenter_conect = SmartConnect(
beierlb22ce2d2019-12-12 12:09:51 -05007609 host=vm_vcenter_info["vm_vcenter_ip"],
7610 user=vm_vcenter_info["vm_vcenter_user"],
7611 pwd=vm_vcenter_info["vm_vcenter_password"],
7612 port=int(vm_vcenter_info["vm_vcenter_port"]),
sousaedu80135b92021-02-17 15:05:18 +01007613 sslContext=context,
7614 )
bhangare06312472017-03-30 05:49:07 -07007615 atexit.register(Disconnect, vcenter_conect)
7616 content = vcenter_conect.RetrieveContent()
sousaedu80135b92021-02-17 15:05:18 +01007617
bhangare06312472017-03-30 05:49:07 -07007618 return vcenter_conect, content
7619
bhangare06312472017-03-30 05:49:07 -07007620 def get_vm_moref_id(self, vapp_uuid):
7621 """
7622 Get the moref_id of given VM
7623 """
7624 try:
7625 if vapp_uuid:
sousaedu80135b92021-02-17 15:05:18 +01007626 vm_details = self.get_vapp_details_rest(
7627 vapp_uuid, need_admin_access=True
7628 )
7629
bhangare06312472017-03-30 05:49:07 -07007630 if vm_details and "vm_vcenter_info" in vm_details:
7631 vm_moref_id = vm_details["vm_vcenter_info"].get("vm_moref_id", None)
bhangare06312472017-03-30 05:49:07 -07007632
sousaedu80135b92021-02-17 15:05:18 +01007633 return vm_moref_id
bhangare06312472017-03-30 05:49:07 -07007634 except Exception as exp:
sousaedu80135b92021-02-17 15:05:18 +01007635 self.logger.error(
7636 "Error occurred while getting VM moref ID " " for VM : {}".format(exp)
7637 )
7638
bhangare06312472017-03-30 05:49:07 -07007639 return None
7640
sousaedu80135b92021-02-17 15:05:18 +01007641 def get_vapp_template_details(
7642 self, catalogs=None, image_id=None, template_name=None
7643 ):
bhangare06312472017-03-30 05:49:07 -07007644 """
sousaedu80135b92021-02-17 15:05:18 +01007645 Method to get vApp template details
7646 Args :
7647 catalogs - list of VDC catalogs
7648 image_id - Catalog ID to find
7649 template_name : template name in catalog
7650 Returns:
7651 parsed_respond : dict of vApp tempalte details
bhangare06312472017-03-30 05:49:07 -07007652 """
7653 parsed_response = {}
7654
7655 vca = self.connect_as_admin()
7656 if not vca:
tierno72774862020-05-04 11:44:15 +00007657 raise vimconn.VimConnConnectionException("Failed to connect vCD")
bhangare06312472017-03-30 05:49:07 -07007658
7659 try:
beierlb22ce2d2019-12-12 12:09:51 -05007660 org, _ = self.get_vdc_details()
bhangare06312472017-03-30 05:49:07 -07007661 catalog = self.get_catalog_obj(image_id, catalogs)
7662 if catalog:
sousaedu80135b92021-02-17 15:05:18 +01007663 items = org.get_catalog_item(catalog.get("name"), catalog.get("name"))
kasarc5bf2932018-03-09 04:15:22 -08007664 catalog_items = [items.attrib]
7665
bhangare06312472017-03-30 05:49:07 -07007666 if len(catalog_items) == 1:
sousaedu80135b92021-02-17 15:05:18 +01007667 headers = {
7668 "Accept": "application/*+xml;version=" + API_VERSION,
7669 "x-vcloud-authorization": vca._session.headers[
7670 "x-vcloud-authorization"
7671 ],
7672 }
7673 response = self.perform_request(
7674 req_type="GET",
7675 url=catalog_items[0].get("href"),
7676 headers=headers,
7677 )
beierl26fec002019-12-06 17:06:40 -05007678 catalogItem = XmlElementTree.fromstring(response.text)
sousaedu80135b92021-02-17 15:05:18 +01007679 entity = [
7680 child
7681 for child in catalogItem
7682 if child.get("type")
7683 == "application/vnd.vmware.vcloud.vAppTemplate+xml"
7684 ][0]
bhangare06312472017-03-30 05:49:07 -07007685 vapp_tempalte_href = entity.get("href")
beierlb22ce2d2019-12-12 12:09:51 -05007686 # get vapp details and parse moref id
bhangare06312472017-03-30 05:49:07 -07007687
beierlb22ce2d2019-12-12 12:09:51 -05007688 namespaces = {
sousaedu80135b92021-02-17 15:05:18 +01007689 "vssd": "http://schemas.dmtf.org/wbem/wscim/1/cim-schema/2/CIM_VirtualSystemSettingData",
7690 "ovf": "http://schemas.dmtf.org/ovf/envelope/1",
7691 "vmw": "http://www.vmware.com/schema/ovf",
7692 "vm": "http://www.vmware.com/vcloud/v1.5",
7693 "rasd": "http://schemas.dmtf.org/wbem/wscim/1/cim-schema/2/CIM_ResourceAllocationSettingData",
7694 "vmext": "http://www.vmware.com/vcloud/extension/v1.5",
7695 "xmlns": "http://www.vmware.com/vcloud/v1.5",
beierlb22ce2d2019-12-12 12:09:51 -05007696 }
bhangare06312472017-03-30 05:49:07 -07007697
kasarc5bf2932018-03-09 04:15:22 -08007698 if vca._session:
sousaedu80135b92021-02-17 15:05:18 +01007699 response = self.perform_request(
7700 req_type="GET", url=vapp_tempalte_href, headers=headers
7701 )
bhangare06312472017-03-30 05:49:07 -07007702
7703 if response.status_code != requests.codes.ok:
sousaedu80135b92021-02-17 15:05:18 +01007704 self.logger.debug(
7705 "REST API call {} failed. Return status code {}".format(
7706 vapp_tempalte_href, response.status_code
7707 )
7708 )
bhangare06312472017-03-30 05:49:07 -07007709 else:
beierl26fec002019-12-06 17:06:40 -05007710 xmlroot_respond = XmlElementTree.fromstring(response.text)
sousaedu80135b92021-02-17 15:05:18 +01007711 children_section = xmlroot_respond.find(
7712 "vm:Children/", namespaces
7713 )
7714
bhangare06312472017-03-30 05:49:07 -07007715 if children_section is not None:
sousaedu80135b92021-02-17 15:05:18 +01007716 vCloud_extension_section = children_section.find(
7717 "xmlns:VCloudExtension", namespaces
7718 )
7719
bhangare06312472017-03-30 05:49:07 -07007720 if vCloud_extension_section is not None:
7721 vm_vcenter_info = {}
sousaedu80135b92021-02-17 15:05:18 +01007722 vim_info = vCloud_extension_section.find(
7723 "vmext:VmVimInfo", namespaces
7724 )
7725 vmext = vim_info.find(
7726 "vmext:VmVimObjectRef", namespaces
7727 )
bhangare06312472017-03-30 05:49:07 -07007728
sousaedu80135b92021-02-17 15:05:18 +01007729 if vmext is not None:
7730 vm_vcenter_info["vm_moref_id"] = vmext.find(
7731 "vmext:MoRef", namespaces
7732 ).text
7733
7734 parsed_response["vm_vcenter_info"] = vm_vcenter_info
beierlb22ce2d2019-12-12 12:09:51 -05007735 except Exception as exp:
sousaedu80135b92021-02-17 15:05:18 +01007736 self.logger.info(
7737 "Error occurred calling rest api for getting vApp details {}".format(
7738 exp
7739 )
7740 )
bhangare06312472017-03-30 05:49:07 -07007741
7742 return parsed_response
7743
beierlb22ce2d2019-12-12 12:09:51 -05007744 def rollback_newvm(self, vapp_uuid, msg, exp_type="Genric"):
bhangare06312472017-03-30 05:49:07 -07007745 """
sousaedu80135b92021-02-17 15:05:18 +01007746 Method to delete vApp
7747 Args :
7748 vapp_uuid - vApp UUID
7749 msg - Error message to be logged
7750 exp_type : Exception type
7751 Returns:
7752 None
bhangare06312472017-03-30 05:49:07 -07007753 """
7754 if vapp_uuid:
beierlb22ce2d2019-12-12 12:09:51 -05007755 self.delete_vminstance(vapp_uuid)
bhangare06312472017-03-30 05:49:07 -07007756 else:
7757 msg = "No vApp ID"
sousaedu80135b92021-02-17 15:05:18 +01007758
bhangare06312472017-03-30 05:49:07 -07007759 self.logger.error(msg)
sousaedu80135b92021-02-17 15:05:18 +01007760
bhangare06312472017-03-30 05:49:07 -07007761 if exp_type == "Genric":
tierno72774862020-05-04 11:44:15 +00007762 raise vimconn.VimConnException(msg)
bhangare06312472017-03-30 05:49:07 -07007763 elif exp_type == "NotFound":
tierno72774862020-05-04 11:44:15 +00007764 raise vimconn.VimConnNotFoundException(message=msg)
bhangare06312472017-03-30 05:49:07 -07007765
kateac1e3792017-04-01 02:16:39 -07007766 def add_sriov(self, vapp_uuid, sriov_nets, vmname_andid):
7767 """
sousaedu80135b92021-02-17 15:05:18 +01007768 Method to attach SRIOV adapters to VM
kateac1e3792017-04-01 02:16:39 -07007769
sousaedu80135b92021-02-17 15:05:18 +01007770 Args:
7771 vapp_uuid - uuid of vApp/VM
7772 sriov_nets - SRIOV devices infromation as specified in VNFD (flavor)
7773 vmname_andid - vmname
kateac1e3792017-04-01 02:16:39 -07007774
sousaedu80135b92021-02-17 15:05:18 +01007775 Returns:
7776 The status of add SRIOV adapter task , vm object and
7777 vcenter_conect object
kateac1e3792017-04-01 02:16:39 -07007778 """
7779 vm_obj = None
7780 vcenter_conect, content = self.get_vcenter_content()
7781 vm_moref_id = self.get_vm_moref_id(vapp_uuid)
7782
7783 if vm_moref_id:
7784 try:
7785 no_of_sriov_devices = len(sriov_nets)
7786 if no_of_sriov_devices > 0:
beierlb22ce2d2019-12-12 12:09:51 -05007787 # Get VM and its host
kateac1e3792017-04-01 02:16:39 -07007788 host_obj, vm_obj = self.get_vm_obj(content, vm_moref_id)
sousaedu80135b92021-02-17 15:05:18 +01007789 self.logger.info(
7790 "VM {} is currently on host {}".format(vm_obj, host_obj)
7791 )
7792
kateac1e3792017-04-01 02:16:39 -07007793 if host_obj and vm_obj:
beierlb22ce2d2019-12-12 12:09:51 -05007794 # get SRIOV devies from host on which vapp is currently installed
sousaedu80135b92021-02-17 15:05:18 +01007795 avilable_sriov_devices = self.get_sriov_devices(
7796 host_obj,
7797 no_of_sriov_devices,
7798 )
kateac1e3792017-04-01 02:16:39 -07007799
7800 if len(avilable_sriov_devices) == 0:
beierlb22ce2d2019-12-12 12:09:51 -05007801 # find other hosts with active pci devices
sousaedu80135b92021-02-17 15:05:18 +01007802 (
7803 new_host_obj,
7804 avilable_sriov_devices,
7805 ) = self.get_host_and_sriov_devices(
beierlb22ce2d2019-12-12 12:09:51 -05007806 content,
7807 no_of_sriov_devices,
sousaedu80135b92021-02-17 15:05:18 +01007808 )
kateac1e3792017-04-01 02:16:39 -07007809
sousaedu80135b92021-02-17 15:05:18 +01007810 if (
7811 new_host_obj is not None
7812 and len(avilable_sriov_devices) > 0
7813 ):
beierlb22ce2d2019-12-12 12:09:51 -05007814 # Migrate vm to the host where SRIOV devices are available
sousaedu80135b92021-02-17 15:05:18 +01007815 self.logger.info(
7816 "Relocate VM {} on new host {}".format(
7817 vm_obj, new_host_obj
7818 )
7819 )
kateac1e3792017-04-01 02:16:39 -07007820 task = self.relocate_vm(new_host_obj, vm_obj)
sousaedu80135b92021-02-17 15:05:18 +01007821
kateac1e3792017-04-01 02:16:39 -07007822 if task is not None:
sousaedu80135b92021-02-17 15:05:18 +01007823 result = self.wait_for_vcenter_task(
7824 task, vcenter_conect
7825 )
7826 self.logger.info(
7827 "Migrate VM status: {}".format(result)
7828 )
kateac1e3792017-04-01 02:16:39 -07007829 host_obj = new_host_obj
7830 else:
sousaedu80135b92021-02-17 15:05:18 +01007831 self.logger.info(
7832 "Fail to migrate VM : {}".format(result)
7833 )
7834
tierno72774862020-05-04 11:44:15 +00007835 raise vimconn.VimConnNotFoundException(
beierlb22ce2d2019-12-12 12:09:51 -05007836 "Fail to migrate VM : {} to host {}".format(
sousaedu80135b92021-02-17 15:05:18 +01007837 vmname_andid, new_host_obj
kateac1e3792017-04-01 02:16:39 -07007838 )
sousaedu80135b92021-02-17 15:05:18 +01007839 )
kateac1e3792017-04-01 02:16:39 -07007840
sousaedu80135b92021-02-17 15:05:18 +01007841 if (
7842 host_obj is not None
7843 and avilable_sriov_devices is not None
7844 and len(avilable_sriov_devices) > 0
7845 ):
beierlb22ce2d2019-12-12 12:09:51 -05007846 # Add SRIOV devices one by one
kateac1e3792017-04-01 02:16:39 -07007847 for sriov_net in sriov_nets:
sousaedu80135b92021-02-17 15:05:18 +01007848 network_name = sriov_net.get("net_id")
beierlb22ce2d2019-12-12 12:09:51 -05007849 self.create_dvPort_group(network_name)
kateac1e3792017-04-01 02:16:39 -07007850
sousaedu80135b92021-02-17 15:05:18 +01007851 if (
7852 sriov_net.get("type") == "VF"
7853 or sriov_net.get("type") == "SR-IOV"
7854 ):
7855 # add vlan ID ,Modify portgroup for vlan ID
7856 self.configure_vlanID(
7857 content, vcenter_conect, network_name
7858 )
7859
7860 task = self.add_sriov_to_vm(
7861 content,
7862 vm_obj,
7863 host_obj,
7864 network_name,
7865 avilable_sriov_devices[0],
7866 )
7867
kateac1e3792017-04-01 02:16:39 -07007868 if task:
sousaedu80135b92021-02-17 15:05:18 +01007869 status = self.wait_for_vcenter_task(
7870 task, vcenter_conect
7871 )
7872
kateac1e3792017-04-01 02:16:39 -07007873 if status:
sousaedu80135b92021-02-17 15:05:18 +01007874 self.logger.info(
7875 "Added SRIOV {} to VM {}".format(
7876 no_of_sriov_devices, str(vm_obj)
7877 )
kateac1e3792017-04-01 02:16:39 -07007878 )
sousaedu80135b92021-02-17 15:05:18 +01007879 else:
7880 self.logger.error(
7881 "Fail to add SRIOV {} to VM {}".format(
7882 no_of_sriov_devices, str(vm_obj)
7883 )
7884 )
7885
7886 raise vimconn.VimConnUnexpectedResponse(
7887 "Fail to add SRIOV adapter in VM {}".format(
7888 str(vm_obj)
7889 )
7890 )
7891
kateac1e3792017-04-01 02:16:39 -07007892 return True, vm_obj, vcenter_conect
7893 else:
sousaedu80135b92021-02-17 15:05:18 +01007894 self.logger.error(
7895 "Currently there is no host with"
7896 " {} number of avaialble SRIOV "
7897 "VFs required for VM {}".format(
7898 no_of_sriov_devices, vmname_andid
7899 )
7900 )
7901
tierno72774862020-05-04 11:44:15 +00007902 raise vimconn.VimConnNotFoundException(
beierlb22ce2d2019-12-12 12:09:51 -05007903 "Currently there is no host with {} "
7904 "number of avaialble SRIOV devices required for VM {}".format(
sousaedu80135b92021-02-17 15:05:18 +01007905 no_of_sriov_devices, vmname_andid
7906 )
7907 )
kateac1e3792017-04-01 02:16:39 -07007908 else:
sousaedu80135b92021-02-17 15:05:18 +01007909 self.logger.debug(
7910 "No infromation about SRIOV devices {} ", sriov_nets
7911 )
kateac1e3792017-04-01 02:16:39 -07007912 except vmodl.MethodFault as error:
beierlb22ce2d2019-12-12 12:09:51 -05007913 self.logger.error("Error occurred while adding SRIOV {} ", error)
sousaedu80135b92021-02-17 15:05:18 +01007914
kateac1e3792017-04-01 02:16:39 -07007915 return None, vm_obj, vcenter_conect
7916
beierlb22ce2d2019-12-12 12:09:51 -05007917 def get_sriov_devices(self, host, no_of_vfs):
kateac1e3792017-04-01 02:16:39 -07007918 """
sousaedu80135b92021-02-17 15:05:18 +01007919 Method to get the details of SRIOV devices on given host
7920 Args:
7921 host - vSphere host object
7922 no_of_vfs - number of VFs needed on host
kateac1e3792017-04-01 02:16:39 -07007923
sousaedu80135b92021-02-17 15:05:18 +01007924 Returns:
7925 array of SRIOV devices
kateac1e3792017-04-01 02:16:39 -07007926 """
beierlb22ce2d2019-12-12 12:09:51 -05007927 sriovInfo = []
sousaedu80135b92021-02-17 15:05:18 +01007928
kateac1e3792017-04-01 02:16:39 -07007929 if host:
7930 for device in host.config.pciPassthruInfo:
beierlb22ce2d2019-12-12 12:09:51 -05007931 if isinstance(device, vim.host.SriovInfo) and device.sriovActive:
kateac1e3792017-04-01 02:16:39 -07007932 if device.numVirtualFunction >= no_of_vfs:
7933 sriovInfo.append(device)
7934 break
sousaedu80135b92021-02-17 15:05:18 +01007935
kateac1e3792017-04-01 02:16:39 -07007936 return sriovInfo
7937
kateac1e3792017-04-01 02:16:39 -07007938 def get_host_and_sriov_devices(self, content, no_of_vfs):
7939 """
sousaedu80135b92021-02-17 15:05:18 +01007940 Method to get the details of SRIOV devices infromation on all hosts
kateac1e3792017-04-01 02:16:39 -07007941
sousaedu80135b92021-02-17 15:05:18 +01007942 Args:
7943 content - vSphere host object
7944 no_of_vfs - number of pci VFs needed on host
kateac1e3792017-04-01 02:16:39 -07007945
sousaedu80135b92021-02-17 15:05:18 +01007946 Returns:
7947 array of SRIOV devices and host object
kateac1e3792017-04-01 02:16:39 -07007948 """
7949 host_obj = None
7950 sriov_device_objs = None
sousaedu80135b92021-02-17 15:05:18 +01007951
kateac1e3792017-04-01 02:16:39 -07007952 try:
7953 if content:
sousaedu80135b92021-02-17 15:05:18 +01007954 container = content.viewManager.CreateContainerView(
7955 content.rootFolder, [vim.HostSystem], True
7956 )
7957
kateac1e3792017-04-01 02:16:39 -07007958 for host in container.view:
7959 devices = self.get_sriov_devices(host, no_of_vfs)
sousaedu80135b92021-02-17 15:05:18 +01007960
kateac1e3792017-04-01 02:16:39 -07007961 if devices:
7962 host_obj = host
7963 sriov_device_objs = devices
7964 break
7965 except Exception as exp:
sousaedu80135b92021-02-17 15:05:18 +01007966 self.logger.error(
7967 "Error {} occurred while finding SRIOV devices on host: {}".format(
7968 exp, host_obj
7969 )
7970 )
kateac1e3792017-04-01 02:16:39 -07007971
beierlb22ce2d2019-12-12 12:09:51 -05007972 return host_obj, sriov_device_objs
kateac1e3792017-04-01 02:16:39 -07007973
beierlb22ce2d2019-12-12 12:09:51 -05007974 def add_sriov_to_vm(self, content, vm_obj, host_obj, network_name, sriov_device):
kateac1e3792017-04-01 02:16:39 -07007975 """
sousaedu80135b92021-02-17 15:05:18 +01007976 Method to add SRIOV adapter to vm
kateac1e3792017-04-01 02:16:39 -07007977
sousaedu80135b92021-02-17 15:05:18 +01007978 Args:
7979 host_obj - vSphere host object
7980 vm_obj - vSphere vm object
7981 content - vCenter content object
7982 network_name - name of distributed virtaul portgroup
7983 sriov_device - SRIOV device info
kateac1e3792017-04-01 02:16:39 -07007984
sousaedu80135b92021-02-17 15:05:18 +01007985 Returns:
7986 task object
kateac1e3792017-04-01 02:16:39 -07007987 """
7988 devices = []
7989 vnic_label = "sriov nic"
sousaedu80135b92021-02-17 15:05:18 +01007990
kateac1e3792017-04-01 02:16:39 -07007991 try:
7992 dvs_portgr = self.get_dvport_group(network_name)
7993 network_name = dvs_portgr.name
7994 nic = vim.vm.device.VirtualDeviceSpec()
7995 # VM device
7996 nic.operation = vim.vm.device.VirtualDeviceSpec.Operation.add
7997 nic.device = vim.vm.device.VirtualSriovEthernetCard()
sousaedu80135b92021-02-17 15:05:18 +01007998 nic.device.addressType = "assigned"
beierlb22ce2d2019-12-12 12:09:51 -05007999 # nic.device.key = 13016
kateac1e3792017-04-01 02:16:39 -07008000 nic.device.deviceInfo = vim.Description()
8001 nic.device.deviceInfo.label = vnic_label
8002 nic.device.deviceInfo.summary = network_name
8003 nic.device.backing = vim.vm.device.VirtualEthernetCard.NetworkBackingInfo()
8004
sousaedu80135b92021-02-17 15:05:18 +01008005 nic.device.backing.network = self.get_obj(
8006 content, [vim.Network], network_name
8007 )
kateac1e3792017-04-01 02:16:39 -07008008 nic.device.backing.deviceName = network_name
8009 nic.device.backing.useAutoDetect = False
8010 nic.device.connectable = vim.vm.device.VirtualDevice.ConnectInfo()
8011 nic.device.connectable.startConnected = True
8012 nic.device.connectable.allowGuestControl = True
8013
sousaedu80135b92021-02-17 15:05:18 +01008014 nic.device.sriovBacking = (
8015 vim.vm.device.VirtualSriovEthernetCard.SriovBackingInfo()
8016 )
8017 nic.device.sriovBacking.physicalFunctionBacking = (
8018 vim.vm.device.VirtualPCIPassthrough.DeviceBackingInfo()
8019 )
kateac1e3792017-04-01 02:16:39 -07008020 nic.device.sriovBacking.physicalFunctionBacking.id = sriov_device.id
8021
8022 devices.append(nic)
8023 vmconf = vim.vm.ConfigSpec(deviceChange=devices)
8024 task = vm_obj.ReconfigVM_Task(vmconf)
sousaedu80135b92021-02-17 15:05:18 +01008025
kateac1e3792017-04-01 02:16:39 -07008026 return task
8027 except Exception as exp:
sousaedu80135b92021-02-17 15:05:18 +01008028 self.logger.error(
8029 "Error {} occurred while adding SRIOV adapter in VM: {}".format(
8030 exp, vm_obj
8031 )
8032 )
8033
kateac1e3792017-04-01 02:16:39 -07008034 return None
8035
kateac1e3792017-04-01 02:16:39 -07008036 def create_dvPort_group(self, network_name):
8037 """
sousaedu80135b92021-02-17 15:05:18 +01008038 Method to create disributed virtual portgroup
kateac1e3792017-04-01 02:16:39 -07008039
sousaedu80135b92021-02-17 15:05:18 +01008040 Args:
8041 network_name - name of network/portgroup
kateac1e3792017-04-01 02:16:39 -07008042
sousaedu80135b92021-02-17 15:05:18 +01008043 Returns:
8044 portgroup key
kateac1e3792017-04-01 02:16:39 -07008045 """
8046 try:
sousaedu80135b92021-02-17 15:05:18 +01008047 new_network_name = [network_name, "-", str(uuid.uuid4())]
8048 network_name = "".join(new_network_name)
kateac1e3792017-04-01 02:16:39 -07008049 vcenter_conect, content = self.get_vcenter_content()
8050
sousaedu80135b92021-02-17 15:05:18 +01008051 dv_switch = self.get_obj(
8052 content, [vim.DistributedVirtualSwitch], self.dvs_name
8053 )
8054
kateac1e3792017-04-01 02:16:39 -07008055 if dv_switch:
8056 dv_pg_spec = vim.dvs.DistributedVirtualPortgroup.ConfigSpec()
8057 dv_pg_spec.name = network_name
8058
sousaedu80135b92021-02-17 15:05:18 +01008059 dv_pg_spec.type = (
8060 vim.dvs.DistributedVirtualPortgroup.PortgroupType.earlyBinding
8061 )
8062 dv_pg_spec.defaultPortConfig = (
8063 vim.dvs.VmwareDistributedVirtualSwitch.VmwarePortConfigPolicy()
8064 )
8065 dv_pg_spec.defaultPortConfig.securityPolicy = (
8066 vim.dvs.VmwareDistributedVirtualSwitch.SecurityPolicy()
8067 )
8068 dv_pg_spec.defaultPortConfig.securityPolicy.allowPromiscuous = (
8069 vim.BoolPolicy(value=False)
8070 )
8071 dv_pg_spec.defaultPortConfig.securityPolicy.forgedTransmits = (
8072 vim.BoolPolicy(value=False)
8073 )
8074 dv_pg_spec.defaultPortConfig.securityPolicy.macChanges = vim.BoolPolicy(
8075 value=False
8076 )
kateac1e3792017-04-01 02:16:39 -07008077
8078 task = dv_switch.AddDVPortgroup_Task([dv_pg_spec])
8079 self.wait_for_vcenter_task(task, vcenter_conect)
8080
sousaedu80135b92021-02-17 15:05:18 +01008081 dvPort_group = self.get_obj(
8082 content, [vim.dvs.DistributedVirtualPortgroup], network_name
8083 )
8084
kateac1e3792017-04-01 02:16:39 -07008085 if dvPort_group:
sousaedu80135b92021-02-17 15:05:18 +01008086 self.logger.info(
8087 "Created disributed virtaul port group: {}".format(dvPort_group)
8088 )
kateac1e3792017-04-01 02:16:39 -07008089 return dvPort_group.key
8090 else:
sousaedu80135b92021-02-17 15:05:18 +01008091 self.logger.debug(
8092 "No disributed virtual switch found with name {}".format(
8093 network_name
8094 )
8095 )
kateac1e3792017-04-01 02:16:39 -07008096
8097 except Exception as exp:
sousaedu80135b92021-02-17 15:05:18 +01008098 self.logger.error(
8099 "Error occurred while creating disributed virtaul port group {}"
8100 " : {}".format(network_name, exp)
8101 )
8102
kateac1e3792017-04-01 02:16:39 -07008103 return None
8104
beierlb22ce2d2019-12-12 12:09:51 -05008105 def reconfig_portgroup(self, content, dvPort_group_name, config_info={}):
kateac1e3792017-04-01 02:16:39 -07008106 """
sousaedu80135b92021-02-17 15:05:18 +01008107 Method to reconfigure disributed virtual portgroup
kateac1e3792017-04-01 02:16:39 -07008108
sousaedu80135b92021-02-17 15:05:18 +01008109 Args:
8110 dvPort_group_name - name of disributed virtual portgroup
8111 content - vCenter content object
8112 config_info - disributed virtual portgroup configuration
kateac1e3792017-04-01 02:16:39 -07008113
sousaedu80135b92021-02-17 15:05:18 +01008114 Returns:
8115 task object
kateac1e3792017-04-01 02:16:39 -07008116 """
8117 try:
8118 dvPort_group = self.get_dvport_group(dvPort_group_name)
sousaedu80135b92021-02-17 15:05:18 +01008119
kateac1e3792017-04-01 02:16:39 -07008120 if dvPort_group:
8121 dv_pg_spec = vim.dvs.DistributedVirtualPortgroup.ConfigSpec()
8122 dv_pg_spec.configVersion = dvPort_group.config.configVersion
sousaedu80135b92021-02-17 15:05:18 +01008123 dv_pg_spec.defaultPortConfig = (
8124 vim.dvs.VmwareDistributedVirtualSwitch.VmwarePortConfigPolicy()
8125 )
8126
kateac1e3792017-04-01 02:16:39 -07008127 if "vlanID" in config_info:
sousaedu80135b92021-02-17 15:05:18 +01008128 dv_pg_spec.defaultPortConfig.vlan = (
8129 vim.dvs.VmwareDistributedVirtualSwitch.VlanIdSpec()
8130 )
8131 dv_pg_spec.defaultPortConfig.vlan.vlanId = config_info.get("vlanID")
kateac1e3792017-04-01 02:16:39 -07008132
8133 task = dvPort_group.ReconfigureDVPortgroup_Task(spec=dv_pg_spec)
sousaedu80135b92021-02-17 15:05:18 +01008134
kateac1e3792017-04-01 02:16:39 -07008135 return task
8136 else:
8137 return None
8138 except Exception as exp:
sousaedu80135b92021-02-17 15:05:18 +01008139 self.logger.error(
8140 "Error occurred while reconfiguraing disributed virtaul port group {}"
8141 " : {}".format(dvPort_group_name, exp)
8142 )
8143
kateac1e3792017-04-01 02:16:39 -07008144 return None
8145
beierlb22ce2d2019-12-12 12:09:51 -05008146 def destroy_dvport_group(self, dvPort_group_name):
kateac1e3792017-04-01 02:16:39 -07008147 """
sousaedu80135b92021-02-17 15:05:18 +01008148 Method to destroy disributed virtual portgroup
kateac1e3792017-04-01 02:16:39 -07008149
sousaedu80135b92021-02-17 15:05:18 +01008150 Args:
8151 network_name - name of network/portgroup
kateac1e3792017-04-01 02:16:39 -07008152
sousaedu80135b92021-02-17 15:05:18 +01008153 Returns:
8154 True if portgroup successfully got deleted else false
kateac1e3792017-04-01 02:16:39 -07008155 """
beierlb22ce2d2019-12-12 12:09:51 -05008156 vcenter_conect, _ = self.get_vcenter_content()
sousaedu80135b92021-02-17 15:05:18 +01008157
kateac1e3792017-04-01 02:16:39 -07008158 try:
8159 status = None
8160 dvPort_group = self.get_dvport_group(dvPort_group_name)
sousaedu80135b92021-02-17 15:05:18 +01008161
kateac1e3792017-04-01 02:16:39 -07008162 if dvPort_group:
8163 task = dvPort_group.Destroy_Task()
8164 status = self.wait_for_vcenter_task(task, vcenter_conect)
sousaedu80135b92021-02-17 15:05:18 +01008165
kateac1e3792017-04-01 02:16:39 -07008166 return status
8167 except vmodl.MethodFault as exp:
sousaedu80135b92021-02-17 15:05:18 +01008168 self.logger.error(
8169 "Caught vmodl fault {} while deleting disributed virtaul port group {}".format(
8170 exp, dvPort_group_name
8171 )
8172 )
8173
kateac1e3792017-04-01 02:16:39 -07008174 return None
8175
kateac1e3792017-04-01 02:16:39 -07008176 def get_dvport_group(self, dvPort_group_name):
8177 """
8178 Method to get disributed virtual portgroup
8179
8180 Args:
8181 network_name - name of network/portgroup
8182
8183 Returns:
8184 portgroup object
8185 """
beierlb22ce2d2019-12-12 12:09:51 -05008186 _, content = self.get_vcenter_content()
kateac1e3792017-04-01 02:16:39 -07008187 dvPort_group = None
sousaedu80135b92021-02-17 15:05:18 +01008188
kateac1e3792017-04-01 02:16:39 -07008189 try:
sousaedu80135b92021-02-17 15:05:18 +01008190 container = content.viewManager.CreateContainerView(
8191 content.rootFolder, [vim.dvs.DistributedVirtualPortgroup], True
8192 )
8193
kateac1e3792017-04-01 02:16:39 -07008194 for item in container.view:
8195 if item.key == dvPort_group_name:
8196 dvPort_group = item
8197 break
sousaedu80135b92021-02-17 15:05:18 +01008198
kateac1e3792017-04-01 02:16:39 -07008199 return dvPort_group
8200 except vmodl.MethodFault as exp:
sousaedu80135b92021-02-17 15:05:18 +01008201 self.logger.error(
8202 "Caught vmodl fault {} for disributed virtual port group {}".format(
8203 exp, dvPort_group_name
8204 )
8205 )
8206
kateac1e3792017-04-01 02:16:39 -07008207 return None
8208
8209 def get_vlanID_from_dvs_portgr(self, dvPort_group_name):
8210 """
sousaedu80135b92021-02-17 15:05:18 +01008211 Method to get disributed virtual portgroup vlanID
kateac1e3792017-04-01 02:16:39 -07008212
sousaedu80135b92021-02-17 15:05:18 +01008213 Args:
8214 network_name - name of network/portgroup
kateac1e3792017-04-01 02:16:39 -07008215
sousaedu80135b92021-02-17 15:05:18 +01008216 Returns:
8217 vlan ID
kateac1e3792017-04-01 02:16:39 -07008218 """
8219 vlanId = None
sousaedu80135b92021-02-17 15:05:18 +01008220
kateac1e3792017-04-01 02:16:39 -07008221 try:
8222 dvPort_group = self.get_dvport_group(dvPort_group_name)
sousaedu80135b92021-02-17 15:05:18 +01008223
kateac1e3792017-04-01 02:16:39 -07008224 if dvPort_group:
8225 vlanId = dvPort_group.config.defaultPortConfig.vlan.vlanId
8226 except vmodl.MethodFault as exp:
sousaedu80135b92021-02-17 15:05:18 +01008227 self.logger.error(
8228 "Caught vmodl fault {} for disributed virtaul port group {}".format(
8229 exp, dvPort_group_name
8230 )
8231 )
8232
kateac1e3792017-04-01 02:16:39 -07008233 return vlanId
8234
kateac1e3792017-04-01 02:16:39 -07008235 def configure_vlanID(self, content, vcenter_conect, dvPort_group_name):
8236 """
sousaedu80135b92021-02-17 15:05:18 +01008237 Method to configure vlanID in disributed virtual portgroup vlanID
kateac1e3792017-04-01 02:16:39 -07008238
sousaedu80135b92021-02-17 15:05:18 +01008239 Args:
8240 network_name - name of network/portgroup
kateac1e3792017-04-01 02:16:39 -07008241
sousaedu80135b92021-02-17 15:05:18 +01008242 Returns:
8243 None
kateac1e3792017-04-01 02:16:39 -07008244 """
8245 vlanID = self.get_vlanID_from_dvs_portgr(dvPort_group_name)
sousaedu80135b92021-02-17 15:05:18 +01008246
kateac1e3792017-04-01 02:16:39 -07008247 if vlanID == 0:
beierlb22ce2d2019-12-12 12:09:51 -05008248 # configure vlanID
kateac1e3792017-04-01 02:16:39 -07008249 vlanID = self.genrate_vlanID(dvPort_group_name)
beierlb22ce2d2019-12-12 12:09:51 -05008250 config = {"vlanID": vlanID}
sousaedu80135b92021-02-17 15:05:18 +01008251 task = self.reconfig_portgroup(
8252 content, dvPort_group_name, config_info=config
8253 )
8254
kateac1e3792017-04-01 02:16:39 -07008255 if task:
beierlb22ce2d2019-12-12 12:09:51 -05008256 status = self.wait_for_vcenter_task(task, vcenter_conect)
sousaedu80135b92021-02-17 15:05:18 +01008257
kateac1e3792017-04-01 02:16:39 -07008258 if status:
sousaedu80135b92021-02-17 15:05:18 +01008259 self.logger.info(
8260 "Reconfigured Port group {} for vlan ID {}".format(
8261 dvPort_group_name, vlanID
8262 )
8263 )
kateac1e3792017-04-01 02:16:39 -07008264 else:
sousaedu80135b92021-02-17 15:05:18 +01008265 self.logger.error(
8266 "Fail reconfigure portgroup {} for vlanID{}".format(
8267 dvPort_group_name, vlanID
8268 )
8269 )
kateac1e3792017-04-01 02:16:39 -07008270
8271 def genrate_vlanID(self, network_name):
8272 """
sousaedu80135b92021-02-17 15:05:18 +01008273 Method to get unused vlanID
8274 Args:
8275 network_name - name of network/portgroup
8276 Returns:
8277 vlanID
kateac1e3792017-04-01 02:16:39 -07008278 """
8279 vlan_id = None
8280 used_ids = []
sousaedu80135b92021-02-17 15:05:18 +01008281
8282 if self.config.get("vlanID_range") is None:
8283 raise vimconn.VimConnConflictException(
8284 "You must provide a 'vlanID_range' "
8285 "at config value before creating sriov network with vlan tag"
8286 )
8287
kateac1e3792017-04-01 02:16:39 -07008288 if "used_vlanIDs" not in self.persistent_info:
sousaedu80135b92021-02-17 15:05:18 +01008289 self.persistent_info["used_vlanIDs"] = {}
kateac1e3792017-04-01 02:16:39 -07008290 else:
tierno7d782ef2019-10-04 12:56:31 +00008291 used_ids = list(self.persistent_info["used_vlanIDs"].values())
kateac1e3792017-04-01 02:16:39 -07008292
sousaedu80135b92021-02-17 15:05:18 +01008293 for vlanID_range in self.config.get("vlanID_range"):
tierno1b856002019-11-07 16:28:54 +00008294 start_vlanid, end_vlanid = vlanID_range.split("-")
sousaedu80135b92021-02-17 15:05:18 +01008295
kateac1e3792017-04-01 02:16:39 -07008296 if start_vlanid > end_vlanid:
sousaedu80135b92021-02-17 15:05:18 +01008297 raise vimconn.VimConnConflictException(
8298 "Invalid vlan ID range {}".format(vlanID_range)
8299 )
kateac1e3792017-04-01 02:16:39 -07008300
beierlb22ce2d2019-12-12 12:09:51 -05008301 for vid in range(int(start_vlanid), int(end_vlanid) + 1):
8302 if vid not in used_ids:
8303 vlan_id = vid
kateac1e3792017-04-01 02:16:39 -07008304 self.persistent_info["used_vlanIDs"][network_name] = vlan_id
8305 return vlan_id
sousaedu80135b92021-02-17 15:05:18 +01008306
kateac1e3792017-04-01 02:16:39 -07008307 if vlan_id is None:
tierno72774862020-05-04 11:44:15 +00008308 raise vimconn.VimConnConflictException("All Vlan IDs are in use")
kateac1e3792017-04-01 02:16:39 -07008309
kateac1e3792017-04-01 02:16:39 -07008310 def get_obj(self, content, vimtype, name):
8311 """
sousaedu80135b92021-02-17 15:05:18 +01008312 Get the vsphere object associated with a given text name
kateac1e3792017-04-01 02:16:39 -07008313 """
8314 obj = None
sousaedu80135b92021-02-17 15:05:18 +01008315 container = content.viewManager.CreateContainerView(
8316 content.rootFolder, vimtype, True
8317 )
8318
kateac1e3792017-04-01 02:16:39 -07008319 for item in container.view:
8320 if item.name == name:
8321 obj = item
8322 break
sousaedu80135b92021-02-17 15:05:18 +01008323
kateac1e3792017-04-01 02:16:39 -07008324 return obj
8325
kasar0c007d62017-05-19 03:13:57 -07008326 def insert_media_to_vm(self, vapp, image_id):
8327 """
8328 Method to insert media CD-ROM (ISO image) from catalog to vm.
8329 vapp - vapp object to get vm id
8330 Image_id - image id for cdrom to be inerted to vm
8331 """
8332 # create connection object
8333 vca = self.connect()
8334 try:
8335 # fetching catalog details
kasarc5bf2932018-03-09 04:15:22 -08008336 rest_url = "{}/api/catalog/{}".format(self.url, image_id)
sousaedu80135b92021-02-17 15:05:18 +01008337
kasarc5bf2932018-03-09 04:15:22 -08008338 if vca._session:
sousaedu80135b92021-02-17 15:05:18 +01008339 headers = {
8340 "Accept": "application/*+xml;version=" + API_VERSION,
8341 "x-vcloud-authorization": vca._session.headers[
8342 "x-vcloud-authorization"
8343 ],
8344 }
8345 response = self.perform_request(
8346 req_type="GET", url=rest_url, headers=headers
8347 )
kasar0c007d62017-05-19 03:13:57 -07008348
8349 if response.status_code != 200:
sousaedu80135b92021-02-17 15:05:18 +01008350 self.logger.error(
8351 "REST call {} failed reason : {}"
8352 "status code : {}".format(
8353 rest_url, response.text, response.status_code
8354 )
8355 )
8356
8357 raise vimconn.VimConnException(
8358 "insert_media_to_vm(): Failed to get " "catalog details"
8359 )
8360
kasar0c007d62017-05-19 03:13:57 -07008361 # searching iso name and id
beierl26fec002019-12-06 17:06:40 -05008362 iso_name, media_id = self.get_media_details(vca, response.text)
kasar0c007d62017-05-19 03:13:57 -07008363
8364 if iso_name and media_id:
beierlb22ce2d2019-12-12 12:09:51 -05008365 data = """<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
kasar0c007d62017-05-19 03:13:57 -07008366 <ns6:MediaInsertOrEjectParams
beierl26fec002019-12-06 17:06:40 -05008367 xmlns="http://www.vmware.com/vcloud/versions" xmlns:ns2="http://schemas.dmtf.org/ovf/envelope/1"
8368 xmlns:ns3="http://schemas.dmtf.org/wbem/wscim/1/cim-schema/2/CIM_VirtualSystemSettingData"
8369 xmlns:ns4="http://schemas.dmtf.org/wbem/wscim/1/common"
8370 xmlns:ns5="http://schemas.dmtf.org/wbem/wscim/1/cim-schema/2/CIM_ResourceAllocationSettingData"
8371 xmlns:ns6="http://www.vmware.com/vcloud/v1.5"
8372 xmlns:ns7="http://www.vmware.com/schema/ovf"
8373 xmlns:ns8="http://schemas.dmtf.org/ovf/environment/1"
Ananda Baitharu319c26f2019-03-05 17:34:31 +00008374 xmlns:ns9="http://www.vmware.com/vcloud/extension/v1.5">
kasar0c007d62017-05-19 03:13:57 -07008375 <ns6:Media
8376 type="application/vnd.vmware.vcloud.media+xml"
Ananda Baitharu319c26f2019-03-05 17:34:31 +00008377 name="{}"
kasar0c007d62017-05-19 03:13:57 -07008378 id="urn:vcloud:media:{}"
8379 href="https://{}/api/media/{}"/>
sousaedu80135b92021-02-17 15:05:18 +01008380 </ns6:MediaInsertOrEjectParams>""".format(
8381 iso_name, media_id, self.url, media_id
8382 )
kasar0c007d62017-05-19 03:13:57 -07008383
kasarc5bf2932018-03-09 04:15:22 -08008384 for vms in vapp.get_all_vms():
sousaedu80135b92021-02-17 15:05:18 +01008385 vm_id = vms.get("id").split(":")[-1]
kasar0c007d62017-05-19 03:13:57 -07008386
sousaedu80135b92021-02-17 15:05:18 +01008387 headers[
8388 "Content-Type"
8389 ] = "application/vnd.vmware.vcloud.mediaInsertOrEjectParams+xml"
8390 rest_url = "{}/api/vApp/vm-{}/media/action/insertMedia".format(
8391 self.url, vm_id
8392 )
kasar0c007d62017-05-19 03:13:57 -07008393
sousaedu80135b92021-02-17 15:05:18 +01008394 response = self.perform_request(
8395 req_type="POST", url=rest_url, data=data, headers=headers
8396 )
kasar0c007d62017-05-19 03:13:57 -07008397
8398 if response.status_code != 202:
sousaedu80135b92021-02-17 15:05:18 +01008399 error_msg = (
8400 "insert_media_to_vm() : Failed to insert CD-ROM to vm. Reason {}. "
8401 "Status code {}".format(response.text, response.status_code)
8402 )
Ananda Baitharu319c26f2019-03-05 17:34:31 +00008403 self.logger.error(error_msg)
sousaedu80135b92021-02-17 15:05:18 +01008404
tierno72774862020-05-04 11:44:15 +00008405 raise vimconn.VimConnException(error_msg)
kasar0c007d62017-05-19 03:13:57 -07008406 else:
beierl26fec002019-12-06 17:06:40 -05008407 task = self.get_task_from_response(response.text)
sousaedu80135b92021-02-17 15:05:18 +01008408 result = self.client.get_task_monitor().wait_for_success(
8409 task=task
8410 )
kasarc5bf2932018-03-09 04:15:22 -08008411
sousaedu80135b92021-02-17 15:05:18 +01008412 if result.get("status") == "success":
8413 self.logger.info(
8414 "insert_media_to_vm(): Sucessfully inserted media ISO"
8415 " image to vm {}".format(vm_id)
8416 )
kasar0c007d62017-05-19 03:13:57 -07008417 except Exception as exp:
sousaedu80135b92021-02-17 15:05:18 +01008418 self.logger.error(
8419 "insert_media_to_vm() : exception occurred "
8420 "while inserting media CD-ROM"
8421 )
8422
tierno72774862020-05-04 11:44:15 +00008423 raise vimconn.VimConnException(message=exp)
kasar0c007d62017-05-19 03:13:57 -07008424
kasar0c007d62017-05-19 03:13:57 -07008425 def get_media_details(self, vca, content):
8426 """
8427 Method to get catalog item details
8428 vca - connection object
8429 content - Catalog details
8430 Return - Media name, media id
8431 """
8432 cataloghref_list = []
8433 try:
8434 if content:
8435 vm_list_xmlroot = XmlElementTree.fromstring(content)
sousaedu80135b92021-02-17 15:05:18 +01008436
kasar0c007d62017-05-19 03:13:57 -07008437 for child in vm_list_xmlroot.iter():
sousaedu80135b92021-02-17 15:05:18 +01008438 if "CatalogItem" in child.tag:
8439 cataloghref_list.append(child.attrib.get("href"))
8440
kasar0c007d62017-05-19 03:13:57 -07008441 if cataloghref_list is not None:
8442 for href in cataloghref_list:
8443 if href:
sousaedu80135b92021-02-17 15:05:18 +01008444 headers = {
8445 "Accept": "application/*+xml;version=" + API_VERSION,
8446 "x-vcloud-authorization": vca._session.headers[
8447 "x-vcloud-authorization"
8448 ],
8449 }
8450 response = self.perform_request(
8451 req_type="GET", url=href, headers=headers
8452 )
8453
kasar0c007d62017-05-19 03:13:57 -07008454 if response.status_code != 200:
sousaedu80135b92021-02-17 15:05:18 +01008455 self.logger.error(
8456 "REST call {} failed reason : {}"
8457 "status code : {}".format(
8458 href, response.text, response.status_code
8459 )
8460 )
8461
8462 raise vimconn.VimConnException(
8463 "get_media_details : Failed to get "
8464 "catalogitem details"
8465 )
8466
beierl26fec002019-12-06 17:06:40 -05008467 list_xmlroot = XmlElementTree.fromstring(response.text)
sousaedu80135b92021-02-17 15:05:18 +01008468
kasar0c007d62017-05-19 03:13:57 -07008469 for child in list_xmlroot.iter():
sousaedu80135b92021-02-17 15:05:18 +01008470 if "Entity" in child.tag:
8471 if "media" in child.attrib.get("href"):
8472 name = child.attrib.get("name")
8473 media_id = (
8474 child.attrib.get("href").split("/").pop()
8475 )
8476
beierlb22ce2d2019-12-12 12:09:51 -05008477 return name, media_id
kasar0c007d62017-05-19 03:13:57 -07008478 else:
8479 self.logger.debug("Media name and id not found")
sousaedu80135b92021-02-17 15:05:18 +01008480
beierlb22ce2d2019-12-12 12:09:51 -05008481 return False, False
kasar0c007d62017-05-19 03:13:57 -07008482 except Exception as exp:
sousaedu80135b92021-02-17 15:05:18 +01008483 self.logger.error(
8484 "get_media_details : exception occurred " "getting media details"
8485 )
8486
tierno72774862020-05-04 11:44:15 +00008487 raise vimconn.VimConnException(message=exp)
kasar0c007d62017-05-19 03:13:57 -07008488
kated47ad5f2017-08-03 02:16:13 -07008489 def retry_rest(self, method, url, add_headers=None, data=None):
sousaedu80135b92021-02-17 15:05:18 +01008490 """Method to get Token & retry respective REST request
8491 Args:
8492 api - REST API - Can be one of 'GET' or 'PUT' or 'POST'
8493 url - request url to be used
8494 add_headers - Additional headers (optional)
8495 data - Request payload data to be passed in request
8496 Returns:
8497 response - Response of request
bhangare1a0b97c2017-06-21 02:20:15 -07008498 """
8499 response = None
8500
beierlb22ce2d2019-12-12 12:09:51 -05008501 # Get token
bhangare1a0b97c2017-06-21 02:20:15 -07008502 self.get_token()
8503
kasarc5bf2932018-03-09 04:15:22 -08008504 if self.client._session:
sousaedu80135b92021-02-17 15:05:18 +01008505 headers = {
8506 "Accept": "application/*+xml;version=" + API_VERSION,
8507 "x-vcloud-authorization": self.client._session.headers[
8508 "x-vcloud-authorization"
8509 ],
8510 }
bhangare1a0b97c2017-06-21 02:20:15 -07008511
8512 if add_headers:
8513 headers.update(add_headers)
8514
sousaedu80135b92021-02-17 15:05:18 +01008515 if method == "GET":
8516 response = self.perform_request(req_type="GET", url=url, headers=headers)
8517 elif method == "PUT":
8518 response = self.perform_request(
8519 req_type="PUT", url=url, headers=headers, data=data
8520 )
8521 elif method == "POST":
8522 response = self.perform_request(
8523 req_type="POST", url=url, headers=headers, data=data
8524 )
8525 elif method == "DELETE":
8526 response = self.perform_request(req_type="DELETE", url=url, headers=headers)
8527
kated47ad5f2017-08-03 02:16:13 -07008528 return response
8529
bhangare1a0b97c2017-06-21 02:20:15 -07008530 def get_token(self):
sousaedu80135b92021-02-17 15:05:18 +01008531 """Generate a new token if expired
bhangare1a0b97c2017-06-21 02:20:15 -07008532
sousaedu80135b92021-02-17 15:05:18 +01008533 Returns:
8534 The return client object that letter can be used to connect to vCloud director as admin for VDC
bhangare1a0b97c2017-06-21 02:20:15 -07008535 """
beierl26fec002019-12-06 17:06:40 -05008536 self.client = self.connect()
bhangare1a0b97c2017-06-21 02:20:15 -07008537
8538 def get_vdc_details(self):
sousaedu80135b92021-02-17 15:05:18 +01008539 """Get VDC details using pyVcloud Lib
bhangare1a0b97c2017-06-21 02:20:15 -07008540
sousaedu80135b92021-02-17 15:05:18 +01008541 Returns org and vdc object
bhangare1a0b97c2017-06-21 02:20:15 -07008542 """
Ravi Chamartyb7ff3552018-10-30 19:51:23 +00008543 vdc = None
sousaedu80135b92021-02-17 15:05:18 +01008544
Ravi Chamartyb7ff3552018-10-30 19:51:23 +00008545 try:
8546 org = Org(self.client, resource=self.client.get_org())
8547 vdc = org.get_vdc(self.tenant_name)
8548 except Exception as e:
8549 # pyvcloud not giving a specific exception, Refresh nevertheless
8550 self.logger.debug("Received exception {}, refreshing token ".format(str(e)))
bhangare1a0b97c2017-06-21 02:20:15 -07008551
beierlb22ce2d2019-12-12 12:09:51 -05008552 # Retry once, if failed by refreshing token
bhangare1a0b97c2017-06-21 02:20:15 -07008553 if vdc is None:
8554 self.get_token()
Ravi Chamartyb7ff3552018-10-30 19:51:23 +00008555 org = Org(self.client, resource=self.client.get_org())
kasarc5bf2932018-03-09 04:15:22 -08008556 vdc = org.get_vdc(self.tenant_name)
bhangare1a0b97c2017-06-21 02:20:15 -07008557
kasarc5bf2932018-03-09 04:15:22 -08008558 return org, vdc
8559
kasarc5bf2932018-03-09 04:15:22 -08008560 def perform_request(self, req_type, url, headers=None, data=None):
8561 """Perform the POST/PUT/GET/DELETE request."""
beierlb22ce2d2019-12-12 12:09:51 -05008562 # Log REST request details
kasarc5bf2932018-03-09 04:15:22 -08008563 self.log_request(req_type, url=url, headers=headers, data=data)
8564 # perform request and return its result
sousaedu80135b92021-02-17 15:05:18 +01008565
8566 if req_type == "GET":
8567 response = requests.get(url=url, headers=headers, verify=False)
8568 elif req_type == "PUT":
8569 response = requests.put(url=url, headers=headers, data=data, verify=False)
8570 elif req_type == "POST":
8571 response = requests.post(url=url, headers=headers, data=data, verify=False)
8572 elif req_type == "DELETE":
8573 response = requests.delete(url=url, headers=headers, verify=False)
8574
beierlb22ce2d2019-12-12 12:09:51 -05008575 # Log the REST response
kasarc5bf2932018-03-09 04:15:22 -08008576 self.log_response(response)
8577
8578 return response
8579
kasarc5bf2932018-03-09 04:15:22 -08008580 def log_request(self, req_type, url=None, headers=None, data=None):
8581 """Logs REST request details"""
8582
8583 if req_type is not None:
8584 self.logger.debug("Request type: {}".format(req_type))
8585
8586 if url is not None:
8587 self.logger.debug("Request url: {}".format(url))
8588
8589 if headers is not None:
8590 for header in headers:
sousaedu80135b92021-02-17 15:05:18 +01008591 self.logger.debug(
8592 "Request header: {}: {}".format(header, headers[header])
8593 )
kasarc5bf2932018-03-09 04:15:22 -08008594
8595 if data is not None:
8596 self.logger.debug("Request data: {}".format(data))
8597
kasarc5bf2932018-03-09 04:15:22 -08008598 def log_response(self, response):
8599 """Logs REST response details"""
8600
8601 self.logger.debug("Response status code: {} ".format(response.status_code))
8602
kasarc5bf2932018-03-09 04:15:22 -08008603 def get_task_from_response(self, content):
8604 """
beierl26fec002019-12-06 17:06:40 -05008605 content - API response.text(response.text)
sbhangarea8e5b782018-06-21 02:10:03 -07008606 return task object
kasarc5bf2932018-03-09 04:15:22 -08008607 """
8608 xmlroot = XmlElementTree.fromstring(content)
sousaedu80135b92021-02-17 15:05:18 +01008609
8610 if xmlroot.tag.split("}")[1] == "Task":
kasarc5bf2932018-03-09 04:15:22 -08008611 return xmlroot
sbhangarea8e5b782018-06-21 02:10:03 -07008612 else:
kasarc5bf2932018-03-09 04:15:22 -08008613 for ele in xmlroot:
8614 if ele.tag.split("}")[1] == "Tasks":
8615 task = ele[0]
sbhangarea8e5b782018-06-21 02:10:03 -07008616 break
sousaedu80135b92021-02-17 15:05:18 +01008617
kasarc5bf2932018-03-09 04:15:22 -08008618 return task
8619
beierlb22ce2d2019-12-12 12:09:51 -05008620 def power_on_vapp(self, vapp_id, vapp_name):
kasarc5bf2932018-03-09 04:15:22 -08008621 """
8622 vapp_id - vApp uuid
8623 vapp_name - vAapp name
sbhangarea8e5b782018-06-21 02:10:03 -07008624 return - Task object
kasarc5bf2932018-03-09 04:15:22 -08008625 """
sousaedu80135b92021-02-17 15:05:18 +01008626 headers = {
8627 "Accept": "application/*+xml;version=" + API_VERSION,
8628 "x-vcloud-authorization": self.client._session.headers[
8629 "x-vcloud-authorization"
8630 ],
8631 }
sbhangarea8e5b782018-06-21 02:10:03 -07008632
sousaedu80135b92021-02-17 15:05:18 +01008633 poweron_href = "{}/api/vApp/vapp-{}/power/action/powerOn".format(
8634 self.url, vapp_id
8635 )
8636 response = self.perform_request(
8637 req_type="POST", url=poweron_href, headers=headers
8638 )
kasarc5bf2932018-03-09 04:15:22 -08008639
8640 if response.status_code != 202:
sousaedu80135b92021-02-17 15:05:18 +01008641 self.logger.error(
8642 "REST call {} failed reason : {}"
8643 "status code : {} ".format(
8644 poweron_href, response.text, response.status_code
8645 )
8646 )
8647
8648 raise vimconn.VimConnException(
8649 "power_on_vapp() : Failed to power on " "vApp {}".format(vapp_name)
8650 )
kasarc5bf2932018-03-09 04:15:22 -08008651 else:
beierl26fec002019-12-06 17:06:40 -05008652 poweron_task = self.get_task_from_response(response.text)
sousaedu80135b92021-02-17 15:05:18 +01008653
kasarc5bf2932018-03-09 04:15:22 -08008654 return poweron_task
elumalai8658c2c2022-04-28 19:09:31 +05308655
8656 def migrate_instance(self, vm_id, compute_host=None):
8657 """
8658 Migrate a vdu
8659 param:
8660 vm_id: ID of an instance
8661 compute_host: Host to migrate the vdu to
8662 """
8663 # TODO: Add support for migration
8664 raise vimconn.VimConnNotImplemented("Should have implemented this")
sritharan29a4c1a2022-05-05 12:15:04 +00008665
8666 def resize_instance(self, vm_id, flavor_id=None):
8667 """
8668 resize a vdu
8669 param:
8670 vm_id: ID of an instance
8671 flavor_id: flavor_id to resize the vdu to
8672 """
8673 # TODO: Add support for resize
8674 raise vimconn.VimConnNotImplemented("Should have implemented this")