vmware-nsx-tempest-plugin/vmware_nsx_tempest_plugin/services/nsxv_client.py

537 lines
20 KiB
Python

# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
import base64
import re
from oslo_log import log as logging
from oslo_serialization import jsonutils
import requests
from tempest import config
import vmware_nsx_tempest_plugin.services.utils as utils
requests.packages.urllib3.disable_warnings()
CONF = config.CONF
LOG = logging.getLogger(__name__)
class VSMClient(object):
"""NSX-v client.
The client provides the API operations on its components.
The purpose of this rest client is to query backend components after
issuing corresponding API calls from OpenStack. This is to make sure
the API calls has been realized on the NSX-v backend.
"""
API_VERSION = "2.0"
def __init__(self, host, username, password, *args, **kwargs):
self.force = True if 'force' in kwargs else False
self.host = host
self.username = username
self.password = password
self.version = None
self.endpoint = None
self.content_type = "application/json"
self.accept_type = "application/json"
self.verify = False
self.secure = True
self.interface = "json"
self.url = None
self.headers = None
self.api_version = VSMClient.API_VERSION
self.default_scope_id = None
self.__set_headers()
self._version = self.get_vsm_version()
def __set_endpoint(self, endpoint):
self.endpoint = endpoint
def get_endpoint(self):
return self.endpoint
def __set_content_type(self, content_type):
self.content_type = content_type
def get_content_type(self):
return self.content_type
def __set_accept_type(self, accept_type):
self.accept_type = accept_type
def get_accept_type(self):
return self.accept_type
def __set_api_version(self, api_version):
self.api_version = api_version
def get_api_version(self):
return self.api_version
def __set_url(self, version=None, secure=None, host=None, endpoint=None):
version = self.api_version if version is None else version
secure = self.secure if secure is None else secure
host = self.host if host is None else host
endpoint = self.endpoint if endpoint is None else endpoint
http_type = 'https' if secure else 'http'
self.url = '%s://%s/api/%s%s' % (http_type, host, version, endpoint)
def get_url(self):
return self.url
def __set_headers(self, content=None, accept=None):
content_type = self.content_type if content is None else content
accept_type = self.accept_type if accept is None else accept
auth_cred = self.username + ":" + self.password
auth = base64.b64encode(auth_cred.encode()).decode()
headers = {}
headers['Authorization'] = "Basic %s" % auth
headers['Content-Type'] = content_type
headers['Accept'] = accept_type
self.headers = headers
def get(self, endpoint=None, params=None):
"""Basic query GET method for json API request."""
self.__set_url(endpoint=endpoint)
response = requests.get(self.url, headers=self.headers,
verify=self.verify, params=params)
return response
def delete(self, endpoint=None, params=None):
"""Basic delete API method on endpoint."""
self.__set_url(endpoint=endpoint)
response = requests.delete(self.url, headers=self.headers,
verify=self.verify, params=params)
return response
def post(self, endpoint=None, body=None):
"""Basic post API method on endpoint."""
self.__set_url(endpoint=endpoint)
response = requests.post(self.url, headers=self.headers,
verify=self.verify,
data=jsonutils.dumps(body))
return response
def put(self, endpoint=None, body=None):
self.__set_url(endpoint=self.endpoint)
response = requests.put(self.url, headers=self.headers,
verify=self.verify,
data=jsonutils.dumps(body))
return response
def enable_ssh_on_edge(self, edge_name, edge_id):
edge_detail = self.get_edge(edge_name + '-' + edge_id)
self.__set_api_version('4.0')
data = {}
data['enabled'] = 'true'
data['rulePriority'] = 'high'
endpoint = "/edges/%s/autoconfiguration" % (edge_detail['id'])
self.__set_endpoint(endpoint)
self.put(body=data)
payload = {}
payload['userName'] = 'admin'
payload['password'] = 'Admin!23Admin'
payload['remoteAccess'] = 'true'
endpoint = "/edges/%s/clisettings" % (edge_detail['id'])
self.__set_endpoint(endpoint)
self.put(body=payload)
rules = [{'name': 'anyRule', "ruleType": "user", "enabled": 'true',
"action": "accept"}]
rule_payload = {"firewallRules": rules}
endpoint = "/edges/%s/firewall/config/rules" % (edge_detail['id'])
self.__set_endpoint(endpoint)
self.post(body=rule_payload)
def get_all_vdn_scopes(self):
"""Retrieve existing network scopes"""
self.__set_api_version('2.0')
self.__set_endpoint("/vdn/scopes")
response = self.get()
return response.json()['allScopes']
# return the vdn_scope_id for the priamry Transport Zone
def get_vdn_scope_id(self):
"""Retrieve existing network scope id."""
scopes = self.get_all_vdn_scopes()
if len(scopes) == 0:
return scopes[0]['objectId']
return CONF.nsxv.vdn_scope_id
def get_vdn_scope_by_id(self, scope_id):
"""Retrieve existing network scopes id"""
self.__set_api_version('2.0')
self.__set_endpoint("/vdn/scopes/%s" % scope_id)
return self.get().json()
def get_vdn_scope_by_name(self, name):
"""Retrieve network scope id of existing scope name:
nsxv_client.get_vdn_scope_id_by_name('TZ1')
"""
scopes = self.get_all_vdn_scopes()
if name is None:
for scope in scopes:
if scope['objectId'] == CONF.nsxv.vdn_scope_id:
return scope
else:
for scope in scopes:
if scope['name'] == name:
return scope
return None
def get_all_logical_switches(self, vdn_scope_id=None):
lswitches = []
self.__set_api_version('2.0')
vdn_scope_id = vdn_scope_id or self.get_vdn_scope_id()
endpoint = "/vdn/scopes/%s/virtualwires" % (vdn_scope_id)
self.__set_endpoint(endpoint)
response = self.get()
paging_info = response.json()['dataPage']['pagingInfo']
page_size = int(paging_info['pageSize'])
total_count = int(paging_info['totalCount'])
msg = ("There are total %s logical switches and page size is %s"
% (total_count, page_size))
LOG.debug(msg)
pages = utils.ceil(total_count, page_size)
LOG.debug("Total pages: %s" % pages)
for i in range(int(pages) + 1):
start_index = page_size * i
params = {'startindex': start_index}
response = self.get(params=params)
lswitches += response.json()['dataPage']['data']
return lswitches
def get_logical_switch(self, name):
"""Get the logical switch based on the name.
The uuid of the OpenStack L2 network. Return ls if found,
otherwise return None.
"""
lswitches = self.get_all_logical_switches()
lswitch = [ls for ls in lswitches if ls['name'] == name]
if len(lswitch) == 0:
LOG.debug('logical switch %s NOT found!' % name)
lswitch = None
else:
ls = lswitch[0]
LOG.debug('Found lswitch: %s' % ls)
return ls
def delete_logical_switch(self, name):
"""Delete logical switch based on name.
The name of the logical switch on NSX-v is the uuid
of the openstack l2 network.
"""
ls = self.get_logical_switch(name)
if ls is not None:
endpoint = '/vdn/virtualwires/%s' % ls['objectId']
response = self.delete(endpoint=endpoint)
if response.status_code == 200:
LOG.debug('Successfully deleted logical switch %s' % name)
else:
LOG.debug('ERROR @delete ls=%s failed with response code %s' %
(name, response.status_code))
def get_all_edges(self):
"""Get all edges on NSX-v backend."""
self.__set_api_version('4.0')
self.__set_endpoint('/edges')
edges = []
response = self.get()
paging_info = response.json()['edgePage']['pagingInfo']
page_size = int(paging_info['pageSize'])
total_count = int(paging_info['totalCount'])
msg = "There are total %s edges and page size is %s" % (total_count,
page_size)
LOG.debug(msg)
pages = utils.ceil(total_count, page_size)
for i in range(int(pages) + 1):
start_index = page_size * i
params = {'startindex': start_index}
response = self.get(params=params)
edges += response.json()['edgePage']['data']
return edges
def get_edge_firewall_rules(self, edge_Id):
"""Get nsx-edge firewall info based on edge_id.
Return firewall rules if found ,else return None.
"""
self.__set_api_version('4.0')
self.__set_endpoint('/edges/%s/firewall/config' % edge_Id)
response = self.get()
rules = response.json()['firewallRules']['firewallRules']
if len(rules) == 0:
rules = None
return rules
def get_firewall(self):
"""Get all firewall on NSX-v beckend.
Return firewalls if found, else return None.
"""
self.__set_api_version('4.0')
self.__set_endpoint('/firewall/globalroot-0/config')
response = self.get()
paging_info = response.json()
if len(paging_info) == 0:
paging_info = None
return paging_info
def get_edge(self, name):
"""Get edge based on the name, which is OpenStack router.
Return edge if found, else return None.
"""
edges = self.get_all_edges()
edge = [e for e in edges if e['name'] == name]
if len(edge) == 0:
LOG.debug('Edge %s NOT found!' % name)
edge = None
else:
edge = edge[0]
LOG.debug('Found edge: %s' % edge)
return edge
def get_dhcp_edge_config(self, edge_id):
"""Get dhcp edge config.
Return edge information.
"""
self.__set_api_version('4.0')
self.__set_endpoint('/edges/%s/dhcp/config' % edge_id)
response = self.get()
return response
def get_excluded_vm_name_list(self):
"""Get excluded vm's list info from beckend.
After disabling port security of vm port, vm will get added
in exclude list.This method returns the list of vm's present
in exclude list.
Returns exclude list of vm's name.
"""
self.__set_api_version('2.1')
self.__set_endpoint('/app/excludelist')
response = self.get()
response_list = []
exclude_list = []
response_list = response.json()[
'excludeListConfigurationDto']['excludeMembers']
exclude_list = [member['member']['name'] for member in response_list
if member['member']['name']]
return exclude_list
def get_dhcp_edge_info(self, version=None):
"""Get dhcp edge info.
Return edge if found, else return None.
"""
edges = self.get_all_edges()
edge_list = []
for e in edges:
if (not e['edgeStatus'] == 'GREY' and
not e['state'] == 'undeployed'):
p = re.compile(r'dhcp*')
if (p.match(e['name'])):
if version is not None and \
version[0:5] >= "6.4.0":
edge_list.append(e['id'])
else:
edge_list.append(e['recentJobInfo']['edgeId'])
count = 0
result_edge = {}
for edge_id in edge_list:
response = self.get_dhcp_edge_config(edge_id)
paging_info = response.json()
if (paging_info['staticBindings']['staticBindings']):
result_edge[count] = paging_info
count += 1
else:
LOG.debug('Host Routes are not avilable for %s ' % edge_id)
if (count > 0):
edge = result_edge[0]
else:
edge = None
return edge
def get_vsm_version(self):
"""Get the VSM client version including major, minor, patch, & build#.
Build number, e.g. 6.2.0.2986609
return: vsm version
"""
self.__set_api_version('1.0')
self.__set_endpoint('/appliance-management/global/info')
response = self.get()
json_ver = response.json()['versionInfo']
return '.'.join([json_ver['majorVersion'], json_ver['minorVersion'],
json_ver['patchVersion'], json_ver['buildNumber']])
def verify_default_snat_rule(self, name, routerip, cidr):
edge_id = self.get_edge_name_substring(name)['id']
self.__set_api_version('4.0')
self.__set_endpoint('/edges/%s/nat/config' % edge_id)
response = self.get()
conf = response.json()['rules']['natRulesDtos']
nat = [(n['originalAddress'], n['translatedAddress']) for n in conf]
if (cidr, routerip) in nat:
return True
else:
return False
def verify_dhcp_relay_on_dhcp_edge(self):
edges = self.get_all_edges()
edge_list = []
for e in edges:
if (not e['edgeStatus'] == 'GREY' and
not e['state'] == 'undeployed'):
p = re.compile(r'dhcp*')
if (p.match(e['name'])):
edge_list.append(e['id'])
rules = self.get_edge_firewall_rules(edge_list[-1])
rule_names = [r['name'] for r in rules]
if 'DHCPRelay' in rule_names:
return True
else:
return False
def get_edge_name_substring(self, name):
"""Get edge based on the name, which is OpenStack router.
Return edge if found, else return None.
"""
edges = self.get_all_edges()
edge = [e for e in edges if name[:-4] in e['name']]
if len(edge) == 0:
LOG.debug('Edge %s NOT found!' % name)
edge = None
else:
edge = edge[0]
LOG.debug('Found edge: %s' % edge)
return edge
def verify_spoofgaurd_policy_nw(self, network_id):
"""Retrieve existing scppfguard policy"""
self.__set_api_version('4.0')
self.__set_endpoint("/services/spoofguard/policies/")
response = self.get()
spoofgaurd_policies = response.json()['policies']
sps = [sp['name'] for sp in spoofgaurd_policies]
if network_id in sps:
LOG.debug('Found spoofgurad policy for network: %s' % network_id)
return True
else:
LOG.debug('spoofguard policy of nw is %s NOT found!' % network_id)
return False
def verify_static_route(self, name, cidr, nexthop):
edge_id = self.get_edge_name_substring(name)['id']
self.__set_api_version('4.0')
self.__set_endpoint('/edges/%s/routing/config/static' % edge_id)
response = self.get()
routes = response.json()['staticRoutes']['staticRoutes']
route = [(r['network'], r['nextHop']) for r in routes]
if (cidr, nexthop) in route:
return True
else:
return False
def check_cert_at_backend(self, lb_id=None, cert_conent=None):
lbaas_edge_name = 'lbaas-' + lb_id[:-6]
edge_id = self.get_lbaas_edge_id(lbaas_edge_name)
self.__set_api_version('2.0')
endpoint = '/services/truststore/certificate/scope/%s' % edge_id
self.__set_endpoint(endpoint)
response = self.get()
certs = response.json()['certificates']
for cert in certs:
if cert['pemEncoding'] == cert_conent:
return True
else:
return False
def get_lbaas_edge_id(self, edge_name):
edges = self.get_all_edges()
edge_ids = [e['id'] for e in edges if edge_name in e['name']]
if len(edge_ids) == 0:
LOG.debug('Edge %s NOT found!' % edge_name)
edge = None
else:
edge = edge_ids[0]
LOG.debug('Found edge: %s' % edge)
return edge
def get_lbaas_config_from_edge(self, lbaas_id):
lbaas_edge_name = 'lbaas-' + lbaas_id[:-6]
edge_id = self.get_lbaas_edge_id(lbaas_edge_name)
if edge_id is not None:
self.__set_api_version('4.0')
self.__set_endpoint('/edges/%s/loadbalancer/config' % edge_id)
response = self.get()
lbaas_config = response.json()
else:
LOG.debug('Edge NOT found with lb_id %s or deleted!' % lbaas_id)
lbaas_config = []
return lbaas_config
def verify_lbaas_on_edge(self, lbaas_id, listener=None,
pool=None, member=None,
hmonitor=None, cleanup=[]):
lbaas_config = self.get_lbaas_config_from_edge(lbaas_id)
if hmonitor:
hms_vsm = [hm['id'] for hm in lbaas_config['monitor']]
if 'hm' in cleanup:
self.assertNotIn(hmonitor['id'], hms_vsm)
else:
self.assertIn(hmonitor['id'], hms_vsm)
if pool:
pool_vsm = \
[(p['name'], p['algorithm']) for p in lbaas_config['pool']]
if 'pool' in cleanup:
self.assertFalse(('pool_' + pool['id'],
'round-robin') in pool_vsm)
else:
self.assertTrue(('pool_' + pool['id'],
'round-robin') in pool_vsm)
if listener:
listener_vsm = \
[lr['name'] for lr in lbaas_config['virtualServer']]
if 'listener' in cleanup:
self.assertFalse('vip_' + listener['id'] in listener_vsm)
else:
self.assertTrue('vip_' + listener['id'] in listener_vsm)
def verify_member_status_of_md_proxy_edges(self):
md_edge_name = 'metadata'
edge_id = self.get_lbaas_edge_id(md_edge_name)
result = False
up_members = 0
if edge_id is not None:
self.__set_api_version('4.0')
self.__set_endpoint('/edges/%s/loadbalancer/statistics' % edge_id)
response = self.get()
members = response.json()['pool'][0]['member']
if members:
for member in members:
if member['status'] == 'UP':
up_members += 1
if len(members) == up_members:
result = True
else:
LOG.debug('pool are not present on required edge')
else:
LOG.debug('Edge NOT found with mdproxy or deleted!')
return result