blob: cd5a47bc8fad4f09c916050b936fd87cec40da02 [file] [log] [blame]
bayramov325fa1c2016-09-08 01:42:46 -07001# -*- coding: utf-8 -*-
2
3##
4# Copyright 2015 Telefónica Investigación y Desarrollo, S.A.U.
5# This file is part of openmano
6# All Rights Reserved.
7#
8# Licensed under the Apache License, Version 2.0 (the "License"); you may
9# not use this file except in compliance with the License. You may obtain
10# a copy of the License at
11#
12# http://www.apache.org/licenses/LICENSE-2.0
13#
14# Unless required by applicable law or agreed to in writing, software
15# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
16# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
17# License for the specific language governing permissions and limitations
18# under the License.
19#
20# For those usages not covered by the Apache License, Version 2.0 please
21# contact with: nfvlabs@tid.es
22##
23
bayramov5761ad12016-10-04 09:00:30 +040024"""
bayramov325fa1c2016-09-08 01:42:46 -070025vimconn_vmware implementation an Abstract class in order to interact with VMware vCloud Director.
26mbayramov@vmware.com
bayramov5761ad12016-10-04 09:00:30 +040027"""
bayramovfe3f3c92016-10-04 07:53:41 +040028from progressbar import Percentage, Bar, ETA, FileTransferSpeed, ProgressBar
bayramovbd6160f2016-09-28 04:12:05 +040029
30import vimconn
bayramov325fa1c2016-09-08 01:42:46 -070031import os
bayramovef390722016-09-27 03:34:46 -070032import traceback
bayramovef390722016-09-27 03:34:46 -070033import itertools
bayramov325fa1c2016-09-08 01:42:46 -070034import requests
35
bayramovef390722016-09-27 03:34:46 -070036from xml.etree import ElementTree as XmlElementTree
bayramov325fa1c2016-09-08 01:42:46 -070037
bayramovef390722016-09-27 03:34:46 -070038import yaml
bayramov325fa1c2016-09-08 01:42:46 -070039from pyvcloud import Http
40from pyvcloud.vcloudair import VCA
41from pyvcloud.schema.vcd.v1_5.schemas.vcloud import sessionType, organizationType, \
42 vAppType, organizationListType, vdcType, catalogType, queryRecordViewType, \
43 networkType, vcloudType, taskType, diskType, vmsType, vdcTemplateListType, mediaType
44from xml.sax.saxutils import escape
45
bayramovef390722016-09-27 03:34:46 -070046from pyvcloud.schema.vcd.v1_5.schemas.admin.vCloudEntities import TaskType
47from pyvcloud.schema.vcd.v1_5.schemas.vcloud.taskType import TaskType as GenericTask
48from pyvcloud.schema.vcd.v1_5.schemas.vcloud.vAppType import TaskType as VappTask
49from pyvcloud.schema.vcd.v1_5.schemas.admin.vCloudEntities import TasksInProgressType
50
bayramov325fa1c2016-09-08 01:42:46 -070051import logging
52import json
bayramov325fa1c2016-09-08 01:42:46 -070053import time
54import uuid
55import httplib
kate15f1c382016-12-15 01:12:40 -080056import hashlib
bhangare0e571a92017-01-12 04:02:23 -080057import socket
58import struct
59import netaddr
bayramov325fa1c2016-09-08 01:42:46 -070060
bayramovbd6160f2016-09-28 04:12:05 +040061# global variable for vcd connector type
62STANDALONE = 'standalone'
63
kate15f1c382016-12-15 01:12:40 -080064# key for flavor dicts
65FLAVOR_RAM_KEY = 'ram'
66FLAVOR_VCPUS_KEY = 'vcpus'
67
bhangare0e571a92017-01-12 04:02:23 -080068DEFAULT_IP_PROFILE = {'gateway_address':"192.168.1.1",
69 'dhcp_count':50,
70 'subnet_address':"192.168.1.0/24",
71 'dhcp_enabled':True,
72 'dhcp_start_address':"192.168.1.3",
73 'ip_version':"IPv4",
74 'dns_address':"192.168.1.2"
75 }
76# global variable for wait time
kate13ab2c42016-12-23 01:34:24 -080077INTERVAL_TIME = 5
78MAX_WAIT_TIME = 1800
bayramov325fa1c2016-09-08 01:42:46 -070079
bayramovbd6160f2016-09-28 04:12:05 +040080VCAVERSION = '5.9'
81
bhangare0e571a92017-01-12 04:02:23 -080082__author__ = "Mustafa Bayramov, Arpita Kate, Sachin Bhangare"
katec324e002016-12-23 00:54:47 -080083__date__ = "$23-Dec-2016 11:09:29$"
bayramovfe3f3c92016-10-04 07:53:41 +040084__version__ = '0.1'
bayramov325fa1c2016-09-08 01:42:46 -070085
bayramovef390722016-09-27 03:34:46 -070086# -1: "Could not be created",
87# 0: "Unresolved",
88# 1: "Resolved",
89# 2: "Deployed",
90# 3: "Suspended",
91# 4: "Powered on",
92# 5: "Waiting for user input",
93# 6: "Unknown state",
94# 7: "Unrecognized state",
95# 8: "Powered off",
96# 9: "Inconsistent state",
97# 10: "Children do not all have the same status",
98# 11: "Upload initiated, OVF descriptor pending",
99# 12: "Upload initiated, copying contents",
100# 13: "Upload initiated , disk contents pending",
101# 14: "Upload has been quarantined",
102# 15: "Upload quarantine period has expired"
103
104# mapping vCD status to MANO
105vcdStatusCode2manoFormat = {4: 'ACTIVE',
106 7: 'PAUSED',
107 3: 'SUSPENDED',
108 8: 'INACTIVE',
109 12: 'BUILD',
110 -1: 'ERROR',
111 14: 'DELETED'}
112
113#
114netStatus2manoFormat = {'ACTIVE': 'ACTIVE', 'PAUSED': 'PAUSED', 'INACTIVE': 'INACTIVE', 'BUILD': 'BUILD',
115 'ERROR': 'ERROR', 'DELETED': 'DELETED'
116 }
117
bayramovbd6160f2016-09-28 04:12:05 +0400118# dict used to store flavor in memory
bayramov325fa1c2016-09-08 01:42:46 -0700119flavorlist = {}
120
bayramovef390722016-09-27 03:34:46 -0700121
bayramovbd6160f2016-09-28 04:12:05 +0400122class vimconnector(vimconn.vimconnector):
123 def __init__(self, uuid=None, name=None, tenant_id=None, tenant_name=None,
tiernofe789902016-09-29 14:20:44 +0000124 url=None, url_admin=None, user=None, passwd=None, log_level=None, config={}):
bayramovb6ffe792016-09-28 11:50:56 +0400125 """
126 Constructor create vmware connector to vCloud director.
127
128 By default construct doesn't validate connection state. So client can create object with None arguments.
129 If client specified username , password and host and VDC name. Connector initialize other missing attributes.
130
131 a) It initialize organization UUID
132 b) Initialize tenant_id/vdc ID. (This information derived from tenant name)
133
134 Args:
135 uuid - is organization uuid.
136 name - is organization name that must be presented in vCloud director.
137 tenant_id - is VDC uuid it must be presented in vCloud director
138 tenant_name - is VDC name.
139 url - is hostname or ip address of vCloud director
140 url_admin - same as above.
141 user - is user that administrator for organization. Caller must make sure that
142 username has right privileges.
143
144 password - is password for a user.
145
146 VMware connector also requires PVDC administrative privileges and separate account.
147 This variables must be passed via config argument dict contains keys
148
149 dict['admin_username']
150 dict['admin_password']
151
152 Returns:
153 Nothing.
154 """
155
bayramovbd6160f2016-09-28 04:12:05 +0400156 vimconn.vimconnector.__init__(self, uuid, name, tenant_id, tenant_name, url,
157 url_admin, user, passwd, log_level, config)
kate15f1c382016-12-15 01:12:40 -0800158
159 self.logger = logging.getLogger('openmano.vim.vmware')
160 self.logger.setLevel(10)
161
bayramovef390722016-09-27 03:34:46 -0700162 self.name = name
kate15f1c382016-12-15 01:12:40 -0800163 self.id = uuid
bayramovef390722016-09-27 03:34:46 -0700164 self.url = url
bayramov325fa1c2016-09-08 01:42:46 -0700165 self.url_admin = url_admin
166 self.tenant_id = tenant_id
167 self.tenant_name = tenant_name
bayramovef390722016-09-27 03:34:46 -0700168 self.user = user
169 self.passwd = passwd
170 self.config = config
171 self.admin_password = None
172 self.admin_user = None
kate15f1c382016-12-15 01:12:40 -0800173 self.org_name = ""
bayramovef390722016-09-27 03:34:46 -0700174
kate15f1c382016-12-15 01:12:40 -0800175 if tenant_name is not None:
176 orgnameandtenant = tenant_name.split(":")
177 if len(orgnameandtenant) == 2:
katec324e002016-12-23 00:54:47 -0800178 self.tenant_name = orgnameandtenant[1]
179 self.org_name = orgnameandtenant[0]
kate15f1c382016-12-15 01:12:40 -0800180 else:
181 self.tenant_name = tenant_name
182 elif "orgname" in config:
183 self.org_name = config['orgname']
katec324e002016-12-23 00:54:47 -0800184
tiernofe789902016-09-29 14:20:44 +0000185 if log_level:
bayramov5761ad12016-10-04 09:00:30 +0400186 self.logger.setLevel(getattr(logging, log_level))
bayramov325fa1c2016-09-08 01:42:46 -0700187
bayramovef390722016-09-27 03:34:46 -0700188 try:
189 self.admin_user = config['admin_username']
190 self.admin_password = config['admin_password']
191 except KeyError:
bayramovbd6160f2016-09-28 04:12:05 +0400192 raise vimconn.vimconnException(message="Error admin username or admin password is empty.")
bayramov325fa1c2016-09-08 01:42:46 -0700193
bayramovef390722016-09-27 03:34:46 -0700194 self.org_uuid = None
195 self.vca = None
bayramov325fa1c2016-09-08 01:42:46 -0700196
197 if not url:
bayramov5761ad12016-10-04 09:00:30 +0400198 raise vimconn.vimconnException('url param can not be NoneType')
bayramov325fa1c2016-09-08 01:42:46 -0700199
bayramovef390722016-09-27 03:34:46 -0700200 if not self.url_admin: # try to use normal url
bayramov325fa1c2016-09-08 01:42:46 -0700201 self.url_admin = self.url
202
kate15f1c382016-12-15 01:12:40 -0800203 logging.debug("UUID: {} name: {} tenant_id: {} tenant name {}".format(self.id, self.org_name,
bayramovef390722016-09-27 03:34:46 -0700204 self.tenant_id, self.tenant_name))
205 logging.debug("vcd url {} vcd username: {} vcd password: {}".format(self.url, self.user, self.passwd))
206 logging.debug("vcd admin username {} vcd admin passowrd {}".format(self.admin_user, self.admin_password))
bayramov325fa1c2016-09-08 01:42:46 -0700207
bayramovef390722016-09-27 03:34:46 -0700208 # initialize organization
bayramovbd6160f2016-09-28 04:12:05 +0400209 if self.user is not None and self.passwd is not None and self.url:
210 self.init_organization()
bayramovef390722016-09-27 03:34:46 -0700211
212 def __getitem__(self, index):
kate15f1c382016-12-15 01:12:40 -0800213 if index == 'name':
214 return self.name
bayramovef390722016-09-27 03:34:46 -0700215 if index == 'tenant_id':
bayramov325fa1c2016-09-08 01:42:46 -0700216 return self.tenant_id
bayramovef390722016-09-27 03:34:46 -0700217 if index == 'tenant_name':
bayramov325fa1c2016-09-08 01:42:46 -0700218 return self.tenant_name
bayramovef390722016-09-27 03:34:46 -0700219 elif index == 'id':
bayramov325fa1c2016-09-08 01:42:46 -0700220 return self.id
bayramovef390722016-09-27 03:34:46 -0700221 elif index == 'org_name':
222 return self.org_name
223 elif index == 'org_uuid':
224 return self.org_uuid
225 elif index == 'user':
bayramov325fa1c2016-09-08 01:42:46 -0700226 return self.user
bayramovef390722016-09-27 03:34:46 -0700227 elif index == 'passwd':
bayramov325fa1c2016-09-08 01:42:46 -0700228 return self.passwd
bayramovef390722016-09-27 03:34:46 -0700229 elif index == 'url':
bayramov325fa1c2016-09-08 01:42:46 -0700230 return self.url
bayramovef390722016-09-27 03:34:46 -0700231 elif index == 'url_admin':
bayramov325fa1c2016-09-08 01:42:46 -0700232 return self.url_admin
bayramovef390722016-09-27 03:34:46 -0700233 elif index == "config":
bayramov325fa1c2016-09-08 01:42:46 -0700234 return self.config
235 else:
bayramovef390722016-09-27 03:34:46 -0700236 raise KeyError("Invalid key '%s'" % str(index))
bayramov325fa1c2016-09-08 01:42:46 -0700237
bayramovef390722016-09-27 03:34:46 -0700238 def __setitem__(self, index, value):
kate15f1c382016-12-15 01:12:40 -0800239 if index == 'name':
240 self.name = value
bayramovef390722016-09-27 03:34:46 -0700241 if index == 'tenant_id':
bayramov325fa1c2016-09-08 01:42:46 -0700242 self.tenant_id = value
bayramovef390722016-09-27 03:34:46 -0700243 if index == 'tenant_name':
bayramov325fa1c2016-09-08 01:42:46 -0700244 self.tenant_name = value
bayramovef390722016-09-27 03:34:46 -0700245 elif index == 'id':
bayramov325fa1c2016-09-08 01:42:46 -0700246 self.id = value
bayramovef390722016-09-27 03:34:46 -0700247 elif index == 'org_name':
248 self.org_name = value
bayramovef390722016-09-27 03:34:46 -0700249 elif index == 'org_uuid':
kate15f1c382016-12-15 01:12:40 -0800250 self.org_uuid = value
bayramovef390722016-09-27 03:34:46 -0700251 elif index == 'user':
bayramov325fa1c2016-09-08 01:42:46 -0700252 self.user = value
bayramovef390722016-09-27 03:34:46 -0700253 elif index == 'passwd':
bayramov325fa1c2016-09-08 01:42:46 -0700254 self.passwd = value
bayramovef390722016-09-27 03:34:46 -0700255 elif index == 'url':
bayramov325fa1c2016-09-08 01:42:46 -0700256 self.url = value
bayramovef390722016-09-27 03:34:46 -0700257 elif index == 'url_admin':
bayramov325fa1c2016-09-08 01:42:46 -0700258 self.url_admin = value
259 else:
bayramovef390722016-09-27 03:34:46 -0700260 raise KeyError("Invalid key '%s'" % str(index))
bayramov325fa1c2016-09-08 01:42:46 -0700261
bayramovef390722016-09-27 03:34:46 -0700262 def connect_as_admin(self):
bayramovb6ffe792016-09-28 11:50:56 +0400263 """ Method connect as pvdc admin user to vCloud director.
264 There are certain action that can be done only by provider vdc admin user.
265 Organization creation / provider network creation etc.
bayramovef390722016-09-27 03:34:46 -0700266
267 Returns:
268 The return vca object that letter can be used to connect to vcloud direct as admin for provider vdc
269 """
270
kate15f1c382016-12-15 01:12:40 -0800271 self.logger.debug("Logging in to a vca {} as admin.".format(self.org_name))
bayramov325fa1c2016-09-08 01:42:46 -0700272
bayramovef390722016-09-27 03:34:46 -0700273 vca_admin = VCA(host=self.url,
274 username=self.admin_user,
bayramovbd6160f2016-09-28 04:12:05 +0400275 service_type=STANDALONE,
276 version=VCAVERSION,
bayramovef390722016-09-27 03:34:46 -0700277 verify=False,
278 log=False)
279 result = vca_admin.login(password=self.admin_password, org='System')
280 if not result:
bayramovbd6160f2016-09-28 04:12:05 +0400281 raise vimconn.vimconnConnectionException(
282 "Can't connect to a vCloud director as: {}".format(self.admin_user))
bayramovef390722016-09-27 03:34:46 -0700283 result = vca_admin.login(token=vca_admin.token, org='System', org_url=vca_admin.vcloud_session.org_url)
284 if result is True:
285 self.logger.info(
286 "Successfully logged to a vcloud direct org: {} as user: {}".format('System', self.admin_user))
bayramov325fa1c2016-09-08 01:42:46 -0700287
bayramovef390722016-09-27 03:34:46 -0700288 return vca_admin
bayramov325fa1c2016-09-08 01:42:46 -0700289
bayramovef390722016-09-27 03:34:46 -0700290 def connect(self):
291 """ Method connect as normal user to vCloud director.
292
293 Returns:
294 The return vca object that letter can be used to connect to vCloud director as admin for VDC
295 """
296
bayramovb6ffe792016-09-28 11:50:56 +0400297 try:
kate15f1c382016-12-15 01:12:40 -0800298 self.logger.debug("Logging in to a vca {} as {} to datacenter {}.".format(self.org_name,
299 self.user,
300 self.org_name))
bayramovb6ffe792016-09-28 11:50:56 +0400301 vca = VCA(host=self.url,
302 username=self.user,
303 service_type=STANDALONE,
304 version=VCAVERSION,
305 verify=False,
306 log=False)
bayramovef390722016-09-27 03:34:46 -0700307
kate15f1c382016-12-15 01:12:40 -0800308 result = vca.login(password=self.passwd, org=self.org_name)
bayramovb6ffe792016-09-28 11:50:56 +0400309 if not result:
310 raise vimconn.vimconnConnectionException("Can't connect to a vCloud director as: {}".format(self.user))
kate15f1c382016-12-15 01:12:40 -0800311 result = vca.login(token=vca.token, org=self.org_name, org_url=vca.vcloud_session.org_url)
bayramovb6ffe792016-09-28 11:50:56 +0400312 if result is True:
bayramovfe3f3c92016-10-04 07:53:41 +0400313 self.logger.info(
kate15f1c382016-12-15 01:12:40 -0800314 "Successfully logged to a vcloud direct org: {} as user: {}".format(self.org_name, self.user))
bayramovb6ffe792016-09-28 11:50:56 +0400315
316 except:
kate15f1c382016-12-15 01:12:40 -0800317 raise vimconn.vimconnConnectionException("Can't connect to a vCloud director org: "
318 "{} as user: {}".format(self.org_name, self.user))
bayramov325fa1c2016-09-08 01:42:46 -0700319
320 return vca
321
bayramovbd6160f2016-09-28 04:12:05 +0400322 def init_organization(self):
323 """ Method initialize organization UUID and VDC parameters.
324
325 At bare minimum client must provide organization name that present in vCloud director and VDC.
326
327 The VDC - UUID ( tenant_id) will be initialized at the run time if client didn't call constructor.
328 The Org - UUID will be initialized at the run time if data center present in vCloud director.
bayramov325fa1c2016-09-08 01:42:46 -0700329
bayramovef390722016-09-27 03:34:46 -0700330 Returns:
331 The return vca object that letter can be used to connect to vcloud direct as admin
332 """
333 try:
334 if self.org_uuid is None:
335 org_dict = self.get_org_list()
336 for org in org_dict:
bayramovbd6160f2016-09-28 04:12:05 +0400337 # we set org UUID at the init phase but we can do it only when we have valid credential.
bayramovef390722016-09-27 03:34:46 -0700338 if org_dict[org] == self.org_name:
339 self.org_uuid = org
bayramovbd6160f2016-09-28 04:12:05 +0400340 self.logger.debug("Setting organization UUID {}".format(self.org_uuid))
341 break
bayramovbd6160f2016-09-28 04:12:05 +0400342 else:
343 raise vimconn.vimconnException("Vcloud director organization {} not found".format(self.org_name))
344
345 # if well good we require for org details
346 org_details_dict = self.get_org(org_uuid=self.org_uuid)
347
348 # we have two case if we want to initialize VDC ID or VDC name at run time
349 # tenant_name provided but no tenant id
bayramov5761ad12016-10-04 09:00:30 +0400350 if self.tenant_id is None and self.tenant_name is not None and 'vdcs' in org_details_dict:
bayramovbd6160f2016-09-28 04:12:05 +0400351 vdcs_dict = org_details_dict['vdcs']
bayramovbd6160f2016-09-28 04:12:05 +0400352 for vdc in vdcs_dict:
353 if vdcs_dict[vdc] == self.tenant_name:
354 self.tenant_id = vdc
355 self.logger.debug("Setting vdc uuid {} for organization UUID {}".format(self.tenant_id,
kate15f1c382016-12-15 01:12:40 -0800356 self.org_name))
bayramovbd6160f2016-09-28 04:12:05 +0400357 break
358 else:
359 raise vimconn.vimconnException("Tenant name indicated but not present in vcloud director.")
360 # case two we have tenant_id but we don't have tenant name so we find and set it.
bayramov5761ad12016-10-04 09:00:30 +0400361 if self.tenant_id is not None and self.tenant_name is None and 'vdcs' in org_details_dict:
bayramovbd6160f2016-09-28 04:12:05 +0400362 vdcs_dict = org_details_dict['vdcs']
363 for vdc in vdcs_dict:
364 if vdc == self.tenant_id:
365 self.tenant_name = vdcs_dict[vdc]
366 self.logger.debug("Setting vdc uuid {} for organization UUID {}".format(self.tenant_id,
kate15f1c382016-12-15 01:12:40 -0800367 self.org_name))
bayramovbd6160f2016-09-28 04:12:05 +0400368 break
369 else:
370 raise vimconn.vimconnException("Tenant id indicated but not present in vcloud director")
bayramovef390722016-09-27 03:34:46 -0700371 self.logger.debug("Setting organization uuid {}".format(self.org_uuid))
372 except:
373 self.logger.debug("Failed initialize organization UUID for org {}".format(self.org_name))
374 self.logger.debug(traceback.format_exc())
375 self.org_uuid = None
bayramov325fa1c2016-09-08 01:42:46 -0700376
bayramovef390722016-09-27 03:34:46 -0700377 def new_tenant(self, tenant_name=None, tenant_description=None):
bayramovb6ffe792016-09-28 11:50:56 +0400378 """ Method adds a new tenant to VIM with this name.
379 This action requires access to create VDC action in vCloud director.
bayramovef390722016-09-27 03:34:46 -0700380
bayramovb6ffe792016-09-28 11:50:56 +0400381 Args:
382 tenant_name is tenant_name to be created.
383 tenant_description not used for this call
384
385 Return:
386 returns the tenant identifier in UUID format.
387 If action is failed method will throw vimconn.vimconnException method
bayramovbd6160f2016-09-28 04:12:05 +0400388 """
bayramovef390722016-09-27 03:34:46 -0700389 vdc_task = self.create_vdc(vdc_name=tenant_name)
390 if vdc_task is not None:
391 vdc_uuid, value = vdc_task.popitem()
392 self.logger.info("Crated new vdc {} and uuid: {}".format(tenant_name, vdc_uuid))
393 return vdc_uuid
394 else:
bayramovbd6160f2016-09-28 04:12:05 +0400395 raise vimconn.vimconnException("Failed create tenant {}".format(tenant_name))
bayramovef390722016-09-27 03:34:46 -0700396
bayramov163f1ae2016-09-28 17:16:55 +0400397 def delete_tenant(self, tenant_id=None):
bayramovef390722016-09-27 03:34:46 -0700398 """Delete a tenant from VIM"""
399 'Returns the tenant identifier'
bayramovbd6160f2016-09-28 04:12:05 +0400400 raise vimconn.vimconnNotImplemented("Should have implemented this")
bayramov325fa1c2016-09-08 01:42:46 -0700401
402 def get_tenant_list(self, filter_dict={}):
bayramovb6ffe792016-09-28 11:50:56 +0400403 """Obtain tenants of VIM
bayramov325fa1c2016-09-08 01:42:46 -0700404 filter_dict can contain the following keys:
405 name: filter by tenant name
406 id: filter by tenant uuid/id
407 <other VIM specific>
bayramovb6ffe792016-09-28 11:50:56 +0400408 Returns the tenant list of dictionaries:
bayramov325fa1c2016-09-08 01:42:46 -0700409 [{'name':'<name>, 'id':'<id>, ...}, ...]
bayramov325fa1c2016-09-08 01:42:46 -0700410
bayramovb6ffe792016-09-28 11:50:56 +0400411 """
bayramovef390722016-09-27 03:34:46 -0700412 org_dict = self.get_org(self.org_uuid)
413 vdcs_dict = org_dict['vdcs']
414
415 vdclist = []
416 try:
417 for k in vdcs_dict:
418 entry = {'name': vdcs_dict[k], 'id': k}
bayramovb6ffe792016-09-28 11:50:56 +0400419 # if caller didn't specify dictionary we return all tenants.
420 if filter_dict is not None and filter_dict:
421 filtered_entry = entry.copy()
422 filtered_dict = set(entry.keys()) - set(filter_dict)
423 for unwanted_key in filtered_dict: del entry[unwanted_key]
424 if filter_dict == entry:
425 vdclist.append(filtered_entry)
426 else:
427 vdclist.append(entry)
bayramovef390722016-09-27 03:34:46 -0700428 except:
429 self.logger.debug("Error in get_tenant_list()")
430 self.logger.debug(traceback.format_exc())
bayramovb6ffe792016-09-28 11:50:56 +0400431 raise vimconn.vimconnException("Incorrect state. {}")
bayramovef390722016-09-27 03:34:46 -0700432
433 return vdclist
434
435 def new_network(self, net_name, net_type, ip_profile=None, shared=False):
bayramovb6ffe792016-09-28 11:50:56 +0400436 """Adds a tenant network to VIM
bayramov325fa1c2016-09-08 01:42:46 -0700437 net_name is the name
bhangare0e571a92017-01-12 04:02:23 -0800438 net_type can be 'bridge','data'.'ptp'.
bayramovb6ffe792016-09-28 11:50:56 +0400439 ip_profile is a dict containing the IP parameters of the network
bayramov325fa1c2016-09-08 01:42:46 -0700440 shared is a boolean
bayramovb6ffe792016-09-28 11:50:56 +0400441 Returns the network identifier"""
bayramov325fa1c2016-09-08 01:42:46 -0700442
bhangare0e571a92017-01-12 04:02:23 -0800443 self.logger.debug("new_network tenant {} net_type {} ip_profile {} shared {}"
444 .format(net_name, net_type, ip_profile, shared))
bayramov325fa1c2016-09-08 01:42:46 -0700445
bayramovef390722016-09-27 03:34:46 -0700446 isshared = 'false'
447 if shared:
448 isshared = 'true'
449
bhangare0e571a92017-01-12 04:02:23 -0800450 network_uuid = self.create_network(network_name=net_name, net_type=net_type,
451 ip_profile=ip_profile, isshared=isshared)
bayramovef390722016-09-27 03:34:46 -0700452 if network_uuid is not None:
453 return network_uuid
454 else:
bayramovbd6160f2016-09-28 04:12:05 +0400455 raise vimconn.vimconnUnexpectedResponse("Failed create a new network {}".format(net_name))
bayramovef390722016-09-27 03:34:46 -0700456
457 def get_vcd_network_list(self):
458 """ Method available organization for a logged in tenant
459
460 Returns:
461 The return vca object that letter can be used to connect to vcloud direct as admin
462 """
463
kate15f1c382016-12-15 01:12:40 -0800464 self.logger.debug("get_vcd_network_list(): retrieving network list for vcd {}".format(self.tenant_name))
bayramovef390722016-09-27 03:34:46 -0700465 vca = self.connect()
466 if not vca:
467 raise vimconn.vimconnConnectionException("self.connect() is failed.")
468
kate15f1c382016-12-15 01:12:40 -0800469 if not self.tenant_name:
470 raise vimconn.vimconnConnectionException("Tenant name is empty.")
471
bayramovef390722016-09-27 03:34:46 -0700472 vdc = vca.get_vdc(self.tenant_name)
kate15f1c382016-12-15 01:12:40 -0800473 if vdc is None:
474 raise vimconn.vimconnConnectionException("Can't retrieve information for a VDC {}".format(self.tenant_name))
475
bayramovef390722016-09-27 03:34:46 -0700476 vdc_uuid = vdc.get_id().split(":")[3]
477 networks = vca.get_networks(vdc.get_name())
478 network_list = []
479 try:
480 for network in networks:
481 filter_dict = {}
482 netid = network.get_id().split(":")
483 if len(netid) != 4:
484 continue
485
486 filter_dict["name"] = network.get_name()
487 filter_dict["id"] = netid[3]
488 filter_dict["shared"] = network.get_IsShared()
489 filter_dict["tenant_id"] = vdc_uuid
490 if network.get_status() == 1:
491 filter_dict["admin_state_up"] = True
492 else:
493 filter_dict["admin_state_up"] = False
494 filter_dict["status"] = "ACTIVE"
495 filter_dict["type"] = "bridge"
496 network_list.append(filter_dict)
497 self.logger.debug("get_vcd_network_list adding entry {}".format(filter_dict))
498 except:
499 self.logger.debug("Error in get_vcd_network_list")
500 self.logger.debug(traceback.format_exc())
501 pass
502
503 self.logger.debug("get_vcd_network_list returning {}".format(network_list))
504 return network_list
bayramov325fa1c2016-09-08 01:42:46 -0700505
506 def get_network_list(self, filter_dict={}):
bayramovb6ffe792016-09-28 11:50:56 +0400507 """Obtain tenant networks of VIM
bayramov325fa1c2016-09-08 01:42:46 -0700508 Filter_dict can be:
bayramovef390722016-09-27 03:34:46 -0700509 name: network name OR/AND
510 id: network uuid OR/AND
511 shared: boolean OR/AND
512 tenant_id: tenant OR/AND
bayramov325fa1c2016-09-08 01:42:46 -0700513 admin_state_up: boolean
514 status: 'ACTIVE'
bayramovef390722016-09-27 03:34:46 -0700515
516 [{key : value , key : value}]
517
bayramov325fa1c2016-09-08 01:42:46 -0700518 Returns the network list of dictionaries:
519 [{<the fields at Filter_dict plus some VIM specific>}, ...]
520 List can be empty
bayramovb6ffe792016-09-28 11:50:56 +0400521 """
bayramov325fa1c2016-09-08 01:42:46 -0700522
kate15f1c382016-12-15 01:12:40 -0800523 self.logger.debug("get_vcd_network_list(): retrieving network list for vcd {}".format(self.tenant_name))
bayramov325fa1c2016-09-08 01:42:46 -0700524 vca = self.connect()
525 if not vca:
kate15f1c382016-12-15 01:12:40 -0800526 raise vimconn.vimconnConnectionException("self.connect() is failed.")
527
528 if not self.tenant_name:
529 raise vimconn.vimconnConnectionException("Tenant name is empty.")
bayramov325fa1c2016-09-08 01:42:46 -0700530
531 vdc = vca.get_vdc(self.tenant_name)
kate15f1c382016-12-15 01:12:40 -0800532 if vdc is None:
533 raise vimconn.vimconnConnectionException("Can't retrieve information for a VDC {}.".format(self.tenant_name))
bayramov325fa1c2016-09-08 01:42:46 -0700534
kate15f1c382016-12-15 01:12:40 -0800535 vdcid = vdc.get_id().split(":")[3]
bayramov325fa1c2016-09-08 01:42:46 -0700536 networks = vca.get_networks(vdc.get_name())
537 network_list = []
bayramov325fa1c2016-09-08 01:42:46 -0700538
bayramovef390722016-09-27 03:34:46 -0700539 try:
540 for network in networks:
541 filter_entry = {}
542 net_uuid = network.get_id().split(":")
543 if len(net_uuid) != 4:
544 continue
545 else:
546 net_uuid = net_uuid[3]
547 # create dict entry
548 self.logger.debug("Adding {} to a list vcd id {} network {}".format(net_uuid,
549 vdcid,
550 network.get_name()))
551 filter_entry["name"] = network.get_name()
552 filter_entry["id"] = net_uuid
553 filter_entry["shared"] = network.get_IsShared()
554 filter_entry["tenant_id"] = vdcid
555 if network.get_status() == 1:
556 filter_entry["admin_state_up"] = True
557 else:
558 filter_entry["admin_state_up"] = False
559 filter_entry["status"] = "ACTIVE"
560 filter_entry["type"] = "bridge"
561 filtered_entry = filter_entry.copy()
562
bayramovb6ffe792016-09-28 11:50:56 +0400563 if filter_dict is not None and filter_dict:
564 # we remove all the key : value we don't care and match only
565 # respected field
566 filtered_dict = set(filter_entry.keys()) - set(filter_dict)
567 for unwanted_key in filtered_dict: del filter_entry[unwanted_key]
568 if filter_dict == filter_entry:
569 network_list.append(filtered_entry)
570 else:
bayramovef390722016-09-27 03:34:46 -0700571 network_list.append(filtered_entry)
572 except:
573 self.logger.debug("Error in get_vcd_network_list")
574 self.logger.debug(traceback.format_exc())
bayramov325fa1c2016-09-08 01:42:46 -0700575
576 self.logger.debug("Returning {}".format(network_list))
577 return network_list
578
579 def get_network(self, net_id):
bayramovfe3f3c92016-10-04 07:53:41 +0400580 """Method obtains network details of net_id VIM network
bayramovef390722016-09-27 03:34:46 -0700581 Return a dict with the fields at filter_dict (see get_network_list) plus some VIM specific>}, ...]"""
582
583 vca = self.connect()
584 if not vca:
585 raise vimconn.vimconnConnectionException("self.connect() is failed")
586
587 vdc = vca.get_vdc(self.tenant_name)
588 vdc_id = vdc.get_id().split(":")[3]
589
590 networks = vca.get_networks(vdc.get_name())
591 filter_dict = {}
592
593 try:
594 for network in networks:
595 vdc_network_id = network.get_id().split(":")
596 if len(vdc_network_id) == 4 and vdc_network_id[3] == net_id:
597 filter_dict["name"] = network.get_name()
598 filter_dict["id"] = vdc_network_id[3]
599 filter_dict["shared"] = network.get_IsShared()
600 filter_dict["tenant_id"] = vdc_id
601 if network.get_status() == 1:
602 filter_dict["admin_state_up"] = True
603 else:
604 filter_dict["admin_state_up"] = False
605 filter_dict["status"] = "ACTIVE"
606 filter_dict["type"] = "bridge"
607 self.logger.debug("Returning {}".format(filter_dict))
608 return filter_dict
609 except:
610 self.logger.debug("Error in get_network")
611 self.logger.debug(traceback.format_exc())
612
613 return filter_dict
bayramov325fa1c2016-09-08 01:42:46 -0700614
615 def delete_network(self, net_id):
bayramovef390722016-09-27 03:34:46 -0700616 """
617 Method Deletes a tenant network from VIM, provide the network id.
618
619 Returns the network identifier or raise an exception
620 """
621
622 vca = self.connect()
623 if not vca:
bayramovfe3f3c92016-10-04 07:53:41 +0400624 raise vimconn.vimconnConnectionException("self.connect() for tenant {} is failed.".format(self.tenant_name))
bayramovef390722016-09-27 03:34:46 -0700625
bayramovfe3f3c92016-10-04 07:53:41 +0400626 vcd_network = self.get_vcd_network(network_uuid=net_id)
627 if vcd_network is not None and vcd_network:
628 if self.delete_network_action(network_uuid=net_id):
629 return net_id
bayramovef390722016-09-27 03:34:46 -0700630 else:
631 raise vimconn.vimconnNotFoundException("Network {} not found".format(net_id))
bayramov325fa1c2016-09-08 01:42:46 -0700632
633 def refresh_nets_status(self, net_list):
bayramovbd6160f2016-09-28 04:12:05 +0400634 """Get the status of the networks
bayramov325fa1c2016-09-08 01:42:46 -0700635 Params: the list of network identifiers
636 Returns a dictionary with:
637 net_id: #VIM id of this network
638 status: #Mandatory. Text with one of:
639 # DELETED (not found at vim)
bayramovbd6160f2016-09-28 04:12:05 +0400640 # VIM_ERROR (Cannot connect to VIM, VIM response error, ...)
bayramov325fa1c2016-09-08 01:42:46 -0700641 # OTHER (Vim reported other status not understood)
642 # ERROR (VIM indicates an ERROR status)
bayramovbd6160f2016-09-28 04:12:05 +0400643 # ACTIVE, INACTIVE, DOWN (admin down),
bayramov325fa1c2016-09-08 01:42:46 -0700644 # BUILD (on building process)
645 #
bayramovbd6160f2016-09-28 04:12:05 +0400646 error_msg: #Text with VIM error message, if any. Or the VIM connection ERROR
bayramov325fa1c2016-09-08 01:42:46 -0700647 vim_info: #Text with plain information obtained from vim (yaml.safe_dump)
648
bayramovbd6160f2016-09-28 04:12:05 +0400649 """
bayramov325fa1c2016-09-08 01:42:46 -0700650
bayramov325fa1c2016-09-08 01:42:46 -0700651 vca = self.connect()
652 if not vca:
bayramovef390722016-09-27 03:34:46 -0700653 raise vimconn.vimconnConnectionException("self.connect() is failed")
654
655 dict_entry = {}
656 try:
657 for net in net_list:
bayramovef390722016-09-27 03:34:46 -0700658 errormsg = ''
659 vcd_network = self.get_vcd_network(network_uuid=net)
bayramovfe3f3c92016-10-04 07:53:41 +0400660 if vcd_network is not None and vcd_network:
bhangare92d4af32016-12-24 02:54:51 -0800661 if vcd_network['status'] == '1':
bayramovef390722016-09-27 03:34:46 -0700662 status = 'ACTIVE'
663 else:
664 status = 'DOWN'
665 else:
666 status = 'DELETED'
bayramovfe3f3c92016-10-04 07:53:41 +0400667 errormsg = 'Network not found.'
668
669 dict_entry[net] = {'status': status, 'error_msg': errormsg,
bhangare92d4af32016-12-24 02:54:51 -0800670 'vim_info': yaml.safe_dump(vcd_network)}
bayramovef390722016-09-27 03:34:46 -0700671 except:
672 self.logger.debug("Error in refresh_nets_status")
673 self.logger.debug(traceback.format_exc())
674
675 return dict_entry
676
bayramovbd6160f2016-09-28 04:12:05 +0400677 def get_flavor(self, flavor_id):
bayramovef390722016-09-27 03:34:46 -0700678 """Obtain flavor details from the VIM
679 Returns the flavor dict details {'id':<>, 'name':<>, other vim specific } #TODO to concrete
680 """
bayramov5761ad12016-10-04 09:00:30 +0400681 if flavor_id not in flavorlist:
bayramovfe3f3c92016-10-04 07:53:41 +0400682 raise vimconn.vimconnNotFoundException("Flavor not found.")
bayramovef390722016-09-27 03:34:46 -0700683 return flavorlist[flavor_id]
bayramov325fa1c2016-09-08 01:42:46 -0700684
685 def new_flavor(self, flavor_data):
bayramovef390722016-09-27 03:34:46 -0700686 """Adds a tenant flavor to VIM
bayramov325fa1c2016-09-08 01:42:46 -0700687 flavor_data contains a dictionary with information, keys:
688 name: flavor name
689 ram: memory (cloud type) in MBytes
690 vpcus: cpus (cloud type)
691 extended: EPA parameters
692 - numas: #items requested in same NUMA
693 memory: number of 1G huge pages memory
694 paired-threads|cores|threads: number of paired hyperthreads, complete cores OR individual threads
695 interfaces: # passthrough(PT) or SRIOV interfaces attached to this numa
696 - name: interface name
697 dedicated: yes|no|yes:sriov; for PT, SRIOV or only one SRIOV for the physical NIC
698 bandwidth: X Gbps; requested guarantee bandwidth
bayramovef390722016-09-27 03:34:46 -0700699 vpci: requested virtual PCI address
bayramov325fa1c2016-09-08 01:42:46 -0700700 disk: disk size
701 is_public:
bayramovef390722016-09-27 03:34:46 -0700702
703
704
bayramov325fa1c2016-09-08 01:42:46 -0700705 #TODO to concrete
bayramovef390722016-09-27 03:34:46 -0700706 Returns the flavor identifier"""
bayramov325fa1c2016-09-08 01:42:46 -0700707
bayramovef390722016-09-27 03:34:46 -0700708 # generate a new uuid put to internal dict and return it.
709 flavor_id = uuid.uuid4()
710 flavorlist[str(flavor_id)] = flavor_data
bayramov325fa1c2016-09-08 01:42:46 -0700711
bayramovef390722016-09-27 03:34:46 -0700712 return str(flavor_id)
bayramov325fa1c2016-09-08 01:42:46 -0700713
714 def delete_flavor(self, flavor_id):
bayramovef390722016-09-27 03:34:46 -0700715 """Deletes a tenant flavor from VIM identify by its id
bayramov325fa1c2016-09-08 01:42:46 -0700716
bayramovfe3f3c92016-10-04 07:53:41 +0400717 Returns the used id or raise an exception
bayramovef390722016-09-27 03:34:46 -0700718 """
bayramov5761ad12016-10-04 09:00:30 +0400719 if flavor_id not in flavorlist:
bayramovfe3f3c92016-10-04 07:53:41 +0400720 raise vimconn.vimconnNotFoundException("Flavor not found.")
bayramovef390722016-09-27 03:34:46 -0700721
bayramovef390722016-09-27 03:34:46 -0700722 flavorlist.pop(flavor_id, None)
723 return flavor_id
724
725 def new_image(self, image_dict):
bayramov5761ad12016-10-04 09:00:30 +0400726 """
bayramov325fa1c2016-09-08 01:42:46 -0700727 Adds a tenant image to VIM
728 Returns:
729 200, image-id if the image is created
730 <0, message if there is an error
bayramov5761ad12016-10-04 09:00:30 +0400731 """
bayramov325fa1c2016-09-08 01:42:46 -0700732
bayramovef390722016-09-27 03:34:46 -0700733 return self.get_image_id_from_path(image_dict['location'])
bayramov325fa1c2016-09-08 01:42:46 -0700734
735 def delete_image(self, image_id):
bayramovfe3f3c92016-10-04 07:53:41 +0400736 """
737
738 :param image_id:
739 :return:
740 """
bayramovfe3f3c92016-10-04 07:53:41 +0400741
bayramovbd6160f2016-09-28 04:12:05 +0400742 raise vimconn.vimconnNotImplemented("Should have implemented this")
bayramov325fa1c2016-09-08 01:42:46 -0700743
744 def catalog_exists(self, catalog_name, catalogs):
bayramovfe3f3c92016-10-04 07:53:41 +0400745 """
746
747 :param catalog_name:
748 :param catalogs:
749 :return:
750 """
bayramov325fa1c2016-09-08 01:42:46 -0700751 for catalog in catalogs:
752 if catalog.name == catalog_name:
753 return True
754 return False
755
bayramovb6ffe792016-09-28 11:50:56 +0400756 def create_vimcatalog(self, vca=None, catalog_name=None):
bayramovfe3f3c92016-10-04 07:53:41 +0400757 """ Create new catalog entry in vCloud director.
bayramovb6ffe792016-09-28 11:50:56 +0400758
759 Args
760 vca: vCloud director.
761 catalog_name catalog that client wish to create. Note no validation done for a name.
762 Client must make sure that provide valid string representation.
763
764 Return (bool) True if catalog created.
765
766 """
767 try:
768 task = vca.create_catalog(catalog_name, catalog_name)
769 result = vca.block_until_completed(task)
770 if not result:
771 return False
772 catalogs = vca.get_catalogs()
773 except:
bayramov325fa1c2016-09-08 01:42:46 -0700774 return False
bayramov325fa1c2016-09-08 01:42:46 -0700775 return self.catalog_exists(catalog_name, catalogs)
776
bayramov5761ad12016-10-04 09:00:30 +0400777 # noinspection PyIncorrectDocstring
bayramovfe3f3c92016-10-04 07:53:41 +0400778 def upload_ovf(self, vca=None, catalog_name=None, image_name=None, media_file_name=None,
779 description='', progress=False, chunk_bytes=128 * 1024):
bayramov325fa1c2016-09-08 01:42:46 -0700780 """
781 Uploads a OVF file to a vCloud catalog
782
bayramov5761ad12016-10-04 09:00:30 +0400783 :param chunk_bytes:
784 :param progress:
785 :param description:
786 :param image_name:
787 :param vca:
bayramov325fa1c2016-09-08 01:42:46 -0700788 :param catalog_name: (str): The name of the catalog to upload the media.
bayramov325fa1c2016-09-08 01:42:46 -0700789 :param media_file_name: (str): The name of the local media file to upload.
790 :return: (bool) True if the media file was successfully uploaded, false otherwise.
791 """
792 os.path.isfile(media_file_name)
793 statinfo = os.stat(media_file_name)
bayramov325fa1c2016-09-08 01:42:46 -0700794
795 # find a catalog entry where we upload OVF.
796 # create vApp Template and check the status if vCD able to read OVF it will respond with appropirate
797 # status change.
798 # if VCD can parse OVF we upload VMDK file
799 for catalog in vca.get_catalogs():
800 if catalog_name != catalog.name:
801 continue
802 link = filter(lambda link: link.get_type() == "application/vnd.vmware.vcloud.media+xml" and
803 link.get_rel() == 'add', catalog.get_Link())
804 assert len(link) == 1
805 data = """
kate15f1c382016-12-15 01:12:40 -0800806 <UploadVAppTemplateParams name="%s" xmlns="http://www.vmware.com/vcloud/v1.5" xmlns:ovf="http://schemas.dmtf.org/ovf/envelope/1"><Description>%s vApp Template</Description></UploadVAppTemplateParams>
807 """ % (escape(catalog_name), escape(description))
bayramov325fa1c2016-09-08 01:42:46 -0700808 headers = vca.vcloud_session.get_vcloud_headers()
809 headers['Content-Type'] = 'application/vnd.vmware.vcloud.uploadVAppTemplateParams+xml'
810 response = Http.post(link[0].get_href(), headers=headers, data=data, verify=vca.verify, logger=self.logger)
811 if response.status_code == requests.codes.created:
bayramovef390722016-09-27 03:34:46 -0700812 catalogItem = XmlElementTree.fromstring(response.content)
bayramov325fa1c2016-09-08 01:42:46 -0700813 entity = [child for child in catalogItem if
814 child.get("type") == "application/vnd.vmware.vcloud.vAppTemplate+xml"][0]
815 href = entity.get('href')
816 template = href
817 response = Http.get(href, headers=vca.vcloud_session.get_vcloud_headers(),
818 verify=vca.verify, logger=self.logger)
819
820 if response.status_code == requests.codes.ok:
821 media = mediaType.parseString(response.content, True)
bayramovfe3f3c92016-10-04 07:53:41 +0400822 link = filter(lambda link: link.get_rel() == 'upload:default',
823 media.get_Files().get_File()[0].get_Link())[0]
bayramov325fa1c2016-09-08 01:42:46 -0700824 headers = vca.vcloud_session.get_vcloud_headers()
825 headers['Content-Type'] = 'Content-Type text/xml'
bayramovfe3f3c92016-10-04 07:53:41 +0400826 response = Http.put(link.get_href(),
827 data=open(media_file_name, 'rb'),
828 headers=headers,
bayramovef390722016-09-27 03:34:46 -0700829 verify=vca.verify, logger=self.logger)
bayramov325fa1c2016-09-08 01:42:46 -0700830 if response.status_code != requests.codes.ok:
bayramovef390722016-09-27 03:34:46 -0700831 self.logger.debug(
832 "Failed create vApp template for catalog name {} and image {}".format(catalog_name,
833 media_file_name))
bayramov325fa1c2016-09-08 01:42:46 -0700834 return False
835
bayramovef390722016-09-27 03:34:46 -0700836 # TODO fix this with aync block
bayramov325fa1c2016-09-08 01:42:46 -0700837 time.sleep(5)
838
kate15f1c382016-12-15 01:12:40 -0800839 self.logger.debug("vApp template for catalog name {} and image {}".format(catalog_name, media_file_name))
bayramov325fa1c2016-09-08 01:42:46 -0700840
841 # uploading VMDK file
bayramovfe3f3c92016-10-04 07:53:41 +0400842 # check status of OVF upload and upload remaining files.
843 response = Http.get(template,
844 headers=vca.vcloud_session.get_vcloud_headers(),
845 verify=vca.verify,
bayramovef390722016-09-27 03:34:46 -0700846 logger=self.logger)
bayramovfe3f3c92016-10-04 07:53:41 +0400847
bayramov325fa1c2016-09-08 01:42:46 -0700848 if response.status_code == requests.codes.ok:
849 media = mediaType.parseString(response.content, True)
bayramovfe3f3c92016-10-04 07:53:41 +0400850 number_of_files = len(media.get_Files().get_File())
851 for index in xrange(0, number_of_files):
852 links_list = filter(lambda link: link.get_rel() == 'upload:default',
853 media.get_Files().get_File()[index].get_Link())
854 for link in links_list:
855 # we skip ovf since it already uploaded.
856 if 'ovf' in link.get_href():
857 continue
858 # The OVF file and VMDK must be in a same directory
859 head, tail = os.path.split(media_file_name)
860 file_vmdk = head + '/' + link.get_href().split("/")[-1]
861 if not os.path.isfile(file_vmdk):
862 return False
863 statinfo = os.stat(file_vmdk)
864 if statinfo.st_size == 0:
865 return False
866 hrefvmdk = link.get_href()
bayramov325fa1c2016-09-08 01:42:46 -0700867
bayramovfe3f3c92016-10-04 07:53:41 +0400868 if progress:
869 print("Uploading file: {}".format(file_vmdk))
870 if progress:
871 widgets = ['Uploading file: ', Percentage(), ' ', Bar(), ' ', ETA(), ' ',
872 FileTransferSpeed()]
873 progress_bar = ProgressBar(widgets=widgets, maxval=statinfo.st_size).start()
bayramov325fa1c2016-09-08 01:42:46 -0700874
bayramovfe3f3c92016-10-04 07:53:41 +0400875 bytes_transferred = 0
876 f = open(file_vmdk, 'rb')
877 while bytes_transferred < statinfo.st_size:
878 my_bytes = f.read(chunk_bytes)
879 if len(my_bytes) <= chunk_bytes:
880 headers = vca.vcloud_session.get_vcloud_headers()
881 headers['Content-Range'] = 'bytes %s-%s/%s' % (
882 bytes_transferred, len(my_bytes) - 1, statinfo.st_size)
883 headers['Content-Length'] = str(len(my_bytes))
884 response = Http.put(hrefvmdk,
885 headers=headers,
886 data=my_bytes,
887 verify=vca.verify,
888 logger=None)
bayramov325fa1c2016-09-08 01:42:46 -0700889
bayramovfe3f3c92016-10-04 07:53:41 +0400890 if response.status_code == requests.codes.ok:
891 bytes_transferred += len(my_bytes)
892 if progress:
893 progress_bar.update(bytes_transferred)
894 else:
895 self.logger.debug(
896 'file upload failed with error: [%s] %s' % (response.status_code,
897 response.content))
898
899 f.close()
900 return False
901 f.close()
902 if progress:
903 progress_bar.finish()
bayramov325fa1c2016-09-08 01:42:46 -0700904 return True
905 else:
906 self.logger.debug("Failed retrieve vApp template for catalog name {} for OVF {}".
907 format(catalog_name, media_file_name))
908 return False
909
910 self.logger.debug("Failed retrieve catalog name {} for OVF file {}".format(catalog_name, media_file_name))
911 return False
912
bayramovfe3f3c92016-10-04 07:53:41 +0400913 def upload_vimimage(self, vca=None, catalog_name=None, media_name=None, medial_file_name=None, progress=False):
bayramov325fa1c2016-09-08 01:42:46 -0700914 """Upload media file"""
bayramovfe3f3c92016-10-04 07:53:41 +0400915 # TODO add named parameters for readability
916
917 return self.upload_ovf(vca=vca, catalog_name=catalog_name, image_name=media_name.split(".")[0],
918 media_file_name=medial_file_name, description='medial_file_name', progress=progress)
bayramov325fa1c2016-09-08 01:42:46 -0700919
bayramovb6ffe792016-09-28 11:50:56 +0400920 def validate_uuid4(self, uuid_string=None):
921 """ Method validate correct format of UUID.
922
923 Return: true if string represent valid uuid
924 """
925 try:
926 val = uuid.UUID(uuid_string, version=4)
927 except ValueError:
928 return False
929 return True
930
931 def get_catalogid(self, catalog_name=None, catalogs=None):
932 """ Method check catalog and return catalog ID in UUID format.
933
934 Args
935 catalog_name: catalog name as string
936 catalogs: list of catalogs.
937
938 Return: catalogs uuid
939 """
940
bayramov325fa1c2016-09-08 01:42:46 -0700941 for catalog in catalogs:
942 if catalog.name == catalog_name:
bayramov325fa1c2016-09-08 01:42:46 -0700943 catalog_id = catalog.get_id().split(":")
944 return catalog_id[3]
945 return None
946
bayramovb6ffe792016-09-28 11:50:56 +0400947 def get_catalogbyid(self, catalog_uuid=None, catalogs=None):
948 """ Method check catalog and return catalog name lookup done by catalog UUID.
949
950 Args
951 catalog_name: catalog name as string
952 catalogs: list of catalogs.
953
954 Return: catalogs name or None
955 """
956
957 if not self.validate_uuid4(uuid_string=catalog_uuid):
958 return None
959
bayramov325fa1c2016-09-08 01:42:46 -0700960 for catalog in catalogs:
bayramovb6ffe792016-09-28 11:50:56 +0400961 catalog_id = catalog.get_id().split(":")[3]
962 if catalog_id == catalog_uuid:
bayramov325fa1c2016-09-08 01:42:46 -0700963 return catalog.name
964 return None
965
bayramovfe3f3c92016-10-04 07:53:41 +0400966 def get_image_id_from_path(self, path=None, progress=False):
bayramovb6ffe792016-09-28 11:50:56 +0400967 """ Method upload OVF image to vCloud director.
bayramov325fa1c2016-09-08 01:42:46 -0700968
bayramovb6ffe792016-09-28 11:50:56 +0400969 Each OVF image represented as single catalog entry in vcloud director.
970 The method check for existing catalog entry. The check done by file name without file extension.
971
972 if given catalog name already present method will respond with existing catalog uuid otherwise
973 it will create new catalog entry and upload OVF file to newly created catalog.
974
975 If method can't create catalog entry or upload a file it will throw exception.
976
bayramovfe3f3c92016-10-04 07:53:41 +0400977 Method accept boolean flag progress that will output progress bar. It useful method
978 for standalone upload use case. In case to test large file upload.
979
bayramovb6ffe792016-09-28 11:50:56 +0400980 Args
bayramovfe3f3c92016-10-04 07:53:41 +0400981 path: - valid path to OVF file.
982 progress - boolean progress bar show progress bar.
bayramovb6ffe792016-09-28 11:50:56 +0400983
984 Return: if image uploaded correct method will provide image catalog UUID.
985 """
bayramov325fa1c2016-09-08 01:42:46 -0700986 vca = self.connect()
987 if not vca:
bayramovfe3f3c92016-10-04 07:53:41 +0400988 raise vimconn.vimconnConnectionException("self.connect() is failed.")
bayramov325fa1c2016-09-08 01:42:46 -0700989
kate15f1c382016-12-15 01:12:40 -0800990 if not path:
bayramovfe3f3c92016-10-04 07:53:41 +0400991 raise vimconn.vimconnException("Image path can't be None.")
992
993 if not os.path.isfile(path):
994 raise vimconn.vimconnException("Can't read file. File not found.")
995
996 if not os.access(path, os.R_OK):
997 raise vimconn.vimconnException("Can't read file. Check file permission to read.")
998
999 self.logger.debug("get_image_id_from_path() client requesting {} ".format(path))
bayramov325fa1c2016-09-08 01:42:46 -07001000
1001 dirpath, filename = os.path.split(path)
1002 flname, file_extension = os.path.splitext(path)
1003 if file_extension != '.ovf':
bayramovfe3f3c92016-10-04 07:53:41 +04001004 self.logger.debug("Wrong file extension {} connector support only OVF container.".format(file_extension))
bayramovb6ffe792016-09-28 11:50:56 +04001005 raise vimconn.vimconnException("Wrong container. vCloud director supports only OVF.")
kate15f1c382016-12-15 01:12:40 -08001006
bayramov325fa1c2016-09-08 01:42:46 -07001007 catalog_name = os.path.splitext(filename)[0]
kate15f1c382016-12-15 01:12:40 -08001008 catalog_md5_name = hashlib.md5(path).hexdigest()
1009 self.logger.debug("File name {} Catalog Name {} file path {} "
1010 "vdc catalog name {}".format(filename, catalog_name, path, catalog_md5_name))
bayramov325fa1c2016-09-08 01:42:46 -07001011
1012 catalogs = vca.get_catalogs()
1013 if len(catalogs) == 0:
bayramovfe3f3c92016-10-04 07:53:41 +04001014 self.logger.info("Creating a new catalog entry {} in vcloud director".format(catalog_name))
kate15f1c382016-12-15 01:12:40 -08001015 result = self.create_vimcatalog(vca, catalog_md5_name)
bayramov325fa1c2016-09-08 01:42:46 -07001016 if not result:
kate15f1c382016-12-15 01:12:40 -08001017 raise vimconn.vimconnException("Failed create new catalog {} ".format(catalog_md5_name))
1018 result = self.upload_vimimage(vca=vca, catalog_name=catalog_md5_name,
bayramovfe3f3c92016-10-04 07:53:41 +04001019 media_name=filename, medial_file_name=path, progress=progress)
bayramov325fa1c2016-09-08 01:42:46 -07001020 if not result:
bayramovb6ffe792016-09-28 11:50:56 +04001021 raise vimconn.vimconnException("Failed create vApp template for catalog {} ".format(catalog_name))
bayramov325fa1c2016-09-08 01:42:46 -07001022 return self.get_catalogid(catalog_name, vca.get_catalogs())
1023 else:
1024 for catalog in catalogs:
1025 # search for existing catalog if we find same name we return ID
1026 # TODO optimize this
kate15f1c382016-12-15 01:12:40 -08001027 if catalog.name == catalog_md5_name:
1028 self.logger.debug("Found existing catalog entry for {} "
1029 "catalog id {}".format(catalog_name,
1030 self.get_catalogid(catalog_md5_name, catalogs)))
1031 return self.get_catalogid(catalog_md5_name, vca.get_catalogs())
bayramov325fa1c2016-09-08 01:42:46 -07001032
bayramovfe3f3c92016-10-04 07:53:41 +04001033 # if we didn't find existing catalog we create a new one and upload image.
kate15f1c382016-12-15 01:12:40 -08001034 self.logger.debug("Creating new catalog entry {} - {}".format(catalog_name, catalog_md5_name))
1035 result = self.create_vimcatalog(vca, catalog_md5_name)
bayramov325fa1c2016-09-08 01:42:46 -07001036 if not result:
kate15f1c382016-12-15 01:12:40 -08001037 raise vimconn.vimconnException("Failed create new catalog {} ".format(catalog_md5_name))
bayramovfe3f3c92016-10-04 07:53:41 +04001038
kate15f1c382016-12-15 01:12:40 -08001039 result = self.upload_vimimage(vca=vca, catalog_name=catalog_md5_name,
bayramovfe3f3c92016-10-04 07:53:41 +04001040 media_name=filename, medial_file_name=path, progress=progress)
bayramov325fa1c2016-09-08 01:42:46 -07001041 if not result:
kate15f1c382016-12-15 01:12:40 -08001042 raise vimconn.vimconnException("Failed create vApp template for catalog {} ".format(catalog_md5_name))
bayramov325fa1c2016-09-08 01:42:46 -07001043
kate15f1c382016-12-15 01:12:40 -08001044 return self.get_catalogid(catalog_md5_name, vca.get_catalogs())
bayramov325fa1c2016-09-08 01:42:46 -07001045
bayramovef390722016-09-27 03:34:46 -07001046 def get_vappid(self, vdc=None, vapp_name=None):
1047 """ Method takes vdc object and vApp name and returns vapp uuid or None
1048
1049 Args:
bayramovef390722016-09-27 03:34:46 -07001050 vdc: The VDC object.
1051 vapp_name: is application vappp name identifier
1052
bayramovb6ffe792016-09-28 11:50:56 +04001053 Returns:
bayramovef390722016-09-27 03:34:46 -07001054 The return vApp name otherwise None
1055 """
bayramovef390722016-09-27 03:34:46 -07001056 if vdc is None or vapp_name is None:
1057 return None
1058 # UUID has following format https://host/api/vApp/vapp-30da58a3-e7c7-4d09-8f68-d4c8201169cf
bayramov325fa1c2016-09-08 01:42:46 -07001059 try:
1060 refs = filter(lambda ref: ref.name == vapp_name and ref.type_ == 'application/vnd.vmware.vcloud.vApp+xml',
bayramovef390722016-09-27 03:34:46 -07001061 vdc.ResourceEntities.ResourceEntity)
bayramov325fa1c2016-09-08 01:42:46 -07001062 if len(refs) == 1:
1063 return refs[0].href.split("vapp")[1][1:]
bayramovef390722016-09-27 03:34:46 -07001064 except Exception as e:
1065 self.logger.exception(e)
1066 return False
1067 return None
1068
bayramovfe3f3c92016-10-04 07:53:41 +04001069 def check_vapp(self, vdc=None, vapp_uuid=None):
1070 """ Method Method returns True or False if vapp deployed in vCloud director
bayramovef390722016-09-27 03:34:46 -07001071
1072 Args:
1073 vca: Connector to VCA
1074 vdc: The VDC object.
1075 vappid: vappid is application identifier
1076
1077 Returns:
bayramovfe3f3c92016-10-04 07:53:41 +04001078 The return True if vApp deployed
bayramov5761ad12016-10-04 09:00:30 +04001079 :param vdc:
1080 :param vapp_uuid:
bayramovef390722016-09-27 03:34:46 -07001081 """
1082 try:
1083 refs = filter(lambda ref:
1084 ref.type_ == 'application/vnd.vmware.vcloud.vApp+xml',
1085 vdc.ResourceEntities.ResourceEntity)
1086 for ref in refs:
1087 vappid = ref.href.split("vapp")[1][1:]
1088 # find vapp with respected vapp uuid
bayramovfe3f3c92016-10-04 07:53:41 +04001089 if vappid == vapp_uuid:
bayramovef390722016-09-27 03:34:46 -07001090 return True
1091 except Exception as e:
1092 self.logger.exception(e)
1093 return False
1094 return False
1095
bayramovfe3f3c92016-10-04 07:53:41 +04001096 def get_namebyvappid(self, vca=None, vdc=None, vapp_uuid=None):
bayramovef390722016-09-27 03:34:46 -07001097 """Method returns vApp name from vCD and lookup done by vapp_id.
1098
1099 Args:
1100 vca: Connector to VCA
1101 vdc: The VDC object.
bayramovfe3f3c92016-10-04 07:53:41 +04001102 vapp_uuid: vappid is application identifier
bayramovef390722016-09-27 03:34:46 -07001103
1104 Returns:
1105 The return vApp name otherwise None
1106 """
1107
1108 try:
1109 refs = filter(lambda ref: ref.type_ == 'application/vnd.vmware.vcloud.vApp+xml',
1110 vdc.ResourceEntities.ResourceEntity)
1111 for ref in refs:
1112 # we care only about UUID the rest doesn't matter
1113 vappid = ref.href.split("vapp")[1][1:]
bayramovfe3f3c92016-10-04 07:53:41 +04001114 if vappid == vapp_uuid:
bayramovef390722016-09-27 03:34:46 -07001115 response = Http.get(ref.href, headers=vca.vcloud_session.get_vcloud_headers(), verify=vca.verify,
1116 logger=self.logger)
1117 tree = XmlElementTree.fromstring(response.content)
1118 return tree.attrib['name']
1119 except Exception as e:
1120 self.logger.exception(e)
bayramov325fa1c2016-09-08 01:42:46 -07001121 return None
1122 return None
1123
bayramovfe3f3c92016-10-04 07:53:41 +04001124 def new_vminstance(self, name=None, description="", start=False, image_id=None, flavor_id=None, net_list={},
montesmoreno0c8def02016-12-22 12:16:23 +00001125 cloud_config=None, disk_list=None):
bayramov325fa1c2016-09-08 01:42:46 -07001126 """Adds a VM instance to VIM
1127 Params:
1128 start: indicates if VM must start or boot in pause mode. Ignored
1129 image_id,flavor_id: image and flavor uuid
1130 net_list: list of interfaces, each one is a dictionary with:
1131 name:
1132 net_id: network uuid to connect
1133 vpci: virtual vcpi to assign
1134 model: interface model, virtio, e2000, ...
1135 mac_address:
1136 use: 'data', 'bridge', 'mgmt'
1137 type: 'virtual', 'PF', 'VF', 'VFnotShared'
1138 vim_id: filled/added by this function
1139 cloud_config: can be a text script to be passed directly to cloud-init,
1140 or an object to inject users and ssh keys with format:
1141 key-pairs: [] list of keys to install to the default user
1142 users: [{ name, key-pairs: []}] list of users to add with their key-pair
1143 #TODO ip, security groups
1144 Returns >=0, the instance identifier
1145 <0, error_text
1146 """
1147
kate15f1c382016-12-15 01:12:40 -08001148 self.logger.info("Creating new instance for entry {}".format(name))
bayramov325fa1c2016-09-08 01:42:46 -07001149 self.logger.debug("desc {} boot {} image_id: {} flavor_id: {} net_list: {} cloud_config {}".
1150 format(description, start, image_id, flavor_id, net_list, cloud_config))
1151 vca = self.connect()
1152 if not vca:
1153 raise vimconn.vimconnConnectionException("self.connect() is failed.")
1154
bayramov5761ad12016-10-04 09:00:30 +04001155 #new vm name = vmname + tenant_id + uuid
1156 new_vm_name = [name, '-', str(uuid.uuid4())]
kate15f1c382016-12-15 01:12:40 -08001157 vmname_andid = ''.join(new_vm_name)
bayramov5761ad12016-10-04 09:00:30 +04001158
bayramovef390722016-09-27 03:34:46 -07001159 # if vm already deployed we return existing uuid
bayramov5761ad12016-10-04 09:00:30 +04001160 # vapp_uuid = self.get_vappid(vca.get_vdc(self.tenant_name), name)
1161 # if vapp_uuid is not None:
1162 # return vapp_uuid
bayramov325fa1c2016-09-08 01:42:46 -07001163
bayramovef390722016-09-27 03:34:46 -07001164 # we check for presence of VDC, Catalog entry and Flavor.
1165 vdc = vca.get_vdc(self.tenant_name)
1166 if vdc is None:
bayramovfe3f3c92016-10-04 07:53:41 +04001167 raise vimconn.vimconnNotFoundException(
bayramovb6ffe792016-09-28 11:50:56 +04001168 "new_vminstance(): Failed create vApp {}: (Failed retrieve VDC information)".format(name))
bayramov325fa1c2016-09-08 01:42:46 -07001169 catalogs = vca.get_catalogs()
bayramovef390722016-09-27 03:34:46 -07001170 if catalogs is None:
bayramovfe3f3c92016-10-04 07:53:41 +04001171 raise vimconn.vimconnNotFoundException(
kate15f1c382016-12-15 01:12:40 -08001172 "new_vminstance(): Failed create vApp {}: (Failed retrieve catalogs list)".format(name))
bayramovbd6160f2016-09-28 04:12:05 +04001173
kate15f1c382016-12-15 01:12:40 -08001174 catalog_hash_name = self.get_catalogbyid(catalog_uuid=image_id, catalogs=catalogs)
1175 if catalog_hash_name:
1176 self.logger.info("Found catalog entry {} for image id {}".format(catalog_hash_name, image_id))
1177 else:
1178 raise vimconn.vimconnNotFoundException("new_vminstance(): Failed create vApp {}: "
1179 "(Failed retrieve catalog information {})".format(name, image_id))
1180
1181
1182 # Set vCPU and Memory based on flavor.
1183 #
bayramovb6ffe792016-09-28 11:50:56 +04001184 vm_cpus = None
1185 vm_memory = None
1186 if flavor_id is not None:
kate15f1c382016-12-15 01:12:40 -08001187 if flavor_id not in flavorlist:
1188 raise vimconn.vimconnNotFoundException("new_vminstance(): Failed create vApp {}: "
1189 "Failed retrieve flavor information "
1190 "flavor id {}".format(name, flavor_id))
bayramovb6ffe792016-09-28 11:50:56 +04001191 else:
1192 try:
kate15f1c382016-12-15 01:12:40 -08001193 flavor = flavorlist[flavor_id]
1194 vm_cpus = flavor[FLAVOR_VCPUS_KEY]
1195 vm_memory = flavor[FLAVOR_RAM_KEY]
bayramovb6ffe792016-09-28 11:50:56 +04001196 except KeyError:
1197 raise vimconn.vimconnException("Corrupted flavor. {}".format(flavor_id))
bayramov325fa1c2016-09-08 01:42:46 -07001198
bayramovef390722016-09-27 03:34:46 -07001199 # image upload creates template name as catalog name space Template.
kate15f1c382016-12-15 01:12:40 -08001200 templateName = self.get_catalogbyid(catalog_uuid=image_id, catalogs=catalogs)
bayramovef390722016-09-27 03:34:46 -07001201 power_on = 'false'
1202 if start:
1203 power_on = 'true'
1204
1205 # client must provide at least one entry in net_list if not we report error
bhangare0e571a92017-01-12 04:02:23 -08001206 #If net type is mgmt, then configure it as primary net & use its NIC index as primary NIC
1207 #If no mgmt, then the 1st NN in netlist is considered as primary net.
1208 primary_net = None
kate15f1c382016-12-15 01:12:40 -08001209 primary_netname = None
1210 network_mode = 'bridged'
bayramovb6ffe792016-09-28 11:50:56 +04001211 if net_list is not None and len(net_list) > 0:
bhangare0e571a92017-01-12 04:02:23 -08001212 for net in net_list:
1213 if 'use' in net and net['use'] == 'mgmt':
1214 primary_net = net
bayramovb6ffe792016-09-28 11:50:56 +04001215 if primary_net is None:
bhangare0e571a92017-01-12 04:02:23 -08001216 primary_net = net_list[0]
1217
1218 try:
1219 primary_net_id = primary_net['net_id']
1220 network_dict = self.get_vcd_network(network_uuid=primary_net_id)
1221 if 'name' in network_dict:
1222 primary_netname = network_dict['name']
1223
1224 except KeyError:
1225 raise vimconn.vimconnException("Corrupted flavor. {}".format(primary_net))
1226 else:
1227 raise vimconn.vimconnUnexpectedResponse("new_vminstance(): Failed network list is empty.".format(name))
bayramovef390722016-09-27 03:34:46 -07001228
1229 # use: 'data', 'bridge', 'mgmt'
1230 # create vApp. Set vcpu and ram based on flavor id.
kate15f1c382016-12-15 01:12:40 -08001231 vapptask = vca.create_vapp(self.tenant_name, vmname_andid, templateName,
bayramovef390722016-09-27 03:34:46 -07001232 self.get_catalogbyid(image_id, catalogs),
bhangare0e571a92017-01-12 04:02:23 -08001233 network_name=None, # None while creating vapp
kate15f1c382016-12-15 01:12:40 -08001234 network_mode=network_mode,
1235 vm_name=vmname_andid,
bayramovfe3f3c92016-10-04 07:53:41 +04001236 vm_cpus=vm_cpus, # can be None if flavor is None
1237 vm_memory=vm_memory) # can be None if flavor is None
bayramovef390722016-09-27 03:34:46 -07001238
1239 if vapptask is None or vapptask is False:
kate15f1c382016-12-15 01:12:40 -08001240 raise vimconn.vimconnUnexpectedResponse("new_vminstance(): failed deploy vApp {}".format(vmname_andid))
bayramovef390722016-09-27 03:34:46 -07001241 if type(vapptask) is VappTask:
1242 vca.block_until_completed(vapptask)
1243
1244 # we should have now vapp in undeployed state.
kate15f1c382016-12-15 01:12:40 -08001245 vapp = vca.get_vapp(vca.get_vdc(self.tenant_name), vmname_andid)
bayramovef390722016-09-27 03:34:46 -07001246 if vapp is None:
bayramovbd6160f2016-09-28 04:12:05 +04001247 raise vimconn.vimconnUnexpectedResponse(
kate15f1c382016-12-15 01:12:40 -08001248 "new_vminstance(): Failed failed retrieve vApp {} after we deployed".format(vmname_andid))
bayramovef390722016-09-27 03:34:46 -07001249
bhangare0e571a92017-01-12 04:02:23 -08001250 # add NICs & connect to networks in netlist
bayramovef390722016-09-27 03:34:46 -07001251 try:
kate15f1c382016-12-15 01:12:40 -08001252 self.logger.info("Request to connect VM to a network: {}".format(net_list))
bayramovef390722016-09-27 03:34:46 -07001253 nicIndex = 0
bhangare0e571a92017-01-12 04:02:23 -08001254 primary_nic_index = 0
bayramovef390722016-09-27 03:34:46 -07001255 for net in net_list:
1256 # openmano uses network id in UUID format.
1257 # vCloud Director need a name so we do reverse operation from provided UUID we lookup a name
kate15f1c382016-12-15 01:12:40 -08001258 # [{'use': 'bridge', 'net_id': '527d4bf7-566a-41e7-a9e7-ca3cdd9cef4f', 'type': 'virtual',
1259 # 'vpci': '0000:00:11.0', 'name': 'eth0'}]
1260
1261 if 'net_id' not in net:
1262 continue
1263
bayramovef390722016-09-27 03:34:46 -07001264 interface_net_id = net['net_id']
kate15f1c382016-12-15 01:12:40 -08001265 interface_net_name = self.get_network_name_by_id(network_uuid=interface_net_id)
bayramovef390722016-09-27 03:34:46 -07001266 interface_network_mode = net['use']
1267
bhangare0e571a92017-01-12 04:02:23 -08001268 if interface_network_mode == 'mgmt':
1269 primary_nic_index = nicIndex
1270
kate15f1c382016-12-15 01:12:40 -08001271 """- POOL (A static IP address is allocated automatically from a pool of addresses.)
1272 - DHCP (The IP address is obtained from a DHCP service.)
1273 - MANUAL (The IP address is assigned manually in the IpAddress element.)
1274 - NONE (No IP addressing mode specified.)"""
1275
1276 if primary_netname is not None:
bayramovef390722016-09-27 03:34:46 -07001277 nets = filter(lambda n: n.name == interface_net_name, vca.get_networks(self.tenant_name))
1278 if len(nets) == 1:
bhangare0e571a92017-01-12 04:02:23 -08001279 self.logger.info("new_vminstance(): Found requested network: {}".format(nets[0].name))
bayramovef390722016-09-27 03:34:46 -07001280 task = vapp.connect_to_network(nets[0].name, nets[0].href)
1281 if type(task) is GenericTask:
1282 vca.block_until_completed(task)
bhangare0e571a92017-01-12 04:02:23 -08001283 # connect network to VM - with all DHCP by default
1284 self.logger.info("new_vminstance(): Connecting VM to a network {}".format(nets[0].name))
kate15f1c382016-12-15 01:12:40 -08001285 task = vapp.connect_vms(nets[0].name,
1286 connection_index=nicIndex,
bhangare0e571a92017-01-12 04:02:23 -08001287 connections_primary_index=primary_nic_index,
bayramovef390722016-09-27 03:34:46 -07001288 ip_allocation_mode='DHCP')
1289 if type(task) is GenericTask:
1290 vca.block_until_completed(task)
bhangare0e571a92017-01-12 04:02:23 -08001291 nicIndex += 1
bayramovef390722016-09-27 03:34:46 -07001292 except KeyError:
bayramovef390722016-09-27 03:34:46 -07001293 # it might be a case if specific mandatory entry in dict is empty
1294 self.logger.debug("Key error {}".format(KeyError.message))
bayramovbd6160f2016-09-28 04:12:05 +04001295 raise vimconn.vimconnUnexpectedResponse("new_vminstance(): Failed create new vm instance {}".format(name))
bayramovef390722016-09-27 03:34:46 -07001296
1297 # deploy and power on vm
1298 task = vapp.poweron()
1299 if type(task) is TaskType:
1300 vca.block_until_completed(task)
1301 deploytask = vapp.deploy(powerOn='True')
1302 if type(task) is TaskType:
1303 vca.block_until_completed(deploytask)
1304
1305 # check if vApp deployed and if that the case return vApp UUID otherwise -1
kate13ab2c42016-12-23 01:34:24 -08001306 wait_time = 0
1307 vapp_uuid = None
1308 while wait_time <= MAX_WAIT_TIME:
1309 vapp = vca.get_vapp(vca.get_vdc(self.tenant_name), vmname_andid)
1310 if vapp and vapp.me.deployed:
1311 vapp_uuid = self.get_vappid(vca.get_vdc(self.tenant_name), vmname_andid)
1312 break
1313 else:
1314 self.logger.debug("new_vminstance(): Wait for vApp {} to deploy".format(name))
1315 time.sleep(INTERVAL_TIME)
1316
1317 wait_time +=INTERVAL_TIME
1318
bayramovef390722016-09-27 03:34:46 -07001319 if vapp_uuid is not None:
1320 return vapp_uuid
bayramovbd6160f2016-09-28 04:12:05 +04001321 else:
1322 raise vimconn.vimconnUnexpectedResponse("new_vminstance(): Failed create new vm instance {}".format(name))
bayramov325fa1c2016-09-08 01:42:46 -07001323
bayramovef390722016-09-27 03:34:46 -07001324 ##
1325 ##
1326 ## based on current discussion
1327 ##
1328 ##
1329 ## server:
1330 # created: '2016-09-08T11:51:58'
1331 # description: simple-instance.linux1.1
1332 # flavor: ddc6776e-75a9-11e6-ad5f-0800273e724c
1333 # hostId: e836c036-74e7-11e6-b249-0800273e724c
1334 # image: dde30fe6-75a9-11e6-ad5f-0800273e724c
1335 # status: ACTIVE
1336 # error_msg:
1337 # interfaces: …
1338 #
bayramovfe3f3c92016-10-04 07:53:41 +04001339 def get_vminstance(self, vim_vm_uuid=None):
bayramov5761ad12016-10-04 09:00:30 +04001340 """Returns the VM instance information from VIM"""
bayramov325fa1c2016-09-08 01:42:46 -07001341
bayramovef390722016-09-27 03:34:46 -07001342 self.logger.debug("Client requesting vm instance {} ".format(vim_vm_uuid))
bayramov325fa1c2016-09-08 01:42:46 -07001343 vca = self.connect()
1344 if not vca:
1345 raise vimconn.vimconnConnectionException("self.connect() is failed.")
1346
bayramovef390722016-09-27 03:34:46 -07001347 vdc = vca.get_vdc(self.tenant_name)
1348 if vdc is None:
bayramovfe3f3c92016-10-04 07:53:41 +04001349 raise vimconn.vimconnConnectionException(
1350 "Failed to get a reference of VDC for a tenant {}".format(self.tenant_name))
bayramov325fa1c2016-09-08 01:42:46 -07001351
bayramovfe3f3c92016-10-04 07:53:41 +04001352 vm_info_dict = self.get_vapp_details_rest(vapp_uuid=vim_vm_uuid)
1353 if not vm_info_dict:
bayramovef390722016-09-27 03:34:46 -07001354 self.logger.debug("get_vminstance(): Failed to get vApp name by UUID {}".format(vim_vm_uuid))
bayramovfe3f3c92016-10-04 07:53:41 +04001355 raise vimconn.vimconnNotFoundException("Failed to get vApp name by UUID {}".format(vim_vm_uuid))
bayramov325fa1c2016-09-08 01:42:46 -07001356
bayramovfe3f3c92016-10-04 07:53:41 +04001357 status_key = vm_info_dict['status']
1358 error = ''
bayramovef390722016-09-27 03:34:46 -07001359 try:
bayramovfe3f3c92016-10-04 07:53:41 +04001360 vm_dict = {'created': vm_info_dict['created'],
1361 'description': vm_info_dict['name'],
1362 'status': vcdStatusCode2manoFormat[int(status_key)],
1363 'hostId': vm_info_dict['vmuuid'],
1364 'error_msg': error,
1365 'vim_info': yaml.safe_dump(vm_info_dict), 'interfaces': []}
bayramovef390722016-09-27 03:34:46 -07001366
bayramov5761ad12016-10-04 09:00:30 +04001367 if 'interfaces' in vm_info_dict:
bayramovfe3f3c92016-10-04 07:53:41 +04001368 vm_dict['interfaces'] = vm_info_dict['interfaces']
1369 else:
1370 vm_dict['interfaces'] = []
1371 except KeyError:
1372 vm_dict = {'created': '',
1373 'description': '',
1374 'status': vcdStatusCode2manoFormat[int(-1)],
1375 'hostId': vm_info_dict['vmuuid'],
1376 'error_msg': "Inconsistency state",
1377 'vim_info': yaml.safe_dump(vm_info_dict), 'interfaces': []}
bayramovef390722016-09-27 03:34:46 -07001378
1379 return vm_dict
1380
1381 def delete_vminstance(self, vm__vim_uuid):
1382 """Method poweroff and remove VM instance from vcloud director network.
1383
1384 Args:
1385 vm__vim_uuid: VM UUID
1386
1387 Returns:
1388 Returns the instance identifier
1389 """
1390
1391 self.logger.debug("Client requesting delete vm instance {} ".format(vm__vim_uuid))
bayramov325fa1c2016-09-08 01:42:46 -07001392 vca = self.connect()
1393 if not vca:
1394 raise vimconn.vimconnConnectionException("self.connect() is failed.")
1395
bayramovef390722016-09-27 03:34:46 -07001396 vdc = vca.get_vdc(self.tenant_name)
1397 if vdc is None:
1398 self.logger.debug("delete_vminstance(): Failed to get a reference of VDC for a tenant {}".format(
1399 self.tenant_name))
bayramovbd6160f2016-09-28 04:12:05 +04001400 raise vimconn.vimconnException(
1401 "delete_vminstance(): Failed to get a reference of VDC for a tenant {}".format(self.tenant_name))
bayramov325fa1c2016-09-08 01:42:46 -07001402
bayramovef390722016-09-27 03:34:46 -07001403 try:
1404 vapp_name = self.get_namebyvappid(vca, vdc, vm__vim_uuid)
1405 if vapp_name is None:
1406 self.logger.debug("delete_vminstance(): Failed to get vm by given {} vm uuid".format(vm__vim_uuid))
1407 return -1, "delete_vminstance(): Failed to get vm by given {} vm uuid".format(vm__vim_uuid)
1408 else:
1409 self.logger.info("Deleting vApp {} and UUID {}".format(vapp_name, vm__vim_uuid))
bayramov325fa1c2016-09-08 01:42:46 -07001410
bayramovef390722016-09-27 03:34:46 -07001411 # Delete vApp and wait for status change if task executed and vApp is None.
bayramovef390722016-09-27 03:34:46 -07001412 vapp = vca.get_vapp(vca.get_vdc(self.tenant_name), vapp_name)
bayramov325fa1c2016-09-08 01:42:46 -07001413
kate13ab2c42016-12-23 01:34:24 -08001414 if vapp:
1415 if vapp.me.deployed:
1416 self.logger.info("Powering off vApp {}".format(vapp_name))
1417 #Power off vApp
1418 powered_off = False
1419 wait_time = 0
1420 while wait_time <= MAX_WAIT_TIME:
1421 vapp = vca.get_vapp(vca.get_vdc(self.tenant_name), vapp_name)
1422 if not vapp:
1423 self.logger.debug("delete_vminstance(): Failed to get vm by given {} vm uuid".format(vm__vim_uuid))
1424 return -1, "delete_vminstance(): Failed to get vm by given {} vm uuid".format(vm__vim_uuid)
bayramovef390722016-09-27 03:34:46 -07001425
kate13ab2c42016-12-23 01:34:24 -08001426 power_off_task = vapp.poweroff()
1427 if type(power_off_task) is GenericTask:
1428 result = vca.block_until_completed(power_off_task)
1429 if result:
1430 powered_off = True
1431 break
1432 else:
1433 self.logger.info("Wait for vApp {} to power off".format(vapp_name))
1434 time.sleep(INTERVAL_TIME)
1435
1436 wait_time +=INTERVAL_TIME
1437 if not powered_off:
1438 self.logger.debug("delete_vminstance(): Failed to power off VM instance {} ".format(vm__vim_uuid))
1439 else:
1440 self.logger.info("delete_vminstance(): Powered off VM instance {} ".format(vm__vim_uuid))
1441
1442 #Undeploy vApp
1443 self.logger.info("Undeploy vApp {}".format(vapp_name))
1444 wait_time = 0
1445 undeployed = False
1446 while wait_time <= MAX_WAIT_TIME:
1447 vapp = vca.get_vapp(vca.get_vdc(self.tenant_name), vapp_name)
1448 if not vapp:
1449 self.logger.debug("delete_vminstance(): Failed to get vm by given {} vm uuid".format(vm__vim_uuid))
1450 return -1, "delete_vminstance(): Failed to get vm by given {} vm uuid".format(vm__vim_uuid)
1451 undeploy_task = vapp.undeploy(action='powerOff')
1452
1453 if type(undeploy_task) is GenericTask:
1454 result = vca.block_until_completed(undeploy_task)
1455 if result:
1456 undeployed = True
1457 break
1458 else:
1459 self.logger.debug("Wait for vApp {} to undeploy".format(vapp_name))
1460 time.sleep(INTERVAL_TIME)
1461
1462 wait_time +=INTERVAL_TIME
1463
1464 if not undeployed:
1465 self.logger.debug("delete_vminstance(): Failed to undeploy vApp {} ".format(vm__vim_uuid))
1466
1467 # delete vapp
1468 self.logger.info("Start deletion of vApp {} ".format(vapp_name))
1469 vapp = vca.get_vapp(vca.get_vdc(self.tenant_name), vapp_name)
1470
1471 if vapp is not None:
1472 wait_time = 0
1473 result = False
1474
1475 while wait_time <= MAX_WAIT_TIME:
1476 vapp = vca.get_vapp(vca.get_vdc(self.tenant_name), vapp_name)
1477 if not vapp:
1478 self.logger.debug("delete_vminstance(): Failed to get vm by given {} vm uuid".format(vm__vim_uuid))
1479 return -1, "delete_vminstance(): Failed to get vm by given {} vm uuid".format(vm__vim_uuid)
1480
1481 delete_task = vapp.delete()
1482
1483 if type(delete_task) is GenericTask:
1484 vca.block_until_completed(delete_task)
1485 result = vca.block_until_completed(delete_task)
1486 if result:
1487 break
1488 else:
1489 self.logger.debug("Wait for vApp {} to delete".format(vapp_name))
1490 time.sleep(INTERVAL_TIME)
1491
1492 wait_time +=INTERVAL_TIME
1493
1494 if not result:
bayramovbd6160f2016-09-28 04:12:05 +04001495 self.logger.debug("delete_vminstance(): Failed delete uuid {} ".format(vm__vim_uuid))
bayramovef390722016-09-27 03:34:46 -07001496
bayramovef390722016-09-27 03:34:46 -07001497 except:
1498 self.logger.debug(traceback.format_exc())
bayramovbd6160f2016-09-28 04:12:05 +04001499 raise vimconn.vimconnException("delete_vminstance(): Failed delete vm instance {}".format(vm__vim_uuid))
bayramovef390722016-09-27 03:34:46 -07001500
bayramovbd6160f2016-09-28 04:12:05 +04001501 if vca.get_vapp(vca.get_vdc(self.tenant_name), vapp_name) is None:
kate13ab2c42016-12-23 01:34:24 -08001502 self.logger.info("Deleted vm instance {} sccessfully".format(vm__vim_uuid))
bayramovbd6160f2016-09-28 04:12:05 +04001503 return vm__vim_uuid
1504 else:
1505 raise vimconn.vimconnException("delete_vminstance(): Failed delete vm instance {}".format(vm__vim_uuid))
bayramov325fa1c2016-09-08 01:42:46 -07001506
1507 def refresh_vms_status(self, vm_list):
bayramovef390722016-09-27 03:34:46 -07001508 """Get the status of the virtual machines and their interfaces/ports
bayramov325fa1c2016-09-08 01:42:46 -07001509 Params: the list of VM identifiers
1510 Returns a dictionary with:
1511 vm_id: #VIM id of this Virtual Machine
1512 status: #Mandatory. Text with one of:
1513 # DELETED (not found at vim)
bayramovef390722016-09-27 03:34:46 -07001514 # VIM_ERROR (Cannot connect to VIM, VIM response error, ...)
bayramov325fa1c2016-09-08 01:42:46 -07001515 # OTHER (Vim reported other status not understood)
1516 # ERROR (VIM indicates an ERROR status)
bayramovef390722016-09-27 03:34:46 -07001517 # ACTIVE, PAUSED, SUSPENDED, INACTIVE (not running),
bayramov325fa1c2016-09-08 01:42:46 -07001518 # CREATING (on building process), ERROR
1519 # ACTIVE:NoMgmtIP (Active but any of its interface has an IP address
1520 #
bayramovef390722016-09-27 03:34:46 -07001521 error_msg: #Text with VIM error message, if any. Or the VIM connection ERROR
bayramov325fa1c2016-09-08 01:42:46 -07001522 vim_info: #Text with plain information obtained from vim (yaml.safe_dump)
1523 interfaces:
1524 - vim_info: #Text with plain information obtained from vim (yaml.safe_dump)
1525 mac_address: #Text format XX:XX:XX:XX:XX:XX
1526 vim_net_id: #network id where this interface is connected
1527 vim_interface_id: #interface/port VIM id
1528 ip_address: #null, or text with IPv4, IPv6 address
bayramovef390722016-09-27 03:34:46 -07001529 """
bayramov325fa1c2016-09-08 01:42:46 -07001530
bayramovef390722016-09-27 03:34:46 -07001531 self.logger.debug("Client requesting refresh vm status for {} ".format(vm_list))
1532 vca = self.connect()
1533 if not vca:
1534 raise vimconn.vimconnConnectionException("self.connect() is failed.")
bayramov325fa1c2016-09-08 01:42:46 -07001535
bayramovef390722016-09-27 03:34:46 -07001536 vdc = vca.get_vdc(self.tenant_name)
1537 if vdc is None:
bayramovbd6160f2016-09-28 04:12:05 +04001538 raise vimconn.vimconnException("Failed to get a reference of VDC for a tenant {}".format(self.tenant_name))
bayramovef390722016-09-27 03:34:46 -07001539
1540 vms_dict = {}
1541 for vmuuid in vm_list:
1542 vmname = self.get_namebyvappid(vca, vdc, vmuuid)
1543 if vmname is not None:
1544
1545 the_vapp = vca.get_vapp(vdc, vmname)
1546 vm_info = the_vapp.get_vms_details()
1547 vm_status = vm_info[0]['status']
1548
bayramov5761ad12016-10-04 09:00:30 +04001549 vm_dict = {'status': vcdStatusCode2manoFormat[the_vapp.me.get_status()],
1550 'error_msg': vcdStatusCode2manoFormat[the_vapp.me.get_status()],
1551 'vim_info': yaml.safe_dump(the_vapp.get_vms_details()), 'interfaces': []}
bayramovef390722016-09-27 03:34:46 -07001552
1553 # get networks
1554 try:
1555 vm_app_networks = the_vapp.get_vms_network_info()
1556 for vapp_network in vm_app_networks:
1557 for vm_network in vapp_network:
1558 if vm_network['name'] == vmname:
bayramov5761ad12016-10-04 09:00:30 +04001559 interface = {"mac_address": vm_network['mac'],
bhangare2c855072016-12-27 01:41:28 -08001560 "vim_net_id": self.get_network_id_by_name(vm_network['network_name']),
1561 "vim_interface_id": self.get_network_id_by_name(vm_network['network_name']),
bayramov5761ad12016-10-04 09:00:30 +04001562 'ip_address': vm_network['ip']}
bayramovef390722016-09-27 03:34:46 -07001563 # interface['vim_info'] = yaml.safe_dump(vm_network)
bayramovef390722016-09-27 03:34:46 -07001564 vm_dict["interfaces"].append(interface)
1565 # add a vm to vm dict
1566 vms_dict.setdefault(vmuuid, vm_dict)
1567 except KeyError:
1568 self.logger.debug("Error in respond {}".format(KeyError.message))
1569 self.logger.debug(traceback.format_exc())
1570
1571 return vms_dict
1572
1573 def action_vminstance(self, vm__vim_uuid=None, action_dict=None):
1574 """Send and action over a VM instance from VIM
1575 Returns the vm_id if the action was successfully sent to the VIM"""
1576
1577 self.logger.debug("Received action for vm {} and action dict {}".format(vm__vim_uuid, action_dict))
1578 if vm__vim_uuid is None or action_dict is None:
bayramovbd6160f2016-09-28 04:12:05 +04001579 raise vimconn.vimconnException("Invalid request. VM id or action is None.")
bayramovef390722016-09-27 03:34:46 -07001580
1581 vca = self.connect()
1582 if not vca:
1583 raise vimconn.vimconnConnectionException("self.connect() is failed.")
1584
1585 vdc = vca.get_vdc(self.tenant_name)
1586 if vdc is None:
1587 return -1, "Failed to get a reference of VDC for a tenant {}".format(self.tenant_name)
1588
1589 vapp_name = self.get_namebyvappid(vca, vdc, vm__vim_uuid)
1590 if vapp_name is None:
1591 self.logger.debug("action_vminstance(): Failed to get vm by given {} vm uuid".format(vm__vim_uuid))
bayramovbd6160f2016-09-28 04:12:05 +04001592 raise vimconn.vimconnException("Failed to get vm by given {} vm uuid".format(vm__vim_uuid))
bayramovef390722016-09-27 03:34:46 -07001593 else:
1594 self.logger.info("Action_vminstance vApp {} and UUID {}".format(vapp_name, vm__vim_uuid))
1595
1596 try:
1597 the_vapp = vca.get_vapp(vdc, vapp_name)
1598 # TODO fix all status
1599 if "start" in action_dict:
1600 if action_dict["start"] == "rebuild":
1601 the_vapp.deploy(powerOn=True)
1602 else:
1603 vm_info = the_vapp.get_vms_details()
1604 vm_status = vm_info[0]['status']
1605 if vm_status == "Suspended":
1606 the_vapp.poweron()
1607 elif vm_status.status == "Powered off":
1608 the_vapp.poweron()
1609 elif "pause" in action_dict:
1610 pass
bayramovb6ffe792016-09-28 11:50:56 +04001611 ## server.pause()
bayramovef390722016-09-27 03:34:46 -07001612 elif "resume" in action_dict:
1613 pass
bayramovb6ffe792016-09-28 11:50:56 +04001614 ## server.resume()
bayramovef390722016-09-27 03:34:46 -07001615 elif "shutoff" in action_dict or "shutdown" in action_dict:
1616 the_vapp.shutdown()
1617 elif "forceOff" in action_dict:
1618 the_vapp.reset()
1619 elif "terminate" in action_dict:
1620 the_vapp.delete()
1621 # elif "createImage" in action_dict:
1622 # server.create_image()
1623 else:
1624 pass
1625 except:
1626 pass
1627
1628 def get_vminstance_console(self, vm_id, console_type="vnc"):
1629 """
bayramov325fa1c2016-09-08 01:42:46 -07001630 Get a console for the virtual machine
1631 Params:
1632 vm_id: uuid of the VM
1633 console_type, can be:
bayramovef390722016-09-27 03:34:46 -07001634 "novnc" (by default), "xvpvnc" for VNC types,
bayramov325fa1c2016-09-08 01:42:46 -07001635 "rdp-html5" for RDP types, "spice-html5" for SPICE types
1636 Returns dict with the console parameters:
1637 protocol: ssh, ftp, http, https, ...
bayramovef390722016-09-27 03:34:46 -07001638 server: usually ip address
1639 port: the http, ssh, ... port
1640 suffix: extra text, e.g. the http path and query string
1641 """
bayramovbd6160f2016-09-28 04:12:05 +04001642 raise vimconn.vimconnNotImplemented("Should have implemented this")
bayramov325fa1c2016-09-08 01:42:46 -07001643
bayramovef390722016-09-27 03:34:46 -07001644 # NOT USED METHODS in current version
bayramov325fa1c2016-09-08 01:42:46 -07001645
1646 def host_vim2gui(self, host, server_dict):
bayramov5761ad12016-10-04 09:00:30 +04001647 """Transform host dictionary from VIM format to GUI format,
bayramov325fa1c2016-09-08 01:42:46 -07001648 and append to the server_dict
bayramov5761ad12016-10-04 09:00:30 +04001649 """
bayramovbd6160f2016-09-28 04:12:05 +04001650 raise vimconn.vimconnNotImplemented("Should have implemented this")
bayramov325fa1c2016-09-08 01:42:46 -07001651
1652 def get_hosts_info(self):
bayramov5761ad12016-10-04 09:00:30 +04001653 """Get the information of deployed hosts
1654 Returns the hosts content"""
bayramovbd6160f2016-09-28 04:12:05 +04001655 raise vimconn.vimconnNotImplemented("Should have implemented this")
bayramov325fa1c2016-09-08 01:42:46 -07001656
1657 def get_hosts(self, vim_tenant):
bayramov5761ad12016-10-04 09:00:30 +04001658 """Get the hosts and deployed instances
1659 Returns the hosts content"""
bayramovbd6160f2016-09-28 04:12:05 +04001660 raise vimconn.vimconnNotImplemented("Should have implemented this")
bayramov325fa1c2016-09-08 01:42:46 -07001661
1662 def get_processor_rankings(self):
bayramov5761ad12016-10-04 09:00:30 +04001663 """Get the processor rankings in the VIM database"""
bayramovbd6160f2016-09-28 04:12:05 +04001664 raise vimconn.vimconnNotImplemented("Should have implemented this")
bayramov325fa1c2016-09-08 01:42:46 -07001665
1666 def new_host(self, host_data):
bayramov5761ad12016-10-04 09:00:30 +04001667 """Adds a new host to VIM"""
bayramov325fa1c2016-09-08 01:42:46 -07001668 '''Returns status code of the VIM response'''
bayramovbd6160f2016-09-28 04:12:05 +04001669 raise vimconn.vimconnNotImplemented("Should have implemented this")
bayramov325fa1c2016-09-08 01:42:46 -07001670
1671 def new_external_port(self, port_data):
bayramov5761ad12016-10-04 09:00:30 +04001672 """Adds a external port to VIM"""
bayramov325fa1c2016-09-08 01:42:46 -07001673 '''Returns the port identifier'''
bayramovbd6160f2016-09-28 04:12:05 +04001674 raise vimconn.vimconnNotImplemented("Should have implemented this")
bayramov325fa1c2016-09-08 01:42:46 -07001675
bayramovef390722016-09-27 03:34:46 -07001676 def new_external_network(self, net_name, net_type):
bayramov5761ad12016-10-04 09:00:30 +04001677 """Adds a external network to VIM (shared)"""
bayramov325fa1c2016-09-08 01:42:46 -07001678 '''Returns the network identifier'''
bayramovbd6160f2016-09-28 04:12:05 +04001679 raise vimconn.vimconnNotImplemented("Should have implemented this")
bayramov325fa1c2016-09-08 01:42:46 -07001680
1681 def connect_port_network(self, port_id, network_id, admin=False):
bayramov5761ad12016-10-04 09:00:30 +04001682 """Connects a external port to a network"""
bayramov325fa1c2016-09-08 01:42:46 -07001683 '''Returns status code of the VIM response'''
bayramovbd6160f2016-09-28 04:12:05 +04001684 raise vimconn.vimconnNotImplemented("Should have implemented this")
bayramov325fa1c2016-09-08 01:42:46 -07001685
1686 def new_vminstancefromJSON(self, vm_data):
bayramov5761ad12016-10-04 09:00:30 +04001687 """Adds a VM instance to VIM"""
bayramov325fa1c2016-09-08 01:42:46 -07001688 '''Returns the instance identifier'''
bayramovbd6160f2016-09-28 04:12:05 +04001689 raise vimconn.vimconnNotImplemented("Should have implemented this")
bayramov325fa1c2016-09-08 01:42:46 -07001690
kate15f1c382016-12-15 01:12:40 -08001691 def get_network_name_by_id(self, network_uuid=None):
bayramovef390722016-09-27 03:34:46 -07001692 """Method gets vcloud director network named based on supplied uuid.
1693
1694 Args:
kate15f1c382016-12-15 01:12:40 -08001695 network_uuid: network_id
bayramovef390722016-09-27 03:34:46 -07001696
1697 Returns:
1698 The return network name.
1699 """
1700
1701 vca = self.connect()
1702 if not vca:
kate15f1c382016-12-15 01:12:40 -08001703 raise vimconn.vimconnConnectionException("self.connect() is failed.")
bayramovef390722016-09-27 03:34:46 -07001704
kate15f1c382016-12-15 01:12:40 -08001705 if not network_uuid:
bayramovef390722016-09-27 03:34:46 -07001706 return None
1707
1708 try:
kate15f1c382016-12-15 01:12:40 -08001709 org_dict = self.get_org(self.org_uuid)
1710 if 'networks' in org_dict:
1711 org_network_dict = org_dict['networks']
1712 for net_uuid in org_network_dict:
1713 if net_uuid == network_uuid:
1714 return org_network_dict[net_uuid]
bayramovef390722016-09-27 03:34:46 -07001715 except:
1716 self.logger.debug("Exception in get_network_name_by_id")
1717 self.logger.debug(traceback.format_exc())
1718
1719 return None
1720
bhangare2c855072016-12-27 01:41:28 -08001721 def get_network_id_by_name(self, network_name=None):
1722 """Method gets vcloud director network uuid based on supplied name.
1723
1724 Args:
1725 network_name: network_name
1726 Returns:
1727 The return network uuid.
1728 network_uuid: network_id
1729 """
1730
1731 vca = self.connect()
1732 if not vca:
1733 raise vimconn.vimconnConnectionException("self.connect() is failed.")
1734
1735 if not network_name:
1736 self.logger.debug("get_network_id_by_name() : Network name is empty")
1737 return None
1738
1739 try:
1740 org_dict = self.get_org(self.org_uuid)
1741 if org_dict and 'networks' in org_dict:
1742 org_network_dict = org_dict['networks']
1743 for net_uuid,net_name in org_network_dict.iteritems():
1744 if net_name == network_name:
1745 return net_uuid
1746
1747 except KeyError as exp:
1748 self.logger.debug("get_network_id_by_name() : KeyError- {} ".format(exp))
1749
1750 return None
1751
bayramovef390722016-09-27 03:34:46 -07001752 def list_org_action(self):
1753 """
1754 Method leverages vCloud director and query for available organization for particular user
1755
1756 Args:
1757 vca - is active VCA connection.
1758 vdc_name - is a vdc name that will be used to query vms action
1759
1760 Returns:
1761 The return XML respond
1762 """
1763
1764 vca = self.connect()
1765 if not vca:
1766 raise vimconn.vimconnConnectionException("self.connect() is failed")
1767
1768 url_list = [vca.host, '/api/org']
1769 vm_list_rest_call = ''.join(url_list)
1770
1771 if not (not vca.vcloud_session or not vca.vcloud_session.organization):
1772 response = Http.get(url=vm_list_rest_call,
1773 headers=vca.vcloud_session.get_vcloud_headers(),
1774 verify=vca.verify,
1775 logger=vca.logger)
1776 if response.status_code == requests.codes.ok:
1777 return response.content
1778
1779 return None
1780
1781 def get_org_action(self, org_uuid=None):
1782 """
1783 Method leverages vCloud director and retrieve available object fdr organization.
1784
1785 Args:
1786 vca - is active VCA connection.
1787 vdc_name - is a vdc name that will be used to query vms action
1788
1789 Returns:
1790 The return XML respond
1791 """
1792
1793 vca = self.connect()
1794 if not vca:
1795 raise vimconn.vimconnConnectionException("self.connect() is failed")
1796
1797 if org_uuid is None:
1798 return None
1799
1800 url_list = [vca.host, '/api/org/', org_uuid]
1801 vm_list_rest_call = ''.join(url_list)
1802
1803 if not (not vca.vcloud_session or not vca.vcloud_session.organization):
1804 response = Http.get(url=vm_list_rest_call,
1805 headers=vca.vcloud_session.get_vcloud_headers(),
1806 verify=vca.verify,
1807 logger=vca.logger)
1808 if response.status_code == requests.codes.ok:
1809 return response.content
1810
1811 return None
1812
1813 def get_org(self, org_uuid=None):
1814 """
1815 Method retrieves available organization in vCloud Director
1816
1817 Args:
bayramovb6ffe792016-09-28 11:50:56 +04001818 org_uuid - is a organization uuid.
bayramovef390722016-09-27 03:34:46 -07001819
1820 Returns:
bayramovb6ffe792016-09-28 11:50:56 +04001821 The return dictionary with following key
1822 "network" - for network list under the org
1823 "catalogs" - for network list under the org
1824 "vdcs" - for vdc list under org
bayramovef390722016-09-27 03:34:46 -07001825 """
1826
1827 org_dict = {}
bayramovef390722016-09-27 03:34:46 -07001828 vca = self.connect()
1829 if not vca:
1830 raise vimconn.vimconnConnectionException("self.connect() is failed")
1831
1832 if org_uuid is None:
1833 return org_dict
1834
1835 content = self.get_org_action(org_uuid=org_uuid)
1836 try:
1837 vdc_list = {}
1838 network_list = {}
1839 catalog_list = {}
1840 vm_list_xmlroot = XmlElementTree.fromstring(content)
1841 for child in vm_list_xmlroot:
1842 if child.attrib['type'] == 'application/vnd.vmware.vcloud.vdc+xml':
1843 vdc_list[child.attrib['href'].split("/")[-1:][0]] = child.attrib['name']
1844 org_dict['vdcs'] = vdc_list
1845 if child.attrib['type'] == 'application/vnd.vmware.vcloud.orgNetwork+xml':
1846 network_list[child.attrib['href'].split("/")[-1:][0]] = child.attrib['name']
1847 org_dict['networks'] = network_list
1848 if child.attrib['type'] == 'application/vnd.vmware.vcloud.catalog+xml':
1849 catalog_list[child.attrib['href'].split("/")[-1:][0]] = child.attrib['name']
1850 org_dict['catalogs'] = catalog_list
1851 except:
1852 pass
1853
1854 return org_dict
1855
1856 def get_org_list(self):
1857 """
1858 Method retrieves available organization in vCloud Director
1859
1860 Args:
1861 vca - is active VCA connection.
1862
1863 Returns:
1864 The return dictionary and key for each entry VDC UUID
1865 """
1866
1867 org_dict = {}
1868 vca = self.connect()
1869 if not vca:
1870 raise vimconn.vimconnConnectionException("self.connect() is failed")
1871
1872 content = self.list_org_action()
1873 try:
1874 vm_list_xmlroot = XmlElementTree.fromstring(content)
1875 for vm_xml in vm_list_xmlroot:
1876 if vm_xml.tag.split("}")[1] == 'Org':
1877 org_uuid = vm_xml.attrib['href'].split('/')[-1:]
1878 org_dict[org_uuid[0]] = vm_xml.attrib['name']
1879 except:
1880 pass
1881
1882 return org_dict
1883
1884 def vms_view_action(self, vdc_name=None):
1885 """ Method leverages vCloud director vms query call
1886
1887 Args:
1888 vca - is active VCA connection.
1889 vdc_name - is a vdc name that will be used to query vms action
1890
1891 Returns:
1892 The return XML respond
1893 """
1894 vca = self.connect()
1895 if vdc_name is None:
1896 return None
1897
1898 url_list = [vca.host, '/api/vms/query']
1899 vm_list_rest_call = ''.join(url_list)
1900
1901 if not (not vca.vcloud_session or not vca.vcloud_session.organization):
1902 refs = filter(lambda ref: ref.name == vdc_name and ref.type_ == 'application/vnd.vmware.vcloud.vdc+xml',
1903 vca.vcloud_session.organization.Link)
1904 if len(refs) == 1:
1905 response = Http.get(url=vm_list_rest_call,
1906 headers=vca.vcloud_session.get_vcloud_headers(),
1907 verify=vca.verify,
1908 logger=vca.logger)
1909 if response.status_code == requests.codes.ok:
1910 return response.content
1911
1912 return None
1913
1914 def get_vapp_list(self, vdc_name=None):
1915 """
1916 Method retrieves vApp list deployed vCloud director and returns a dictionary
1917 contains a list of all vapp deployed for queried VDC.
1918 The key for a dictionary is vApp UUID
1919
1920
1921 Args:
1922 vca - is active VCA connection.
1923 vdc_name - is a vdc name that will be used to query vms action
1924
1925 Returns:
1926 The return dictionary and key for each entry vapp UUID
1927 """
1928
1929 vapp_dict = {}
1930 if vdc_name is None:
1931 return vapp_dict
1932
1933 content = self.vms_view_action(vdc_name=vdc_name)
1934 try:
1935 vm_list_xmlroot = XmlElementTree.fromstring(content)
1936 for vm_xml in vm_list_xmlroot:
1937 if vm_xml.tag.split("}")[1] == 'VMRecord':
1938 if vm_xml.attrib['isVAppTemplate'] == 'true':
1939 rawuuid = vm_xml.attrib['container'].split('/')[-1:]
1940 if 'vappTemplate-' in rawuuid[0]:
1941 # vm in format vappTemplate-e63d40e7-4ff5-4c6d-851f-96c1e4da86a5 we remove
1942 # vm and use raw UUID as key
1943 vapp_dict[rawuuid[0][13:]] = vm_xml.attrib
1944 except:
1945 pass
1946
1947 return vapp_dict
1948
1949 def get_vm_list(self, vdc_name=None):
1950 """
1951 Method retrieves VM's list deployed vCloud director. It returns a dictionary
1952 contains a list of all VM's deployed for queried VDC.
1953 The key for a dictionary is VM UUID
1954
1955
1956 Args:
1957 vca - is active VCA connection.
1958 vdc_name - is a vdc name that will be used to query vms action
1959
1960 Returns:
1961 The return dictionary and key for each entry vapp UUID
1962 """
1963 vm_dict = {}
1964
1965 if vdc_name is None:
1966 return vm_dict
1967
1968 content = self.vms_view_action(vdc_name=vdc_name)
1969 try:
1970 vm_list_xmlroot = XmlElementTree.fromstring(content)
1971 for vm_xml in vm_list_xmlroot:
1972 if vm_xml.tag.split("}")[1] == 'VMRecord':
1973 if vm_xml.attrib['isVAppTemplate'] == 'false':
1974 rawuuid = vm_xml.attrib['href'].split('/')[-1:]
1975 if 'vm-' in rawuuid[0]:
1976 # vm in format vm-e63d40e7-4ff5-4c6d-851f-96c1e4da86a5 we remove
1977 # vm and use raw UUID as key
1978 vm_dict[rawuuid[0][3:]] = vm_xml.attrib
1979 except:
1980 pass
1981
1982 return vm_dict
1983
1984 def get_vapp(self, vdc_name=None, vapp_name=None, isuuid=False):
1985 """
bayramovb6ffe792016-09-28 11:50:56 +04001986 Method retrieves VM deployed vCloud director. It returns VM attribute as dictionary
bayramovef390722016-09-27 03:34:46 -07001987 contains a list of all VM's deployed for queried VDC.
1988 The key for a dictionary is VM UUID
1989
1990
1991 Args:
1992 vca - is active VCA connection.
1993 vdc_name - is a vdc name that will be used to query vms action
1994
1995 Returns:
1996 The return dictionary and key for each entry vapp UUID
1997 """
1998 vm_dict = {}
1999 vca = self.connect()
2000 if not vca:
2001 raise vimconn.vimconnConnectionException("self.connect() is failed")
2002
2003 if vdc_name is None:
2004 return vm_dict
2005
2006 content = self.vms_view_action(vdc_name=vdc_name)
2007 try:
2008 vm_list_xmlroot = XmlElementTree.fromstring(content)
2009 for vm_xml in vm_list_xmlroot:
bayramovb6ffe792016-09-28 11:50:56 +04002010 if vm_xml.tag.split("}")[1] == 'VMRecord' and vm_xml.attrib['isVAppTemplate'] == 'false':
2011 # lookup done by UUID
bayramovef390722016-09-27 03:34:46 -07002012 if isuuid:
bayramovef390722016-09-27 03:34:46 -07002013 if vapp_name in vm_xml.attrib['container']:
2014 rawuuid = vm_xml.attrib['href'].split('/')[-1:]
2015 if 'vm-' in rawuuid[0]:
bayramovef390722016-09-27 03:34:46 -07002016 vm_dict[rawuuid[0][3:]] = vm_xml.attrib
bayramovb6ffe792016-09-28 11:50:56 +04002017 break
2018 # lookup done by Name
2019 else:
2020 if vapp_name in vm_xml.attrib['name']:
2021 rawuuid = vm_xml.attrib['href'].split('/')[-1:]
2022 if 'vm-' in rawuuid[0]:
2023 vm_dict[rawuuid[0][3:]] = vm_xml.attrib
2024 break
bayramovef390722016-09-27 03:34:46 -07002025 except:
2026 pass
2027
2028 return vm_dict
2029
2030 def get_network_action(self, network_uuid=None):
2031 """
2032 Method leverages vCloud director and query network based on network uuid
2033
2034 Args:
2035 vca - is active VCA connection.
2036 network_uuid - is a network uuid
2037
2038 Returns:
2039 The return XML respond
2040 """
2041
2042 vca = self.connect()
2043 if not vca:
2044 raise vimconn.vimconnConnectionException("self.connect() is failed")
2045
2046 if network_uuid is None:
2047 return None
2048
2049 url_list = [vca.host, '/api/network/', network_uuid]
2050 vm_list_rest_call = ''.join(url_list)
2051
2052 if not (not vca.vcloud_session or not vca.vcloud_session.organization):
2053 response = Http.get(url=vm_list_rest_call,
2054 headers=vca.vcloud_session.get_vcloud_headers(),
2055 verify=vca.verify,
2056 logger=vca.logger)
2057 if response.status_code == requests.codes.ok:
2058 return response.content
2059
2060 return None
2061
2062 def get_vcd_network(self, network_uuid=None):
2063 """
2064 Method retrieves available network from vCloud Director
2065
2066 Args:
2067 network_uuid - is VCD network UUID
2068
2069 Each element serialized as key : value pair
2070
2071 Following keys available for access. network_configuration['Gateway'}
2072 <Configuration>
2073 <IpScopes>
2074 <IpScope>
2075 <IsInherited>true</IsInherited>
2076 <Gateway>172.16.252.100</Gateway>
2077 <Netmask>255.255.255.0</Netmask>
2078 <Dns1>172.16.254.201</Dns1>
2079 <Dns2>172.16.254.202</Dns2>
2080 <DnsSuffix>vmwarelab.edu</DnsSuffix>
2081 <IsEnabled>true</IsEnabled>
2082 <IpRanges>
2083 <IpRange>
2084 <StartAddress>172.16.252.1</StartAddress>
2085 <EndAddress>172.16.252.99</EndAddress>
2086 </IpRange>
2087 </IpRanges>
2088 </IpScope>
2089 </IpScopes>
2090 <FenceMode>bridged</FenceMode>
2091
2092 Returns:
2093 The return dictionary and key for each entry vapp UUID
2094 """
2095
2096 network_configuration = {}
2097 if network_uuid is None:
2098 return network_uuid
2099
2100 content = self.get_network_action(network_uuid=network_uuid)
2101 try:
2102 vm_list_xmlroot = XmlElementTree.fromstring(content)
2103
2104 network_configuration['status'] = vm_list_xmlroot.get("status")
2105 network_configuration['name'] = vm_list_xmlroot.get("name")
2106 network_configuration['uuid'] = vm_list_xmlroot.get("id").split(":")[3]
2107
2108 for child in vm_list_xmlroot:
2109 if child.tag.split("}")[1] == 'IsShared':
2110 network_configuration['isShared'] = child.text.strip()
2111 if child.tag.split("}")[1] == 'Configuration':
2112 for configuration in child.iter():
2113 tagKey = configuration.tag.split("}")[1].strip()
2114 if tagKey != "":
2115 network_configuration[tagKey] = configuration.text.strip()
2116 return network_configuration
2117 except:
2118 pass
2119
2120 return network_configuration
2121
2122 def delete_network_action(self, network_uuid=None):
2123 """
2124 Method delete given network from vCloud director
2125
2126 Args:
2127 network_uuid - is a network uuid that client wish to delete
2128
2129 Returns:
2130 The return None or XML respond or false
2131 """
2132
2133 vca = self.connect_as_admin()
2134 if not vca:
2135 raise vimconn.vimconnConnectionException("self.connect() is failed")
2136 if network_uuid is None:
2137 return False
2138
2139 url_list = [vca.host, '/api/admin/network/', network_uuid]
2140 vm_list_rest_call = ''.join(url_list)
2141
2142 if not (not vca.vcloud_session or not vca.vcloud_session.organization):
2143 response = Http.delete(url=vm_list_rest_call,
2144 headers=vca.vcloud_session.get_vcloud_headers(),
2145 verify=vca.verify,
2146 logger=vca.logger)
2147
2148 if response.status_code == 202:
2149 return True
2150
2151 return False
2152
bhangare0e571a92017-01-12 04:02:23 -08002153 def create_network(self, network_name=None, net_type='bridge', parent_network_uuid=None,
2154 ip_profile=None, isshared='true'):
bayramovef390722016-09-27 03:34:46 -07002155 """
2156 Method create network in vCloud director
2157
2158 Args:
2159 network_name - is network name to be created.
bhangare0e571a92017-01-12 04:02:23 -08002160 net_type - can be 'bridge','data','ptp','mgmt'.
2161 ip_profile is a dict containing the IP parameters of the network
2162 isshared - is a boolean
bayramovef390722016-09-27 03:34:46 -07002163 parent_network_uuid - is parent provider vdc network that will be used for mapping.
2164 It optional attribute. by default if no parent network indicate the first available will be used.
2165
2166 Returns:
2167 The return network uuid or return None
2168 """
2169
bayramov5761ad12016-10-04 09:00:30 +04002170 new_network_name = [network_name, '-', str(uuid.uuid4())]
2171 content = self.create_network_rest(network_name=''.join(new_network_name),
bhangare0e571a92017-01-12 04:02:23 -08002172 ip_profile=ip_profile,
2173 net_type=net_type,
bayramovef390722016-09-27 03:34:46 -07002174 parent_network_uuid=parent_network_uuid,
2175 isshared=isshared)
2176 if content is None:
2177 self.logger.debug("Failed create network {}.".format(network_name))
2178 return None
2179
2180 try:
2181 vm_list_xmlroot = XmlElementTree.fromstring(content)
2182 vcd_uuid = vm_list_xmlroot.get('id').split(":")
2183 if len(vcd_uuid) == 4:
2184 self.logger.info("Create new network name: {} uuid: {}".format(network_name, vcd_uuid[3]))
2185 return vcd_uuid[3]
2186 except:
2187 self.logger.debug("Failed create network {}".format(network_name))
2188 return None
2189
bhangare0e571a92017-01-12 04:02:23 -08002190 def create_network_rest(self, network_name=None, net_type='bridge', parent_network_uuid=None,
2191 ip_profile=None, isshared='true'):
bayramovef390722016-09-27 03:34:46 -07002192 """
2193 Method create network in vCloud director
2194
2195 Args:
2196 network_name - is network name to be created.
bhangare0e571a92017-01-12 04:02:23 -08002197 net_type - can be 'bridge','data','ptp','mgmt'.
2198 ip_profile is a dict containing the IP parameters of the network
2199 isshared - is a boolean
bayramovef390722016-09-27 03:34:46 -07002200 parent_network_uuid - is parent provider vdc network that will be used for mapping.
2201 It optional attribute. by default if no parent network indicate the first available will be used.
2202
2203 Returns:
2204 The return network uuid or return None
2205 """
2206
2207 vca = self.connect_as_admin()
2208 if not vca:
bayramov5761ad12016-10-04 09:00:30 +04002209 raise vimconn.vimconnConnectionException("self.connect() is failed.")
bayramovef390722016-09-27 03:34:46 -07002210 if network_name is None:
2211 return None
2212
2213 url_list = [vca.host, '/api/admin/vdc/', self.tenant_id]
2214 vm_list_rest_call = ''.join(url_list)
2215 if not (not vca.vcloud_session or not vca.vcloud_session.organization):
2216 response = Http.get(url=vm_list_rest_call,
2217 headers=vca.vcloud_session.get_vcloud_headers(),
2218 verify=vca.verify,
2219 logger=vca.logger)
2220
2221 provider_network = None
2222 available_networks = None
2223 add_vdc_rest_url = None
2224
2225 if response.status_code != requests.codes.ok:
2226 self.logger.debug("REST API call {} failed. Return status code {}".format(vm_list_rest_call,
2227 response.status_code))
2228 return None
2229 else:
2230 try:
2231 vm_list_xmlroot = XmlElementTree.fromstring(response.content)
2232 for child in vm_list_xmlroot:
2233 if child.tag.split("}")[1] == 'ProviderVdcReference':
2234 provider_network = child.attrib.get('href')
2235 # application/vnd.vmware.admin.providervdc+xml
2236 if child.tag.split("}")[1] == 'Link':
2237 if child.attrib.get('type') == 'application/vnd.vmware.vcloud.orgVdcNetwork+xml' \
2238 and child.attrib.get('rel') == 'add':
2239 add_vdc_rest_url = child.attrib.get('href')
2240 except:
2241 self.logger.debug("Failed parse respond for rest api call {}".format(vm_list_rest_call))
2242 self.logger.debug("Respond body {}".format(response.content))
2243 return None
2244
2245 # find pvdc provided available network
2246 response = Http.get(url=provider_network,
2247 headers=vca.vcloud_session.get_vcloud_headers(),
2248 verify=vca.verify,
2249 logger=vca.logger)
2250 if response.status_code != requests.codes.ok:
2251 self.logger.debug("REST API call {} failed. Return status code {}".format(vm_list_rest_call,
2252 response.status_code))
2253 return None
2254
2255 # available_networks.split("/")[-1]
2256
2257 if parent_network_uuid is None:
2258 try:
2259 vm_list_xmlroot = XmlElementTree.fromstring(response.content)
2260 for child in vm_list_xmlroot.iter():
2261 if child.tag.split("}")[1] == 'AvailableNetworks':
2262 for networks in child.iter():
2263 # application/vnd.vmware.admin.network+xml
2264 if networks.attrib.get('href') is not None:
2265 available_networks = networks.attrib.get('href')
2266 break
2267 except:
2268 return None
2269
bhangare0e571a92017-01-12 04:02:23 -08002270 #Configure IP profile of the network
2271 ip_profile = ip_profile if ip_profile is not None else DEFAULT_IP_PROFILE
2272
2273 gateway_address=ip_profile['gateway_address']
2274 dhcp_count=int(ip_profile['dhcp_count'])
2275 subnet_address=self.convert_cidr_to_netmask(ip_profile['subnet_address'])
2276
2277 if ip_profile['dhcp_enabled']==True:
2278 dhcp_enabled='true'
2279 else:
2280 dhcp_enabled='false'
2281 dhcp_start_address=ip_profile['dhcp_start_address']
2282
2283 #derive dhcp_end_address from dhcp_start_address & dhcp_count
2284 end_ip_int = int(netaddr.IPAddress(dhcp_start_address))
2285 end_ip_int += dhcp_count - 1
2286 dhcp_end_address = str(netaddr.IPAddress(end_ip_int))
2287
2288 ip_version=ip_profile['ip_version']
2289 dns_address=ip_profile['dns_address']
2290
bayramovef390722016-09-27 03:34:46 -07002291 # either use client provided UUID or search for a first available
2292 # if both are not defined we return none
2293 if parent_network_uuid is not None:
2294 url_list = [vca.host, '/api/admin/network/', parent_network_uuid]
2295 add_vdc_rest_url = ''.join(url_list)
2296
bhangare0e571a92017-01-12 04:02:23 -08002297 if net_type=='ptp':
2298 fence_mode="isolated"
2299 isshared='false'
2300 is_inherited='false'
2301 data = """ <OrgVdcNetwork name="{0:s}" xmlns="http://www.vmware.com/vcloud/v1.5">
2302 <Description>Openmano created</Description>
2303 <Configuration>
2304 <IpScopes>
2305 <IpScope>
2306 <IsInherited>{1:s}</IsInherited>
2307 <Gateway>{2:s}</Gateway>
2308 <Netmask>{3:s}</Netmask>
2309 <Dns1>{4:s}</Dns1>
2310 <IsEnabled>{5:s}</IsEnabled>
2311 <IpRanges>
2312 <IpRange>
2313 <StartAddress>{6:s}</StartAddress>
2314 <EndAddress>{7:s}</EndAddress>
2315 </IpRange>
2316 </IpRanges>
2317 </IpScope>
2318 </IpScopes>
2319 <FenceMode>{8:s}</FenceMode>
2320 </Configuration>
2321 <IsShared>{9:s}</IsShared>
2322 </OrgVdcNetwork> """.format(escape(network_name), is_inherited, gateway_address,
2323 subnet_address, dns_address, dhcp_enabled,
2324 dhcp_start_address, dhcp_end_address, fence_mode, isshared)
2325
2326 else:
2327 fence_mode="bridged"
2328 is_inherited='false'
2329 data = """ <OrgVdcNetwork name="{0:s}" xmlns="http://www.vmware.com/vcloud/v1.5">
2330 <Description>Openmano created</Description>
2331 <Configuration>
2332 <IpScopes>
2333 <IpScope>
2334 <IsInherited>{1:s}</IsInherited>
2335 <Gateway>{2:s}</Gateway>
2336 <Netmask>{3:s}</Netmask>
2337 <Dns1>{4:s}</Dns1>
2338 <IsEnabled>{5:s}</IsEnabled>
2339 <IpRanges>
2340 <IpRange>
2341 <StartAddress>{6:s}</StartAddress>
2342 <EndAddress>{7:s}</EndAddress>
2343 </IpRange>
2344 </IpRanges>
2345 </IpScope>
2346 </IpScopes>
2347 <ParentNetwork href="{8:s}"/>
2348 <FenceMode>{9:s}</FenceMode>
2349 </Configuration>
2350 <IsShared>{10:s}</IsShared>
2351 </OrgVdcNetwork> """.format(escape(network_name), is_inherited, gateway_address,
2352 subnet_address, dns_address, dhcp_enabled,
2353 dhcp_start_address, dhcp_end_address, available_networks,
2354 fence_mode, isshared)
bayramovef390722016-09-27 03:34:46 -07002355
2356 headers = vca.vcloud_session.get_vcloud_headers()
2357 headers['Content-Type'] = 'application/vnd.vmware.vcloud.orgVdcNetwork+xml'
bhangare0e571a92017-01-12 04:02:23 -08002358 try:
2359 response = Http.post(url=add_vdc_rest_url,
2360 headers=headers,
2361 data=data,
2362 verify=vca.verify,
2363 logger=vca.logger)
bayramovef390722016-09-27 03:34:46 -07002364
bhangare0e571a92017-01-12 04:02:23 -08002365 if response.status_code != 201:
2366 self.logger.debug("Create Network POST REST API call failed. Return status code {}"
2367 .format(response.status_code))
2368 else:
2369 network = networkType.parseString(response.content, True)
2370 create_nw_task = network.get_Tasks().get_Task()[0]
2371
2372 # if we all ok we respond with content after network creation completes
2373 # otherwise by default return None
2374 if create_nw_task is not None:
2375 self.logger.debug("Create Network REST : Waiting for Nw creation complete")
2376 status = vca.block_until_completed(create_nw_task)
2377 if status:
2378 return response.content
2379 else:
2380 self.logger.debug("create_network_rest task failed. Network Create response : {}"
2381 .format(response.content))
2382 except Exception as exp:
2383 self.logger.debug("create_network_rest : Exception : {} ".format(exp))
2384
2385 return None
2386
2387 def convert_cidr_to_netmask(self, cidr_ip=None):
2388 """
2389 Method sets convert CIDR netmask address to normal IP format
2390 Args:
2391 cidr_ip : CIDR IP address
2392 Returns:
2393 netmask : Converted netmask
2394 """
2395 if cidr_ip is not None:
2396 if '/' in cidr_ip:
2397 network, net_bits = cidr_ip.split('/')
2398 netmask = socket.inet_ntoa(struct.pack(">I", (0xffffffff << (32 - int(net_bits))) & 0xffffffff))
2399 else:
2400 netmask = cidr_ip
2401 return netmask
bayramovef390722016-09-27 03:34:46 -07002402 return None
2403
2404 def get_provider_rest(self, vca=None):
2405 """
2406 Method gets provider vdc view from vcloud director
2407
2408 Args:
2409 network_name - is network name to be created.
2410 parent_network_uuid - is parent provider vdc network that will be used for mapping.
2411 It optional attribute. by default if no parent network indicate the first available will be used.
2412
2413 Returns:
2414 The return xml content of respond or None
2415 """
2416
2417 url_list = [vca.host, '/api/admin']
2418 response = Http.get(url=''.join(url_list),
2419 headers=vca.vcloud_session.get_vcloud_headers(),
2420 verify=vca.verify,
2421 logger=vca.logger)
2422
2423 if response.status_code == requests.codes.ok:
2424 return response.content
2425 return None
2426
2427 def create_vdc(self, vdc_name=None):
2428
2429 vdc_dict = {}
2430
2431 xml_content = self.create_vdc_from_tmpl_rest(vdc_name=vdc_name)
2432 if xml_content is not None:
bayramovef390722016-09-27 03:34:46 -07002433 try:
2434 task_resp_xmlroot = XmlElementTree.fromstring(xml_content)
2435 for child in task_resp_xmlroot:
2436 if child.tag.split("}")[1] == 'Owner':
2437 vdc_id = child.attrib.get('href').split("/")[-1]
2438 vdc_dict[vdc_id] = task_resp_xmlroot.get('href')
2439 return vdc_dict
2440 except:
2441 self.logger.debug("Respond body {}".format(xml_content))
2442
2443 return None
2444
2445 def create_vdc_from_tmpl_rest(self, vdc_name=None):
2446 """
2447 Method create vdc in vCloud director based on VDC template.
2448 it uses pre-defined template that must be named openmano
2449
2450 Args:
2451 vdc_name - name of a new vdc.
2452
2453 Returns:
2454 The return xml content of respond or None
2455 """
2456
2457 self.logger.info("Creating new vdc {}".format(vdc_name))
bayramovef390722016-09-27 03:34:46 -07002458 vca = self.connect()
2459 if not vca:
2460 raise vimconn.vimconnConnectionException("self.connect() is failed")
2461 if vdc_name is None:
2462 return None
2463
2464 url_list = [vca.host, '/api/vdcTemplates']
2465 vm_list_rest_call = ''.join(url_list)
2466 response = Http.get(url=vm_list_rest_call,
2467 headers=vca.vcloud_session.get_vcloud_headers(),
2468 verify=vca.verify,
2469 logger=vca.logger)
2470
2471 # container url to a template
2472 vdc_template_ref = None
2473 try:
2474 vm_list_xmlroot = XmlElementTree.fromstring(response.content)
2475 for child in vm_list_xmlroot:
2476 # application/vnd.vmware.admin.providervdc+xml
2477 # we need find a template from witch we instantiate VDC
2478 if child.tag.split("}")[1] == 'VdcTemplate':
2479 if child.attrib.get('type') == 'application/vnd.vmware.admin.vdcTemplate+xml' and child.attrib.get(
2480 'name') == 'openmano':
2481 vdc_template_ref = child.attrib.get('href')
2482 except:
2483 self.logger.debug("Failed parse respond for rest api call {}".format(vm_list_rest_call))
2484 self.logger.debug("Respond body {}".format(response.content))
2485 return None
2486
2487 # if we didn't found required pre defined template we return None
2488 if vdc_template_ref is None:
2489 return None
2490
2491 try:
2492 # instantiate vdc
2493 url_list = [vca.host, '/api/org/', self.org_uuid, '/action/instantiate']
2494 vm_list_rest_call = ''.join(url_list)
2495 data = """<InstantiateVdcTemplateParams name="{0:s}" xmlns="http://www.vmware.com/vcloud/v1.5">
2496 <Source href="{1:s}"></Source>
2497 <Description>opnemano</Description>
2498 </InstantiateVdcTemplateParams>""".format(vdc_name, vdc_template_ref)
2499 headers = vca.vcloud_session.get_vcloud_headers()
2500 headers['Content-Type'] = 'application/vnd.vmware.vcloud.instantiateVdcTemplateParams+xml'
2501 response = Http.post(url=vm_list_rest_call, headers=headers, data=data, verify=vca.verify,
2502 logger=vca.logger)
2503 # if we all ok we respond with content otherwise by default None
2504 if response.status_code >= 200 and response.status_code < 300:
2505 return response.content
2506 return None
2507 except:
2508 self.logger.debug("Failed parse respond for rest api call {}".format(vm_list_rest_call))
2509 self.logger.debug("Respond body {}".format(response.content))
2510
2511 return None
2512
2513 def create_vdc_rest(self, vdc_name=None):
2514 """
2515 Method create network in vCloud director
2516
2517 Args:
2518 network_name - is network name to be created.
2519 parent_network_uuid - is parent provider vdc network that will be used for mapping.
2520 It optional attribute. by default if no parent network indicate the first available will be used.
2521
2522 Returns:
2523 The return network uuid or return None
2524 """
2525
2526 self.logger.info("Creating new vdc {}".format(vdc_name))
bayramovef390722016-09-27 03:34:46 -07002527
2528 vca = self.connect_as_admin()
2529 if not vca:
2530 raise vimconn.vimconnConnectionException("self.connect() is failed")
2531 if vdc_name is None:
2532 return None
2533
2534 url_list = [vca.host, '/api/admin/org/', self.org_uuid]
2535 vm_list_rest_call = ''.join(url_list)
2536 if not (not vca.vcloud_session or not vca.vcloud_session.organization):
2537 response = Http.get(url=vm_list_rest_call,
2538 headers=vca.vcloud_session.get_vcloud_headers(),
2539 verify=vca.verify,
2540 logger=vca.logger)
2541
2542 provider_vdc_ref = None
2543 add_vdc_rest_url = None
2544 available_networks = None
2545
2546 if response.status_code != requests.codes.ok:
2547 self.logger.debug("REST API call {} failed. Return status code {}".format(vm_list_rest_call,
2548 response.status_code))
2549 return None
2550 else:
2551 try:
2552 vm_list_xmlroot = XmlElementTree.fromstring(response.content)
2553 for child in vm_list_xmlroot:
2554 # application/vnd.vmware.admin.providervdc+xml
2555 if child.tag.split("}")[1] == 'Link':
2556 if child.attrib.get('type') == 'application/vnd.vmware.admin.createVdcParams+xml' \
2557 and child.attrib.get('rel') == 'add':
2558 add_vdc_rest_url = child.attrib.get('href')
2559 except:
2560 self.logger.debug("Failed parse respond for rest api call {}".format(vm_list_rest_call))
2561 self.logger.debug("Respond body {}".format(response.content))
2562 return None
2563
2564 response = self.get_provider_rest(vca=vca)
bayramovef390722016-09-27 03:34:46 -07002565 try:
2566 vm_list_xmlroot = XmlElementTree.fromstring(response)
2567 for child in vm_list_xmlroot:
2568 if child.tag.split("}")[1] == 'ProviderVdcReferences':
2569 for sub_child in child:
2570 provider_vdc_ref = sub_child.attrib.get('href')
2571 except:
2572 self.logger.debug("Failed parse respond for rest api call {}".format(vm_list_rest_call))
2573 self.logger.debug("Respond body {}".format(response))
2574 return None
2575
bayramovef390722016-09-27 03:34:46 -07002576 if add_vdc_rest_url is not None and provider_vdc_ref is not None:
2577 data = """ <CreateVdcParams name="{0:s}" xmlns="http://www.vmware.com/vcloud/v1.5"><Description>{1:s}</Description>
2578 <AllocationModel>ReservationPool</AllocationModel>
2579 <ComputeCapacity><Cpu><Units>MHz</Units><Allocated>2048</Allocated><Limit>2048</Limit></Cpu>
2580 <Memory><Units>MB</Units><Allocated>2048</Allocated><Limit>2048</Limit></Memory>
2581 </ComputeCapacity><NicQuota>0</NicQuota><NetworkQuota>100</NetworkQuota>
2582 <VdcStorageProfile><Enabled>true</Enabled><Units>MB</Units><Limit>20480</Limit><Default>true</Default></VdcStorageProfile>
2583 <ProviderVdcReference
2584 name="Main Provider"
2585 href="{2:s}" />
2586 <UsesFastProvisioning>true</UsesFastProvisioning></CreateVdcParams>""".format(escape(vdc_name),
2587 escape(vdc_name),
2588 provider_vdc_ref)
2589
bayramovef390722016-09-27 03:34:46 -07002590 headers = vca.vcloud_session.get_vcloud_headers()
2591 headers['Content-Type'] = 'application/vnd.vmware.admin.createVdcParams+xml'
2592 response = Http.post(url=add_vdc_rest_url, headers=headers, data=data, verify=vca.verify,
2593 logger=vca.logger)
2594
bayramovef390722016-09-27 03:34:46 -07002595 # if we all ok we respond with content otherwise by default None
2596 if response.status_code == 201:
2597 return response.content
2598 return None
bayramovfe3f3c92016-10-04 07:53:41 +04002599
2600 def get_vapp_details_rest(self, vapp_uuid=None):
2601 """
2602 Method retrieve vapp detail from vCloud director
2603
2604 Args:
2605 vapp_uuid - is vapp identifier.
2606
2607 Returns:
2608 The return network uuid or return None
2609 """
2610
2611 parsed_respond = {}
2612
2613 vca = self.connect()
2614 if not vca:
2615 raise vimconn.vimconnConnectionException("self.connect() is failed")
2616 if vapp_uuid is None:
2617 return None
2618
2619 url_list = [vca.host, '/api/vApp/vapp-', vapp_uuid]
2620 get_vapp_restcall = ''.join(url_list)
2621 if not (not vca.vcloud_session or not vca.vcloud_session.organization):
2622 response = Http.get(url=get_vapp_restcall,
2623 headers=vca.vcloud_session.get_vcloud_headers(),
2624 verify=vca.verify,
2625 logger=vca.logger)
2626
2627 if response.status_code != requests.codes.ok:
2628 self.logger.debug("REST API call {} failed. Return status code {}".format(get_vapp_restcall,
2629 response.status_code))
2630 return parsed_respond
2631
2632 try:
2633 xmlroot_respond = XmlElementTree.fromstring(response.content)
2634 parsed_respond['ovfDescriptorUploaded'] = xmlroot_respond.attrib['ovfDescriptorUploaded']
2635
2636 namespaces_ovf = {'ovf': 'http://schemas.dmtf.org/ovf/envelope/1'}
2637 namespace_vmm = {'vmw': 'http://www.vmware.com/schema/ovf'}
2638 namespace_vm = {'vm': 'http://www.vmware.com/vcloud/v1.5'}
2639
2640 created_section = xmlroot_respond.find('vm:DateCreated', namespace_vm)
2641 if created_section is not None:
2642 parsed_respond['created'] = created_section.text
2643
2644 network_section = xmlroot_respond.find('vm:NetworkConfigSection/vm:NetworkConfig', namespace_vm)
bayramov5761ad12016-10-04 09:00:30 +04002645 if network_section is not None and 'networkName' in network_section.attrib:
bayramovfe3f3c92016-10-04 07:53:41 +04002646 parsed_respond['networkname'] = network_section.attrib['networkName']
2647
2648 ipscopes_section = \
2649 xmlroot_respond.find('vm:NetworkConfigSection/vm:NetworkConfig/vm:Configuration/vm:IpScopes',
2650 namespace_vm)
2651 if ipscopes_section is not None:
2652 for ipscope in ipscopes_section:
2653 for scope in ipscope:
2654 tag_key = scope.tag.split("}")[1]
2655 if tag_key == 'IpRanges':
2656 ip_ranges = scope.getchildren()
2657 for ipblock in ip_ranges:
2658 for block in ipblock:
2659 parsed_respond[block.tag.split("}")[1]] = block.text
2660 else:
2661 parsed_respond[tag_key] = scope.text
2662
2663 # parse children section for other attrib
2664 children_section = xmlroot_respond.find('vm:Children/', namespace_vm)
2665 if children_section is not None:
2666 parsed_respond['name'] = children_section.attrib['name']
2667 parsed_respond['nestedHypervisorEnabled'] = children_section.attrib['nestedHypervisorEnabled']
2668 parsed_respond['deployed'] = children_section.attrib['deployed']
2669 parsed_respond['status'] = children_section.attrib['status']
2670 parsed_respond['vmuuid'] = children_section.attrib['id'].split(":")[-1]
2671 network_adapter = children_section.find('vm:NetworkConnectionSection', namespace_vm)
2672 nic_list = []
2673 for adapters in network_adapter:
2674 adapter_key = adapters.tag.split("}")[1]
2675 if adapter_key == 'PrimaryNetworkConnectionIndex':
2676 parsed_respond['primarynetwork'] = adapters.text
2677 if adapter_key == 'NetworkConnection':
2678 vnic = {}
bayramov5761ad12016-10-04 09:00:30 +04002679 if 'network' in adapters.attrib:
bayramovfe3f3c92016-10-04 07:53:41 +04002680 vnic['network'] = adapters.attrib['network']
2681 for adapter in adapters:
2682 setting_key = adapter.tag.split("}")[1]
2683 vnic[setting_key] = adapter.text
2684 nic_list.append(vnic)
2685
2686 for link in children_section:
bayramov5761ad12016-10-04 09:00:30 +04002687 if link.tag.split("}")[1] == 'Link' and 'rel' in link.attrib:
bayramovfe3f3c92016-10-04 07:53:41 +04002688 if link.attrib['rel'] == 'screen:acquireTicket':
2689 parsed_respond['acquireTicket'] = link.attrib
2690 if link.attrib['rel'] == 'screen:acquireMksTicket':
2691 parsed_respond['acquireMksTicket'] = link.attrib
2692
2693 parsed_respond['interfaces'] = nic_list
2694 except:
2695 pass
2696
2697 return parsed_respond
2698
bayramov5761ad12016-10-04 09:00:30 +04002699 def acuire_console(self, vm_uuid=None):
bayramovfe3f3c92016-10-04 07:53:41 +04002700
2701 vca = self.connect()
2702 if not vca:
2703 raise vimconn.vimconnConnectionException("self.connect() is failed")
2704 if vm_uuid is None:
2705 return None
2706
2707 if not (not vca.vcloud_session or not vca.vcloud_session.organization):
bayramov5761ad12016-10-04 09:00:30 +04002708 vm_dict = self.get_vapp_details_rest(self, vapp_uuid=vm_uuid)
bayramovfe3f3c92016-10-04 07:53:41 +04002709 console_dict = vm_dict['acquireTicket']
2710 console_rest_call = console_dict['href']
2711
2712 response = Http.post(url=console_rest_call,
2713 headers=vca.vcloud_session.get_vcloud_headers(),
2714 verify=vca.verify,
2715 logger=vca.logger)
2716
bayramov5761ad12016-10-04 09:00:30 +04002717 if response.status_code == requests.codes.ok:
2718 return response.content
bayramovfe3f3c92016-10-04 07:53:41 +04002719
kate15f1c382016-12-15 01:12:40 -08002720 return None
kate13ab2c42016-12-23 01:34:24 -08002721
bhangare0e571a92017-01-12 04:02:23 -08002722