fuel-qa/system_test/actions/vcenter_actions.py

565 lines
23 KiB
Python

# Copyright 2016 Mirantis, Inc.
#
# 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.
from time import sleep
from random import randrange
from devops.helpers import helpers
from proboscis import SkipTest
from proboscis.asserts import assert_equal
from proboscis.asserts import assert_not_equal
from proboscis.asserts import assert_true
from fuelweb_test.helpers.os_actions import OpenStackActions
from fuelweb_test.helpers.ssh_manager import SSHManager
from fuelweb_test.settings import NEUTRON
from system_test import logger
from system_test import deferred_decorator
from system_test import action
from system_test.helpers.decorators import make_snapshot_if_step_fail
# pylint: disable=no-member
# noinspection PyUnresolvedReferences
class VMwareActions(object):
"""VMware vCenter/DVS related actions"""
plugin_version = None
vcenter_az = 'vcenter'
cinder_az = 'vcenter-cinder'
vmware_image = 'TestVM-VMDK'
net_name = 'admin_internal_net'
sg_name = 'default'
image_name = None
image_url = None
image_creds = None
@deferred_decorator([make_snapshot_if_step_fail])
@action
def configure_dvs_plugin(self):
"""Configure DVS plugin"""
msg = "Plugin couldn't be enabled. Check plugin version. Test aborted"
assert_true(
self.fuel_web.check_plugin_exists(
self.cluster_id,
self.plugin_name),
msg)
dvs_settings = self.full_config['template']['cluster_template'][
'settings']['vmware_dvs']
self.update_dvs_plugin_settings(dvs_settings)
def update_dvs_plugin_settings(self, dvs_settings):
"""Update plugin settings
:param dvs_settings: dict
"""
options = {
'vmware_dvs_fw_driver/value': dvs_settings['dvs_fw_driver'],
'vmware_dvs_net_maps/value': dvs_settings['dvswitch_name']
}
self.fuel_web.update_plugin_settings(
self.cluster_id, self.plugin_name, self.plugin_version, options,
enabled=True)
@deferred_decorator([make_snapshot_if_step_fail])
@action
def configure_vcenter(self):
"""Configure vCenter settings"""
vmware_vcenter = self.env_settings['vmware_vcenter']
vcenter_value = {
"glance": {"vcenter_username": "",
"datacenter": "",
"vcenter_host": "",
"vcenter_password": "",
"datastore": ""
},
"availability_zones": [
{"vcenter_username": vmware_vcenter['settings']['user'],
"nova_computes": [],
"vcenter_host": vmware_vcenter['settings']['host'],
"az_name": vmware_vcenter['settings']['az'],
"vcenter_password": vmware_vcenter['settings']['pwd']
}]
}
clusters = vmware_vcenter['nova-compute']
nodes = self.fuel_web.client.list_cluster_nodes(self.cluster_id)
roles = ['compute-vmware']
comp_vmware_nodes = [n for n in nodes if set(roles) <=
set(n['pending_roles'])]
for cluster in clusters:
cluster_name = cluster['cluster']
srv_name = cluster['srv_name']
datastore = cluster['datastore']
if cluster['target_node'] == 'compute-vmware':
node = comp_vmware_nodes.pop()
target_node = node['hostname']
else:
target_node = cluster['target_node']
vcenter_value["availability_zones"][0]["nova_computes"].append(
{"vsphere_cluster": cluster_name,
"service_name": srv_name,
"datastore_regex": datastore,
"target_node": {
"current": {"id": target_node,
"label": target_node},
"options": [{"id": target_node,
"label": target_node}, ]},
}
)
if vmware_vcenter['glance']['enable']:
attributes = self.fuel_web.client.get_cluster_attributes(
self.cluster_id)
attributes['editable']['storage']['images_vcenter']['value'] =\
vmware_vcenter['glance']['enable']
self.fuel_web.client.update_cluster_attributes(self.cluster_id,
attributes)
vcenter_value["glance"]["vcenter_host"] = vmware_vcenter[
'glance']['host']
vcenter_value["glance"]["vcenter_username"] = vmware_vcenter[
'glance']['user']
vcenter_value["glance"]["vcenter_password"] = vmware_vcenter[
'glance']['pwd']
vcenter_value["glance"]["datacenter"] = vmware_vcenter[
'glance']['datacenter']
vcenter_value["glance"]["datastore"] = vmware_vcenter[
'glance']['datastore']
logger.info('Configuring vCenter...')
vmware_attr = \
self.fuel_web.client.get_cluster_vmware_attributes(self.cluster_id)
vcenter_data = vmware_attr['editable']
vcenter_data['value'] = vcenter_value
logger.debug("Try to update cluster with next "
"vmware_attributes {0}".format(vmware_attr))
self.fuel_web.client.update_cluster_vmware_attributes(self.cluster_id,
vmware_attr)
logger.debug("Attributes of cluster have been updated")
@deferred_decorator([make_snapshot_if_step_fail])
@action
def set_custom_node_names(self):
"""Set custom node names"""
custom_hostnames = []
for node in self.fuel_web.client.list_cluster_nodes(self.cluster_id):
custom_hostname = "{0}-{1}".format(
node['pending_roles'][0], randrange(0, 0xffff))
custom_hostnames.append(custom_hostname)
self.fuel_web.client.set_hostname(node['id'], custom_hostname)
@staticmethod
def get_nova_conf_dict(az, nova):
"""
:param az: vcenter az (api), dict
:param nova: nova (api), dict
:return: dict
"""
conf_dict = {
'host': 'vcenter-{}'.format(nova['service_name']),
'cluster_name': nova['vsphere_cluster'],
'datastore_regex': nova['datastore_regex'],
'host_username': az['vcenter_username'],
'host_password': az['vcenter_password'],
'host_ip': az['vcenter_host']
}
return conf_dict
@deferred_decorator([make_snapshot_if_step_fail])
@action
def check_nova_conf(self):
"""Verify nova-compute vmware configuration"""
nodes = self.fuel_web.client.list_cluster_nodes(self.cluster_id)
vmware_attr = self.fuel_web.client.get_cluster_vmware_attributes(
self.cluster_id)
az = vmware_attr['editable']['value']['availability_zones'][0]
nova_computes = az['nova_computes']
data = []
ctrl_nodes = self.fuel_web.get_nailgun_cluster_nodes_by_roles(
self.cluster_id, ["controller"])
for nova in nova_computes:
target_node = nova['target_node']['current']['id']
if target_node == 'controllers':
conf_path = '/etc/nova/nova-compute.d/vmware-vcenter_{0}.' \
'conf'.format(nova['service_name'])
for node in ctrl_nodes:
hostname = node['hostname']
ip = node['ip']
conf_dict = self.get_nova_conf_dict(az, nova)
params = (hostname, ip, conf_path, conf_dict)
data.append(params)
else:
conf_path = '/etc/nova/nova-compute.conf'
for node in nodes:
if node['hostname'] == target_node:
hostname = node['hostname']
ip = node['ip']
conf_dict = self.get_nova_conf_dict(az, nova)
params = (hostname, ip, conf_path, conf_dict)
data.append(params)
for hostname, ip, conf_path, conf_dict in data:
logger.info("Check nova conf of {0}".format(hostname))
for key in conf_dict.keys():
cmd = 'cat {0} | grep {1}={2}'.format(conf_path, key,
conf_dict[key])
logger.debug('CMD: {}'.format(cmd))
SSHManager().execute_on_remote(ip, cmd)
@deferred_decorator([make_snapshot_if_step_fail])
@action
def check_nova_srv(self):
"""Verify nova-compute service for each vSphere cluster"""
vmware_attr = self.fuel_web.client.get_cluster_vmware_attributes(
self.cluster_id)
az = vmware_attr['editable']['value']['availability_zones'][0]
nova_computes = az['nova_computes']
ctrl_nodes = self.fuel_web.get_nailgun_cluster_nodes_by_roles(
self.cluster_id, ["controller"])
for nova in nova_computes:
srv_name = nova['service_name']
cmd = '. openrc; nova-manage service describe_resource ' \
'vcenter-{}'.format(srv_name)
logger.debug('CMD: {}'.format(cmd))
SSHManager().execute_on_remote(ctrl_nodes[0]['ip'],
cmd)
@deferred_decorator([make_snapshot_if_step_fail])
@action
def check_cinder_vmware_srv(self):
"""Verify cinder-vmware service"""
ctrl_nodes = self.fuel_web.get_nailgun_cluster_nodes_by_roles(
self.cluster_id, ["controller"])
cmd = '. openrc; cinder-manage service list | grep vcenter | ' \
'grep ":-)"'
logger.debug('CMD: {}'.format(cmd))
SSHManager().execute_on_remote(ctrl_nodes[0]['ip'], cmd)
@deferred_decorator([make_snapshot_if_step_fail])
@action
def deploy_changes(self):
"""Deploy environment"""
if self.cluster_id is None:
raise SkipTest("The cluster_id is not specified, can not deploy")
self.fuel_web.deploy_cluster_wait(self.cluster_id,
check_services=False)
@action
def create_and_attach_empty_volume(self):
"""Create and attach to instance empty volume"""
mount_point = '/dev/sdb'
public_ip = self.fuel_web.get_public_vip(self.cluster_id)
os_conn = OpenStackActions(public_ip)
vol = os_conn.create_volume(availability_zone=self.cinder_az)
image = os_conn.get_image(self.vmware_image)
net = os_conn.get_network(self.net_name)
sg = os_conn.get_security_group(self.sg_name)
vm = os_conn.create_server(image=image,
availability_zone=self.vcenter_az,
security_groups=[sg],
net_id=net['id'])
floating_ip = os_conn.assign_floating_ip(vm)
helpers.wait(lambda: helpers.tcp_ping(floating_ip.ip, 22), timeout=180,
timeout_msg="Node {ip} is not accessible by SSH.".format(
ip=floating_ip.ip))
logger.info("Attaching volume via cli")
ctrl_nodes = self.fuel_web.get_nailgun_cluster_nodes_by_roles(
self.cluster_id, ["controller"])
cmd = '. openrc; nova volume-attach {srv_id} {volume_id} {mount}' \
''.format(srv_id=vm.id, volume_id=vol.id, mount=mount_point)
logger.debug('CMD: {}'.format(cmd))
SSHManager().execute_on_remote(ctrl_nodes[0]['ip'], cmd)
helpers.wait(
lambda: os_conn.get_volume_status(vol) == "in-use",
timeout=30, timeout_msg="Volume doesn't reach 'in-use' state")
vm.reboot()
sleep(10)
helpers.wait(lambda: helpers.tcp_ping(floating_ip.ip, 22), timeout=180,
timeout_msg="Node {ip} is not accessible by SSH.".format(
ip=floating_ip.ip))
controller = self.fuel_web.get_nailgun_cluster_nodes_by_roles(
self.cluster_id, ["controller"])[0]
with self.fuel_web.get_ssh_for_nailgun_node(controller) as remote:
cmd = 'sudo /sbin/fdisk -l | grep {}'.format(mount_point)
res = os_conn.execute_through_host(remote, floating_ip.ip, cmd)
logger.debug('OUTPUT: {}'.format(res))
assert_equal(res['exit_code'], 0, "Attached volume is not found")
os_conn.delete_instance(vm)
os_conn.verify_srv_deleted(vm)
os_conn.delete_volume(vol)
@action
def create_bootable_volume_and_run_instance(self):
"""Create bootable volume and launch instance from it"""
public_ip = self.fuel_web.get_public_vip(self.cluster_id)
os_conn = OpenStackActions(public_ip)
image = os_conn.get_image(self.vmware_image)
vol = os_conn.create_volume(image_id=image.id,
availability_zone=self.cinder_az)
block_device_mapping = {'vda': vol.id}
net = os_conn.get_network(self.net_name)
vm = os_conn.create_server(availability_zone=self.vcenter_az,
image=False,
net_id=net['id'],
block_device_mapping=block_device_mapping)
floating_ip = os_conn.assign_floating_ip(vm)
helpers.wait(lambda: helpers.tcp_ping(floating_ip.ip, 22), timeout=180,
timeout_msg="Node {ip} is not accessible by SSH.".format(
ip=floating_ip.ip))
os_conn.delete_instance(vm)
os_conn.verify_srv_deleted(vm)
os_conn.delete_volume_and_wait(vol)
@action
def check_vmware_service_actions(self):
"""Disable vmware host (cluster) and check instance creation
on enabled cluster"""
public_ip = self.fuel_web.get_public_vip(self.cluster_id)
os_conn = OpenStackActions(public_ip)
services = os_conn.get_nova_service_list()
vmware_services = []
for service in services:
if service.binary == 'nova-compute' and \
service.zone == self.vcenter_az:
vmware_services.append(service)
os_conn.disable_nova_service(service)
image = os_conn.get_image(self.vmware_image)
sg = os_conn.get_security_group(self.sg_name)
net = os_conn.get_network(self.net_name)
for service in vmware_services:
logger.info("Check {}".format(service.host))
os_conn.enable_nova_service(service)
vm = os_conn.create_server(image=image,
availability_zone=self.vcenter_az,
net_id=net['id'], security_groups=[sg])
vm_host = getattr(vm, 'OS-EXT-SRV-ATTR:host')
assert_true(service.host == vm_host, 'Instance was launched on a'
' disabled vmware cluster')
os_conn.delete_instance(vm)
os_conn.verify_srv_deleted(vm)
os_conn.disable_nova_service(service)
@action
def upload_image(self):
"""Upload vmdk image"""
controller = self.fuel_web.get_nailgun_cluster_nodes_by_roles(
self.cluster_id, ["controller"])[0]
cmd_add_img = 'glance image-create --name {0!r} --disk-format vmdk ' \
'--container-format bare --file {1!r} ' \
'--property hypervisor_type=vmware ' \
'--property vmware_adaptertype=lsiLogic ' \
'--property vmware_disktype=sparse' \
''.format(self.image_name, self.image_name)
cmd = '. openrc; test -f {0} || (wget -q {1} && {2})'.format(
self.image_name, self.image_url, cmd_add_img)
SSHManager().execute_on_remote(controller['ip'], cmd)
public_ip = self.fuel_web.get_public_vip(self.cluster_id)
os_conn = OpenStackActions(public_ip)
image = os_conn.get_image(self.image_name)
helpers.wait(lambda: os_conn.get_image(image.name).status == 'active',
timeout=60 * 2, timeout_msg='Image is not active')
@action
def check_instance_creation(self):
"""Create instance and check connection"""
public_ip = self.fuel_web.get_public_vip(self.cluster_id)
os_conn = OpenStackActions(public_ip)
flavor = os_conn.get_flavor_by_name('m1.small')
if self.image_name:
image = os_conn.get_image(self.image_name)
else:
image = os_conn.get_image(self.vmware_image)
sg = os_conn.get_security_group(self.sg_name)
net = os_conn.get_network(self.net_name)
vm = os_conn.create_server(image=image,
availability_zone=self.vcenter_az,
net_id=net['id'], security_groups=[sg],
flavor_id=flavor.id, timeout=666)
floating_ip = os_conn.assign_floating_ip(vm)
helpers.wait(lambda: helpers.tcp_ping(floating_ip.ip, 22), timeout=180,
timeout_msg="Node {ip} is not accessible by SSH.".format(
ip=floating_ip.ip))
os_conn.delete_instance(vm)
os_conn.verify_srv_deleted(vm)
@action
def create_instance_with_vmxnet3_adapter(self):
"""Create instance with vmxnet3 adapter"""
public_ip = self.fuel_web.get_public_vip(self.cluster_id)
os_conn = OpenStackActions(public_ip)
image = os_conn.get_image(self.image_name)
os_conn.update_image(image,
properties={"hw_vif_model": "VirtualVmxnet3"})
flavor = os_conn.get_flavor_by_name('m1.small')
sg = os_conn.get_security_group(self.sg_name)
net = os_conn.get_network(self.net_name)
vm = os_conn.create_server(image=image,
availability_zone=self.vcenter_az,
net_id=net['id'], security_groups=[sg],
flavor_id=flavor.id, timeout=666)
floating_ip = os_conn.assign_floating_ip(vm)
helpers.wait(lambda: helpers.tcp_ping(floating_ip.ip, 22), timeout=180,
timeout_msg="Node {ip} is not accessible by SSH.".format(
ip=floating_ip.ip))
controller = self.fuel_web.get_nailgun_cluster_nodes_by_roles(
self.cluster_id, ["controller"])[0]
with self.fuel_web.get_ssh_for_nailgun_node(controller) as remote:
cmd = '/usr/bin/lshw -class network | grep vmxnet3'
res = os_conn.execute_through_host(remote, floating_ip.ip, cmd,
creds=self.image_creds)
logger.debug('OUTPUT: {}'.format(res))
assert_equal(res['exit_code'], 0, "VMxnet3 driver is not found")
os_conn.delete_instance(vm)
os_conn.verify_srv_deleted(vm)
@action
def check_batch_instance_creation(self):
"""Create several instance simultaneously"""
count = 10
vm_name = 'vcenter_vm'
public_ip = self.fuel_web.get_public_vip(self.cluster_id)
os_conn = OpenStackActions(public_ip)
image = os_conn.get_image(self.vmware_image)
net = os_conn.get_network(self.net_name)
sg = os_conn.get_security_group(self.sg_name)
os_conn.create_server(name=vm_name, image=image,
availability_zone=self.vcenter_az,
net_id=net['id'], security_groups=[sg],
min_count=count)
for i in range(1, count + 1):
vm = os_conn.get_server_by_name('{name}-{index}'.format(
name=vm_name, index=i))
logger.info("Check state for {} instance".format(vm.name))
helpers.wait(
lambda: os_conn.get_instance_detail(vm).status == "ACTIVE",
timeout=180, timeout_msg="Instance state is not active"
)
for i in range(1, count + 1):
vm = os_conn.get_server_by_name('{name}-{index}'.format(
name=vm_name, index=i))
os_conn.delete_instance(vm)
os_conn.verify_srv_deleted(vm)
@action
def create_instance_with_different_disktype(self):
"""Create instances with different disk type"""
public_ip = self.fuel_web.get_public_vip(self.cluster_id)
os_conn = OpenStackActions(public_ip)
image = os_conn.get_image(self.vmware_image)
net = os_conn.get_network(self.net_name)
os_conn.update_image(image,
properties={"vmware_disktype": "sparse"})
vm = os_conn.create_server(image=image,
availability_zone=self.vcenter_az,
net_id=net['id'])
os_conn.delete_instance(vm)
os_conn.verify_srv_deleted(vm)
os_conn.update_image(image,
properties={"vmware_disktype": "preallocated "})
vm = os_conn.create_server(image=image,
availability_zone=self.vcenter_az,
net_id=net['id'])
os_conn.delete_instance(vm)
os_conn.verify_srv_deleted(vm)
os_conn.update_image(image,
properties={"vmware_disktype": "thin "})
vm = os_conn.create_server(image=image,
availability_zone=self.vcenter_az,
net_id=net['id'])
os_conn.delete_instance(vm)
os_conn.verify_srv_deleted(vm)
@deferred_decorator([make_snapshot_if_step_fail])
@action
def check_neutron_public(self):
"""Check that public network was assigned to all nodes"""
cluster = self.fuel_web.client.get_cluster(self.cluster_id)
assert_equal(str(cluster['net_provider']), NEUTRON)
os_conn = OpenStackActions(
self.fuel_web.get_public_vip(self.cluster_id))
self.fuel_web.check_fixed_network_cidr(
self.cluster_id, os_conn)
@deferred_decorator([make_snapshot_if_step_fail])
@action
def check_gw_on_vmware_nodes(self):
"""Check that default gw != fuel node ip"""
vmware_nodes = []
vmware_nodes.extend(self.fuel_web.get_nailgun_cluster_nodes_by_roles(
self.cluster_id, ["compute-vmware"]))
vmware_nodes.extend(self.fuel_web.get_nailgun_cluster_nodes_by_roles(
self.cluster_id, ["cinder-vmware"]))
logger.debug('Fuel ip is {0}'.format(self.fuel_web.admin_node_ip))
for node in vmware_nodes:
cmd = "ip route | grep default | awk '{print $3}'"
gw_ip = SSHManager().execute_on_remote(node['ip'], cmd)
logger.debug('Default gw for node {0} is {1}'.format(
node['name'], gw_ip['stdout_str']))
assert_not_equal(gw_ip['stdout_str'], self.fuel_web.admin_node_ip)