Skip to content

Commit

Permalink
Merge pull request #627 from openvstorage/develop
Browse files Browse the repository at this point in the history
Promote develop
  • Loading branch information
JeffreyDevloo committed May 9, 2018
2 parents 066c0e8 + 6a3d552 commit 580dc78
Show file tree
Hide file tree
Showing 71 changed files with 2,404 additions and 1,151 deletions.
198 changes: 110 additions & 88 deletions ci/autotests.py

Large diffs are not rendered by default.

93 changes: 10 additions & 83 deletions ci/scenario_helpers/ci_constants.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,53 +14,33 @@
# Open vStorage is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY of any kind.
import json
from ci.api_lib.helpers.api import OVSClient
from ci.api_lib.helpers.hypervisor.hypervisor import HypervisorFactory
from ci.api_lib.helpers.storagerouter import StoragerouterHelper
from ci.main import CONFIG_LOC
from ci.main import SETTINGS_LOC
from ovs.lib.helpers.toolbox import Toolbox
from ci.api_lib.helpers.ci_constants import CIConstants as _CIConstants


class CIConstants(object):
class CIConstants(_CIConstants):
"""
Collection of multiple constants and constant related instances
"""
SETTINGS_LOC = "/opt/OpenvStorage/ci/config/settings.json"

FIO_BIN = {'url': 'http://www.include.gr/fio.bin.latest', 'location': '/tmp/fio.bin.latest'}
FIO_BIN_EE = {'url': 'http://www.include.gr/fio.bin.latest.ee', 'location': '/tmp/fio.bin.latest'}

with open(CONFIG_LOC, 'r') as JSON_CONFIG:
SETUP_CFG = json.load(JSON_CONFIG)

with open(SETTINGS_LOC, 'r') as JSON_SETTINGS:
SETTINGS = json.load(JSON_SETTINGS)

DATA_TEST_CASES = [(0, 100), (30, 70), (40, 60), (50, 50), (70, 30), (100, 0)] # read write patterns to test (read, write)

CLOUD_INIT_DATA = {
'script_loc': 'http://fileserver.cloudfounders.com/QA/cloud-init/create-config-drive',
'script_dest': '/tmp/cloud_init_script.sh',
'user-data_loc': '/tmp/user-data-migrate-test',
'config_dest': '/tmp/cloud-init-config-migrate-test'
}

# collect details about parent hypervisor
PARENT_HYPERVISOR_INFO = SETUP_CFG['ci'].get('hypervisor')
'config_dest': '/tmp/cloud-init-config-migrate-test'}

# hypervisor details
HYPERVISOR_TYPE = SETUP_CFG['ci']['local_hypervisor']['type']
HYPERVISOR_USER = SETUP_CFG['ci']['local_hypervisor']['user']
HYPERVISOR_PASSWORD = SETUP_CFG['ci']['local_hypervisor']['password']

HYPERVISOR_INFO = {'type': HYPERVISOR_TYPE,
'user': HYPERVISOR_USER,
'password': HYPERVISOR_PASSWORD}

VM_USERNAME = 'root' # vm credentials & details
VM_PASSWORD = 'rooter'
VM_VCPUS = 4
VM_VRAM = 1024 # In MB
VM_OS_TYPE = 'ubuntu16.04'
VM_CREATION_TIMEOUT = 12 * 60

VM_WAIT_TIME = 300 # wait time before timing out on the vm install in seconds

Expand All @@ -70,36 +50,7 @@ class CIConstants(object):
IO_REFRESH_RATE = 5 # Refresh rate used for polling IO
AMOUNT_TO_WRITE = 1 * 1024 ** 3 # Amount of data to RW to produce IO

HA_TIMEOUT = 300

