blob: a3c25ca019000ee2183aaf43652d61fc1767f7c0 [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 -050028from lxml import etree as lxmlElementTree
tierno72774862020-05-04 11:44:15 +000029from osm_ro_plugin import vimconn
beierlb22ce2d2019-12-12 12:09:51 -050030from progressbar import Percentage, Bar, ETA, FileTransferSpeed, ProgressBar
31from pyVim.connect import SmartConnect, Disconnect
32from pyVmomi import vim, vmodl # @UnresolvedImport
33from pyvcloud.vcd.client import BasicLoginCredentials, Client
34from pyvcloud.vcd.org import Org
35from pyvcloud.vcd.vapp import VApp
36from pyvcloud.vcd.vdc import VDC
37from xml.etree import ElementTree as XmlElementTree
38from xml.sax.saxutils import escape
39import atexit
40import hashlib
41import json
42import logging
43import netaddr
bayramov325fa1c2016-09-08 01:42:46 -070044import os
beierlb22ce2d2019-12-12 12:09:51 -050045import random
46import re
47import requests
Ananda Baitharu319c26f2019-03-05 17:34:31 +000048import shutil
beierlb22ce2d2019-12-12 12:09:51 -050049import socket
50import ssl
51import struct
Ananda Baitharu319c26f2019-03-05 17:34:31 +000052import subprocess
53import tempfile
bayramov325fa1c2016-09-08 01:42:46 -070054import time
beierlb22ce2d2019-12-12 12:09:51 -050055import traceback
bayramov325fa1c2016-09-08 01:42:46 -070056import uuid
beierlb22ce2d2019-12-12 12:09:51 -050057import yaml
bayramov325fa1c2016-09-08 01:42:46 -070058
bayramovbd6160f2016-09-28 04:12:05 +040059# global variable for vcd connector type
sousaedu2ad85172021-02-17 15:05:18 +010060STANDALONE = "standalone"
bayramovbd6160f2016-09-28 04:12:05 +040061
kate15f1c382016-12-15 01:12:40 -080062# key for flavor dicts
sousaedu2ad85172021-02-17 15:05:18 +010063FLAVOR_RAM_KEY = "ram"
64FLAVOR_VCPUS_KEY = "vcpus"
65FLAVOR_DISK_KEY = "disk"
66DEFAULT_IP_PROFILE = {"dhcp_count": 50, "dhcp_enabled": True, "ip_version": "IPv4"}
bhangare0e571a92017-01-12 04:02:23 -080067# global variable for wait time
kate13ab2c42016-12-23 01:34:24 -080068INTERVAL_TIME = 5
69MAX_WAIT_TIME = 1800
bayramov325fa1c2016-09-08 01:42:46 -070070
sousaedu2ad85172021-02-17 15:05:18 +010071API_VERSION = "27.0"
bayramovbd6160f2016-09-28 04:12:05 +040072
bayramovef390722016-09-27 03:34:46 -070073# -1: "Could not be created",
74# 0: "Unresolved",
75# 1: "Resolved",
76# 2: "Deployed",
77# 3: "Suspended",
78# 4: "Powered on",
79# 5: "Waiting for user input",
80# 6: "Unknown state",
81# 7: "Unrecognized state",
82# 8: "Powered off",
83# 9: "Inconsistent state",
84# 10: "Children do not all have the same status",
85# 11: "Upload initiated, OVF descriptor pending",
86# 12: "Upload initiated, copying contents",
87# 13: "Upload initiated , disk contents pending",
88# 14: "Upload has been quarantined",
89# 15: "Upload quarantine period has expired"
90
91# mapping vCD status to MANO
sousaedu2ad85172021-02-17 15:05:18 +010092vcdStatusCode2manoFormat = {
93 4: "ACTIVE",
94 7: "PAUSED",
95 3: "SUSPENDED",
96 8: "INACTIVE",
97 12: "BUILD",
98 -1: "ERROR",
99 14: "DELETED",
100}
bayramovef390722016-09-27 03:34:46 -0700101
102#
sousaedu2ad85172021-02-17 15:05:18 +0100103netStatus2manoFormat = {
104 "ACTIVE": "ACTIVE",
105 "PAUSED": "PAUSED",
106 "INACTIVE": "INACTIVE",
107 "BUILD": "BUILD",
108 "ERROR": "ERROR",
109 "DELETED": "DELETED",
110}
bayramovef390722016-09-27 03:34:46 -0700111
beierl26fec002019-12-06 17:06:40 -0500112
tierno72774862020-05-04 11:44:15 +0000113class vimconnector(vimconn.VimConnector):
kateeb044522017-03-06 23:54:39 -0800114 # dict used to store flavor in memory
115 flavorlist = {}
116
sousaedu2ad85172021-02-17 15:05:18 +0100117 def __init__(
118 self,
119 uuid=None,
120 name=None,
121 tenant_id=None,
122 tenant_name=None,
123 url=None,
124 url_admin=None,
125 user=None,
126 passwd=None,
127 log_level=None,
128 config={},
129 persistent_info={},
130 ):
bayramovb6ffe792016-09-28 11:50:56 +0400131 """
132 Constructor create vmware connector to vCloud director.
133
134 By default construct doesn't validate connection state. So client can create object with None arguments.
135 If client specified username , password and host and VDC name. Connector initialize other missing attributes.
136
137 a) It initialize organization UUID
138 b) Initialize tenant_id/vdc ID. (This information derived from tenant name)
139
140 Args:
141 uuid - is organization uuid.
142 name - is organization name that must be presented in vCloud director.
143 tenant_id - is VDC uuid it must be presented in vCloud director
144 tenant_name - is VDC name.
145 url - is hostname or ip address of vCloud director
146 url_admin - same as above.
147 user - is user that administrator for organization. Caller must make sure that
148 username has right privileges.
149
150 password - is password for a user.
151
152 VMware connector also requires PVDC administrative privileges and separate account.
153 This variables must be passed via config argument dict contains keys
154
155 dict['admin_username']
156 dict['admin_password']
kateeb044522017-03-06 23:54:39 -0800157 config - Provide NSX and vCenter information
bayramovb6ffe792016-09-28 11:50:56 +0400158
159 Returns:
160 Nothing.
161 """
162
sousaedu2ad85172021-02-17 15:05:18 +0100163 vimconn.VimConnector.__init__(
164 self,
165 uuid,
166 name,
167 tenant_id,
168 tenant_name,
169 url,
170 url_admin,
171 user,
172 passwd,
173 log_level,
174 config,
175 )
kate15f1c382016-12-15 01:12:40 -0800176
sousaedu2ad85172021-02-17 15:05:18 +0100177 self.logger = logging.getLogger("ro.vim.vmware")
kate15f1c382016-12-15 01:12:40 -0800178 self.logger.setLevel(10)
tiernob3d36742017-03-03 23:51:05 +0100179 self.persistent_info = persistent_info
kate15f1c382016-12-15 01:12:40 -0800180
bayramovef390722016-09-27 03:34:46 -0700181 self.name = name
kate15f1c382016-12-15 01:12:40 -0800182 self.id = uuid
bayramovef390722016-09-27 03:34:46 -0700183 self.url = url
bayramov325fa1c2016-09-08 01:42:46 -0700184 self.url_admin = url_admin
185 self.tenant_id = tenant_id
186 self.tenant_name = tenant_name
bayramovef390722016-09-27 03:34:46 -0700187 self.user = user
188 self.passwd = passwd
189 self.config = config
190 self.admin_password = None
191 self.admin_user = None
kate15f1c382016-12-15 01:12:40 -0800192 self.org_name = ""
bhangare985a1fd2017-01-31 01:53:21 -0800193 self.nsx_manager = None
194 self.nsx_user = None
195 self.nsx_password = None
sbhangarea8e5b782018-06-21 02:10:03 -0700196 self.availability_zone = None
bayramovef390722016-09-27 03:34:46 -0700197
kasarc5bf2932018-03-09 04:15:22 -0800198 # Disable warnings from self-signed certificates.
199 requests.packages.urllib3.disable_warnings()
200
kate15f1c382016-12-15 01:12:40 -0800201 if tenant_name is not None:
202 orgnameandtenant = tenant_name.split(":")
sousaedu2ad85172021-02-17 15:05:18 +0100203
kate15f1c382016-12-15 01:12:40 -0800204 if len(orgnameandtenant) == 2:
katec324e002016-12-23 00:54:47 -0800205 self.tenant_name = orgnameandtenant[1]
206 self.org_name = orgnameandtenant[0]
kate15f1c382016-12-15 01:12:40 -0800207 else:
208 self.tenant_name = tenant_name
sousaedu2ad85172021-02-17 15:05:18 +0100209
bhangarea92ae392017-01-12 22:30:29 -0800210 if "orgname" in config:
sousaedu2ad85172021-02-17 15:05:18 +0100211 self.org_name = config["orgname"]
katec324e002016-12-23 00:54:47 -0800212
tiernofe789902016-09-29 14:20:44 +0000213 if log_level:
bayramov5761ad12016-10-04 09:00:30 +0400214 self.logger.setLevel(getattr(logging, log_level))
bayramov325fa1c2016-09-08 01:42:46 -0700215
bayramovef390722016-09-27 03:34:46 -0700216 try:
sousaedu2ad85172021-02-17 15:05:18 +0100217 self.admin_user = config["admin_username"]
218 self.admin_password = config["admin_password"]
bayramovef390722016-09-27 03:34:46 -0700219 except KeyError:
sousaedu2ad85172021-02-17 15:05:18 +0100220 raise vimconn.VimConnException(
221 message="Error admin username or admin password is empty."
222 )
bayramov325fa1c2016-09-08 01:42:46 -0700223
bhangare985a1fd2017-01-31 01:53:21 -0800224 try:
sousaedu2ad85172021-02-17 15:05:18 +0100225 self.nsx_manager = config["nsx_manager"]
226 self.nsx_user = config["nsx_user"]
227 self.nsx_password = config["nsx_password"]
bhangare985a1fd2017-01-31 01:53:21 -0800228 except KeyError:
sousaedu2ad85172021-02-17 15:05:18 +0100229 raise vimconn.VimConnException(
230 message="Error: nsx manager or nsx user or nsx password is empty in Config"
231 )
bhangare985a1fd2017-01-31 01:53:21 -0800232
kateeb044522017-03-06 23:54:39 -0800233 self.vcenter_ip = config.get("vcenter_ip", None)
234 self.vcenter_port = config.get("vcenter_port", None)
235 self.vcenter_user = config.get("vcenter_user", None)
236 self.vcenter_password = config.get("vcenter_password", None)
237
beierlb22ce2d2019-12-12 12:09:51 -0500238 # Set availability zone for Affinity rules
sbhangarea8e5b782018-06-21 02:10:03 -0700239 self.availability_zone = self.set_availability_zones()
240
sousaedu2ad85172021-02-17 15:05:18 +0100241 # ############# Stub code for SRIOV #################
242 # try:
243 # self.dvs_name = config['dv_switch_name']
244 # except KeyError:
245 # raise vimconn.VimConnException(message="Error:
246 # distributed virtaul switch name is empty in Config")
247 #
248 # self.vlanID_range = config.get("vlanID_range", None)
kateac1e3792017-04-01 02:16:39 -0700249
bayramovef390722016-09-27 03:34:46 -0700250 self.org_uuid = None
kasarc5bf2932018-03-09 04:15:22 -0800251 self.client = None
bayramov325fa1c2016-09-08 01:42:46 -0700252
253 if not url:
sousaedu2ad85172021-02-17 15:05:18 +0100254 raise vimconn.VimConnException("url param can not be NoneType")
bayramov325fa1c2016-09-08 01:42:46 -0700255
bayramovef390722016-09-27 03:34:46 -0700256 if not self.url_admin: # try to use normal url
bayramov325fa1c2016-09-08 01:42:46 -0700257 self.url_admin = self.url
258
sousaedu2ad85172021-02-17 15:05:18 +0100259 logging.debug(
260 "UUID: {} name: {} tenant_id: {} tenant name {}".format(
261 self.id, self.org_name, self.tenant_id, self.tenant_name
262 )
263 )
264 logging.debug(
265 "vcd url {} vcd username: {} vcd password: {}".format(
266 self.url, self.user, self.passwd
267 )
268 )
269 logging.debug(
270 "vcd admin username {} vcd admin passowrd {}".format(
271 self.admin_user, self.admin_password
272 )
273 )
bayramov325fa1c2016-09-08 01:42:46 -0700274
bayramovef390722016-09-27 03:34:46 -0700275 # initialize organization
bayramovbd6160f2016-09-28 04:12:05 +0400276 if self.user is not None and self.passwd is not None and self.url:
277 self.init_organization()
bayramovef390722016-09-27 03:34:46 -0700278
279 def __getitem__(self, index):
sousaedu2ad85172021-02-17 15:05:18 +0100280 if index == "name":
kate15f1c382016-12-15 01:12:40 -0800281 return self.name
sousaedu2ad85172021-02-17 15:05:18 +0100282
283 if index == "tenant_id":
bayramov325fa1c2016-09-08 01:42:46 -0700284 return self.tenant_id
sousaedu2ad85172021-02-17 15:05:18 +0100285
286 if index == "tenant_name":
bayramov325fa1c2016-09-08 01:42:46 -0700287 return self.tenant_name
sousaedu2ad85172021-02-17 15:05:18 +0100288 elif index == "id":
bayramov325fa1c2016-09-08 01:42:46 -0700289 return self.id
sousaedu2ad85172021-02-17 15:05:18 +0100290 elif index == "org_name":
bayramovef390722016-09-27 03:34:46 -0700291 return self.org_name
sousaedu2ad85172021-02-17 15:05:18 +0100292 elif index == "org_uuid":
bayramovef390722016-09-27 03:34:46 -0700293 return self.org_uuid
sousaedu2ad85172021-02-17 15:05:18 +0100294 elif index == "user":
bayramov325fa1c2016-09-08 01:42:46 -0700295 return self.user
sousaedu2ad85172021-02-17 15:05:18 +0100296 elif index == "passwd":
bayramov325fa1c2016-09-08 01:42:46 -0700297 return self.passwd
sousaedu2ad85172021-02-17 15:05:18 +0100298 elif index == "url":
bayramov325fa1c2016-09-08 01:42:46 -0700299 return self.url
sousaedu2ad85172021-02-17 15:05:18 +0100300 elif index == "url_admin":
bayramov325fa1c2016-09-08 01:42:46 -0700301 return self.url_admin
bayramovef390722016-09-27 03:34:46 -0700302 elif index == "config":
bayramov325fa1c2016-09-08 01:42:46 -0700303 return self.config
304 else:
tierno7d782ef2019-10-04 12:56:31 +0000305 raise KeyError("Invalid key '{}'".format(index))
bayramov325fa1c2016-09-08 01:42:46 -0700306
bayramovef390722016-09-27 03:34:46 -0700307 def __setitem__(self, index, value):
sousaedu2ad85172021-02-17 15:05:18 +0100308 if index == "name":
kate15f1c382016-12-15 01:12:40 -0800309 self.name = value
sousaedu2ad85172021-02-17 15:05:18 +0100310
311 if index == "tenant_id":
bayramov325fa1c2016-09-08 01:42:46 -0700312 self.tenant_id = value
sousaedu2ad85172021-02-17 15:05:18 +0100313
314 if index == "tenant_name":
bayramov325fa1c2016-09-08 01:42:46 -0700315 self.tenant_name = value
sousaedu2ad85172021-02-17 15:05:18 +0100316 elif index == "id":
bayramov325fa1c2016-09-08 01:42:46 -0700317 self.id = value
sousaedu2ad85172021-02-17 15:05:18 +0100318 elif index == "org_name":
bayramovef390722016-09-27 03:34:46 -0700319 self.org_name = value
sousaedu2ad85172021-02-17 15:05:18 +0100320 elif index == "org_uuid":
kate15f1c382016-12-15 01:12:40 -0800321 self.org_uuid = value
sousaedu2ad85172021-02-17 15:05:18 +0100322 elif index == "user":
bayramov325fa1c2016-09-08 01:42:46 -0700323 self.user = value
sousaedu2ad85172021-02-17 15:05:18 +0100324 elif index == "passwd":
bayramov325fa1c2016-09-08 01:42:46 -0700325 self.passwd = value
sousaedu2ad85172021-02-17 15:05:18 +0100326 elif index == "url":
bayramov325fa1c2016-09-08 01:42:46 -0700327 self.url = value
sousaedu2ad85172021-02-17 15:05:18 +0100328 elif index == "url_admin":
bayramov325fa1c2016-09-08 01:42:46 -0700329 self.url_admin = value
330 else:
tierno7d782ef2019-10-04 12:56:31 +0000331 raise KeyError("Invalid key '{}'".format(index))
bayramov325fa1c2016-09-08 01:42:46 -0700332
bayramovef390722016-09-27 03:34:46 -0700333 def connect_as_admin(self):
sousaedu2ad85172021-02-17 15:05:18 +0100334 """Method connect as pvdc admin user to vCloud director.
335 There are certain action that can be done only by provider vdc admin user.
336 Organization creation / provider network creation etc.
bayramovef390722016-09-27 03:34:46 -0700337
sousaedu2ad85172021-02-17 15:05:18 +0100338 Returns:
339 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 -0700340 """
kasarc5bf2932018-03-09 04:15:22 -0800341 self.logger.debug("Logging into vCD {} as admin.".format(self.org_name))
bayramov325fa1c2016-09-08 01:42:46 -0700342
kasarc5bf2932018-03-09 04:15:22 -0800343 try:
344 host = self.url
sousaedu2ad85172021-02-17 15:05:18 +0100345 org = "System"
346 client_as_admin = Client(
347 host, verify_ssl_certs=False, api_version=API_VERSION
348 )
349 client_as_admin.set_credentials(
350 BasicLoginCredentials(self.admin_user, org, self.admin_password)
351 )
kasarc5bf2932018-03-09 04:15:22 -0800352 except Exception as e:
tierno72774862020-05-04 11:44:15 +0000353 raise vimconn.VimConnException(
sousaedu2ad85172021-02-17 15:05:18 +0100354 "Can't connect to vCloud director as: {} with exception {}".format(
355 self.admin_user, e
356 )
357 )
bayramov325fa1c2016-09-08 01:42:46 -0700358
kasarc5bf2932018-03-09 04:15:22 -0800359 return client_as_admin
bayramov325fa1c2016-09-08 01:42:46 -0700360
bayramovef390722016-09-27 03:34:46 -0700361 def connect(self):
sousaedu2ad85172021-02-17 15:05:18 +0100362 """Method connect as normal user to vCloud director.
bayramovef390722016-09-27 03:34:46 -0700363
sousaedu2ad85172021-02-17 15:05:18 +0100364 Returns:
365 The return client object that latter can be used to connect to vCloud director as admin for VDC
bayramovef390722016-09-27 03:34:46 -0700366 """
bayramovb6ffe792016-09-28 11:50:56 +0400367 try:
sousaedu2ad85172021-02-17 15:05:18 +0100368 self.logger.debug(
369 "Logging into vCD {} as {} to datacenter {}.".format(
370 self.org_name, self.user, self.org_name
371 )
372 )
kasarc5bf2932018-03-09 04:15:22 -0800373 host = self.url
beierl26fec002019-12-06 17:06:40 -0500374 client = Client(host, verify_ssl_certs=False, api_version=API_VERSION)
sousaedu2ad85172021-02-17 15:05:18 +0100375 client.set_credentials(
376 BasicLoginCredentials(self.user, self.org_name, self.passwd)
377 )
beierl26fec002019-12-06 17:06:40 -0500378 except Exception as e:
sousaedu2ad85172021-02-17 15:05:18 +0100379 raise vimconn.VimConnConnectionException(
380 "Can't connect to vCloud director org: "
381 "{} as user {} with exception: {}".format(self.org_name, self.user, e)
382 )
bayramov325fa1c2016-09-08 01:42:46 -0700383
kasarc5bf2932018-03-09 04:15:22 -0800384 return client
bayramov325fa1c2016-09-08 01:42:46 -0700385
bayramovbd6160f2016-09-28 04:12:05 +0400386 def init_organization(self):
sousaedu2ad85172021-02-17 15:05:18 +0100387 """Method initialize organization UUID and VDC parameters.
bayramovbd6160f2016-09-28 04:12:05 +0400388
sousaedu2ad85172021-02-17 15:05:18 +0100389 At bare minimum client must provide organization name that present in vCloud director and VDC.
bayramovbd6160f2016-09-28 04:12:05 +0400390
sousaedu2ad85172021-02-17 15:05:18 +0100391 The VDC - UUID ( tenant_id) will be initialized at the run time if client didn't call constructor.
392 The Org - UUID will be initialized at the run time if data center present in vCloud director.
bayramov325fa1c2016-09-08 01:42:46 -0700393
sousaedu2ad85172021-02-17 15:05:18 +0100394 Returns:
395 The return vca object that letter can be used to connect to vcloud direct as admin
bayramovef390722016-09-27 03:34:46 -0700396 """
kasarc5bf2932018-03-09 04:15:22 -0800397 client = self.connect()
sousaedu2ad85172021-02-17 15:05:18 +0100398
kasarc5bf2932018-03-09 04:15:22 -0800399 if not client:
tierno72774862020-05-04 11:44:15 +0000400 raise vimconn.VimConnConnectionException("Failed to connect vCD.")
bhangare1a0b97c2017-06-21 02:20:15 -0700401
kasarc5bf2932018-03-09 04:15:22 -0800402 self.client = client
bayramovef390722016-09-27 03:34:46 -0700403 try:
404 if self.org_uuid is None:
kasarc5bf2932018-03-09 04:15:22 -0800405 org_list = client.get_org_list()
406 for org in org_list.Org:
bayramovbd6160f2016-09-28 04:12:05 +0400407 # we set org UUID at the init phase but we can do it only when we have valid credential.
sousaedu2ad85172021-02-17 15:05:18 +0100408 if org.get("name") == self.org_name:
409 self.org_uuid = org.get("href").split("/")[-1]
410 self.logger.debug(
411 "Setting organization UUID {}".format(self.org_uuid)
412 )
bayramovbd6160f2016-09-28 04:12:05 +0400413 break
bayramovbd6160f2016-09-28 04:12:05 +0400414 else:
sousaedu2ad85172021-02-17 15:05:18 +0100415 raise vimconn.VimConnException(
416 "Vcloud director organization {} not found".format(
417 self.org_name
418 )
419 )
bayramovbd6160f2016-09-28 04:12:05 +0400420
421 # if well good we require for org details
422 org_details_dict = self.get_org(org_uuid=self.org_uuid)
423
424 # we have two case if we want to initialize VDC ID or VDC name at run time
425 # tenant_name provided but no tenant id
sousaedu2ad85172021-02-17 15:05:18 +0100426 if (
427 self.tenant_id is None
428 and self.tenant_name is not None
429 and "vdcs" in org_details_dict
430 ):
431 vdcs_dict = org_details_dict["vdcs"]
bayramovbd6160f2016-09-28 04:12:05 +0400432 for vdc in vdcs_dict:
433 if vdcs_dict[vdc] == self.tenant_name:
434 self.tenant_id = vdc
sousaedu2ad85172021-02-17 15:05:18 +0100435 self.logger.debug(
436 "Setting vdc uuid {} for organization UUID {}".format(
437 self.tenant_id, self.org_name
438 )
439 )
bayramovbd6160f2016-09-28 04:12:05 +0400440 break
441 else:
sousaedu2ad85172021-02-17 15:05:18 +0100442 raise vimconn.VimConnException(
443 "Tenant name indicated but not present in vcloud director."
444 )
445
bayramovbd6160f2016-09-28 04:12:05 +0400446 # case two we have tenant_id but we don't have tenant name so we find and set it.
sousaedu2ad85172021-02-17 15:05:18 +0100447 if (
448 self.tenant_id is not None
449 and self.tenant_name is None
450 and "vdcs" in org_details_dict
451 ):
452 vdcs_dict = org_details_dict["vdcs"]
bayramovbd6160f2016-09-28 04:12:05 +0400453 for vdc in vdcs_dict:
454 if vdc == self.tenant_id:
455 self.tenant_name = vdcs_dict[vdc]
sousaedu2ad85172021-02-17 15:05:18 +0100456 self.logger.debug(
457 "Setting vdc uuid {} for organization UUID {}".format(
458 self.tenant_id, self.org_name
459 )
460 )
bayramovbd6160f2016-09-28 04:12:05 +0400461 break
462 else:
sousaedu2ad85172021-02-17 15:05:18 +0100463 raise vimconn.VimConnException(
464 "Tenant id indicated but not present in vcloud director"
465 )
466
bayramovef390722016-09-27 03:34:46 -0700467 self.logger.debug("Setting organization uuid {}".format(self.org_uuid))
beierl26fec002019-12-06 17:06:40 -0500468 except Exception as e:
sousaedu2ad85172021-02-17 15:05:18 +0100469 self.logger.debug(
470 "Failed initialize organization UUID for org {}: {}".format(
471 self.org_name, e
472 ),
473 )
bayramovef390722016-09-27 03:34:46 -0700474 self.logger.debug(traceback.format_exc())
475 self.org_uuid = None
bayramov325fa1c2016-09-08 01:42:46 -0700476
bayramovef390722016-09-27 03:34:46 -0700477 def new_tenant(self, tenant_name=None, tenant_description=None):
sousaedu2ad85172021-02-17 15:05:18 +0100478 """Method adds a new tenant to VIM with this name.
479 This action requires access to create VDC action in vCloud director.
bayramovef390722016-09-27 03:34:46 -0700480
sousaedu2ad85172021-02-17 15:05:18 +0100481 Args:
482 tenant_name is tenant_name to be created.
483 tenant_description not used for this call
bayramovb6ffe792016-09-28 11:50:56 +0400484
sousaedu2ad85172021-02-17 15:05:18 +0100485 Return:
486 returns the tenant identifier in UUID format.
487 If action is failed method will throw vimconn.VimConnException method
488 """
bayramovef390722016-09-27 03:34:46 -0700489 vdc_task = self.create_vdc(vdc_name=tenant_name)
490 if vdc_task is not None:
beierlb22ce2d2019-12-12 12:09:51 -0500491 vdc_uuid, _ = vdc_task.popitem()
sousaedu2ad85172021-02-17 15:05:18 +0100492 self.logger.info(
493 "Created new vdc {} and uuid: {}".format(tenant_name, vdc_uuid)
494 )
495
bayramovef390722016-09-27 03:34:46 -0700496 return vdc_uuid
497 else:
sousaedu2ad85172021-02-17 15:05:18 +0100498 raise vimconn.VimConnException(
499 "Failed create tenant {}".format(tenant_name)
500 )
bayramovef390722016-09-27 03:34:46 -0700501
bayramov163f1ae2016-09-28 17:16:55 +0400502 def delete_tenant(self, tenant_id=None):
sousaedu2ad85172021-02-17 15:05:18 +0100503 """Delete a tenant from VIM
504 Args:
505 tenant_id is tenant_id to be deleted.
kated47ad5f2017-08-03 02:16:13 -0700506
sousaedu2ad85172021-02-17 15:05:18 +0100507 Return:
508 returns the tenant identifier in UUID format.
509 If action is failed method will throw exception
kated47ad5f2017-08-03 02:16:13 -0700510 """
511 vca = self.connect_as_admin()
512 if not vca:
tierno72774862020-05-04 11:44:15 +0000513 raise vimconn.VimConnConnectionException("Failed to connect vCD")
kated47ad5f2017-08-03 02:16:13 -0700514
515 if tenant_id is not None:
kasarc5bf2932018-03-09 04:15:22 -0800516 if vca._session:
beierlb22ce2d2019-12-12 12:09:51 -0500517 # Get OrgVDC
sousaedu2ad85172021-02-17 15:05:18 +0100518 url_list = [self.url, "/api/vdc/", tenant_id]
519 orgvdc_herf = "".join(url_list)
kasarc5bf2932018-03-09 04:15:22 -0800520
sousaedu2ad85172021-02-17 15:05:18 +0100521 headers = {
522 "Accept": "application/*+xml;version=" + API_VERSION,
523 "x-vcloud-authorization": vca._session.headers[
524 "x-vcloud-authorization"
525 ],
526 }
527 response = self.perform_request(
528 req_type="GET", url=orgvdc_herf, headers=headers
529 )
kated47ad5f2017-08-03 02:16:13 -0700530
531 if response.status_code != requests.codes.ok:
sousaedu2ad85172021-02-17 15:05:18 +0100532 self.logger.debug(
533 "delete_tenant():GET REST API call {} failed. "
534 "Return status code {}".format(
535 orgvdc_herf, response.status_code
536 )
537 )
538
539 raise vimconn.VimConnNotFoundException(
540 "Fail to get tenant {}".format(tenant_id)
541 )
kated47ad5f2017-08-03 02:16:13 -0700542
beierl01bd6692019-12-09 17:06:20 -0500543 lxmlroot_respond = lxmlElementTree.fromstring(response.content)
sousaedu2ad85172021-02-17 15:05:18 +0100544 namespaces = {
545 prefix: uri
546 for prefix, uri in lxmlroot_respond.nsmap.items()
547 if prefix
548 }
beierlb22ce2d2019-12-12 12:09:51 -0500549 namespaces["xmlns"] = "http://www.vmware.com/vcloud/v1.5"
sousaedu2ad85172021-02-17 15:05:18 +0100550 vdc_remove_href = lxmlroot_respond.find(
551 "xmlns:Link[@rel='remove']", namespaces
552 ).attrib["href"]
553 vdc_remove_href = vdc_remove_href + "?recursive=true&force=true"
kated47ad5f2017-08-03 02:16:13 -0700554
sousaedu2ad85172021-02-17 15:05:18 +0100555 response = self.perform_request(
556 req_type="DELETE", url=vdc_remove_href, headers=headers
557 )
kated47ad5f2017-08-03 02:16:13 -0700558
559 if response.status_code == 202:
kasarc5bf2932018-03-09 04:15:22 -0800560 time.sleep(5)
sousaedu2ad85172021-02-17 15:05:18 +0100561
kasarc5bf2932018-03-09 04:15:22 -0800562 return tenant_id
kated47ad5f2017-08-03 02:16:13 -0700563 else:
sousaedu2ad85172021-02-17 15:05:18 +0100564 self.logger.debug(
565 "delete_tenant(): DELETE REST API call {} failed. "
566 "Return status code {}".format(
567 vdc_remove_href, response.status_code
568 )
569 )
570
571 raise vimconn.VimConnException(
572 "Fail to delete tenant with ID {}".format(tenant_id)
573 )
kated47ad5f2017-08-03 02:16:13 -0700574 else:
sousaedu2ad85172021-02-17 15:05:18 +0100575 self.logger.debug(
576 "delete_tenant():Incorrect tenant ID {}".format(tenant_id)
577 )
578
579 raise vimconn.VimConnNotFoundException(
580 "Fail to get tenant {}".format(tenant_id)
581 )
kated47ad5f2017-08-03 02:16:13 -0700582
bayramov325fa1c2016-09-08 01:42:46 -0700583 def get_tenant_list(self, filter_dict={}):
bayramovb6ffe792016-09-28 11:50:56 +0400584 """Obtain tenants of VIM
bayramov325fa1c2016-09-08 01:42:46 -0700585 filter_dict can contain the following keys:
586 name: filter by tenant name
587 id: filter by tenant uuid/id
588 <other VIM specific>
bayramovb6ffe792016-09-28 11:50:56 +0400589 Returns the tenant list of dictionaries:
bayramov325fa1c2016-09-08 01:42:46 -0700590 [{'name':'<name>, 'id':'<id>, ...}, ...]
bayramov325fa1c2016-09-08 01:42:46 -0700591
bayramovb6ffe792016-09-28 11:50:56 +0400592 """
bayramovef390722016-09-27 03:34:46 -0700593 org_dict = self.get_org(self.org_uuid)
sousaedu2ad85172021-02-17 15:05:18 +0100594 vdcs_dict = org_dict["vdcs"]
bayramovef390722016-09-27 03:34:46 -0700595
596 vdclist = []
597 try:
598 for k in vdcs_dict:
sousaedu2ad85172021-02-17 15:05:18 +0100599 entry = {"name": vdcs_dict[k], "id": k}
bayramovb6ffe792016-09-28 11:50:56 +0400600 # if caller didn't specify dictionary we return all tenants.
sousaedu2ad85172021-02-17 15:05:18 +0100601
bayramovb6ffe792016-09-28 11:50:56 +0400602 if filter_dict is not None and filter_dict:
603 filtered_entry = entry.copy()
604 filtered_dict = set(entry.keys()) - set(filter_dict)
sousaedu2ad85172021-02-17 15:05:18 +0100605
beierlb22ce2d2019-12-12 12:09:51 -0500606 for unwanted_key in filtered_dict:
607 del entry[unwanted_key]
sousaedu2ad85172021-02-17 15:05:18 +0100608
bayramovb6ffe792016-09-28 11:50:56 +0400609 if filter_dict == entry:
610 vdclist.append(filtered_entry)
611 else:
612 vdclist.append(entry)
beierlb22ce2d2019-12-12 12:09:51 -0500613 except Exception:
bayramovef390722016-09-27 03:34:46 -0700614 self.logger.debug("Error in get_tenant_list()")
615 self.logger.debug(traceback.format_exc())
sousaedu2ad85172021-02-17 15:05:18 +0100616
tierno72774862020-05-04 11:44:15 +0000617 raise vimconn.VimConnException("Incorrect state. {}")
bayramovef390722016-09-27 03:34:46 -0700618
619 return vdclist
620
sousaedu2ad85172021-02-17 15:05:18 +0100621 def new_network(
622 self,
623 net_name,
624 net_type,
625 ip_profile=None,
626 shared=False,
627 provider_network_profile=None,
628 ):
bayramovb6ffe792016-09-28 11:50:56 +0400629 """Adds a tenant network to VIM
garciadeblasebd66722019-01-31 16:01:31 +0000630 Params:
631 'net_name': name of the network
632 'net_type': one of:
633 'bridge': overlay isolated network
634 'data': underlay E-LAN network for Passthrough and SRIOV interfaces
635 'ptp': underlay E-LINE network for Passthrough and SRIOV interfaces.
636 'ip_profile': is a dict containing the IP parameters of the network
637 'ip_version': can be "IPv4" or "IPv6" (Currently only IPv4 is implemented)
638 'subnet_address': ip_prefix_schema, that is X.X.X.X/Y
639 'gateway_address': (Optional) ip_schema, that is X.X.X.X
640 'dns_address': (Optional) comma separated list of ip_schema, e.g. X.X.X.X[,X,X,X,X]
641 'dhcp_enabled': True or False
642 'dhcp_start_address': ip_schema, first IP to grant
643 'dhcp_count': number of IPs to grant.
644 'shared': if this network can be seen/use by other tenants/organization
kbsuba85c54d2019-10-17 16:30:32 +0000645 'provider_network_profile': (optional) contains {segmentation-id: vlan, provider-network: vim_netowrk}
garciadeblasebd66722019-01-31 16:01:31 +0000646 Returns a tuple with the network identifier and created_items, or raises an exception on error
647 created_items can be None or a dictionary where this method can include key-values that will be passed to
648 the method delete_network. Can be used to store created segments, created l2gw connections, etc.
649 Format is vimconnector dependent, but do not use nested dictionaries and a value of None should be the same
650 as not present.
651 """
bayramov325fa1c2016-09-08 01:42:46 -0700652
sousaedu2ad85172021-02-17 15:05:18 +0100653 self.logger.debug(
654 "new_network tenant {} net_type {} ip_profile {} shared {} provider_network_profile {}".format(
655 net_name, net_type, ip_profile, shared, provider_network_profile
656 )
657 )
658 # vlan = None
659 # if provider_network_profile:
660 # vlan = provider_network_profile.get("segmentation-id")
bayramov325fa1c2016-09-08 01:42:46 -0700661
garciadeblasebd66722019-01-31 16:01:31 +0000662 created_items = {}
sousaedu2ad85172021-02-17 15:05:18 +0100663 isshared = "false"
bayramovef390722016-09-27 03:34:46 -0700664
sousaedu2ad85172021-02-17 15:05:18 +0100665 if shared:
666 isshared = "true"
667
668 # ############# Stub code for SRIOV #################
669 # if net_type == "data" or net_type == "ptp":
670 # if self.config.get('dv_switch_name') == None:
671 # raise vimconn.VimConnConflictException("You must provide 'dv_switch_name' at config value")
672 # network_uuid = self.create_dvPort_group(net_name)
kbsuba85c54d2019-10-17 16:30:32 +0000673 parent_network_uuid = None
674
kbsuba85c54d2019-10-17 16:30:32 +0000675 if provider_network_profile is not None:
676 for k, v in provider_network_profile.items():
sousaedu2ad85172021-02-17 15:05:18 +0100677 if k == "physical_network":
kbsuba85c54d2019-10-17 16:30:32 +0000678 parent_network_uuid = self.get_physical_network_by_name(v)
kateac1e3792017-04-01 02:16:39 -0700679
sousaedu2ad85172021-02-17 15:05:18 +0100680 network_uuid = self.create_network(
681 network_name=net_name,
682 net_type=net_type,
683 ip_profile=ip_profile,
684 isshared=isshared,
685 parent_network_uuid=parent_network_uuid,
686 )
687
bayramovef390722016-09-27 03:34:46 -0700688 if network_uuid is not None:
garciadeblasebd66722019-01-31 16:01:31 +0000689 return network_uuid, created_items
bayramovef390722016-09-27 03:34:46 -0700690 else:
sousaedu2ad85172021-02-17 15:05:18 +0100691 raise vimconn.VimConnUnexpectedResponse(
692 "Failed create a new network {}".format(net_name)
693 )
bayramovef390722016-09-27 03:34:46 -0700694
695 def get_vcd_network_list(self):
sousaedu2ad85172021-02-17 15:05:18 +0100696 """Method available organization for a logged in tenant
bayramovef390722016-09-27 03:34:46 -0700697
sousaedu2ad85172021-02-17 15:05:18 +0100698 Returns:
699 The return vca object that letter can be used to connect to vcloud direct as admin
bayramovef390722016-09-27 03:34:46 -0700700 """
701
sousaedu2ad85172021-02-17 15:05:18 +0100702 self.logger.debug(
703 "get_vcd_network_list(): retrieving network list for vcd {}".format(
704 self.tenant_name
705 )
706 )
bayramovef390722016-09-27 03:34:46 -0700707
kate15f1c382016-12-15 01:12:40 -0800708 if not self.tenant_name:
tierno72774862020-05-04 11:44:15 +0000709 raise vimconn.VimConnConnectionException("Tenant name is empty.")
kate15f1c382016-12-15 01:12:40 -0800710
beierlb22ce2d2019-12-12 12:09:51 -0500711 _, vdc = self.get_vdc_details()
kate15f1c382016-12-15 01:12:40 -0800712 if vdc is None:
sousaedu2ad85172021-02-17 15:05:18 +0100713 raise vimconn.VimConnConnectionException(
714 "Can't retrieve information for a VDC {}".format(self.tenant_name)
715 )
kate15f1c382016-12-15 01:12:40 -0800716
sousaedu2ad85172021-02-17 15:05:18 +0100717 vdc_uuid = vdc.get("id").split(":")[3]
kasarc5bf2932018-03-09 04:15:22 -0800718 if self.client._session:
sousaedu2ad85172021-02-17 15:05:18 +0100719 headers = {
720 "Accept": "application/*+xml;version=" + API_VERSION,
721 "x-vcloud-authorization": self.client._session.headers[
722 "x-vcloud-authorization"
723 ],
724 }
725 response = self.perform_request(
726 req_type="GET", url=vdc.get("href"), headers=headers
727 )
728
kasarc5bf2932018-03-09 04:15:22 -0800729 if response.status_code != 200:
730 self.logger.error("Failed to get vdc content")
tierno72774862020-05-04 11:44:15 +0000731 raise vimconn.VimConnNotFoundException("Failed to get vdc content")
kasarc5bf2932018-03-09 04:15:22 -0800732 else:
beierl26fec002019-12-06 17:06:40 -0500733 content = XmlElementTree.fromstring(response.text)
sbhangarea8e5b782018-06-21 02:10:03 -0700734
bayramovef390722016-09-27 03:34:46 -0700735 network_list = []
736 try:
kasarc5bf2932018-03-09 04:15:22 -0800737 for item in content:
sousaedu2ad85172021-02-17 15:05:18 +0100738 if item.tag.split("}")[-1] == "AvailableNetworks":
kasarc5bf2932018-03-09 04:15:22 -0800739 for net in item:
sousaedu2ad85172021-02-17 15:05:18 +0100740 response = self.perform_request(
741 req_type="GET", url=net.get("href"), headers=headers
742 )
bayramovef390722016-09-27 03:34:46 -0700743
kasarc5bf2932018-03-09 04:15:22 -0800744 if response.status_code != 200:
745 self.logger.error("Failed to get network content")
sousaedu2ad85172021-02-17 15:05:18 +0100746 raise vimconn.VimConnNotFoundException(
747 "Failed to get network content"
748 )
kasarc5bf2932018-03-09 04:15:22 -0800749 else:
beierl26fec002019-12-06 17:06:40 -0500750 net_details = XmlElementTree.fromstring(response.text)
kasarc5bf2932018-03-09 04:15:22 -0800751
752 filter_dict = {}
sousaedu2ad85172021-02-17 15:05:18 +0100753 net_uuid = net_details.get("id").split(":")
754
kasarc5bf2932018-03-09 04:15:22 -0800755 if len(net_uuid) != 4:
756 continue
757 else:
758 net_uuid = net_uuid[3]
759 # create dict entry
sousaedu2ad85172021-02-17 15:05:18 +0100760 self.logger.debug(
761 "get_vcd_network_list(): Adding network {} "
762 "to a list vcd id {} network {}".format(
763 net_uuid, vdc_uuid, net_details.get("name")
764 )
765 )
766 filter_dict["name"] = net_details.get("name")
kasarc5bf2932018-03-09 04:15:22 -0800767 filter_dict["id"] = net_uuid
sousaedu2ad85172021-02-17 15:05:18 +0100768
769 if [
770 i.text
771 for i in net_details
772 if i.tag.split("}")[-1] == "IsShared"
773 ][0] == "true":
kasarc5bf2932018-03-09 04:15:22 -0800774 shared = True
775 else:
776 shared = False
sousaedu2ad85172021-02-17 15:05:18 +0100777
kasarc5bf2932018-03-09 04:15:22 -0800778 filter_dict["shared"] = shared
779 filter_dict["tenant_id"] = vdc_uuid
sousaedu2ad85172021-02-17 15:05:18 +0100780
781 if int(net_details.get("status")) == 1:
kasarc5bf2932018-03-09 04:15:22 -0800782 filter_dict["admin_state_up"] = True
783 else:
784 filter_dict["admin_state_up"] = False
sousaedu2ad85172021-02-17 15:05:18 +0100785
kasarc5bf2932018-03-09 04:15:22 -0800786 filter_dict["status"] = "ACTIVE"
787 filter_dict["type"] = "bridge"
788 network_list.append(filter_dict)
sousaedu2ad85172021-02-17 15:05:18 +0100789 self.logger.debug(
790 "get_vcd_network_list adding entry {}".format(
791 filter_dict
792 )
793 )
beierlb22ce2d2019-12-12 12:09:51 -0500794 except Exception:
kasarc5bf2932018-03-09 04:15:22 -0800795 self.logger.debug("Error in get_vcd_network_list", exc_info=True)
bayramovef390722016-09-27 03:34:46 -0700796 pass
797
798 self.logger.debug("get_vcd_network_list returning {}".format(network_list))
sousaedu2ad85172021-02-17 15:05:18 +0100799
bayramovef390722016-09-27 03:34:46 -0700800 return network_list
bayramov325fa1c2016-09-08 01:42:46 -0700801
802 def get_network_list(self, filter_dict={}):
bayramovb6ffe792016-09-28 11:50:56 +0400803 """Obtain tenant networks of VIM
bayramov325fa1c2016-09-08 01:42:46 -0700804 Filter_dict can be:
bayramovef390722016-09-27 03:34:46 -0700805 name: network name OR/AND
806 id: network uuid OR/AND
807 shared: boolean OR/AND
808 tenant_id: tenant OR/AND
bayramov325fa1c2016-09-08 01:42:46 -0700809 admin_state_up: boolean
810 status: 'ACTIVE'
bayramovef390722016-09-27 03:34:46 -0700811
812 [{key : value , key : value}]
813
bayramov325fa1c2016-09-08 01:42:46 -0700814 Returns the network list of dictionaries:
815 [{<the fields at Filter_dict plus some VIM specific>}, ...]
816 List can be empty
bayramovb6ffe792016-09-28 11:50:56 +0400817 """
bayramov325fa1c2016-09-08 01:42:46 -0700818
sousaedu2ad85172021-02-17 15:05:18 +0100819 self.logger.debug(
820 "get_network_list(): retrieving network list for vcd {}".format(
821 self.tenant_name
822 )
823 )
kate15f1c382016-12-15 01:12:40 -0800824
825 if not self.tenant_name:
tierno72774862020-05-04 11:44:15 +0000826 raise vimconn.VimConnConnectionException("Tenant name is empty.")
bayramov325fa1c2016-09-08 01:42:46 -0700827
beierlb22ce2d2019-12-12 12:09:51 -0500828 _, vdc = self.get_vdc_details()
kate15f1c382016-12-15 01:12:40 -0800829 if vdc is None:
tierno72774862020-05-04 11:44:15 +0000830 raise vimconn.VimConnConnectionException(
sousaedu2ad85172021-02-17 15:05:18 +0100831 "Can't retrieve information for a VDC {}.".format(self.tenant_name)
832 )
bayramov325fa1c2016-09-08 01:42:46 -0700833
bayramovef390722016-09-27 03:34:46 -0700834 try:
sousaedu2ad85172021-02-17 15:05:18 +0100835 vdcid = vdc.get("id").split(":")[3]
kasarc5bf2932018-03-09 04:15:22 -0800836
837 if self.client._session:
sousaedu2ad85172021-02-17 15:05:18 +0100838 headers = {
839 "Accept": "application/*+xml;version=" + API_VERSION,
840 "x-vcloud-authorization": self.client._session.headers[
841 "x-vcloud-authorization"
842 ],
843 }
844 response = self.perform_request(
845 req_type="GET", url=vdc.get("href"), headers=headers
846 )
847
kasarc5bf2932018-03-09 04:15:22 -0800848 if response.status_code != 200:
849 self.logger.error("Failed to get vdc content")
tierno72774862020-05-04 11:44:15 +0000850 raise vimconn.VimConnNotFoundException("Failed to get vdc content")
kasarc5bf2932018-03-09 04:15:22 -0800851 else:
beierl26fec002019-12-06 17:06:40 -0500852 content = XmlElementTree.fromstring(response.text)
kasarc5bf2932018-03-09 04:15:22 -0800853
bhangarebfdca492017-03-11 01:32:46 -0800854 network_list = []
kasarc5bf2932018-03-09 04:15:22 -0800855 for item in content:
sousaedu2ad85172021-02-17 15:05:18 +0100856 if item.tag.split("}")[-1] == "AvailableNetworks":
kasarc5bf2932018-03-09 04:15:22 -0800857 for net in item:
sousaedu2ad85172021-02-17 15:05:18 +0100858 response = self.perform_request(
859 req_type="GET", url=net.get("href"), headers=headers
860 )
bhangarebfdca492017-03-11 01:32:46 -0800861
kasarc5bf2932018-03-09 04:15:22 -0800862 if response.status_code != 200:
863 self.logger.error("Failed to get network content")
sousaedu2ad85172021-02-17 15:05:18 +0100864 raise vimconn.VimConnNotFoundException(
865 "Failed to get network content"
866 )
kasarc5bf2932018-03-09 04:15:22 -0800867 else:
beierl26fec002019-12-06 17:06:40 -0500868 net_details = XmlElementTree.fromstring(response.text)
bayramovef390722016-09-27 03:34:46 -0700869
kasarc5bf2932018-03-09 04:15:22 -0800870 filter_entry = {}
sousaedu2ad85172021-02-17 15:05:18 +0100871 net_uuid = net_details.get("id").split(":")
872
kasarc5bf2932018-03-09 04:15:22 -0800873 if len(net_uuid) != 4:
874 continue
875 else:
sbhangarea8e5b782018-06-21 02:10:03 -0700876 net_uuid = net_uuid[3]
kasarc5bf2932018-03-09 04:15:22 -0800877 # create dict entry
sousaedu2ad85172021-02-17 15:05:18 +0100878 self.logger.debug(
879 "get_network_list(): Adding net {}"
880 " to a list vcd id {} network {}".format(
881 net_uuid, vdcid, net_details.get("name")
882 )
883 )
884 filter_entry["name"] = net_details.get("name")
kasarc5bf2932018-03-09 04:15:22 -0800885 filter_entry["id"] = net_uuid
sousaedu2ad85172021-02-17 15:05:18 +0100886
887 if [
888 i.text
889 for i in net_details
890 if i.tag.split("}")[-1] == "IsShared"
891 ][0] == "true":
kasarc5bf2932018-03-09 04:15:22 -0800892 shared = True
893 else:
894 shared = False
sousaedu2ad85172021-02-17 15:05:18 +0100895
kasarc5bf2932018-03-09 04:15:22 -0800896 filter_entry["shared"] = shared
897 filter_entry["tenant_id"] = vdcid
sousaedu2ad85172021-02-17 15:05:18 +0100898
899 if int(net_details.get("status")) == 1:
kasarc5bf2932018-03-09 04:15:22 -0800900 filter_entry["admin_state_up"] = True
901 else:
902 filter_entry["admin_state_up"] = False
sousaedu2ad85172021-02-17 15:05:18 +0100903
kasarc5bf2932018-03-09 04:15:22 -0800904 filter_entry["status"] = "ACTIVE"
905 filter_entry["type"] = "bridge"
906 filtered_entry = filter_entry.copy()
907
908 if filter_dict is not None and filter_dict:
909 # we remove all the key : value we don't care and match only
910 # respected field
sousaedu2ad85172021-02-17 15:05:18 +0100911 filtered_dict = set(filter_entry.keys()) - set(
912 filter_dict
913 )
914
beierlb22ce2d2019-12-12 12:09:51 -0500915 for unwanted_key in filtered_dict:
916 del filter_entry[unwanted_key]
sousaedu2ad85172021-02-17 15:05:18 +0100917
kasarc5bf2932018-03-09 04:15:22 -0800918 if filter_dict == filter_entry:
919 network_list.append(filtered_entry)
920 else:
921 network_list.append(filtered_entry)
922 except Exception as e:
beierlb22ce2d2019-12-12 12:09:51 -0500923 self.logger.debug("Error in get_network_list", exc_info=True)
sousaedu2ad85172021-02-17 15:05:18 +0100924
tierno72774862020-05-04 11:44:15 +0000925 if isinstance(e, vimconn.VimConnException):
kasarc5bf2932018-03-09 04:15:22 -0800926 raise
927 else:
sousaedu2ad85172021-02-17 15:05:18 +0100928 raise vimconn.VimConnNotFoundException(
929 "Failed : Networks list not found {} ".format(e)
930 )
bayramov325fa1c2016-09-08 01:42:46 -0700931
932 self.logger.debug("Returning {}".format(network_list))
sousaedu2ad85172021-02-17 15:05:18 +0100933
bayramov325fa1c2016-09-08 01:42:46 -0700934 return network_list
935
936 def get_network(self, net_id):
bayramovfe3f3c92016-10-04 07:53:41 +0400937 """Method obtains network details of net_id VIM network
sousaedu2ad85172021-02-17 15:05:18 +0100938 Return a dict with the fields at filter_dict (see get_network_list) plus some VIM specific>}, ...]"""
bayramovef390722016-09-27 03:34:46 -0700939 try:
beierlb22ce2d2019-12-12 12:09:51 -0500940 _, vdc = self.get_vdc_details()
sousaedu2ad85172021-02-17 15:05:18 +0100941 vdc_id = vdc.get("id").split(":")[3]
942
kasarc5bf2932018-03-09 04:15:22 -0800943 if self.client._session:
sousaedu2ad85172021-02-17 15:05:18 +0100944 headers = {
945 "Accept": "application/*+xml;version=" + API_VERSION,
946 "x-vcloud-authorization": self.client._session.headers[
947 "x-vcloud-authorization"
948 ],
949 }
950 response = self.perform_request(
951 req_type="GET", url=vdc.get("href"), headers=headers
952 )
953
kasarc5bf2932018-03-09 04:15:22 -0800954 if response.status_code != 200:
955 self.logger.error("Failed to get vdc content")
tierno72774862020-05-04 11:44:15 +0000956 raise vimconn.VimConnNotFoundException("Failed to get vdc content")
kasarc5bf2932018-03-09 04:15:22 -0800957 else:
beierl26fec002019-12-06 17:06:40 -0500958 content = XmlElementTree.fromstring(response.text)
bhangarebfdca492017-03-11 01:32:46 -0800959
bhangarebfdca492017-03-11 01:32:46 -0800960 filter_dict = {}
961
kasarc5bf2932018-03-09 04:15:22 -0800962 for item in content:
sousaedu2ad85172021-02-17 15:05:18 +0100963 if item.tag.split("}")[-1] == "AvailableNetworks":
kasarc5bf2932018-03-09 04:15:22 -0800964 for net in item:
sousaedu2ad85172021-02-17 15:05:18 +0100965 response = self.perform_request(
966 req_type="GET", url=net.get("href"), headers=headers
967 )
kasarc30a04e2017-08-24 05:58:18 -0700968
kasarc5bf2932018-03-09 04:15:22 -0800969 if response.status_code != 200:
970 self.logger.error("Failed to get network content")
sousaedu2ad85172021-02-17 15:05:18 +0100971 raise vimconn.VimConnNotFoundException(
972 "Failed to get network content"
973 )
kasarc5bf2932018-03-09 04:15:22 -0800974 else:
beierl26fec002019-12-06 17:06:40 -0500975 net_details = XmlElementTree.fromstring(response.text)
kasarc5bf2932018-03-09 04:15:22 -0800976
sousaedu2ad85172021-02-17 15:05:18 +0100977 vdc_network_id = net_details.get("id").split(":")
kasarc5bf2932018-03-09 04:15:22 -0800978 if len(vdc_network_id) == 4 and vdc_network_id[3] == net_id:
sousaedu2ad85172021-02-17 15:05:18 +0100979 filter_dict["name"] = net_details.get("name")
kasarc5bf2932018-03-09 04:15:22 -0800980 filter_dict["id"] = vdc_network_id[3]
sousaedu2ad85172021-02-17 15:05:18 +0100981
982 if [
983 i.text
984 for i in net_details
985 if i.tag.split("}")[-1] == "IsShared"
986 ][0] == "true":
kasarc5bf2932018-03-09 04:15:22 -0800987 shared = True
988 else:
989 shared = False
sousaedu2ad85172021-02-17 15:05:18 +0100990
kasarc5bf2932018-03-09 04:15:22 -0800991 filter_dict["shared"] = shared
992 filter_dict["tenant_id"] = vdc_id
sousaedu2ad85172021-02-17 15:05:18 +0100993
994 if int(net_details.get("status")) == 1:
kasarc5bf2932018-03-09 04:15:22 -0800995 filter_dict["admin_state_up"] = True
996 else:
997 filter_dict["admin_state_up"] = False
sousaedu2ad85172021-02-17 15:05:18 +0100998
kasarc5bf2932018-03-09 04:15:22 -0800999 filter_dict["status"] = "ACTIVE"
1000 filter_dict["type"] = "bridge"
1001 self.logger.debug("Returning {}".format(filter_dict))
sousaedu2ad85172021-02-17 15:05:18 +01001002
kasarc5bf2932018-03-09 04:15:22 -08001003 return filter_dict
bayramovef390722016-09-27 03:34:46 -07001004 else:
sousaedu2ad85172021-02-17 15:05:18 +01001005 raise vimconn.VimConnNotFoundException(
1006 "Network {} not found".format(net_id)
1007 )
kasarc30a04e2017-08-24 05:58:18 -07001008 except Exception as e:
bayramovef390722016-09-27 03:34:46 -07001009 self.logger.debug("Error in get_network")
1010 self.logger.debug(traceback.format_exc())
sousaedu2ad85172021-02-17 15:05:18 +01001011
tierno72774862020-05-04 11:44:15 +00001012 if isinstance(e, vimconn.VimConnException):
kasarc30a04e2017-08-24 05:58:18 -07001013 raise
1014 else:
sousaedu2ad85172021-02-17 15:05:18 +01001015 raise vimconn.VimConnNotFoundException(
1016 "Failed : Network not found {} ".format(e)
1017 )
bayramovef390722016-09-27 03:34:46 -07001018
1019 return filter_dict
bayramov325fa1c2016-09-08 01:42:46 -07001020
garciadeblasebd66722019-01-31 16:01:31 +00001021 def delete_network(self, net_id, created_items=None):
bayramovef390722016-09-27 03:34:46 -07001022 """
garciadeblasebd66722019-01-31 16:01:31 +00001023 Removes a tenant network from VIM and its associated elements
1024 :param net_id: VIM identifier of the network, provided by method new_network
1025 :param created_items: dictionary with extra items to be deleted. provided by method new_network
1026 Returns the network identifier or raises an exception upon error or when network is not found
bayramovef390722016-09-27 03:34:46 -07001027 """
1028
kateac1e3792017-04-01 02:16:39 -07001029 # ############# Stub code for SRIOV #################
sousaedu2ad85172021-02-17 15:05:18 +01001030 # dvport_group = self.get_dvport_group(net_id)
1031 # if dvport_group:
1032 # #delete portgroup
1033 # status = self.destroy_dvport_group(net_id)
1034 # if status:
1035 # # Remove vlanID from persistent info
1036 # if net_id in self.persistent_info["used_vlanIDs"]:
1037 # del self.persistent_info["used_vlanIDs"][net_id]
1038 #
1039 # return net_id
kateac1e3792017-04-01 02:16:39 -07001040
bayramovfe3f3c92016-10-04 07:53:41 +04001041 vcd_network = self.get_vcd_network(network_uuid=net_id)
1042 if vcd_network is not None and vcd_network:
1043 if self.delete_network_action(network_uuid=net_id):
1044 return net_id
bayramovef390722016-09-27 03:34:46 -07001045 else:
sousaedu2ad85172021-02-17 15:05:18 +01001046 raise vimconn.VimConnNotFoundException(
1047 "Network {} not found".format(net_id)
1048 )
bayramov325fa1c2016-09-08 01:42:46 -07001049
1050 def refresh_nets_status(self, net_list):
bayramovbd6160f2016-09-28 04:12:05 +04001051 """Get the status of the networks
sousaedu2ad85172021-02-17 15:05:18 +01001052 Params: the list of network identifiers
1053 Returns a dictionary with:
1054 net_id: #VIM id of this network
1055 status: #Mandatory. Text with one of:
1056 # DELETED (not found at vim)
1057 # VIM_ERROR (Cannot connect to VIM, VIM response error, ...)
1058 # OTHER (Vim reported other status not understood)
1059 # ERROR (VIM indicates an ERROR status)
1060 # ACTIVE, INACTIVE, DOWN (admin down),
1061 # BUILD (on building process)
1062 #
1063 error_msg: #Text with VIM error message, if any. Or the VIM connection ERROR
1064 vim_info: #Text with plain information obtained from vim (yaml.safe_dump)
bayramov325fa1c2016-09-08 01:42:46 -07001065
bayramovbd6160f2016-09-28 04:12:05 +04001066 """
bayramovef390722016-09-27 03:34:46 -07001067 dict_entry = {}
1068 try:
1069 for net in net_list:
sousaedu2ad85172021-02-17 15:05:18 +01001070 errormsg = ""
bayramovef390722016-09-27 03:34:46 -07001071 vcd_network = self.get_vcd_network(network_uuid=net)
bayramovfe3f3c92016-10-04 07:53:41 +04001072 if vcd_network is not None and vcd_network:
sousaedu2ad85172021-02-17 15:05:18 +01001073 if vcd_network["status"] == "1":
1074 status = "ACTIVE"
bayramovef390722016-09-27 03:34:46 -07001075 else:
sousaedu2ad85172021-02-17 15:05:18 +01001076 status = "DOWN"
bayramovef390722016-09-27 03:34:46 -07001077 else:
sousaedu2ad85172021-02-17 15:05:18 +01001078 status = "DELETED"
1079 errormsg = "Network not found."
bayramovfe3f3c92016-10-04 07:53:41 +04001080
sousaedu2ad85172021-02-17 15:05:18 +01001081 dict_entry[net] = {
1082 "status": status,
1083 "error_msg": errormsg,
1084 "vim_info": yaml.safe_dump(vcd_network),
1085 }
beierlb22ce2d2019-12-12 12:09:51 -05001086 except Exception:
bayramovef390722016-09-27 03:34:46 -07001087 self.logger.debug("Error in refresh_nets_status")
1088 self.logger.debug(traceback.format_exc())
1089
1090 return dict_entry
1091
bayramovbd6160f2016-09-28 04:12:05 +04001092 def get_flavor(self, flavor_id):
bayramovef390722016-09-27 03:34:46 -07001093 """Obtain flavor details from the VIM
sousaedu2ad85172021-02-17 15:05:18 +01001094 Returns the flavor dict details {'id':<>, 'name':<>, other vim specific } #TODO to concrete
bayramovef390722016-09-27 03:34:46 -07001095 """
kateeb044522017-03-06 23:54:39 -08001096 if flavor_id not in vimconnector.flavorlist:
tierno72774862020-05-04 11:44:15 +00001097 raise vimconn.VimConnNotFoundException("Flavor not found.")
sousaedu2ad85172021-02-17 15:05:18 +01001098
kateeb044522017-03-06 23:54:39 -08001099 return vimconnector.flavorlist[flavor_id]
bayramov325fa1c2016-09-08 01:42:46 -07001100
1101 def new_flavor(self, flavor_data):
bayramovef390722016-09-27 03:34:46 -07001102 """Adds a tenant flavor to VIM
bayramov325fa1c2016-09-08 01:42:46 -07001103 flavor_data contains a dictionary with information, keys:
1104 name: flavor name
1105 ram: memory (cloud type) in MBytes
1106 vpcus: cpus (cloud type)
1107 extended: EPA parameters
1108 - numas: #items requested in same NUMA
1109 memory: number of 1G huge pages memory
beierlb22ce2d2019-12-12 12:09:51 -05001110 paired-threads|cores|threads: number of paired hyperthreads, complete cores OR individual
1111 threads
bayramov325fa1c2016-09-08 01:42:46 -07001112 interfaces: # passthrough(PT) or SRIOV interfaces attached to this numa
1113 - name: interface name
1114 dedicated: yes|no|yes:sriov; for PT, SRIOV or only one SRIOV for the physical NIC
1115 bandwidth: X Gbps; requested guarantee bandwidth
bayramovef390722016-09-27 03:34:46 -07001116 vpci: requested virtual PCI address
bayramov325fa1c2016-09-08 01:42:46 -07001117 disk: disk size
1118 is_public:
bayramov325fa1c2016-09-08 01:42:46 -07001119 #TODO to concrete
bayramovef390722016-09-27 03:34:46 -07001120 Returns the flavor identifier"""
bayramov325fa1c2016-09-08 01:42:46 -07001121
bayramovef390722016-09-27 03:34:46 -07001122 # generate a new uuid put to internal dict and return it.
bhangarea92ae392017-01-12 22:30:29 -08001123 self.logger.debug("Creating new flavor - flavor_data: {}".format(flavor_data))
beierlb22ce2d2019-12-12 12:09:51 -05001124 new_flavor = flavor_data
bhangarea92ae392017-01-12 22:30:29 -08001125 ram = flavor_data.get(FLAVOR_RAM_KEY, 1024)
1126 cpu = flavor_data.get(FLAVOR_VCPUS_KEY, 1)
garciadeblas79d1a1a2017-12-11 16:07:07 +01001127 disk = flavor_data.get(FLAVOR_DISK_KEY, 0)
bhangarea92ae392017-01-12 22:30:29 -08001128
kasarfeaaa052017-06-08 03:46:18 -07001129 if not isinstance(ram, int):
tierno72774862020-05-04 11:44:15 +00001130 raise vimconn.VimConnException("Non-integer value for ram")
kasarfeaaa052017-06-08 03:46:18 -07001131 elif not isinstance(cpu, int):
tierno72774862020-05-04 11:44:15 +00001132 raise vimconn.VimConnException("Non-integer value for cpu")
kasarfeaaa052017-06-08 03:46:18 -07001133 elif not isinstance(disk, int):
tierno72774862020-05-04 11:44:15 +00001134 raise vimconn.VimConnException("Non-integer value for disk")
kasarfeaaa052017-06-08 03:46:18 -07001135
bhangarea92ae392017-01-12 22:30:29 -08001136 extended_flv = flavor_data.get("extended")
1137 if extended_flv:
beierlb22ce2d2019-12-12 12:09:51 -05001138 numas = extended_flv.get("numas")
bhangarea92ae392017-01-12 22:30:29 -08001139 if numas:
1140 for numa in numas:
beierlb22ce2d2019-12-12 12:09:51 -05001141 # overwrite ram and vcpus
sousaedu2ad85172021-02-17 15:05:18 +01001142 if "memory" in numa:
1143 ram = numa["memory"] * 1024
1144
1145 if "paired-threads" in numa:
1146 cpu = numa["paired-threads"] * 2
1147 elif "cores" in numa:
1148 cpu = numa["cores"]
1149 elif "threads" in numa:
1150 cpu = numa["threads"]
bhangarea92ae392017-01-12 22:30:29 -08001151
1152 new_flavor[FLAVOR_RAM_KEY] = ram
1153 new_flavor[FLAVOR_VCPUS_KEY] = cpu
1154 new_flavor[FLAVOR_DISK_KEY] = disk
1155 # generate a new uuid put to internal dict and return it.
bayramovef390722016-09-27 03:34:46 -07001156 flavor_id = uuid.uuid4()
kateeb044522017-03-06 23:54:39 -08001157 vimconnector.flavorlist[str(flavor_id)] = new_flavor
bhangarea92ae392017-01-12 22:30:29 -08001158 self.logger.debug("Created flavor - {} : {}".format(flavor_id, new_flavor))
bayramov325fa1c2016-09-08 01:42:46 -07001159
bayramovef390722016-09-27 03:34:46 -07001160 return str(flavor_id)
bayramov325fa1c2016-09-08 01:42:46 -07001161
1162 def delete_flavor(self, flavor_id):
bayramovef390722016-09-27 03:34:46 -07001163 """Deletes a tenant flavor from VIM identify by its id
bayramov325fa1c2016-09-08 01:42:46 -07001164
sousaedu2ad85172021-02-17 15:05:18 +01001165 Returns the used id or raise an exception
bayramovef390722016-09-27 03:34:46 -07001166 """
kateeb044522017-03-06 23:54:39 -08001167 if flavor_id not in vimconnector.flavorlist:
tierno72774862020-05-04 11:44:15 +00001168 raise vimconn.VimConnNotFoundException("Flavor not found.")
bayramovef390722016-09-27 03:34:46 -07001169
kateeb044522017-03-06 23:54:39 -08001170 vimconnector.flavorlist.pop(flavor_id, None)
sousaedu2ad85172021-02-17 15:05:18 +01001171
bayramovef390722016-09-27 03:34:46 -07001172 return flavor_id
1173
1174 def new_image(self, image_dict):
bayramov5761ad12016-10-04 09:00:30 +04001175 """
bayramov325fa1c2016-09-08 01:42:46 -07001176 Adds a tenant image to VIM
1177 Returns:
1178 200, image-id if the image is created
1179 <0, message if there is an error
bayramov5761ad12016-10-04 09:00:30 +04001180 """
sousaedu2ad85172021-02-17 15:05:18 +01001181 return self.get_image_id_from_path(image_dict["location"])
bayramov325fa1c2016-09-08 01:42:46 -07001182
1183 def delete_image(self, image_id):
bayramovfe3f3c92016-10-04 07:53:41 +04001184 """
sousaedu2ad85172021-02-17 15:05:18 +01001185 Deletes a tenant image from VIM
1186 Args:
1187 image_id is ID of Image to be deleted
1188 Return:
1189 returns the image identifier in UUID format or raises an exception on error
bayramovfe3f3c92016-10-04 07:53:41 +04001190 """
kasarc5bf2932018-03-09 04:15:22 -08001191 conn = self.connect_as_admin()
sousaedu2ad85172021-02-17 15:05:18 +01001192
kasarc5bf2932018-03-09 04:15:22 -08001193 if not conn:
tierno72774862020-05-04 11:44:15 +00001194 raise vimconn.VimConnConnectionException("Failed to connect vCD")
sousaedu2ad85172021-02-17 15:05:18 +01001195
kated47ad5f2017-08-03 02:16:13 -07001196 # Get Catalog details
sousaedu2ad85172021-02-17 15:05:18 +01001197 url_list = [self.url, "/api/catalog/", image_id]
1198 catalog_herf = "".join(url_list)
kasarc5bf2932018-03-09 04:15:22 -08001199
sousaedu2ad85172021-02-17 15:05:18 +01001200 headers = {
1201 "Accept": "application/*+xml;version=" + API_VERSION,
1202 "x-vcloud-authorization": conn._session.headers["x-vcloud-authorization"],
1203 }
kasarc5bf2932018-03-09 04:15:22 -08001204
sousaedu2ad85172021-02-17 15:05:18 +01001205 response = self.perform_request(
1206 req_type="GET", url=catalog_herf, headers=headers
1207 )
bayramovfe3f3c92016-10-04 07:53:41 +04001208
kated47ad5f2017-08-03 02:16:13 -07001209 if response.status_code != requests.codes.ok:
sousaedu2ad85172021-02-17 15:05:18 +01001210 self.logger.debug(
1211 "delete_image():GET REST API call {} failed. "
1212 "Return status code {}".format(catalog_herf, response.status_code)
1213 )
1214
1215 raise vimconn.VimConnNotFoundException(
1216 "Fail to get image {}".format(image_id)
1217 )
kated47ad5f2017-08-03 02:16:13 -07001218
beierl01bd6692019-12-09 17:06:20 -05001219 lxmlroot_respond = lxmlElementTree.fromstring(response.content)
sousaedu2ad85172021-02-17 15:05:18 +01001220 namespaces = {
1221 prefix: uri for prefix, uri in lxmlroot_respond.nsmap.items() if prefix
1222 }
beierl01bd6692019-12-09 17:06:20 -05001223 namespaces["xmlns"] = "http://www.vmware.com/vcloud/v1.5"
kated47ad5f2017-08-03 02:16:13 -07001224
beierl01bd6692019-12-09 17:06:20 -05001225 catalogItems_section = lxmlroot_respond.find("xmlns:CatalogItems", namespaces)
1226 catalogItems = catalogItems_section.iterfind("xmlns:CatalogItem", namespaces)
kated47ad5f2017-08-03 02:16:13 -07001227
sousaedu2ad85172021-02-17 15:05:18 +01001228 for catalogItem in catalogItems:
1229 catalogItem_href = catalogItem.attrib["href"]
1230
1231 response = self.perform_request(
1232 req_type="GET", url=catalogItem_href, headers=headers
1233 )
kated47ad5f2017-08-03 02:16:13 -07001234
1235 if response.status_code != requests.codes.ok:
sousaedu2ad85172021-02-17 15:05:18 +01001236 self.logger.debug(
1237 "delete_image():GET REST API call {} failed. "
1238 "Return status code {}".format(catalog_herf, response.status_code)
1239 )
1240 raise vimconn.VimConnNotFoundException(
1241 "Fail to get catalogItem {} for catalog {}".format(
1242 catalogItem, image_id
1243 )
1244 )
kated47ad5f2017-08-03 02:16:13 -07001245
beierl01bd6692019-12-09 17:06:20 -05001246 lxmlroot_respond = lxmlElementTree.fromstring(response.content)
sousaedu2ad85172021-02-17 15:05:18 +01001247 namespaces = {
1248 prefix: uri for prefix, uri in lxmlroot_respond.nsmap.items() if prefix
1249 }
beierl01bd6692019-12-09 17:06:20 -05001250 namespaces["xmlns"] = "http://www.vmware.com/vcloud/v1.5"
sousaedu2ad85172021-02-17 15:05:18 +01001251 catalogitem_remove_href = lxmlroot_respond.find(
1252 "xmlns:Link[@rel='remove']", namespaces
1253 ).attrib["href"]
kated47ad5f2017-08-03 02:16:13 -07001254
beierl01bd6692019-12-09 17:06:20 -05001255 # Remove catalogItem
sousaedu2ad85172021-02-17 15:05:18 +01001256 response = self.perform_request(
1257 req_type="DELETE", url=catalogitem_remove_href, headers=headers
1258 )
1259
kated47ad5f2017-08-03 02:16:13 -07001260 if response.status_code == requests.codes.no_content:
1261 self.logger.debug("Deleted Catalog item {}".format(catalogItem))
1262 else:
sousaedu2ad85172021-02-17 15:05:18 +01001263 raise vimconn.VimConnException(
1264 "Fail to delete Catalog Item {}".format(catalogItem)
1265 )
kated47ad5f2017-08-03 02:16:13 -07001266
beierl01bd6692019-12-09 17:06:20 -05001267 # Remove catalog
sousaedu2ad85172021-02-17 15:05:18 +01001268 url_list = [self.url, "/api/admin/catalog/", image_id]
1269 catalog_remove_herf = "".join(url_list)
1270 response = self.perform_request(
1271 req_type="DELETE", url=catalog_remove_herf, headers=headers
1272 )
kated47ad5f2017-08-03 02:16:13 -07001273
1274 if response.status_code == requests.codes.no_content:
1275 self.logger.debug("Deleted Catalog {}".format(image_id))
sousaedu2ad85172021-02-17 15:05:18 +01001276
kated47ad5f2017-08-03 02:16:13 -07001277 return image_id
1278 else:
tierno72774862020-05-04 11:44:15 +00001279 raise vimconn.VimConnException("Fail to delete Catalog {}".format(image_id))
kated47ad5f2017-08-03 02:16:13 -07001280
bayramov325fa1c2016-09-08 01:42:46 -07001281 def catalog_exists(self, catalog_name, catalogs):
bayramovfe3f3c92016-10-04 07:53:41 +04001282 """
1283
1284 :param catalog_name:
1285 :param catalogs:
1286 :return:
1287 """
bayramov325fa1c2016-09-08 01:42:46 -07001288 for catalog in catalogs:
sousaedu2ad85172021-02-17 15:05:18 +01001289 if catalog["name"] == catalog_name:
1290 return catalog["id"]
bayramov325fa1c2016-09-08 01:42:46 -07001291
bayramovb6ffe792016-09-28 11:50:56 +04001292 def create_vimcatalog(self, vca=None, catalog_name=None):
sousaedu2ad85172021-02-17 15:05:18 +01001293 """Create new catalog entry in vCloud director.
bayramovb6ffe792016-09-28 11:50:56 +04001294
sousaedu2ad85172021-02-17 15:05:18 +01001295 Args
1296 vca: vCloud director.
1297 catalog_name catalog that client wish to create. Note no validation done for a name.
1298 Client must make sure that provide valid string representation.
bayramovb6ffe792016-09-28 11:50:56 +04001299
sousaedu2ad85172021-02-17 15:05:18 +01001300 Returns catalog id if catalog created else None.
bayramovb6ffe792016-09-28 11:50:56 +04001301
1302 """
1303 try:
Ananda Baitharu319c26f2019-03-05 17:34:31 +00001304 lxml_catalog_element = vca.create_catalog(catalog_name, catalog_name)
sousaedu2ad85172021-02-17 15:05:18 +01001305
Ananda Baitharu319c26f2019-03-05 17:34:31 +00001306 if lxml_catalog_element:
sousaedu2ad85172021-02-17 15:05:18 +01001307 id_attr_value = lxml_catalog_element.get("id")
1308 return id_attr_value.split(":")[-1]
1309
kasarc5bf2932018-03-09 04:15:22 -08001310 catalogs = vca.list_catalogs()
Ananda Baitharu319c26f2019-03-05 17:34:31 +00001311 except Exception as ex:
1312 self.logger.error(
sousaedu2ad85172021-02-17 15:05:18 +01001313 'create_vimcatalog(): Creation of catalog "{}" failed with error: {}'.format(
1314 catalog_name, ex
1315 )
1316 )
Ananda Baitharu319c26f2019-03-05 17:34:31 +00001317 raise
bayramov325fa1c2016-09-08 01:42:46 -07001318 return self.catalog_exists(catalog_name, catalogs)
1319
bayramov5761ad12016-10-04 09:00:30 +04001320 # noinspection PyIncorrectDocstring
sousaedu2ad85172021-02-17 15:05:18 +01001321 def upload_ovf(
1322 self,
1323 vca=None,
1324 catalog_name=None,
1325 image_name=None,
1326 media_file_name=None,
1327 description="",
1328 progress=False,
1329 chunk_bytes=128 * 1024,
1330 ):
bayramov325fa1c2016-09-08 01:42:46 -07001331 """
1332 Uploads a OVF file to a vCloud catalog
1333
bayramov5761ad12016-10-04 09:00:30 +04001334 :param chunk_bytes:
1335 :param progress:
1336 :param description:
1337 :param image_name:
1338 :param vca:
bayramov325fa1c2016-09-08 01:42:46 -07001339 :param catalog_name: (str): The name of the catalog to upload the media.
bayramov325fa1c2016-09-08 01:42:46 -07001340 :param media_file_name: (str): The name of the local media file to upload.
1341 :return: (bool) True if the media file was successfully uploaded, false otherwise.
1342 """
1343 os.path.isfile(media_file_name)
1344 statinfo = os.stat(media_file_name)
bayramov325fa1c2016-09-08 01:42:46 -07001345
1346 # find a catalog entry where we upload OVF.
1347 # create vApp Template and check the status if vCD able to read OVF it will respond with appropirate
1348 # status change.
1349 # if VCD can parse OVF we upload VMDK file
bhangarebfdca492017-03-11 01:32:46 -08001350 try:
kasarc5bf2932018-03-09 04:15:22 -08001351 for catalog in vca.list_catalogs():
sousaedu2ad85172021-02-17 15:05:18 +01001352 if catalog_name != catalog["name"]:
bhangarebfdca492017-03-11 01:32:46 -08001353 continue
sousaedu2ad85172021-02-17 15:05:18 +01001354 catalog_href = "{}/api/catalog/{}/action/upload".format(
1355 self.url, catalog["id"]
1356 )
bhangarebfdca492017-03-11 01:32:46 -08001357 data = """
beierlb22ce2d2019-12-12 12:09:51 -05001358 <UploadVAppTemplateParams name="{}"
1359 xmlns="http://www.vmware.com/vcloud/v1.5"
1360 xmlns:ovf="http://schemas.dmtf.org/ovf/envelope/1">
1361 <Description>{} vApp Template</Description>
1362 </UploadVAppTemplateParams>
sousaedu2ad85172021-02-17 15:05:18 +01001363 """.format(
1364 catalog_name, description
1365 )
kasarc5bf2932018-03-09 04:15:22 -08001366
1367 if self.client:
sousaedu2ad85172021-02-17 15:05:18 +01001368 headers = {
1369 "Accept": "application/*+xml;version=" + API_VERSION,
1370 "x-vcloud-authorization": self.client._session.headers[
1371 "x-vcloud-authorization"
1372 ],
1373 }
1374 headers[
1375 "Content-Type"
1376 ] = "application/vnd.vmware.vcloud.uploadVAppTemplateParams+xml"
kasarc5bf2932018-03-09 04:15:22 -08001377
sousaedu2ad85172021-02-17 15:05:18 +01001378 response = self.perform_request(
1379 req_type="POST", url=catalog_href, headers=headers, data=data
1380 )
kasarc5bf2932018-03-09 04:15:22 -08001381
bhangarebfdca492017-03-11 01:32:46 -08001382 if response.status_code == requests.codes.created:
beierl26fec002019-12-06 17:06:40 -05001383 catalogItem = XmlElementTree.fromstring(response.text)
sousaedu2ad85172021-02-17 15:05:18 +01001384 entity = [
1385 child
1386 for child in catalogItem
1387 if child.get("type")
1388 == "application/vnd.vmware.vcloud.vAppTemplate+xml"
1389 ][0]
1390 href = entity.get("href")
bhangarebfdca492017-03-11 01:32:46 -08001391 template = href
kasarc5bf2932018-03-09 04:15:22 -08001392
sousaedu2ad85172021-02-17 15:05:18 +01001393 response = self.perform_request(
1394 req_type="GET", url=href, headers=headers
1395 )
bhangarebfdca492017-03-11 01:32:46 -08001396
1397 if response.status_code == requests.codes.ok:
sousaedu2ad85172021-02-17 15:05:18 +01001398 headers["Content-Type"] = "Content-Type text/xml"
1399 result = re.search(
1400 'rel="upload:default"\shref="(.*?\/descriptor.ovf)"',
1401 response.text,
1402 )
1403
kasarc5bf2932018-03-09 04:15:22 -08001404 if result:
1405 transfer_href = result.group(1)
1406
sousaedu2ad85172021-02-17 15:05:18 +01001407 response = self.perform_request(
1408 req_type="PUT",
1409 url=transfer_href,
1410 headers=headers,
1411 data=open(media_file_name, "rb"),
1412 )
1413
bhangarebfdca492017-03-11 01:32:46 -08001414 if response.status_code != requests.codes.ok:
1415 self.logger.debug(
sousaedu2ad85172021-02-17 15:05:18 +01001416 "Failed create vApp template for catalog name {} and image {}".format(
1417 catalog_name, media_file_name
1418 )
1419 )
bhangarebfdca492017-03-11 01:32:46 -08001420 return False
1421
1422 # TODO fix this with aync block
1423 time.sleep(5)
1424
sousaedu2ad85172021-02-17 15:05:18 +01001425 self.logger.debug(
1426 "vApp template for catalog name {} and image {}".format(
1427 catalog_name, media_file_name
1428 )
1429 )
bhangarebfdca492017-03-11 01:32:46 -08001430
1431 # uploading VMDK file
1432 # check status of OVF upload and upload remaining files.
sousaedu2ad85172021-02-17 15:05:18 +01001433 response = self.perform_request(
1434 req_type="GET", url=template, headers=headers
1435 )
bhangarebfdca492017-03-11 01:32:46 -08001436
1437 if response.status_code == requests.codes.ok:
sousaedu2ad85172021-02-17 15:05:18 +01001438 result = re.search(
1439 'rel="upload:default"\s*href="(.*?vmdk)"', response.text
1440 )
1441
kasarc5bf2932018-03-09 04:15:22 -08001442 if result:
1443 link_href = result.group(1)
sousaedu2ad85172021-02-17 15:05:18 +01001444
kasarc5bf2932018-03-09 04:15:22 -08001445 # we skip ovf since it already uploaded.
sousaedu2ad85172021-02-17 15:05:18 +01001446 if "ovf" in link_href:
kasarc5bf2932018-03-09 04:15:22 -08001447 continue
sousaedu2ad85172021-02-17 15:05:18 +01001448
kasarc5bf2932018-03-09 04:15:22 -08001449 # The OVF file and VMDK must be in a same directory
beierlb22ce2d2019-12-12 12:09:51 -05001450 head, _ = os.path.split(media_file_name)
sousaedu2ad85172021-02-17 15:05:18 +01001451 file_vmdk = head + "/" + link_href.split("/")[-1]
1452
kasarc5bf2932018-03-09 04:15:22 -08001453 if not os.path.isfile(file_vmdk):
1454 return False
sousaedu2ad85172021-02-17 15:05:18 +01001455
kasarc5bf2932018-03-09 04:15:22 -08001456 statinfo = os.stat(file_vmdk)
1457 if statinfo.st_size == 0:
1458 return False
sousaedu2ad85172021-02-17 15:05:18 +01001459
kasarc5bf2932018-03-09 04:15:22 -08001460 hrefvmdk = link_href
1461
1462 if progress:
sousaedu2ad85172021-02-17 15:05:18 +01001463 widgets = [
1464 "Uploading file: ",
1465 Percentage(),
1466 " ",
1467 Bar(),
1468 " ",
1469 ETA(),
1470 " ",
1471 FileTransferSpeed(),
1472 ]
1473 progress_bar = ProgressBar(
1474 widgets=widgets, maxval=statinfo.st_size
1475 ).start()
kasarc5bf2932018-03-09 04:15:22 -08001476
1477 bytes_transferred = 0
sousaedu2ad85172021-02-17 15:05:18 +01001478 f = open(file_vmdk, "rb")
1479
kasarc5bf2932018-03-09 04:15:22 -08001480 while bytes_transferred < statinfo.st_size:
1481 my_bytes = f.read(chunk_bytes)
1482 if len(my_bytes) <= chunk_bytes:
sousaedu2ad85172021-02-17 15:05:18 +01001483 headers["Content-Range"] = "bytes {}-{}/{}".format(
1484 bytes_transferred,
1485 len(my_bytes) - 1,
1486 statinfo.st_size,
1487 )
1488 headers["Content-Length"] = str(len(my_bytes))
1489 response = requests.put(
1490 url=hrefvmdk,
1491 headers=headers,
1492 data=my_bytes,
1493 verify=False,
1494 )
1495
kasarc5bf2932018-03-09 04:15:22 -08001496 if response.status_code == requests.codes.ok:
1497 bytes_transferred += len(my_bytes)
1498 if progress:
1499 progress_bar.update(bytes_transferred)
1500 else:
1501 self.logger.debug(
sousaedu2ad85172021-02-17 15:05:18 +01001502 "file upload failed with error: [{}] {}".format(
1503 response.status_code, response.text
1504 )
1505 )
kasarc5bf2932018-03-09 04:15:22 -08001506
1507 f.close()
sousaedu2ad85172021-02-17 15:05:18 +01001508
bhangarebfdca492017-03-11 01:32:46 -08001509 return False
sousaedu2ad85172021-02-17 15:05:18 +01001510
kasarc5bf2932018-03-09 04:15:22 -08001511 f.close()
1512 if progress:
1513 progress_bar.finish()
1514 time.sleep(10)
sousaedu2ad85172021-02-17 15:05:18 +01001515
kasarc5bf2932018-03-09 04:15:22 -08001516 return True
1517 else:
sousaedu2ad85172021-02-17 15:05:18 +01001518 self.logger.debug(
1519 "Failed retrieve vApp template for catalog name {} for OVF {}".format(
1520 catalog_name, media_file_name
1521 )
1522 )
kasarc5bf2932018-03-09 04:15:22 -08001523 return False
bhangarebfdca492017-03-11 01:32:46 -08001524 except Exception as exp:
sousaedu2ad85172021-02-17 15:05:18 +01001525 self.logger.debug(
1526 "Failed while uploading OVF to catalog {} for OVF file {} with Exception {}".format(
1527 catalog_name, media_file_name, exp
1528 )
1529 )
bayramov325fa1c2016-09-08 01:42:46 -07001530
sousaedu2ad85172021-02-17 15:05:18 +01001531 raise vimconn.VimConnException(
1532 "Failed while uploading OVF to catalog {} for OVF file {} with Exception {}".format(
1533 catalog_name, media_file_name, exp
1534 )
1535 )
1536
1537 self.logger.debug(
1538 "Failed retrieve catalog name {} for OVF file {}".format(
1539 catalog_name, media_file_name
1540 )
1541 )
1542
bayramov325fa1c2016-09-08 01:42:46 -07001543 return False
1544
sousaedu2ad85172021-02-17 15:05:18 +01001545 def upload_vimimage(
1546 self,
1547 vca=None,
1548 catalog_name=None,
1549 media_name=None,
1550 medial_file_name=None,
1551 progress=False,
1552 ):
bayramov325fa1c2016-09-08 01:42:46 -07001553 """Upload media file"""
bayramovfe3f3c92016-10-04 07:53:41 +04001554 # TODO add named parameters for readability
sousaedu2ad85172021-02-17 15:05:18 +01001555 return self.upload_ovf(
1556 vca=vca,
1557 catalog_name=catalog_name,
1558 image_name=media_name.split(".")[0],
1559 media_file_name=medial_file_name,
1560 description="medial_file_name",
1561 progress=progress,
1562 )
bayramov325fa1c2016-09-08 01:42:46 -07001563
bayramovb6ffe792016-09-28 11:50:56 +04001564 def validate_uuid4(self, uuid_string=None):
sousaedu2ad85172021-02-17 15:05:18 +01001565 """Method validate correct format of UUID.
bayramovb6ffe792016-09-28 11:50:56 +04001566
1567 Return: true if string represent valid uuid
1568 """
1569 try:
beierlb22ce2d2019-12-12 12:09:51 -05001570 uuid.UUID(uuid_string, version=4)
bayramovb6ffe792016-09-28 11:50:56 +04001571 except ValueError:
1572 return False
sousaedu2ad85172021-02-17 15:05:18 +01001573
bayramovb6ffe792016-09-28 11:50:56 +04001574 return True
1575
1576 def get_catalogid(self, catalog_name=None, catalogs=None):
sousaedu2ad85172021-02-17 15:05:18 +01001577 """Method check catalog and return catalog ID in UUID format.
bayramovb6ffe792016-09-28 11:50:56 +04001578
1579 Args
1580 catalog_name: catalog name as string
1581 catalogs: list of catalogs.
1582
1583 Return: catalogs uuid
1584 """
bayramov325fa1c2016-09-08 01:42:46 -07001585 for catalog in catalogs:
sousaedu2ad85172021-02-17 15:05:18 +01001586 if catalog["name"] == catalog_name:
1587 catalog_id = catalog["id"]
kasarc5bf2932018-03-09 04:15:22 -08001588 return catalog_id
sousaedu2ad85172021-02-17 15:05:18 +01001589
bayramov325fa1c2016-09-08 01:42:46 -07001590 return None
1591
bayramovb6ffe792016-09-28 11:50:56 +04001592 def get_catalogbyid(self, catalog_uuid=None, catalogs=None):
sousaedu2ad85172021-02-17 15:05:18 +01001593 """Method check catalog and return catalog name lookup done by catalog UUID.
bayramovb6ffe792016-09-28 11:50:56 +04001594
1595 Args
1596 catalog_name: catalog name as string
1597 catalogs: list of catalogs.
1598
1599 Return: catalogs name or None
1600 """
bayramovb6ffe792016-09-28 11:50:56 +04001601 if not self.validate_uuid4(uuid_string=catalog_uuid):
1602 return None
1603
bayramov325fa1c2016-09-08 01:42:46 -07001604 for catalog in catalogs:
sousaedu2ad85172021-02-17 15:05:18 +01001605 catalog_id = catalog.get("id")
1606
bayramovb6ffe792016-09-28 11:50:56 +04001607 if catalog_id == catalog_uuid:
sousaedu2ad85172021-02-17 15:05:18 +01001608 return catalog.get("name")
1609
bayramov325fa1c2016-09-08 01:42:46 -07001610 return None
1611
bhangare06312472017-03-30 05:49:07 -07001612 def get_catalog_obj(self, catalog_uuid=None, catalogs=None):
sousaedu2ad85172021-02-17 15:05:18 +01001613 """Method check catalog and return catalog name lookup done by catalog UUID.
bhangare06312472017-03-30 05:49:07 -07001614
1615 Args
1616 catalog_name: catalog name as string
1617 catalogs: list of catalogs.
1618
1619 Return: catalogs name or None
1620 """
bhangare06312472017-03-30 05:49:07 -07001621 if not self.validate_uuid4(uuid_string=catalog_uuid):
1622 return None
1623
1624 for catalog in catalogs:
sousaedu2ad85172021-02-17 15:05:18 +01001625 catalog_id = catalog.get("id")
1626
bhangare06312472017-03-30 05:49:07 -07001627 if catalog_id == catalog_uuid:
1628 return catalog
sousaedu2ad85172021-02-17 15:05:18 +01001629
bhangare06312472017-03-30 05:49:07 -07001630 return None
1631
bayramovfe3f3c92016-10-04 07:53:41 +04001632 def get_image_id_from_path(self, path=None, progress=False):
sousaedu2ad85172021-02-17 15:05:18 +01001633 """Method upload OVF image to vCloud director.
bayramov325fa1c2016-09-08 01:42:46 -07001634
bayramovb6ffe792016-09-28 11:50:56 +04001635 Each OVF image represented as single catalog entry in vcloud director.
1636 The method check for existing catalog entry. The check done by file name without file extension.
1637
1638 if given catalog name already present method will respond with existing catalog uuid otherwise
1639 it will create new catalog entry and upload OVF file to newly created catalog.
1640
1641 If method can't create catalog entry or upload a file it will throw exception.
1642
bayramovfe3f3c92016-10-04 07:53:41 +04001643 Method accept boolean flag progress that will output progress bar. It useful method
1644 for standalone upload use case. In case to test large file upload.
1645
bayramovb6ffe792016-09-28 11:50:56 +04001646 Args
bayramovfe3f3c92016-10-04 07:53:41 +04001647 path: - valid path to OVF file.
1648 progress - boolean progress bar show progress bar.
bayramovb6ffe792016-09-28 11:50:56 +04001649
1650 Return: if image uploaded correct method will provide image catalog UUID.
1651 """
kate15f1c382016-12-15 01:12:40 -08001652 if not path:
tierno72774862020-05-04 11:44:15 +00001653 raise vimconn.VimConnException("Image path can't be None.")
bayramovfe3f3c92016-10-04 07:53:41 +04001654
1655 if not os.path.isfile(path):
tierno72774862020-05-04 11:44:15 +00001656 raise vimconn.VimConnException("Can't read file. File not found.")
bayramovfe3f3c92016-10-04 07:53:41 +04001657
1658 if not os.access(path, os.R_OK):
sousaedu2ad85172021-02-17 15:05:18 +01001659 raise vimconn.VimConnException(
1660 "Can't read file. Check file permission to read."
1661 )
bayramovfe3f3c92016-10-04 07:53:41 +04001662
1663 self.logger.debug("get_image_id_from_path() client requesting {} ".format(path))
bayramov325fa1c2016-09-08 01:42:46 -07001664
beierlb22ce2d2019-12-12 12:09:51 -05001665 _, filename = os.path.split(path)
1666 _, file_extension = os.path.splitext(path)
sousaedu2ad85172021-02-17 15:05:18 +01001667 if file_extension != ".ovf":
1668 self.logger.debug(
1669 "Wrong file extension {} connector support only OVF container.".format(
1670 file_extension
1671 )
1672 )
1673
1674 raise vimconn.VimConnException(
1675 "Wrong container. vCloud director supports only OVF."
1676 )
kate15f1c382016-12-15 01:12:40 -08001677
bayramov325fa1c2016-09-08 01:42:46 -07001678 catalog_name = os.path.splitext(filename)[0]
sousaedu2ad85172021-02-17 15:05:18 +01001679 catalog_md5_name = hashlib.md5(path.encode("utf-8")).hexdigest()
1680 self.logger.debug(
1681 "File name {} Catalog Name {} file path {} "
1682 "vdc catalog name {}".format(filename, catalog_name, path, catalog_md5_name)
1683 )
bayramov325fa1c2016-09-08 01:42:46 -07001684
bhangarebfdca492017-03-11 01:32:46 -08001685 try:
beierlb22ce2d2019-12-12 12:09:51 -05001686 org, _ = self.get_vdc_details()
kasarc5bf2932018-03-09 04:15:22 -08001687 catalogs = org.list_catalogs()
bhangarebfdca492017-03-11 01:32:46 -08001688 except Exception as exp:
1689 self.logger.debug("Failed get catalogs() with Exception {} ".format(exp))
sousaedu2ad85172021-02-17 15:05:18 +01001690
1691 raise vimconn.VimConnException(
1692 "Failed get catalogs() with Exception {} ".format(exp)
1693 )
bhangarebfdca492017-03-11 01:32:46 -08001694
bayramov325fa1c2016-09-08 01:42:46 -07001695 if len(catalogs) == 0:
sousaedu2ad85172021-02-17 15:05:18 +01001696 self.logger.info(
1697 "Creating a new catalog entry {} in vcloud director".format(
1698 catalog_name
1699 )
1700 )
kasarc5bf2932018-03-09 04:15:22 -08001701
sousaedu2ad85172021-02-17 15:05:18 +01001702 if self.create_vimcatalog(org, catalog_md5_name) is None:
1703 raise vimconn.VimConnException(
1704 "Failed create new catalog {} ".format(catalog_md5_name)
1705 )
1706
1707 result = self.upload_vimimage(
1708 vca=org,
1709 catalog_name=catalog_md5_name,
1710 media_name=filename,
1711 medial_file_name=path,
1712 progress=progress,
1713 )
1714
bayramov325fa1c2016-09-08 01:42:46 -07001715 if not result:
sousaedu2ad85172021-02-17 15:05:18 +01001716 raise vimconn.VimConnException(
1717 "Failed create vApp template for catalog {} ".format(catalog_name)
1718 )
1719
kasarc5bf2932018-03-09 04:15:22 -08001720 return self.get_catalogid(catalog_name, catalogs)
bayramov325fa1c2016-09-08 01:42:46 -07001721 else:
1722 for catalog in catalogs:
1723 # search for existing catalog if we find same name we return ID
1724 # TODO optimize this
sousaedu2ad85172021-02-17 15:05:18 +01001725 if catalog["name"] == catalog_md5_name:
1726 self.logger.debug(
1727 "Found existing catalog entry for {} "
1728 "catalog id {}".format(
1729 catalog_name, self.get_catalogid(catalog_md5_name, catalogs)
1730 )
1731 )
1732
kasarc5bf2932018-03-09 04:15:22 -08001733 return self.get_catalogid(catalog_md5_name, catalogs)
bayramov325fa1c2016-09-08 01:42:46 -07001734
bayramovfe3f3c92016-10-04 07:53:41 +04001735 # if we didn't find existing catalog we create a new one and upload image.
sousaedu2ad85172021-02-17 15:05:18 +01001736 self.logger.debug(
1737 "Creating new catalog entry {} - {}".format(catalog_name, catalog_md5_name)
1738 )
Ananda Baitharu319c26f2019-03-05 17:34:31 +00001739 if self.create_vimcatalog(org, catalog_md5_name) is None:
sousaedu2ad85172021-02-17 15:05:18 +01001740 raise vimconn.VimConnException(
1741 "Failed create new catalog {} ".format(catalog_md5_name)
1742 )
bayramovfe3f3c92016-10-04 07:53:41 +04001743
sousaedu2ad85172021-02-17 15:05:18 +01001744 result = self.upload_vimimage(
1745 vca=org,
1746 catalog_name=catalog_md5_name,
1747 media_name=filename,
1748 medial_file_name=path,
1749 progress=progress,
1750 )
bayramov325fa1c2016-09-08 01:42:46 -07001751 if not result:
sousaedu2ad85172021-02-17 15:05:18 +01001752 raise vimconn.VimConnException(
1753 "Failed create vApp template for catalog {} ".format(catalog_md5_name)
1754 )
bayramov325fa1c2016-09-08 01:42:46 -07001755
kasarc5bf2932018-03-09 04:15:22 -08001756 return self.get_catalogid(catalog_md5_name, org.list_catalogs())
bayramov325fa1c2016-09-08 01:42:46 -07001757
kate8fc61fc2017-01-23 19:57:06 -08001758 def get_image_list(self, filter_dict={}):
sousaedu2ad85172021-02-17 15:05:18 +01001759 """Obtain tenant images from VIM
kate8fc61fc2017-01-23 19:57:06 -08001760 Filter_dict can be:
1761 name: image name
1762 id: image uuid
1763 checksum: image checksum
1764 location: image path
1765 Returns the image list of dictionaries:
1766 [{<the fields at Filter_dict plus some VIM specific>}, ...]
1767 List can be empty
sousaedu2ad85172021-02-17 15:05:18 +01001768 """
kate8fc61fc2017-01-23 19:57:06 -08001769 try:
beierlb22ce2d2019-12-12 12:09:51 -05001770 org, _ = self.get_vdc_details()
kate8fc61fc2017-01-23 19:57:06 -08001771 image_list = []
kasarc5bf2932018-03-09 04:15:22 -08001772 catalogs = org.list_catalogs()
sousaedu2ad85172021-02-17 15:05:18 +01001773
kate8fc61fc2017-01-23 19:57:06 -08001774 if len(catalogs) == 0:
1775 return image_list
1776 else:
1777 for catalog in catalogs:
sousaedu2ad85172021-02-17 15:05:18 +01001778 catalog_uuid = catalog.get("id")
1779 name = catalog.get("name")
kate8fc61fc2017-01-23 19:57:06 -08001780 filtered_dict = {}
sousaedu2ad85172021-02-17 15:05:18 +01001781
kate34718682017-01-24 03:20:43 -08001782 if filter_dict.get("name") and filter_dict["name"] != name:
1783 continue
sousaedu2ad85172021-02-17 15:05:18 +01001784
kate34718682017-01-24 03:20:43 -08001785 if filter_dict.get("id") and filter_dict["id"] != catalog_uuid:
1786 continue
sousaedu2ad85172021-02-17 15:05:18 +01001787
beierlb22ce2d2019-12-12 12:09:51 -05001788 filtered_dict["name"] = name
1789 filtered_dict["id"] = catalog_uuid
kate34718682017-01-24 03:20:43 -08001790 image_list.append(filtered_dict)
kate8fc61fc2017-01-23 19:57:06 -08001791
sousaedu2ad85172021-02-17 15:05:18 +01001792 self.logger.debug(
1793 "List of already created catalog items: {}".format(image_list)
1794 )
1795
kate8fc61fc2017-01-23 19:57:06 -08001796 return image_list
1797 except Exception as exp:
sousaedu2ad85172021-02-17 15:05:18 +01001798 raise vimconn.VimConnException(
1799 "Exception occured while retriving catalog items {}".format(exp)
1800 )
kate8fc61fc2017-01-23 19:57:06 -08001801
bayramovef390722016-09-27 03:34:46 -07001802 def get_vappid(self, vdc=None, vapp_name=None):
sousaedu2ad85172021-02-17 15:05:18 +01001803 """Method takes vdc object and vApp name and returns vapp uuid or None
bayramovef390722016-09-27 03:34:46 -07001804
1805 Args:
bayramovef390722016-09-27 03:34:46 -07001806 vdc: The VDC object.
1807 vapp_name: is application vappp name identifier
1808
bayramovb6ffe792016-09-28 11:50:56 +04001809 Returns:
bayramovef390722016-09-27 03:34:46 -07001810 The return vApp name otherwise None
1811 """
bayramovef390722016-09-27 03:34:46 -07001812 if vdc is None or vapp_name is None:
1813 return None
sousaedu2ad85172021-02-17 15:05:18 +01001814
bayramovef390722016-09-27 03:34:46 -07001815 # UUID has following format https://host/api/vApp/vapp-30da58a3-e7c7-4d09-8f68-d4c8201169cf
bayramov325fa1c2016-09-08 01:42:46 -07001816 try:
sousaedu2ad85172021-02-17 15:05:18 +01001817 refs = [
1818 ref
1819 for ref in vdc.ResourceEntities.ResourceEntity
1820 if ref.name == vapp_name
1821 and ref.type_ == "application/vnd.vmware.vcloud.vApp+xml"
1822 ]
1823
bayramov325fa1c2016-09-08 01:42:46 -07001824 if len(refs) == 1:
1825 return refs[0].href.split("vapp")[1][1:]
bayramovef390722016-09-27 03:34:46 -07001826 except Exception as e:
1827 self.logger.exception(e)
1828 return False
sousaedu2ad85172021-02-17 15:05:18 +01001829
bayramovef390722016-09-27 03:34:46 -07001830 return None
1831
bayramovfe3f3c92016-10-04 07:53:41 +04001832 def check_vapp(self, vdc=None, vapp_uuid=None):
sousaedu2ad85172021-02-17 15:05:18 +01001833 """Method Method returns True or False if vapp deployed in vCloud director
bayramovef390722016-09-27 03:34:46 -07001834
sousaedu2ad85172021-02-17 15:05:18 +01001835 Args:
1836 vca: Connector to VCA
1837 vdc: The VDC object.
1838 vappid: vappid is application identifier
bayramovef390722016-09-27 03:34:46 -07001839
sousaedu2ad85172021-02-17 15:05:18 +01001840 Returns:
1841 The return True if vApp deployed
1842 :param vdc:
1843 :param vapp_uuid:
bayramovef390722016-09-27 03:34:46 -07001844 """
1845 try:
sousaedu2ad85172021-02-17 15:05:18 +01001846 refs = [
1847 ref
1848 for ref in vdc.ResourceEntities.ResourceEntity
1849 if ref.type_ == "application/vnd.vmware.vcloud.vApp+xml"
1850 ]
1851
bayramovef390722016-09-27 03:34:46 -07001852 for ref in refs:
1853 vappid = ref.href.split("vapp")[1][1:]
1854 # find vapp with respected vapp uuid
sousaedu2ad85172021-02-17 15:05:18 +01001855
bayramovfe3f3c92016-10-04 07:53:41 +04001856 if vappid == vapp_uuid:
bayramovef390722016-09-27 03:34:46 -07001857 return True
1858 except Exception as e:
1859 self.logger.exception(e)
sousaedu2ad85172021-02-17 15:05:18 +01001860
bayramovef390722016-09-27 03:34:46 -07001861 return False
sousaedu2ad85172021-02-17 15:05:18 +01001862
bayramovef390722016-09-27 03:34:46 -07001863 return False
1864
kasarc5bf2932018-03-09 04:15:22 -08001865 def get_namebyvappid(self, vapp_uuid=None):
bayramovef390722016-09-27 03:34:46 -07001866 """Method returns vApp name from vCD and lookup done by vapp_id.
1867
1868 Args:
bayramovfe3f3c92016-10-04 07:53:41 +04001869 vapp_uuid: vappid is application identifier
bayramovef390722016-09-27 03:34:46 -07001870
1871 Returns:
1872 The return vApp name otherwise None
1873 """
bayramovef390722016-09-27 03:34:46 -07001874 try:
kasarc5bf2932018-03-09 04:15:22 -08001875 if self.client and vapp_uuid:
1876 vapp_call = "{}/api/vApp/vapp-{}".format(self.url, vapp_uuid)
sousaedu2ad85172021-02-17 15:05:18 +01001877 headers = {
1878 "Accept": "application/*+xml;version=" + API_VERSION,
1879 "x-vcloud-authorization": self.client._session.headers[
1880 "x-vcloud-authorization"
1881 ],
1882 }
bhangare1a0b97c2017-06-21 02:20:15 -07001883
sousaedu2ad85172021-02-17 15:05:18 +01001884 response = self.perform_request(
1885 req_type="GET", url=vapp_call, headers=headers
1886 )
1887
beierlb22ce2d2019-12-12 12:09:51 -05001888 # Retry login if session expired & retry sending request
kasarc5bf2932018-03-09 04:15:22 -08001889 if response.status_code == 403:
sousaedu2ad85172021-02-17 15:05:18 +01001890 response = self.retry_rest("GET", vapp_call)
bhangare1a0b97c2017-06-21 02:20:15 -07001891
beierl26fec002019-12-06 17:06:40 -05001892 tree = XmlElementTree.fromstring(response.text)
sousaedu2ad85172021-02-17 15:05:18 +01001893
1894 return tree.attrib["name"] if "name" in tree.attrib else None
bayramovef390722016-09-27 03:34:46 -07001895 except Exception as e:
1896 self.logger.exception(e)
sousaedu2ad85172021-02-17 15:05:18 +01001897
bayramov325fa1c2016-09-08 01:42:46 -07001898 return None
sousaedu2ad85172021-02-17 15:05:18 +01001899
bayramov325fa1c2016-09-08 01:42:46 -07001900 return None
1901
sousaedu2ad85172021-02-17 15:05:18 +01001902 def new_vminstance(
1903 self,
1904 name=None,
1905 description="",
1906 start=False,
1907 image_id=None,
1908 flavor_id=None,
1909 net_list=[],
1910 cloud_config=None,
1911 disk_list=None,
1912 availability_zone_index=None,
1913 availability_zone_list=None,
1914 ):
bayramov325fa1c2016-09-08 01:42:46 -07001915 """Adds a VM instance to VIM
1916 Params:
tierno19860412017-10-03 10:46:46 +02001917 'start': (boolean) indicates if VM must start or created in pause mode.
1918 'image_id','flavor_id': image and flavor VIM id to use for the VM
1919 'net_list': list of interfaces, each one is a dictionary with:
1920 'name': (optional) name for the interface.
1921 'net_id': VIM network id where this interface must be connect to. Mandatory for type==virtual
beierlb22ce2d2019-12-12 12:09:51 -05001922 'vpci': (optional) virtual vPCI address to assign at the VM. Can be ignored depending on VIM
1923 capabilities
garciadeblasc4f4d732018-10-25 18:17:24 +02001924 'model': (optional and only have sense for type==virtual) interface model: virtio, e1000, ...
tierno19860412017-10-03 10:46:46 +02001925 'mac_address': (optional) mac address to assign to this interface
beierlb22ce2d2019-12-12 12:09:51 -05001926 #TODO: CHECK if an optional 'vlan' parameter is needed for VIMs when type if VF and net_id is not
1927 provided, the VLAN tag to be used. In case net_id is provided, the internal network vlan is used
1928 for tagging VF
tierno19860412017-10-03 10:46:46 +02001929 'type': (mandatory) can be one of:
1930 'virtual', in this case always connected to a network of type 'net_type=bridge'
beierlb22ce2d2019-12-12 12:09:51 -05001931 'PCI-PASSTHROUGH' or 'PF' (passthrough): depending on VIM capabilities it can be connected to a
1932 data/ptp network or it can created unconnected
tierno66eba6e2017-11-10 17:09:18 +01001933 'SR-IOV' or 'VF' (SRIOV with VLAN tag): same as PF for network connectivity.
tierno19860412017-10-03 10:46:46 +02001934 'VFnotShared'(SRIOV without VLAN tag) same as PF for network connectivity. VF where no other VFs
1935 are allocated on the same physical NIC
1936 'bw': (optional) only for PF/VF/VFnotShared. Minimal Bandwidth required for the interface in GBPS
1937 'port_security': (optional) If False it must avoid any traffic filtering at this interface. If missing
1938 or True, it must apply the default VIM behaviour
1939 After execution the method will add the key:
1940 'vim_id': must be filled/added by this method with the VIM identifier generated by the VIM for this
1941 interface. 'net_list' is modified
1942 'cloud_config': (optional) dictionary with:
1943 'key-pairs': (optional) list of strings with the public key to be inserted to the default user
1944 'users': (optional) list of users to be inserted, each item is a dict with:
1945 'name': (mandatory) user name,
1946 'key-pairs': (optional) list of strings with the public key to be inserted to the user
1947 'user-data': (optional) can be a string with the text script to be passed directly to cloud-init,
1948 or a list of strings, each one contains a script to be passed, usually with a MIMEmultipart file
1949 'config-files': (optional). List of files to be transferred. Each item is a dict with:
1950 'dest': (mandatory) string with the destination absolute path
1951 'encoding': (optional, by default text). Can be one of:
1952 'b64', 'base64', 'gz', 'gz+b64', 'gz+base64', 'gzip+b64', 'gzip+base64'
1953 'content' (mandatory): string with the content of the file
1954 'permissions': (optional) string with file permissions, typically octal notation '0644'
1955 'owner': (optional) file owner, string with the format 'owner:group'
1956 'boot-data-drive': boolean to indicate if user-data must be passed using a boot drive (hard disk)
1957 'disk_list': (optional) list with additional disks to the VM. Each item is a dict with:
1958 'image_id': (optional). VIM id of an existing image. If not provided an empty disk must be mounted
1959 'size': (mandatory) string with the size of the disk in GB
1960 availability_zone_index: Index of availability_zone_list to use for this this VM. None if not AV required
1961 availability_zone_list: list of availability zones given by user in the VNFD descriptor. Ignore if
1962 availability_zone_index is None
tierno98e909c2017-10-14 13:27:03 +02001963 Returns a tuple with the instance identifier and created_items or raises an exception on error
1964 created_items can be None or a dictionary where this method can include key-values that will be passed to
1965 the method delete_vminstance and action_vminstance. Can be used to store created ports, volumes, etc.
1966 Format is vimconnector dependent, but do not use nested dictionaries and a value of None should be the same
1967 as not present.
bayramov325fa1c2016-09-08 01:42:46 -07001968 """
kate15f1c382016-12-15 01:12:40 -08001969 self.logger.info("Creating new instance for entry {}".format(name))
sousaedu2ad85172021-02-17 15:05:18 +01001970 self.logger.debug(
1971 "desc {} boot {} image_id: {} flavor_id: {} net_list: {} cloud_config {} disk_list {} "
1972 "availability_zone_index {} availability_zone_list {}".format(
1973 description,
1974 start,
1975 image_id,
1976 flavor_id,
1977 net_list,
1978 cloud_config,
1979 disk_list,
1980 availability_zone_index,
1981 availability_zone_list,
1982 )
1983 )
bayramov325fa1c2016-09-08 01:42:46 -07001984
beierlb22ce2d2019-12-12 12:09:51 -05001985 # new vm name = vmname + tenant_id + uuid
sousaedu2ad85172021-02-17 15:05:18 +01001986 new_vm_name = [name, "-", str(uuid.uuid4())]
1987 vmname_andid = "".join(new_vm_name)
bayramov5761ad12016-10-04 09:00:30 +04001988
kasarc5bf2932018-03-09 04:15:22 -08001989 for net in net_list:
sousaedu2ad85172021-02-17 15:05:18 +01001990 if net["type"] == "PCI-PASSTHROUGH":
tierno72774862020-05-04 11:44:15 +00001991 raise vimconn.VimConnNotSupportedException(
sousaedu2ad85172021-02-17 15:05:18 +01001992 "Current vCD version does not support type : {}".format(net["type"])
1993 )
bayramov325fa1c2016-09-08 01:42:46 -07001994
kasarc5bf2932018-03-09 04:15:22 -08001995 if len(net_list) > 10:
tierno72774862020-05-04 11:44:15 +00001996 raise vimconn.VimConnNotSupportedException(
sousaedu2ad85172021-02-17 15:05:18 +01001997 "The VM hardware versions 7 and above support upto 10 NICs only"
1998 )
kasarc5bf2932018-03-09 04:15:22 -08001999
2000 # if vm already deployed we return existing uuid
bayramovef390722016-09-27 03:34:46 -07002001 # we check for presence of VDC, Catalog entry and Flavor.
kasarc5bf2932018-03-09 04:15:22 -08002002 org, vdc = self.get_vdc_details()
bayramovef390722016-09-27 03:34:46 -07002003 if vdc is None:
tierno72774862020-05-04 11:44:15 +00002004 raise vimconn.VimConnNotFoundException(
sousaedu2ad85172021-02-17 15:05:18 +01002005 "new_vminstance(): Failed create vApp {}: (Failed retrieve VDC information)".format(
2006 name
2007 )
2008 )
2009
kasarc5bf2932018-03-09 04:15:22 -08002010 catalogs = org.list_catalogs()
bhangare1a0b97c2017-06-21 02:20:15 -07002011 if catalogs is None:
beierlb22ce2d2019-12-12 12:09:51 -05002012 # Retry once, if failed by refreshing token
bhangare1a0b97c2017-06-21 02:20:15 -07002013 self.get_token()
kasarc5bf2932018-03-09 04:15:22 -08002014 org = Org(self.client, resource=self.client.get_org())
2015 catalogs = org.list_catalogs()
sousaedu2ad85172021-02-17 15:05:18 +01002016
bayramovef390722016-09-27 03:34:46 -07002017 if catalogs is None:
tierno72774862020-05-04 11:44:15 +00002018 raise vimconn.VimConnNotFoundException(
sousaedu2ad85172021-02-17 15:05:18 +01002019 "new_vminstance(): Failed create vApp {}: (Failed retrieve catalogs list)".format(
2020 name
2021 )
2022 )
bayramovbd6160f2016-09-28 04:12:05 +04002023
sousaedu2ad85172021-02-17 15:05:18 +01002024 catalog_hash_name = self.get_catalogbyid(
2025 catalog_uuid=image_id, catalogs=catalogs
2026 )
kate15f1c382016-12-15 01:12:40 -08002027 if catalog_hash_name:
sousaedu2ad85172021-02-17 15:05:18 +01002028 self.logger.info(
2029 "Found catalog entry {} for image id {}".format(
2030 catalog_hash_name, image_id
2031 )
2032 )
kate15f1c382016-12-15 01:12:40 -08002033 else:
sousaedu2ad85172021-02-17 15:05:18 +01002034 raise vimconn.VimConnNotFoundException(
2035 "new_vminstance(): Failed create vApp {}: "
2036 "(Failed retrieve catalog information {})".format(name, image_id)
2037 )
kate15f1c382016-12-15 01:12:40 -08002038
kate15f1c382016-12-15 01:12:40 -08002039 # Set vCPU and Memory based on flavor.
bayramovb6ffe792016-09-28 11:50:56 +04002040 vm_cpus = None
2041 vm_memory = None
bhangarea92ae392017-01-12 22:30:29 -08002042 vm_disk = None
bhangare68e73e62017-07-04 22:44:01 -07002043 numas = None
kateac1e3792017-04-01 02:16:39 -07002044
bayramovb6ffe792016-09-28 11:50:56 +04002045 if flavor_id is not None:
kateeb044522017-03-06 23:54:39 -08002046 if flavor_id not in vimconnector.flavorlist:
sousaedu2ad85172021-02-17 15:05:18 +01002047 raise vimconn.VimConnNotFoundException(
2048 "new_vminstance(): Failed create vApp {}: "
2049 "Failed retrieve flavor information "
2050 "flavor id {}".format(name, flavor_id)
2051 )
bayramovb6ffe792016-09-28 11:50:56 +04002052 else:
2053 try:
kateeb044522017-03-06 23:54:39 -08002054 flavor = vimconnector.flavorlist[flavor_id]
kate15f1c382016-12-15 01:12:40 -08002055 vm_cpus = flavor[FLAVOR_VCPUS_KEY]
2056 vm_memory = flavor[FLAVOR_RAM_KEY]
bhangarea92ae392017-01-12 22:30:29 -08002057 vm_disk = flavor[FLAVOR_DISK_KEY]
bhangarefda5f7c2017-01-12 23:50:34 -08002058 extended = flavor.get("extended", None)
sousaedu2ad85172021-02-17 15:05:18 +01002059
bhangarefda5f7c2017-01-12 23:50:34 -08002060 if extended:
beierlb22ce2d2019-12-12 12:09:51 -05002061 numas = extended.get("numas", None)
kateeb044522017-03-06 23:54:39 -08002062 except Exception as exp:
sousaedu2ad85172021-02-17 15:05:18 +01002063 raise vimconn.VimConnException(
2064 "Corrupted flavor. {}.Exception: {}".format(flavor_id, exp)
2065 )
bayramov325fa1c2016-09-08 01:42:46 -07002066
bayramovef390722016-09-27 03:34:46 -07002067 # image upload creates template name as catalog name space Template.
kate15f1c382016-12-15 01:12:40 -08002068 templateName = self.get_catalogbyid(catalog_uuid=image_id, catalogs=catalogs)
beierlb22ce2d2019-12-12 12:09:51 -05002069 # power_on = 'false'
2070 # if start:
2071 # power_on = 'true'
bayramovef390722016-09-27 03:34:46 -07002072
2073 # client must provide at least one entry in net_list if not we report error
beierlb22ce2d2019-12-12 12:09:51 -05002074 # If net type is mgmt, then configure it as primary net & use its NIC index as primary NIC
beierl26fec002019-12-06 17:06:40 -05002075 # If no mgmt, then the 1st NN in netlist is considered as primary net.
bhangare0e571a92017-01-12 04:02:23 -08002076 primary_net = None
kate15f1c382016-12-15 01:12:40 -08002077 primary_netname = None
Ravi Chamarty1fdf9992018-10-07 15:45:44 +00002078 primary_net_href = None
beierlb22ce2d2019-12-12 12:09:51 -05002079 # network_mode = 'bridged'
bayramovb6ffe792016-09-28 11:50:56 +04002080 if net_list is not None and len(net_list) > 0:
bhangare0e571a92017-01-12 04:02:23 -08002081 for net in net_list:
sousaedu2ad85172021-02-17 15:05:18 +01002082 if "use" in net and net["use"] == "mgmt" and not primary_net:
bhangare0e571a92017-01-12 04:02:23 -08002083 primary_net = net
sousaedu2ad85172021-02-17 15:05:18 +01002084
bayramovb6ffe792016-09-28 11:50:56 +04002085 if primary_net is None:
bhangare0e571a92017-01-12 04:02:23 -08002086 primary_net = net_list[0]
2087
2088 try:
sousaedu2ad85172021-02-17 15:05:18 +01002089 primary_net_id = primary_net["net_id"]
2090 url_list = [self.url, "/api/network/", primary_net_id]
2091 primary_net_href = "".join(url_list)
bhangare0e571a92017-01-12 04:02:23 -08002092 network_dict = self.get_vcd_network(network_uuid=primary_net_id)
bhangare0e571a92017-01-12 04:02:23 -08002093
sousaedu2ad85172021-02-17 15:05:18 +01002094 if "name" in network_dict:
2095 primary_netname = network_dict["name"]
bhangare0e571a92017-01-12 04:02:23 -08002096 except KeyError:
sousaedu2ad85172021-02-17 15:05:18 +01002097 raise vimconn.VimConnException(
2098 "Corrupted flavor. {}".format(primary_net)
2099 )
bhangare0e571a92017-01-12 04:02:23 -08002100 else:
sousaedu2ad85172021-02-17 15:05:18 +01002101 raise vimconn.VimConnUnexpectedResponse(
2102 "new_vminstance(): Failed network list is empty."
2103 )
bayramovef390722016-09-27 03:34:46 -07002104
2105 # use: 'data', 'bridge', 'mgmt'
2106 # create vApp. Set vcpu and ram based on flavor id.
bhangarebfdca492017-03-11 01:32:46 -08002107 try:
kasarc5bf2932018-03-09 04:15:22 -08002108 vdc_obj = VDC(self.client, resource=org.get_vdc(self.tenant_name))
2109 if not vdc_obj:
sousaedu2ad85172021-02-17 15:05:18 +01002110 raise vimconn.VimConnNotFoundException(
2111 "new_vminstance(): Failed to get VDC object"
2112 )
bhangare1a0b97c2017-06-21 02:20:15 -07002113
beierl26fec002019-12-06 17:06:40 -05002114 for retry in (1, 2):
kasarc5bf2932018-03-09 04:15:22 -08002115 items = org.get_catalog_item(catalog_hash_name, catalog_hash_name)
2116 catalog_items = [items.attrib]
2117
2118 if len(catalog_items) == 1:
2119 if self.client:
sousaedu2ad85172021-02-17 15:05:18 +01002120 headers = {
2121 "Accept": "application/*+xml;version=" + API_VERSION,
2122 "x-vcloud-authorization": self.client._session.headers[
2123 "x-vcloud-authorization"
2124 ],
2125 }
kasarc5bf2932018-03-09 04:15:22 -08002126
sousaedu2ad85172021-02-17 15:05:18 +01002127 response = self.perform_request(
2128 req_type="GET",
2129 url=catalog_items[0].get("href"),
2130 headers=headers,
2131 )
beierl26fec002019-12-06 17:06:40 -05002132 catalogItem = XmlElementTree.fromstring(response.text)
sousaedu2ad85172021-02-17 15:05:18 +01002133 entity = [
2134 child
2135 for child in catalogItem
2136 if child.get("type")
2137 == "application/vnd.vmware.vcloud.vAppTemplate+xml"
2138 ][0]
kasarc5bf2932018-03-09 04:15:22 -08002139 vapp_tempalte_href = entity.get("href")
sbhangarea8e5b782018-06-21 02:10:03 -07002140
sousaedu2ad85172021-02-17 15:05:18 +01002141 response = self.perform_request(
2142 req_type="GET", url=vapp_tempalte_href, headers=headers
2143 )
2144
kasarc5bf2932018-03-09 04:15:22 -08002145 if response.status_code != requests.codes.ok:
sousaedu2ad85172021-02-17 15:05:18 +01002146 self.logger.debug(
2147 "REST API call {} failed. Return status code {}".format(
2148 vapp_tempalte_href, response.status_code
2149 )
2150 )
kasarc5bf2932018-03-09 04:15:22 -08002151 else:
beierl26fec002019-12-06 17:06:40 -05002152 result = (response.text).replace("\n", " ")
kasarc5bf2932018-03-09 04:15:22 -08002153
beierl26fec002019-12-06 17:06:40 -05002154 vapp_template_tree = XmlElementTree.fromstring(response.text)
sousaedu2ad85172021-02-17 15:05:18 +01002155 children_element = [
2156 child for child in vapp_template_tree if "Children" in child.tag
2157 ][0]
2158 vm_element = [child for child in children_element if "Vm" in child.tag][
2159 0
2160 ]
2161 vm_name = vm_element.get("name")
2162 vm_id = vm_element.get("id")
2163 vm_href = vm_element.get("href")
kasarc5bf2932018-03-09 04:15:22 -08002164
beierlb22ce2d2019-12-12 12:09:51 -05002165 # cpus = re.search('<rasd:Description>Number of Virtual CPUs</.*?>(\d+)</rasd:VirtualQuantity>',
2166 # result).group(1)
sousaedu2ad85172021-02-17 15:05:18 +01002167 memory_mb = re.search(
2168 "<rasd:Description>Memory Size</.*?>(\d+)</rasd:VirtualQuantity>",
2169 result,
2170 ).group(1)
beierlb22ce2d2019-12-12 12:09:51 -05002171 # cores = re.search('<vmw:CoresPerSocket ovf:required.*?>(\d+)</vmw:CoresPerSocket>', result).group(1)
kasarc5bf2932018-03-09 04:15:22 -08002172
sousaedu2ad85172021-02-17 15:05:18 +01002173 headers[
2174 "Content-Type"
2175 ] = "application/vnd.vmware.vcloud.instantiateVAppTemplateParams+xml"
2176 vdc_id = vdc.get("id").split(":")[-1]
2177 instantiate_vapp_href = (
2178 "{}/api/vdc/{}/action/instantiateVAppTemplate".format(
2179 self.url, vdc_id
2180 )
2181 )
2182
2183 with open(
2184 os.path.join(
2185 os.path.dirname(__file__), "InstantiateVAppTemplateParams.xml"
2186 ),
2187 "r",
2188 ) as f:
beierl26fec002019-12-06 17:06:40 -05002189 template = f.read()
2190
sousaedu2ad85172021-02-17 15:05:18 +01002191 data = template.format(
2192 vmname_andid,
2193 primary_netname,
2194 primary_net_href,
2195 vapp_tempalte_href,
2196 vm_href,
2197 vm_id,
2198 vm_name,
2199 primary_netname,
2200 cpu=vm_cpus,
2201 core=1,
2202 memory=vm_memory,
2203 )
kasarc5bf2932018-03-09 04:15:22 -08002204
sousaedu2ad85172021-02-17 15:05:18 +01002205 response = self.perform_request(
2206 req_type="POST",
2207 url=instantiate_vapp_href,
2208 headers=headers,
2209 data=data,
2210 )
kasarc5bf2932018-03-09 04:15:22 -08002211
2212 if response.status_code != 201:
sousaedu2ad85172021-02-17 15:05:18 +01002213 self.logger.error(
2214 "REST call {} failed reason : {}"
2215 "status code : {}".format(
2216 instantiate_vapp_href, response.text, response.status_code
2217 )
2218 )
2219 raise vimconn.VimConnException(
2220 "new_vminstance(): Failed to create"
2221 "vAapp {}".format(vmname_andid)
2222 )
kasarc5bf2932018-03-09 04:15:22 -08002223 else:
beierl26fec002019-12-06 17:06:40 -05002224 vapptask = self.get_task_from_response(response.text)
kasarc5bf2932018-03-09 04:15:22 -08002225
beierlb22ce2d2019-12-12 12:09:51 -05002226 if vapptask is None and retry == 1:
2227 self.get_token() # Retry getting token
bhangare68e73e62017-07-04 22:44:01 -07002228 continue
2229 else:
2230 break
2231
bhangare1a0b97c2017-06-21 02:20:15 -07002232 if vapptask is None or vapptask is False:
tierno72774862020-05-04 11:44:15 +00002233 raise vimconn.VimConnUnexpectedResponse(
sousaedu2ad85172021-02-17 15:05:18 +01002234 "new_vminstance(): failed to create vApp {}".format(vmname_andid)
2235 )
kasarc5bf2932018-03-09 04:15:22 -08002236
sbhangarea8e5b782018-06-21 02:10:03 -07002237 # wait for task to complete
kasarc5bf2932018-03-09 04:15:22 -08002238 result = self.client.get_task_monitor().wait_for_success(task=vapptask)
2239
sousaedu2ad85172021-02-17 15:05:18 +01002240 if result.get("status") == "success":
2241 self.logger.debug(
2242 "new_vminstance(): Sucessfully created Vapp {}".format(vmname_andid)
2243 )
kasarc5bf2932018-03-09 04:15:22 -08002244 else:
tierno72774862020-05-04 11:44:15 +00002245 raise vimconn.VimConnUnexpectedResponse(
sousaedu2ad85172021-02-17 15:05:18 +01002246 "new_vminstance(): failed to create vApp {}".format(vmname_andid)
2247 )
bhangarebfdca492017-03-11 01:32:46 -08002248 except Exception as exp:
tierno72774862020-05-04 11:44:15 +00002249 raise vimconn.VimConnUnexpectedResponse(
sousaedu2ad85172021-02-17 15:05:18 +01002250 "new_vminstance(): failed to create vApp {} with Exception:{}".format(
2251 vmname_andid, exp
2252 )
2253 )
bayramovef390722016-09-27 03:34:46 -07002254
2255 # we should have now vapp in undeployed state.
bhangarebfdca492017-03-11 01:32:46 -08002256 try:
sousaedu2ad85172021-02-17 15:05:18 +01002257 vdc_obj = VDC(self.client, href=vdc.get("href"))
kasarc5bf2932018-03-09 04:15:22 -08002258 vapp_resource = vdc_obj.get_vapp(vmname_andid)
sousaedu2ad85172021-02-17 15:05:18 +01002259 vapp_uuid = vapp_resource.get("id").split(":")[-1]
kasarc5bf2932018-03-09 04:15:22 -08002260 vapp = VApp(self.client, resource=vapp_resource)
bhangarebfdca492017-03-11 01:32:46 -08002261 except Exception as exp:
tierno72774862020-05-04 11:44:15 +00002262 raise vimconn.VimConnUnexpectedResponse(
sousaedu2ad85172021-02-17 15:05:18 +01002263 "new_vminstance(): Failed to retrieve vApp {} after creation: Exception:{}".format(
2264 vmname_andid, exp
2265 )
2266 )
bhangarebfdca492017-03-11 01:32:46 -08002267
bhangare1a0b97c2017-06-21 02:20:15 -07002268 if vapp_uuid is None:
tierno72774862020-05-04 11:44:15 +00002269 raise vimconn.VimConnUnexpectedResponse(
sousaedu2ad85172021-02-17 15:05:18 +01002270 "new_vminstance(): Failed to retrieve vApp {} after creation".format(
2271 vmname_andid
2272 )
2273 )
bhangarea92ae392017-01-12 22:30:29 -08002274
beierl26fec002019-12-06 17:06:40 -05002275 # Add PCI passthrough/SRIOV configrations
kateac1e3792017-04-01 02:16:39 -07002276 pci_devices_info = []
kateac1e3792017-04-01 02:16:39 -07002277 reserve_memory = False
2278
2279 for net in net_list:
tierno66eba6e2017-11-10 17:09:18 +01002280 if net["type"] == "PF" or net["type"] == "PCI-PASSTHROUGH":
kateac1e3792017-04-01 02:16:39 -07002281 pci_devices_info.append(net)
sousaedu2ad85172021-02-17 15:05:18 +01002282 elif (
2283 net["type"] == "VF"
2284 or net["type"] == "SR-IOV"
2285 or net["type"] == "VFnotShared"
2286 ) and "net_id" in net:
Ravi Chamartye21c9cc2018-10-24 02:14:53 +00002287 reserve_memory = True
kateac1e3792017-04-01 02:16:39 -07002288
beierl26fec002019-12-06 17:06:40 -05002289 # Add PCI
bhangarefda5f7c2017-01-12 23:50:34 -08002290 if len(pci_devices_info) > 0:
sousaedu2ad85172021-02-17 15:05:18 +01002291 self.logger.info(
2292 "Need to add PCI devices {} into VM {}".format(
2293 pci_devices_info, vmname_andid
2294 )
2295 )
2296 PCI_devices_status, _, _ = self.add_pci_devices(
2297 vapp_uuid, pci_devices_info, vmname_andid
2298 )
2299
beierl26fec002019-12-06 17:06:40 -05002300 if PCI_devices_status:
sousaedu2ad85172021-02-17 15:05:18 +01002301 self.logger.info(
2302 "Added PCI devives {} to VM {}".format(
2303 pci_devices_info, vmname_andid
2304 )
2305 )
kateac1e3792017-04-01 02:16:39 -07002306 reserve_memory = True
bhangarefda5f7c2017-01-12 23:50:34 -08002307 else:
sousaedu2ad85172021-02-17 15:05:18 +01002308 self.logger.info(
2309 "Fail to add PCI devives {} to VM {}".format(
2310 pci_devices_info, vmname_andid
2311 )
2312 )
bhangare1a0b97c2017-06-21 02:20:15 -07002313
beierl26fec002019-12-06 17:06:40 -05002314 # Add serial console - this allows cloud images to boot as if we are running under OpenStack
2315 self.add_serial_device(vapp_uuid)
2316
bhangarea92ae392017-01-12 22:30:29 -08002317 if vm_disk:
beierl26fec002019-12-06 17:06:40 -05002318 # Assuming there is only one disk in ovf and fast provisioning in organization vDC is disabled
bhangarea92ae392017-01-12 22:30:29 -08002319 result = self.modify_vm_disk(vapp_uuid, vm_disk)
beierl26fec002019-12-06 17:06:40 -05002320 if result:
bhangarea92ae392017-01-12 22:30:29 -08002321 self.logger.debug("Modified Disk size of VM {} ".format(vmname_andid))
bayramovef390722016-09-27 03:34:46 -07002322
beierlb22ce2d2019-12-12 12:09:51 -05002323 # Add new or existing disks to vApp
bhangare06312472017-03-30 05:49:07 -07002324 if disk_list:
2325 added_existing_disk = False
2326 for disk in disk_list:
sousaedu2ad85172021-02-17 15:05:18 +01002327 if "device_type" in disk and disk["device_type"] == "cdrom":
2328 image_id = disk["image_id"]
kasar0c007d62017-05-19 03:13:57 -07002329 # Adding CD-ROM to VM
2330 # will revisit code once specification ready to support this feature
2331 self.insert_media_to_vm(vapp, image_id)
2332 elif "image_id" in disk and disk["image_id"] is not None:
sousaedu2ad85172021-02-17 15:05:18 +01002333 self.logger.debug(
2334 "Adding existing disk from image {} to vm {} ".format(
2335 disk["image_id"], vapp_uuid
2336 )
2337 )
2338 self.add_existing_disk(
2339 catalogs=catalogs,
2340 image_id=disk["image_id"],
2341 size=disk["size"],
2342 template_name=templateName,
2343 vapp_uuid=vapp_uuid,
2344 )
bhangare06312472017-03-30 05:49:07 -07002345 added_existing_disk = True
2346 else:
beierlb22ce2d2019-12-12 12:09:51 -05002347 # Wait till added existing disk gets reflected into vCD database/API
bhangare06312472017-03-30 05:49:07 -07002348 if added_existing_disk:
2349 time.sleep(5)
2350 added_existing_disk = False
sousaedu2ad85172021-02-17 15:05:18 +01002351 self.add_new_disk(vapp_uuid, disk["size"])
bhangare06312472017-03-30 05:49:07 -07002352
kasarde691232017-03-25 03:37:31 -07002353 if numas:
2354 # Assigning numa affinity setting
2355 for numa in numas:
sousaedu2ad85172021-02-17 15:05:18 +01002356 if "paired-threads-id" in numa:
2357 paired_threads_id = numa["paired-threads-id"]
kasarde691232017-03-25 03:37:31 -07002358 self.set_numa_affinity(vapp_uuid, paired_threads_id)
2359
bhangare0e571a92017-01-12 04:02:23 -08002360 # add NICs & connect to networks in netlist
bayramovef390722016-09-27 03:34:46 -07002361 try:
sousaedu2ad85172021-02-17 15:05:18 +01002362 vdc_obj = VDC(self.client, href=vdc.get("href"))
Ravi Chamarty5b2d5c12018-10-22 23:59:10 +00002363 vapp_resource = vdc_obj.get_vapp(vmname_andid)
2364 vapp = VApp(self.client, resource=vapp_resource)
sousaedu2ad85172021-02-17 15:05:18 +01002365 vapp_id = vapp_resource.get("id").split(":")[-1]
Ravi Chamarty5b2d5c12018-10-22 23:59:10 +00002366
2367 self.logger.info("Removing primary NIC: ")
2368 # First remove all NICs so that NIC properties can be adjusted as needed
2369 self.remove_primary_network_adapter_from_all_vms(vapp)
2370
kate15f1c382016-12-15 01:12:40 -08002371 self.logger.info("Request to connect VM to a network: {}".format(net_list))
bhangare0e571a92017-01-12 04:02:23 -08002372 primary_nic_index = 0
Ravi Chamarty1fdf9992018-10-07 15:45:44 +00002373 nicIndex = 0
bayramovef390722016-09-27 03:34:46 -07002374 for net in net_list:
2375 # openmano uses network id in UUID format.
2376 # vCloud Director need a name so we do reverse operation from provided UUID we lookup a name
kate15f1c382016-12-15 01:12:40 -08002377 # [{'use': 'bridge', 'net_id': '527d4bf7-566a-41e7-a9e7-ca3cdd9cef4f', 'type': 'virtual',
2378 # 'vpci': '0000:00:11.0', 'name': 'eth0'}]
2379
sousaedu2ad85172021-02-17 15:05:18 +01002380 if "net_id" not in net:
kate15f1c382016-12-15 01:12:40 -08002381 continue
2382
beierlb22ce2d2019-12-12 12:09:51 -05002383 # Using net_id as a vim_id i.e. vim interface id, as do not have saperate vim interface id
2384 # Same will be returned in refresh_vms_status() as vim_interface_id
sousaedu2ad85172021-02-17 15:05:18 +01002385 net["vim_id"] = net[
2386 "net_id"
2387 ] # Provide the same VIM identifier as the VIM network
tierno19860412017-10-03 10:46:46 +02002388
sousaedu2ad85172021-02-17 15:05:18 +01002389 interface_net_id = net["net_id"]
2390 interface_net_name = self.get_network_name_by_id(
2391 network_uuid=interface_net_id
2392 )
2393 interface_network_mode = net["use"]
bayramovef390722016-09-27 03:34:46 -07002394
sousaedu2ad85172021-02-17 15:05:18 +01002395 if interface_network_mode == "mgmt":
bhangare0e571a92017-01-12 04:02:23 -08002396 primary_nic_index = nicIndex
2397
kate15f1c382016-12-15 01:12:40 -08002398 """- POOL (A static IP address is allocated automatically from a pool of addresses.)
2399 - DHCP (The IP address is obtained from a DHCP service.)
2400 - MANUAL (The IP address is assigned manually in the IpAddress element.)
2401 - NONE (No IP addressing mode specified.)"""
2402
2403 if primary_netname is not None:
sousaedu2ad85172021-02-17 15:05:18 +01002404 self.logger.debug(
2405 "new_vminstance(): Filtering by net name {}".format(
2406 interface_net_name
2407 )
2408 )
2409 nets = [
2410 n
2411 for n in self.get_network_list()
2412 if n.get("name") == interface_net_name
2413 ]
2414
bayramovef390722016-09-27 03:34:46 -07002415 if len(nets) == 1:
sousaedu2ad85172021-02-17 15:05:18 +01002416 self.logger.info(
2417 "new_vminstance(): Found requested network: {}".format(
2418 nets[0].get("name")
2419 )
2420 )
bhangare1a0b97c2017-06-21 02:20:15 -07002421
Ravi Chamarty5b2d5c12018-10-22 23:59:10 +00002422 if interface_net_name != primary_netname:
2423 # connect network to VM - with all DHCP by default
sousaedu2ad85172021-02-17 15:05:18 +01002424 self.logger.info(
2425 "new_vminstance(): Attaching net {} to vapp".format(
2426 interface_net_name
2427 )
2428 )
2429 self.connect_vapp_to_org_vdc_network(
2430 vapp_id, nets[0].get("name")
2431 )
kasar3ac5dc42017-03-15 06:28:22 -07002432
sousaedu2ad85172021-02-17 15:05:18 +01002433 type_list = ("PF", "PCI-PASSTHROUGH", "VFnotShared")
2434 nic_type = "VMXNET3"
2435 if "type" in net and net["type"] not in type_list:
kasar3ac5dc42017-03-15 06:28:22 -07002436 # fetching nic type from vnf
sousaedu2ad85172021-02-17 15:05:18 +01002437 if "model" in net:
2438 if net["model"] is not None:
2439 if (
2440 net["model"].lower() == "paravirt"
2441 or net["model"].lower() == "virtio"
2442 ):
2443 nic_type = "VMXNET3"
kasar204e39e2018-01-25 00:57:02 -08002444 else:
sousaedu2ad85172021-02-17 15:05:18 +01002445 nic_type = net["model"]
kasar204e39e2018-01-25 00:57:02 -08002446
sousaedu2ad85172021-02-17 15:05:18 +01002447 self.logger.info(
2448 "new_vminstance(): adding network adapter "
2449 "to a network {}".format(nets[0].get("name"))
2450 )
2451 self.add_network_adapter_to_vms(
2452 vapp,
2453 nets[0].get("name"),
2454 primary_nic_index,
2455 nicIndex,
2456 net,
2457 nic_type=nic_type,
2458 )
kasar3ac5dc42017-03-15 06:28:22 -07002459 else:
sousaedu2ad85172021-02-17 15:05:18 +01002460 self.logger.info(
2461 "new_vminstance(): adding network adapter "
2462 "to a network {}".format(nets[0].get("name"))
2463 )
2464
2465 if net["type"] in ["SR-IOV", "VF"]:
2466 nic_type = net["type"]
2467 self.add_network_adapter_to_vms(
2468 vapp,
2469 nets[0].get("name"),
2470 primary_nic_index,
2471 nicIndex,
2472 net,
2473 nic_type=nic_type,
2474 )
bhangare0e571a92017-01-12 04:02:23 -08002475 nicIndex += 1
bayramovef390722016-09-27 03:34:46 -07002476
kasardc1f02e2017-03-25 07:20:30 -07002477 # cloud-init for ssh-key injection
2478 if cloud_config:
Ananda Baitharu319c26f2019-03-05 17:34:31 +00002479 # Create a catalog which will be carrying the config drive ISO
2480 # This catalog is deleted during vApp deletion. The catalog name carries
2481 # vApp UUID and thats how it gets identified during its deletion.
sousaedu2ad85172021-02-17 15:05:18 +01002482 config_drive_catalog_name = "cfg_drv-" + vapp_uuid
2483 self.logger.info(
2484 'new_vminstance(): Creating catalog "{}" to carry config drive ISO'.format(
2485 config_drive_catalog_name
2486 )
2487 )
2488 config_drive_catalog_id = self.create_vimcatalog(
2489 org, config_drive_catalog_name
2490 )
2491
Ananda Baitharu319c26f2019-03-05 17:34:31 +00002492 if config_drive_catalog_id is None:
sousaedu2ad85172021-02-17 15:05:18 +01002493 error_msg = (
2494 "new_vminstance(): Failed to create new catalog '{}' to carry the config drive "
2495 "ISO".format(config_drive_catalog_name)
2496 )
Ananda Baitharu319c26f2019-03-05 17:34:31 +00002497 raise Exception(error_msg)
2498
2499 # Create config-drive ISO
2500 _, userdata = self._create_user_data(cloud_config)
2501 # self.logger.debug('new_vminstance(): The userdata for cloud-init: {}'.format(userdata))
2502 iso_path = self.create_config_drive_iso(userdata)
sousaedu2ad85172021-02-17 15:05:18 +01002503 self.logger.debug(
2504 "new_vminstance(): The ISO is successfully created. Path: {}".format(
2505 iso_path
2506 )
2507 )
Ananda Baitharu319c26f2019-03-05 17:34:31 +00002508
sousaedu2ad85172021-02-17 15:05:18 +01002509 self.logger.info(
2510 "new_vminstance(): uploading iso to catalog {}".format(
2511 config_drive_catalog_name
2512 )
2513 )
Ananda Baitharu319c26f2019-03-05 17:34:31 +00002514 self.upload_iso_to_catalog(config_drive_catalog_id, iso_path)
2515 # Attach the config-drive ISO to the VM
sousaedu2ad85172021-02-17 15:05:18 +01002516 self.logger.info(
2517 "new_vminstance(): Attaching the config-drive ISO to the VM"
2518 )
Ananda Baitharu319c26f2019-03-05 17:34:31 +00002519 self.insert_media_to_vm(vapp, config_drive_catalog_id)
2520 shutil.rmtree(os.path.dirname(iso_path), ignore_errors=True)
kasardc1f02e2017-03-25 07:20:30 -07002521
kateac1e3792017-04-01 02:16:39 -07002522 # If VM has PCI devices or SRIOV reserve memory for VM
2523 if reserve_memory:
Ravi Chamartye21c9cc2018-10-24 02:14:53 +00002524 self.reserve_memory_for_all_vms(vapp, memory_mb)
bhangarefda5f7c2017-01-12 23:50:34 -08002525
sousaedu2ad85172021-02-17 15:05:18 +01002526 self.logger.debug(
2527 "new_vminstance(): starting power on vApp {} ".format(vmname_andid)
2528 )
bhangare1a0b97c2017-06-21 02:20:15 -07002529
kasarc5bf2932018-03-09 04:15:22 -08002530 poweron_task = self.power_on_vapp(vapp_id, vmname_andid)
2531 result = self.client.get_task_monitor().wait_for_success(task=poweron_task)
sousaedu2ad85172021-02-17 15:05:18 +01002532 if result.get("status") == "success":
2533 self.logger.info(
2534 "new_vminstance(): Successfully power on "
2535 "vApp {}".format(vmname_andid)
2536 )
kasarc5bf2932018-03-09 04:15:22 -08002537 else:
sousaedu2ad85172021-02-17 15:05:18 +01002538 self.logger.error(
2539 "new_vminstance(): failed to power on vApp "
2540 "{}".format(vmname_andid)
2541 )
bhangarebfdca492017-03-11 01:32:46 -08002542
Ananda Baitharu319c26f2019-03-05 17:34:31 +00002543 except Exception as exp:
2544 try:
2545 self.delete_vminstance(vapp_uuid)
2546 except Exception as exp2:
2547 self.logger.error("new_vminstance rollback fail {}".format(exp2))
bhangarebfdca492017-03-11 01:32:46 -08002548 # it might be a case if specific mandatory entry in dict is empty or some other pyVcloud exception
sousaedu2ad85172021-02-17 15:05:18 +01002549 self.logger.error(
2550 "new_vminstance(): Failed create new vm instance {} with exception {}".format(
2551 name, exp
2552 )
2553 )
2554 raise vimconn.VimConnException(
2555 "new_vminstance(): Failed create new vm instance {} with exception {}".format(
2556 name, exp
2557 )
2558 )
bayramovef390722016-09-27 03:34:46 -07002559 # check if vApp deployed and if that the case return vApp UUID otherwise -1
kate13ab2c42016-12-23 01:34:24 -08002560 wait_time = 0
2561 vapp_uuid = None
2562 while wait_time <= MAX_WAIT_TIME:
bhangarebfdca492017-03-11 01:32:46 -08002563 try:
kasarc5bf2932018-03-09 04:15:22 -08002564 vapp_resource = vdc_obj.get_vapp(vmname_andid)
sbhangarea8e5b782018-06-21 02:10:03 -07002565 vapp = VApp(self.client, resource=vapp_resource)
bhangarebfdca492017-03-11 01:32:46 -08002566 except Exception as exp:
tierno72774862020-05-04 11:44:15 +00002567 raise vimconn.VimConnUnexpectedResponse(
sousaedu2ad85172021-02-17 15:05:18 +01002568 "new_vminstance(): Failed to retrieve vApp {} after creation: Exception:{}".format(
2569 vmname_andid, exp
2570 )
2571 )
bhangarebfdca492017-03-11 01:32:46 -08002572
beierlb22ce2d2019-12-12 12:09:51 -05002573 # if vapp and vapp.me.deployed:
sousaedu2ad85172021-02-17 15:05:18 +01002574 if vapp and vapp_resource.get("deployed") == "true":
2575 vapp_uuid = vapp_resource.get("id").split(":")[-1]
kate13ab2c42016-12-23 01:34:24 -08002576 break
2577 else:
sousaedu2ad85172021-02-17 15:05:18 +01002578 self.logger.debug(
2579 "new_vminstance(): Wait for vApp {} to deploy".format(name)
2580 )
kate13ab2c42016-12-23 01:34:24 -08002581 time.sleep(INTERVAL_TIME)
2582
beierlb22ce2d2019-12-12 12:09:51 -05002583 wait_time += INTERVAL_TIME
kate13ab2c42016-12-23 01:34:24 -08002584
beierlb22ce2d2019-12-12 12:09:51 -05002585 # SET Affinity Rule for VM
2586 # Pre-requisites: User has created Hosh Groups in vCenter with respective Hosts to be used
2587 # While creating VIM account user has to pass the Host Group names in availability_zone list
2588 # "availability_zone" is a part of VIM "config" parameters
2589 # For example, in VIM config: "availability_zone":["HG_170","HG_174","HG_175"]
2590 # Host groups are referred as availability zones
2591 # With following procedure, deployed VM will be added into a VM group.
2592 # Then A VM to Host Affinity rule will be created using the VM group & Host group.
sousaedu2ad85172021-02-17 15:05:18 +01002593 if availability_zone_list:
2594 self.logger.debug(
2595 "Existing Host Groups in VIM {}".format(
2596 self.config.get("availability_zone")
2597 )
2598 )
beierlb22ce2d2019-12-12 12:09:51 -05002599 # Admin access required for creating Affinity rules
sbhangarea8e5b782018-06-21 02:10:03 -07002600 client = self.connect_as_admin()
sousaedu2ad85172021-02-17 15:05:18 +01002601
sbhangarea8e5b782018-06-21 02:10:03 -07002602 if not client:
sousaedu2ad85172021-02-17 15:05:18 +01002603 raise vimconn.VimConnConnectionException(
2604 "Failed to connect vCD as admin"
2605 )
sbhangarea8e5b782018-06-21 02:10:03 -07002606 else:
2607 self.client = client
sousaedu2ad85172021-02-17 15:05:18 +01002608
sbhangarea8e5b782018-06-21 02:10:03 -07002609 if self.client:
sousaedu2ad85172021-02-17 15:05:18 +01002610 headers = {
2611 "Accept": "application/*+xml;version=27.0",
2612 "x-vcloud-authorization": self.client._session.headers[
2613 "x-vcloud-authorization"
2614 ],
2615 }
2616
beierlb22ce2d2019-12-12 12:09:51 -05002617 # Step1: Get provider vdc details from organization
sbhangarea8e5b782018-06-21 02:10:03 -07002618 pvdc_href = self.get_pvdc_for_org(self.tenant_name, headers)
2619 if pvdc_href is not None:
beierlb22ce2d2019-12-12 12:09:51 -05002620 # Step2: Found required pvdc, now get resource pool information
sbhangarea8e5b782018-06-21 02:10:03 -07002621 respool_href = self.get_resource_pool_details(pvdc_href, headers)
2622 if respool_href is None:
beierlb22ce2d2019-12-12 12:09:51 -05002623 # Raise error if respool_href not found
sousaedu2ad85172021-02-17 15:05:18 +01002624 msg = "new_vminstance():Error in finding resource pool details in pvdc {}".format(
2625 pvdc_href
2626 )
sbhangarea8e5b782018-06-21 02:10:03 -07002627 self.log_message(msg)
2628
beierlb22ce2d2019-12-12 12:09:51 -05002629 # Step3: Verify requested availability zone(hostGroup) is present in vCD
sbhangarea8e5b782018-06-21 02:10:03 -07002630 # get availability Zone
sousaedu2ad85172021-02-17 15:05:18 +01002631 vm_az = self.get_vm_availability_zone(
2632 availability_zone_index, availability_zone_list
2633 )
2634
sbhangarea8e5b782018-06-21 02:10:03 -07002635 # check if provided av zone(hostGroup) is present in vCD VIM
2636 status = self.check_availibility_zone(vm_az, respool_href, headers)
2637 if status is False:
sousaedu2ad85172021-02-17 15:05:18 +01002638 msg = (
2639 "new_vminstance(): Error in finding availability zone(Host Group): {} in "
2640 "resource pool {} status: {}"
2641 ).format(vm_az, respool_href, status)
sbhangarea8e5b782018-06-21 02:10:03 -07002642 self.log_message(msg)
2643 else:
sousaedu2ad85172021-02-17 15:05:18 +01002644 self.logger.debug(
2645 "new_vminstance(): Availability zone {} found in VIM".format(vm_az)
2646 )
sbhangarea8e5b782018-06-21 02:10:03 -07002647
beierlb22ce2d2019-12-12 12:09:51 -05002648 # Step4: Find VM group references to create vm group
sbhangarea8e5b782018-06-21 02:10:03 -07002649 vmgrp_href = self.find_vmgroup_reference(respool_href, headers)
beierlb22ce2d2019-12-12 12:09:51 -05002650 if vmgrp_href is None:
sbhangarea8e5b782018-06-21 02:10:03 -07002651 msg = "new_vminstance(): No reference to VmGroup found in resource pool"
2652 self.log_message(msg)
2653
beierlb22ce2d2019-12-12 12:09:51 -05002654 # Step5: Create a VmGroup with name az_VmGroup
sousaedu2ad85172021-02-17 15:05:18 +01002655 vmgrp_name = (
2656 vm_az + "_" + name
2657 ) # Formed VM Group name = Host Group name + VM name
sbhangarea8e5b782018-06-21 02:10:03 -07002658 status = self.create_vmgroup(vmgrp_name, vmgrp_href, headers)
2659 if status is not True:
sousaedu2ad85172021-02-17 15:05:18 +01002660 msg = "new_vminstance(): Error in creating VM group {}".format(
2661 vmgrp_name
2662 )
sbhangarea8e5b782018-06-21 02:10:03 -07002663 self.log_message(msg)
2664
beierlb22ce2d2019-12-12 12:09:51 -05002665 # VM Group url to add vms to vm group
2666 vmgrpname_url = self.url + "/api/admin/extension/vmGroup/name/" + vmgrp_name
sbhangarea8e5b782018-06-21 02:10:03 -07002667
beierlb22ce2d2019-12-12 12:09:51 -05002668 # Step6: Add VM to VM Group
2669 # Find VM uuid from vapp_uuid
sbhangarea8e5b782018-06-21 02:10:03 -07002670 vm_details = self.get_vapp_details_rest(vapp_uuid)
sousaedu2ad85172021-02-17 15:05:18 +01002671 vm_uuid = vm_details["vmuuid"]
sbhangarea8e5b782018-06-21 02:10:03 -07002672
2673 status = self.add_vm_to_vmgroup(vm_uuid, vmgrpname_url, vmgrp_name, headers)
2674 if status is not True:
sousaedu2ad85172021-02-17 15:05:18 +01002675 msg = "new_vminstance(): Error in adding VM to VM group {}".format(
2676 vmgrp_name
2677 )
sbhangarea8e5b782018-06-21 02:10:03 -07002678 self.log_message(msg)
2679
beierlb22ce2d2019-12-12 12:09:51 -05002680 # Step7: Create VM to Host affinity rule
2681 addrule_href = self.get_add_rule_reference(respool_href, headers)
sbhangarea8e5b782018-06-21 02:10:03 -07002682 if addrule_href is None:
sousaedu2ad85172021-02-17 15:05:18 +01002683 msg = "new_vminstance(): Error in finding href to add rule in resource pool: {}".format(
2684 respool_href
2685 )
sbhangarea8e5b782018-06-21 02:10:03 -07002686 self.log_message(msg)
2687
sousaedu2ad85172021-02-17 15:05:18 +01002688 status = self.create_vm_to_host_affinity_rule(
2689 addrule_href, vmgrp_name, vm_az, "Affinity", headers
2690 )
sbhangarea8e5b782018-06-21 02:10:03 -07002691 if status is False:
sousaedu2ad85172021-02-17 15:05:18 +01002692 msg = "new_vminstance(): Error in creating affinity rule for VM {} in Host group {}".format(
2693 name, vm_az
2694 )
sbhangarea8e5b782018-06-21 02:10:03 -07002695 self.log_message(msg)
2696 else:
sousaedu2ad85172021-02-17 15:05:18 +01002697 self.logger.debug(
2698 "new_vminstance(): Affinity rule created successfully. Added {} in Host group {}".format(
2699 name, vm_az
2700 )
2701 )
beierlb22ce2d2019-12-12 12:09:51 -05002702 # Reset token to a normal user to perform other operations
sbhangarea8e5b782018-06-21 02:10:03 -07002703 self.get_token()
2704
bayramovef390722016-09-27 03:34:46 -07002705 if vapp_uuid is not None:
tierno98e909c2017-10-14 13:27:03 +02002706 return vapp_uuid, None
bayramovbd6160f2016-09-28 04:12:05 +04002707 else:
sousaedu2ad85172021-02-17 15:05:18 +01002708 raise vimconn.VimConnUnexpectedResponse(
2709 "new_vminstance(): Failed create new vm instance {}".format(name)
2710 )
bayramov325fa1c2016-09-08 01:42:46 -07002711
Ananda Baitharu319c26f2019-03-05 17:34:31 +00002712 def create_config_drive_iso(self, user_data):
2713 tmpdir = tempfile.mkdtemp()
sousaedu2ad85172021-02-17 15:05:18 +01002714 iso_path = os.path.join(tmpdir, "ConfigDrive.iso")
2715 latest_dir = os.path.join(tmpdir, "openstack", "latest")
Ananda Baitharu319c26f2019-03-05 17:34:31 +00002716 os.makedirs(latest_dir)
sousaedu2ad85172021-02-17 15:05:18 +01002717 with open(
2718 os.path.join(latest_dir, "meta_data.json"), "w"
2719 ) as meta_file_obj, open(
2720 os.path.join(latest_dir, "user_data"), "w"
2721 ) as userdata_file_obj:
Ananda Baitharu319c26f2019-03-05 17:34:31 +00002722 userdata_file_obj.write(user_data)
sousaedu2ad85172021-02-17 15:05:18 +01002723 meta_file_obj.write(
2724 json.dumps(
2725 {
2726 "availability_zone": "nova",
2727 "launch_index": 0,
2728 "name": "ConfigDrive",
2729 "uuid": str(uuid.uuid4()),
2730 }
2731 )
2732 )
2733 genisoimage_cmd = (
2734 "genisoimage -J -r -V config-2 -o {iso_path} {source_dir_path}".format(
2735 iso_path=iso_path, source_dir_path=tmpdir
2736 )
2737 )
2738 self.logger.info(
2739 'create_config_drive_iso(): Creating ISO by running command "{}"'.format(
2740 genisoimage_cmd
2741 )
2742 )
2743
Ananda Baitharu319c26f2019-03-05 17:34:31 +00002744 try:
sousaedu2ad85172021-02-17 15:05:18 +01002745 FNULL = open(os.devnull, "w")
Ananda Baitharu319c26f2019-03-05 17:34:31 +00002746 subprocess.check_call(genisoimage_cmd, shell=True, stdout=FNULL)
2747 except subprocess.CalledProcessError as e:
2748 shutil.rmtree(tmpdir, ignore_errors=True)
sousaedu2ad85172021-02-17 15:05:18 +01002749 error_msg = "create_config_drive_iso(): Exception while running genisoimage command: {}".format(
2750 e
2751 )
Ananda Baitharu319c26f2019-03-05 17:34:31 +00002752 self.logger.error(error_msg)
2753 raise Exception(error_msg)
sousaedu2ad85172021-02-17 15:05:18 +01002754
Ananda Baitharu319c26f2019-03-05 17:34:31 +00002755 return iso_path
2756
2757 def upload_iso_to_catalog(self, catalog_id, iso_file_path):
2758 if not os.path.isfile(iso_file_path):
sousaedu2ad85172021-02-17 15:05:18 +01002759 error_msg = "upload_iso_to_catalog(): Given iso file is not present. Given path: {}".format(
2760 iso_file_path
2761 )
Ananda Baitharu319c26f2019-03-05 17:34:31 +00002762 self.logger.error(error_msg)
2763 raise Exception(error_msg)
sousaedu2ad85172021-02-17 15:05:18 +01002764
Ananda Baitharu319c26f2019-03-05 17:34:31 +00002765 iso_file_stat = os.stat(iso_file_path)
sousaedu2ad85172021-02-17 15:05:18 +01002766 xml_media_elem = """<?xml version="1.0" encoding="UTF-8"?>
Ananda Baitharu319c26f2019-03-05 17:34:31 +00002767 <Media
2768 xmlns="http://www.vmware.com/vcloud/v1.5"
2769 name="{iso_name}"
2770 size="{iso_size}"
2771 imageType="iso">
2772 <Description>ISO image for config-drive</Description>
sousaedu2ad85172021-02-17 15:05:18 +01002773 </Media>""".format(
2774 iso_name=os.path.basename(iso_file_path), iso_size=iso_file_stat.st_size
2775 )
2776 headers = {
2777 "Accept": "application/*+xml;version=" + API_VERSION,
2778 "x-vcloud-authorization": self.client._session.headers[
2779 "x-vcloud-authorization"
2780 ],
2781 }
2782 headers["Content-Type"] = "application/vnd.vmware.vcloud.media+xml"
2783 catalog_href = self.url + "/api/catalog/" + catalog_id + "/action/upload"
2784 response = self.perform_request(
2785 req_type="POST", url=catalog_href, headers=headers, data=xml_media_elem
2786 )
Ananda Baitharu319c26f2019-03-05 17:34:31 +00002787
2788 if response.status_code != 201:
sousaedu2ad85172021-02-17 15:05:18 +01002789 error_msg = "upload_iso_to_catalog(): Failed to POST an action/upload request to {}".format(
2790 catalog_href
2791 )
Ananda Baitharu319c26f2019-03-05 17:34:31 +00002792 self.logger.error(error_msg)
2793 raise Exception(error_msg)
2794
beierl26fec002019-12-06 17:06:40 -05002795 catalogItem = XmlElementTree.fromstring(response.text)
sousaedu2ad85172021-02-17 15:05:18 +01002796 entity = [
2797 child
2798 for child in catalogItem
2799 if child.get("type") == "application/vnd.vmware.vcloud.media+xml"
2800 ][0]
2801 entity_href = entity.get("href")
Ananda Baitharu319c26f2019-03-05 17:34:31 +00002802
sousaedu2ad85172021-02-17 15:05:18 +01002803 response = self.perform_request(
2804 req_type="GET", url=entity_href, headers=headers
2805 )
Ananda Baitharu319c26f2019-03-05 17:34:31 +00002806 if response.status_code != 200:
sousaedu2ad85172021-02-17 15:05:18 +01002807 raise Exception(
2808 "upload_iso_to_catalog(): Failed to GET entity href {}".format(
2809 entity_href
2810 )
2811 )
Ananda Baitharu319c26f2019-03-05 17:34:31 +00002812
sousaedu2ad85172021-02-17 15:05:18 +01002813 match = re.search(
2814 r'<Files>\s+?<File.+?href="(.+?)"/>\s+?</File>\s+?</Files>',
2815 response.text,
2816 re.DOTALL,
2817 )
Ananda Baitharu319c26f2019-03-05 17:34:31 +00002818 if match:
2819 media_upload_href = match.group(1)
2820 else:
sousaedu2ad85172021-02-17 15:05:18 +01002821 raise Exception(
2822 "Could not parse the upload URL for the media file from the last response"
2823 )
beierl26fec002019-12-06 17:06:40 -05002824 upload_iso_task = self.get_task_from_response(response.text)
sousaedu2ad85172021-02-17 15:05:18 +01002825 headers["Content-Type"] = "application/octet-stream"
2826 response = self.perform_request(
2827 req_type="PUT",
2828 url=media_upload_href,
2829 headers=headers,
2830 data=open(iso_file_path, "rb"),
2831 )
Ananda Baitharu319c26f2019-03-05 17:34:31 +00002832
2833 if response.status_code != 200:
2834 raise Exception('PUT request to "{}" failed'.format(media_upload_href))
sousaedu2ad85172021-02-17 15:05:18 +01002835
Ananda Baitharub23558c2019-06-18 13:53:37 +00002836 result = self.client.get_task_monitor().wait_for_success(task=upload_iso_task)
sousaedu2ad85172021-02-17 15:05:18 +01002837 if result.get("status") != "success":
2838 raise Exception(
2839 "The upload iso task failed with status {}".format(result.get("status"))
2840 )
sbhangarea8e5b782018-06-21 02:10:03 -07002841
beierlb22ce2d2019-12-12 12:09:51 -05002842 def get_vcd_availibility_zones(self, respool_href, headers):
sousaedu2ad85172021-02-17 15:05:18 +01002843 """Method to find presence of av zone is VIM resource pool
sbhangarea8e5b782018-06-21 02:10:03 -07002844
sousaedu2ad85172021-02-17 15:05:18 +01002845 Args:
2846 respool_href - resource pool href
2847 headers - header information
sbhangarea8e5b782018-06-21 02:10:03 -07002848
sousaedu2ad85172021-02-17 15:05:18 +01002849 Returns:
2850 vcd_az - list of azone present in vCD
sbhangarea8e5b782018-06-21 02:10:03 -07002851 """
2852 vcd_az = []
beierlb22ce2d2019-12-12 12:09:51 -05002853 url = respool_href
sousaedu2ad85172021-02-17 15:05:18 +01002854 resp = self.perform_request(req_type="GET", url=respool_href, headers=headers)
sbhangarea8e5b782018-06-21 02:10:03 -07002855
2856 if resp.status_code != requests.codes.ok:
sousaedu2ad85172021-02-17 15:05:18 +01002857 self.logger.debug(
2858 "REST API call {} failed. Return status code {}".format(
2859 url, resp.status_code
2860 )
2861 )
sbhangarea8e5b782018-06-21 02:10:03 -07002862 else:
beierlb22ce2d2019-12-12 12:09:51 -05002863 # Get the href to hostGroups and find provided hostGroup is present in it
sbhangarea8e5b782018-06-21 02:10:03 -07002864 resp_xml = XmlElementTree.fromstring(resp.content)
2865 for child in resp_xml:
sousaedu2ad85172021-02-17 15:05:18 +01002866 if "VMWProviderVdcResourcePool" in child.tag:
sbhangarea8e5b782018-06-21 02:10:03 -07002867 for schild in child:
sousaedu2ad85172021-02-17 15:05:18 +01002868 if "Link" in schild.tag:
2869 if (
2870 schild.attrib.get("type")
2871 == "application/vnd.vmware.admin.vmwHostGroupsType+xml"
2872 ):
2873 hostGroup = schild.attrib.get("href")
2874 hg_resp = self.perform_request(
2875 req_type="GET", url=hostGroup, headers=headers
2876 )
2877
sbhangarea8e5b782018-06-21 02:10:03 -07002878 if hg_resp.status_code != requests.codes.ok:
sousaedu2ad85172021-02-17 15:05:18 +01002879 self.logger.debug(
2880 "REST API call {} failed. Return status code {}".format(
2881 hostGroup, hg_resp.status_code
2882 )
2883 )
sbhangarea8e5b782018-06-21 02:10:03 -07002884 else:
sousaedu2ad85172021-02-17 15:05:18 +01002885 hg_resp_xml = XmlElementTree.fromstring(
2886 hg_resp.content
2887 )
sbhangarea8e5b782018-06-21 02:10:03 -07002888 for hostGroup in hg_resp_xml:
sousaedu2ad85172021-02-17 15:05:18 +01002889 if "HostGroup" in hostGroup.tag:
beierlb22ce2d2019-12-12 12:09:51 -05002890 # append host group name to the list
sbhangarea8e5b782018-06-21 02:10:03 -07002891 vcd_az.append(hostGroup.attrib.get("name"))
sousaedu2ad85172021-02-17 15:05:18 +01002892
sbhangarea8e5b782018-06-21 02:10:03 -07002893 return vcd_az
2894
sbhangarea8e5b782018-06-21 02:10:03 -07002895 def set_availability_zones(self):
2896 """
2897 Set vim availability zone
2898 """
sbhangarea8e5b782018-06-21 02:10:03 -07002899 vim_availability_zones = None
2900 availability_zone = None
sousaedu2ad85172021-02-17 15:05:18 +01002901
2902 if "availability_zone" in self.config:
2903 vim_availability_zones = self.config.get("availability_zone")
2904
sbhangarea8e5b782018-06-21 02:10:03 -07002905 if isinstance(vim_availability_zones, str):
2906 availability_zone = [vim_availability_zones]
2907 elif isinstance(vim_availability_zones, list):
2908 availability_zone = vim_availability_zones
2909 else:
2910 return availability_zone
2911
2912 return availability_zone
2913
sbhangarea8e5b782018-06-21 02:10:03 -07002914 def get_vm_availability_zone(self, availability_zone_index, availability_zone_list):
2915 """
2916 Return the availability zone to be used by the created VM.
2917 returns: The VIM availability zone to be used or None
2918 """
2919 if availability_zone_index is None:
sousaedu2ad85172021-02-17 15:05:18 +01002920 if not self.config.get("availability_zone"):
sbhangarea8e5b782018-06-21 02:10:03 -07002921 return None
sousaedu2ad85172021-02-17 15:05:18 +01002922 elif isinstance(self.config.get("availability_zone"), str):
2923 return self.config["availability_zone"]
sbhangarea8e5b782018-06-21 02:10:03 -07002924 else:
sousaedu2ad85172021-02-17 15:05:18 +01002925 return self.config["availability_zone"][0]
sbhangarea8e5b782018-06-21 02:10:03 -07002926
2927 vim_availability_zones = self.availability_zone
2928
2929 # check if VIM offer enough availability zones describe in the VNFD
sousaedu2ad85172021-02-17 15:05:18 +01002930 if vim_availability_zones and len(availability_zone_list) <= len(
2931 vim_availability_zones
2932 ):
sbhangarea8e5b782018-06-21 02:10:03 -07002933 # check if all the names of NFV AV match VIM AV names
2934 match_by_index = False
2935 for av in availability_zone_list:
2936 if av not in vim_availability_zones:
2937 match_by_index = True
2938 break
sousaedu2ad85172021-02-17 15:05:18 +01002939
sbhangarea8e5b782018-06-21 02:10:03 -07002940 if match_by_index:
sousaedu2ad85172021-02-17 15:05:18 +01002941 self.logger.debug(
2942 "Required Availability zone or Host Group not found in VIM config"
2943 )
2944 self.logger.debug(
2945 "Input Availability zone list: {}".format(availability_zone_list)
2946 )
2947 self.logger.debug(
2948 "VIM configured Availability zones: {}".format(
2949 vim_availability_zones
2950 )
2951 )
sbhangarea8e5b782018-06-21 02:10:03 -07002952 self.logger.debug("VIM Availability zones will be used by index")
2953 return vim_availability_zones[availability_zone_index]
2954 else:
2955 return availability_zone_list[availability_zone_index]
2956 else:
sousaedu2ad85172021-02-17 15:05:18 +01002957 raise vimconn.VimConnConflictException(
2958 "No enough availability zones at VIM for this deployment"
2959 )
sbhangarea8e5b782018-06-21 02:10:03 -07002960
sousaedu2ad85172021-02-17 15:05:18 +01002961 def create_vm_to_host_affinity_rule(
2962 self, addrule_href, vmgrpname, hostgrpname, polarity, headers
2963 ):
2964 """Method to create VM to Host Affinity rule in vCD
sbhangarea8e5b782018-06-21 02:10:03 -07002965
2966 Args:
2967 addrule_href - href to make a POST request
2968 vmgrpname - name of the VM group created
2969 hostgrpnmae - name of the host group created earlier
2970 polarity - Affinity or Anti-affinity (default: Affinity)
2971 headers - headers to make REST call
2972
2973 Returns:
2974 True- if rule is created
2975 False- Failed to create rule due to some error
2976
2977 """
2978 task_status = False
2979 rule_name = polarity + "_" + vmgrpname
2980 payload = """<?xml version="1.0" encoding="UTF-8"?>
2981 <vmext:VMWVmHostAffinityRule
2982 xmlns:vmext="http://www.vmware.com/vcloud/extension/v1.5"
2983 xmlns:vcloud="http://www.vmware.com/vcloud/v1.5"
2984 type="application/vnd.vmware.admin.vmwVmHostAffinityRule+xml">
2985 <vcloud:Name>{}</vcloud:Name>
2986 <vcloud:IsEnabled>true</vcloud:IsEnabled>
2987 <vcloud:IsMandatory>true</vcloud:IsMandatory>
2988 <vcloud:Polarity>{}</vcloud:Polarity>
2989 <vmext:HostGroupName>{}</vmext:HostGroupName>
2990 <vmext:VmGroupName>{}</vmext:VmGroupName>
sousaedu2ad85172021-02-17 15:05:18 +01002991 </vmext:VMWVmHostAffinityRule>""".format(
2992 rule_name, polarity, hostgrpname, vmgrpname
2993 )
sbhangarea8e5b782018-06-21 02:10:03 -07002994
sousaedu2ad85172021-02-17 15:05:18 +01002995 resp = self.perform_request(
2996 req_type="POST", url=addrule_href, headers=headers, data=payload
2997 )
sbhangarea8e5b782018-06-21 02:10:03 -07002998
2999 if resp.status_code != requests.codes.accepted:
sousaedu2ad85172021-02-17 15:05:18 +01003000 self.logger.debug(
3001 "REST API call {} failed. Return status code {}".format(
3002 addrule_href, resp.status_code
3003 )
3004 )
sbhangarea8e5b782018-06-21 02:10:03 -07003005 task_status = False
sousaedu2ad85172021-02-17 15:05:18 +01003006
sbhangarea8e5b782018-06-21 02:10:03 -07003007 return task_status
3008 else:
3009 affinity_task = self.get_task_from_response(resp.content)
beierlb22ce2d2019-12-12 12:09:51 -05003010 self.logger.debug("affinity_task: {}".format(affinity_task))
sousaedu2ad85172021-02-17 15:05:18 +01003011
sbhangarea8e5b782018-06-21 02:10:03 -07003012 if affinity_task is None or affinity_task is False:
tierno72774862020-05-04 11:44:15 +00003013 raise vimconn.VimConnUnexpectedResponse("failed to find affinity task")
sbhangarea8e5b782018-06-21 02:10:03 -07003014 # wait for task to complete
3015 result = self.client.get_task_monitor().wait_for_success(task=affinity_task)
sousaedu2ad85172021-02-17 15:05:18 +01003016
3017 if result.get("status") == "success":
3018 self.logger.debug(
3019 "Successfully created affinity rule {}".format(rule_name)
3020 )
sbhangarea8e5b782018-06-21 02:10:03 -07003021 return True
3022 else:
tierno72774862020-05-04 11:44:15 +00003023 raise vimconn.VimConnUnexpectedResponse(
sousaedu2ad85172021-02-17 15:05:18 +01003024 "failed to create affinity rule {}".format(rule_name)
3025 )
sbhangarea8e5b782018-06-21 02:10:03 -07003026
beierlb22ce2d2019-12-12 12:09:51 -05003027 def get_add_rule_reference(self, respool_href, headers):
sousaedu2ad85172021-02-17 15:05:18 +01003028 """This method finds href to add vm to host affinity rule to vCD
sbhangarea8e5b782018-06-21 02:10:03 -07003029
3030 Args:
3031 respool_href- href to resource pool
3032 headers- header information to make REST call
3033
3034 Returns:
3035 None - if no valid href to add rule found or
3036 addrule_href - href to add vm to host affinity rule of resource pool
3037 """
3038 addrule_href = None
sousaedu2ad85172021-02-17 15:05:18 +01003039 resp = self.perform_request(req_type="GET", url=respool_href, headers=headers)
sbhangarea8e5b782018-06-21 02:10:03 -07003040
3041 if resp.status_code != requests.codes.ok:
sousaedu2ad85172021-02-17 15:05:18 +01003042 self.logger.debug(
3043 "REST API call {} failed. Return status code {}".format(
3044 respool_href, resp.status_code
3045 )
3046 )
sbhangarea8e5b782018-06-21 02:10:03 -07003047 else:
sbhangarea8e5b782018-06-21 02:10:03 -07003048 resp_xml = XmlElementTree.fromstring(resp.content)
3049 for child in resp_xml:
sousaedu2ad85172021-02-17 15:05:18 +01003050 if "VMWProviderVdcResourcePool" in child.tag:
sbhangarea8e5b782018-06-21 02:10:03 -07003051 for schild in child:
sousaedu2ad85172021-02-17 15:05:18 +01003052 if "Link" in schild.tag:
3053 if (
3054 schild.attrib.get("type")
3055 == "application/vnd.vmware.admin.vmwVmHostAffinityRule+xml"
3056 and schild.attrib.get("rel") == "add"
3057 ):
3058 addrule_href = schild.attrib.get("href")
sbhangarea8e5b782018-06-21 02:10:03 -07003059 break
3060
3061 return addrule_href
3062
sbhangarea8e5b782018-06-21 02:10:03 -07003063 def add_vm_to_vmgroup(self, vm_uuid, vmGroupNameURL, vmGroup_name, headers):
sousaedu2ad85172021-02-17 15:05:18 +01003064 """Method to add deployed VM to newly created VM Group.
sbhangarea8e5b782018-06-21 02:10:03 -07003065 This is required to create VM to Host affinity in vCD
3066
3067 Args:
3068 vm_uuid- newly created vm uuid
3069 vmGroupNameURL- URL to VM Group name
3070 vmGroup_name- Name of VM group created
3071 headers- Headers for REST request
3072
3073 Returns:
3074 True- if VM added to VM group successfully
3075 False- if any error encounter
3076 """
sousaedu2ad85172021-02-17 15:05:18 +01003077 addvm_resp = self.perform_request(
3078 req_type="GET", url=vmGroupNameURL, headers=headers
3079 ) # , data=payload)
sbhangarea8e5b782018-06-21 02:10:03 -07003080
3081 if addvm_resp.status_code != requests.codes.ok:
sousaedu2ad85172021-02-17 15:05:18 +01003082 self.logger.debug(
3083 "REST API call to get VM Group Name url {} failed. Return status code {}".format(
3084 vmGroupNameURL, addvm_resp.status_code
3085 )
3086 )
sbhangarea8e5b782018-06-21 02:10:03 -07003087 return False
3088 else:
3089 resp_xml = XmlElementTree.fromstring(addvm_resp.content)
3090 for child in resp_xml:
sousaedu2ad85172021-02-17 15:05:18 +01003091 if child.tag.split("}")[1] == "Link":
sbhangarea8e5b782018-06-21 02:10:03 -07003092 if child.attrib.get("rel") == "addVms":
beierlb22ce2d2019-12-12 12:09:51 -05003093 addvmtogrpURL = child.attrib.get("href")
sbhangarea8e5b782018-06-21 02:10:03 -07003094
beierlb22ce2d2019-12-12 12:09:51 -05003095 # Get vm details
sousaedu2ad85172021-02-17 15:05:18 +01003096 url_list = [self.url, "/api/vApp/vm-", vm_uuid]
3097 vmdetailsURL = "".join(url_list)
sbhangarea8e5b782018-06-21 02:10:03 -07003098
sousaedu2ad85172021-02-17 15:05:18 +01003099 resp = self.perform_request(req_type="GET", url=vmdetailsURL, headers=headers)
sbhangarea8e5b782018-06-21 02:10:03 -07003100
3101 if resp.status_code != requests.codes.ok:
sousaedu2ad85172021-02-17 15:05:18 +01003102 self.logger.debug(
3103 "REST API call {} failed. Return status code {}".format(
3104 vmdetailsURL, resp.status_code
3105 )
3106 )
sbhangarea8e5b782018-06-21 02:10:03 -07003107 return False
3108
beierlb22ce2d2019-12-12 12:09:51 -05003109 # Parse VM details
sbhangarea8e5b782018-06-21 02:10:03 -07003110 resp_xml = XmlElementTree.fromstring(resp.content)
sousaedu2ad85172021-02-17 15:05:18 +01003111 if resp_xml.tag.split("}")[1] == "Vm":
sbhangarea8e5b782018-06-21 02:10:03 -07003112 vm_id = resp_xml.attrib.get("id")
3113 vm_name = resp_xml.attrib.get("name")
3114 vm_href = resp_xml.attrib.get("href")
beierlb22ce2d2019-12-12 12:09:51 -05003115 # print vm_id, vm_name, vm_href
sousaedu2ad85172021-02-17 15:05:18 +01003116
beierlb22ce2d2019-12-12 12:09:51 -05003117 # Add VM into VMgroup
sbhangarea8e5b782018-06-21 02:10:03 -07003118 payload = """<?xml version="1.0" encoding="UTF-8"?>\
3119 <ns2:Vms xmlns:ns2="http://www.vmware.com/vcloud/v1.5" \
3120 xmlns="http://www.vmware.com/vcloud/versions" \
3121 xmlns:ns3="http://schemas.dmtf.org/ovf/envelope/1" \
3122 xmlns:ns4="http://schemas.dmtf.org/wbem/wscim/1/cim-schema/2/CIM_VirtualSystemSettingData" \
3123 xmlns:ns5="http://schemas.dmtf.org/wbem/wscim/1/common" \
3124 xmlns:ns6="http://schemas.dmtf.org/wbem/wscim/1/cim-schema/2/CIM_ResourceAllocationSettingData" \
3125 xmlns:ns7="http://www.vmware.com/schema/ovf" \
3126 xmlns:ns8="http://schemas.dmtf.org/ovf/environment/1" \
3127 xmlns:ns9="http://www.vmware.com/vcloud/extension/v1.5">\
3128 <ns2:VmReference href="{}" id="{}" name="{}" \
3129 type="application/vnd.vmware.vcloud.vm+xml" />\
sousaedu2ad85172021-02-17 15:05:18 +01003130 </ns2:Vms>""".format(
3131 vm_href, vm_id, vm_name
3132 )
sbhangarea8e5b782018-06-21 02:10:03 -07003133
sousaedu2ad85172021-02-17 15:05:18 +01003134 addvmtogrp_resp = self.perform_request(
3135 req_type="POST", url=addvmtogrpURL, headers=headers, data=payload
3136 )
sbhangarea8e5b782018-06-21 02:10:03 -07003137
3138 if addvmtogrp_resp.status_code != requests.codes.accepted:
sousaedu2ad85172021-02-17 15:05:18 +01003139 self.logger.debug(
3140 "REST API call {} failed. Return status code {}".format(
3141 addvmtogrpURL, addvmtogrp_resp.status_code
3142 )
3143 )
3144
sbhangarea8e5b782018-06-21 02:10:03 -07003145 return False
3146 else:
sousaedu2ad85172021-02-17 15:05:18 +01003147 self.logger.debug(
3148 "Done adding VM {} to VMgroup {}".format(vm_name, vmGroup_name)
3149 )
3150
sbhangarea8e5b782018-06-21 02:10:03 -07003151 return True
3152
sbhangarea8e5b782018-06-21 02:10:03 -07003153 def create_vmgroup(self, vmgroup_name, vmgroup_href, headers):
3154 """Method to create a VM group in vCD
3155
sousaedu2ad85172021-02-17 15:05:18 +01003156 Args:
3157 vmgroup_name : Name of VM group to be created
3158 vmgroup_href : href for vmgroup
3159 headers- Headers for REST request
sbhangarea8e5b782018-06-21 02:10:03 -07003160 """
beierlb22ce2d2019-12-12 12:09:51 -05003161 # POST to add URL with required data
sbhangarea8e5b782018-06-21 02:10:03 -07003162 vmgroup_status = False
3163 payload = """<VMWVmGroup xmlns="http://www.vmware.com/vcloud/extension/v1.5" \
3164 xmlns:vcloud_v1.5="http://www.vmware.com/vcloud/v1.5" name="{}">\
3165 <vmCount>1</vmCount>\
sousaedu2ad85172021-02-17 15:05:18 +01003166 </VMWVmGroup>""".format(
3167 vmgroup_name
3168 )
3169 resp = self.perform_request(
3170 req_type="POST", url=vmgroup_href, headers=headers, data=payload
3171 )
sbhangarea8e5b782018-06-21 02:10:03 -07003172
3173 if resp.status_code != requests.codes.accepted:
sousaedu2ad85172021-02-17 15:05:18 +01003174 self.logger.debug(
3175 "REST API call {} failed. Return status code {}".format(
3176 vmgroup_href, resp.status_code
3177 )
3178 )
3179
sbhangarea8e5b782018-06-21 02:10:03 -07003180 return vmgroup_status
3181 else:
3182 vmgroup_task = self.get_task_from_response(resp.content)
3183 if vmgroup_task is None or vmgroup_task is False:
tierno72774862020-05-04 11:44:15 +00003184 raise vimconn.VimConnUnexpectedResponse(
sousaedu2ad85172021-02-17 15:05:18 +01003185 "create_vmgroup(): failed to create VM group {}".format(
3186 vmgroup_name
3187 )
3188 )
sbhangarea8e5b782018-06-21 02:10:03 -07003189
3190 # wait for task to complete
3191 result = self.client.get_task_monitor().wait_for_success(task=vmgroup_task)
3192
sousaedu2ad85172021-02-17 15:05:18 +01003193 if result.get("status") == "success":
3194 self.logger.debug(
3195 "create_vmgroup(): Successfully created VM group {}".format(
3196 vmgroup_name
3197 )
3198 )
beierlb22ce2d2019-12-12 12:09:51 -05003199 # time.sleep(10)
sbhangarea8e5b782018-06-21 02:10:03 -07003200 vmgroup_status = True
sousaedu2ad85172021-02-17 15:05:18 +01003201
sbhangarea8e5b782018-06-21 02:10:03 -07003202 return vmgroup_status
3203 else:
tierno72774862020-05-04 11:44:15 +00003204 raise vimconn.VimConnUnexpectedResponse(
sousaedu2ad85172021-02-17 15:05:18 +01003205 "create_vmgroup(): failed to create VM group {}".format(
3206 vmgroup_name
3207 )
3208 )
sbhangarea8e5b782018-06-21 02:10:03 -07003209
3210 def find_vmgroup_reference(self, url, headers):
sousaedu2ad85172021-02-17 15:05:18 +01003211 """Method to create a new VMGroup which is required to add created VM
3212 Args:
3213 url- resource pool href
3214 headers- header information
sbhangarea8e5b782018-06-21 02:10:03 -07003215
sousaedu2ad85172021-02-17 15:05:18 +01003216 Returns:
3217 returns href to VM group to create VM group
sbhangarea8e5b782018-06-21 02:10:03 -07003218 """
beierlb22ce2d2019-12-12 12:09:51 -05003219 # Perform GET on resource pool to find 'add' link to create VMGroup
3220 # https://vcd-ip/api/admin/extension/providervdc/<providervdc id>/resourcePools
sbhangarea8e5b782018-06-21 02:10:03 -07003221 vmgrp_href = None
sousaedu2ad85172021-02-17 15:05:18 +01003222 resp = self.perform_request(req_type="GET", url=url, headers=headers)
sbhangarea8e5b782018-06-21 02:10:03 -07003223
3224 if resp.status_code != requests.codes.ok:
sousaedu2ad85172021-02-17 15:05:18 +01003225 self.logger.debug(
3226 "REST API call {} failed. Return status code {}".format(
3227 url, resp.status_code
3228 )
3229 )
sbhangarea8e5b782018-06-21 02:10:03 -07003230 else:
beierlb22ce2d2019-12-12 12:09:51 -05003231 # Get the href to add vmGroup to vCD
sbhangarea8e5b782018-06-21 02:10:03 -07003232 resp_xml = XmlElementTree.fromstring(resp.content)
3233 for child in resp_xml:
sousaedu2ad85172021-02-17 15:05:18 +01003234 if "VMWProviderVdcResourcePool" in child.tag:
sbhangarea8e5b782018-06-21 02:10:03 -07003235 for schild in child:
sousaedu2ad85172021-02-17 15:05:18 +01003236 if "Link" in schild.tag:
beierlb22ce2d2019-12-12 12:09:51 -05003237 # Find href with type VMGroup and rel with add
sousaedu2ad85172021-02-17 15:05:18 +01003238 if (
3239 schild.attrib.get("type")
3240 == "application/vnd.vmware.admin.vmwVmGroupType+xml"
3241 and schild.attrib.get("rel") == "add"
3242 ):
3243 vmgrp_href = schild.attrib.get("href")
3244
sbhangarea8e5b782018-06-21 02:10:03 -07003245 return vmgrp_href
3246
sbhangarea8e5b782018-06-21 02:10:03 -07003247 def check_availibility_zone(self, az, respool_href, headers):
sousaedu2ad85172021-02-17 15:05:18 +01003248 """Method to verify requested av zone is present or not in provided
3249 resource pool
sbhangarea8e5b782018-06-21 02:10:03 -07003250
sousaedu2ad85172021-02-17 15:05:18 +01003251 Args:
3252 az - name of hostgroup (availibility_zone)
3253 respool_href - Resource Pool href
3254 headers - Headers to make REST call
3255 Returns:
3256 az_found - True if availibility_zone is found else False
sbhangarea8e5b782018-06-21 02:10:03 -07003257 """
3258 az_found = False
sousaedu2ad85172021-02-17 15:05:18 +01003259 headers["Accept"] = "application/*+xml;version=27.0"
3260 resp = self.perform_request(req_type="GET", url=respool_href, headers=headers)
sbhangarea8e5b782018-06-21 02:10:03 -07003261
3262 if resp.status_code != requests.codes.ok:
sousaedu2ad85172021-02-17 15:05:18 +01003263 self.logger.debug(
3264 "REST API call {} failed. Return status code {}".format(
3265 respool_href, resp.status_code
3266 )
3267 )
sbhangarea8e5b782018-06-21 02:10:03 -07003268 else:
beierlb22ce2d2019-12-12 12:09:51 -05003269 # Get the href to hostGroups and find provided hostGroup is present in it
sbhangarea8e5b782018-06-21 02:10:03 -07003270 resp_xml = XmlElementTree.fromstring(resp.content)
3271
3272 for child in resp_xml:
sousaedu2ad85172021-02-17 15:05:18 +01003273 if "VMWProviderVdcResourcePool" in child.tag:
sbhangarea8e5b782018-06-21 02:10:03 -07003274 for schild in child:
sousaedu2ad85172021-02-17 15:05:18 +01003275 if "Link" in schild.tag:
3276 if (
3277 schild.attrib.get("type")
3278 == "application/vnd.vmware.admin.vmwHostGroupsType+xml"
3279 ):
3280 hostGroup_href = schild.attrib.get("href")
3281 hg_resp = self.perform_request(
3282 req_type="GET", url=hostGroup_href, headers=headers
3283 )
3284
sbhangarea8e5b782018-06-21 02:10:03 -07003285 if hg_resp.status_code != requests.codes.ok:
beierlb22ce2d2019-12-12 12:09:51 -05003286 self.logger.debug(
sousaedu2ad85172021-02-17 15:05:18 +01003287 "REST API call {} failed. Return status code {}".format(
3288 hostGroup_href, hg_resp.status_code
3289 )
3290 )
sbhangarea8e5b782018-06-21 02:10:03 -07003291 else:
sousaedu2ad85172021-02-17 15:05:18 +01003292 hg_resp_xml = XmlElementTree.fromstring(
3293 hg_resp.content
3294 )
sbhangarea8e5b782018-06-21 02:10:03 -07003295 for hostGroup in hg_resp_xml:
sousaedu2ad85172021-02-17 15:05:18 +01003296 if "HostGroup" in hostGroup.tag:
sbhangarea8e5b782018-06-21 02:10:03 -07003297 if hostGroup.attrib.get("name") == az:
3298 az_found = True
3299 break
sousaedu2ad85172021-02-17 15:05:18 +01003300
sbhangarea8e5b782018-06-21 02:10:03 -07003301 return az_found
3302
sbhangarea8e5b782018-06-21 02:10:03 -07003303 def get_pvdc_for_org(self, org_vdc, headers):
sousaedu2ad85172021-02-17 15:05:18 +01003304 """This method gets provider vdc references from organisation
sbhangarea8e5b782018-06-21 02:10:03 -07003305
sousaedu2ad85172021-02-17 15:05:18 +01003306 Args:
3307 org_vdc - name of the organisation VDC to find pvdc
3308 headers - headers to make REST call
sbhangarea8e5b782018-06-21 02:10:03 -07003309
sousaedu2ad85172021-02-17 15:05:18 +01003310 Returns:
3311 None - if no pvdc href found else
3312 pvdc_href - href to pvdc
sbhangarea8e5b782018-06-21 02:10:03 -07003313 """
beierlb22ce2d2019-12-12 12:09:51 -05003314 # Get provider VDC references from vCD
sbhangarea8e5b782018-06-21 02:10:03 -07003315 pvdc_href = None
beierlb22ce2d2019-12-12 12:09:51 -05003316 # url = '<vcd url>/api/admin/extension/providerVdcReferences'
sousaedu2ad85172021-02-17 15:05:18 +01003317 url_list = [self.url, "/api/admin/extension/providerVdcReferences"]
3318 url = "".join(url_list)
sbhangarea8e5b782018-06-21 02:10:03 -07003319
sousaedu2ad85172021-02-17 15:05:18 +01003320 response = self.perform_request(req_type="GET", url=url, headers=headers)
sbhangarea8e5b782018-06-21 02:10:03 -07003321 if response.status_code != requests.codes.ok:
sousaedu2ad85172021-02-17 15:05:18 +01003322 self.logger.debug(
3323 "REST API call {} failed. Return status code {}".format(
3324 url, response.status_code
3325 )
3326 )
sbhangarea8e5b782018-06-21 02:10:03 -07003327 else:
beierl26fec002019-12-06 17:06:40 -05003328 xmlroot_response = XmlElementTree.fromstring(response.text)
sbhangarea8e5b782018-06-21 02:10:03 -07003329 for child in xmlroot_response:
sousaedu2ad85172021-02-17 15:05:18 +01003330 if "ProviderVdcReference" in child.tag:
3331 pvdc_href = child.attrib.get("href")
beierlb22ce2d2019-12-12 12:09:51 -05003332 # Get vdcReferences to find org
sousaedu2ad85172021-02-17 15:05:18 +01003333 pvdc_resp = self.perform_request(
3334 req_type="GET", url=pvdc_href, headers=headers
3335 )
3336
sbhangarea8e5b782018-06-21 02:10:03 -07003337 if pvdc_resp.status_code != requests.codes.ok:
sousaedu2ad85172021-02-17 15:05:18 +01003338 raise vimconn.VimConnException(
3339 "REST API call {} failed. "
3340 "Return status code {}".format(url, pvdc_resp.status_code)
3341 )
sbhangarea8e5b782018-06-21 02:10:03 -07003342
3343 pvdc_resp_xml = XmlElementTree.fromstring(pvdc_resp.content)
3344 for child in pvdc_resp_xml:
sousaedu2ad85172021-02-17 15:05:18 +01003345 if "Link" in child.tag:
3346 if (
3347 child.attrib.get("type")
3348 == "application/vnd.vmware.admin.vdcReferences+xml"
3349 ):
3350 vdc_href = child.attrib.get("href")
sbhangarea8e5b782018-06-21 02:10:03 -07003351
beierlb22ce2d2019-12-12 12:09:51 -05003352 # Check if provided org is present in vdc
sousaedu2ad85172021-02-17 15:05:18 +01003353 vdc_resp = self.perform_request(
3354 req_type="GET", url=vdc_href, headers=headers
3355 )
3356
sbhangarea8e5b782018-06-21 02:10:03 -07003357 if vdc_resp.status_code != requests.codes.ok:
sousaedu2ad85172021-02-17 15:05:18 +01003358 raise vimconn.VimConnException(
3359 "REST API call {} failed. "
3360 "Return status code {}".format(
3361 url, vdc_resp.status_code
3362 )
3363 )
3364 vdc_resp_xml = XmlElementTree.fromstring(
3365 vdc_resp.content
3366 )
3367
sbhangarea8e5b782018-06-21 02:10:03 -07003368 for child in vdc_resp_xml:
sousaedu2ad85172021-02-17 15:05:18 +01003369 if "VdcReference" in child.tag:
3370 if child.attrib.get("name") == org_vdc:
sbhangarea8e5b782018-06-21 02:10:03 -07003371 return pvdc_href
3372
sbhangarea8e5b782018-06-21 02:10:03 -07003373 def get_resource_pool_details(self, pvdc_href, headers):
sousaedu2ad85172021-02-17 15:05:18 +01003374 """Method to get resource pool information.
3375 Host groups are property of resource group.
3376 To get host groups, we need to GET details of resource pool.
sbhangarea8e5b782018-06-21 02:10:03 -07003377
sousaedu2ad85172021-02-17 15:05:18 +01003378 Args:
3379 pvdc_href: href to pvdc details
3380 headers: headers
sbhangarea8e5b782018-06-21 02:10:03 -07003381
sousaedu2ad85172021-02-17 15:05:18 +01003382 Returns:
3383 respool_href - Returns href link reference to resource pool
sbhangarea8e5b782018-06-21 02:10:03 -07003384 """
3385 respool_href = None
sousaedu2ad85172021-02-17 15:05:18 +01003386 resp = self.perform_request(req_type="GET", url=pvdc_href, headers=headers)
sbhangarea8e5b782018-06-21 02:10:03 -07003387
3388 if resp.status_code != requests.codes.ok:
sousaedu2ad85172021-02-17 15:05:18 +01003389 self.logger.debug(
3390 "REST API call {} failed. Return status code {}".format(
3391 pvdc_href, resp.status_code
3392 )
3393 )
sbhangarea8e5b782018-06-21 02:10:03 -07003394 else:
3395 respool_resp_xml = XmlElementTree.fromstring(resp.content)
3396 for child in respool_resp_xml:
sousaedu2ad85172021-02-17 15:05:18 +01003397 if "Link" in child.tag:
3398 if (
3399 child.attrib.get("type")
3400 == "application/vnd.vmware.admin.vmwProviderVdcResourcePoolSet+xml"
3401 ):
sbhangarea8e5b782018-06-21 02:10:03 -07003402 respool_href = child.attrib.get("href")
3403 break
sousaedu2ad85172021-02-17 15:05:18 +01003404
sbhangarea8e5b782018-06-21 02:10:03 -07003405 return respool_href
3406
sbhangarea8e5b782018-06-21 02:10:03 -07003407 def log_message(self, msg):
3408 """
sousaedu2ad85172021-02-17 15:05:18 +01003409 Method to log error messages related to Affinity rule creation
3410 in new_vminstance & raise Exception
3411 Args :
3412 msg - Error message to be logged
sbhangarea8e5b782018-06-21 02:10:03 -07003413
3414 """
beierlb22ce2d2019-12-12 12:09:51 -05003415 # get token to connect vCD as a normal user
sbhangarea8e5b782018-06-21 02:10:03 -07003416 self.get_token()
3417 self.logger.debug(msg)
sousaedu2ad85172021-02-17 15:05:18 +01003418
tierno72774862020-05-04 11:44:15 +00003419 raise vimconn.VimConnException(msg)
sbhangarea8e5b782018-06-21 02:10:03 -07003420
beierlb22ce2d2019-12-12 12:09:51 -05003421 # #
3422 # #
3423 # # based on current discussion
3424 # #
3425 # #
3426 # # server:
bayramovef390722016-09-27 03:34:46 -07003427 # created: '2016-09-08T11:51:58'
3428 # description: simple-instance.linux1.1
3429 # flavor: ddc6776e-75a9-11e6-ad5f-0800273e724c
3430 # hostId: e836c036-74e7-11e6-b249-0800273e724c
3431 # image: dde30fe6-75a9-11e6-ad5f-0800273e724c
3432 # status: ACTIVE
3433 # error_msg:
3434 # interfaces: …
3435 #
bayramovfe3f3c92016-10-04 07:53:41 +04003436 def get_vminstance(self, vim_vm_uuid=None):
bayramov5761ad12016-10-04 09:00:30 +04003437 """Returns the VM instance information from VIM"""
bayramovef390722016-09-27 03:34:46 -07003438 self.logger.debug("Client requesting vm instance {} ".format(vim_vm_uuid))
bayramov325fa1c2016-09-08 01:42:46 -07003439
beierlb22ce2d2019-12-12 12:09:51 -05003440 _, vdc = self.get_vdc_details()
bayramovef390722016-09-27 03:34:46 -07003441 if vdc is None:
tierno72774862020-05-04 11:44:15 +00003442 raise vimconn.VimConnConnectionException(
sousaedu2ad85172021-02-17 15:05:18 +01003443 "Failed to get a reference of VDC for a tenant {}".format(
3444 self.tenant_name
3445 )
3446 )
bayramov325fa1c2016-09-08 01:42:46 -07003447
bayramovfe3f3c92016-10-04 07:53:41 +04003448 vm_info_dict = self.get_vapp_details_rest(vapp_uuid=vim_vm_uuid)
3449 if not vm_info_dict:
sousaedu2ad85172021-02-17 15:05:18 +01003450 self.logger.debug(
3451 "get_vminstance(): Failed to get vApp name by UUID {}".format(
3452 vim_vm_uuid
3453 )
3454 )
3455 raise vimconn.VimConnNotFoundException(
3456 "Failed to get vApp name by UUID {}".format(vim_vm_uuid)
3457 )
bayramov325fa1c2016-09-08 01:42:46 -07003458
sousaedu2ad85172021-02-17 15:05:18 +01003459 status_key = vm_info_dict["status"]
3460 error = ""
bayramovef390722016-09-27 03:34:46 -07003461 try:
sousaedu2ad85172021-02-17 15:05:18 +01003462 vm_dict = {
3463 "created": vm_info_dict["created"],
3464 "description": vm_info_dict["name"],
3465 "status": vcdStatusCode2manoFormat[int(status_key)],
3466 "hostId": vm_info_dict["vmuuid"],
3467 "error_msg": error,
3468 "vim_info": yaml.safe_dump(vm_info_dict),
3469 "interfaces": [],
3470 }
bayramovef390722016-09-27 03:34:46 -07003471
sousaedu2ad85172021-02-17 15:05:18 +01003472 if "interfaces" in vm_info_dict:
3473 vm_dict["interfaces"] = vm_info_dict["interfaces"]
bayramovfe3f3c92016-10-04 07:53:41 +04003474 else:
sousaedu2ad85172021-02-17 15:05:18 +01003475 vm_dict["interfaces"] = []
bayramovfe3f3c92016-10-04 07:53:41 +04003476 except KeyError:
sousaedu2ad85172021-02-17 15:05:18 +01003477 vm_dict = {
3478 "created": "",
3479 "description": "",
3480 "status": vcdStatusCode2manoFormat[int(-1)],
3481 "hostId": vm_info_dict["vmuuid"],
3482 "error_msg": "Inconsistency state",
3483 "vim_info": yaml.safe_dump(vm_info_dict),
3484 "interfaces": [],
3485 }
bayramovef390722016-09-27 03:34:46 -07003486
3487 return vm_dict
3488
tierno98e909c2017-10-14 13:27:03 +02003489 def delete_vminstance(self, vm__vim_uuid, created_items=None):
bayramovef390722016-09-27 03:34:46 -07003490 """Method poweroff and remove VM instance from vcloud director network.
3491
3492 Args:
3493 vm__vim_uuid: VM UUID
3494
3495 Returns:
3496 Returns the instance identifier
3497 """
sousaedu2ad85172021-02-17 15:05:18 +01003498 self.logger.debug(
3499 "Client requesting delete vm instance {} ".format(vm__vim_uuid)
3500 )
bayramov325fa1c2016-09-08 01:42:46 -07003501
beierl01bd6692019-12-09 17:06:20 -05003502 _, vdc = self.get_vdc_details()
sousaedu2ad85172021-02-17 15:05:18 +01003503 vdc_obj = VDC(self.client, href=vdc.get("href"))
kasarc5bf2932018-03-09 04:15:22 -08003504 if vdc_obj is None:
sousaedu2ad85172021-02-17 15:05:18 +01003505 self.logger.debug(
3506 "delete_vminstance(): Failed to get a reference of VDC for a tenant {}".format(
3507 self.tenant_name
3508 )
3509 )
tierno72774862020-05-04 11:44:15 +00003510 raise vimconn.VimConnException(
sousaedu2ad85172021-02-17 15:05:18 +01003511 "delete_vminstance(): Failed to get a reference of VDC for a tenant {}".format(
3512 self.tenant_name
3513 )
3514 )
bayramov325fa1c2016-09-08 01:42:46 -07003515
bayramovef390722016-09-27 03:34:46 -07003516 try:
kasarc5bf2932018-03-09 04:15:22 -08003517 vapp_name = self.get_namebyvappid(vm__vim_uuid)
bayramovef390722016-09-27 03:34:46 -07003518 if vapp_name is None:
sousaedu2ad85172021-02-17 15:05:18 +01003519 self.logger.debug(
3520 "delete_vminstance(): Failed to get vm by given {} vm uuid".format(
3521 vm__vim_uuid
3522 )
3523 )
3524
3525 return (
3526 -1,
3527 "delete_vminstance(): Failed to get vm by given {} vm uuid".format(
3528 vm__vim_uuid
3529 ),
3530 )
3531
3532 self.logger.info(
3533 "Deleting vApp {} and UUID {}".format(vapp_name, vm__vim_uuid)
3534 )
Ravi Chamarty41840092018-10-31 16:12:38 +00003535 vapp_resource = vdc_obj.get_vapp(vapp_name)
3536 vapp = VApp(self.client, resource=vapp_resource)
bayramov325fa1c2016-09-08 01:42:46 -07003537
bayramovef390722016-09-27 03:34:46 -07003538 # Delete vApp and wait for status change if task executed and vApp is None.
kate13ab2c42016-12-23 01:34:24 -08003539 if vapp:
sousaedu2ad85172021-02-17 15:05:18 +01003540 if vapp_resource.get("deployed") == "true":
kate13ab2c42016-12-23 01:34:24 -08003541 self.logger.info("Powering off vApp {}".format(vapp_name))
beierl01bd6692019-12-09 17:06:20 -05003542 # Power off vApp
kate13ab2c42016-12-23 01:34:24 -08003543 powered_off = False
3544 wait_time = 0
sousaedu2ad85172021-02-17 15:05:18 +01003545
kate13ab2c42016-12-23 01:34:24 -08003546 while wait_time <= MAX_WAIT_TIME:
kasarc5bf2932018-03-09 04:15:22 -08003547 power_off_task = vapp.power_off()
sousaedu2ad85172021-02-17 15:05:18 +01003548 result = self.client.get_task_monitor().wait_for_success(
3549 task=power_off_task
3550 )
bayramovef390722016-09-27 03:34:46 -07003551
sousaedu2ad85172021-02-17 15:05:18 +01003552 if result.get("status") == "success":
kasarc5bf2932018-03-09 04:15:22 -08003553 powered_off = True
3554 break
kate13ab2c42016-12-23 01:34:24 -08003555 else:
sousaedu2ad85172021-02-17 15:05:18 +01003556 self.logger.info(
3557 "Wait for vApp {} to power off".format(vapp_name)
3558 )
kate13ab2c42016-12-23 01:34:24 -08003559 time.sleep(INTERVAL_TIME)
3560
beierl01bd6692019-12-09 17:06:20 -05003561 wait_time += INTERVAL_TIME
sousaedu2ad85172021-02-17 15:05:18 +01003562
kate13ab2c42016-12-23 01:34:24 -08003563 if not powered_off:
beierl01bd6692019-12-09 17:06:20 -05003564 self.logger.debug(
sousaedu2ad85172021-02-17 15:05:18 +01003565 "delete_vminstance(): Failed to power off VM instance {} ".format(
3566 vm__vim_uuid
3567 )
3568 )
kate13ab2c42016-12-23 01:34:24 -08003569 else:
sousaedu2ad85172021-02-17 15:05:18 +01003570 self.logger.info(
3571 "delete_vminstance(): Powered off VM instance {} ".format(
3572 vm__vim_uuid
3573 )
3574 )
kate13ab2c42016-12-23 01:34:24 -08003575
beierl01bd6692019-12-09 17:06:20 -05003576 # Undeploy vApp
kate13ab2c42016-12-23 01:34:24 -08003577 self.logger.info("Undeploy vApp {}".format(vapp_name))
3578 wait_time = 0
3579 undeployed = False
3580 while wait_time <= MAX_WAIT_TIME:
sbhangarea8e5b782018-06-21 02:10:03 -07003581 vapp = VApp(self.client, resource=vapp_resource)
kate13ab2c42016-12-23 01:34:24 -08003582 if not vapp:
beierl01bd6692019-12-09 17:06:20 -05003583 self.logger.debug(
sousaedu2ad85172021-02-17 15:05:18 +01003584 "delete_vminstance(): Failed to get vm by given {} vm uuid".format(
3585 vm__vim_uuid
3586 )
3587 )
kate13ab2c42016-12-23 01:34:24 -08003588
sousaedu2ad85172021-02-17 15:05:18 +01003589 return (
3590 -1,
3591 "delete_vminstance(): Failed to get vm by given {} vm uuid".format(
3592 vm__vim_uuid
3593 ),
3594 )
3595
3596 undeploy_task = vapp.undeploy()
3597 result = self.client.get_task_monitor().wait_for_success(
3598 task=undeploy_task
3599 )
3600
3601 if result.get("status") == "success":
kasarc5bf2932018-03-09 04:15:22 -08003602 undeployed = True
3603 break
kate13ab2c42016-12-23 01:34:24 -08003604 else:
sousaedu2ad85172021-02-17 15:05:18 +01003605 self.logger.debug(
3606 "Wait for vApp {} to undeploy".format(vapp_name)
3607 )
kate13ab2c42016-12-23 01:34:24 -08003608 time.sleep(INTERVAL_TIME)
3609
beierl01bd6692019-12-09 17:06:20 -05003610 wait_time += INTERVAL_TIME
kate13ab2c42016-12-23 01:34:24 -08003611
3612 if not undeployed:
sousaedu2ad85172021-02-17 15:05:18 +01003613 self.logger.debug(
3614 "delete_vminstance(): Failed to undeploy vApp {} ".format(
3615 vm__vim_uuid
3616 )
3617 )
kate13ab2c42016-12-23 01:34:24 -08003618
3619 # delete vapp
3620 self.logger.info("Start deletion of vApp {} ".format(vapp_name))
kate13ab2c42016-12-23 01:34:24 -08003621 if vapp is not None:
3622 wait_time = 0
3623 result = False
3624
3625 while wait_time <= MAX_WAIT_TIME:
kasarc5bf2932018-03-09 04:15:22 -08003626 vapp = VApp(self.client, resource=vapp_resource)
kate13ab2c42016-12-23 01:34:24 -08003627 if not vapp:
beierl01bd6692019-12-09 17:06:20 -05003628 self.logger.debug(
sousaedu2ad85172021-02-17 15:05:18 +01003629 "delete_vminstance(): Failed to get vm by given {} vm uuid".format(
3630 vm__vim_uuid
3631 )
3632 )
3633
3634 return (
3635 -1,
3636 "delete_vminstance(): Failed to get vm by given {} vm uuid".format(
3637 vm__vim_uuid
3638 ),
3639 )
kate13ab2c42016-12-23 01:34:24 -08003640
kasarc5bf2932018-03-09 04:15:22 -08003641 delete_task = vdc_obj.delete_vapp(vapp.name, force=True)
sousaedu2ad85172021-02-17 15:05:18 +01003642 result = self.client.get_task_monitor().wait_for_success(
3643 task=delete_task
3644 )
3645 if result.get("status") == "success":
kasarc5bf2932018-03-09 04:15:22 -08003646 break
kate13ab2c42016-12-23 01:34:24 -08003647 else:
sousaedu2ad85172021-02-17 15:05:18 +01003648 self.logger.debug(
3649 "Wait for vApp {} to delete".format(vapp_name)
3650 )
kate13ab2c42016-12-23 01:34:24 -08003651 time.sleep(INTERVAL_TIME)
3652
beierl01bd6692019-12-09 17:06:20 -05003653 wait_time += INTERVAL_TIME
kate13ab2c42016-12-23 01:34:24 -08003654
kasarc5bf2932018-03-09 04:15:22 -08003655 if result is None:
sousaedu2ad85172021-02-17 15:05:18 +01003656 self.logger.debug(
3657 "delete_vminstance(): Failed delete uuid {} ".format(
3658 vm__vim_uuid
3659 )
3660 )
kasarc5bf2932018-03-09 04:15:22 -08003661 else:
sousaedu2ad85172021-02-17 15:05:18 +01003662 self.logger.info(
3663 "Deleted vm instance {} sccessfully".format(vm__vim_uuid)
3664 )
3665 config_drive_catalog_name, config_drive_catalog_id = (
3666 "cfg_drv-" + vm__vim_uuid,
3667 None,
3668 )
Ananda Baitharu319c26f2019-03-05 17:34:31 +00003669 catalog_list = self.get_image_list()
sousaedu2ad85172021-02-17 15:05:18 +01003670
Ananda Baitharu319c26f2019-03-05 17:34:31 +00003671 try:
sousaedu2ad85172021-02-17 15:05:18 +01003672 config_drive_catalog_id = [
3673 catalog_["id"]
3674 for catalog_ in catalog_list
3675 if catalog_["name"] == config_drive_catalog_name
3676 ][0]
Ananda Baitharu319c26f2019-03-05 17:34:31 +00003677 except IndexError:
3678 pass
sousaedu2ad85172021-02-17 15:05:18 +01003679
Ananda Baitharu319c26f2019-03-05 17:34:31 +00003680 if config_drive_catalog_id:
sousaedu2ad85172021-02-17 15:05:18 +01003681 self.logger.debug(
3682 "delete_vminstance(): Found a config drive catalog {} matching "
3683 'vapp_name"{}". Deleting it.'.format(
3684 config_drive_catalog_id, vapp_name
3685 )
3686 )
Ananda Baitharu319c26f2019-03-05 17:34:31 +00003687 self.delete_image(config_drive_catalog_id)
sousaedu2ad85172021-02-17 15:05:18 +01003688
kasarc5bf2932018-03-09 04:15:22 -08003689 return vm__vim_uuid
beierl01bd6692019-12-09 17:06:20 -05003690 except Exception:
bayramovef390722016-09-27 03:34:46 -07003691 self.logger.debug(traceback.format_exc())
sousaedu2ad85172021-02-17 15:05:18 +01003692
3693 raise vimconn.VimConnException(
3694 "delete_vminstance(): Failed delete vm instance {}".format(vm__vim_uuid)
3695 )
bayramovef390722016-09-27 03:34:46 -07003696
bayramov325fa1c2016-09-08 01:42:46 -07003697 def refresh_vms_status(self, vm_list):
bayramovef390722016-09-27 03:34:46 -07003698 """Get the status of the virtual machines and their interfaces/ports
sousaedu2ad85172021-02-17 15:05:18 +01003699 Params: the list of VM identifiers
3700 Returns a dictionary with:
3701 vm_id: #VIM id of this Virtual Machine
3702 status: #Mandatory. Text with one of:
3703 # DELETED (not found at vim)
3704 # VIM_ERROR (Cannot connect to VIM, VIM response error, ...)
3705 # OTHER (Vim reported other status not understood)
3706 # ERROR (VIM indicates an ERROR status)
3707 # ACTIVE, PAUSED, SUSPENDED, INACTIVE (not running),
3708 # CREATING (on building process), ERROR
3709 # ACTIVE:NoMgmtIP (Active but any of its interface has an IP address
3710 #
3711 error_msg: #Text with VIM error message, if any. Or the VIM connection ERROR
3712 vim_info: #Text with plain information obtained from vim (yaml.safe_dump)
3713 interfaces:
3714 - vim_info: #Text with plain information obtained from vim (yaml.safe_dump)
3715 mac_address: #Text format XX:XX:XX:XX:XX:XX
3716 vim_net_id: #network id where this interface is connected
3717 vim_interface_id: #interface/port VIM id
3718 ip_address: #null, or text with IPv4, IPv6 address
bayramovef390722016-09-27 03:34:46 -07003719 """
bayramovef390722016-09-27 03:34:46 -07003720 self.logger.debug("Client requesting refresh vm status for {} ".format(vm_list))
bhangare985a1fd2017-01-31 01:53:21 -08003721
beierlb22ce2d2019-12-12 12:09:51 -05003722 _, vdc = self.get_vdc_details()
bayramovef390722016-09-27 03:34:46 -07003723 if vdc is None:
sousaedu2ad85172021-02-17 15:05:18 +01003724 raise vimconn.VimConnException(
3725 "Failed to get a reference of VDC for a tenant {}".format(
3726 self.tenant_name
3727 )
3728 )
bayramovef390722016-09-27 03:34:46 -07003729
3730 vms_dict = {}
kasarde691232017-03-25 03:37:31 -07003731 nsx_edge_list = []
bayramovef390722016-09-27 03:34:46 -07003732 for vmuuid in vm_list:
kasarc5bf2932018-03-09 04:15:22 -08003733 vapp_name = self.get_namebyvappid(vmuuid)
3734 if vapp_name is not None:
bayramovef390722016-09-27 03:34:46 -07003735 try:
bhangare1a0b97c2017-06-21 02:20:15 -07003736 vm_pci_details = self.get_vm_pci_details(vmuuid)
sousaedu2ad85172021-02-17 15:05:18 +01003737 vdc_obj = VDC(self.client, href=vdc.get("href"))
kasarc5bf2932018-03-09 04:15:22 -08003738 vapp_resource = vdc_obj.get_vapp(vapp_name)
3739 the_vapp = VApp(self.client, resource=vapp_resource)
bhangarebfdca492017-03-11 01:32:46 -08003740
kasarc5bf2932018-03-09 04:15:22 -08003741 vm_details = {}
3742 for vm in the_vapp.get_all_vms():
sousaedu2ad85172021-02-17 15:05:18 +01003743 headers = {
3744 "Accept": "application/*+xml;version=" + API_VERSION,
3745 "x-vcloud-authorization": self.client._session.headers[
3746 "x-vcloud-authorization"
3747 ],
3748 }
3749 response = self.perform_request(
3750 req_type="GET", url=vm.get("href"), headers=headers
3751 )
bhangarebfdca492017-03-11 01:32:46 -08003752
kasarc5bf2932018-03-09 04:15:22 -08003753 if response.status_code != 200:
sousaedu2ad85172021-02-17 15:05:18 +01003754 self.logger.error(
3755 "refresh_vms_status : REST call {} failed reason : {}"
3756 "status code : {}".format(
3757 vm.get("href"), response.text, response.status_code
3758 )
3759 )
3760 raise vimconn.VimConnException(
3761 "refresh_vms_status : Failed to get VM details"
3762 )
kasarde691232017-03-25 03:37:31 -07003763
sousaedu2ad85172021-02-17 15:05:18 +01003764 xmlroot = XmlElementTree.fromstring(response.text)
beierl26fec002019-12-06 17:06:40 -05003765 result = response.text.replace("\n", " ")
beierlb22ce2d2019-12-12 12:09:51 -05003766 hdd_match = re.search(
sousaedu2ad85172021-02-17 15:05:18 +01003767 'vcloud:capacity="(\d+)"\svcloud:storageProfileOverrideVmDefault=',
3768 result,
3769 )
3770
Ravi Chamarty1fdf9992018-10-07 15:45:44 +00003771 if hdd_match:
3772 hdd_mb = hdd_match.group(1)
sousaedu2ad85172021-02-17 15:05:18 +01003773 vm_details["hdd_mb"] = int(hdd_mb) if hdd_mb else None
3774
beierlb22ce2d2019-12-12 12:09:51 -05003775 cpus_match = re.search(
sousaedu2ad85172021-02-17 15:05:18 +01003776 "<rasd:Description>Number of Virtual CPUs</.*?>(\d+)</rasd:VirtualQuantity>",
3777 result,
3778 )
3779
Ravi Chamarty1fdf9992018-10-07 15:45:44 +00003780 if cpus_match:
3781 cpus = cpus_match.group(1)
sousaedu2ad85172021-02-17 15:05:18 +01003782 vm_details["cpus"] = int(cpus) if cpus else None
3783
beierlb22ce2d2019-12-12 12:09:51 -05003784 memory_mb = re.search(
sousaedu2ad85172021-02-17 15:05:18 +01003785 "<rasd:Description>Memory Size</.*?>(\d+)</rasd:VirtualQuantity>",
3786 result,
3787 ).group(1)
3788 vm_details["memory_mb"] = int(memory_mb) if memory_mb else None
3789 vm_details["status"] = vcdStatusCode2manoFormat[
3790 int(xmlroot.get("status"))
3791 ]
3792 vm_details["id"] = xmlroot.get("id")
3793 vm_details["name"] = xmlroot.get("name")
kasarc5bf2932018-03-09 04:15:22 -08003794 vm_info = [vm_details]
sousaedu2ad85172021-02-17 15:05:18 +01003795
kasarc5bf2932018-03-09 04:15:22 -08003796 if vm_pci_details:
sbhangarea8e5b782018-06-21 02:10:03 -07003797 vm_info[0].update(vm_pci_details)
kasarc5bf2932018-03-09 04:15:22 -08003798
sousaedu2ad85172021-02-17 15:05:18 +01003799 vm_dict = {
3800 "status": vcdStatusCode2manoFormat[
3801 int(vapp_resource.get("status"))
3802 ],
3803 "error_msg": vcdStatusCode2manoFormat[
3804 int(vapp_resource.get("status"))
3805 ],
3806 "vim_info": yaml.safe_dump(vm_info),
3807 "interfaces": [],
3808 }
kasarc5bf2932018-03-09 04:15:22 -08003809
3810 # get networks
sbhangarea8e5b782018-06-21 02:10:03 -07003811 vm_ip = None
kasar1b7b9522018-05-15 06:15:07 -07003812 vm_mac = None
sousaedu2ad85172021-02-17 15:05:18 +01003813 networks = re.findall(
3814 "<NetworkConnection needsCustomization=.*?</NetworkConnection>",
3815 result,
3816 )
3817
kasar1b7b9522018-05-15 06:15:07 -07003818 for network in networks:
sousaedu2ad85172021-02-17 15:05:18 +01003819 mac_s = re.search("<MACAddress>(.*?)</MACAddress>", network)
kasar1b7b9522018-05-15 06:15:07 -07003820 vm_mac = mac_s.group(1) if mac_s else None
sousaedu2ad85172021-02-17 15:05:18 +01003821 ip_s = re.search("<IpAddress>(.*?)</IpAddress>", network)
kasar1b7b9522018-05-15 06:15:07 -07003822 vm_ip = ip_s.group(1) if ip_s else None
kasarc5bf2932018-03-09 04:15:22 -08003823
kasar1b7b9522018-05-15 06:15:07 -07003824 if vm_ip is None:
3825 if not nsx_edge_list:
3826 nsx_edge_list = self.get_edge_details()
3827 if nsx_edge_list is None:
sousaedu2ad85172021-02-17 15:05:18 +01003828 raise vimconn.VimConnException(
3829 "refresh_vms_status:"
3830 "Failed to get edge details from NSX Manager"
3831 )
3832
kasar1b7b9522018-05-15 06:15:07 -07003833 if vm_mac is not None:
sousaedu2ad85172021-02-17 15:05:18 +01003834 vm_ip = self.get_ipaddr_from_NSXedge(
3835 nsx_edge_list, vm_mac
3836 )
kasarc5bf2932018-03-09 04:15:22 -08003837
beierlb22ce2d2019-12-12 12:09:51 -05003838 net_s = re.search('network="(.*?)"', network)
kasarabac1e22018-05-17 02:44:39 -07003839 network_name = net_s.group(1) if net_s else None
kasar1b7b9522018-05-15 06:15:07 -07003840 vm_net_id = self.get_network_id_by_name(network_name)
sousaedu2ad85172021-02-17 15:05:18 +01003841 interface = {
3842 "mac_address": vm_mac,
3843 "vim_net_id": vm_net_id,
3844 "vim_interface_id": vm_net_id,
3845 "ip_address": vm_ip,
3846 }
kasar1b7b9522018-05-15 06:15:07 -07003847 vm_dict["interfaces"].append(interface)
kasarc5bf2932018-03-09 04:15:22 -08003848
bayramovef390722016-09-27 03:34:46 -07003849 # add a vm to vm dict
3850 vms_dict.setdefault(vmuuid, vm_dict)
kasarc5bf2932018-03-09 04:15:22 -08003851 self.logger.debug("refresh_vms_status : vm info {}".format(vm_dict))
bhangarebfdca492017-03-11 01:32:46 -08003852 except Exception as exp:
3853 self.logger.debug("Error in response {}".format(exp))
bayramovef390722016-09-27 03:34:46 -07003854 self.logger.debug(traceback.format_exc())
3855
3856 return vms_dict
3857
kasarde691232017-03-25 03:37:31 -07003858 def get_edge_details(self):
3859 """Get the NSX edge list from NSX Manager
sousaedu2ad85172021-02-17 15:05:18 +01003860 Returns list of NSX edges
kasarde691232017-03-25 03:37:31 -07003861 """
3862 edge_list = []
sousaedu2ad85172021-02-17 15:05:18 +01003863 rheaders = {"Content-Type": "application/xml"}
3864 nsx_api_url = "/api/4.0/edges"
kasarde691232017-03-25 03:37:31 -07003865
sousaedu2ad85172021-02-17 15:05:18 +01003866 self.logger.debug(
3867 "Get edge details from NSX Manager {} {}".format(
3868 self.nsx_manager, nsx_api_url
3869 )
3870 )
kasarde691232017-03-25 03:37:31 -07003871
3872 try:
sousaedu2ad85172021-02-17 15:05:18 +01003873 resp = requests.get(
3874 self.nsx_manager + nsx_api_url,
3875 auth=(self.nsx_user, self.nsx_password),
3876 verify=False,
3877 headers=rheaders,
3878 )
kasarde691232017-03-25 03:37:31 -07003879 if resp.status_code == requests.codes.ok:
3880 paged_Edge_List = XmlElementTree.fromstring(resp.text)
3881 for edge_pages in paged_Edge_List:
sousaedu2ad85172021-02-17 15:05:18 +01003882 if edge_pages.tag == "edgePage":
kasarde691232017-03-25 03:37:31 -07003883 for edge_summary in edge_pages:
sousaedu2ad85172021-02-17 15:05:18 +01003884 if edge_summary.tag == "pagingInfo":
kasarde691232017-03-25 03:37:31 -07003885 for element in edge_summary:
sousaedu2ad85172021-02-17 15:05:18 +01003886 if (
3887 element.tag == "totalCount"
3888 and element.text == "0"
3889 ):
tierno72774862020-05-04 11:44:15 +00003890 raise vimconn.VimConnException(
sousaedu2ad85172021-02-17 15:05:18 +01003891 "get_edge_details: No NSX edges details found: {}".format(
3892 self.nsx_manager
3893 )
3894 )
kasarde691232017-03-25 03:37:31 -07003895
sousaedu2ad85172021-02-17 15:05:18 +01003896 if edge_summary.tag == "edgeSummary":
kasarde691232017-03-25 03:37:31 -07003897 for element in edge_summary:
sousaedu2ad85172021-02-17 15:05:18 +01003898 if element.tag == "id":
kasarde691232017-03-25 03:37:31 -07003899 edge_list.append(element.text)
3900 else:
sousaedu2ad85172021-02-17 15:05:18 +01003901 raise vimconn.VimConnException(
3902 "get_edge_details: No NSX edge details found: {}".format(
3903 self.nsx_manager
3904 )
3905 )
kasarde691232017-03-25 03:37:31 -07003906
3907 if not edge_list:
sousaedu2ad85172021-02-17 15:05:18 +01003908 raise vimconn.VimConnException(
3909 "get_edge_details: "
3910 "No NSX edge details found: {}".format(self.nsx_manager)
3911 )
kasarde691232017-03-25 03:37:31 -07003912 else:
sousaedu2ad85172021-02-17 15:05:18 +01003913 self.logger.debug(
3914 "get_edge_details: Found NSX edges {}".format(edge_list)
3915 )
3916
kasarde691232017-03-25 03:37:31 -07003917 return edge_list
3918 else:
sousaedu2ad85172021-02-17 15:05:18 +01003919 self.logger.debug(
3920 "get_edge_details: "
3921 "Failed to get NSX edge details from NSX Manager: {}".format(
3922 resp.content
3923 )
3924 )
3925
kasarde691232017-03-25 03:37:31 -07003926 return None
3927
3928 except Exception as exp:
sousaedu2ad85172021-02-17 15:05:18 +01003929 self.logger.debug(
3930 "get_edge_details: "
3931 "Failed to get NSX edge details from NSX Manager: {}".format(exp)
3932 )
3933 raise vimconn.VimConnException(
3934 "get_edge_details: "
3935 "Failed to get NSX edge details from NSX Manager: {}".format(exp)
3936 )
kasarde691232017-03-25 03:37:31 -07003937
kasarde691232017-03-25 03:37:31 -07003938 def get_ipaddr_from_NSXedge(self, nsx_edges, mac_address):
3939 """Get IP address details from NSX edges, using the MAC address
sousaedu2ad85172021-02-17 15:05:18 +01003940 PARAMS: nsx_edges : List of NSX edges
3941 mac_address : Find IP address corresponding to this MAC address
3942 Returns: IP address corrresponding to the provided MAC address
kasarde691232017-03-25 03:37:31 -07003943 """
kasarde691232017-03-25 03:37:31 -07003944 ip_addr = None
sousaedu2ad85172021-02-17 15:05:18 +01003945 rheaders = {"Content-Type": "application/xml"}
kasarde691232017-03-25 03:37:31 -07003946
3947 self.logger.debug("get_ipaddr_from_NSXedge: Finding IP addr from NSX edge")
3948
3949 try:
3950 for edge in nsx_edges:
sousaedu2ad85172021-02-17 15:05:18 +01003951 nsx_api_url = "/api/4.0/edges/" + edge + "/dhcp/leaseInfo"
kasarde691232017-03-25 03:37:31 -07003952
sousaedu2ad85172021-02-17 15:05:18 +01003953 resp = requests.get(
3954 self.nsx_manager + nsx_api_url,
3955 auth=(self.nsx_user, self.nsx_password),
3956 verify=False,
3957 headers=rheaders,
3958 )
kasarde691232017-03-25 03:37:31 -07003959
3960 if resp.status_code == requests.codes.ok:
3961 dhcp_leases = XmlElementTree.fromstring(resp.text)
3962 for child in dhcp_leases:
sousaedu2ad85172021-02-17 15:05:18 +01003963 if child.tag == "dhcpLeaseInfo":
kasarde691232017-03-25 03:37:31 -07003964 dhcpLeaseInfo = child
3965 for leaseInfo in dhcpLeaseInfo:
3966 for elem in leaseInfo:
sousaedu2ad85172021-02-17 15:05:18 +01003967 if (elem.tag) == "macAddress":
kasarde691232017-03-25 03:37:31 -07003968 edge_mac_addr = elem.text
sousaedu2ad85172021-02-17 15:05:18 +01003969
3970 if (elem.tag) == "ipAddress":
kasarde691232017-03-25 03:37:31 -07003971 ip_addr = elem.text
sousaedu2ad85172021-02-17 15:05:18 +01003972
kasarde691232017-03-25 03:37:31 -07003973 if edge_mac_addr is not None:
3974 if edge_mac_addr == mac_address:
sousaedu2ad85172021-02-17 15:05:18 +01003975 self.logger.debug(
3976 "Found ip addr {} for mac {} at NSX edge {}".format(
3977 ip_addr, mac_address, edge
3978 )
3979 )
3980
kasarde691232017-03-25 03:37:31 -07003981 return ip_addr
3982 else:
sousaedu2ad85172021-02-17 15:05:18 +01003983 self.logger.debug(
3984 "get_ipaddr_from_NSXedge: "
3985 "Error occurred while getting DHCP lease info from NSX Manager: {}".format(
3986 resp.content
3987 )
3988 )
kasarde691232017-03-25 03:37:31 -07003989
sousaedu2ad85172021-02-17 15:05:18 +01003990 self.logger.debug(
3991 "get_ipaddr_from_NSXedge: No IP addr found in any NSX edge"
3992 )
3993
kasarde691232017-03-25 03:37:31 -07003994 return None
3995
3996 except XmlElementTree.ParseError as Err:
sousaedu2ad85172021-02-17 15:05:18 +01003997 self.logger.debug(
3998 "ParseError in response from NSX Manager {}".format(Err.message),
3999 exc_info=True,
4000 )
kasarde691232017-03-25 03:37:31 -07004001
tierno98e909c2017-10-14 13:27:03 +02004002 def action_vminstance(self, vm__vim_uuid=None, action_dict=None, created_items={}):
bayramovef390722016-09-27 03:34:46 -07004003 """Send and action over a VM instance from VIM
4004 Returns the vm_id if the action was successfully sent to the VIM"""
4005
sousaedu2ad85172021-02-17 15:05:18 +01004006 self.logger.debug(
4007 "Received action for vm {} and action dict {}".format(
4008 vm__vim_uuid, action_dict
4009 )
4010 )
4011
bayramovef390722016-09-27 03:34:46 -07004012 if vm__vim_uuid is None or action_dict is None:
tierno72774862020-05-04 11:44:15 +00004013 raise vimconn.VimConnException("Invalid request. VM id or action is None.")
bayramovef390722016-09-27 03:34:46 -07004014
beierlb22ce2d2019-12-12 12:09:51 -05004015 _, vdc = self.get_vdc_details()
bayramovef390722016-09-27 03:34:46 -07004016 if vdc is None:
sousaedu2ad85172021-02-17 15:05:18 +01004017 raise vimconn.VimConnException(
4018 "Failed to get a reference of VDC for a tenant {}".format(
4019 self.tenant_name
4020 )
4021 )
bayramovef390722016-09-27 03:34:46 -07004022
kasarc5bf2932018-03-09 04:15:22 -08004023 vapp_name = self.get_namebyvappid(vm__vim_uuid)
bayramovef390722016-09-27 03:34:46 -07004024 if vapp_name is None:
sousaedu2ad85172021-02-17 15:05:18 +01004025 self.logger.debug(
4026 "action_vminstance(): Failed to get vm by given {} vm uuid".format(
4027 vm__vim_uuid
4028 )
4029 )
4030
4031 raise vimconn.VimConnException(
4032 "Failed to get vm by given {} vm uuid".format(vm__vim_uuid)
4033 )
bayramovef390722016-09-27 03:34:46 -07004034 else:
sousaedu2ad85172021-02-17 15:05:18 +01004035 self.logger.info(
4036 "Action_vminstance vApp {} and UUID {}".format(vapp_name, vm__vim_uuid)
4037 )
bayramovef390722016-09-27 03:34:46 -07004038
4039 try:
sousaedu2ad85172021-02-17 15:05:18 +01004040 vdc_obj = VDC(self.client, href=vdc.get("href"))
kasarc5bf2932018-03-09 04:15:22 -08004041 vapp_resource = vdc_obj.get_vapp(vapp_name)
sbhangarea8e5b782018-06-21 02:10:03 -07004042 vapp = VApp(self.client, resource=vapp_resource)
sousaedu2ad85172021-02-17 15:05:18 +01004043
bayramovef390722016-09-27 03:34:46 -07004044 if "start" in action_dict:
sousaedu2ad85172021-02-17 15:05:18 +01004045 self.logger.info(
4046 "action_vminstance: Power on vApp: {}".format(vapp_name)
4047 )
sbhangarea8e5b782018-06-21 02:10:03 -07004048 poweron_task = self.power_on_vapp(vm__vim_uuid, vapp_name)
sousaedu2ad85172021-02-17 15:05:18 +01004049 result = self.client.get_task_monitor().wait_for_success(
4050 task=poweron_task
4051 )
kasarc5bf2932018-03-09 04:15:22 -08004052 self.instance_actions_result("start", result, vapp_name)
kasar3ac5dc42017-03-15 06:28:22 -07004053 elif "rebuild" in action_dict:
sousaedu2ad85172021-02-17 15:05:18 +01004054 self.logger.info(
4055 "action_vminstance: Rebuild vApp: {}".format(vapp_name)
4056 )
kasarc5bf2932018-03-09 04:15:22 -08004057 rebuild_task = vapp.deploy(power_on=True)
sousaedu2ad85172021-02-17 15:05:18 +01004058 result = self.client.get_task_monitor().wait_for_success(
4059 task=rebuild_task
4060 )
kasar3ac5dc42017-03-15 06:28:22 -07004061 self.instance_actions_result("rebuild", result, vapp_name)
bayramovef390722016-09-27 03:34:46 -07004062 elif "pause" in action_dict:
kasar3ac5dc42017-03-15 06:28:22 -07004063 self.logger.info("action_vminstance: pause vApp: {}".format(vapp_name))
sousaedu2ad85172021-02-17 15:05:18 +01004064 pause_task = vapp.undeploy(action="suspend")
4065 result = self.client.get_task_monitor().wait_for_success(
4066 task=pause_task
4067 )
kasar3ac5dc42017-03-15 06:28:22 -07004068 self.instance_actions_result("pause", result, vapp_name)
bayramovef390722016-09-27 03:34:46 -07004069 elif "resume" in action_dict:
kasar3ac5dc42017-03-15 06:28:22 -07004070 self.logger.info("action_vminstance: resume vApp: {}".format(vapp_name))
kasarc5bf2932018-03-09 04:15:22 -08004071 poweron_task = self.power_on_vapp(vm__vim_uuid, vapp_name)
sousaedu2ad85172021-02-17 15:05:18 +01004072 result = self.client.get_task_monitor().wait_for_success(
4073 task=poweron_task
4074 )
kasar3ac5dc42017-03-15 06:28:22 -07004075 self.instance_actions_result("resume", result, vapp_name)
bayramovef390722016-09-27 03:34:46 -07004076 elif "shutoff" in action_dict or "shutdown" in action_dict:
beierlb22ce2d2019-12-12 12:09:51 -05004077 action_name, _ = list(action_dict.items())[0]
sousaedu2ad85172021-02-17 15:05:18 +01004078 self.logger.info(
4079 "action_vminstance: {} vApp: {}".format(action_name, vapp_name)
4080 )
kasarc5bf2932018-03-09 04:15:22 -08004081 shutdown_task = vapp.shutdown()
sousaedu2ad85172021-02-17 15:05:18 +01004082 result = self.client.get_task_monitor().wait_for_success(
4083 task=shutdown_task
4084 )
kasar3ac5dc42017-03-15 06:28:22 -07004085 if action_name == "shutdown":
4086 self.instance_actions_result("shutdown", result, vapp_name)
bhangare985a1fd2017-01-31 01:53:21 -08004087 else:
kasar3ac5dc42017-03-15 06:28:22 -07004088 self.instance_actions_result("shutoff", result, vapp_name)
bayramovef390722016-09-27 03:34:46 -07004089 elif "forceOff" in action_dict:
sousaedu2ad85172021-02-17 15:05:18 +01004090 result = vapp.undeploy(action="powerOff")
kasar3ac5dc42017-03-15 06:28:22 -07004091 self.instance_actions_result("forceOff", result, vapp_name)
4092 elif "reboot" in action_dict:
4093 self.logger.info("action_vminstance: reboot vApp: {}".format(vapp_name))
kasarc5bf2932018-03-09 04:15:22 -08004094 reboot_task = vapp.reboot()
sbhangarea8e5b782018-06-21 02:10:03 -07004095 self.client.get_task_monitor().wait_for_success(task=reboot_task)
bayramovef390722016-09-27 03:34:46 -07004096 else:
tierno72774862020-05-04 11:44:15 +00004097 raise vimconn.VimConnException(
sousaedu2ad85172021-02-17 15:05:18 +01004098 "action_vminstance: Invalid action {} or action is None.".format(
4099 action_dict
4100 )
4101 )
4102
kasarc5bf2932018-03-09 04:15:22 -08004103 return vm__vim_uuid
beierlb22ce2d2019-12-12 12:09:51 -05004104 except Exception as exp:
bhangarebfdca492017-03-11 01:32:46 -08004105 self.logger.debug("action_vminstance: Failed with Exception {}".format(exp))
sousaedu2ad85172021-02-17 15:05:18 +01004106
4107 raise vimconn.VimConnException(
4108 "action_vminstance: Failed with Exception {}".format(exp)
4109 )
bayramovef390722016-09-27 03:34:46 -07004110
kasar3ac5dc42017-03-15 06:28:22 -07004111 def instance_actions_result(self, action, result, vapp_name):
sousaedu2ad85172021-02-17 15:05:18 +01004112 if result.get("status") == "success":
4113 self.logger.info(
4114 "action_vminstance: Sucessfully {} the vApp: {}".format(
4115 action, vapp_name
4116 )
4117 )
kasar3ac5dc42017-03-15 06:28:22 -07004118 else:
sousaedu2ad85172021-02-17 15:05:18 +01004119 self.logger.error(
4120 "action_vminstance: Failed to {} vApp: {}".format(action, vapp_name)
4121 )
kasar3ac5dc42017-03-15 06:28:22 -07004122
kasarcf655072019-03-20 01:40:05 -07004123 def get_vminstance_console(self, vm_id, console_type="novnc"):
bayramovef390722016-09-27 03:34:46 -07004124 """
bayramov325fa1c2016-09-08 01:42:46 -07004125 Get a console for the virtual machine
4126 Params:
4127 vm_id: uuid of the VM
4128 console_type, can be:
bayramovef390722016-09-27 03:34:46 -07004129 "novnc" (by default), "xvpvnc" for VNC types,
bayramov325fa1c2016-09-08 01:42:46 -07004130 "rdp-html5" for RDP types, "spice-html5" for SPICE types
4131 Returns dict with the console parameters:
4132 protocol: ssh, ftp, http, https, ...
bayramovef390722016-09-27 03:34:46 -07004133 server: usually ip address
4134 port: the http, ssh, ... port
4135 suffix: extra text, e.g. the http path and query string
4136 """
kasarcf655072019-03-20 01:40:05 -07004137 console_dict = {}
4138
sousaedu2ad85172021-02-17 15:05:18 +01004139 if console_type is None or console_type == "novnc":
4140 url_rest_call = "{}/api/vApp/vm-{}/screen/action/acquireMksTicket".format(
4141 self.url, vm_id
4142 )
4143 headers = {
4144 "Accept": "application/*+xml;version=" + API_VERSION,
4145 "x-vcloud-authorization": self.client._session.headers[
4146 "x-vcloud-authorization"
4147 ],
4148 }
4149 response = self.perform_request(
4150 req_type="POST", url=url_rest_call, headers=headers
4151 )
kasarcf655072019-03-20 01:40:05 -07004152
4153 if response.status_code == 403:
sousaedu2ad85172021-02-17 15:05:18 +01004154 response = self.retry_rest("GET", url_rest_call)
kasarcf655072019-03-20 01:40:05 -07004155
4156 if response.status_code != 200:
sousaedu2ad85172021-02-17 15:05:18 +01004157 self.logger.error(
4158 "REST call {} failed reason : {}"
4159 "status code : {}".format(
4160 url_rest_call, response.text, response.status_code
4161 )
4162 )
4163 raise vimconn.VimConnException(
4164 "get_vminstance_console : Failed to get " "VM Mks ticket details"
4165 )
4166
beierl26fec002019-12-06 17:06:40 -05004167 s = re.search("<Host>(.*?)</Host>", response.text)
sousaedu2ad85172021-02-17 15:05:18 +01004168 console_dict["server"] = s.group(1) if s else None
beierl26fec002019-12-06 17:06:40 -05004169 s1 = re.search("<Port>(\d+)</Port>", response.text)
sousaedu2ad85172021-02-17 15:05:18 +01004170 console_dict["port"] = s1.group(1) if s1 else None
4171 url_rest_call = "{}/api/vApp/vm-{}/screen/action/acquireTicket".format(
4172 self.url, vm_id
4173 )
4174 headers = {
4175 "Accept": "application/*+xml;version=" + API_VERSION,
4176 "x-vcloud-authorization": self.client._session.headers[
4177 "x-vcloud-authorization"
4178 ],
4179 }
4180 response = self.perform_request(
4181 req_type="POST", url=url_rest_call, headers=headers
4182 )
kasarcf655072019-03-20 01:40:05 -07004183
4184 if response.status_code == 403:
sousaedu2ad85172021-02-17 15:05:18 +01004185 response = self.retry_rest("GET", url_rest_call)
kasarcf655072019-03-20 01:40:05 -07004186
4187 if response.status_code != 200:
sousaedu2ad85172021-02-17 15:05:18 +01004188 self.logger.error(
4189 "REST call {} failed reason : {}"
4190 "status code : {}".format(
4191 url_rest_call, response.text, response.status_code
4192 )
4193 )
4194 raise vimconn.VimConnException(
4195 "get_vminstance_console : Failed to get " "VM console details"
4196 )
4197
beierl26fec002019-12-06 17:06:40 -05004198 s = re.search(">.*?/(vm-\d+.*)</", response.text)
sousaedu2ad85172021-02-17 15:05:18 +01004199 console_dict["suffix"] = s.group(1) if s else None
4200 console_dict["protocol"] = "https"
kasarcf655072019-03-20 01:40:05 -07004201
4202 return console_dict
bayramov325fa1c2016-09-08 01:42:46 -07004203
bayramovef390722016-09-27 03:34:46 -07004204 # NOT USED METHODS in current version
bayramov325fa1c2016-09-08 01:42:46 -07004205
4206 def host_vim2gui(self, host, server_dict):
bayramov5761ad12016-10-04 09:00:30 +04004207 """Transform host dictionary from VIM format to GUI format,
bayramov325fa1c2016-09-08 01:42:46 -07004208 and append to the server_dict
bayramov5761ad12016-10-04 09:00:30 +04004209 """
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_info(self):
bayramov5761ad12016-10-04 09:00:30 +04004213 """Get the information of deployed hosts
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_hosts(self, vim_tenant):
bayramov5761ad12016-10-04 09:00:30 +04004218 """Get the hosts and deployed instances
4219 Returns the hosts content"""
tierno72774862020-05-04 11:44:15 +00004220 raise vimconn.VimConnNotImplemented("Should have implemented this")
bayramov325fa1c2016-09-08 01:42:46 -07004221
4222 def get_processor_rankings(self):
bayramov5761ad12016-10-04 09:00:30 +04004223 """Get the processor rankings in the VIM database"""
tierno72774862020-05-04 11:44:15 +00004224 raise vimconn.VimConnNotImplemented("Should have implemented this")
bayramov325fa1c2016-09-08 01:42:46 -07004225
4226 def new_host(self, host_data):
bayramov5761ad12016-10-04 09:00:30 +04004227 """Adds a new host to VIM"""
sousaedu2ad85172021-02-17 15:05:18 +01004228 """Returns status code of the VIM response"""
tierno72774862020-05-04 11:44:15 +00004229 raise vimconn.VimConnNotImplemented("Should have implemented this")
bayramov325fa1c2016-09-08 01:42:46 -07004230
4231 def new_external_port(self, port_data):
bayramov5761ad12016-10-04 09:00:30 +04004232 """Adds a external port to VIM"""
sousaedu2ad85172021-02-17 15:05:18 +01004233 """Returns the port identifier"""
tierno72774862020-05-04 11:44:15 +00004234 raise vimconn.VimConnNotImplemented("Should have implemented this")
bayramov325fa1c2016-09-08 01:42:46 -07004235
bayramovef390722016-09-27 03:34:46 -07004236 def new_external_network(self, net_name, net_type):
bayramov5761ad12016-10-04 09:00:30 +04004237 """Adds a external network to VIM (shared)"""
sousaedu2ad85172021-02-17 15:05:18 +01004238 """Returns the network identifier"""
tierno72774862020-05-04 11:44:15 +00004239 raise vimconn.VimConnNotImplemented("Should have implemented this")
bayramov325fa1c2016-09-08 01:42:46 -07004240
4241 def connect_port_network(self, port_id, network_id, admin=False):
bayramov5761ad12016-10-04 09:00:30 +04004242 """Connects a external port to a network"""
sousaedu2ad85172021-02-17 15:05:18 +01004243 """Returns status code of the VIM response"""
tierno72774862020-05-04 11:44:15 +00004244 raise vimconn.VimConnNotImplemented("Should have implemented this")
bayramov325fa1c2016-09-08 01:42:46 -07004245
4246 def new_vminstancefromJSON(self, vm_data):
bayramov5761ad12016-10-04 09:00:30 +04004247 """Adds a VM instance to VIM"""
sousaedu2ad85172021-02-17 15:05:18 +01004248 """Returns the instance identifier"""
tierno72774862020-05-04 11:44:15 +00004249 raise vimconn.VimConnNotImplemented("Should have implemented this")
bayramov325fa1c2016-09-08 01:42:46 -07004250
kate15f1c382016-12-15 01:12:40 -08004251 def get_network_name_by_id(self, network_uuid=None):
bayramovef390722016-09-27 03:34:46 -07004252 """Method gets vcloud director network named based on supplied uuid.
4253
4254 Args:
kate15f1c382016-12-15 01:12:40 -08004255 network_uuid: network_id
bayramovef390722016-09-27 03:34:46 -07004256
4257 Returns:
4258 The return network name.
4259 """
4260
kate15f1c382016-12-15 01:12:40 -08004261 if not network_uuid:
bayramovef390722016-09-27 03:34:46 -07004262 return None
4263
4264 try:
kate15f1c382016-12-15 01:12:40 -08004265 org_dict = self.get_org(self.org_uuid)
sousaedu2ad85172021-02-17 15:05:18 +01004266 if "networks" in org_dict:
4267 org_network_dict = org_dict["networks"]
4268
kate15f1c382016-12-15 01:12:40 -08004269 for net_uuid in org_network_dict:
4270 if net_uuid == network_uuid:
4271 return org_network_dict[net_uuid]
beierlb22ce2d2019-12-12 12:09:51 -05004272 except Exception:
bayramovef390722016-09-27 03:34:46 -07004273 self.logger.debug("Exception in get_network_name_by_id")
4274 self.logger.debug(traceback.format_exc())
4275
4276 return None
4277
bhangare2c855072016-12-27 01:41:28 -08004278 def get_network_id_by_name(self, network_name=None):
4279 """Method gets vcloud director network uuid based on supplied name.
4280
4281 Args:
4282 network_name: network_name
4283 Returns:
4284 The return network uuid.
4285 network_uuid: network_id
4286 """
bhangare2c855072016-12-27 01:41:28 -08004287 if not network_name:
4288 self.logger.debug("get_network_id_by_name() : Network name is empty")
4289 return None
4290
4291 try:
4292 org_dict = self.get_org(self.org_uuid)
sousaedu2ad85172021-02-17 15:05:18 +01004293 if org_dict and "networks" in org_dict:
4294 org_network_dict = org_dict["networks"]
4295
tierno1b856002019-11-07 16:28:54 +00004296 for net_uuid, net_name in org_network_dict.items():
bhangare2c855072016-12-27 01:41:28 -08004297 if net_name == network_name:
4298 return net_uuid
4299
4300 except KeyError as exp:
4301 self.logger.debug("get_network_id_by_name() : KeyError- {} ".format(exp))
4302
4303 return None
4304
kbsuba85c54d2019-10-17 16:30:32 +00004305 def get_physical_network_by_name(self, physical_network_name):
sousaedu2ad85172021-02-17 15:05:18 +01004306 """
kbsuba85c54d2019-10-17 16:30:32 +00004307 Methos returns uuid of physical network which passed
4308 Args:
4309 physical_network_name: physical network name
4310 Returns:
4311 UUID of physical_network_name
sousaedu2ad85172021-02-17 15:05:18 +01004312 """
kbsuba85c54d2019-10-17 16:30:32 +00004313 try:
4314 client_as_admin = self.connect_as_admin()
sousaedu2ad85172021-02-17 15:05:18 +01004315
kbsuba85c54d2019-10-17 16:30:32 +00004316 if not client_as_admin:
tierno72774862020-05-04 11:44:15 +00004317 raise vimconn.VimConnConnectionException("Failed to connect vCD.")
sousaedu2ad85172021-02-17 15:05:18 +01004318
4319 url_list = [self.url, "/api/admin/vdc/", self.tenant_id]
4320 vm_list_rest_call = "".join(url_list)
kbsuba85c54d2019-10-17 16:30:32 +00004321
4322 if client_as_admin._session:
sousaedu2ad85172021-02-17 15:05:18 +01004323 headers = {
4324 "Accept": "application/*+xml;version=" + API_VERSION,
4325 "x-vcloud-authorization": client_as_admin._session.headers[
4326 "x-vcloud-authorization"
4327 ],
4328 }
4329 response = self.perform_request(
4330 req_type="GET", url=vm_list_rest_call, headers=headers
4331 )
kbsuba85c54d2019-10-17 16:30:32 +00004332 provider_network = None
4333 available_network = None
beierlb22ce2d2019-12-12 12:09:51 -05004334 # add_vdc_rest_url = None
kbsuba85c54d2019-10-17 16:30:32 +00004335
4336 if response.status_code != requests.codes.ok:
sousaedu2ad85172021-02-17 15:05:18 +01004337 self.logger.debug(
4338 "REST API call {} failed. Return status code {}".format(
4339 vm_list_rest_call, response.status_code
4340 )
4341 )
kbsuba85c54d2019-10-17 16:30:32 +00004342 return None
4343 else:
4344 try:
beierl26fec002019-12-06 17:06:40 -05004345 vm_list_xmlroot = XmlElementTree.fromstring(response.text)
kbsuba85c54d2019-10-17 16:30:32 +00004346 for child in vm_list_xmlroot:
sousaedu2ad85172021-02-17 15:05:18 +01004347 if child.tag.split("}")[1] == "ProviderVdcReference":
4348 provider_network = child.attrib.get("href")
kbsuba85c54d2019-10-17 16:30:32 +00004349 # application/vnd.vmware.admin.providervdc+xml
sousaedu2ad85172021-02-17 15:05:18 +01004350
4351 if child.tag.split("}")[1] == "Link":
4352 if (
4353 child.attrib.get("type")
4354 == "application/vnd.vmware.vcloud.orgVdcNetwork+xml"
4355 and child.attrib.get("rel") == "add"
4356 ):
4357 child.attrib.get("href")
beierlb22ce2d2019-12-12 12:09:51 -05004358 except Exception:
sousaedu2ad85172021-02-17 15:05:18 +01004359 self.logger.debug(
4360 "Failed parse respond for rest api call {}".format(
4361 vm_list_rest_call
4362 )
4363 )
beierl26fec002019-12-06 17:06:40 -05004364 self.logger.debug("Respond body {}".format(response.text))
sousaedu2ad85172021-02-17 15:05:18 +01004365
kbsuba85c54d2019-10-17 16:30:32 +00004366 return None
4367
4368 # find pvdc provided available network
sousaedu2ad85172021-02-17 15:05:18 +01004369 response = self.perform_request(
4370 req_type="GET", url=provider_network, headers=headers
4371 )
kbsuba85c54d2019-10-17 16:30:32 +00004372
4373 if response.status_code != requests.codes.ok:
sousaedu2ad85172021-02-17 15:05:18 +01004374 self.logger.debug(
4375 "REST API call {} failed. Return status code {}".format(
4376 vm_list_rest_call, response.status_code
4377 )
4378 )
4379
kbsuba85c54d2019-10-17 16:30:32 +00004380 return None
4381
4382 try:
beierl26fec002019-12-06 17:06:40 -05004383 vm_list_xmlroot = XmlElementTree.fromstring(response.text)
kbsuba85c54d2019-10-17 16:30:32 +00004384 for child in vm_list_xmlroot.iter():
sousaedu2ad85172021-02-17 15:05:18 +01004385 if child.tag.split("}")[1] == "AvailableNetworks":
kbsuba85c54d2019-10-17 16:30:32 +00004386 for networks in child.iter():
sousaedu2ad85172021-02-17 15:05:18 +01004387 if (
4388 networks.attrib.get("href") is not None
4389 and networks.attrib.get("name") is not None
4390 ):
4391 if (
4392 networks.attrib.get("name")
4393 == physical_network_name
4394 ):
4395 network_url = networks.attrib.get("href")
4396 available_network = network_url[
4397 network_url.rindex("/") + 1 :
4398 ]
kbsuba85c54d2019-10-17 16:30:32 +00004399 break
sousaedu2ad85172021-02-17 15:05:18 +01004400 except Exception:
kbsuba85c54d2019-10-17 16:30:32 +00004401 return None
4402
4403 return available_network
4404 except Exception as e:
4405 self.logger.error("Error while getting physical network: {}".format(e))
4406
bayramovef390722016-09-27 03:34:46 -07004407 def list_org_action(self):
4408 """
4409 Method leverages vCloud director and query for available organization for particular user
4410
4411 Args:
4412 vca - is active VCA connection.
4413 vdc_name - is a vdc name that will be used to query vms action
4414
4415 Returns:
4416 The return XML respond
4417 """
sousaedu2ad85172021-02-17 15:05:18 +01004418 url_list = [self.url, "/api/org"]
4419 vm_list_rest_call = "".join(url_list)
bayramovef390722016-09-27 03:34:46 -07004420
kasarc5bf2932018-03-09 04:15:22 -08004421 if self.client._session:
sousaedu2ad85172021-02-17 15:05:18 +01004422 headers = {
4423 "Accept": "application/*+xml;version=" + API_VERSION,
4424 "x-vcloud-authorization": self.client._session.headers[
4425 "x-vcloud-authorization"
4426 ],
4427 }
kasarc5bf2932018-03-09 04:15:22 -08004428
sousaedu2ad85172021-02-17 15:05:18 +01004429 response = self.perform_request(
4430 req_type="GET", url=vm_list_rest_call, headers=headers
4431 )
bhangare1a0b97c2017-06-21 02:20:15 -07004432
4433 if response.status_code == 403:
sousaedu2ad85172021-02-17 15:05:18 +01004434 response = self.retry_rest("GET", vm_list_rest_call)
bhangare1a0b97c2017-06-21 02:20:15 -07004435
bayramovef390722016-09-27 03:34:46 -07004436 if response.status_code == requests.codes.ok:
beierl26fec002019-12-06 17:06:40 -05004437 return response.text
bayramovef390722016-09-27 03:34:46 -07004438
4439 return None
4440
4441 def get_org_action(self, org_uuid=None):
4442 """
kasarc5bf2932018-03-09 04:15:22 -08004443 Method leverages vCloud director and retrieve available object for organization.
bayramovef390722016-09-27 03:34:46 -07004444
4445 Args:
kasarc5bf2932018-03-09 04:15:22 -08004446 org_uuid - vCD organization uuid
4447 self.client - is active connection.
bayramovef390722016-09-27 03:34:46 -07004448
4449 Returns:
4450 The return XML respond
4451 """
4452
bayramovef390722016-09-27 03:34:46 -07004453 if org_uuid is None:
4454 return None
4455
sousaedu2ad85172021-02-17 15:05:18 +01004456 url_list = [self.url, "/api/org/", org_uuid]
4457 vm_list_rest_call = "".join(url_list)
bayramovef390722016-09-27 03:34:46 -07004458
sbhangarea8e5b782018-06-21 02:10:03 -07004459 if self.client._session:
sousaedu2ad85172021-02-17 15:05:18 +01004460 headers = {
4461 "Accept": "application/*+xml;version=" + API_VERSION,
4462 "x-vcloud-authorization": self.client._session.headers[
4463 "x-vcloud-authorization"
4464 ],
4465 }
bhangare1a0b97c2017-06-21 02:20:15 -07004466
beierlb22ce2d2019-12-12 12:09:51 -05004467 # response = requests.get(vm_list_rest_call, headers=headers, verify=False)
sousaedu2ad85172021-02-17 15:05:18 +01004468 response = self.perform_request(
4469 req_type="GET", url=vm_list_rest_call, headers=headers
4470 )
4471
bhangare1a0b97c2017-06-21 02:20:15 -07004472 if response.status_code == 403:
sousaedu2ad85172021-02-17 15:05:18 +01004473 response = self.retry_rest("GET", vm_list_rest_call)
bhangare1a0b97c2017-06-21 02:20:15 -07004474
bayramovef390722016-09-27 03:34:46 -07004475 if response.status_code == requests.codes.ok:
beierl26fec002019-12-06 17:06:40 -05004476 return response.text
sousaedu2ad85172021-02-17 15:05:18 +01004477
bayramovef390722016-09-27 03:34:46 -07004478 return None
4479
4480 def get_org(self, org_uuid=None):
4481 """
4482 Method retrieves available organization in vCloud Director
4483
4484 Args:
bayramovb6ffe792016-09-28 11:50:56 +04004485 org_uuid - is a organization uuid.
bayramovef390722016-09-27 03:34:46 -07004486
4487 Returns:
bayramovb6ffe792016-09-28 11:50:56 +04004488 The return dictionary with following key
4489 "network" - for network list under the org
4490 "catalogs" - for network list under the org
4491 "vdcs" - for vdc list under org
bayramovef390722016-09-27 03:34:46 -07004492 """
4493
4494 org_dict = {}
bayramovef390722016-09-27 03:34:46 -07004495
4496 if org_uuid is None:
4497 return org_dict
4498
4499 content = self.get_org_action(org_uuid=org_uuid)
4500 try:
4501 vdc_list = {}
4502 network_list = {}
4503 catalog_list = {}
4504 vm_list_xmlroot = XmlElementTree.fromstring(content)
4505 for child in vm_list_xmlroot:
sousaedu2ad85172021-02-17 15:05:18 +01004506 if child.attrib["type"] == "application/vnd.vmware.vcloud.vdc+xml":
4507 vdc_list[child.attrib["href"].split("/")[-1:][0]] = child.attrib[
4508 "name"
4509 ]
4510 org_dict["vdcs"] = vdc_list
4511
4512 if (
4513 child.attrib["type"]
4514 == "application/vnd.vmware.vcloud.orgNetwork+xml"
4515 ):
4516 network_list[
4517 child.attrib["href"].split("/")[-1:][0]
4518 ] = child.attrib["name"]
4519 org_dict["networks"] = network_list
4520
4521 if child.attrib["type"] == "application/vnd.vmware.vcloud.catalog+xml":
4522 catalog_list[
4523 child.attrib["href"].split("/")[-1:][0]
4524 ] = child.attrib["name"]
4525 org_dict["catalogs"] = catalog_list
beierlb22ce2d2019-12-12 12:09:51 -05004526 except Exception:
bayramovef390722016-09-27 03:34:46 -07004527 pass
4528
4529 return org_dict
4530
4531 def get_org_list(self):
4532 """
4533 Method retrieves available organization in vCloud Director
4534
4535 Args:
4536 vca - is active VCA connection.
4537
4538 Returns:
4539 The return dictionary and key for each entry VDC UUID
4540 """
bayramovef390722016-09-27 03:34:46 -07004541 org_dict = {}
bayramovef390722016-09-27 03:34:46 -07004542
4543 content = self.list_org_action()
4544 try:
4545 vm_list_xmlroot = XmlElementTree.fromstring(content)
sousaedu2ad85172021-02-17 15:05:18 +01004546
bayramovef390722016-09-27 03:34:46 -07004547 for vm_xml in vm_list_xmlroot:
sousaedu2ad85172021-02-17 15:05:18 +01004548 if vm_xml.tag.split("}")[1] == "Org":
4549 org_uuid = vm_xml.attrib["href"].split("/")[-1:]
4550 org_dict[org_uuid[0]] = vm_xml.attrib["name"]
beierlb22ce2d2019-12-12 12:09:51 -05004551 except Exception:
bayramovef390722016-09-27 03:34:46 -07004552 pass
4553
4554 return org_dict
4555
4556 def vms_view_action(self, vdc_name=None):
sousaedu2ad85172021-02-17 15:05:18 +01004557 """Method leverages vCloud director vms query call
bayramovef390722016-09-27 03:34:46 -07004558
4559 Args:
4560 vca - is active VCA connection.
4561 vdc_name - is a vdc name that will be used to query vms action
4562
4563 Returns:
4564 The return XML respond
4565 """
4566 vca = self.connect()
4567 if vdc_name is None:
4568 return None
4569
sousaedu2ad85172021-02-17 15:05:18 +01004570 url_list = [vca.host, "/api/vms/query"]
4571 vm_list_rest_call = "".join(url_list)
bayramovef390722016-09-27 03:34:46 -07004572
4573 if not (not vca.vcloud_session or not vca.vcloud_session.organization):
sousaedu2ad85172021-02-17 15:05:18 +01004574 refs = [
4575 ref
4576 for ref in vca.vcloud_session.organization.Link
4577 if ref.name == vdc_name
4578 and ref.type_ == "application/vnd.vmware.vcloud.vdc+xml"
4579 ]
4580
bayramovef390722016-09-27 03:34:46 -07004581 if len(refs) == 1:
sousaedu2ad85172021-02-17 15:05:18 +01004582 response = self.perform_request(
4583 req_type="GET",
4584 url=vm_list_rest_call,
4585 headers=vca.vcloud_session.get_vcloud_headers(),
4586 verify=vca.verify,
4587 logger=vca.logger,
4588 )
4589
bayramovef390722016-09-27 03:34:46 -07004590 if response.status_code == requests.codes.ok:
beierl26fec002019-12-06 17:06:40 -05004591 return response.text
bayramovef390722016-09-27 03:34:46 -07004592
4593 return None
4594
4595 def get_vapp_list(self, vdc_name=None):
4596 """
4597 Method retrieves vApp list deployed vCloud director and returns a dictionary
4598 contains a list of all vapp deployed for queried VDC.
4599 The key for a dictionary is vApp UUID
4600
4601
4602 Args:
4603 vca - is active VCA connection.
4604 vdc_name - is a vdc name that will be used to query vms action
4605
4606 Returns:
4607 The return dictionary and key for each entry vapp UUID
4608 """
bayramovef390722016-09-27 03:34:46 -07004609 vapp_dict = {}
sousaedu2ad85172021-02-17 15:05:18 +01004610
bayramovef390722016-09-27 03:34:46 -07004611 if vdc_name is None:
4612 return vapp_dict
4613
4614 content = self.vms_view_action(vdc_name=vdc_name)
4615 try:
4616 vm_list_xmlroot = XmlElementTree.fromstring(content)
4617 for vm_xml in vm_list_xmlroot:
sousaedu2ad85172021-02-17 15:05:18 +01004618 if vm_xml.tag.split("}")[1] == "VMRecord":
4619 if vm_xml.attrib["isVAppTemplate"] == "true":
4620 rawuuid = vm_xml.attrib["container"].split("/")[-1:]
4621 if "vappTemplate-" in rawuuid[0]:
bayramovef390722016-09-27 03:34:46 -07004622 # vm in format vappTemplate-e63d40e7-4ff5-4c6d-851f-96c1e4da86a5 we remove
4623 # vm and use raw UUID as key
4624 vapp_dict[rawuuid[0][13:]] = vm_xml.attrib
beierlb22ce2d2019-12-12 12:09:51 -05004625 except Exception:
bayramovef390722016-09-27 03:34:46 -07004626 pass
4627
4628 return vapp_dict
4629
4630 def get_vm_list(self, vdc_name=None):
4631 """
4632 Method retrieves VM's list deployed vCloud director. It returns a dictionary
4633 contains a list of all VM's deployed for queried VDC.
4634 The key for a dictionary is VM UUID
4635
4636
4637 Args:
4638 vca - is active VCA connection.
4639 vdc_name - is a vdc name that will be used to query vms action
4640
4641 Returns:
4642 The return dictionary and key for each entry vapp UUID
4643 """
4644 vm_dict = {}
4645
4646 if vdc_name is None:
4647 return vm_dict
4648
4649 content = self.vms_view_action(vdc_name=vdc_name)
4650 try:
4651 vm_list_xmlroot = XmlElementTree.fromstring(content)
4652 for vm_xml in vm_list_xmlroot:
sousaedu2ad85172021-02-17 15:05:18 +01004653 if vm_xml.tag.split("}")[1] == "VMRecord":
4654 if vm_xml.attrib["isVAppTemplate"] == "false":
4655 rawuuid = vm_xml.attrib["href"].split("/")[-1:]
4656 if "vm-" in rawuuid[0]:
bayramovef390722016-09-27 03:34:46 -07004657 # vm in format vm-e63d40e7-4ff5-4c6d-851f-96c1e4da86a5 we remove
4658 # vm and use raw UUID as key
4659 vm_dict[rawuuid[0][3:]] = vm_xml.attrib
beierlb22ce2d2019-12-12 12:09:51 -05004660 except Exception:
bayramovef390722016-09-27 03:34:46 -07004661 pass
4662
4663 return vm_dict
4664
4665 def get_vapp(self, vdc_name=None, vapp_name=None, isuuid=False):
4666 """
bayramovb6ffe792016-09-28 11:50:56 +04004667 Method retrieves VM deployed vCloud director. It returns VM attribute as dictionary
bayramovef390722016-09-27 03:34:46 -07004668 contains a list of all VM's deployed for queried VDC.
4669 The key for a dictionary is VM UUID
4670
4671
4672 Args:
4673 vca - is active VCA connection.
4674 vdc_name - is a vdc name that will be used to query vms action
4675
4676 Returns:
4677 The return dictionary and key for each entry vapp UUID
4678 """
4679 vm_dict = {}
4680 vca = self.connect()
sousaedu2ad85172021-02-17 15:05:18 +01004681
bayramovef390722016-09-27 03:34:46 -07004682 if not vca:
tierno72774862020-05-04 11:44:15 +00004683 raise vimconn.VimConnConnectionException("self.connect() is failed")
bayramovef390722016-09-27 03:34:46 -07004684
4685 if vdc_name is None:
4686 return vm_dict
4687
4688 content = self.vms_view_action(vdc_name=vdc_name)
4689 try:
4690 vm_list_xmlroot = XmlElementTree.fromstring(content)
4691 for vm_xml in vm_list_xmlroot:
sousaedu2ad85172021-02-17 15:05:18 +01004692 if (
4693 vm_xml.tag.split("}")[1] == "VMRecord"
4694 and vm_xml.attrib["isVAppTemplate"] == "false"
4695 ):
bayramovb6ffe792016-09-28 11:50:56 +04004696 # lookup done by UUID
bayramovef390722016-09-27 03:34:46 -07004697 if isuuid:
sousaedu2ad85172021-02-17 15:05:18 +01004698 if vapp_name in vm_xml.attrib["container"]:
4699 rawuuid = vm_xml.attrib["href"].split("/")[-1:]
4700 if "vm-" in rawuuid[0]:
bayramovef390722016-09-27 03:34:46 -07004701 vm_dict[rawuuid[0][3:]] = vm_xml.attrib
bayramovb6ffe792016-09-28 11:50:56 +04004702 break
4703 # lookup done by Name
4704 else:
sousaedu2ad85172021-02-17 15:05:18 +01004705 if vapp_name in vm_xml.attrib["name"]:
4706 rawuuid = vm_xml.attrib["href"].split("/")[-1:]
4707 if "vm-" in rawuuid[0]:
bayramovb6ffe792016-09-28 11:50:56 +04004708 vm_dict[rawuuid[0][3:]] = vm_xml.attrib
4709 break
beierlb22ce2d2019-12-12 12:09:51 -05004710 except Exception:
bayramovef390722016-09-27 03:34:46 -07004711 pass
4712
4713 return vm_dict
4714
4715 def get_network_action(self, network_uuid=None):
4716 """
4717 Method leverages vCloud director and query network based on network uuid
4718
4719 Args:
4720 vca - is active VCA connection.
4721 network_uuid - is a network uuid
4722
4723 Returns:
4724 The return XML respond
4725 """
bayramovef390722016-09-27 03:34:46 -07004726 if network_uuid is None:
4727 return None
4728
sousaedu2ad85172021-02-17 15:05:18 +01004729 url_list = [self.url, "/api/network/", network_uuid]
4730 vm_list_rest_call = "".join(url_list)
bayramovef390722016-09-27 03:34:46 -07004731
kasarc5bf2932018-03-09 04:15:22 -08004732 if self.client._session:
sousaedu2ad85172021-02-17 15:05:18 +01004733 headers = {
4734 "Accept": "application/*+xml;version=" + API_VERSION,
4735 "x-vcloud-authorization": self.client._session.headers[
4736 "x-vcloud-authorization"
4737 ],
4738 }
4739 response = self.perform_request(
4740 req_type="GET", url=vm_list_rest_call, headers=headers
4741 )
bhangare1a0b97c2017-06-21 02:20:15 -07004742
beierlb22ce2d2019-12-12 12:09:51 -05004743 # Retry login if session expired & retry sending request
bhangare1a0b97c2017-06-21 02:20:15 -07004744 if response.status_code == 403:
sousaedu2ad85172021-02-17 15:05:18 +01004745 response = self.retry_rest("GET", vm_list_rest_call)
bhangare1a0b97c2017-06-21 02:20:15 -07004746
bayramovef390722016-09-27 03:34:46 -07004747 if response.status_code == requests.codes.ok:
beierl26fec002019-12-06 17:06:40 -05004748 return response.text
bayramovef390722016-09-27 03:34:46 -07004749
4750 return None
4751
4752 def get_vcd_network(self, network_uuid=None):
4753 """
4754 Method retrieves available network from vCloud Director
4755
4756 Args:
4757 network_uuid - is VCD network UUID
4758
4759 Each element serialized as key : value pair
4760
4761 Following keys available for access. network_configuration['Gateway'}
4762 <Configuration>
4763 <IpScopes>
4764 <IpScope>
4765 <IsInherited>true</IsInherited>
4766 <Gateway>172.16.252.100</Gateway>
4767 <Netmask>255.255.255.0</Netmask>
4768 <Dns1>172.16.254.201</Dns1>
4769 <Dns2>172.16.254.202</Dns2>
4770 <DnsSuffix>vmwarelab.edu</DnsSuffix>
4771 <IsEnabled>true</IsEnabled>
4772 <IpRanges>
4773 <IpRange>
4774 <StartAddress>172.16.252.1</StartAddress>
4775 <EndAddress>172.16.252.99</EndAddress>
4776 </IpRange>
4777 </IpRanges>
4778 </IpScope>
4779 </IpScopes>
4780 <FenceMode>bridged</FenceMode>
4781
4782 Returns:
4783 The return dictionary and key for each entry vapp UUID
4784 """
bayramovef390722016-09-27 03:34:46 -07004785 network_configuration = {}
sousaedu2ad85172021-02-17 15:05:18 +01004786
bayramovef390722016-09-27 03:34:46 -07004787 if network_uuid is None:
4788 return network_uuid
4789
bayramovef390722016-09-27 03:34:46 -07004790 try:
bhangarebfdca492017-03-11 01:32:46 -08004791 content = self.get_network_action(network_uuid=network_uuid)
kbsub3de27d62019-12-05 17:20:18 +00004792 if content is not None:
4793 vm_list_xmlroot = XmlElementTree.fromstring(content)
sousaedu2ad85172021-02-17 15:05:18 +01004794 network_configuration["status"] = vm_list_xmlroot.get("status")
4795 network_configuration["name"] = vm_list_xmlroot.get("name")
4796 network_configuration["uuid"] = vm_list_xmlroot.get("id").split(":")[3]
bayramovef390722016-09-27 03:34:46 -07004797
kbsub3de27d62019-12-05 17:20:18 +00004798 for child in vm_list_xmlroot:
sousaedu2ad85172021-02-17 15:05:18 +01004799 if child.tag.split("}")[1] == "IsShared":
4800 network_configuration["isShared"] = child.text.strip()
4801
4802 if child.tag.split("}")[1] == "Configuration":
kbsub3de27d62019-12-05 17:20:18 +00004803 for configuration in child.iter():
4804 tagKey = configuration.tag.split("}")[1].strip()
4805 if tagKey != "":
sousaedu2ad85172021-02-17 15:05:18 +01004806 network_configuration[
4807 tagKey
4808 ] = configuration.text.strip()
beierlb22ce2d2019-12-12 12:09:51 -05004809 except Exception as exp:
bhangarebfdca492017-03-11 01:32:46 -08004810 self.logger.debug("get_vcd_network: Failed with Exception {}".format(exp))
sousaedu2ad85172021-02-17 15:05:18 +01004811
4812 raise vimconn.VimConnException(
4813 "get_vcd_network: Failed with Exception {}".format(exp)
4814 )
bayramovef390722016-09-27 03:34:46 -07004815
4816 return network_configuration
4817
4818 def delete_network_action(self, network_uuid=None):
4819 """
4820 Method delete given network from vCloud director
4821
4822 Args:
4823 network_uuid - is a network uuid that client wish to delete
4824
4825 Returns:
4826 The return None or XML respond or false
4827 """
kasarc5bf2932018-03-09 04:15:22 -08004828 client = self.connect_as_admin()
sousaedu2ad85172021-02-17 15:05:18 +01004829
kasarc5bf2932018-03-09 04:15:22 -08004830 if not client:
tierno72774862020-05-04 11:44:15 +00004831 raise vimconn.VimConnConnectionException("Failed to connect vCD as admin")
sousaedu2ad85172021-02-17 15:05:18 +01004832
bayramovef390722016-09-27 03:34:46 -07004833 if network_uuid is None:
4834 return False
4835
sousaedu2ad85172021-02-17 15:05:18 +01004836 url_list = [self.url, "/api/admin/network/", network_uuid]
4837 vm_list_rest_call = "".join(url_list)
bayramovef390722016-09-27 03:34:46 -07004838
kasarc5bf2932018-03-09 04:15:22 -08004839 if client._session:
sousaedu2ad85172021-02-17 15:05:18 +01004840 headers = {
4841 "Accept": "application/*+xml;version=" + API_VERSION,
4842 "x-vcloud-authorization": client._session.headers[
4843 "x-vcloud-authorization"
4844 ],
4845 }
4846 response = self.perform_request(
4847 req_type="DELETE", url=vm_list_rest_call, headers=headers
4848 )
4849
bayramovef390722016-09-27 03:34:46 -07004850 if response.status_code == 202:
4851 return True
4852
4853 return False
4854
sousaedu2ad85172021-02-17 15:05:18 +01004855 def create_network(
4856 self,
4857 network_name=None,
4858 net_type="bridge",
4859 parent_network_uuid=None,
4860 ip_profile=None,
4861 isshared="true",
4862 ):
bayramovef390722016-09-27 03:34:46 -07004863 """
4864 Method create network in vCloud director
4865
4866 Args:
4867 network_name - is network name to be created.
bhangare0e571a92017-01-12 04:02:23 -08004868 net_type - can be 'bridge','data','ptp','mgmt'.
4869 ip_profile is a dict containing the IP parameters of the network
4870 isshared - is a boolean
bayramovef390722016-09-27 03:34:46 -07004871 parent_network_uuid - is parent provider vdc network that will be used for mapping.
4872 It optional attribute. by default if no parent network indicate the first available will be used.
4873
4874 Returns:
4875 The return network uuid or return None
4876 """
sousaedu2ad85172021-02-17 15:05:18 +01004877 new_network_name = [network_name, "-", str(uuid.uuid4())]
4878 content = self.create_network_rest(
4879 network_name="".join(new_network_name),
4880 ip_profile=ip_profile,
4881 net_type=net_type,
4882 parent_network_uuid=parent_network_uuid,
4883 isshared=isshared,
4884 )
bayramovef390722016-09-27 03:34:46 -07004885
bayramovef390722016-09-27 03:34:46 -07004886 if content is None:
4887 self.logger.debug("Failed create network {}.".format(network_name))
sousaedu2ad85172021-02-17 15:05:18 +01004888
bayramovef390722016-09-27 03:34:46 -07004889 return None
4890
4891 try:
4892 vm_list_xmlroot = XmlElementTree.fromstring(content)
sousaedu2ad85172021-02-17 15:05:18 +01004893 vcd_uuid = vm_list_xmlroot.get("id").split(":")
bayramovef390722016-09-27 03:34:46 -07004894 if len(vcd_uuid) == 4:
sousaedu2ad85172021-02-17 15:05:18 +01004895 self.logger.info(
4896 "Created new network name: {} uuid: {}".format(
4897 network_name, vcd_uuid[3]
4898 )
4899 )
4900
bayramovef390722016-09-27 03:34:46 -07004901 return vcd_uuid[3]
beierlb22ce2d2019-12-12 12:09:51 -05004902 except Exception:
bayramovef390722016-09-27 03:34:46 -07004903 self.logger.debug("Failed create network {}".format(network_name))
sousaedu2ad85172021-02-17 15:05:18 +01004904
bayramovef390722016-09-27 03:34:46 -07004905 return None
4906
sousaedu2ad85172021-02-17 15:05:18 +01004907 def create_network_rest(
4908 self,
4909 network_name=None,
4910 net_type="bridge",
4911 parent_network_uuid=None,
4912 ip_profile=None,
4913 isshared="true",
4914 ):
bayramovef390722016-09-27 03:34:46 -07004915 """
4916 Method create network in vCloud director
4917
4918 Args:
4919 network_name - is network name to be created.
bhangare0e571a92017-01-12 04:02:23 -08004920 net_type - can be 'bridge','data','ptp','mgmt'.
4921 ip_profile is a dict containing the IP parameters of the network
4922 isshared - is a boolean
bayramovef390722016-09-27 03:34:46 -07004923 parent_network_uuid - is parent provider vdc network that will be used for mapping.
4924 It optional attribute. by default if no parent network indicate the first available will be used.
4925
4926 Returns:
4927 The return network uuid or return None
4928 """
kasarc5bf2932018-03-09 04:15:22 -08004929 client_as_admin = self.connect_as_admin()
sousaedu2ad85172021-02-17 15:05:18 +01004930
kasarc5bf2932018-03-09 04:15:22 -08004931 if not client_as_admin:
tierno72774862020-05-04 11:44:15 +00004932 raise vimconn.VimConnConnectionException("Failed to connect vCD.")
sousaedu2ad85172021-02-17 15:05:18 +01004933
bayramovef390722016-09-27 03:34:46 -07004934 if network_name is None:
4935 return None
4936
sousaedu2ad85172021-02-17 15:05:18 +01004937 url_list = [self.url, "/api/admin/vdc/", self.tenant_id]
4938 vm_list_rest_call = "".join(url_list)
kasarc5bf2932018-03-09 04:15:22 -08004939
4940 if client_as_admin._session:
sousaedu2ad85172021-02-17 15:05:18 +01004941 headers = {
4942 "Accept": "application/*+xml;version=" + API_VERSION,
4943 "x-vcloud-authorization": client_as_admin._session.headers[
4944 "x-vcloud-authorization"
4945 ],
4946 }
4947 response = self.perform_request(
4948 req_type="GET", url=vm_list_rest_call, headers=headers
4949 )
bayramovef390722016-09-27 03:34:46 -07004950 provider_network = None
4951 available_networks = None
4952 add_vdc_rest_url = None
4953
4954 if response.status_code != requests.codes.ok:
sousaedu2ad85172021-02-17 15:05:18 +01004955 self.logger.debug(
4956 "REST API call {} failed. Return status code {}".format(
4957 vm_list_rest_call, response.status_code
4958 )
4959 )
4960
bayramovef390722016-09-27 03:34:46 -07004961 return None
4962 else:
4963 try:
beierl26fec002019-12-06 17:06:40 -05004964 vm_list_xmlroot = XmlElementTree.fromstring(response.text)
bayramovef390722016-09-27 03:34:46 -07004965 for child in vm_list_xmlroot:
sousaedu2ad85172021-02-17 15:05:18 +01004966 if child.tag.split("}")[1] == "ProviderVdcReference":
4967 provider_network = child.attrib.get("href")
bayramovef390722016-09-27 03:34:46 -07004968 # application/vnd.vmware.admin.providervdc+xml
sousaedu2ad85172021-02-17 15:05:18 +01004969
4970 if child.tag.split("}")[1] == "Link":
4971 if (
4972 child.attrib.get("type")
4973 == "application/vnd.vmware.vcloud.orgVdcNetwork+xml"
4974 and child.attrib.get("rel") == "add"
4975 ):
4976 add_vdc_rest_url = child.attrib.get("href")
beierlb22ce2d2019-12-12 12:09:51 -05004977 except Exception:
sousaedu2ad85172021-02-17 15:05:18 +01004978 self.logger.debug(
4979 "Failed parse respond for rest api call {}".format(
4980 vm_list_rest_call
4981 )
4982 )
beierl26fec002019-12-06 17:06:40 -05004983 self.logger.debug("Respond body {}".format(response.text))
sousaedu2ad85172021-02-17 15:05:18 +01004984
bayramovef390722016-09-27 03:34:46 -07004985 return None
4986
4987 # find pvdc provided available network
sousaedu2ad85172021-02-17 15:05:18 +01004988 response = self.perform_request(
4989 req_type="GET", url=provider_network, headers=headers
4990 )
kbsuba85c54d2019-10-17 16:30:32 +00004991
bayramovef390722016-09-27 03:34:46 -07004992 if response.status_code != requests.codes.ok:
sousaedu2ad85172021-02-17 15:05:18 +01004993 self.logger.debug(
4994 "REST API call {} failed. Return status code {}".format(
4995 vm_list_rest_call, response.status_code
4996 )
4997 )
4998
bayramovef390722016-09-27 03:34:46 -07004999 return None
5000
bayramovef390722016-09-27 03:34:46 -07005001 if parent_network_uuid is None:
5002 try:
beierl26fec002019-12-06 17:06:40 -05005003 vm_list_xmlroot = XmlElementTree.fromstring(response.text)
bayramovef390722016-09-27 03:34:46 -07005004 for child in vm_list_xmlroot.iter():
sousaedu2ad85172021-02-17 15:05:18 +01005005 if child.tag.split("}")[1] == "AvailableNetworks":
bayramovef390722016-09-27 03:34:46 -07005006 for networks in child.iter():
5007 # application/vnd.vmware.admin.network+xml
sousaedu2ad85172021-02-17 15:05:18 +01005008 if networks.attrib.get("href") is not None:
5009 available_networks = networks.attrib.get("href")
bayramovef390722016-09-27 03:34:46 -07005010 break
beierlb22ce2d2019-12-12 12:09:51 -05005011 except Exception:
bayramovef390722016-09-27 03:34:46 -07005012 return None
5013
bhangarebfdca492017-03-11 01:32:46 -08005014 try:
beierlb22ce2d2019-12-12 12:09:51 -05005015 # Configure IP profile of the network
sousaedu2ad85172021-02-17 15:05:18 +01005016 ip_profile = (
5017 ip_profile if ip_profile is not None else DEFAULT_IP_PROFILE
5018 )
bhangare0e571a92017-01-12 04:02:23 -08005019
sousaedu2ad85172021-02-17 15:05:18 +01005020 if (
5021 "subnet_address" not in ip_profile
5022 or ip_profile["subnet_address"] is None
5023 ):
kasarde691232017-03-25 03:37:31 -07005024 subnet_rand = random.randint(0, 255)
5025 ip_base = "192.168.{}.".format(subnet_rand)
sousaedu2ad85172021-02-17 15:05:18 +01005026 ip_profile["subnet_address"] = ip_base + "0/24"
kasarde691232017-03-25 03:37:31 -07005027 else:
sousaedu2ad85172021-02-17 15:05:18 +01005028 ip_base = ip_profile["subnet_address"].rsplit(".", 1)[0] + "."
kasarde691232017-03-25 03:37:31 -07005029
sousaedu2ad85172021-02-17 15:05:18 +01005030 if (
5031 "gateway_address" not in ip_profile
5032 or ip_profile["gateway_address"] is None
5033 ):
5034 ip_profile["gateway_address"] = ip_base + "1"
bhangare0e571a92017-01-12 04:02:23 -08005035
sousaedu2ad85172021-02-17 15:05:18 +01005036 if "dhcp_count" not in ip_profile or ip_profile["dhcp_count"] is None:
5037 ip_profile["dhcp_count"] = DEFAULT_IP_PROFILE["dhcp_count"]
bhangare0e571a92017-01-12 04:02:23 -08005038
sousaedu2ad85172021-02-17 15:05:18 +01005039 if (
5040 "dhcp_enabled" not in ip_profile
5041 or ip_profile["dhcp_enabled"] is None
5042 ):
5043 ip_profile["dhcp_enabled"] = DEFAULT_IP_PROFILE["dhcp_enabled"]
5044
5045 if (
5046 "dhcp_start_address" not in ip_profile
5047 or ip_profile["dhcp_start_address"] is None
5048 ):
5049 ip_profile["dhcp_start_address"] = ip_base + "3"
5050
5051 if "ip_version" not in ip_profile or ip_profile["ip_version"] is None:
5052 ip_profile["ip_version"] = DEFAULT_IP_PROFILE["ip_version"]
5053
5054 if "dns_address" not in ip_profile or ip_profile["dns_address"] is None:
5055 ip_profile["dns_address"] = ip_base + "2"
5056
5057 gateway_address = ip_profile["gateway_address"]
5058 dhcp_count = int(ip_profile["dhcp_count"])
5059 subnet_address = self.convert_cidr_to_netmask(
5060 ip_profile["subnet_address"]
5061 )
5062
5063 if ip_profile["dhcp_enabled"] is True:
5064 dhcp_enabled = "true"
bhangarebfdca492017-03-11 01:32:46 -08005065 else:
sousaedu2ad85172021-02-17 15:05:18 +01005066 dhcp_enabled = "false"
5067
5068 dhcp_start_address = ip_profile["dhcp_start_address"]
bhangare0e571a92017-01-12 04:02:23 -08005069
beierlb22ce2d2019-12-12 12:09:51 -05005070 # derive dhcp_end_address from dhcp_start_address & dhcp_count
bhangarebfdca492017-03-11 01:32:46 -08005071 end_ip_int = int(netaddr.IPAddress(dhcp_start_address))
5072 end_ip_int += dhcp_count - 1
5073 dhcp_end_address = str(netaddr.IPAddress(end_ip_int))
5074
beierlb22ce2d2019-12-12 12:09:51 -05005075 # ip_version = ip_profile['ip_version']
sousaedu2ad85172021-02-17 15:05:18 +01005076 dns_address = ip_profile["dns_address"]
bhangarebfdca492017-03-11 01:32:46 -08005077 except KeyError as exp:
5078 self.logger.debug("Create Network REST: Key error {}".format(exp))
sousaedu2ad85172021-02-17 15:05:18 +01005079
5080 raise vimconn.VimConnException(
5081 "Create Network REST: Key error{}".format(exp)
5082 )
bhangare0e571a92017-01-12 04:02:23 -08005083
bayramovef390722016-09-27 03:34:46 -07005084 # either use client provided UUID or search for a first available
5085 # if both are not defined we return none
5086 if parent_network_uuid is not None:
Ravi Chamartyb0ab2c02018-10-26 01:40:50 +00005087 provider_network = None
5088 available_networks = None
5089 add_vdc_rest_url = None
sousaedu2ad85172021-02-17 15:05:18 +01005090 url_list = [self.url, "/api/admin/vdc/", self.tenant_id, "/networks"]
5091 add_vdc_rest_url = "".join(url_list)
5092 url_list = [self.url, "/api/admin/network/", parent_network_uuid]
5093 available_networks = "".join(url_list)
Ravi Chamartyb0ab2c02018-10-26 01:40:50 +00005094
beierlb22ce2d2019-12-12 12:09:51 -05005095 # Creating all networks as Direct Org VDC type networks.
5096 # Unused in case of Underlay (data/ptp) network interface.
5097 fence_mode = "isolated"
sousaedu2ad85172021-02-17 15:05:18 +01005098 is_inherited = "false"
tierno455612d2017-05-30 16:40:10 +02005099 dns_list = dns_address.split(";")
5100 dns1 = dns_list[0]
5101 dns2_text = ""
sousaedu2ad85172021-02-17 15:05:18 +01005102
tierno455612d2017-05-30 16:40:10 +02005103 if len(dns_list) >= 2:
sousaedu2ad85172021-02-17 15:05:18 +01005104 dns2_text = "\n <Dns2>{}</Dns2>\n".format(
5105 dns_list[1]
5106 )
5107
kbsuba85c54d2019-10-17 16:30:32 +00005108 if net_type == "isolated":
beierlb22ce2d2019-12-12 12:09:51 -05005109 fence_mode = "isolated"
kbsuba85c54d2019-10-17 16:30:32 +00005110 data = """ <OrgVdcNetwork name="{0:s}" xmlns="http://www.vmware.com/vcloud/v1.5">
5111 <Description>Openmano created</Description>
5112 <Configuration>
5113 <IpScopes>
5114 <IpScope>
5115 <IsInherited>{1:s}</IsInherited>
5116 <Gateway>{2:s}</Gateway>
5117 <Netmask>{3:s}</Netmask>
5118 <Dns1>{4:s}</Dns1>{5:s}
5119 <IsEnabled>{6:s}</IsEnabled>
5120 <IpRanges>
5121 <IpRange>
5122 <StartAddress>{7:s}</StartAddress>
5123 <EndAddress>{8:s}</EndAddress>
5124 </IpRange>
5125 </IpRanges>
5126 </IpScope>
5127 </IpScopes>
5128 <FenceMode>{9:s}</FenceMode>
5129 </Configuration>
5130 <IsShared>{10:s}</IsShared>
sousaedu2ad85172021-02-17 15:05:18 +01005131 </OrgVdcNetwork> """.format(
5132 escape(network_name),
5133 is_inherited,
5134 gateway_address,
5135 subnet_address,
5136 dns1,
5137 dns2_text,
5138 dhcp_enabled,
5139 dhcp_start_address,
5140 dhcp_end_address,
5141 fence_mode,
5142 isshared,
5143 )
kbsuba85c54d2019-10-17 16:30:32 +00005144 else:
5145 fence_mode = "bridged"
5146 data = """ <OrgVdcNetwork name="{0:s}" xmlns="http://www.vmware.com/vcloud/v1.5">
5147 <Description>Openmano created</Description>
5148 <Configuration>
5149 <IpScopes>
5150 <IpScope>
5151 <IsInherited>{1:s}</IsInherited>
5152 <Gateway>{2:s}</Gateway>
5153 <Netmask>{3:s}</Netmask>
5154 <Dns1>{4:s}</Dns1>{5:s}
5155 <IsEnabled>{6:s}</IsEnabled>
5156 <IpRanges>
5157 <IpRange>
5158 <StartAddress>{7:s}</StartAddress>
5159 <EndAddress>{8:s}</EndAddress>
5160 </IpRange>
5161 </IpRanges>
5162 </IpScope>
5163 </IpScopes>
5164 <ParentNetwork href="{9:s}"/>
5165 <FenceMode>{10:s}</FenceMode>
5166 </Configuration>
5167 <IsShared>{11:s}</IsShared>
sousaedu2ad85172021-02-17 15:05:18 +01005168 </OrgVdcNetwork> """.format(
5169 escape(network_name),
5170 is_inherited,
5171 gateway_address,
5172 subnet_address,
5173 dns1,
5174 dns2_text,
5175 dhcp_enabled,
5176 dhcp_start_address,
5177 dhcp_end_address,
5178 available_networks,
5179 fence_mode,
5180 isshared,
5181 )
bayramovef390722016-09-27 03:34:46 -07005182
sousaedu2ad85172021-02-17 15:05:18 +01005183 headers["Content-Type"] = "application/vnd.vmware.vcloud.orgVdcNetwork+xml"
bhangare0e571a92017-01-12 04:02:23 -08005184 try:
sousaedu2ad85172021-02-17 15:05:18 +01005185 response = self.perform_request(
5186 req_type="POST", url=add_vdc_rest_url, headers=headers, data=data
5187 )
bayramovef390722016-09-27 03:34:46 -07005188
bhangare0e571a92017-01-12 04:02:23 -08005189 if response.status_code != 201:
sousaedu2ad85172021-02-17 15:05:18 +01005190 self.logger.debug(
5191 "Create Network POST REST API call failed. "
5192 "Return status code {}, response.text: {}".format(
5193 response.status_code, response.text
5194 )
5195 )
bhangare0e571a92017-01-12 04:02:23 -08005196 else:
beierl26fec002019-12-06 17:06:40 -05005197 network_task = self.get_task_from_response(response.text)
sousaedu2ad85172021-02-17 15:05:18 +01005198 self.logger.debug(
5199 "Create Network REST : Waiting for Network creation complete"
5200 )
kasarc5bf2932018-03-09 04:15:22 -08005201 time.sleep(5)
sousaedu2ad85172021-02-17 15:05:18 +01005202 result = self.client.get_task_monitor().wait_for_success(
5203 task=network_task
5204 )
5205
5206 if result.get("status") == "success":
beierl26fec002019-12-06 17:06:40 -05005207 return response.text
kasarc5bf2932018-03-09 04:15:22 -08005208 else:
sousaedu2ad85172021-02-17 15:05:18 +01005209 self.logger.debug(
5210 "create_network_rest task failed. Network Create response : {}".format(
5211 response.text
5212 )
5213 )
bhangare0e571a92017-01-12 04:02:23 -08005214 except Exception as exp:
5215 self.logger.debug("create_network_rest : Exception : {} ".format(exp))
5216
5217 return None
5218
5219 def convert_cidr_to_netmask(self, cidr_ip=None):
5220 """
5221 Method sets convert CIDR netmask address to normal IP format
5222 Args:
5223 cidr_ip : CIDR IP address
5224 Returns:
5225 netmask : Converted netmask
5226 """
5227 if cidr_ip is not None:
sousaedu2ad85172021-02-17 15:05:18 +01005228 if "/" in cidr_ip:
5229 _, net_bits = cidr_ip.split("/")
5230 netmask = socket.inet_ntoa(
5231 struct.pack(">I", (0xFFFFFFFF << (32 - int(net_bits))) & 0xFFFFFFFF)
5232 )
bhangare0e571a92017-01-12 04:02:23 -08005233 else:
5234 netmask = cidr_ip
sousaedu2ad85172021-02-17 15:05:18 +01005235
bhangare0e571a92017-01-12 04:02:23 -08005236 return netmask
sousaedu2ad85172021-02-17 15:05:18 +01005237
bayramovef390722016-09-27 03:34:46 -07005238 return None
5239
5240 def get_provider_rest(self, vca=None):
5241 """
5242 Method gets provider vdc view from vcloud director
5243
5244 Args:
5245 network_name - is network name to be created.
5246 parent_network_uuid - is parent provider vdc network that will be used for mapping.
5247 It optional attribute. by default if no parent network indicate the first available will be used.
5248
5249 Returns:
5250 The return xml content of respond or None
5251 """
sousaedu2ad85172021-02-17 15:05:18 +01005252 url_list = [self.url, "/api/admin"]
bayramovef390722016-09-27 03:34:46 -07005253
kasarc5bf2932018-03-09 04:15:22 -08005254 if vca:
sousaedu2ad85172021-02-17 15:05:18 +01005255 headers = {
5256 "Accept": "application/*+xml;version=" + API_VERSION,
5257 "x-vcloud-authorization": self.client._session.headers[
5258 "x-vcloud-authorization"
5259 ],
5260 }
5261 response = self.perform_request(
5262 req_type="GET", url="".join(url_list), headers=headers
5263 )
bayramovef390722016-09-27 03:34:46 -07005264
5265 if response.status_code == requests.codes.ok:
beierl26fec002019-12-06 17:06:40 -05005266 return response.text
sousaedu2ad85172021-02-17 15:05:18 +01005267
bayramovef390722016-09-27 03:34:46 -07005268 return None
5269
5270 def create_vdc(self, vdc_name=None):
bayramovef390722016-09-27 03:34:46 -07005271 vdc_dict = {}
bayramovef390722016-09-27 03:34:46 -07005272 xml_content = self.create_vdc_from_tmpl_rest(vdc_name=vdc_name)
sousaedu2ad85172021-02-17 15:05:18 +01005273
bayramovef390722016-09-27 03:34:46 -07005274 if xml_content is not None:
bayramovef390722016-09-27 03:34:46 -07005275 try:
5276 task_resp_xmlroot = XmlElementTree.fromstring(xml_content)
5277 for child in task_resp_xmlroot:
sousaedu2ad85172021-02-17 15:05:18 +01005278 if child.tag.split("}")[1] == "Owner":
5279 vdc_id = child.attrib.get("href").split("/")[-1]
5280 vdc_dict[vdc_id] = task_resp_xmlroot.get("href")
5281
bayramovef390722016-09-27 03:34:46 -07005282 return vdc_dict
beierlb22ce2d2019-12-12 12:09:51 -05005283 except Exception:
bayramovef390722016-09-27 03:34:46 -07005284 self.logger.debug("Respond body {}".format(xml_content))
5285
5286 return None
5287
5288 def create_vdc_from_tmpl_rest(self, vdc_name=None):
5289 """
5290 Method create vdc in vCloud director based on VDC template.
kasarc5bf2932018-03-09 04:15:22 -08005291 it uses pre-defined template.
bayramovef390722016-09-27 03:34:46 -07005292
5293 Args:
5294 vdc_name - name of a new vdc.
5295
5296 Returns:
5297 The return xml content of respond or None
5298 """
kasarc5bf2932018-03-09 04:15:22 -08005299 # pre-requesite atleast one vdc template should be available in vCD
bayramovef390722016-09-27 03:34:46 -07005300 self.logger.info("Creating new vdc {}".format(vdc_name))
kasarc5bf2932018-03-09 04:15:22 -08005301 vca = self.connect_as_admin()
sousaedu2ad85172021-02-17 15:05:18 +01005302
bayramovef390722016-09-27 03:34:46 -07005303 if not vca:
tierno72774862020-05-04 11:44:15 +00005304 raise vimconn.VimConnConnectionException("Failed to connect vCD")
sousaedu2ad85172021-02-17 15:05:18 +01005305
bayramovef390722016-09-27 03:34:46 -07005306 if vdc_name is None:
5307 return None
5308
sousaedu2ad85172021-02-17 15:05:18 +01005309 url_list = [self.url, "/api/vdcTemplates"]
5310 vm_list_rest_call = "".join(url_list)
5311 headers = {
5312 "Accept": "application/*+xml;version=" + API_VERSION,
5313 "x-vcloud-authorization": vca._session.headers["x-vcloud-authorization"],
5314 }
5315 response = self.perform_request(
5316 req_type="GET", url=vm_list_rest_call, headers=headers
5317 )
bayramovef390722016-09-27 03:34:46 -07005318
5319 # container url to a template
5320 vdc_template_ref = None
5321 try:
beierl26fec002019-12-06 17:06:40 -05005322 vm_list_xmlroot = XmlElementTree.fromstring(response.text)
bayramovef390722016-09-27 03:34:46 -07005323 for child in vm_list_xmlroot:
5324 # application/vnd.vmware.admin.providervdc+xml
5325 # we need find a template from witch we instantiate VDC
sousaedu2ad85172021-02-17 15:05:18 +01005326 if child.tag.split("}")[1] == "VdcTemplate":
5327 if (
5328 child.attrib.get("type")
5329 == "application/vnd.vmware.admin.vdcTemplate+xml"
5330 ):
5331 vdc_template_ref = child.attrib.get("href")
beierlb22ce2d2019-12-12 12:09:51 -05005332 except Exception:
sousaedu2ad85172021-02-17 15:05:18 +01005333 self.logger.debug(
5334 "Failed parse respond for rest api call {}".format(vm_list_rest_call)
5335 )
beierl26fec002019-12-06 17:06:40 -05005336 self.logger.debug("Respond body {}".format(response.text))
sousaedu2ad85172021-02-17 15:05:18 +01005337
bayramovef390722016-09-27 03:34:46 -07005338 return None
5339
5340 # if we didn't found required pre defined template we return None
5341 if vdc_template_ref is None:
5342 return None
5343
5344 try:
5345 # instantiate vdc
sousaedu2ad85172021-02-17 15:05:18 +01005346 url_list = [self.url, "/api/org/", self.org_uuid, "/action/instantiate"]
5347 vm_list_rest_call = "".join(url_list)
bayramovef390722016-09-27 03:34:46 -07005348 data = """<InstantiateVdcTemplateParams name="{0:s}" xmlns="http://www.vmware.com/vcloud/v1.5">
5349 <Source href="{1:s}"></Source>
5350 <Description>opnemano</Description>
sousaedu2ad85172021-02-17 15:05:18 +01005351 </InstantiateVdcTemplateParams>""".format(
5352 vdc_name, vdc_template_ref
5353 )
5354 headers[
5355 "Content-Type"
5356 ] = "application/vnd.vmware.vcloud.instantiateVdcTemplateParams+xml"
5357 response = self.perform_request(
5358 req_type="POST", url=vm_list_rest_call, headers=headers, data=data
5359 )
beierl26fec002019-12-06 17:06:40 -05005360 vdc_task = self.get_task_from_response(response.text)
kasarc5bf2932018-03-09 04:15:22 -08005361 self.client.get_task_monitor().wait_for_success(task=vdc_task)
kated47ad5f2017-08-03 02:16:13 -07005362
bayramovef390722016-09-27 03:34:46 -07005363 # if we all ok we respond with content otherwise by default None
5364 if response.status_code >= 200 and response.status_code < 300:
beierl26fec002019-12-06 17:06:40 -05005365 return response.text
sousaedu2ad85172021-02-17 15:05:18 +01005366
bayramovef390722016-09-27 03:34:46 -07005367 return None
beierlb22ce2d2019-12-12 12:09:51 -05005368 except Exception:
sousaedu2ad85172021-02-17 15:05:18 +01005369 self.logger.debug(
5370 "Failed parse respond for rest api call {}".format(vm_list_rest_call)
5371 )
beierl26fec002019-12-06 17:06:40 -05005372 self.logger.debug("Respond body {}".format(response.text))
bayramovef390722016-09-27 03:34:46 -07005373
5374 return None
5375
5376 def create_vdc_rest(self, vdc_name=None):
5377 """
5378 Method create network in vCloud director
5379
5380 Args:
kasarc5bf2932018-03-09 04:15:22 -08005381 vdc_name - vdc name to be created
bayramovef390722016-09-27 03:34:46 -07005382 Returns:
kasarc5bf2932018-03-09 04:15:22 -08005383 The return response
bayramovef390722016-09-27 03:34:46 -07005384 """
bayramovef390722016-09-27 03:34:46 -07005385 self.logger.info("Creating new vdc {}".format(vdc_name))
bayramovef390722016-09-27 03:34:46 -07005386 vca = self.connect_as_admin()
sousaedu2ad85172021-02-17 15:05:18 +01005387
bayramovef390722016-09-27 03:34:46 -07005388 if not vca:
tierno72774862020-05-04 11:44:15 +00005389 raise vimconn.VimConnConnectionException("Failed to connect vCD")
sousaedu2ad85172021-02-17 15:05:18 +01005390
bayramovef390722016-09-27 03:34:46 -07005391 if vdc_name is None:
5392 return None
5393
sousaedu2ad85172021-02-17 15:05:18 +01005394 url_list = [self.url, "/api/admin/org/", self.org_uuid]
5395 vm_list_rest_call = "".join(url_list)
kasarc5bf2932018-03-09 04:15:22 -08005396
5397 if vca._session:
sousaedu2ad85172021-02-17 15:05:18 +01005398 headers = {
5399 "Accept": "application/*+xml;version=" + API_VERSION,
5400 "x-vcloud-authorization": self.client._session.headers[
5401 "x-vcloud-authorization"
5402 ],
5403 }
5404 response = self.perform_request(
5405 req_type="GET", url=vm_list_rest_call, headers=headers
5406 )
bayramovef390722016-09-27 03:34:46 -07005407 provider_vdc_ref = None
5408 add_vdc_rest_url = None
beierlb22ce2d2019-12-12 12:09:51 -05005409 # available_networks = None
bayramovef390722016-09-27 03:34:46 -07005410
5411 if response.status_code != requests.codes.ok:
sousaedu2ad85172021-02-17 15:05:18 +01005412 self.logger.debug(
5413 "REST API call {} failed. Return status code {}".format(
5414 vm_list_rest_call, response.status_code
5415 )
5416 )
5417
bayramovef390722016-09-27 03:34:46 -07005418 return None
5419 else:
5420 try:
beierl26fec002019-12-06 17:06:40 -05005421 vm_list_xmlroot = XmlElementTree.fromstring(response.text)
bayramovef390722016-09-27 03:34:46 -07005422 for child in vm_list_xmlroot:
5423 # application/vnd.vmware.admin.providervdc+xml
sousaedu2ad85172021-02-17 15:05:18 +01005424 if child.tag.split("}")[1] == "Link":
5425 if (
5426 child.attrib.get("type")
5427 == "application/vnd.vmware.admin.createVdcParams+xml"
5428 and child.attrib.get("rel") == "add"
5429 ):
5430 add_vdc_rest_url = child.attrib.get("href")
beierlb22ce2d2019-12-12 12:09:51 -05005431 except Exception:
sousaedu2ad85172021-02-17 15:05:18 +01005432 self.logger.debug(
5433 "Failed parse respond for rest api call {}".format(
5434 vm_list_rest_call
5435 )
5436 )
beierl26fec002019-12-06 17:06:40 -05005437 self.logger.debug("Respond body {}".format(response.text))
sousaedu2ad85172021-02-17 15:05:18 +01005438
bayramovef390722016-09-27 03:34:46 -07005439 return None
5440
5441 response = self.get_provider_rest(vca=vca)
bayramovef390722016-09-27 03:34:46 -07005442 try:
5443 vm_list_xmlroot = XmlElementTree.fromstring(response)
5444 for child in vm_list_xmlroot:
sousaedu2ad85172021-02-17 15:05:18 +01005445 if child.tag.split("}")[1] == "ProviderVdcReferences":
bayramovef390722016-09-27 03:34:46 -07005446 for sub_child in child:
sousaedu2ad85172021-02-17 15:05:18 +01005447 provider_vdc_ref = sub_child.attrib.get("href")
beierlb22ce2d2019-12-12 12:09:51 -05005448 except Exception:
sousaedu2ad85172021-02-17 15:05:18 +01005449 self.logger.debug(
5450 "Failed parse respond for rest api call {}".format(
5451 vm_list_rest_call
5452 )
5453 )
bayramovef390722016-09-27 03:34:46 -07005454 self.logger.debug("Respond body {}".format(response))
sousaedu2ad85172021-02-17 15:05:18 +01005455
bayramovef390722016-09-27 03:34:46 -07005456 return None
5457
bayramovef390722016-09-27 03:34:46 -07005458 if add_vdc_rest_url is not None and provider_vdc_ref is not None:
5459 data = """ <CreateVdcParams name="{0:s}" xmlns="http://www.vmware.com/vcloud/v1.5"><Description>{1:s}</Description>
5460 <AllocationModel>ReservationPool</AllocationModel>
5461 <ComputeCapacity><Cpu><Units>MHz</Units><Allocated>2048</Allocated><Limit>2048</Limit></Cpu>
5462 <Memory><Units>MB</Units><Allocated>2048</Allocated><Limit>2048</Limit></Memory>
5463 </ComputeCapacity><NicQuota>0</NicQuota><NetworkQuota>100</NetworkQuota>
5464 <VdcStorageProfile><Enabled>true</Enabled><Units>MB</Units><Limit>20480</Limit><Default>true</Default></VdcStorageProfile>
5465 <ProviderVdcReference
5466 name="Main Provider"
5467 href="{2:s}" />
sousaedu2ad85172021-02-17 15:05:18 +01005468 <UsesFastProvisioning>true</UsesFastProvisioning></CreateVdcParams>""".format(
5469 escape(vdc_name), escape(vdc_name), provider_vdc_ref
5470 )
5471 headers[
5472 "Content-Type"
5473 ] = "application/vnd.vmware.admin.createVdcParams+xml"
5474 response = self.perform_request(
5475 req_type="POST",
5476 url=add_vdc_rest_url,
5477 headers=headers,
5478 data=data,
5479 )
bayramovef390722016-09-27 03:34:46 -07005480
bayramovef390722016-09-27 03:34:46 -07005481 # if we all ok we respond with content otherwise by default None
5482 if response.status_code == 201:
beierl26fec002019-12-06 17:06:40 -05005483 return response.text
sousaedu2ad85172021-02-17 15:05:18 +01005484
bayramovef390722016-09-27 03:34:46 -07005485 return None
bayramovfe3f3c92016-10-04 07:53:41 +04005486
bhangarefda5f7c2017-01-12 23:50:34 -08005487 def get_vapp_details_rest(self, vapp_uuid=None, need_admin_access=False):
bayramovfe3f3c92016-10-04 07:53:41 +04005488 """
5489 Method retrieve vapp detail from vCloud director
5490
5491 Args:
5492 vapp_uuid - is vapp identifier.
5493
5494 Returns:
5495 The return network uuid or return None
5496 """
bayramovfe3f3c92016-10-04 07:53:41 +04005497 parsed_respond = {}
bhangarefda5f7c2017-01-12 23:50:34 -08005498 vca = None
bayramovfe3f3c92016-10-04 07:53:41 +04005499
bhangarefda5f7c2017-01-12 23:50:34 -08005500 if need_admin_access:
5501 vca = self.connect_as_admin()
5502 else:
sbhangarea8e5b782018-06-21 02:10:03 -07005503 vca = self.client
bhangarefda5f7c2017-01-12 23:50:34 -08005504
bayramovfe3f3c92016-10-04 07:53:41 +04005505 if not vca:
tierno72774862020-05-04 11:44:15 +00005506 raise vimconn.VimConnConnectionException("Failed to connect vCD")
bayramovfe3f3c92016-10-04 07:53:41 +04005507 if vapp_uuid is None:
5508 return None
5509
sousaedu2ad85172021-02-17 15:05:18 +01005510 url_list = [self.url, "/api/vApp/vapp-", vapp_uuid]
5511 get_vapp_restcall = "".join(url_list)
bhangarefda5f7c2017-01-12 23:50:34 -08005512
kasarc5bf2932018-03-09 04:15:22 -08005513 if vca._session:
sousaedu2ad85172021-02-17 15:05:18 +01005514 headers = {
5515 "Accept": "application/*+xml;version=" + API_VERSION,
5516 "x-vcloud-authorization": vca._session.headers[
5517 "x-vcloud-authorization"
5518 ],
5519 }
5520 response = self.perform_request(
5521 req_type="GET", url=get_vapp_restcall, headers=headers
5522 )
bayramovfe3f3c92016-10-04 07:53:41 +04005523
bhangare1a0b97c2017-06-21 02:20:15 -07005524 if response.status_code == 403:
beierlb22ce2d2019-12-12 12:09:51 -05005525 if need_admin_access is False:
sousaedu2ad85172021-02-17 15:05:18 +01005526 response = self.retry_rest("GET", get_vapp_restcall)
bhangare1a0b97c2017-06-21 02:20:15 -07005527
bayramovfe3f3c92016-10-04 07:53:41 +04005528 if response.status_code != requests.codes.ok:
sousaedu2ad85172021-02-17 15:05:18 +01005529 self.logger.debug(
5530 "REST API call {} failed. Return status code {}".format(
5531 get_vapp_restcall, response.status_code
5532 )
5533 )
5534
bayramovfe3f3c92016-10-04 07:53:41 +04005535 return parsed_respond
5536
5537 try:
beierl26fec002019-12-06 17:06:40 -05005538 xmlroot_respond = XmlElementTree.fromstring(response.text)
sousaedu2ad85172021-02-17 15:05:18 +01005539 parsed_respond["ovfDescriptorUploaded"] = xmlroot_respond.attrib[
5540 "ovfDescriptorUploaded"
5541 ]
beierlb22ce2d2019-12-12 12:09:51 -05005542 namespaces = {
5543 "vssd": "http://schemas.dmtf.org/wbem/wscim/1/cim-schema/2/CIM_VirtualSystemSettingData",
sousaedu2ad85172021-02-17 15:05:18 +01005544 "ovf": "http://schemas.dmtf.org/ovf/envelope/1",
5545 "vmw": "http://www.vmware.com/schema/ovf",
5546 "vm": "http://www.vmware.com/vcloud/v1.5",
5547 "rasd": "http://schemas.dmtf.org/wbem/wscim/1/cim-schema/2/CIM_ResourceAllocationSettingData",
beierlb22ce2d2019-12-12 12:09:51 -05005548 "vmext": "http://www.vmware.com/vcloud/extension/v1.5",
sousaedu2ad85172021-02-17 15:05:18 +01005549 "xmlns": "http://www.vmware.com/vcloud/v1.5",
beierlb22ce2d2019-12-12 12:09:51 -05005550 }
bayramovfe3f3c92016-10-04 07:53:41 +04005551
sousaedu2ad85172021-02-17 15:05:18 +01005552 created_section = xmlroot_respond.find("vm:DateCreated", namespaces)
bayramovfe3f3c92016-10-04 07:53:41 +04005553 if created_section is not None:
sousaedu2ad85172021-02-17 15:05:18 +01005554 parsed_respond["created"] = created_section.text
bayramovfe3f3c92016-10-04 07:53:41 +04005555
sousaedu2ad85172021-02-17 15:05:18 +01005556 network_section = xmlroot_respond.find(
5557 "vm:NetworkConfigSection/vm:NetworkConfig", namespaces
5558 )
5559 if (
5560 network_section is not None
5561 and "networkName" in network_section.attrib
5562 ):
5563 parsed_respond["networkname"] = network_section.attrib[
5564 "networkName"
5565 ]
bayramovfe3f3c92016-10-04 07:53:41 +04005566
sousaedu2ad85172021-02-17 15:05:18 +01005567 ipscopes_section = xmlroot_respond.find(
5568 "vm:NetworkConfigSection/vm:NetworkConfig/vm:Configuration/vm:IpScopes",
5569 namespaces,
5570 )
bayramovfe3f3c92016-10-04 07:53:41 +04005571 if ipscopes_section is not None:
5572 for ipscope in ipscopes_section:
5573 for scope in ipscope:
5574 tag_key = scope.tag.split("}")[1]
sousaedu2ad85172021-02-17 15:05:18 +01005575 if tag_key == "IpRanges":
bayramovfe3f3c92016-10-04 07:53:41 +04005576 ip_ranges = scope.getchildren()
5577 for ipblock in ip_ranges:
5578 for block in ipblock:
sousaedu2ad85172021-02-17 15:05:18 +01005579 parsed_respond[
5580 block.tag.split("}")[1]
5581 ] = block.text
bayramovfe3f3c92016-10-04 07:53:41 +04005582 else:
5583 parsed_respond[tag_key] = scope.text
5584
5585 # parse children section for other attrib
sousaedu2ad85172021-02-17 15:05:18 +01005586 children_section = xmlroot_respond.find("vm:Children/", namespaces)
bayramovfe3f3c92016-10-04 07:53:41 +04005587 if children_section is not None:
sousaedu2ad85172021-02-17 15:05:18 +01005588 parsed_respond["name"] = children_section.attrib["name"]
5589 parsed_respond["nestedHypervisorEnabled"] = (
5590 children_section.attrib["nestedHypervisorEnabled"]
5591 if "nestedHypervisorEnabled" in children_section.attrib
5592 else None
5593 )
5594 parsed_respond["deployed"] = children_section.attrib["deployed"]
5595 parsed_respond["status"] = children_section.attrib["status"]
5596 parsed_respond["vmuuid"] = children_section.attrib["id"].split(":")[
5597 -1
5598 ]
5599 network_adapter = children_section.find(
5600 "vm:NetworkConnectionSection", namespaces
5601 )
bayramovfe3f3c92016-10-04 07:53:41 +04005602 nic_list = []
5603 for adapters in network_adapter:
5604 adapter_key = adapters.tag.split("}")[1]
sousaedu2ad85172021-02-17 15:05:18 +01005605 if adapter_key == "PrimaryNetworkConnectionIndex":
5606 parsed_respond["primarynetwork"] = adapters.text
5607
5608 if adapter_key == "NetworkConnection":
bayramovfe3f3c92016-10-04 07:53:41 +04005609 vnic = {}
sousaedu2ad85172021-02-17 15:05:18 +01005610 if "network" in adapters.attrib:
5611 vnic["network"] = adapters.attrib["network"]
bayramovfe3f3c92016-10-04 07:53:41 +04005612 for adapter in adapters:
5613 setting_key = adapter.tag.split("}")[1]
5614 vnic[setting_key] = adapter.text
5615 nic_list.append(vnic)
5616
5617 for link in children_section:
sousaedu2ad85172021-02-17 15:05:18 +01005618 if link.tag.split("}")[1] == "Link" and "rel" in link.attrib:
5619 if link.attrib["rel"] == "screen:acquireTicket":
5620 parsed_respond["acquireTicket"] = link.attrib
bayramovfe3f3c92016-10-04 07:53:41 +04005621
sousaedu2ad85172021-02-17 15:05:18 +01005622 if link.attrib["rel"] == "screen:acquireMksTicket":
5623 parsed_respond["acquireMksTicket"] = link.attrib
5624
5625 parsed_respond["interfaces"] = nic_list
5626 vCloud_extension_section = children_section.find(
5627 "xmlns:VCloudExtension", namespaces
5628 )
bhangarefda5f7c2017-01-12 23:50:34 -08005629 if vCloud_extension_section is not None:
5630 vm_vcenter_info = {}
sousaedu2ad85172021-02-17 15:05:18 +01005631 vim_info = vCloud_extension_section.find(
5632 "vmext:VmVimInfo", namespaces
5633 )
5634 vmext = vim_info.find("vmext:VmVimObjectRef", namespaces)
5635
bhangarefda5f7c2017-01-12 23:50:34 -08005636 if vmext is not None:
sousaedu2ad85172021-02-17 15:05:18 +01005637 vm_vcenter_info["vm_moref_id"] = vmext.find(
5638 "vmext:MoRef", namespaces
5639 ).text
5640
beierlb22ce2d2019-12-12 12:09:51 -05005641 parsed_respond["vm_vcenter_info"] = vm_vcenter_info
bayramovfe3f3c92016-10-04 07:53:41 +04005642
sousaedu2ad85172021-02-17 15:05:18 +01005643 virtual_hardware_section = children_section.find(
5644 "ovf:VirtualHardwareSection", namespaces
5645 )
bhangarea92ae392017-01-12 22:30:29 -08005646 vm_virtual_hardware_info = {}
5647 if virtual_hardware_section is not None:
sousaedu2ad85172021-02-17 15:05:18 +01005648 for item in virtual_hardware_section.iterfind(
5649 "ovf:Item", namespaces
5650 ):
5651 if (
5652 item.find("rasd:Description", namespaces).text
5653 == "Hard disk"
5654 ):
beierlb22ce2d2019-12-12 12:09:51 -05005655 disk_size = item.find(
sousaedu2ad85172021-02-17 15:05:18 +01005656 "rasd:HostResource", namespaces
5657 ).attrib["{" + namespaces["vm"] + "}capacity"]
beierlb22ce2d2019-12-12 12:09:51 -05005658 vm_virtual_hardware_info["disk_size"] = disk_size
bhangarea92ae392017-01-12 22:30:29 -08005659 break
5660
5661 for link in virtual_hardware_section:
sousaedu2ad85172021-02-17 15:05:18 +01005662 if (
5663 link.tag.split("}")[1] == "Link"
5664 and "rel" in link.attrib
5665 ):
5666 if link.attrib["rel"] == "edit" and link.attrib[
5667 "href"
5668 ].endswith("/disks"):
5669 vm_virtual_hardware_info[
5670 "disk_edit_href"
5671 ] = link.attrib["href"]
bhangarea92ae392017-01-12 22:30:29 -08005672 break
5673
beierlb22ce2d2019-12-12 12:09:51 -05005674 parsed_respond["vm_virtual_hardware"] = vm_virtual_hardware_info
5675 except Exception as exp:
sousaedu2ad85172021-02-17 15:05:18 +01005676 self.logger.info(
5677 "Error occurred calling rest api for getting vApp details {}".format(
5678 exp
5679 )
5680 )
5681
bayramovfe3f3c92016-10-04 07:53:41 +04005682 return parsed_respond
5683
kasarc5bf2932018-03-09 04:15:22 -08005684 def acquire_console(self, vm_uuid=None):
bayramovfe3f3c92016-10-04 07:53:41 +04005685 if vm_uuid is None:
5686 return None
bayramovfe3f3c92016-10-04 07:53:41 +04005687
sousaedu2ad85172021-02-17 15:05:18 +01005688 if self.client._session:
5689 headers = {
5690 "Accept": "application/*+xml;version=" + API_VERSION,
5691 "x-vcloud-authorization": self.client._session.headers[
5692 "x-vcloud-authorization"
5693 ],
5694 }
5695 vm_dict = self.get_vapp_details_rest(vapp_uuid=vm_uuid)
5696 console_dict = vm_dict["acquireTicket"]
5697 console_rest_call = console_dict["href"]
5698
5699 response = self.perform_request(
5700 req_type="POST", url=console_rest_call, headers=headers
5701 )
kasarc5bf2932018-03-09 04:15:22 -08005702
bhangare1a0b97c2017-06-21 02:20:15 -07005703 if response.status_code == 403:
sousaedu2ad85172021-02-17 15:05:18 +01005704 response = self.retry_rest("POST", console_rest_call)
bayramovfe3f3c92016-10-04 07:53:41 +04005705
bayramov5761ad12016-10-04 09:00:30 +04005706 if response.status_code == requests.codes.ok:
beierl26fec002019-12-06 17:06:40 -05005707 return response.text
bayramovfe3f3c92016-10-04 07:53:41 +04005708
kate15f1c382016-12-15 01:12:40 -08005709 return None
kate13ab2c42016-12-23 01:34:24 -08005710
bhangarea92ae392017-01-12 22:30:29 -08005711 def modify_vm_disk(self, vapp_uuid, flavor_disk):
5712 """
5713 Method retrieve vm disk details
5714
5715 Args:
5716 vapp_uuid - is vapp identifier.
5717 flavor_disk - disk size as specified in VNFD (flavor)
5718
5719 Returns:
5720 The return network uuid or return None
5721 """
5722 status = None
5723 try:
beierlb22ce2d2019-12-12 12:09:51 -05005724 # Flavor disk is in GB convert it into MB
bhangarea92ae392017-01-12 22:30:29 -08005725 flavor_disk = int(flavor_disk) * 1024
5726 vm_details = self.get_vapp_details_rest(vapp_uuid)
sousaedu2ad85172021-02-17 15:05:18 +01005727
bhangarea92ae392017-01-12 22:30:29 -08005728 if vm_details:
5729 vm_name = vm_details["name"]
beierlb22ce2d2019-12-12 12:09:51 -05005730 self.logger.info("VM: {} flavor_disk :{}".format(vm_name, flavor_disk))
bhangarea92ae392017-01-12 22:30:29 -08005731
5732 if vm_details and "vm_virtual_hardware" in vm_details:
5733 vm_disk = int(vm_details["vm_virtual_hardware"]["disk_size"])
5734 disk_edit_href = vm_details["vm_virtual_hardware"]["disk_edit_href"]
beierlb22ce2d2019-12-12 12:09:51 -05005735 self.logger.info("VM: {} VM_disk :{}".format(vm_name, vm_disk))
bhangarea92ae392017-01-12 22:30:29 -08005736
5737 if flavor_disk > vm_disk:
beierlb22ce2d2019-12-12 12:09:51 -05005738 status = self.modify_vm_disk_rest(disk_edit_href, flavor_disk)
sousaedu2ad85172021-02-17 15:05:18 +01005739 self.logger.info(
5740 "Modify disk of VM {} from {} to {} MB".format(
5741 vm_name, vm_disk, flavor_disk
5742 )
5743 )
bhangarea92ae392017-01-12 22:30:29 -08005744 else:
5745 status = True
5746 self.logger.info("No need to modify disk of VM {}".format(vm_name))
5747
5748 return status
5749 except Exception as exp:
5750 self.logger.info("Error occurred while modifing disk size {}".format(exp))
5751
beierlb22ce2d2019-12-12 12:09:51 -05005752 def modify_vm_disk_rest(self, disk_href, disk_size):
bhangarea92ae392017-01-12 22:30:29 -08005753 """
5754 Method retrieve modify vm disk size
5755
5756 Args:
5757 disk_href - vCD API URL to GET and PUT disk data
5758 disk_size - disk size as specified in VNFD (flavor)
5759
5760 Returns:
5761 The return network uuid or return None
5762 """
bhangarea92ae392017-01-12 22:30:29 -08005763 if disk_href is None or disk_size is None:
5764 return None
5765
kasarc5bf2932018-03-09 04:15:22 -08005766 if self.client._session:
sousaedu2ad85172021-02-17 15:05:18 +01005767 headers = {
5768 "Accept": "application/*+xml;version=" + API_VERSION,
5769 "x-vcloud-authorization": self.client._session.headers[
5770 "x-vcloud-authorization"
5771 ],
5772 }
5773 response = self.perform_request(
5774 req_type="GET", url=disk_href, headers=headers
5775 )
bhangare1a0b97c2017-06-21 02:20:15 -07005776
5777 if response.status_code == 403:
sousaedu2ad85172021-02-17 15:05:18 +01005778 response = self.retry_rest("GET", disk_href)
bhangarea92ae392017-01-12 22:30:29 -08005779
5780 if response.status_code != requests.codes.ok:
sousaedu2ad85172021-02-17 15:05:18 +01005781 self.logger.debug(
5782 "GET REST API call {} failed. Return status code {}".format(
5783 disk_href, response.status_code
5784 )
5785 )
5786
bhangarea92ae392017-01-12 22:30:29 -08005787 return None
sousaedu2ad85172021-02-17 15:05:18 +01005788
bhangarea92ae392017-01-12 22:30:29 -08005789 try:
beierl01bd6692019-12-09 17:06:20 -05005790 lxmlroot_respond = lxmlElementTree.fromstring(response.content)
sousaedu2ad85172021-02-17 15:05:18 +01005791 namespaces = {
5792 prefix: uri for prefix, uri in lxmlroot_respond.nsmap.items() if prefix
5793 }
beierlb22ce2d2019-12-12 12:09:51 -05005794 namespaces["xmlns"] = "http://www.vmware.com/vcloud/v1.5"
bhangarea92ae392017-01-12 22:30:29 -08005795
sousaedu2ad85172021-02-17 15:05:18 +01005796 for item in lxmlroot_respond.iterfind("xmlns:Item", namespaces):
beierlb22ce2d2019-12-12 12:09:51 -05005797 if item.find("rasd:Description", namespaces).text == "Hard disk":
5798 disk_item = item.find("rasd:HostResource", namespaces)
bhangarea92ae392017-01-12 22:30:29 -08005799 if disk_item is not None:
sousaedu2ad85172021-02-17 15:05:18 +01005800 disk_item.attrib["{" + namespaces["xmlns"] + "}capacity"] = str(
5801 disk_size
5802 )
bhangarea92ae392017-01-12 22:30:29 -08005803 break
5804
sousaedu2ad85172021-02-17 15:05:18 +01005805 data = lxmlElementTree.tostring(
5806 lxmlroot_respond, encoding="utf8", method="xml", xml_declaration=True
5807 )
bhangarea92ae392017-01-12 22:30:29 -08005808
beierlb22ce2d2019-12-12 12:09:51 -05005809 # Send PUT request to modify disk size
sousaedu2ad85172021-02-17 15:05:18 +01005810 headers[
5811 "Content-Type"
5812 ] = "application/vnd.vmware.vcloud.rasdItemsList+xml; charset=ISO-8859-1"
bhangarea92ae392017-01-12 22:30:29 -08005813
sousaedu2ad85172021-02-17 15:05:18 +01005814 response = self.perform_request(
5815 req_type="PUT", url=disk_href, headers=headers, data=data
5816 )
bhangare1a0b97c2017-06-21 02:20:15 -07005817 if response.status_code == 403:
sousaedu2ad85172021-02-17 15:05:18 +01005818 add_headers = {"Content-Type": headers["Content-Type"]}
5819 response = self.retry_rest("PUT", disk_href, add_headers, data)
bhangarea92ae392017-01-12 22:30:29 -08005820
5821 if response.status_code != 202:
sousaedu2ad85172021-02-17 15:05:18 +01005822 self.logger.debug(
5823 "PUT REST API call {} failed. Return status code {}".format(
5824 disk_href, response.status_code
5825 )
5826 )
bhangarea92ae392017-01-12 22:30:29 -08005827 else:
beierl26fec002019-12-06 17:06:40 -05005828 modify_disk_task = self.get_task_from_response(response.text)
sousaedu2ad85172021-02-17 15:05:18 +01005829 result = self.client.get_task_monitor().wait_for_success(
5830 task=modify_disk_task
5831 )
5832 if result.get("status") == "success":
kasarc5bf2932018-03-09 04:15:22 -08005833 return True
5834 else:
sbhangarea8e5b782018-06-21 02:10:03 -07005835 return False
bhangarea92ae392017-01-12 22:30:29 -08005836
sousaedu2ad85172021-02-17 15:05:18 +01005837 return None
beierl26fec002019-12-06 17:06:40 -05005838 except Exception as exp:
sousaedu2ad85172021-02-17 15:05:18 +01005839 self.logger.info(
5840 "Error occurred calling rest api for modifing disk size {}".format(exp)
5841 )
5842
5843 return None
bhangarea92ae392017-01-12 22:30:29 -08005844
beierl26fec002019-12-06 17:06:40 -05005845 def add_serial_device(self, vapp_uuid):
5846 """
sousaedu2ad85172021-02-17 15:05:18 +01005847 Method to attach a serial device to a VM
beierl26fec002019-12-06 17:06:40 -05005848
sousaedu2ad85172021-02-17 15:05:18 +01005849 Args:
5850 vapp_uuid - uuid of vApp/VM
beierl26fec002019-12-06 17:06:40 -05005851
sousaedu2ad85172021-02-17 15:05:18 +01005852 Returns:
beierl26fec002019-12-06 17:06:40 -05005853 """
5854 self.logger.info("Add serial devices into vApp {}".format(vapp_uuid))
5855 _, content = self.get_vcenter_content()
5856 vm_moref_id = self.get_vm_moref_id(vapp_uuid)
sousaedu2ad85172021-02-17 15:05:18 +01005857
beierl26fec002019-12-06 17:06:40 -05005858 if vm_moref_id:
5859 try:
5860 host_obj, vm_obj = self.get_vm_obj(content, vm_moref_id)
sousaedu2ad85172021-02-17 15:05:18 +01005861 self.logger.info(
5862 "VM {} is currently on host {}".format(vm_obj, host_obj)
5863 )
beierl26fec002019-12-06 17:06:40 -05005864 if host_obj and vm_obj:
5865 spec = vim.vm.ConfigSpec()
5866 spec.deviceChange = []
5867 serial_spec = vim.vm.device.VirtualDeviceSpec()
sousaedu2ad85172021-02-17 15:05:18 +01005868 serial_spec.operation = "add"
beierl26fec002019-12-06 17:06:40 -05005869 serial_port = vim.vm.device.VirtualSerialPort()
5870 serial_port.yieldOnPoll = True
5871 backing = serial_port.URIBackingInfo()
sousaedu2ad85172021-02-17 15:05:18 +01005872 backing.serviceURI = "tcp://:65500"
5873 backing.direction = "server"
beierl26fec002019-12-06 17:06:40 -05005874 serial_port.backing = backing
5875 serial_spec.device = serial_port
5876 spec.deviceChange.append(serial_spec)
5877 vm_obj.ReconfigVM_Task(spec=spec)
beierl26fec002019-12-06 17:06:40 -05005878 self.logger.info("Adding serial device to VM {}".format(vm_obj))
5879 except vmodl.MethodFault as error:
5880 self.logger.error("Error occurred while adding PCI devices {} ", error)
5881
5882 def add_pci_devices(self, vapp_uuid, pci_devices, vmname_andid):
bhangarefda5f7c2017-01-12 23:50:34 -08005883 """
sousaedu2ad85172021-02-17 15:05:18 +01005884 Method to attach pci devices to VM
bhangarefda5f7c2017-01-12 23:50:34 -08005885
sousaedu2ad85172021-02-17 15:05:18 +01005886 Args:
5887 vapp_uuid - uuid of vApp/VM
5888 pci_devices - pci devices infromation as specified in VNFD (flavor)
bhangarefda5f7c2017-01-12 23:50:34 -08005889
sousaedu2ad85172021-02-17 15:05:18 +01005890 Returns:
5891 The status of add pci device task , vm object and
5892 vcenter_conect object
bhangarefda5f7c2017-01-12 23:50:34 -08005893 """
5894 vm_obj = None
sousaedu2ad85172021-02-17 15:05:18 +01005895 self.logger.info(
5896 "Add pci devices {} into vApp {}".format(pci_devices, vapp_uuid)
5897 )
bhangare06312472017-03-30 05:49:07 -07005898 vcenter_conect, content = self.get_vcenter_content()
5899 vm_moref_id = self.get_vm_moref_id(vapp_uuid)
kateeb044522017-03-06 23:54:39 -08005900
bhangare06312472017-03-30 05:49:07 -07005901 if vm_moref_id:
bhangarefda5f7c2017-01-12 23:50:34 -08005902 try:
5903 no_of_pci_devices = len(pci_devices)
5904 if no_of_pci_devices > 0:
beierlb22ce2d2019-12-12 12:09:51 -05005905 # Get VM and its host
bhangare06312472017-03-30 05:49:07 -07005906 host_obj, vm_obj = self.get_vm_obj(content, vm_moref_id)
sousaedu2ad85172021-02-17 15:05:18 +01005907 self.logger.info(
5908 "VM {} is currently on host {}".format(vm_obj, host_obj)
5909 )
5910
bhangarefda5f7c2017-01-12 23:50:34 -08005911 if host_obj and vm_obj:
beierlb22ce2d2019-12-12 12:09:51 -05005912 # get PCI devies from host on which vapp is currently installed
sousaedu2ad85172021-02-17 15:05:18 +01005913 avilable_pci_devices = self.get_pci_devices(
5914 host_obj, no_of_pci_devices
5915 )
bhangarefda5f7c2017-01-12 23:50:34 -08005916
5917 if avilable_pci_devices is None:
beierlb22ce2d2019-12-12 12:09:51 -05005918 # find other hosts with active pci devices
sousaedu2ad85172021-02-17 15:05:18 +01005919 (
5920 new_host_obj,
5921 avilable_pci_devices,
5922 ) = self.get_host_and_PCIdevices(content, no_of_pci_devices)
5923
5924 if (
5925 new_host_obj is not None
5926 and avilable_pci_devices is not None
5927 and len(avilable_pci_devices) > 0
5928 ):
5929 # Migrate vm to the host where PCI devices are availble
5930 self.logger.info(
5931 "Relocate VM {} on new host {}".format(
5932 vm_obj, new_host_obj
5933 )
beierlb22ce2d2019-12-12 12:09:51 -05005934 )
bhangarefda5f7c2017-01-12 23:50:34 -08005935
bhangarefda5f7c2017-01-12 23:50:34 -08005936 task = self.relocate_vm(new_host_obj, vm_obj)
5937 if task is not None:
sousaedu2ad85172021-02-17 15:05:18 +01005938 result = self.wait_for_vcenter_task(
5939 task, vcenter_conect
5940 )
5941 self.logger.info(
5942 "Migrate VM status: {}".format(result)
5943 )
bhangarefda5f7c2017-01-12 23:50:34 -08005944 host_obj = new_host_obj
5945 else:
sousaedu2ad85172021-02-17 15:05:18 +01005946 self.logger.info(
5947 "Fail to migrate VM : {}".format(result)
5948 )
tierno72774862020-05-04 11:44:15 +00005949 raise vimconn.VimConnNotFoundException(
beierlb22ce2d2019-12-12 12:09:51 -05005950 "Fail to migrate VM : {} to host {}".format(
sousaedu2ad85172021-02-17 15:05:18 +01005951 vmname_andid, new_host_obj
bhangarefda5f7c2017-01-12 23:50:34 -08005952 )
sousaedu2ad85172021-02-17 15:05:18 +01005953 )
bhangarefda5f7c2017-01-12 23:50:34 -08005954
sousaedu2ad85172021-02-17 15:05:18 +01005955 if (
5956 host_obj is not None
5957 and avilable_pci_devices is not None
5958 and len(avilable_pci_devices) > 0
5959 ):
beierlb22ce2d2019-12-12 12:09:51 -05005960 # Add PCI devices one by one
bhangarefda5f7c2017-01-12 23:50:34 -08005961 for pci_device in avilable_pci_devices:
5962 task = self.add_pci_to_vm(host_obj, vm_obj, pci_device)
5963 if task:
sousaedu2ad85172021-02-17 15:05:18 +01005964 status = self.wait_for_vcenter_task(
5965 task, vcenter_conect
5966 )
5967
bhangarefda5f7c2017-01-12 23:50:34 -08005968 if status:
sousaedu2ad85172021-02-17 15:05:18 +01005969 self.logger.info(
5970 "Added PCI device {} to VM {}".format(
5971 pci_device, str(vm_obj)
5972 )
5973 )
bhangarefda5f7c2017-01-12 23:50:34 -08005974 else:
sousaedu2ad85172021-02-17 15:05:18 +01005975 self.logger.error(
5976 "Fail to add PCI device {} to VM {}".format(
5977 pci_device, str(vm_obj)
5978 )
5979 )
5980
bhangarefda5f7c2017-01-12 23:50:34 -08005981 return True, vm_obj, vcenter_conect
5982 else:
sousaedu2ad85172021-02-17 15:05:18 +01005983 self.logger.error(
5984 "Currently there is no host with"
5985 " {} number of avaialble PCI devices required for VM {}".format(
5986 no_of_pci_devices, vmname_andid
5987 )
5988 )
5989
tierno72774862020-05-04 11:44:15 +00005990 raise vimconn.VimConnNotFoundException(
beierlb22ce2d2019-12-12 12:09:51 -05005991 "Currently there is no host with {} "
5992 "number of avaialble PCI devices required for VM {}".format(
sousaedu2ad85172021-02-17 15:05:18 +01005993 no_of_pci_devices, vmname_andid
5994 )
5995 )
bhangarefda5f7c2017-01-12 23:50:34 -08005996 else:
sousaedu2ad85172021-02-17 15:05:18 +01005997 self.logger.debug(
5998 "No infromation about PCI devices {} ", pci_devices
5999 )
bhangarefda5f7c2017-01-12 23:50:34 -08006000 except vmodl.MethodFault as error:
beierlb22ce2d2019-12-12 12:09:51 -05006001 self.logger.error("Error occurred while adding PCI devices {} ", error)
sousaedu2ad85172021-02-17 15:05:18 +01006002
bhangarefda5f7c2017-01-12 23:50:34 -08006003 return None, vm_obj, vcenter_conect
6004
6005 def get_vm_obj(self, content, mob_id):
6006 """
sousaedu2ad85172021-02-17 15:05:18 +01006007 Method to get the vsphere VM object associated with a given morf ID
6008 Args:
6009 vapp_uuid - uuid of vApp/VM
6010 content - vCenter content object
6011 mob_id - mob_id of VM
bhangarefda5f7c2017-01-12 23:50:34 -08006012
sousaedu2ad85172021-02-17 15:05:18 +01006013 Returns:
6014 VM and host object
bhangarefda5f7c2017-01-12 23:50:34 -08006015 """
6016 vm_obj = None
6017 host_obj = None
sousaedu2ad85172021-02-17 15:05:18 +01006018
beierlb22ce2d2019-12-12 12:09:51 -05006019 try:
sousaedu2ad85172021-02-17 15:05:18 +01006020 container = content.viewManager.CreateContainerView(
6021 content.rootFolder, [vim.VirtualMachine], True
6022 )
bhangarefda5f7c2017-01-12 23:50:34 -08006023 for vm in container.view:
6024 mobID = vm._GetMoId()
sousaedu2ad85172021-02-17 15:05:18 +01006025
bhangarefda5f7c2017-01-12 23:50:34 -08006026 if mobID == mob_id:
6027 vm_obj = vm
6028 host_obj = vm_obj.runtime.host
6029 break
6030 except Exception as exp:
6031 self.logger.error("Error occurred while finding VM object : {}".format(exp))
sousaedu2ad85172021-02-17 15:05:18 +01006032
bhangarefda5f7c2017-01-12 23:50:34 -08006033 return host_obj, vm_obj
6034
6035 def get_pci_devices(self, host, need_devices):
6036 """
sousaedu2ad85172021-02-17 15:05:18 +01006037 Method to get the details of pci devices on given host
6038 Args:
6039 host - vSphere host object
6040 need_devices - number of pci devices needed on host
bhangarefda5f7c2017-01-12 23:50:34 -08006041
sousaedu2ad85172021-02-17 15:05:18 +01006042 Returns:
6043 array of pci devices
bhangarefda5f7c2017-01-12 23:50:34 -08006044 """
6045 all_devices = []
6046 all_device_ids = []
6047 used_devices_ids = []
6048
6049 try:
6050 if host:
6051 pciPassthruInfo = host.config.pciPassthruInfo
6052 pciDevies = host.hardware.pciDevice
6053
6054 for pci_status in pciPassthruInfo:
6055 if pci_status.passthruActive:
6056 for device in pciDevies:
6057 if device.id == pci_status.id:
6058 all_device_ids.append(device.id)
6059 all_devices.append(device)
6060
beierlb22ce2d2019-12-12 12:09:51 -05006061 # check if devices are in use
bhangarefda5f7c2017-01-12 23:50:34 -08006062 avalible_devices = all_devices
6063 for vm in host.vm:
6064 if vm.runtime.powerState == vim.VirtualMachinePowerState.poweredOn:
6065 vm_devices = vm.config.hardware.device
6066 for device in vm_devices:
6067 if type(device) is vim.vm.device.VirtualPCIPassthrough:
6068 if device.backing.id in all_device_ids:
6069 for use_device in avalible_devices:
6070 if use_device.id == device.backing.id:
6071 avalible_devices.remove(use_device)
sousaedu2ad85172021-02-17 15:05:18 +01006072
bhangarefda5f7c2017-01-12 23:50:34 -08006073 used_devices_ids.append(device.backing.id)
sousaedu2ad85172021-02-17 15:05:18 +01006074 self.logger.debug(
6075 "Device {} from devices {}"
6076 "is in use".format(device.backing.id, device)
6077 )
bhangarefda5f7c2017-01-12 23:50:34 -08006078 if len(avalible_devices) < need_devices:
sousaedu2ad85172021-02-17 15:05:18 +01006079 self.logger.debug(
6080 "Host {} don't have {} number of active devices".format(
6081 host, need_devices
6082 )
6083 )
6084 self.logger.debug(
6085 "found only {} devices {}".format(
6086 len(avalible_devices), avalible_devices
6087 )
6088 )
6089
bhangarefda5f7c2017-01-12 23:50:34 -08006090 return None
6091 else:
6092 required_devices = avalible_devices[:need_devices]
sousaedu2ad85172021-02-17 15:05:18 +01006093 self.logger.info(
6094 "Found {} PCI devices on host {} but required only {}".format(
6095 len(avalible_devices), host, need_devices
6096 )
6097 )
6098 self.logger.info(
6099 "Retruning {} devices as {}".format(need_devices, required_devices)
6100 )
bhangarefda5f7c2017-01-12 23:50:34 -08006101
sousaedu2ad85172021-02-17 15:05:18 +01006102 return required_devices
bhangarefda5f7c2017-01-12 23:50:34 -08006103 except Exception as exp:
sousaedu2ad85172021-02-17 15:05:18 +01006104 self.logger.error(
6105 "Error {} occurred while finding pci devices on host: {}".format(
6106 exp, host
6107 )
6108 )
bhangarefda5f7c2017-01-12 23:50:34 -08006109
6110 return None
6111
6112 def get_host_and_PCIdevices(self, content, need_devices):
6113 """
sousaedu2ad85172021-02-17 15:05:18 +01006114 Method to get the details of pci devices infromation on all hosts
bhangarefda5f7c2017-01-12 23:50:34 -08006115
sousaedu2ad85172021-02-17 15:05:18 +01006116 Args:
6117 content - vSphere host object
6118 need_devices - number of pci devices needed on host
bhangarefda5f7c2017-01-12 23:50:34 -08006119
sousaedu2ad85172021-02-17 15:05:18 +01006120 Returns:
6121 array of pci devices and host object
bhangarefda5f7c2017-01-12 23:50:34 -08006122 """
6123 host_obj = None
6124 pci_device_objs = None
sousaedu2ad85172021-02-17 15:05:18 +01006125
bhangarefda5f7c2017-01-12 23:50:34 -08006126 try:
6127 if content:
sousaedu2ad85172021-02-17 15:05:18 +01006128 container = content.viewManager.CreateContainerView(
6129 content.rootFolder, [vim.HostSystem], True
6130 )
bhangarefda5f7c2017-01-12 23:50:34 -08006131 for host in container.view:
6132 devices = self.get_pci_devices(host, need_devices)
sousaedu2ad85172021-02-17 15:05:18 +01006133
bhangarefda5f7c2017-01-12 23:50:34 -08006134 if devices:
6135 host_obj = host
6136 pci_device_objs = devices
6137 break
6138 except Exception as exp:
sousaedu2ad85172021-02-17 15:05:18 +01006139 self.logger.error(
6140 "Error {} occurred while finding pci devices on host: {}".format(
6141 exp, host_obj
6142 )
6143 )
bhangarefda5f7c2017-01-12 23:50:34 -08006144
beierlb22ce2d2019-12-12 12:09:51 -05006145 return host_obj, pci_device_objs
bhangarefda5f7c2017-01-12 23:50:34 -08006146
beierlb22ce2d2019-12-12 12:09:51 -05006147 def relocate_vm(self, dest_host, vm):
bhangarefda5f7c2017-01-12 23:50:34 -08006148 """
sousaedu2ad85172021-02-17 15:05:18 +01006149 Method to get the relocate VM to new host
bhangarefda5f7c2017-01-12 23:50:34 -08006150
sousaedu2ad85172021-02-17 15:05:18 +01006151 Args:
6152 dest_host - vSphere host object
6153 vm - vSphere VM object
bhangarefda5f7c2017-01-12 23:50:34 -08006154
sousaedu2ad85172021-02-17 15:05:18 +01006155 Returns:
6156 task object
bhangarefda5f7c2017-01-12 23:50:34 -08006157 """
6158 task = None
sousaedu2ad85172021-02-17 15:05:18 +01006159
bhangarefda5f7c2017-01-12 23:50:34 -08006160 try:
6161 relocate_spec = vim.vm.RelocateSpec(host=dest_host)
6162 task = vm.Relocate(relocate_spec)
sousaedu2ad85172021-02-17 15:05:18 +01006163 self.logger.info(
6164 "Migrating {} to destination host {}".format(vm, dest_host)
6165 )
bhangarefda5f7c2017-01-12 23:50:34 -08006166 except Exception as exp:
sousaedu2ad85172021-02-17 15:05:18 +01006167 self.logger.error(
6168 "Error occurred while relocate VM {} to new host {}: {}".format(
6169 dest_host, vm, exp
6170 )
6171 )
6172
bhangarefda5f7c2017-01-12 23:50:34 -08006173 return task
6174
sousaedu2ad85172021-02-17 15:05:18 +01006175 def wait_for_vcenter_task(self, task, actionName="job", hideResult=False):
bhangarefda5f7c2017-01-12 23:50:34 -08006176 """
6177 Waits and provides updates on a vSphere task
6178 """
6179 while task.info.state == vim.TaskInfo.State.running:
6180 time.sleep(2)
6181
6182 if task.info.state == vim.TaskInfo.State.success:
6183 if task.info.result is not None and not hideResult:
sousaedu2ad85172021-02-17 15:05:18 +01006184 self.logger.info(
6185 "{} completed successfully, result: {}".format(
6186 actionName, task.info.result
6187 )
beierlb22ce2d2019-12-12 12:09:51 -05006188 )
sousaedu2ad85172021-02-17 15:05:18 +01006189 else:
6190 self.logger.info("Task {} completed successfully.".format(actionName))
6191 else:
6192 self.logger.error(
6193 "{} did not complete successfully: {} ".format(
6194 actionName, task.info.error
6195 )
6196 )
bhangarefda5f7c2017-01-12 23:50:34 -08006197
6198 return task.info.result
6199
beierlb22ce2d2019-12-12 12:09:51 -05006200 def add_pci_to_vm(self, host_object, vm_object, host_pci_dev):
bhangarefda5f7c2017-01-12 23:50:34 -08006201 """
sousaedu2ad85172021-02-17 15:05:18 +01006202 Method to add pci device in given VM
bhangarefda5f7c2017-01-12 23:50:34 -08006203
sousaedu2ad85172021-02-17 15:05:18 +01006204 Args:
6205 host_object - vSphere host object
6206 vm_object - vSphere VM object
6207 host_pci_dev - host_pci_dev must be one of the devices from the
6208 host_object.hardware.pciDevice list
6209 which is configured as a PCI passthrough device
bhangarefda5f7c2017-01-12 23:50:34 -08006210
sousaedu2ad85172021-02-17 15:05:18 +01006211 Returns:
6212 task object
bhangarefda5f7c2017-01-12 23:50:34 -08006213 """
6214 task = None
sousaedu2ad85172021-02-17 15:05:18 +01006215
bhangarefda5f7c2017-01-12 23:50:34 -08006216 if vm_object and host_object and host_pci_dev:
beierlb22ce2d2019-12-12 12:09:51 -05006217 try:
6218 # Add PCI device to VM
sousaedu2ad85172021-02-17 15:05:18 +01006219 pci_passthroughs = vm_object.environmentBrowser.QueryConfigTarget(
6220 host=None
6221 ).pciPassthrough
6222 systemid_by_pciid = {
6223 item.pciDevice.id: item.systemId for item in pci_passthroughs
6224 }
bhangarefda5f7c2017-01-12 23:50:34 -08006225
6226 if host_pci_dev.id not in systemid_by_pciid:
sousaedu2ad85172021-02-17 15:05:18 +01006227 self.logger.error(
6228 "Device {} is not a passthrough device ".format(host_pci_dev)
6229 )
bhangarefda5f7c2017-01-12 23:50:34 -08006230 return None
6231
sousaedu2ad85172021-02-17 15:05:18 +01006232 deviceId = hex(host_pci_dev.deviceId % 2 ** 16).lstrip("0x")
6233 backing = vim.VirtualPCIPassthroughDeviceBackingInfo(
6234 deviceId=deviceId,
6235 id=host_pci_dev.id,
6236 systemId=systemid_by_pciid[host_pci_dev.id],
6237 vendorId=host_pci_dev.vendorId,
6238 deviceName=host_pci_dev.deviceName,
6239 )
bhangarefda5f7c2017-01-12 23:50:34 -08006240
6241 hba_object = vim.VirtualPCIPassthrough(key=-100, backing=backing)
bhangarefda5f7c2017-01-12 23:50:34 -08006242 new_device_config = vim.VirtualDeviceConfigSpec(device=hba_object)
6243 new_device_config.operation = "add"
6244 vmConfigSpec = vim.vm.ConfigSpec()
6245 vmConfigSpec.deviceChange = [new_device_config]
bhangarefda5f7c2017-01-12 23:50:34 -08006246 task = vm_object.ReconfigVM_Task(spec=vmConfigSpec)
sousaedu2ad85172021-02-17 15:05:18 +01006247 self.logger.info(
6248 "Adding PCI device {} into VM {} from host {} ".format(
6249 host_pci_dev, vm_object, host_object
beierlb22ce2d2019-12-12 12:09:51 -05006250 )
sousaedu2ad85172021-02-17 15:05:18 +01006251 )
bhangarefda5f7c2017-01-12 23:50:34 -08006252 except Exception as exp:
sousaedu2ad85172021-02-17 15:05:18 +01006253 self.logger.error(
6254 "Error occurred while adding pci devive {} to VM {}: {}".format(
6255 host_pci_dev, vm_object, exp
6256 )
6257 )
6258
bhangarefda5f7c2017-01-12 23:50:34 -08006259 return task
6260
bhangare06312472017-03-30 05:49:07 -07006261 def get_vm_vcenter_info(self):
bhangarefda5f7c2017-01-12 23:50:34 -08006262 """
kateeb044522017-03-06 23:54:39 -08006263 Method to get details of vCenter and vm
bhangarefda5f7c2017-01-12 23:50:34 -08006264
6265 Args:
6266 vapp_uuid - uuid of vApp or VM
6267
6268 Returns:
6269 Moref Id of VM and deails of vCenter
6270 """
kateeb044522017-03-06 23:54:39 -08006271 vm_vcenter_info = {}
bhangarefda5f7c2017-01-12 23:50:34 -08006272
kateeb044522017-03-06 23:54:39 -08006273 if self.vcenter_ip is not None:
6274 vm_vcenter_info["vm_vcenter_ip"] = self.vcenter_ip
6275 else:
sousaedu2ad85172021-02-17 15:05:18 +01006276 raise vimconn.VimConnException(
6277 message="vCenter IP is not provided."
6278 " Please provide vCenter IP while attaching datacenter "
6279 "to tenant in --config"
6280 )
6281
kateeb044522017-03-06 23:54:39 -08006282 if self.vcenter_port is not None:
6283 vm_vcenter_info["vm_vcenter_port"] = self.vcenter_port
6284 else:
sousaedu2ad85172021-02-17 15:05:18 +01006285 raise vimconn.VimConnException(
6286 message="vCenter port is not provided."
6287 " Please provide vCenter port while attaching datacenter "
6288 "to tenant in --config"
6289 )
6290
kateeb044522017-03-06 23:54:39 -08006291 if self.vcenter_user is not None:
6292 vm_vcenter_info["vm_vcenter_user"] = self.vcenter_user
6293 else:
sousaedu2ad85172021-02-17 15:05:18 +01006294 raise vimconn.VimConnException(
6295 message="vCenter user is not provided."
6296 " Please provide vCenter user while attaching datacenter "
6297 "to tenant in --config"
6298 )
bhangarefda5f7c2017-01-12 23:50:34 -08006299
kateeb044522017-03-06 23:54:39 -08006300 if self.vcenter_password is not None:
6301 vm_vcenter_info["vm_vcenter_password"] = self.vcenter_password
6302 else:
sousaedu2ad85172021-02-17 15:05:18 +01006303 raise vimconn.VimConnException(
6304 message="vCenter user password is not provided."
6305 " Please provide vCenter user password while attaching datacenter "
6306 "to tenant in --config"
6307 )
bhangarefda5f7c2017-01-12 23:50:34 -08006308
bhangare06312472017-03-30 05:49:07 -07006309 return vm_vcenter_info
bhangarefda5f7c2017-01-12 23:50:34 -08006310
bhangarefda5f7c2017-01-12 23:50:34 -08006311 def get_vm_pci_details(self, vmuuid):
6312 """
sousaedu2ad85172021-02-17 15:05:18 +01006313 Method to get VM PCI device details from vCenter
bhangarefda5f7c2017-01-12 23:50:34 -08006314
sousaedu2ad85172021-02-17 15:05:18 +01006315 Args:
6316 vm_obj - vSphere VM object
bhangarefda5f7c2017-01-12 23:50:34 -08006317
sousaedu2ad85172021-02-17 15:05:18 +01006318 Returns:
6319 dict of PCI devives attached to VM
bhangarefda5f7c2017-01-12 23:50:34 -08006320
6321 """
6322 vm_pci_devices_info = {}
sousaedu2ad85172021-02-17 15:05:18 +01006323
bhangarefda5f7c2017-01-12 23:50:34 -08006324 try:
beierlb22ce2d2019-12-12 12:09:51 -05006325 _, content = self.get_vcenter_content()
bhangare06312472017-03-30 05:49:07 -07006326 vm_moref_id = self.get_vm_moref_id(vmuuid)
6327 if vm_moref_id:
beierlb22ce2d2019-12-12 12:09:51 -05006328 # Get VM and its host
kateeb044522017-03-06 23:54:39 -08006329 if content:
bhangare06312472017-03-30 05:49:07 -07006330 host_obj, vm_obj = self.get_vm_obj(content, vm_moref_id)
kateeb044522017-03-06 23:54:39 -08006331 if host_obj and vm_obj:
beierlb22ce2d2019-12-12 12:09:51 -05006332 vm_pci_devices_info["host_name"] = host_obj.name
sousaedu2ad85172021-02-17 15:05:18 +01006333 vm_pci_devices_info["host_ip"] = host_obj.config.network.vnic[
6334 0
6335 ].spec.ip.ipAddress
6336
kateeb044522017-03-06 23:54:39 -08006337 for device in vm_obj.config.hardware.device:
6338 if type(device) == vim.vm.device.VirtualPCIPassthrough:
sousaedu2ad85172021-02-17 15:05:18 +01006339 device_details = {
6340 "devide_id": device.backing.id,
6341 "pciSlotNumber": device.slotInfo.pciSlotNumber,
6342 }
6343 vm_pci_devices_info[
6344 device.deviceInfo.label
6345 ] = device_details
kateeb044522017-03-06 23:54:39 -08006346 else:
sousaedu2ad85172021-02-17 15:05:18 +01006347 self.logger.error(
6348 "Can not connect to vCenter while getting "
6349 "PCI devices infromationn"
6350 )
6351
kateeb044522017-03-06 23:54:39 -08006352 return vm_pci_devices_info
bhangarefda5f7c2017-01-12 23:50:34 -08006353 except Exception as exp:
sousaedu2ad85172021-02-17 15:05:18 +01006354 self.logger.error(
6355 "Error occurred while getting VM information" " for VM : {}".format(exp)
6356 )
6357
tierno72774862020-05-04 11:44:15 +00006358 raise vimconn.VimConnException(message=exp)
bhangare0e571a92017-01-12 04:02:23 -08006359
Ravi Chamartyb0ab2c02018-10-26 01:40:50 +00006360 def reserve_memory_for_all_vms(self, vapp, memory_mb):
6361 """
sousaedu2ad85172021-02-17 15:05:18 +01006362 Method to reserve memory for all VMs
6363 Args :
6364 vapp - VApp
6365 memory_mb - Memory in MB
6366 Returns:
6367 None
Ravi Chamartyb0ab2c02018-10-26 01:40:50 +00006368 """
Ravi Chamartyb0ab2c02018-10-26 01:40:50 +00006369 self.logger.info("Reserve memory for all VMs")
sousaedu2ad85172021-02-17 15:05:18 +01006370
Ravi Chamartyb0ab2c02018-10-26 01:40:50 +00006371 for vms in vapp.get_all_vms():
sousaedu2ad85172021-02-17 15:05:18 +01006372 vm_id = vms.get("id").split(":")[-1]
6373 url_rest_call = "{}/api/vApp/vm-{}/virtualHardwareSection/memory".format(
6374 self.url, vm_id
6375 )
6376 headers = {
6377 "Accept": "application/*+xml;version=" + API_VERSION,
6378 "x-vcloud-authorization": self.client._session.headers[
6379 "x-vcloud-authorization"
6380 ],
6381 }
6382 headers["Content-Type"] = "application/vnd.vmware.vcloud.rasdItem+xml"
6383 response = self.perform_request(
6384 req_type="GET", url=url_rest_call, headers=headers
6385 )
Ravi Chamartyb0ab2c02018-10-26 01:40:50 +00006386
6387 if response.status_code == 403:
sousaedu2ad85172021-02-17 15:05:18 +01006388 response = self.retry_rest("GET", url_rest_call)
Ravi Chamartyb0ab2c02018-10-26 01:40:50 +00006389
6390 if response.status_code != 200:
sousaedu2ad85172021-02-17 15:05:18 +01006391 self.logger.error(
6392 "REST call {} failed reason : {}"
6393 "status code : {}".format(
6394 url_rest_call, response.text, response.status_code
6395 )
6396 )
6397 raise vimconn.VimConnException(
6398 "reserve_memory_for_all_vms : Failed to get " "memory"
6399 )
Ravi Chamartyb0ab2c02018-10-26 01:40:50 +00006400
sousaedu2ad85172021-02-17 15:05:18 +01006401 bytexml = bytes(bytearray(response.text, encoding="utf-8"))
Ravi Chamartyb0ab2c02018-10-26 01:40:50 +00006402 contentelem = lxmlElementTree.XML(bytexml)
sousaedu2ad85172021-02-17 15:05:18 +01006403 namespaces = {
6404 prefix: uri for prefix, uri in contentelem.nsmap.items() if prefix
6405 }
beierlb22ce2d2019-12-12 12:09:51 -05006406 namespaces["xmlns"] = "http://www.vmware.com/vcloud/v1.5"
Ravi Chamartyb0ab2c02018-10-26 01:40:50 +00006407
6408 # Find the reservation element in the response
6409 memelem_list = contentelem.findall(".//rasd:Reservation", namespaces)
6410 for memelem in memelem_list:
6411 memelem.text = str(memory_mb)
6412
6413 newdata = lxmlElementTree.tostring(contentelem, pretty_print=True)
6414
sousaedu2ad85172021-02-17 15:05:18 +01006415 response = self.perform_request(
6416 req_type="PUT", url=url_rest_call, headers=headers, data=newdata
6417 )
Ravi Chamartyb0ab2c02018-10-26 01:40:50 +00006418
6419 if response.status_code == 403:
sousaedu2ad85172021-02-17 15:05:18 +01006420 add_headers = {"Content-Type": headers["Content-Type"]}
6421 response = self.retry_rest("PUT", url_rest_call, add_headers, newdata)
Ravi Chamartyb0ab2c02018-10-26 01:40:50 +00006422
6423 if response.status_code != 202:
sousaedu2ad85172021-02-17 15:05:18 +01006424 self.logger.error(
6425 "REST call {} failed reason : {}"
6426 "status code : {} ".format(
6427 url_rest_call, response.text, response.status_code
6428 )
6429 )
6430 raise vimconn.VimConnException(
6431 "reserve_memory_for_all_vms : Failed to update "
6432 "virtual hardware memory section"
6433 )
Ravi Chamartyb0ab2c02018-10-26 01:40:50 +00006434 else:
beierl26fec002019-12-06 17:06:40 -05006435 mem_task = self.get_task_from_response(response.text)
Ravi Chamartyb0ab2c02018-10-26 01:40:50 +00006436 result = self.client.get_task_monitor().wait_for_success(task=mem_task)
sousaedu2ad85172021-02-17 15:05:18 +01006437
6438 if result.get("status") == "success":
6439 self.logger.info(
6440 "reserve_memory_for_all_vms(): VM {} succeeded ".format(vm_id)
6441 )
Ravi Chamartyb0ab2c02018-10-26 01:40:50 +00006442 else:
sousaedu2ad85172021-02-17 15:05:18 +01006443 self.logger.error(
6444 "reserve_memory_for_all_vms(): VM {} failed ".format(vm_id)
6445 )
Ravi Chamartyb0ab2c02018-10-26 01:40:50 +00006446
6447 def connect_vapp_to_org_vdc_network(self, vapp_id, net_name):
6448 """
sousaedu2ad85172021-02-17 15:05:18 +01006449 Configure VApp network config with org vdc network
6450 Args :
6451 vapp - VApp
6452 Returns:
6453 None
Ravi Chamartyb0ab2c02018-10-26 01:40:50 +00006454 """
6455
sousaedu2ad85172021-02-17 15:05:18 +01006456 self.logger.info(
6457 "Connecting vapp {} to org vdc network {}".format(vapp_id, net_name)
6458 )
Ravi Chamartyb0ab2c02018-10-26 01:40:50 +00006459
sousaedu2ad85172021-02-17 15:05:18 +01006460 url_rest_call = "{}/api/vApp/vapp-{}/networkConfigSection/".format(
6461 self.url, vapp_id
6462 )
Ravi Chamartyb0ab2c02018-10-26 01:40:50 +00006463
sousaedu2ad85172021-02-17 15:05:18 +01006464 headers = {
6465 "Accept": "application/*+xml;version=" + API_VERSION,
6466 "x-vcloud-authorization": self.client._session.headers[
6467 "x-vcloud-authorization"
6468 ],
6469 }
6470 response = self.perform_request(
6471 req_type="GET", url=url_rest_call, headers=headers
6472 )
Ravi Chamartyb0ab2c02018-10-26 01:40:50 +00006473
6474 if response.status_code == 403:
sousaedu2ad85172021-02-17 15:05:18 +01006475 response = self.retry_rest("GET", url_rest_call)
Ravi Chamartyb0ab2c02018-10-26 01:40:50 +00006476
6477 if response.status_code != 200:
sousaedu2ad85172021-02-17 15:05:18 +01006478 self.logger.error(
6479 "REST call {} failed reason : {}"
6480 "status code : {}".format(
6481 url_rest_call, response.text, response.status_code
6482 )
6483 )
6484 raise vimconn.VimConnException(
6485 "connect_vapp_to_org_vdc_network : Failed to get "
6486 "network config section"
6487 )
Ravi Chamartyb0ab2c02018-10-26 01:40:50 +00006488
beierl26fec002019-12-06 17:06:40 -05006489 data = response.text
sousaedu2ad85172021-02-17 15:05:18 +01006490 headers[
6491 "Content-Type"
6492 ] = "application/vnd.vmware.vcloud.networkConfigSection+xml"
Ravi Chamartyb0ab2c02018-10-26 01:40:50 +00006493 net_id = self.get_network_id_by_name(net_name)
6494 if not net_id:
sousaedu2ad85172021-02-17 15:05:18 +01006495 raise vimconn.VimConnException(
6496 "connect_vapp_to_org_vdc_network : Failed to find " "existing network"
6497 )
Ravi Chamartyb0ab2c02018-10-26 01:40:50 +00006498
sousaedu2ad85172021-02-17 15:05:18 +01006499 bytexml = bytes(bytearray(data, encoding="utf-8"))
Ravi Chamartyb0ab2c02018-10-26 01:40:50 +00006500 newelem = lxmlElementTree.XML(bytexml)
tierno7d782ef2019-10-04 12:56:31 +00006501 namespaces = {prefix: uri for prefix, uri in newelem.nsmap.items() if prefix}
Ravi Chamartyb0ab2c02018-10-26 01:40:50 +00006502 namespaces["xmlns"] = "http://www.vmware.com/vcloud/v1.5"
6503 nwcfglist = newelem.findall(".//xmlns:NetworkConfig", namespaces)
6504
Ravi Chamarty259aebc2019-06-05 17:06:39 +00006505 # VCD 9.7 returns an incorrect parentnetwork element. Fix it before PUT operation
6506 parentnetworklist = newelem.findall(".//xmlns:ParentNetwork", namespaces)
6507 if parentnetworklist:
6508 for pn in parentnetworklist:
6509 if "href" not in pn.keys():
6510 id_val = pn.get("id")
6511 href_val = "{}/api/network/{}".format(self.url, id_val)
6512 pn.set("href", href_val)
6513
Ravi Chamartyb0ab2c02018-10-26 01:40:50 +00006514 newstr = """<NetworkConfig networkName="{}">
6515 <Configuration>
6516 <ParentNetwork href="{}/api/network/{}"/>
6517 <FenceMode>bridged</FenceMode>
6518 </Configuration>
6519 </NetworkConfig>
sousaedu2ad85172021-02-17 15:05:18 +01006520 """.format(
6521 net_name, self.url, net_id
6522 )
Ravi Chamartyb0ab2c02018-10-26 01:40:50 +00006523 newcfgelem = lxmlElementTree.fromstring(newstr)
6524 if nwcfglist:
6525 nwcfglist[0].addnext(newcfgelem)
6526
6527 newdata = lxmlElementTree.tostring(newelem, pretty_print=True)
6528
sousaedu2ad85172021-02-17 15:05:18 +01006529 response = self.perform_request(
6530 req_type="PUT", url=url_rest_call, headers=headers, data=newdata
6531 )
Ravi Chamartyb0ab2c02018-10-26 01:40:50 +00006532
6533 if response.status_code == 403:
sousaedu2ad85172021-02-17 15:05:18 +01006534 add_headers = {"Content-Type": headers["Content-Type"]}
6535 response = self.retry_rest("PUT", url_rest_call, add_headers, newdata)
Ravi Chamartyb0ab2c02018-10-26 01:40:50 +00006536
6537 if response.status_code != 202:
sousaedu2ad85172021-02-17 15:05:18 +01006538 self.logger.error(
6539 "REST call {} failed reason : {}"
6540 "status code : {} ".format(
6541 url_rest_call, response.text, response.status_code
6542 )
6543 )
6544 raise vimconn.VimConnException(
6545 "connect_vapp_to_org_vdc_network : Failed to update "
6546 "network config section"
6547 )
Ravi Chamartyb0ab2c02018-10-26 01:40:50 +00006548 else:
beierl26fec002019-12-06 17:06:40 -05006549 vapp_task = self.get_task_from_response(response.text)
Ravi Chamartyb0ab2c02018-10-26 01:40:50 +00006550 result = self.client.get_task_monitor().wait_for_success(task=vapp_task)
sousaedu2ad85172021-02-17 15:05:18 +01006551 if result.get("status") == "success":
6552 self.logger.info(
6553 "connect_vapp_to_org_vdc_network(): Vapp {} connected to "
6554 "network {}".format(vapp_id, net_name)
6555 )
Ravi Chamartyb0ab2c02018-10-26 01:40:50 +00006556 else:
sousaedu2ad85172021-02-17 15:05:18 +01006557 self.logger.error(
6558 "connect_vapp_to_org_vdc_network(): Vapp {} failed to "
6559 "connect to network {}".format(vapp_id, net_name)
6560 )
Ravi Chamartyb0ab2c02018-10-26 01:40:50 +00006561
Ravi Chamarty5b2d5c12018-10-22 23:59:10 +00006562 def remove_primary_network_adapter_from_all_vms(self, vapp):
6563 """
sousaedu2ad85172021-02-17 15:05:18 +01006564 Method to remove network adapter type to vm
6565 Args :
6566 vapp - VApp
6567 Returns:
6568 None
Ravi Chamarty5b2d5c12018-10-22 23:59:10 +00006569 """
Ravi Chamarty5b2d5c12018-10-22 23:59:10 +00006570 self.logger.info("Removing network adapter from all VMs")
sousaedu2ad85172021-02-17 15:05:18 +01006571
Ravi Chamarty5b2d5c12018-10-22 23:59:10 +00006572 for vms in vapp.get_all_vms():
sousaedu2ad85172021-02-17 15:05:18 +01006573 vm_id = vms.get("id").split(":")[-1]
Ravi Chamarty5b2d5c12018-10-22 23:59:10 +00006574
sousaedu2ad85172021-02-17 15:05:18 +01006575 url_rest_call = "{}/api/vApp/vm-{}/networkConnectionSection/".format(
6576 self.url, vm_id
6577 )
Ravi Chamarty5b2d5c12018-10-22 23:59:10 +00006578
sousaedu2ad85172021-02-17 15:05:18 +01006579 headers = {
6580 "Accept": "application/*+xml;version=" + API_VERSION,
6581 "x-vcloud-authorization": self.client._session.headers[
6582 "x-vcloud-authorization"
6583 ],
6584 }
6585 response = self.perform_request(
6586 req_type="GET", url=url_rest_call, headers=headers
6587 )
Ravi Chamarty5b2d5c12018-10-22 23:59:10 +00006588
6589 if response.status_code == 403:
sousaedu2ad85172021-02-17 15:05:18 +01006590 response = self.retry_rest("GET", url_rest_call)
Ravi Chamarty5b2d5c12018-10-22 23:59:10 +00006591
6592 if response.status_code != 200:
sousaedu2ad85172021-02-17 15:05:18 +01006593 self.logger.error(
6594 "REST call {} failed reason : {}"
6595 "status code : {}".format(
6596 url_rest_call, response.text, response.status_code
6597 )
6598 )
6599 raise vimconn.VimConnException(
6600 "remove_primary_network_adapter : Failed to get "
6601 "network connection section"
6602 )
Ravi Chamarty5b2d5c12018-10-22 23:59:10 +00006603
beierl26fec002019-12-06 17:06:40 -05006604 data = response.text
Ravi Chamarty5b2d5c12018-10-22 23:59:10 +00006605 data = data.split('<Link rel="edit"')[0]
6606
sousaedu2ad85172021-02-17 15:05:18 +01006607 headers[
6608 "Content-Type"
6609 ] = "application/vnd.vmware.vcloud.networkConnectionSection+xml"
Ravi Chamarty5b2d5c12018-10-22 23:59:10 +00006610
6611 newdata = """<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
6612 <NetworkConnectionSection xmlns="http://www.vmware.com/vcloud/v1.5"
6613 xmlns:ovf="http://schemas.dmtf.org/ovf/envelope/1"
6614 xmlns:vssd="http://schemas.dmtf.org/wbem/wscim/1/cim-schema/2/CIM_VirtualSystemSettingData"
6615 xmlns:common="http://schemas.dmtf.org/wbem/wscim/1/common"
6616 xmlns:rasd="http://schemas.dmtf.org/wbem/wscim/1/cim-schema/2/CIM_ResourceAllocationSettingData"
6617 xmlns:vmw="http://www.vmware.com/schema/ovf"
6618 xmlns:ovfenv="http://schemas.dmtf.org/ovf/environment/1"
6619 xmlns:vmext="http://www.vmware.com/vcloud/extension/v1.5"
6620 xmlns:ns9="http://www.vmware.com/vcloud/versions"
beierlb22ce2d2019-12-12 12:09:51 -05006621 href="{url}" type="application/vnd.vmware.vcloud.networkConnectionSection+xml"
6622 ovf:required="false">
Ravi Chamarty5b2d5c12018-10-22 23:59:10 +00006623 <ovf:Info>Specifies the available VM network connections</ovf:Info>
6624 <PrimaryNetworkConnectionIndex>0</PrimaryNetworkConnectionIndex>
beierlb22ce2d2019-12-12 12:09:51 -05006625 <Link rel="edit" href="{url}"
6626 type="application/vnd.vmware.vcloud.networkConnectionSection+xml"/>
sousaedu2ad85172021-02-17 15:05:18 +01006627 </NetworkConnectionSection>""".format(
6628 url=url_rest_call
6629 )
6630 response = self.perform_request(
6631 req_type="PUT", url=url_rest_call, headers=headers, data=newdata
6632 )
Ravi Chamarty5b2d5c12018-10-22 23:59:10 +00006633
6634 if response.status_code == 403:
sousaedu2ad85172021-02-17 15:05:18 +01006635 add_headers = {"Content-Type": headers["Content-Type"]}
6636 response = self.retry_rest("PUT", url_rest_call, add_headers, newdata)
Ravi Chamarty5b2d5c12018-10-22 23:59:10 +00006637
6638 if response.status_code != 202:
sousaedu2ad85172021-02-17 15:05:18 +01006639 self.logger.error(
6640 "REST call {} failed reason : {}"
6641 "status code : {} ".format(
6642 url_rest_call, response.text, response.status_code
6643 )
6644 )
6645 raise vimconn.VimConnException(
6646 "remove_primary_network_adapter : Failed to update "
6647 "network connection section"
6648 )
Ravi Chamarty5b2d5c12018-10-22 23:59:10 +00006649 else:
beierl26fec002019-12-06 17:06:40 -05006650 nic_task = self.get_task_from_response(response.text)
Ravi Chamarty5b2d5c12018-10-22 23:59:10 +00006651 result = self.client.get_task_monitor().wait_for_success(task=nic_task)
sousaedu2ad85172021-02-17 15:05:18 +01006652 if result.get("status") == "success":
6653 self.logger.info(
6654 "remove_primary_network_adapter(): VM {} conneced to "
6655 "default NIC type".format(vm_id)
6656 )
Ravi Chamarty5b2d5c12018-10-22 23:59:10 +00006657 else:
sousaedu2ad85172021-02-17 15:05:18 +01006658 self.logger.error(
6659 "remove_primary_network_adapter(): VM {} failed to "
6660 "connect NIC type".format(vm_id)
6661 )
Ravi Chamarty5b2d5c12018-10-22 23:59:10 +00006662
sousaedu2ad85172021-02-17 15:05:18 +01006663 def add_network_adapter_to_vms(
6664 self, vapp, network_name, primary_nic_index, nicIndex, net, nic_type=None
6665 ):
kasar3ac5dc42017-03-15 06:28:22 -07006666 """
sousaedu2ad85172021-02-17 15:05:18 +01006667 Method to add network adapter type to vm
6668 Args :
6669 network_name - name of network
6670 primary_nic_index - int value for primary nic index
6671 nicIndex - int value for nic index
6672 nic_type - specify model name to which add to vm
6673 Returns:
6674 None
kasar3ac5dc42017-03-15 06:28:22 -07006675 """
kasar3ac5dc42017-03-15 06:28:22 -07006676
sousaedu2ad85172021-02-17 15:05:18 +01006677 self.logger.info(
6678 "Add network adapter to VM: network_name {} nicIndex {} nic_type {}".format(
6679 network_name, nicIndex, nic_type
6680 )
6681 )
kasar4cb6e902017-03-18 00:17:27 -07006682 try:
kasard2963622017-03-31 05:53:17 -07006683 ip_address = None
kasardc1f02e2017-03-25 07:20:30 -07006684 floating_ip = False
kasarc5bf2932018-03-09 04:15:22 -08006685 mac_address = None
sousaedu2ad85172021-02-17 15:05:18 +01006686 if "floating_ip" in net:
6687 floating_ip = net["floating_ip"]
kasard2963622017-03-31 05:53:17 -07006688
6689 # Stub for ip_address feature
sousaedu2ad85172021-02-17 15:05:18 +01006690 if "ip_address" in net:
6691 ip_address = net["ip_address"]
kasard2963622017-03-31 05:53:17 -07006692
sousaedu2ad85172021-02-17 15:05:18 +01006693 if "mac_address" in net:
6694 mac_address = net["mac_address"]
kasarc5bf2932018-03-09 04:15:22 -08006695
kasard2963622017-03-31 05:53:17 -07006696 if floating_ip:
6697 allocation_mode = "POOL"
6698 elif ip_address:
6699 allocation_mode = "MANUAL"
6700 else:
6701 allocation_mode = "DHCP"
kasardc1f02e2017-03-25 07:20:30 -07006702
kasar3ac5dc42017-03-15 06:28:22 -07006703 if not nic_type:
kasarc5bf2932018-03-09 04:15:22 -08006704 for vms in vapp.get_all_vms():
sousaedu2ad85172021-02-17 15:05:18 +01006705 vm_id = vms.get("id").split(":")[-1]
kasar3ac5dc42017-03-15 06:28:22 -07006706
sousaedu2ad85172021-02-17 15:05:18 +01006707 url_rest_call = (
6708 "{}/api/vApp/vm-{}/networkConnectionSection/".format(
6709 self.url, vm_id
6710 )
6711 )
kasar3ac5dc42017-03-15 06:28:22 -07006712
sousaedu2ad85172021-02-17 15:05:18 +01006713 headers = {
6714 "Accept": "application/*+xml;version=" + API_VERSION,
6715 "x-vcloud-authorization": self.client._session.headers[
6716 "x-vcloud-authorization"
6717 ],
6718 }
6719 response = self.perform_request(
6720 req_type="GET", url=url_rest_call, headers=headers
6721 )
bhangare1a0b97c2017-06-21 02:20:15 -07006722
6723 if response.status_code == 403:
sousaedu2ad85172021-02-17 15:05:18 +01006724 response = self.retry_rest("GET", url_rest_call)
bhangare1a0b97c2017-06-21 02:20:15 -07006725
kasar3ac5dc42017-03-15 06:28:22 -07006726 if response.status_code != 200:
sousaedu2ad85172021-02-17 15:05:18 +01006727 self.logger.error(
6728 "REST call {} failed reason : {}"
6729 "status code : {}".format(
6730 url_rest_call, response.text, response.status_code
6731 )
6732 )
6733 raise vimconn.VimConnException(
6734 "add_network_adapter_to_vms : Failed to get "
6735 "network connection section"
6736 )
kasar3ac5dc42017-03-15 06:28:22 -07006737
beierl26fec002019-12-06 17:06:40 -05006738 data = response.text
kasarc5bf2932018-03-09 04:15:22 -08006739 data = data.split('<Link rel="edit"')[0]
sousaedu2ad85172021-02-17 15:05:18 +01006740 if "<PrimaryNetworkConnectionIndex>" not in data:
Ravi Chamarty5b2d5c12018-10-22 23:59:10 +00006741 self.logger.debug("add_network_adapter PrimaryNIC not in data")
kasar3ac5dc42017-03-15 06:28:22 -07006742 item = """<PrimaryNetworkConnectionIndex>{}</PrimaryNetworkConnectionIndex>
6743 <NetworkConnection network="{}">
6744 <NetworkConnectionIndex>{}</NetworkConnectionIndex>
6745 <IsConnected>true</IsConnected>
kasardc1f02e2017-03-25 07:20:30 -07006746 <IpAddressAllocationMode>{}</IpAddressAllocationMode>
sousaedu2ad85172021-02-17 15:05:18 +01006747 </NetworkConnection>""".format(
6748 primary_nic_index, network_name, nicIndex, allocation_mode
6749 )
6750
kasard2963622017-03-31 05:53:17 -07006751 # Stub for ip_address feature
6752 if ip_address:
sousaedu2ad85172021-02-17 15:05:18 +01006753 ip_tag = "<IpAddress>{}</IpAddress>".format(ip_address)
6754 item = item.replace(
6755 "</NetworkConnectionIndex>\n",
6756 "</NetworkConnectionIndex>\n{}\n".format(ip_tag),
6757 )
kasardc1f02e2017-03-25 07:20:30 -07006758
kasarc5bf2932018-03-09 04:15:22 -08006759 if mac_address:
sousaedu2ad85172021-02-17 15:05:18 +01006760 mac_tag = "<MACAddress>{}</MACAddress>".format(mac_address)
6761 item = item.replace(
6762 "</IsConnected>\n",
6763 "</IsConnected>\n{}\n".format(mac_tag),
6764 )
kasarc5bf2932018-03-09 04:15:22 -08006765
sousaedu2ad85172021-02-17 15:05:18 +01006766 data = data.replace(
6767 "</ovf:Info>\n",
6768 "</ovf:Info>\n{}\n</NetworkConnectionSection>".format(item),
6769 )
kasar3ac5dc42017-03-15 06:28:22 -07006770 else:
Ravi Chamarty5b2d5c12018-10-22 23:59:10 +00006771 self.logger.debug("add_network_adapter PrimaryNIC in data")
kasar3ac5dc42017-03-15 06:28:22 -07006772 new_item = """<NetworkConnection network="{}">
6773 <NetworkConnectionIndex>{}</NetworkConnectionIndex>
6774 <IsConnected>true</IsConnected>
kasardc1f02e2017-03-25 07:20:30 -07006775 <IpAddressAllocationMode>{}</IpAddressAllocationMode>
sousaedu2ad85172021-02-17 15:05:18 +01006776 </NetworkConnection>""".format(
6777 network_name, nicIndex, allocation_mode
6778 )
6779
kasard2963622017-03-31 05:53:17 -07006780 # Stub for ip_address feature
6781 if ip_address:
sousaedu2ad85172021-02-17 15:05:18 +01006782 ip_tag = "<IpAddress>{}</IpAddress>".format(ip_address)
6783 new_item = new_item.replace(
6784 "</NetworkConnectionIndex>\n",
6785 "</NetworkConnectionIndex>\n{}\n".format(ip_tag),
6786 )
kasardc1f02e2017-03-25 07:20:30 -07006787
kasarc5bf2932018-03-09 04:15:22 -08006788 if mac_address:
sousaedu2ad85172021-02-17 15:05:18 +01006789 mac_tag = "<MACAddress>{}</MACAddress>".format(mac_address)
6790 new_item = new_item.replace(
6791 "</IsConnected>\n",
6792 "</IsConnected>\n{}\n".format(mac_tag),
6793 )
kasar3ac5dc42017-03-15 06:28:22 -07006794
sousaedu2ad85172021-02-17 15:05:18 +01006795 data = data + new_item + "</NetworkConnectionSection>"
kasarc5bf2932018-03-09 04:15:22 -08006796
sousaedu2ad85172021-02-17 15:05:18 +01006797 headers[
6798 "Content-Type"
6799 ] = "application/vnd.vmware.vcloud.networkConnectionSection+xml"
kasarc5bf2932018-03-09 04:15:22 -08006800
sousaedu2ad85172021-02-17 15:05:18 +01006801 response = self.perform_request(
6802 req_type="PUT", url=url_rest_call, headers=headers, data=data
6803 )
bhangare1a0b97c2017-06-21 02:20:15 -07006804
6805 if response.status_code == 403:
sousaedu2ad85172021-02-17 15:05:18 +01006806 add_headers = {"Content-Type": headers["Content-Type"]}
6807 response = self.retry_rest(
6808 "PUT", url_rest_call, add_headers, data
6809 )
bhangare1a0b97c2017-06-21 02:20:15 -07006810
kasar3ac5dc42017-03-15 06:28:22 -07006811 if response.status_code != 202:
sousaedu2ad85172021-02-17 15:05:18 +01006812 self.logger.error(
6813 "REST call {} failed reason : {}"
6814 "status code : {} ".format(
6815 url_rest_call, response.text, response.status_code
6816 )
6817 )
6818 raise vimconn.VimConnException(
6819 "add_network_adapter_to_vms : Failed to update "
6820 "network connection section"
6821 )
kasar3ac5dc42017-03-15 06:28:22 -07006822 else:
beierl26fec002019-12-06 17:06:40 -05006823 nic_task = self.get_task_from_response(response.text)
sousaedu2ad85172021-02-17 15:05:18 +01006824 result = self.client.get_task_monitor().wait_for_success(
6825 task=nic_task
6826 )
6827
6828 if result.get("status") == "success":
6829 self.logger.info(
6830 "add_network_adapter_to_vms(): VM {} conneced to "
6831 "default NIC type".format(vm_id)
6832 )
kasar3ac5dc42017-03-15 06:28:22 -07006833 else:
sousaedu2ad85172021-02-17 15:05:18 +01006834 self.logger.error(
6835 "add_network_adapter_to_vms(): VM {} failed to "
6836 "connect NIC type".format(vm_id)
6837 )
kasar3ac5dc42017-03-15 06:28:22 -07006838 else:
kasarc5bf2932018-03-09 04:15:22 -08006839 for vms in vapp.get_all_vms():
sousaedu2ad85172021-02-17 15:05:18 +01006840 vm_id = vms.get("id").split(":")[-1]
kasar3ac5dc42017-03-15 06:28:22 -07006841
sousaedu2ad85172021-02-17 15:05:18 +01006842 url_rest_call = (
6843 "{}/api/vApp/vm-{}/networkConnectionSection/".format(
6844 self.url, vm_id
6845 )
6846 )
kasarc5bf2932018-03-09 04:15:22 -08006847
sousaedu2ad85172021-02-17 15:05:18 +01006848 headers = {
6849 "Accept": "application/*+xml;version=" + API_VERSION,
6850 "x-vcloud-authorization": self.client._session.headers[
6851 "x-vcloud-authorization"
6852 ],
6853 }
6854 response = self.perform_request(
6855 req_type="GET", url=url_rest_call, headers=headers
6856 )
bhangare1a0b97c2017-06-21 02:20:15 -07006857
6858 if response.status_code == 403:
sousaedu2ad85172021-02-17 15:05:18 +01006859 response = self.retry_rest("GET", url_rest_call)
bhangare1a0b97c2017-06-21 02:20:15 -07006860
kasar3ac5dc42017-03-15 06:28:22 -07006861 if response.status_code != 200:
sousaedu2ad85172021-02-17 15:05:18 +01006862 self.logger.error(
6863 "REST call {} failed reason : {}"
6864 "status code : {}".format(
6865 url_rest_call, response.text, response.status_code
6866 )
6867 )
6868 raise vimconn.VimConnException(
6869 "add_network_adapter_to_vms : Failed to get "
6870 "network connection section"
6871 )
beierl26fec002019-12-06 17:06:40 -05006872 data = response.text
kasarc5bf2932018-03-09 04:15:22 -08006873 data = data.split('<Link rel="edit"')[0]
Ravi Chamartye21c9cc2018-10-24 02:14:53 +00006874 vcd_netadapter_type = nic_type
sousaedu2ad85172021-02-17 15:05:18 +01006875
6876 if nic_type in ["SR-IOV", "VF"]:
Ravi Chamartye21c9cc2018-10-24 02:14:53 +00006877 vcd_netadapter_type = "SRIOVETHERNETCARD"
6878
sousaedu2ad85172021-02-17 15:05:18 +01006879 if "<PrimaryNetworkConnectionIndex>" not in data:
6880 self.logger.debug(
6881 "add_network_adapter PrimaryNIC not in data nic_type {}".format(
6882 nic_type
6883 )
6884 )
kasar3ac5dc42017-03-15 06:28:22 -07006885 item = """<PrimaryNetworkConnectionIndex>{}</PrimaryNetworkConnectionIndex>
6886 <NetworkConnection network="{}">
6887 <NetworkConnectionIndex>{}</NetworkConnectionIndex>
6888 <IsConnected>true</IsConnected>
kasardc1f02e2017-03-25 07:20:30 -07006889 <IpAddressAllocationMode>{}</IpAddressAllocationMode>
kasar3ac5dc42017-03-15 06:28:22 -07006890 <NetworkAdapterType>{}</NetworkAdapterType>
sousaedu2ad85172021-02-17 15:05:18 +01006891 </NetworkConnection>""".format(
6892 primary_nic_index,
6893 network_name,
6894 nicIndex,
6895 allocation_mode,
6896 vcd_netadapter_type,
6897 )
6898
kasard2963622017-03-31 05:53:17 -07006899 # Stub for ip_address feature
6900 if ip_address:
sousaedu2ad85172021-02-17 15:05:18 +01006901 ip_tag = "<IpAddress>{}</IpAddress>".format(ip_address)
6902 item = item.replace(
6903 "</NetworkConnectionIndex>\n",
6904 "</NetworkConnectionIndex>\n{}\n".format(ip_tag),
6905 )
kasardc1f02e2017-03-25 07:20:30 -07006906
kasarc5bf2932018-03-09 04:15:22 -08006907 if mac_address:
sousaedu2ad85172021-02-17 15:05:18 +01006908 mac_tag = "<MACAddress>{}</MACAddress>".format(mac_address)
6909 item = item.replace(
6910 "</IsConnected>\n",
6911 "</IsConnected>\n{}\n".format(mac_tag),
6912 )
kasarc5bf2932018-03-09 04:15:22 -08006913
sousaedu2ad85172021-02-17 15:05:18 +01006914 data = data.replace(
6915 "</ovf:Info>\n",
6916 "</ovf:Info>\n{}\n</NetworkConnectionSection>".format(item),
6917 )
kasar3ac5dc42017-03-15 06:28:22 -07006918 else:
sousaedu2ad85172021-02-17 15:05:18 +01006919 self.logger.debug(
6920 "add_network_adapter PrimaryNIC in data nic_type {}".format(
6921 nic_type
6922 )
6923 )
kasar3ac5dc42017-03-15 06:28:22 -07006924 new_item = """<NetworkConnection network="{}">
6925 <NetworkConnectionIndex>{}</NetworkConnectionIndex>
6926 <IsConnected>true</IsConnected>
kasardc1f02e2017-03-25 07:20:30 -07006927 <IpAddressAllocationMode>{}</IpAddressAllocationMode>
kasar3ac5dc42017-03-15 06:28:22 -07006928 <NetworkAdapterType>{}</NetworkAdapterType>
sousaedu2ad85172021-02-17 15:05:18 +01006929 </NetworkConnection>""".format(
6930 network_name, nicIndex, allocation_mode, vcd_netadapter_type
6931 )
6932
kasard2963622017-03-31 05:53:17 -07006933 # Stub for ip_address feature
6934 if ip_address:
sousaedu2ad85172021-02-17 15:05:18 +01006935 ip_tag = "<IpAddress>{}</IpAddress>".format(ip_address)
6936 new_item = new_item.replace(
6937 "</NetworkConnectionIndex>\n",
6938 "</NetworkConnectionIndex>\n{}\n".format(ip_tag),
6939 )
kasardc1f02e2017-03-25 07:20:30 -07006940
kasarc5bf2932018-03-09 04:15:22 -08006941 if mac_address:
sousaedu2ad85172021-02-17 15:05:18 +01006942 mac_tag = "<MACAddress>{}</MACAddress>".format(mac_address)
6943 new_item = new_item.replace(
6944 "</IsConnected>\n",
6945 "</IsConnected>\n{}\n".format(mac_tag),
6946 )
kasar3ac5dc42017-03-15 06:28:22 -07006947
sousaedu2ad85172021-02-17 15:05:18 +01006948 data = data + new_item + "</NetworkConnectionSection>"
kasarc5bf2932018-03-09 04:15:22 -08006949
sousaedu2ad85172021-02-17 15:05:18 +01006950 headers[
6951 "Content-Type"
6952 ] = "application/vnd.vmware.vcloud.networkConnectionSection+xml"
kasarc5bf2932018-03-09 04:15:22 -08006953
sousaedu2ad85172021-02-17 15:05:18 +01006954 response = self.perform_request(
6955 req_type="PUT", url=url_rest_call, headers=headers, data=data
6956 )
bhangare1a0b97c2017-06-21 02:20:15 -07006957
6958 if response.status_code == 403:
sousaedu2ad85172021-02-17 15:05:18 +01006959 add_headers = {"Content-Type": headers["Content-Type"]}
6960 response = self.retry_rest(
6961 "PUT", url_rest_call, add_headers, data
6962 )
kasar3ac5dc42017-03-15 06:28:22 -07006963
6964 if response.status_code != 202:
sousaedu2ad85172021-02-17 15:05:18 +01006965 self.logger.error(
6966 "REST call {} failed reason : {}"
6967 "status code : {}".format(
6968 url_rest_call, response.text, response.status_code
6969 )
6970 )
6971 raise vimconn.VimConnException(
6972 "add_network_adapter_to_vms : Failed to update "
6973 "network connection section"
6974 )
kasar3ac5dc42017-03-15 06:28:22 -07006975 else:
beierl26fec002019-12-06 17:06:40 -05006976 nic_task = self.get_task_from_response(response.text)
sousaedu2ad85172021-02-17 15:05:18 +01006977 result = self.client.get_task_monitor().wait_for_success(
6978 task=nic_task
6979 )
6980
6981 if result.get("status") == "success":
6982 self.logger.info(
6983 "add_network_adapter_to_vms(): VM {} "
6984 "conneced to NIC type {}".format(vm_id, nic_type)
6985 )
kasar3ac5dc42017-03-15 06:28:22 -07006986 else:
sousaedu2ad85172021-02-17 15:05:18 +01006987 self.logger.error(
6988 "add_network_adapter_to_vms(): VM {} "
6989 "failed to connect NIC type {}".format(vm_id, nic_type)
6990 )
kasar3ac5dc42017-03-15 06:28:22 -07006991 except Exception as exp:
sousaedu2ad85172021-02-17 15:05:18 +01006992 self.logger.error(
6993 "add_network_adapter_to_vms() : exception occurred "
6994 "while adding Network adapter"
6995 )
6996
tierno72774862020-05-04 11:44:15 +00006997 raise vimconn.VimConnException(message=exp)
kasarde691232017-03-25 03:37:31 -07006998
kasarde691232017-03-25 03:37:31 -07006999 def set_numa_affinity(self, vmuuid, paired_threads_id):
7000 """
sousaedu2ad85172021-02-17 15:05:18 +01007001 Method to assign numa affinity in vm configuration parammeters
7002 Args :
7003 vmuuid - vm uuid
7004 paired_threads_id - one or more virtual processor
7005 numbers
7006 Returns:
7007 return if True
kasarde691232017-03-25 03:37:31 -07007008 """
7009 try:
kasar204e39e2018-01-25 00:57:02 -08007010 vcenter_conect, content = self.get_vcenter_content()
7011 vm_moref_id = self.get_vm_moref_id(vmuuid)
beierlb22ce2d2019-12-12 12:09:51 -05007012 _, vm_obj = self.get_vm_obj(content, vm_moref_id)
sousaedu2ad85172021-02-17 15:05:18 +01007013
kasar204e39e2018-01-25 00:57:02 -08007014 if vm_obj:
7015 config_spec = vim.vm.ConfigSpec()
7016 config_spec.extraConfig = []
7017 opt = vim.option.OptionValue()
sousaedu2ad85172021-02-17 15:05:18 +01007018 opt.key = "numa.nodeAffinity"
kasar204e39e2018-01-25 00:57:02 -08007019 opt.value = str(paired_threads_id)
7020 config_spec.extraConfig.append(opt)
7021 task = vm_obj.ReconfigVM_Task(config_spec)
sousaedu2ad85172021-02-17 15:05:18 +01007022
kasar204e39e2018-01-25 00:57:02 -08007023 if task:
beierlb22ce2d2019-12-12 12:09:51 -05007024 self.wait_for_vcenter_task(task, vcenter_conect)
kasar204e39e2018-01-25 00:57:02 -08007025 extra_config = vm_obj.config.extraConfig
7026 flag = False
sousaedu2ad85172021-02-17 15:05:18 +01007027
kasar204e39e2018-01-25 00:57:02 -08007028 for opts in extra_config:
sousaedu2ad85172021-02-17 15:05:18 +01007029 if "numa.nodeAffinity" in opts.key:
kasar204e39e2018-01-25 00:57:02 -08007030 flag = True
sousaedu2ad85172021-02-17 15:05:18 +01007031 self.logger.info(
7032 "set_numa_affinity: Sucessfully assign numa affinity "
7033 "value {} for vm {}".format(opt.value, vm_obj)
7034 )
7035
kasar204e39e2018-01-25 00:57:02 -08007036 if flag:
7037 return
7038 else:
7039 self.logger.error("set_numa_affinity: Failed to assign numa affinity")
kasarde691232017-03-25 03:37:31 -07007040 except Exception as exp:
sousaedu2ad85172021-02-17 15:05:18 +01007041 self.logger.error(
7042 "set_numa_affinity : exception occurred while setting numa affinity "
7043 "for VM {} : {}".format(vm_obj, vm_moref_id)
7044 )
7045
7046 raise vimconn.VimConnException(
7047 "set_numa_affinity : Error {} failed to assign numa "
7048 "affinity".format(exp)
7049 )
kasardc1f02e2017-03-25 07:20:30 -07007050
7051 def cloud_init(self, vapp, cloud_config):
7052 """
7053 Method to inject ssh-key
7054 vapp - vapp object
7055 cloud_config a dictionary with:
7056 'key-pairs': (optional) list of strings with the public key to be inserted to the default user
7057 'users': (optional) list of users to be inserted, each item is a dict with:
7058 'name': (mandatory) user name,
7059 'key-pairs': (optional) list of strings with the public key to be inserted to the user
tierno40e1bce2017-08-09 09:12:04 +02007060 'user-data': (optional) can be a string with the text script to be passed directly to cloud-init,
7061 or a list of strings, each one contains a script to be passed, usually with a MIMEmultipart file
kasardc1f02e2017-03-25 07:20:30 -07007062 'config-files': (optional). List of files to be transferred. Each item is a dict with:
7063 'dest': (mandatory) string with the destination absolute path
7064 'encoding': (optional, by default text). Can be one of:
7065 'b64', 'base64', 'gz', 'gz+b64', 'gz+base64', 'gzip+b64', 'gzip+base64'
7066 'content' (mandatory): string with the content of the file
7067 'permissions': (optional) string with file permissions, typically octal notation '0644'
7068 'owner': (optional) file owner, string with the format 'owner:group'
7069 'boot-data-drive': boolean to indicate if user-data must be passed using a boot drive (hard disk
7070 """
kasardc1f02e2017-03-25 07:20:30 -07007071 try:
kasar2aa50742017-08-08 02:11:22 -07007072 if not isinstance(cloud_config, dict):
sousaedu2ad85172021-02-17 15:05:18 +01007073 raise Exception(
7074 "cloud_init : parameter cloud_config is not a dictionary"
7075 )
kasar2aa50742017-08-08 02:11:22 -07007076 else:
kasardc1f02e2017-03-25 07:20:30 -07007077 key_pairs = []
7078 userdata = []
sousaedu2ad85172021-02-17 15:05:18 +01007079
kasardc1f02e2017-03-25 07:20:30 -07007080 if "key-pairs" in cloud_config:
7081 key_pairs = cloud_config["key-pairs"]
7082
7083 if "users" in cloud_config:
7084 userdata = cloud_config["users"]
7085
kasar2aa50742017-08-08 02:11:22 -07007086 self.logger.debug("cloud_init : Guest os customization started..")
sousaedu2ad85172021-02-17 15:05:18 +01007087 customize_script = self.format_script(
7088 key_pairs=key_pairs, users_list=userdata
7089 )
beierlb22ce2d2019-12-12 12:09:51 -05007090 customize_script = customize_script.replace("&", "&amp;")
kasar2aa50742017-08-08 02:11:22 -07007091 self.guest_customization(vapp, customize_script)
kasardc1f02e2017-03-25 07:20:30 -07007092 except Exception as exp:
sousaedu2ad85172021-02-17 15:05:18 +01007093 self.logger.error(
7094 "cloud_init : exception occurred while injecting " "ssh-key"
7095 )
7096
7097 raise vimconn.VimConnException(
7098 "cloud_init : Error {} failed to inject " "ssh-key".format(exp)
7099 )
bhangare06312472017-03-30 05:49:07 -07007100
kasar2aa50742017-08-08 02:11:22 -07007101 def format_script(self, key_pairs=[], users_list=[]):
kasarc5bf2932018-03-09 04:15:22 -08007102 bash_script = """#!/bin/sh
beierlb22ce2d2019-12-12 12:09:51 -05007103echo performing customization tasks with param $1 at `date "+DATE: %Y-%m-%d - TIME: %H:%M:%S"`>> /root/customization.log
7104if [ "$1" = "precustomization" ];then
7105 echo performing precustomization tasks on `date "+DATE: %Y-%m-%d - TIME: %H:%M:%S"` >> /root/customization.log
7106"""
kasar2aa50742017-08-08 02:11:22 -07007107
7108 keys = "\n".join(key_pairs)
7109 if keys:
7110 keys_data = """
7111 if [ ! -d /root/.ssh ];then
7112 mkdir /root/.ssh
7113 chown root:root /root/.ssh
7114 chmod 700 /root/.ssh
7115 touch /root/.ssh/authorized_keys
7116 chown root:root /root/.ssh/authorized_keys
7117 chmod 600 /root/.ssh/authorized_keys
7118 # make centos with selinux happy
7119 which restorecon && restorecon -Rv /root/.ssh
7120 else
7121 touch /root/.ssh/authorized_keys
7122 chown root:root /root/.ssh/authorized_keys
7123 chmod 600 /root/.ssh/authorized_keys
7124 fi
7125 echo '{key}' >> /root/.ssh/authorized_keys
sousaedu2ad85172021-02-17 15:05:18 +01007126 """.format(
7127 key=keys
7128 )
kasar2aa50742017-08-08 02:11:22 -07007129
beierlb22ce2d2019-12-12 12:09:51 -05007130 bash_script += keys_data
kasar2aa50742017-08-08 02:11:22 -07007131
7132 for user in users_list:
sousaedu2ad85172021-02-17 15:05:18 +01007133 if "name" in user:
7134 user_name = user["name"]
7135
7136 if "key-pairs" in user:
7137 user_keys = "\n".join(user["key-pairs"])
kasar2aa50742017-08-08 02:11:22 -07007138 else:
7139 user_keys = None
7140
7141 add_user_name = """
7142 useradd -d /home/{user_name} -m -g users -s /bin/bash {user_name}
sousaedu2ad85172021-02-17 15:05:18 +01007143 """.format(
7144 user_name=user_name
7145 )
kasar2aa50742017-08-08 02:11:22 -07007146
beierlb22ce2d2019-12-12 12:09:51 -05007147 bash_script += add_user_name
kasar2aa50742017-08-08 02:11:22 -07007148
7149 if user_keys:
7150 user_keys_data = """
7151 mkdir /home/{user_name}/.ssh
7152 chown {user_name}:{user_name} /home/{user_name}/.ssh
7153 chmod 700 /home/{user_name}/.ssh
7154 touch /home/{user_name}/.ssh/authorized_keys
7155 chown {user_name}:{user_name} /home/{user_name}/.ssh/authorized_keys
7156 chmod 600 /home/{user_name}/.ssh/authorized_keys
7157 # make centos with selinux happy
7158 which restorecon && restorecon -Rv /home/{user_name}/.ssh
7159 echo '{user_key}' >> /home/{user_name}/.ssh/authorized_keys
sousaedu2ad85172021-02-17 15:05:18 +01007160 """.format(
7161 user_name=user_name, user_key=user_keys
7162 )
beierlb22ce2d2019-12-12 12:09:51 -05007163 bash_script += user_keys_data
kasar2aa50742017-08-08 02:11:22 -07007164
beierlb22ce2d2019-12-12 12:09:51 -05007165 return bash_script + "\n\tfi"
kasar2aa50742017-08-08 02:11:22 -07007166
7167 def guest_customization(self, vapp, customize_script):
7168 """
7169 Method to customize guest os
7170 vapp - Vapp object
7171 customize_script - Customize script to be run at first boot of VM.
7172 """
kasarc5bf2932018-03-09 04:15:22 -08007173 for vm in vapp.get_all_vms():
sousaedu2ad85172021-02-17 15:05:18 +01007174 vm_id = vm.get("id").split(":")[-1]
7175 vm_name = vm.get("name")
7176 vm_name = vm_name.replace("_", "-")
sbhangarea8e5b782018-06-21 02:10:03 -07007177
sousaedu2ad85172021-02-17 15:05:18 +01007178 vm_customization_url = (
7179 "{}/api/vApp/vm-{}/guestCustomizationSection/".format(self.url, vm_id)
7180 )
7181 headers = {
7182 "Accept": "application/*+xml;version=" + API_VERSION,
7183 "x-vcloud-authorization": self.client._session.headers[
7184 "x-vcloud-authorization"
7185 ],
7186 }
kasarc5bf2932018-03-09 04:15:22 -08007187
sousaedu2ad85172021-02-17 15:05:18 +01007188 headers[
7189 "Content-Type"
7190 ] = "application/vnd.vmware.vcloud.guestCustomizationSection+xml"
kasarc5bf2932018-03-09 04:15:22 -08007191
7192 data = """<GuestCustomizationSection
7193 xmlns="http://www.vmware.com/vcloud/v1.5"
7194 xmlns:ovf="http://schemas.dmtf.org/ovf/envelope/1"
beierlb22ce2d2019-12-12 12:09:51 -05007195 ovf:required="false" href="{}"
7196 type="application/vnd.vmware.vcloud.guestCustomizationSection+xml">
kasarc5bf2932018-03-09 04:15:22 -08007197 <ovf:Info>Specifies Guest OS Customization Settings</ovf:Info>
7198 <Enabled>true</Enabled>
7199 <ChangeSid>false</ChangeSid>
7200 <VirtualMachineId>{}</VirtualMachineId>
7201 <JoinDomainEnabled>false</JoinDomainEnabled>
7202 <UseOrgSettings>false</UseOrgSettings>
7203 <AdminPasswordEnabled>false</AdminPasswordEnabled>
7204 <AdminPasswordAuto>true</AdminPasswordAuto>
7205 <AdminAutoLogonEnabled>false</AdminAutoLogonEnabled>
7206 <AdminAutoLogonCount>0</AdminAutoLogonCount>
7207 <ResetPasswordRequired>false</ResetPasswordRequired>
7208 <CustomizationScript>{}</CustomizationScript>
7209 <ComputerName>{}</ComputerName>
beierlb22ce2d2019-12-12 12:09:51 -05007210 <Link href="{}"
7211 type="application/vnd.vmware.vcloud.guestCustomizationSection+xml" rel="edit"/>
sbhangarea8e5b782018-06-21 02:10:03 -07007212 </GuestCustomizationSection>
sousaedu2ad85172021-02-17 15:05:18 +01007213 """.format(
7214 vm_customization_url,
7215 vm_id,
7216 customize_script,
7217 vm_name,
7218 vm_customization_url,
7219 )
kasarc5bf2932018-03-09 04:15:22 -08007220
sousaedu2ad85172021-02-17 15:05:18 +01007221 response = self.perform_request(
7222 req_type="PUT", url=vm_customization_url, headers=headers, data=data
7223 )
kasarc5bf2932018-03-09 04:15:22 -08007224 if response.status_code == 202:
beierl26fec002019-12-06 17:06:40 -05007225 guest_task = self.get_task_from_response(response.text)
kasarc5bf2932018-03-09 04:15:22 -08007226 self.client.get_task_monitor().wait_for_success(task=guest_task)
sousaedu2ad85172021-02-17 15:05:18 +01007227 self.logger.info(
7228 "guest_customization : customized guest os task "
7229 "completed for VM {}".format(vm_name)
7230 )
kasar2aa50742017-08-08 02:11:22 -07007231 else:
sousaedu2ad85172021-02-17 15:05:18 +01007232 self.logger.error(
7233 "guest_customization : task for customized guest os"
7234 "failed for VM {}".format(vm_name)
7235 )
7236
7237 raise vimconn.VimConnException(
7238 "guest_customization : failed to perform"
7239 "guest os customization on VM {}".format(vm_name)
7240 )
bhangare06312472017-03-30 05:49:07 -07007241
bhangare1a0b97c2017-06-21 02:20:15 -07007242 def add_new_disk(self, vapp_uuid, disk_size):
bhangare06312472017-03-30 05:49:07 -07007243 """
sousaedu2ad85172021-02-17 15:05:18 +01007244 Method to create an empty vm disk
bhangare06312472017-03-30 05:49:07 -07007245
sousaedu2ad85172021-02-17 15:05:18 +01007246 Args:
7247 vapp_uuid - is vapp identifier.
7248 disk_size - size of disk to be created in GB
bhangare06312472017-03-30 05:49:07 -07007249
sousaedu2ad85172021-02-17 15:05:18 +01007250 Returns:
7251 None
bhangare06312472017-03-30 05:49:07 -07007252 """
7253 status = False
7254 vm_details = None
7255 try:
beierlb22ce2d2019-12-12 12:09:51 -05007256 # Disk size in GB, convert it into MB
bhangare06312472017-03-30 05:49:07 -07007257 if disk_size is not None:
7258 disk_size_mb = int(disk_size) * 1024
7259 vm_details = self.get_vapp_details_rest(vapp_uuid)
7260
7261 if vm_details and "vm_virtual_hardware" in vm_details:
sousaedu2ad85172021-02-17 15:05:18 +01007262 self.logger.info(
7263 "Adding disk to VM: {} disk size:{}GB".format(
7264 vm_details["name"], disk_size
7265 )
7266 )
bhangare06312472017-03-30 05:49:07 -07007267 disk_href = vm_details["vm_virtual_hardware"]["disk_edit_href"]
bhangare1a0b97c2017-06-21 02:20:15 -07007268 status = self.add_new_disk_rest(disk_href, disk_size_mb)
bhangare06312472017-03-30 05:49:07 -07007269 except Exception as exp:
7270 msg = "Error occurred while creating new disk {}.".format(exp)
7271 self.rollback_newvm(vapp_uuid, msg)
7272
7273 if status:
sousaedu2ad85172021-02-17 15:05:18 +01007274 self.logger.info(
7275 "Added new disk to VM: {} disk size:{}GB".format(
7276 vm_details["name"], disk_size
7277 )
7278 )
bhangare06312472017-03-30 05:49:07 -07007279 else:
beierlb22ce2d2019-12-12 12:09:51 -05007280 # If failed to add disk, delete VM
sousaedu2ad85172021-02-17 15:05:18 +01007281 msg = "add_new_disk: Failed to add new disk to {}".format(
7282 vm_details["name"]
7283 )
bhangare06312472017-03-30 05:49:07 -07007284 self.rollback_newvm(vapp_uuid, msg)
7285
bhangare1a0b97c2017-06-21 02:20:15 -07007286 def add_new_disk_rest(self, disk_href, disk_size_mb):
bhangare06312472017-03-30 05:49:07 -07007287 """
7288 Retrives vApp Disks section & add new empty disk
7289
7290 Args:
7291 disk_href: Disk section href to addd disk
7292 disk_size_mb: Disk size in MB
7293
7294 Returns: Status of add new disk task
7295 """
7296 status = False
kasarc5bf2932018-03-09 04:15:22 -08007297 if self.client._session:
sousaedu2ad85172021-02-17 15:05:18 +01007298 headers = {
7299 "Accept": "application/*+xml;version=" + API_VERSION,
7300 "x-vcloud-authorization": self.client._session.headers[
7301 "x-vcloud-authorization"
7302 ],
7303 }
7304 response = self.perform_request(
7305 req_type="GET", url=disk_href, headers=headers
7306 )
bhangare1a0b97c2017-06-21 02:20:15 -07007307
7308 if response.status_code == 403:
sousaedu2ad85172021-02-17 15:05:18 +01007309 response = self.retry_rest("GET", disk_href)
bhangare06312472017-03-30 05:49:07 -07007310
7311 if response.status_code != requests.codes.ok:
sousaedu2ad85172021-02-17 15:05:18 +01007312 self.logger.error(
7313 "add_new_disk_rest: GET REST API call {} failed. Return status code {}".format(
7314 disk_href, response.status_code
7315 )
7316 )
7317
bhangare06312472017-03-30 05:49:07 -07007318 return status
sousaedu2ad85172021-02-17 15:05:18 +01007319
bhangare06312472017-03-30 05:49:07 -07007320 try:
beierlb22ce2d2019-12-12 12:09:51 -05007321 # Find but type & max of instance IDs assigned to disks
beierl01bd6692019-12-09 17:06:20 -05007322 lxmlroot_respond = lxmlElementTree.fromstring(response.content)
sousaedu2ad85172021-02-17 15:05:18 +01007323 namespaces = {
7324 prefix: uri for prefix, uri in lxmlroot_respond.nsmap.items() if prefix
7325 }
beierlb22ce2d2019-12-12 12:09:51 -05007326 namespaces["xmlns"] = "http://www.vmware.com/vcloud/v1.5"
bhangare06312472017-03-30 05:49:07 -07007327 instance_id = 0
sousaedu2ad85172021-02-17 15:05:18 +01007328
7329 for item in lxmlroot_respond.iterfind("xmlns:Item", namespaces):
beierlb22ce2d2019-12-12 12:09:51 -05007330 if item.find("rasd:Description", namespaces).text == "Hard disk":
7331 inst_id = int(item.find("rasd:InstanceID", namespaces).text)
sousaedu2ad85172021-02-17 15:05:18 +01007332
bhangare06312472017-03-30 05:49:07 -07007333 if inst_id > instance_id:
7334 instance_id = inst_id
beierlb22ce2d2019-12-12 12:09:51 -05007335 disk_item = item.find("rasd:HostResource", namespaces)
sousaedu2ad85172021-02-17 15:05:18 +01007336 bus_subtype = disk_item.attrib[
7337 "{" + namespaces["xmlns"] + "}busSubType"
7338 ]
7339 bus_type = disk_item.attrib[
7340 "{" + namespaces["xmlns"] + "}busType"
7341 ]
bhangare06312472017-03-30 05:49:07 -07007342
7343 instance_id = instance_id + 1
beierlb22ce2d2019-12-12 12:09:51 -05007344 new_item = """<Item>
bhangare06312472017-03-30 05:49:07 -07007345 <rasd:Description>Hard disk</rasd:Description>
7346 <rasd:ElementName>New disk</rasd:ElementName>
7347 <rasd:HostResource
7348 xmlns:vcloud="http://www.vmware.com/vcloud/v1.5"
7349 vcloud:capacity="{}"
7350 vcloud:busSubType="{}"
7351 vcloud:busType="{}"></rasd:HostResource>
7352 <rasd:InstanceID>{}</rasd:InstanceID>
7353 <rasd:ResourceType>17</rasd:ResourceType>
sousaedu2ad85172021-02-17 15:05:18 +01007354 </Item>""".format(
7355 disk_size_mb, bus_subtype, bus_type, instance_id
7356 )
bhangare06312472017-03-30 05:49:07 -07007357
beierl26fec002019-12-06 17:06:40 -05007358 new_data = response.text
beierlb22ce2d2019-12-12 12:09:51 -05007359 # Add new item at the bottom
sousaedu2ad85172021-02-17 15:05:18 +01007360 new_data = new_data.replace(
7361 "</Item>\n</RasdItemsList>",
7362 "</Item>\n{}\n</RasdItemsList>".format(new_item),
7363 )
bhangare06312472017-03-30 05:49:07 -07007364
7365 # Send PUT request to modify virtual hardware section with new disk
sousaedu2ad85172021-02-17 15:05:18 +01007366 headers[
7367 "Content-Type"
7368 ] = "application/vnd.vmware.vcloud.rasdItemsList+xml; charset=ISO-8859-1"
bhangare06312472017-03-30 05:49:07 -07007369
sousaedu2ad85172021-02-17 15:05:18 +01007370 response = self.perform_request(
7371 req_type="PUT", url=disk_href, data=new_data, headers=headers
7372 )
bhangare1a0b97c2017-06-21 02:20:15 -07007373
7374 if response.status_code == 403:
sousaedu2ad85172021-02-17 15:05:18 +01007375 add_headers = {"Content-Type": headers["Content-Type"]}
7376 response = self.retry_rest("PUT", disk_href, add_headers, new_data)
bhangare06312472017-03-30 05:49:07 -07007377
7378 if response.status_code != 202:
sousaedu2ad85172021-02-17 15:05:18 +01007379 self.logger.error(
7380 "PUT REST API call {} failed. Return status code {}. response.text:{}".format(
7381 disk_href, response.status_code, response.text
7382 )
7383 )
bhangare06312472017-03-30 05:49:07 -07007384 else:
beierl26fec002019-12-06 17:06:40 -05007385 add_disk_task = self.get_task_from_response(response.text)
sousaedu2ad85172021-02-17 15:05:18 +01007386 result = self.client.get_task_monitor().wait_for_success(
7387 task=add_disk_task
7388 )
7389
7390 if result.get("status") == "success":
kasarc5bf2932018-03-09 04:15:22 -08007391 status = True
7392 else:
sousaedu2ad85172021-02-17 15:05:18 +01007393 self.logger.error(
7394 "Add new disk REST task failed to add {} MB disk".format(
7395 disk_size_mb
7396 )
7397 )
bhangare06312472017-03-30 05:49:07 -07007398 except Exception as exp:
sousaedu2ad85172021-02-17 15:05:18 +01007399 self.logger.error(
7400 "Error occurred calling rest api for creating new disk {}".format(exp)
7401 )
bhangare06312472017-03-30 05:49:07 -07007402
7403 return status
7404
sousaedu2ad85172021-02-17 15:05:18 +01007405 def add_existing_disk(
7406 self,
7407 catalogs=None,
7408 image_id=None,
7409 size=None,
7410 template_name=None,
7411 vapp_uuid=None,
7412 ):
bhangare06312472017-03-30 05:49:07 -07007413 """
sousaedu2ad85172021-02-17 15:05:18 +01007414 Method to add existing disk to vm
7415 Args :
7416 catalogs - List of VDC catalogs
7417 image_id - Catalog ID
7418 template_name - Name of template in catalog
7419 vapp_uuid - UUID of vApp
7420 Returns:
7421 None
bhangare06312472017-03-30 05:49:07 -07007422 """
7423 disk_info = None
7424 vcenter_conect, content = self.get_vcenter_content()
beierlb22ce2d2019-12-12 12:09:51 -05007425 # find moref-id of vm in image
sousaedu2ad85172021-02-17 15:05:18 +01007426 catalog_vm_info = self.get_vapp_template_details(
7427 catalogs=catalogs,
7428 image_id=image_id,
7429 )
bhangare06312472017-03-30 05:49:07 -07007430
7431 if catalog_vm_info and "vm_vcenter_info" in catalog_vm_info:
7432 if "vm_moref_id" in catalog_vm_info["vm_vcenter_info"]:
sousaedu2ad85172021-02-17 15:05:18 +01007433 catalog_vm_moref_id = catalog_vm_info["vm_vcenter_info"].get(
7434 "vm_moref_id", None
7435 )
7436
bhangare06312472017-03-30 05:49:07 -07007437 if catalog_vm_moref_id:
sousaedu2ad85172021-02-17 15:05:18 +01007438 self.logger.info(
7439 "Moref_id of VM in catalog : {}".format(catalog_vm_moref_id)
7440 )
beierlb22ce2d2019-12-12 12:09:51 -05007441 _, catalog_vm_obj = self.get_vm_obj(content, catalog_vm_moref_id)
sousaedu2ad85172021-02-17 15:05:18 +01007442
bhangare06312472017-03-30 05:49:07 -07007443 if catalog_vm_obj:
beierlb22ce2d2019-12-12 12:09:51 -05007444 # find existing disk
bhangare06312472017-03-30 05:49:07 -07007445 disk_info = self.find_disk(catalog_vm_obj)
7446 else:
7447 exp_msg = "No VM with image id {} found".format(image_id)
7448 self.rollback_newvm(vapp_uuid, exp_msg, exp_type="NotFound")
7449 else:
7450 exp_msg = "No Image found with image ID {} ".format(image_id)
7451 self.rollback_newvm(vapp_uuid, exp_msg, exp_type="NotFound")
7452
7453 if disk_info:
7454 self.logger.info("Existing disk_info : {}".format(disk_info))
beierlb22ce2d2019-12-12 12:09:51 -05007455 # get VM
bhangare06312472017-03-30 05:49:07 -07007456 vm_moref_id = self.get_vm_moref_id(vapp_uuid)
beierlb22ce2d2019-12-12 12:09:51 -05007457 _, vm_obj = self.get_vm_obj(content, vm_moref_id)
sousaedu2ad85172021-02-17 15:05:18 +01007458
bhangare06312472017-03-30 05:49:07 -07007459 if vm_obj:
sousaedu2ad85172021-02-17 15:05:18 +01007460 status = self.add_disk(
7461 vcenter_conect=vcenter_conect,
7462 vm=vm_obj,
7463 disk_info=disk_info,
7464 size=size,
7465 vapp_uuid=vapp_uuid,
7466 )
7467
bhangare06312472017-03-30 05:49:07 -07007468 if status:
sousaedu2ad85172021-02-17 15:05:18 +01007469 self.logger.info(
7470 "Disk from image id {} added to {}".format(
7471 image_id, vm_obj.config.name
7472 )
7473 )
bhangare06312472017-03-30 05:49:07 -07007474 else:
7475 msg = "No disk found with image id {} to add in VM {}".format(
sousaedu2ad85172021-02-17 15:05:18 +01007476 image_id, vm_obj.config.name
7477 )
bhangare06312472017-03-30 05:49:07 -07007478 self.rollback_newvm(vapp_uuid, msg, exp_type="NotFound")
7479
bhangare06312472017-03-30 05:49:07 -07007480 def find_disk(self, vm_obj):
7481 """
sousaedu2ad85172021-02-17 15:05:18 +01007482 Method to find details of existing disk in VM
7483 Args:
bhangare06312472017-03-30 05:49:07 -07007484 vm_obj - vCenter object of VM
bhangare06312472017-03-30 05:49:07 -07007485 Returns:
7486 disk_info : dict of disk details
7487 """
7488 disk_info = {}
7489 if vm_obj:
7490 try:
7491 devices = vm_obj.config.hardware.device
sousaedu2ad85172021-02-17 15:05:18 +01007492
bhangare06312472017-03-30 05:49:07 -07007493 for device in devices:
7494 if type(device) is vim.vm.device.VirtualDisk:
sousaedu2ad85172021-02-17 15:05:18 +01007495 if (
7496 isinstance(
7497 device.backing,
7498 vim.vm.device.VirtualDisk.FlatVer2BackingInfo,
7499 )
7500 and hasattr(device.backing, "fileName")
7501 ):
bhangare06312472017-03-30 05:49:07 -07007502 disk_info["full_path"] = device.backing.fileName
7503 disk_info["datastore"] = device.backing.datastore
7504 disk_info["capacityKB"] = device.capacityInKB
7505 break
7506 except Exception as exp:
sousaedu2ad85172021-02-17 15:05:18 +01007507 self.logger.error(
7508 "find_disk() : exception occurred while "
7509 "getting existing disk details :{}".format(exp)
7510 )
7511
bhangare06312472017-03-30 05:49:07 -07007512 return disk_info
7513
sousaedu2ad85172021-02-17 15:05:18 +01007514 def add_disk(
7515 self, vcenter_conect=None, vm=None, size=None, vapp_uuid=None, disk_info={}
7516 ):
bhangare06312472017-03-30 05:49:07 -07007517 """
sousaedu2ad85172021-02-17 15:05:18 +01007518 Method to add existing disk in VM
7519 Args :
7520 vcenter_conect - vCenter content object
7521 vm - vCenter vm object
7522 disk_info : dict of disk details
7523 Returns:
7524 status : status of add disk task
bhangare06312472017-03-30 05:49:07 -07007525 """
7526 datastore = disk_info["datastore"] if "datastore" in disk_info else None
7527 fullpath = disk_info["full_path"] if "full_path" in disk_info else None
7528 capacityKB = disk_info["capacityKB"] if "capacityKB" in disk_info else None
7529 if size is not None:
beierlb22ce2d2019-12-12 12:09:51 -05007530 # Convert size from GB to KB
bhangare06312472017-03-30 05:49:07 -07007531 sizeKB = int(size) * 1024 * 1024
beierlb22ce2d2019-12-12 12:09:51 -05007532 # compare size of existing disk and user given size.Assign whicherver is greater
sousaedu2ad85172021-02-17 15:05:18 +01007533 self.logger.info(
7534 "Add Existing disk : sizeKB {} , capacityKB {}".format(
7535 sizeKB, capacityKB
7536 )
7537 )
7538
bhangare06312472017-03-30 05:49:07 -07007539 if sizeKB > capacityKB:
7540 capacityKB = sizeKB
7541
7542 if datastore and fullpath and capacityKB:
7543 try:
7544 spec = vim.vm.ConfigSpec()
7545 # get all disks on a VM, set unit_number to the next available
7546 unit_number = 0
7547 for dev in vm.config.hardware.device:
sousaedu2ad85172021-02-17 15:05:18 +01007548 if hasattr(dev.backing, "fileName"):
bhangare06312472017-03-30 05:49:07 -07007549 unit_number = int(dev.unitNumber) + 1
7550 # unit_number 7 reserved for scsi controller
sousaedu2ad85172021-02-17 15:05:18 +01007551
bhangare06312472017-03-30 05:49:07 -07007552 if unit_number == 7:
7553 unit_number += 1
sousaedu2ad85172021-02-17 15:05:18 +01007554
bhangare06312472017-03-30 05:49:07 -07007555 if isinstance(dev, vim.vm.device.VirtualDisk):
beierlb22ce2d2019-12-12 12:09:51 -05007556 # vim.vm.device.VirtualSCSIController
bhangare06312472017-03-30 05:49:07 -07007557 controller_key = dev.controllerKey
7558
sousaedu2ad85172021-02-17 15:05:18 +01007559 self.logger.info(
7560 "Add Existing disk : unit number {} , controller key {}".format(
7561 unit_number, controller_key
7562 )
7563 )
bhangare06312472017-03-30 05:49:07 -07007564 # add disk here
7565 dev_changes = []
7566 disk_spec = vim.vm.device.VirtualDeviceSpec()
7567 disk_spec.operation = vim.vm.device.VirtualDeviceSpec.Operation.add
7568 disk_spec.device = vim.vm.device.VirtualDisk()
sousaedu2ad85172021-02-17 15:05:18 +01007569 disk_spec.device.backing = (
bhangare06312472017-03-30 05:49:07 -07007570 vim.vm.device.VirtualDisk.FlatVer2BackingInfo()
sousaedu2ad85172021-02-17 15:05:18 +01007571 )
bhangare06312472017-03-30 05:49:07 -07007572 disk_spec.device.backing.thinProvisioned = True
sousaedu2ad85172021-02-17 15:05:18 +01007573 disk_spec.device.backing.diskMode = "persistent"
beierlb22ce2d2019-12-12 12:09:51 -05007574 disk_spec.device.backing.datastore = datastore
7575 disk_spec.device.backing.fileName = fullpath
bhangare06312472017-03-30 05:49:07 -07007576
7577 disk_spec.device.unitNumber = unit_number
7578 disk_spec.device.capacityInKB = capacityKB
7579 disk_spec.device.controllerKey = controller_key
7580 dev_changes.append(disk_spec)
7581 spec.deviceChange = dev_changes
7582 task = vm.ReconfigVM_Task(spec=spec)
7583 status = self.wait_for_vcenter_task(task, vcenter_conect)
sousaedu2ad85172021-02-17 15:05:18 +01007584
bhangare06312472017-03-30 05:49:07 -07007585 return status
7586 except Exception as exp:
sousaedu2ad85172021-02-17 15:05:18 +01007587 exp_msg = (
7588 "add_disk() : exception {} occurred while adding disk "
7589 "{} to vm {}".format(exp, fullpath, vm.config.name)
7590 )
bhangare06312472017-03-30 05:49:07 -07007591 self.rollback_newvm(vapp_uuid, exp_msg)
7592 else:
sousaedu2ad85172021-02-17 15:05:18 +01007593 msg = "add_disk() : Can not add disk to VM with disk info {} ".format(
7594 disk_info
7595 )
bhangare06312472017-03-30 05:49:07 -07007596 self.rollback_newvm(vapp_uuid, msg)
7597
bhangare06312472017-03-30 05:49:07 -07007598 def get_vcenter_content(self):
7599 """
sousaedu2ad85172021-02-17 15:05:18 +01007600 Get the vsphere content object
bhangare06312472017-03-30 05:49:07 -07007601 """
7602 try:
7603 vm_vcenter_info = self.get_vm_vcenter_info()
7604 except Exception as exp:
sousaedu2ad85172021-02-17 15:05:18 +01007605 self.logger.error(
7606 "Error occurred while getting vCenter infromationn"
7607 " for VM : {}".format(exp)
7608 )
7609
tierno72774862020-05-04 11:44:15 +00007610 raise vimconn.VimConnException(message=exp)
bhangare06312472017-03-30 05:49:07 -07007611
7612 context = None
sousaedu2ad85172021-02-17 15:05:18 +01007613 if hasattr(ssl, "_create_unverified_context"):
bhangare06312472017-03-30 05:49:07 -07007614 context = ssl._create_unverified_context()
7615
7616 vcenter_conect = SmartConnect(
beierlb22ce2d2019-12-12 12:09:51 -05007617 host=vm_vcenter_info["vm_vcenter_ip"],
7618 user=vm_vcenter_info["vm_vcenter_user"],
7619 pwd=vm_vcenter_info["vm_vcenter_password"],
7620 port=int(vm_vcenter_info["vm_vcenter_port"]),
sousaedu2ad85172021-02-17 15:05:18 +01007621 sslContext=context,
7622 )
bhangare06312472017-03-30 05:49:07 -07007623 atexit.register(Disconnect, vcenter_conect)
7624 content = vcenter_conect.RetrieveContent()
sousaedu2ad85172021-02-17 15:05:18 +01007625
bhangare06312472017-03-30 05:49:07 -07007626 return vcenter_conect, content
7627
bhangare06312472017-03-30 05:49:07 -07007628 def get_vm_moref_id(self, vapp_uuid):
7629 """
7630 Get the moref_id of given VM
7631 """
7632 try:
7633 if vapp_uuid:
sousaedu2ad85172021-02-17 15:05:18 +01007634 vm_details = self.get_vapp_details_rest(
7635 vapp_uuid, need_admin_access=True
7636 )
7637
bhangare06312472017-03-30 05:49:07 -07007638 if vm_details and "vm_vcenter_info" in vm_details:
7639 vm_moref_id = vm_details["vm_vcenter_info"].get("vm_moref_id", None)
bhangare06312472017-03-30 05:49:07 -07007640
sousaedu2ad85172021-02-17 15:05:18 +01007641 return vm_moref_id
bhangare06312472017-03-30 05:49:07 -07007642 except Exception as exp:
sousaedu2ad85172021-02-17 15:05:18 +01007643 self.logger.error(
7644 "Error occurred while getting VM moref ID " " for VM : {}".format(exp)
7645 )
7646
bhangare06312472017-03-30 05:49:07 -07007647 return None
7648
sousaedu2ad85172021-02-17 15:05:18 +01007649 def get_vapp_template_details(
7650 self, catalogs=None, image_id=None, template_name=None
7651 ):
bhangare06312472017-03-30 05:49:07 -07007652 """
sousaedu2ad85172021-02-17 15:05:18 +01007653 Method to get vApp template details
7654 Args :
7655 catalogs - list of VDC catalogs
7656 image_id - Catalog ID to find
7657 template_name : template name in catalog
7658 Returns:
7659 parsed_respond : dict of vApp tempalte details
bhangare06312472017-03-30 05:49:07 -07007660 """
7661 parsed_response = {}
7662
7663 vca = self.connect_as_admin()
7664 if not vca:
tierno72774862020-05-04 11:44:15 +00007665 raise vimconn.VimConnConnectionException("Failed to connect vCD")
bhangare06312472017-03-30 05:49:07 -07007666
7667 try:
beierlb22ce2d2019-12-12 12:09:51 -05007668 org, _ = self.get_vdc_details()
bhangare06312472017-03-30 05:49:07 -07007669 catalog = self.get_catalog_obj(image_id, catalogs)
7670 if catalog:
sousaedu2ad85172021-02-17 15:05:18 +01007671 items = org.get_catalog_item(catalog.get("name"), catalog.get("name"))
kasarc5bf2932018-03-09 04:15:22 -08007672 catalog_items = [items.attrib]
7673
bhangare06312472017-03-30 05:49:07 -07007674 if len(catalog_items) == 1:
sousaedu2ad85172021-02-17 15:05:18 +01007675 headers = {
7676 "Accept": "application/*+xml;version=" + API_VERSION,
7677 "x-vcloud-authorization": vca._session.headers[
7678 "x-vcloud-authorization"
7679 ],
7680 }
7681 response = self.perform_request(
7682 req_type="GET",
7683 url=catalog_items[0].get("href"),
7684 headers=headers,
7685 )
beierl26fec002019-12-06 17:06:40 -05007686 catalogItem = XmlElementTree.fromstring(response.text)
sousaedu2ad85172021-02-17 15:05:18 +01007687 entity = [
7688 child
7689 for child in catalogItem
7690 if child.get("type")
7691 == "application/vnd.vmware.vcloud.vAppTemplate+xml"
7692 ][0]
bhangare06312472017-03-30 05:49:07 -07007693 vapp_tempalte_href = entity.get("href")
beierlb22ce2d2019-12-12 12:09:51 -05007694 # get vapp details and parse moref id
bhangare06312472017-03-30 05:49:07 -07007695
beierlb22ce2d2019-12-12 12:09:51 -05007696 namespaces = {
sousaedu2ad85172021-02-17 15:05:18 +01007697 "vssd": "http://schemas.dmtf.org/wbem/wscim/1/cim-schema/2/CIM_VirtualSystemSettingData",
7698 "ovf": "http://schemas.dmtf.org/ovf/envelope/1",
7699 "vmw": "http://www.vmware.com/schema/ovf",
7700 "vm": "http://www.vmware.com/vcloud/v1.5",
7701 "rasd": "http://schemas.dmtf.org/wbem/wscim/1/cim-schema/2/CIM_ResourceAllocationSettingData",
7702 "vmext": "http://www.vmware.com/vcloud/extension/v1.5",
7703 "xmlns": "http://www.vmware.com/vcloud/v1.5",
beierlb22ce2d2019-12-12 12:09:51 -05007704 }
bhangare06312472017-03-30 05:49:07 -07007705
kasarc5bf2932018-03-09 04:15:22 -08007706 if vca._session:
sousaedu2ad85172021-02-17 15:05:18 +01007707 response = self.perform_request(
7708 req_type="GET", url=vapp_tempalte_href, headers=headers
7709 )
bhangare06312472017-03-30 05:49:07 -07007710
7711 if response.status_code != requests.codes.ok:
sousaedu2ad85172021-02-17 15:05:18 +01007712 self.logger.debug(
7713 "REST API call {} failed. Return status code {}".format(
7714 vapp_tempalte_href, response.status_code
7715 )
7716 )
bhangare06312472017-03-30 05:49:07 -07007717 else:
beierl26fec002019-12-06 17:06:40 -05007718 xmlroot_respond = XmlElementTree.fromstring(response.text)
sousaedu2ad85172021-02-17 15:05:18 +01007719 children_section = xmlroot_respond.find(
7720 "vm:Children/", namespaces
7721 )
7722
bhangare06312472017-03-30 05:49:07 -07007723 if children_section is not None:
sousaedu2ad85172021-02-17 15:05:18 +01007724 vCloud_extension_section = children_section.find(
7725 "xmlns:VCloudExtension", namespaces
7726 )
7727
bhangare06312472017-03-30 05:49:07 -07007728 if vCloud_extension_section is not None:
7729 vm_vcenter_info = {}
sousaedu2ad85172021-02-17 15:05:18 +01007730 vim_info = vCloud_extension_section.find(
7731 "vmext:VmVimInfo", namespaces
7732 )
7733 vmext = vim_info.find(
7734 "vmext:VmVimObjectRef", namespaces
7735 )
bhangare06312472017-03-30 05:49:07 -07007736
sousaedu2ad85172021-02-17 15:05:18 +01007737 if vmext is not None:
7738 vm_vcenter_info["vm_moref_id"] = vmext.find(
7739 "vmext:MoRef", namespaces
7740 ).text
7741
7742 parsed_response["vm_vcenter_info"] = vm_vcenter_info
beierlb22ce2d2019-12-12 12:09:51 -05007743 except Exception as exp:
sousaedu2ad85172021-02-17 15:05:18 +01007744 self.logger.info(
7745 "Error occurred calling rest api for getting vApp details {}".format(
7746 exp
7747 )
7748 )
bhangare06312472017-03-30 05:49:07 -07007749
7750 return parsed_response
7751
beierlb22ce2d2019-12-12 12:09:51 -05007752 def rollback_newvm(self, vapp_uuid, msg, exp_type="Genric"):
bhangare06312472017-03-30 05:49:07 -07007753 """
sousaedu2ad85172021-02-17 15:05:18 +01007754 Method to delete vApp
7755 Args :
7756 vapp_uuid - vApp UUID
7757 msg - Error message to be logged
7758 exp_type : Exception type
7759 Returns:
7760 None
bhangare06312472017-03-30 05:49:07 -07007761 """
7762 if vapp_uuid:
beierlb22ce2d2019-12-12 12:09:51 -05007763 self.delete_vminstance(vapp_uuid)
bhangare06312472017-03-30 05:49:07 -07007764 else:
7765 msg = "No vApp ID"
sousaedu2ad85172021-02-17 15:05:18 +01007766
bhangare06312472017-03-30 05:49:07 -07007767 self.logger.error(msg)
sousaedu2ad85172021-02-17 15:05:18 +01007768
bhangare06312472017-03-30 05:49:07 -07007769 if exp_type == "Genric":
tierno72774862020-05-04 11:44:15 +00007770 raise vimconn.VimConnException(msg)
bhangare06312472017-03-30 05:49:07 -07007771 elif exp_type == "NotFound":
tierno72774862020-05-04 11:44:15 +00007772 raise vimconn.VimConnNotFoundException(message=msg)
bhangare06312472017-03-30 05:49:07 -07007773
kateac1e3792017-04-01 02:16:39 -07007774 def add_sriov(self, vapp_uuid, sriov_nets, vmname_andid):
7775 """
sousaedu2ad85172021-02-17 15:05:18 +01007776 Method to attach SRIOV adapters to VM
kateac1e3792017-04-01 02:16:39 -07007777
sousaedu2ad85172021-02-17 15:05:18 +01007778 Args:
7779 vapp_uuid - uuid of vApp/VM
7780 sriov_nets - SRIOV devices infromation as specified in VNFD (flavor)
7781 vmname_andid - vmname
kateac1e3792017-04-01 02:16:39 -07007782
sousaedu2ad85172021-02-17 15:05:18 +01007783 Returns:
7784 The status of add SRIOV adapter task , vm object and
7785 vcenter_conect object
kateac1e3792017-04-01 02:16:39 -07007786 """
7787 vm_obj = None
7788 vcenter_conect, content = self.get_vcenter_content()
7789 vm_moref_id = self.get_vm_moref_id(vapp_uuid)
7790
7791 if vm_moref_id:
7792 try:
7793 no_of_sriov_devices = len(sriov_nets)
7794 if no_of_sriov_devices > 0:
beierlb22ce2d2019-12-12 12:09:51 -05007795 # Get VM and its host
kateac1e3792017-04-01 02:16:39 -07007796 host_obj, vm_obj = self.get_vm_obj(content, vm_moref_id)
sousaedu2ad85172021-02-17 15:05:18 +01007797 self.logger.info(
7798 "VM {} is currently on host {}".format(vm_obj, host_obj)
7799 )
7800
kateac1e3792017-04-01 02:16:39 -07007801 if host_obj and vm_obj:
beierlb22ce2d2019-12-12 12:09:51 -05007802 # get SRIOV devies from host on which vapp is currently installed
sousaedu2ad85172021-02-17 15:05:18 +01007803 avilable_sriov_devices = self.get_sriov_devices(
7804 host_obj,
7805 no_of_sriov_devices,
7806 )
kateac1e3792017-04-01 02:16:39 -07007807
7808 if len(avilable_sriov_devices) == 0:
beierlb22ce2d2019-12-12 12:09:51 -05007809 # find other hosts with active pci devices
sousaedu2ad85172021-02-17 15:05:18 +01007810 (
7811 new_host_obj,
7812 avilable_sriov_devices,
7813 ) = self.get_host_and_sriov_devices(
beierlb22ce2d2019-12-12 12:09:51 -05007814 content,
7815 no_of_sriov_devices,
sousaedu2ad85172021-02-17 15:05:18 +01007816 )
kateac1e3792017-04-01 02:16:39 -07007817
sousaedu2ad85172021-02-17 15:05:18 +01007818 if (
7819 new_host_obj is not None
7820 and len(avilable_sriov_devices) > 0
7821 ):
beierlb22ce2d2019-12-12 12:09:51 -05007822 # Migrate vm to the host where SRIOV devices are available
sousaedu2ad85172021-02-17 15:05:18 +01007823 self.logger.info(
7824 "Relocate VM {} on new host {}".format(
7825 vm_obj, new_host_obj
7826 )
7827 )
kateac1e3792017-04-01 02:16:39 -07007828 task = self.relocate_vm(new_host_obj, vm_obj)
sousaedu2ad85172021-02-17 15:05:18 +01007829
kateac1e3792017-04-01 02:16:39 -07007830 if task is not None:
sousaedu2ad85172021-02-17 15:05:18 +01007831 result = self.wait_for_vcenter_task(
7832 task, vcenter_conect
7833 )
7834 self.logger.info(
7835 "Migrate VM status: {}".format(result)
7836 )
kateac1e3792017-04-01 02:16:39 -07007837 host_obj = new_host_obj
7838 else:
sousaedu2ad85172021-02-17 15:05:18 +01007839 self.logger.info(
7840 "Fail to migrate VM : {}".format(result)
7841 )
7842
tierno72774862020-05-04 11:44:15 +00007843 raise vimconn.VimConnNotFoundException(
beierlb22ce2d2019-12-12 12:09:51 -05007844 "Fail to migrate VM : {} to host {}".format(
sousaedu2ad85172021-02-17 15:05:18 +01007845 vmname_andid, new_host_obj
kateac1e3792017-04-01 02:16:39 -07007846 )
sousaedu2ad85172021-02-17 15:05:18 +01007847 )
kateac1e3792017-04-01 02:16:39 -07007848
sousaedu2ad85172021-02-17 15:05:18 +01007849 if (
7850 host_obj is not None
7851 and avilable_sriov_devices is not None
7852 and len(avilable_sriov_devices) > 0
7853 ):
beierlb22ce2d2019-12-12 12:09:51 -05007854 # Add SRIOV devices one by one
kateac1e3792017-04-01 02:16:39 -07007855 for sriov_net in sriov_nets:
sousaedu2ad85172021-02-17 15:05:18 +01007856 network_name = sriov_net.get("net_id")
beierlb22ce2d2019-12-12 12:09:51 -05007857 self.create_dvPort_group(network_name)
kateac1e3792017-04-01 02:16:39 -07007858
sousaedu2ad85172021-02-17 15:05:18 +01007859 if (
7860 sriov_net.get("type") == "VF"
7861 or sriov_net.get("type") == "SR-IOV"
7862 ):
7863 # add vlan ID ,Modify portgroup for vlan ID
7864 self.configure_vlanID(
7865 content, vcenter_conect, network_name
7866 )
7867
7868 task = self.add_sriov_to_vm(
7869 content,
7870 vm_obj,
7871 host_obj,
7872 network_name,
7873 avilable_sriov_devices[0],
7874 )
7875
kateac1e3792017-04-01 02:16:39 -07007876 if task:
sousaedu2ad85172021-02-17 15:05:18 +01007877 status = self.wait_for_vcenter_task(
7878 task, vcenter_conect
7879 )
7880
kateac1e3792017-04-01 02:16:39 -07007881 if status:
sousaedu2ad85172021-02-17 15:05:18 +01007882 self.logger.info(
7883 "Added SRIOV {} to VM {}".format(
7884 no_of_sriov_devices, str(vm_obj)
7885 )
kateac1e3792017-04-01 02:16:39 -07007886 )
sousaedu2ad85172021-02-17 15:05:18 +01007887 else:
7888 self.logger.error(
7889 "Fail to add SRIOV {} to VM {}".format(
7890 no_of_sriov_devices, str(vm_obj)
7891 )
7892 )
7893
7894 raise vimconn.VimConnUnexpectedResponse(
7895 "Fail to add SRIOV adapter in VM {}".format(
7896 str(vm_obj)
7897 )
7898 )
7899
kateac1e3792017-04-01 02:16:39 -07007900 return True, vm_obj, vcenter_conect
7901 else:
sousaedu2ad85172021-02-17 15:05:18 +01007902 self.logger.error(
7903 "Currently there is no host with"
7904 " {} number of avaialble SRIOV "
7905 "VFs required for VM {}".format(
7906 no_of_sriov_devices, vmname_andid
7907 )
7908 )
7909
tierno72774862020-05-04 11:44:15 +00007910 raise vimconn.VimConnNotFoundException(
beierlb22ce2d2019-12-12 12:09:51 -05007911 "Currently there is no host with {} "
7912 "number of avaialble SRIOV devices required for VM {}".format(
sousaedu2ad85172021-02-17 15:05:18 +01007913 no_of_sriov_devices, vmname_andid
7914 )
7915 )
kateac1e3792017-04-01 02:16:39 -07007916 else:
sousaedu2ad85172021-02-17 15:05:18 +01007917 self.logger.debug(
7918 "No infromation about SRIOV devices {} ", sriov_nets
7919 )
kateac1e3792017-04-01 02:16:39 -07007920 except vmodl.MethodFault as error:
beierlb22ce2d2019-12-12 12:09:51 -05007921 self.logger.error("Error occurred while adding SRIOV {} ", error)
sousaedu2ad85172021-02-17 15:05:18 +01007922
kateac1e3792017-04-01 02:16:39 -07007923 return None, vm_obj, vcenter_conect
7924
beierlb22ce2d2019-12-12 12:09:51 -05007925 def get_sriov_devices(self, host, no_of_vfs):
kateac1e3792017-04-01 02:16:39 -07007926 """
sousaedu2ad85172021-02-17 15:05:18 +01007927 Method to get the details of SRIOV devices on given host
7928 Args:
7929 host - vSphere host object
7930 no_of_vfs - number of VFs needed on host
kateac1e3792017-04-01 02:16:39 -07007931
sousaedu2ad85172021-02-17 15:05:18 +01007932 Returns:
7933 array of SRIOV devices
kateac1e3792017-04-01 02:16:39 -07007934 """
beierlb22ce2d2019-12-12 12:09:51 -05007935 sriovInfo = []
sousaedu2ad85172021-02-17 15:05:18 +01007936
kateac1e3792017-04-01 02:16:39 -07007937 if host:
7938 for device in host.config.pciPassthruInfo:
beierlb22ce2d2019-12-12 12:09:51 -05007939 if isinstance(device, vim.host.SriovInfo) and device.sriovActive:
kateac1e3792017-04-01 02:16:39 -07007940 if device.numVirtualFunction >= no_of_vfs:
7941 sriovInfo.append(device)
7942 break
sousaedu2ad85172021-02-17 15:05:18 +01007943
kateac1e3792017-04-01 02:16:39 -07007944 return sriovInfo
7945
kateac1e3792017-04-01 02:16:39 -07007946 def get_host_and_sriov_devices(self, content, no_of_vfs):
7947 """
sousaedu2ad85172021-02-17 15:05:18 +01007948 Method to get the details of SRIOV devices infromation on all hosts
kateac1e3792017-04-01 02:16:39 -07007949
sousaedu2ad85172021-02-17 15:05:18 +01007950 Args:
7951 content - vSphere host object
7952 no_of_vfs - number of pci VFs needed on host
kateac1e3792017-04-01 02:16:39 -07007953
sousaedu2ad85172021-02-17 15:05:18 +01007954 Returns:
7955 array of SRIOV devices and host object
kateac1e3792017-04-01 02:16:39 -07007956 """
7957 host_obj = None
7958 sriov_device_objs = None
sousaedu2ad85172021-02-17 15:05:18 +01007959
kateac1e3792017-04-01 02:16:39 -07007960 try:
7961 if content:
sousaedu2ad85172021-02-17 15:05:18 +01007962 container = content.viewManager.CreateContainerView(
7963 content.rootFolder, [vim.HostSystem], True
7964 )
7965
kateac1e3792017-04-01 02:16:39 -07007966 for host in container.view:
7967 devices = self.get_sriov_devices(host, no_of_vfs)
sousaedu2ad85172021-02-17 15:05:18 +01007968
kateac1e3792017-04-01 02:16:39 -07007969 if devices:
7970 host_obj = host
7971 sriov_device_objs = devices
7972 break
7973 except Exception as exp:
sousaedu2ad85172021-02-17 15:05:18 +01007974 self.logger.error(
7975 "Error {} occurred while finding SRIOV devices on host: {}".format(
7976 exp, host_obj
7977 )
7978 )
kateac1e3792017-04-01 02:16:39 -07007979
beierlb22ce2d2019-12-12 12:09:51 -05007980 return host_obj, sriov_device_objs
kateac1e3792017-04-01 02:16:39 -07007981
beierlb22ce2d2019-12-12 12:09:51 -05007982 def add_sriov_to_vm(self, content, vm_obj, host_obj, network_name, sriov_device):
kateac1e3792017-04-01 02:16:39 -07007983 """
sousaedu2ad85172021-02-17 15:05:18 +01007984 Method to add SRIOV adapter to vm
kateac1e3792017-04-01 02:16:39 -07007985
sousaedu2ad85172021-02-17 15:05:18 +01007986 Args:
7987 host_obj - vSphere host object
7988 vm_obj - vSphere vm object
7989 content - vCenter content object
7990 network_name - name of distributed virtaul portgroup
7991 sriov_device - SRIOV device info
kateac1e3792017-04-01 02:16:39 -07007992
sousaedu2ad85172021-02-17 15:05:18 +01007993 Returns:
7994 task object
kateac1e3792017-04-01 02:16:39 -07007995 """
7996 devices = []
7997 vnic_label = "sriov nic"
sousaedu2ad85172021-02-17 15:05:18 +01007998
kateac1e3792017-04-01 02:16:39 -07007999 try:
8000 dvs_portgr = self.get_dvport_group(network_name)
8001 network_name = dvs_portgr.name
8002 nic = vim.vm.device.VirtualDeviceSpec()
8003 # VM device
8004 nic.operation = vim.vm.device.VirtualDeviceSpec.Operation.add
8005 nic.device = vim.vm.device.VirtualSriovEthernetCard()
sousaedu2ad85172021-02-17 15:05:18 +01008006 nic.device.addressType = "assigned"
beierlb22ce2d2019-12-12 12:09:51 -05008007 # nic.device.key = 13016
kateac1e3792017-04-01 02:16:39 -07008008 nic.device.deviceInfo = vim.Description()
8009 nic.device.deviceInfo.label = vnic_label
8010 nic.device.deviceInfo.summary = network_name
8011 nic.device.backing = vim.vm.device.VirtualEthernetCard.NetworkBackingInfo()
8012
sousaedu2ad85172021-02-17 15:05:18 +01008013 nic.device.backing.network = self.get_obj(
8014 content, [vim.Network], network_name
8015 )
kateac1e3792017-04-01 02:16:39 -07008016 nic.device.backing.deviceName = network_name
8017 nic.device.backing.useAutoDetect = False
8018 nic.device.connectable = vim.vm.device.VirtualDevice.ConnectInfo()
8019 nic.device.connectable.startConnected = True
8020 nic.device.connectable.allowGuestControl = True
8021
sousaedu2ad85172021-02-17 15:05:18 +01008022 nic.device.sriovBacking = (
8023 vim.vm.device.VirtualSriovEthernetCard.SriovBackingInfo()
8024 )
8025 nic.device.sriovBacking.physicalFunctionBacking = (
8026 vim.vm.device.VirtualPCIPassthrough.DeviceBackingInfo()
8027 )
kateac1e3792017-04-01 02:16:39 -07008028 nic.device.sriovBacking.physicalFunctionBacking.id = sriov_device.id
8029
8030 devices.append(nic)
8031 vmconf = vim.vm.ConfigSpec(deviceChange=devices)
8032 task = vm_obj.ReconfigVM_Task(vmconf)
sousaedu2ad85172021-02-17 15:05:18 +01008033
kateac1e3792017-04-01 02:16:39 -07008034 return task
8035 except Exception as exp:
sousaedu2ad85172021-02-17 15:05:18 +01008036 self.logger.error(
8037 "Error {} occurred while adding SRIOV adapter in VM: {}".format(
8038 exp, vm_obj
8039 )
8040 )
8041
kateac1e3792017-04-01 02:16:39 -07008042 return None
8043
kateac1e3792017-04-01 02:16:39 -07008044 def create_dvPort_group(self, network_name):
8045 """
sousaedu2ad85172021-02-17 15:05:18 +01008046 Method to create disributed virtual portgroup
kateac1e3792017-04-01 02:16:39 -07008047
sousaedu2ad85172021-02-17 15:05:18 +01008048 Args:
8049 network_name - name of network/portgroup
kateac1e3792017-04-01 02:16:39 -07008050
sousaedu2ad85172021-02-17 15:05:18 +01008051 Returns:
8052 portgroup key
kateac1e3792017-04-01 02:16:39 -07008053 """
8054 try:
sousaedu2ad85172021-02-17 15:05:18 +01008055 new_network_name = [network_name, "-", str(uuid.uuid4())]
8056 network_name = "".join(new_network_name)
kateac1e3792017-04-01 02:16:39 -07008057 vcenter_conect, content = self.get_vcenter_content()
8058
sousaedu2ad85172021-02-17 15:05:18 +01008059 dv_switch = self.get_obj(
8060 content, [vim.DistributedVirtualSwitch], self.dvs_name
8061 )
8062
kateac1e3792017-04-01 02:16:39 -07008063 if dv_switch:
8064 dv_pg_spec = vim.dvs.DistributedVirtualPortgroup.ConfigSpec()
8065 dv_pg_spec.name = network_name
8066
sousaedu2ad85172021-02-17 15:05:18 +01008067 dv_pg_spec.type = (
8068 vim.dvs.DistributedVirtualPortgroup.PortgroupType.earlyBinding
8069 )
8070 dv_pg_spec.defaultPortConfig = (
8071 vim.dvs.VmwareDistributedVirtualSwitch.VmwarePortConfigPolicy()
8072 )
8073 dv_pg_spec.defaultPortConfig.securityPolicy = (
8074 vim.dvs.VmwareDistributedVirtualSwitch.SecurityPolicy()
8075 )
8076 dv_pg_spec.defaultPortConfig.securityPolicy.allowPromiscuous = (
8077 vim.BoolPolicy(value=False)
8078 )
8079 dv_pg_spec.defaultPortConfig.securityPolicy.forgedTransmits = (
8080 vim.BoolPolicy(value=False)
8081 )
8082 dv_pg_spec.defaultPortConfig.securityPolicy.macChanges = vim.BoolPolicy(
8083 value=False
8084 )
kateac1e3792017-04-01 02:16:39 -07008085
8086 task = dv_switch.AddDVPortgroup_Task([dv_pg_spec])
8087 self.wait_for_vcenter_task(task, vcenter_conect)
8088
sousaedu2ad85172021-02-17 15:05:18 +01008089 dvPort_group = self.get_obj(
8090 content, [vim.dvs.DistributedVirtualPortgroup], network_name
8091 )
8092
kateac1e3792017-04-01 02:16:39 -07008093 if dvPort_group:
sousaedu2ad85172021-02-17 15:05:18 +01008094 self.logger.info(
8095 "Created disributed virtaul port group: {}".format(dvPort_group)
8096 )
kateac1e3792017-04-01 02:16:39 -07008097 return dvPort_group.key
8098 else:
sousaedu2ad85172021-02-17 15:05:18 +01008099 self.logger.debug(
8100 "No disributed virtual switch found with name {}".format(
8101 network_name
8102 )
8103 )
kateac1e3792017-04-01 02:16:39 -07008104
8105 except Exception as exp:
sousaedu2ad85172021-02-17 15:05:18 +01008106 self.logger.error(
8107 "Error occurred while creating disributed virtaul port group {}"
8108 " : {}".format(network_name, exp)
8109 )
8110
kateac1e3792017-04-01 02:16:39 -07008111 return None
8112
beierlb22ce2d2019-12-12 12:09:51 -05008113 def reconfig_portgroup(self, content, dvPort_group_name, config_info={}):
kateac1e3792017-04-01 02:16:39 -07008114 """
sousaedu2ad85172021-02-17 15:05:18 +01008115 Method to reconfigure disributed virtual portgroup
kateac1e3792017-04-01 02:16:39 -07008116
sousaedu2ad85172021-02-17 15:05:18 +01008117 Args:
8118 dvPort_group_name - name of disributed virtual portgroup
8119 content - vCenter content object
8120 config_info - disributed virtual portgroup configuration
kateac1e3792017-04-01 02:16:39 -07008121
sousaedu2ad85172021-02-17 15:05:18 +01008122 Returns:
8123 task object
kateac1e3792017-04-01 02:16:39 -07008124 """
8125 try:
8126 dvPort_group = self.get_dvport_group(dvPort_group_name)
sousaedu2ad85172021-02-17 15:05:18 +01008127
kateac1e3792017-04-01 02:16:39 -07008128 if dvPort_group:
8129 dv_pg_spec = vim.dvs.DistributedVirtualPortgroup.ConfigSpec()
8130 dv_pg_spec.configVersion = dvPort_group.config.configVersion
sousaedu2ad85172021-02-17 15:05:18 +01008131 dv_pg_spec.defaultPortConfig = (
8132 vim.dvs.VmwareDistributedVirtualSwitch.VmwarePortConfigPolicy()
8133 )
8134
kateac1e3792017-04-01 02:16:39 -07008135 if "vlanID" in config_info:
sousaedu2ad85172021-02-17 15:05:18 +01008136 dv_pg_spec.defaultPortConfig.vlan = (
8137 vim.dvs.VmwareDistributedVirtualSwitch.VlanIdSpec()
8138 )
8139 dv_pg_spec.defaultPortConfig.vlan.vlanId = config_info.get("vlanID")
kateac1e3792017-04-01 02:16:39 -07008140
8141 task = dvPort_group.ReconfigureDVPortgroup_Task(spec=dv_pg_spec)
sousaedu2ad85172021-02-17 15:05:18 +01008142
kateac1e3792017-04-01 02:16:39 -07008143 return task
8144 else:
8145 return None
8146 except Exception as exp:
sousaedu2ad85172021-02-17 15:05:18 +01008147 self.logger.error(
8148 "Error occurred while reconfiguraing disributed virtaul port group {}"
8149 " : {}".format(dvPort_group_name, exp)
8150 )
8151
kateac1e3792017-04-01 02:16:39 -07008152 return None
8153
beierlb22ce2d2019-12-12 12:09:51 -05008154 def destroy_dvport_group(self, dvPort_group_name):
kateac1e3792017-04-01 02:16:39 -07008155 """
sousaedu2ad85172021-02-17 15:05:18 +01008156 Method to destroy disributed virtual portgroup
kateac1e3792017-04-01 02:16:39 -07008157
sousaedu2ad85172021-02-17 15:05:18 +01008158 Args:
8159 network_name - name of network/portgroup
kateac1e3792017-04-01 02:16:39 -07008160
sousaedu2ad85172021-02-17 15:05:18 +01008161 Returns:
8162 True if portgroup successfully got deleted else false
kateac1e3792017-04-01 02:16:39 -07008163 """
beierlb22ce2d2019-12-12 12:09:51 -05008164 vcenter_conect, _ = self.get_vcenter_content()
sousaedu2ad85172021-02-17 15:05:18 +01008165
kateac1e3792017-04-01 02:16:39 -07008166 try:
8167 status = None
8168 dvPort_group = self.get_dvport_group(dvPort_group_name)
sousaedu2ad85172021-02-17 15:05:18 +01008169
kateac1e3792017-04-01 02:16:39 -07008170 if dvPort_group:
8171 task = dvPort_group.Destroy_Task()
8172 status = self.wait_for_vcenter_task(task, vcenter_conect)
sousaedu2ad85172021-02-17 15:05:18 +01008173
kateac1e3792017-04-01 02:16:39 -07008174 return status
8175 except vmodl.MethodFault as exp:
sousaedu2ad85172021-02-17 15:05:18 +01008176 self.logger.error(
8177 "Caught vmodl fault {} while deleting disributed virtaul port group {}".format(
8178 exp, dvPort_group_name
8179 )
8180 )
8181
kateac1e3792017-04-01 02:16:39 -07008182 return None
8183
kateac1e3792017-04-01 02:16:39 -07008184 def get_dvport_group(self, dvPort_group_name):
8185 """
8186 Method to get disributed virtual portgroup
8187
8188 Args:
8189 network_name - name of network/portgroup
8190
8191 Returns:
8192 portgroup object
8193 """
beierlb22ce2d2019-12-12 12:09:51 -05008194 _, content = self.get_vcenter_content()
kateac1e3792017-04-01 02:16:39 -07008195 dvPort_group = None
sousaedu2ad85172021-02-17 15:05:18 +01008196
kateac1e3792017-04-01 02:16:39 -07008197 try:
sousaedu2ad85172021-02-17 15:05:18 +01008198 container = content.viewManager.CreateContainerView(
8199 content.rootFolder, [vim.dvs.DistributedVirtualPortgroup], True
8200 )
8201
kateac1e3792017-04-01 02:16:39 -07008202 for item in container.view:
8203 if item.key == dvPort_group_name:
8204 dvPort_group = item
8205 break
sousaedu2ad85172021-02-17 15:05:18 +01008206
kateac1e3792017-04-01 02:16:39 -07008207 return dvPort_group
8208 except vmodl.MethodFault as exp:
sousaedu2ad85172021-02-17 15:05:18 +01008209 self.logger.error(
8210 "Caught vmodl fault {} for disributed virtual port group {}".format(
8211 exp, dvPort_group_name
8212 )
8213 )
8214
kateac1e3792017-04-01 02:16:39 -07008215 return None
8216
8217 def get_vlanID_from_dvs_portgr(self, dvPort_group_name):
8218 """
sousaedu2ad85172021-02-17 15:05:18 +01008219 Method to get disributed virtual portgroup vlanID
kateac1e3792017-04-01 02:16:39 -07008220
sousaedu2ad85172021-02-17 15:05:18 +01008221 Args:
8222 network_name - name of network/portgroup
kateac1e3792017-04-01 02:16:39 -07008223
sousaedu2ad85172021-02-17 15:05:18 +01008224 Returns:
8225 vlan ID
kateac1e3792017-04-01 02:16:39 -07008226 """
8227 vlanId = None
sousaedu2ad85172021-02-17 15:05:18 +01008228
kateac1e3792017-04-01 02:16:39 -07008229 try:
8230 dvPort_group = self.get_dvport_group(dvPort_group_name)
sousaedu2ad85172021-02-17 15:05:18 +01008231
kateac1e3792017-04-01 02:16:39 -07008232 if dvPort_group:
8233 vlanId = dvPort_group.config.defaultPortConfig.vlan.vlanId
8234 except vmodl.MethodFault as exp:
sousaedu2ad85172021-02-17 15:05:18 +01008235 self.logger.error(
8236 "Caught vmodl fault {} for disributed virtaul port group {}".format(
8237 exp, dvPort_group_name
8238 )
8239 )
8240
kateac1e3792017-04-01 02:16:39 -07008241 return vlanId
8242
kateac1e3792017-04-01 02:16:39 -07008243 def configure_vlanID(self, content, vcenter_conect, dvPort_group_name):
8244 """
sousaedu2ad85172021-02-17 15:05:18 +01008245 Method to configure vlanID in disributed virtual portgroup vlanID
kateac1e3792017-04-01 02:16:39 -07008246
sousaedu2ad85172021-02-17 15:05:18 +01008247 Args:
8248 network_name - name of network/portgroup
kateac1e3792017-04-01 02:16:39 -07008249
sousaedu2ad85172021-02-17 15:05:18 +01008250 Returns:
8251 None
kateac1e3792017-04-01 02:16:39 -07008252 """
8253 vlanID = self.get_vlanID_from_dvs_portgr(dvPort_group_name)
sousaedu2ad85172021-02-17 15:05:18 +01008254
kateac1e3792017-04-01 02:16:39 -07008255 if vlanID == 0:
beierlb22ce2d2019-12-12 12:09:51 -05008256 # configure vlanID
kateac1e3792017-04-01 02:16:39 -07008257 vlanID = self.genrate_vlanID(dvPort_group_name)
beierlb22ce2d2019-12-12 12:09:51 -05008258 config = {"vlanID": vlanID}
sousaedu2ad85172021-02-17 15:05:18 +01008259 task = self.reconfig_portgroup(
8260 content, dvPort_group_name, config_info=config
8261 )
8262
kateac1e3792017-04-01 02:16:39 -07008263 if task:
beierlb22ce2d2019-12-12 12:09:51 -05008264 status = self.wait_for_vcenter_task(task, vcenter_conect)
sousaedu2ad85172021-02-17 15:05:18 +01008265
kateac1e3792017-04-01 02:16:39 -07008266 if status:
sousaedu2ad85172021-02-17 15:05:18 +01008267 self.logger.info(
8268 "Reconfigured Port group {} for vlan ID {}".format(
8269 dvPort_group_name, vlanID
8270 )
8271 )
kateac1e3792017-04-01 02:16:39 -07008272 else:
sousaedu2ad85172021-02-17 15:05:18 +01008273 self.logger.error(
8274 "Fail reconfigure portgroup {} for vlanID{}".format(
8275 dvPort_group_name, vlanID
8276 )
8277 )
kateac1e3792017-04-01 02:16:39 -07008278
8279 def genrate_vlanID(self, network_name):
8280 """
sousaedu2ad85172021-02-17 15:05:18 +01008281 Method to get unused vlanID
8282 Args:
8283 network_name - name of network/portgroup
8284 Returns:
8285 vlanID
kateac1e3792017-04-01 02:16:39 -07008286 """
8287 vlan_id = None
8288 used_ids = []
sousaedu2ad85172021-02-17 15:05:18 +01008289
8290 if self.config.get("vlanID_range") is None:
8291 raise vimconn.VimConnConflictException(
8292 "You must provide a 'vlanID_range' "
8293 "at config value before creating sriov network with vlan tag"
8294 )
8295
kateac1e3792017-04-01 02:16:39 -07008296 if "used_vlanIDs" not in self.persistent_info:
sousaedu2ad85172021-02-17 15:05:18 +01008297 self.persistent_info["used_vlanIDs"] = {}
kateac1e3792017-04-01 02:16:39 -07008298 else:
tierno7d782ef2019-10-04 12:56:31 +00008299 used_ids = list(self.persistent_info["used_vlanIDs"].values())
kateac1e3792017-04-01 02:16:39 -07008300
sousaedu2ad85172021-02-17 15:05:18 +01008301 for vlanID_range in self.config.get("vlanID_range"):
tierno1b856002019-11-07 16:28:54 +00008302 start_vlanid, end_vlanid = vlanID_range.split("-")
sousaedu2ad85172021-02-17 15:05:18 +01008303
kateac1e3792017-04-01 02:16:39 -07008304 if start_vlanid > end_vlanid:
sousaedu2ad85172021-02-17 15:05:18 +01008305 raise vimconn.VimConnConflictException(
8306 "Invalid vlan ID range {}".format(vlanID_range)
8307 )
kateac1e3792017-04-01 02:16:39 -07008308
beierlb22ce2d2019-12-12 12:09:51 -05008309 for vid in range(int(start_vlanid), int(end_vlanid) + 1):
8310 if vid not in used_ids:
8311 vlan_id = vid
kateac1e3792017-04-01 02:16:39 -07008312 self.persistent_info["used_vlanIDs"][network_name] = vlan_id
8313 return vlan_id
sousaedu2ad85172021-02-17 15:05:18 +01008314
kateac1e3792017-04-01 02:16:39 -07008315 if vlan_id is None:
tierno72774862020-05-04 11:44:15 +00008316 raise vimconn.VimConnConflictException("All Vlan IDs are in use")
kateac1e3792017-04-01 02:16:39 -07008317
kateac1e3792017-04-01 02:16:39 -07008318 def get_obj(self, content, vimtype, name):
8319 """
sousaedu2ad85172021-02-17 15:05:18 +01008320 Get the vsphere object associated with a given text name
kateac1e3792017-04-01 02:16:39 -07008321 """
8322 obj = None
sousaedu2ad85172021-02-17 15:05:18 +01008323 container = content.viewManager.CreateContainerView(
8324 content.rootFolder, vimtype, True
8325 )
8326
kateac1e3792017-04-01 02:16:39 -07008327 for item in container.view:
8328 if item.name == name:
8329 obj = item
8330 break
sousaedu2ad85172021-02-17 15:05:18 +01008331
kateac1e3792017-04-01 02:16:39 -07008332 return obj
8333
kasar0c007d62017-05-19 03:13:57 -07008334 def insert_media_to_vm(self, vapp, image_id):
8335 """
8336 Method to insert media CD-ROM (ISO image) from catalog to vm.
8337 vapp - vapp object to get vm id
8338 Image_id - image id for cdrom to be inerted to vm
8339 """
8340 # create connection object
8341 vca = self.connect()
8342 try:
8343 # fetching catalog details
kasarc5bf2932018-03-09 04:15:22 -08008344 rest_url = "{}/api/catalog/{}".format(self.url, image_id)
sousaedu2ad85172021-02-17 15:05:18 +01008345
kasarc5bf2932018-03-09 04:15:22 -08008346 if vca._session:
sousaedu2ad85172021-02-17 15:05:18 +01008347 headers = {
8348 "Accept": "application/*+xml;version=" + API_VERSION,
8349 "x-vcloud-authorization": vca._session.headers[
8350 "x-vcloud-authorization"
8351 ],
8352 }
8353 response = self.perform_request(
8354 req_type="GET", url=rest_url, headers=headers
8355 )
kasar0c007d62017-05-19 03:13:57 -07008356
8357 if response.status_code != 200:
sousaedu2ad85172021-02-17 15:05:18 +01008358 self.logger.error(
8359 "REST call {} failed reason : {}"
8360 "status code : {}".format(
8361 rest_url, response.text, response.status_code
8362 )
8363 )
8364
8365 raise vimconn.VimConnException(
8366 "insert_media_to_vm(): Failed to get " "catalog details"
8367 )
8368
kasar0c007d62017-05-19 03:13:57 -07008369 # searching iso name and id
beierl26fec002019-12-06 17:06:40 -05008370 iso_name, media_id = self.get_media_details(vca, response.text)
kasar0c007d62017-05-19 03:13:57 -07008371
8372 if iso_name and media_id:
beierlb22ce2d2019-12-12 12:09:51 -05008373 data = """<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
kasar0c007d62017-05-19 03:13:57 -07008374 <ns6:MediaInsertOrEjectParams
beierl26fec002019-12-06 17:06:40 -05008375 xmlns="http://www.vmware.com/vcloud/versions" xmlns:ns2="http://schemas.dmtf.org/ovf/envelope/1"
8376 xmlns:ns3="http://schemas.dmtf.org/wbem/wscim/1/cim-schema/2/CIM_VirtualSystemSettingData"
8377 xmlns:ns4="http://schemas.dmtf.org/wbem/wscim/1/common"
8378 xmlns:ns5="http://schemas.dmtf.org/wbem/wscim/1/cim-schema/2/CIM_ResourceAllocationSettingData"
8379 xmlns:ns6="http://www.vmware.com/vcloud/v1.5"
8380 xmlns:ns7="http://www.vmware.com/schema/ovf"
8381 xmlns:ns8="http://schemas.dmtf.org/ovf/environment/1"
Ananda Baitharu319c26f2019-03-05 17:34:31 +00008382 xmlns:ns9="http://www.vmware.com/vcloud/extension/v1.5">
kasar0c007d62017-05-19 03:13:57 -07008383 <ns6:Media
8384 type="application/vnd.vmware.vcloud.media+xml"
Ananda Baitharu319c26f2019-03-05 17:34:31 +00008385 name="{}"
kasar0c007d62017-05-19 03:13:57 -07008386 id="urn:vcloud:media:{}"
8387 href="https://{}/api/media/{}"/>
sousaedu2ad85172021-02-17 15:05:18 +01008388 </ns6:MediaInsertOrEjectParams>""".format(
8389 iso_name, media_id, self.url, media_id
8390 )
kasar0c007d62017-05-19 03:13:57 -07008391
kasarc5bf2932018-03-09 04:15:22 -08008392 for vms in vapp.get_all_vms():
sousaedu2ad85172021-02-17 15:05:18 +01008393 vm_id = vms.get("id").split(":")[-1]
kasar0c007d62017-05-19 03:13:57 -07008394
sousaedu2ad85172021-02-17 15:05:18 +01008395 headers[
8396 "Content-Type"
8397 ] = "application/vnd.vmware.vcloud.mediaInsertOrEjectParams+xml"
8398 rest_url = "{}/api/vApp/vm-{}/media/action/insertMedia".format(
8399 self.url, vm_id
8400 )
kasar0c007d62017-05-19 03:13:57 -07008401
sousaedu2ad85172021-02-17 15:05:18 +01008402 response = self.perform_request(
8403 req_type="POST", url=rest_url, data=data, headers=headers
8404 )
kasar0c007d62017-05-19 03:13:57 -07008405
8406 if response.status_code != 202:
sousaedu2ad85172021-02-17 15:05:18 +01008407 error_msg = (
8408 "insert_media_to_vm() : Failed to insert CD-ROM to vm. Reason {}. "
8409 "Status code {}".format(response.text, response.status_code)
8410 )
Ananda Baitharu319c26f2019-03-05 17:34:31 +00008411 self.logger.error(error_msg)
sousaedu2ad85172021-02-17 15:05:18 +01008412
tierno72774862020-05-04 11:44:15 +00008413 raise vimconn.VimConnException(error_msg)
kasar0c007d62017-05-19 03:13:57 -07008414 else:
beierl26fec002019-12-06 17:06:40 -05008415 task = self.get_task_from_response(response.text)
sousaedu2ad85172021-02-17 15:05:18 +01008416 result = self.client.get_task_monitor().wait_for_success(
8417 task=task
8418 )
kasarc5bf2932018-03-09 04:15:22 -08008419
sousaedu2ad85172021-02-17 15:05:18 +01008420 if result.get("status") == "success":
8421 self.logger.info(
8422 "insert_media_to_vm(): Sucessfully inserted media ISO"
8423 " image to vm {}".format(vm_id)
8424 )
kasar0c007d62017-05-19 03:13:57 -07008425 except Exception as exp:
sousaedu2ad85172021-02-17 15:05:18 +01008426 self.logger.error(
8427 "insert_media_to_vm() : exception occurred "
8428 "while inserting media CD-ROM"
8429 )
8430
tierno72774862020-05-04 11:44:15 +00008431 raise vimconn.VimConnException(message=exp)
kasar0c007d62017-05-19 03:13:57 -07008432
kasar0c007d62017-05-19 03:13:57 -07008433 def get_media_details(self, vca, content):
8434 """
8435 Method to get catalog item details
8436 vca - connection object
8437 content - Catalog details
8438 Return - Media name, media id
8439 """
8440 cataloghref_list = []
8441 try:
8442 if content:
8443 vm_list_xmlroot = XmlElementTree.fromstring(content)
sousaedu2ad85172021-02-17 15:05:18 +01008444
kasar0c007d62017-05-19 03:13:57 -07008445 for child in vm_list_xmlroot.iter():
sousaedu2ad85172021-02-17 15:05:18 +01008446 if "CatalogItem" in child.tag:
8447 cataloghref_list.append(child.attrib.get("href"))
8448
kasar0c007d62017-05-19 03:13:57 -07008449 if cataloghref_list is not None:
8450 for href in cataloghref_list:
8451 if href:
sousaedu2ad85172021-02-17 15:05:18 +01008452 headers = {
8453 "Accept": "application/*+xml;version=" + API_VERSION,
8454 "x-vcloud-authorization": vca._session.headers[
8455 "x-vcloud-authorization"
8456 ],
8457 }
8458 response = self.perform_request(
8459 req_type="GET", url=href, headers=headers
8460 )
8461
kasar0c007d62017-05-19 03:13:57 -07008462 if response.status_code != 200:
sousaedu2ad85172021-02-17 15:05:18 +01008463 self.logger.error(
8464 "REST call {} failed reason : {}"
8465 "status code : {}".format(
8466 href, response.text, response.status_code
8467 )
8468 )
8469
8470 raise vimconn.VimConnException(
8471 "get_media_details : Failed to get "
8472 "catalogitem details"
8473 )
8474
beierl26fec002019-12-06 17:06:40 -05008475 list_xmlroot = XmlElementTree.fromstring(response.text)
sousaedu2ad85172021-02-17 15:05:18 +01008476
kasar0c007d62017-05-19 03:13:57 -07008477 for child in list_xmlroot.iter():
sousaedu2ad85172021-02-17 15:05:18 +01008478 if "Entity" in child.tag:
8479 if "media" in child.attrib.get("href"):
8480 name = child.attrib.get("name")
8481 media_id = (
8482 child.attrib.get("href").split("/").pop()
8483 )
8484
beierlb22ce2d2019-12-12 12:09:51 -05008485 return name, media_id
kasar0c007d62017-05-19 03:13:57 -07008486 else:
8487 self.logger.debug("Media name and id not found")
sousaedu2ad85172021-02-17 15:05:18 +01008488
beierlb22ce2d2019-12-12 12:09:51 -05008489 return False, False
kasar0c007d62017-05-19 03:13:57 -07008490 except Exception as exp:
sousaedu2ad85172021-02-17 15:05:18 +01008491 self.logger.error(
8492 "get_media_details : exception occurred " "getting media details"
8493 )
8494
tierno72774862020-05-04 11:44:15 +00008495 raise vimconn.VimConnException(message=exp)
kasar0c007d62017-05-19 03:13:57 -07008496
kated47ad5f2017-08-03 02:16:13 -07008497 def retry_rest(self, method, url, add_headers=None, data=None):
sousaedu2ad85172021-02-17 15:05:18 +01008498 """Method to get Token & retry respective REST request
8499 Args:
8500 api - REST API - Can be one of 'GET' or 'PUT' or 'POST'
8501 url - request url to be used
8502 add_headers - Additional headers (optional)
8503 data - Request payload data to be passed in request
8504 Returns:
8505 response - Response of request
bhangare1a0b97c2017-06-21 02:20:15 -07008506 """
8507 response = None
8508
beierlb22ce2d2019-12-12 12:09:51 -05008509 # Get token
bhangare1a0b97c2017-06-21 02:20:15 -07008510 self.get_token()
8511
kasarc5bf2932018-03-09 04:15:22 -08008512 if self.client._session:
sousaedu2ad85172021-02-17 15:05:18 +01008513 headers = {
8514 "Accept": "application/*+xml;version=" + API_VERSION,
8515 "x-vcloud-authorization": self.client._session.headers[
8516 "x-vcloud-authorization"
8517 ],
8518 }
bhangare1a0b97c2017-06-21 02:20:15 -07008519
8520 if add_headers:
8521 headers.update(add_headers)
8522
sousaedu2ad85172021-02-17 15:05:18 +01008523 if method == "GET":
8524 response = self.perform_request(req_type="GET", url=url, headers=headers)
8525 elif method == "PUT":
8526 response = self.perform_request(
8527 req_type="PUT", url=url, headers=headers, data=data
8528 )
8529 elif method == "POST":
8530 response = self.perform_request(
8531 req_type="POST", url=url, headers=headers, data=data
8532 )
8533 elif method == "DELETE":
8534 response = self.perform_request(req_type="DELETE", url=url, headers=headers)
8535
kated47ad5f2017-08-03 02:16:13 -07008536 return response
8537
bhangare1a0b97c2017-06-21 02:20:15 -07008538 def get_token(self):
sousaedu2ad85172021-02-17 15:05:18 +01008539 """Generate a new token if expired
bhangare1a0b97c2017-06-21 02:20:15 -07008540
sousaedu2ad85172021-02-17 15:05:18 +01008541 Returns:
8542 The return client object that letter can be used to connect to vCloud director as admin for VDC
bhangare1a0b97c2017-06-21 02:20:15 -07008543 """
beierl26fec002019-12-06 17:06:40 -05008544 self.client = self.connect()
bhangare1a0b97c2017-06-21 02:20:15 -07008545
8546 def get_vdc_details(self):
sousaedu2ad85172021-02-17 15:05:18 +01008547 """Get VDC details using pyVcloud Lib
bhangare1a0b97c2017-06-21 02:20:15 -07008548
sousaedu2ad85172021-02-17 15:05:18 +01008549 Returns org and vdc object
bhangare1a0b97c2017-06-21 02:20:15 -07008550 """
Ravi Chamartyb7ff3552018-10-30 19:51:23 +00008551 vdc = None
sousaedu2ad85172021-02-17 15:05:18 +01008552
Ravi Chamartyb7ff3552018-10-30 19:51:23 +00008553 try:
8554 org = Org(self.client, resource=self.client.get_org())
8555 vdc = org.get_vdc(self.tenant_name)
8556 except Exception as e:
8557 # pyvcloud not giving a specific exception, Refresh nevertheless
8558 self.logger.debug("Received exception {}, refreshing token ".format(str(e)))
bhangare1a0b97c2017-06-21 02:20:15 -07008559
beierlb22ce2d2019-12-12 12:09:51 -05008560 # Retry once, if failed by refreshing token
bhangare1a0b97c2017-06-21 02:20:15 -07008561 if vdc is None:
8562 self.get_token()
Ravi Chamartyb7ff3552018-10-30 19:51:23 +00008563 org = Org(self.client, resource=self.client.get_org())
kasarc5bf2932018-03-09 04:15:22 -08008564 vdc = org.get_vdc(self.tenant_name)
bhangare1a0b97c2017-06-21 02:20:15 -07008565
kasarc5bf2932018-03-09 04:15:22 -08008566 return org, vdc
8567
kasarc5bf2932018-03-09 04:15:22 -08008568 def perform_request(self, req_type, url, headers=None, data=None):
8569 """Perform the POST/PUT/GET/DELETE request."""
beierlb22ce2d2019-12-12 12:09:51 -05008570 # Log REST request details
kasarc5bf2932018-03-09 04:15:22 -08008571 self.log_request(req_type, url=url, headers=headers, data=data)
8572 # perform request and return its result
sousaedu2ad85172021-02-17 15:05:18 +01008573
8574 if req_type == "GET":
8575 response = requests.get(url=url, headers=headers, verify=False)
8576 elif req_type == "PUT":
8577 response = requests.put(url=url, headers=headers, data=data, verify=False)
8578 elif req_type == "POST":
8579 response = requests.post(url=url, headers=headers, data=data, verify=False)
8580 elif req_type == "DELETE":
8581 response = requests.delete(url=url, headers=headers, verify=False)
8582
beierlb22ce2d2019-12-12 12:09:51 -05008583 # Log the REST response
kasarc5bf2932018-03-09 04:15:22 -08008584 self.log_response(response)
8585
8586 return response
8587
kasarc5bf2932018-03-09 04:15:22 -08008588 def log_request(self, req_type, url=None, headers=None, data=None):
8589 """Logs REST request details"""
8590
8591 if req_type is not None:
8592 self.logger.debug("Request type: {}".format(req_type))
8593
8594 if url is not None:
8595 self.logger.debug("Request url: {}".format(url))
8596
8597 if headers is not None:
8598 for header in headers:
sousaedu2ad85172021-02-17 15:05:18 +01008599 self.logger.debug(
8600 "Request header: {}: {}".format(header, headers[header])
8601 )
kasarc5bf2932018-03-09 04:15:22 -08008602
8603 if data is not None:
8604 self.logger.debug("Request data: {}".format(data))
8605
kasarc5bf2932018-03-09 04:15:22 -08008606 def log_response(self, response):
8607 """Logs REST response details"""
8608
8609 self.logger.debug("Response status code: {} ".format(response.status_code))
8610
kasarc5bf2932018-03-09 04:15:22 -08008611 def get_task_from_response(self, content):
8612 """
beierl26fec002019-12-06 17:06:40 -05008613 content - API response.text(response.text)
sbhangarea8e5b782018-06-21 02:10:03 -07008614 return task object
kasarc5bf2932018-03-09 04:15:22 -08008615 """
8616 xmlroot = XmlElementTree.fromstring(content)
sousaedu2ad85172021-02-17 15:05:18 +01008617
8618 if xmlroot.tag.split("}")[1] == "Task":
kasarc5bf2932018-03-09 04:15:22 -08008619 return xmlroot
sbhangarea8e5b782018-06-21 02:10:03 -07008620 else:
kasarc5bf2932018-03-09 04:15:22 -08008621 for ele in xmlroot:
8622 if ele.tag.split("}")[1] == "Tasks":
8623 task = ele[0]
sbhangarea8e5b782018-06-21 02:10:03 -07008624 break
sousaedu2ad85172021-02-17 15:05:18 +01008625
kasarc5bf2932018-03-09 04:15:22 -08008626 return task
8627
beierlb22ce2d2019-12-12 12:09:51 -05008628 def power_on_vapp(self, vapp_id, vapp_name):
kasarc5bf2932018-03-09 04:15:22 -08008629 """
8630 vapp_id - vApp uuid
8631 vapp_name - vAapp name
sbhangarea8e5b782018-06-21 02:10:03 -07008632 return - Task object
kasarc5bf2932018-03-09 04:15:22 -08008633 """
sousaedu2ad85172021-02-17 15:05:18 +01008634 headers = {
8635 "Accept": "application/*+xml;version=" + API_VERSION,
8636 "x-vcloud-authorization": self.client._session.headers[
8637 "x-vcloud-authorization"
8638 ],
8639 }
sbhangarea8e5b782018-06-21 02:10:03 -07008640
sousaedu2ad85172021-02-17 15:05:18 +01008641 poweron_href = "{}/api/vApp/vapp-{}/power/action/powerOn".format(
8642 self.url, vapp_id
8643 )
8644 response = self.perform_request(
8645 req_type="POST", url=poweron_href, headers=headers
8646 )
kasarc5bf2932018-03-09 04:15:22 -08008647
8648 if response.status_code != 202:
sousaedu2ad85172021-02-17 15:05:18 +01008649 self.logger.error(
8650 "REST call {} failed reason : {}"
8651 "status code : {} ".format(
8652 poweron_href, response.text, response.status_code
8653 )
8654 )
8655
8656 raise vimconn.VimConnException(
8657 "power_on_vapp() : Failed to power on " "vApp {}".format(vapp_name)
8658 )
kasarc5bf2932018-03-09 04:15:22 -08008659 else:
beierl26fec002019-12-06 17:06:40 -05008660 poweron_task = self.get_task_from_response(response.text)
sousaedu2ad85172021-02-17 15:05:18 +01008661
kasarc5bf2932018-03-09 04:15:22 -08008662 return poweron_task