@classmethod
def get_api_instance(cls):
"""
Fetches the api instance using the constants provided by the configuration files
:return: ovsclient instance
:rtype: ci.api_lib.helpers.api.OVSClient
"""
return OVSClient(cls.SETUP_CFG['ci']['grid_ip'],
cls.SETUP_CFG['ci']['user']['api']['username'],
cls.SETUP_CFG['ci']['user']['api']['password'])

@classmethod
def get_parent_hypervisor_instance(cls):
"""
Fetches the parent hypervisor instance
:return: Hypervisor instance
"""
required_params = {'ip': (str, Toolbox.regex_ip),
'user': (str, None),
'password': (str, None),
'type': (str, ['KVM', 'VMWARE'])}
if not isinstance(cls.PARENT_HYPERVISOR_INFO, dict):
raise TypeError('Expecting the parenthypervisor entry to be present in the configuration.')
Toolbox.verify_required_params(required_params, cls.PARENT_HYPERVISOR_INFO)
return HypervisorFactory.get(cls.PARENT_HYPERVISOR_INFO['ip'],
cls.PARENT_HYPERVISOR_INFO['user'],
cls.PARENT_HYPERVISOR_INFO['password'],
cls.PARENT_HYPERVISOR_INFO['type'])
HA_TIMEOUT = 400

@classmethod
def get_shell_user(cls):
Expand All @@ -111,37 +62,13 @@ def get_shell_user(cls):
return {'username': cls.SETUP_CFG['ci']['user']['shell']['username'],
'password': cls.SETUP_CFG['ci']['user']['shell']['password']}

@classmethod
def get_storagerouters_by_role(cls):
"""
Gets storagerouters based on roles
:return:
"""
voldr_str_1 = None # Will act as volumedriver node
voldr_str_2 = None # Will act as volumedriver node
compute_str = None # Will act as compute node
if isinstance(cls.PARENT_HYPERVISOR_INFO, dict): # Hypervisor section is filled in -> VM environment
nodes_info = cls.PARENT_HYPERVISOR_INFO['vms']
elif cls.SETUP_CFG['ci'].get('nodes') is not None: # Physical node section -> Physical environment
nodes_info = cls.SETUP_CFG['ci']['nodes']
else:
raise RuntimeError('Unable to fetch node information. Either hypervisor section or node section is missing!')
for node_ip, node_details in nodes_info.iteritems():
if node_details['role'] == "VOLDRV":
if voldr_str_1 is None:
voldr_str_1 = StoragerouterHelper.get_storagerouter_by_ip(node_ip)
elif voldr_str_2 is None:
voldr_str_2 = StoragerouterHelper.get_storagerouter_by_ip(node_ip)
elif node_details['role'] == "COMPUTE" and compute_str is None:
compute_str = StoragerouterHelper.get_storagerouter_by_ip(node_ip)
assert voldr_str_1 is not None and voldr_str_2 is not None and compute_str is not None,\
'Could not fetch 2 storagediver nodes and 1 compute node based on the setup.json config.'
return voldr_str_1, voldr_str_2, compute_str

@classmethod
def get_images(cls):
"""
Gets images specified in the settings.json
:return:
"""
return cls.SETTINGS['images']

with open(SETTINGS_LOC, 'r') as JSON_SETTINGS:
SETTINGS = json.load(JSON_SETTINGS)
7 changes: 3 additions & 4 deletions ci/scenario_helpers/data_writing.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,7 @@
import math
import uuid
from ovs.extensions.generic.logger import Logger
from ovs.lib.helpers.toolbox import Toolbox

from ovs_extensions.generic.toolbox import ExtensionsToolbox

class DataWriter(object):
"""
Expand Down Expand Up @@ -56,7 +55,7 @@ def write_data_fio(cls, client, fio_configuration, edge_configuration=None, file
'output_format': (str, ['normal', 'terse', 'json'], False), # Output format of fio
'io_size': (int, None), # Nr of bytes to write/read
'configuration': (tuple, None)} # configuration params for fio.First value represents read, second one write percentage eg (10, 90)
Toolbox.verify_required_params(required_fio_params, fio_configuration)
ExtensionsToolbox.verify_required_params(required_fio_params, fio_configuration)
if isinstance(edge_configuration, dict):
required_edge_params = {'volumenames': (list, str),
'port': (int, {'min': 1, 'max': 65535}),
Expand All @@ -65,7 +64,7 @@ def write_data_fio(cls, client, fio_configuration, edge_configuration=None, file
'fio_bin_location': (str, None),
'username': (str, None, False),
'password': (str, None, False)}
Toolbox.verify_required_params(required_edge_params, edge_configuration)
ExtensionsToolbox.verify_required_params(required_edge_params, edge_configuration)
bs = fio_configuration.get('bs', '4k')
iodepth = fio_configuration.get('iodepth', 32)
fio_output_format = fio_configuration.get('output_format', 'json')
Expand Down
154 changes: 154 additions & 0 deletions ci/scenario_helpers/setup.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,154 @@
# Copyright (C) 2018 iNuron NV
#
# This file is part of Open vStorage Open Source Edition (OSE),
# as available from
#
# http://www.openvstorage.org and
# http://www.openvstorage.com.
#
# This file is free software; you can redistribute it and/or modify it
# under the terms of the GNU Affero General Public License v3 (GNU AGPLv3)
# as published by the Free Software Foundation, in version 3 as it comes
# in the LICENSE.txt file of the Open vStorage OSE distribution.
#
# Open vStorage is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY of any kind.

import random
from ci.scenario_helpers.ci_constants import CIConstants
from ci.api_lib.helpers.domain import DomainHelper
from ci.api_lib.helpers.storagedriver import StoragedriverHelper
from ci.api_lib.helpers.storagerouter import StoragerouterHelper
from ci.api_lib.helpers.system import SystemHelper
from ci.api_lib.helpers.vpool import VPoolHelper

from ovs.extensions.generic.logger import Logger


class SetupHelper(CIConstants):
"""
Setup helper that aids in building test environments required in vm-dependent integration tests
"""
LOGGER = Logger('scenario_helpers-setup_helper')

@classmethod
def setup_cloud_info(cls, client, src_std):
"""
Retrieve the cloud init file
:param client: SSHclient to use for cloud initialization
:type client: ovs.extensions.generic.SSHClient
:param src_std: storagedriver to check which edition is running
:type src_std: ovs.dal.hybrids.StorageDriver
:return:
"""
cloud_init_loc = cls.CLOUD_INIT_DATA.get('script_dest')
client.run(['wget', cls.CLOUD_INIT_DATA.get('script_loc'), '-O', cloud_init_loc])
client.file_chmod(cloud_init_loc, 755)
assert client.file_exists(cloud_init_loc), 'Could not fetch the cloud init script'
is_ee = SystemHelper.get_ovs_version(src_std.storagerouter) == 'ee'
return cloud_init_loc, is_ee

@classmethod
def get_vpool_with_2_storagedrivers(cls):
"""
Check for all vpools if there is at least one containing two storagedrivers
:return: ovs.dal.hybrids.vpool
"""
vpool = None
for vp in VPoolHelper.get_vpools():
if len(vp.storagedrivers) >= 2 and vp.configuration['dtl_mode'] == 'sync' and vp.name in cls.get_vpool_names():
vpool = vp
return vpool
assert vpool is not None, 'We need at least one vpool with two storagedrivers'

@classmethod
def check_images(cls, client):
"""
Check if enough images are available on the provided node
:param client: SSHclient to check for images
:type client: ovs.extensions.generic.SSHClient
:return: str
"""
images = cls.get_images()
assert len(images) >= 1, 'We require an cloud init bootable image file.'
image_path = images[0]
assert client.file_exists(image_path), 'Image `{0}` does not exists on `{1}`!'.format(images[0], client.ip)
return image_path

@classmethod
def get_fio_bin_path(cls, client, is_ee):
"""
Returns the location of the fio binary
:param client: sshclient to connect with
:param is_ee: boolean whether the install is ee edition or not
:return:
"""
if is_ee is True:
fio_bin_loc = cls.FIO_BIN_EE['location']
fio_bin_url = cls.FIO_BIN_EE['url']
else:
fio_bin_loc = cls.FIO_BIN['location']
fio_bin_url = cls.FIO_BIN['url']
# Get the fio binary
client.run(['wget', fio_bin_url, '-O', fio_bin_loc])
client.file_chmod(fio_bin_loc, 755)
assert client.file_exists(fio_bin_loc), 'Could not get the latest fio binary.'
return fio_bin_loc

@classmethod
def setup_env(cls, domain_based=False):
"""
Return a dict containing instances of storagedrivers and storagerouters
:param domain_based:
:return: dict
"""
vpool = None
if domain_based:
destination_str, source_str, compute_str = StoragerouterHelper().get_storagerouters_by_role()
destination_storagedriver = None
source_storagedriver = None
if len(source_str.regular_domains) == 0:
storagedrivers = StoragedriverHelper.get_storagedrivers()
else:
storagedrivers = DomainHelper.get_storagedrivers_in_same_domain(domain_guid=source_str.regular_domains[0])
for storagedriver in storagedrivers:
if len(storagedriver.vpool.storagedrivers) < 2:
continue
if storagedriver.vpool.name not in cls.get_vpool_names():
continue
if storagedriver.guid in destination_str.storagedrivers_guids:
if destination_storagedriver is None and (source_storagedriver is None or source_storagedriver.vpool_guid == storagedriver.vpool_guid):
destination_storagedriver = storagedriver
cls.LOGGER.info('Chosen destination storagedriver is: {0}'.format(destination_storagedriver.storage_ip))
elif storagedriver.guid in source_str.storagedrivers_guids:
# Select if the source driver isn't select and destination is also unknown or the storagedriver has matches with the same vpool
if source_storagedriver is None and (destination_storagedriver is None or destination_storagedriver.vpool_guid == storagedriver.vpool_guid):
source_storagedriver = storagedriver
cls.LOGGER.info('Chosen source storagedriver is: {0}'.format(source_storagedriver.storage_ip))
assert source_storagedriver is not None and destination_storagedriver is not None, 'We require at least two storagedrivers within the same domain.'

else:
vpool = SetupHelper.get_vpool_with_2_storagedrivers()

available_storagedrivers = [storagedriver for storagedriver in vpool.storagedrivers]
destination_storagedriver = available_storagedrivers.pop(random.randrange(len(available_storagedrivers)))
source_storagedriver = available_storagedrivers.pop(random.randrange(len(available_storagedrivers)))
destination_str = destination_storagedriver.storagerouter # Will act as volumedriver node
source_str = source_storagedriver.storagerouter # Will act as volumedriver node
compute_str = [storagerouter for storagerouter in StoragerouterHelper.get_storagerouters() if
storagerouter.guid not in [destination_str.guid, source_str.guid]][0] # Will act as compute node

# Choose source & destination storage driver
destination_storagedriver = [storagedriver for storagedriver in destination_str.storagedrivers if storagedriver.vpool_guid == vpool.guid][0]
source_storagedriver = [storagedriver for storagedriver in source_str.storagedrivers if storagedriver.vpool_guid == vpool.guid][0]
cls.LOGGER.info('Chosen destination storagedriver is: {0}'.format(destination_storagedriver.storage_ip))
cls.LOGGER.info('Chosen source storagedriver is: {0}'.format(source_storagedriver.storage_ip))

cluster_info = {'storagerouters': {'destination': destination_str,
'source': source_str,
'compute': compute_str},
'storagedrivers': {'destination': destination_storagedriver,
'source': source_storagedriver},
'vpool': vpool}

return cluster_info

0 comments on commit 580dc78

Please sign in to comment.