Skip to content

Commit

Permalink
network: re-enable test_ipv6_support module
Browse files Browse the repository at this point in the history
Re-enable tests and refactor.

Change-Id: Ib47213ddad77366f881ab0f2e83a305c06b40e1a
Signed-off-by: Eitan Raviv <[email protected]>
  • Loading branch information
erav committed Feb 25, 2022
1 parent 6250f3f commit a780d33
Show file tree
Hide file tree
Showing 5 changed files with 122 additions and 243 deletions.
92 changes: 0 additions & 92 deletions network-suite-master/fixtures/fqdn.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@
import pytest

from ovirtlib import sshlib
from ovirtlib import syncutil

OVN_CONF = '/etc/ovirt-provider-ovn/conf.d/10-setup-ovirt-provider-ovn.conf'

Expand Down Expand Up @@ -35,94 +34,3 @@ def _fetch_fqdn(answer_file):
for line in f:
if line.startswith(FQDN_ENTRY):
return line.strip().split(':', 1)[1]


@pytest.fixture(scope='session')
def host0_eth2_ipv6(host0_facts):
"""
nics created by lago are managed by nmcli and have autoconf ipv6 but have
not been assigned an address. this function requests a dynamic assignment
of an ipv6 to 'eth2' and retrieves it.
:return: the ipv6 address as string
:raise: timeout exception if global ipv6 address not found on NIC
"""
host_0 = sshlib.Node(host0_facts.default_ip(), host0_facts.ssh_password)
return _enable_dynamic_ipv6(host_0, 'eth2')


@pytest.fixture(scope='session')
def host0_eth1_ipv6(host0_facts):
"""
nics created by lago are managed by nmcli and have autoconf ipv6 but have
not been assigned an address. this function requests a dynamic assignment
of an ipv6 to 'eth1' and retrieves it.
:return: the ipv6 address as string
:raise: timeout exception if global ipv6 address not found on NIC
"""
host_0 = sshlib.Node(host0_facts.default_ip(), host0_facts.ssh_password)
return _enable_dynamic_ipv6(host_0, 'eth1')


@pytest.fixture(scope='session')
def engine_storage_ipv6(engine_facts):
"""
lago creates a network with an ipv6 subnet and connects it to NIC
'eth1' of the engine. It names the network 'storage' but does not assign an
ipv6 address to the NIC.
this function requests a dynamic assignment of an ipv6 to 'eth1' of the
engine machine and retrieves it.
:return: the ipv6 address as string
:raise: timeout exception if global ipv6 address not found on NIC
"""
engine = sshlib.Node(engine_facts.default_ip(), engine_facts.ssh_password)
ENGINE_STORAGE_NIC = 'eth1'
return _enable_dynamic_ipv6(engine, ENGINE_STORAGE_NIC)


def _enable_dynamic_ipv6(ssh_node, nic_name):
"""
this function connects to the specified lago VM using its ssh API to:
* request the host OS to dynamically assign an ipv6 address to the
specified NIC
* wait for the address to be assigned (it might take up to a few seconds)
* retrieve the address
:return: the ipv6 address as string
:raise: timeout exception if global ipv6 address not found on NIC
"""
_assign_ipv6(ssh_node, nic_name)
return syncutil.sync(
exec_func=_get_ipv6,
exec_func_args=(ssh_node, nic_name),
success_criteria=lambda ipv6: ipv6 != '',
timeout=10,
)


def _assign_ipv6(ssh_node, nic_name):
"""
lago creates ipv6 subnets and sets ipv6 autoconf on its VMs' NICs but does
not assign ipv6 addresses to the NICs.
this function connects to a lago VM using its ssh API and requests an ipv6
address be assigned to the NIC using nmcli.
:param ssh_node: an sshlib.Node that exposes an ssh API into itself
:param nic_name: the name of the NIC to assign an ipv6 address to
:raise: exception if an error occurred during the assignment
"""
res = ssh_node.exec_command(' '.join(['nmcli', 'con', 'modify', nic_name, 'ipv6.method', 'auto']))

if res.code:
raise Exception('nmcli con modify failed: exit code %s, error "%s"' % (res.code, res.err))
res = ssh_node.exec_command(' '.join(['nmcli', 'con', 'up', nic_name]))
if res.code:
raise Exception('nmcli con up failed: exit code %s, error "%s"' % (res.code, res.err))


def _get_ipv6(ssh_node, nic_name):
"""
:param ssh_node: an sshlib.Node that exposes an ssh API into itself
:param nic_name: the name of the NIC from which to get the ipv6 address
:return: the ipv6 address of the lago vm on eth1 as string or empty string
"""
INET6 = 'inet6 '
res = ssh_node.exec_command(['ip -o -6 a show', nic_name, 'scope global'])
return res.out[res.out.find(INET6) + len(INET6) : res.out.find('/')]
9 changes: 2 additions & 7 deletions network-suite-master/fixtures/storage.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,16 +22,11 @@ def default_storage_domain(system, engine_facts, host_0_up, default_data_center)
try:
storage_domain.import_by_name(DEFAULT_DOMAIN_NAME)
except EntityNotFoundError:
nfs_storage_data = storagelib.NfsStorageData(engine_facts.default_ip(urlize=True), DEFAULT_DOMAIN_PATH)
storage_domain.create(
name=DEFAULT_DOMAIN_NAME,
domain_type=storagelib.StorageDomainType.DATA,
host=host_0_up,
host_storage_data=storagelib.HostStorageData(
storage_type=storagelib.StorageType.NFS,
address=engine_facts.default_ip(urlize=True),
path=DEFAULT_DOMAIN_PATH,
nfs_version=storagelib.NfsVersion.V4_2,
),
host_storage_data=nfs_storage_data,
)
storage_domain.wait_for_unattached_status()
default_data_center.attach_storage_domain(storage_domain)
Expand Down
123 changes: 82 additions & 41 deletions network-suite-master/ovirtlib/storagelib.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
# SPDX-License-Identifier: GPL-2.0-or-later
#
#
import abc
import contextlib

from ovirtsdk4 import types
Expand Down Expand Up @@ -55,25 +56,26 @@ class NfsVersion(object):
V4_2 = types.NfsVersion.V4_2


class HostStorageData(object):
def __init__(self, storage_type, address, path, nfs_version=None, logical_units=()):
class HostStorageData(metaclass=abc.ABCMeta):
def __init__(self, storage_type, domain_type, address=None, path=None):
"""
:param storage_type: string indicates the storage type.
:param address: string indicates the NFS storage address.
:param path: string indicates the NFS storage path.
:param nfs_version: string indicates the NFS storage version.
:param logical_units: tuple of LogicalUnits.
Represent logical units (luns) in case of an iSCSI storage domain.
:param storage_type: storagelib.StorageType
:param domain_type: storagelib.StorageDomainType
:param address: string indicates the storage address.
:param path: string indicates the storage path.
"""
self._type = storage_type
self._storage_type = storage_type
self._domain_type = domain_type
self._address = address
self._path = path
self._nfs_version = nfs_version
self._logical_units = logical_units

@property
def type(self):
return self._type
def storage_type(self):
return self._storage_type

@property
def domain_type(self):
return self._domain_type

@property
def address(self):
Expand All @@ -83,14 +85,64 @@ def address(self):
def path(self):
return self._path

@abc.abstractmethod
def as_sdk_type(self):
"""
:return: representation of this object as the equivalent ovirtsdk4.types object.
ovirtlib is a wrapper and encapsulator of ovirtsdk4.types and ovirtsdk4.services,
so this method should not be used outside ovirtlib
"""


class NfsStorageData(HostStorageData):
def __init__(self, address, path, domain_type=StorageDomainType.DATA, version=NfsVersion.V4_2):
super(NfsStorageData, self).__init__(StorageType.NFS, address, path, domain_type)
self._version = version

@property
def nfs_version(self):
return self._nfs_version
def version(self):
return self._version

def as_sdk_type(self):
return types.HostStorage(
type=self.storage_type,
address=self.address,
path=self.path,
nfs_version=self.version,
)

def __repr__(self):
return (
f'<{self.__class__.__name__}| '
f'address:{self.address}, '
f'path:{self.path}, '
f'version:{self.version}>'
f'domain_type:{self.domain_type}, '
)


class IscsiStorageData(HostStorageData):
def __init__(self, domain_type=StorageDomainType.DATA, logical_units=()):
super(IscsiStorageData, self).__init__(StorageType.ISCSI, domain_type)
self._logical_units = logical_units

@property
def logical_units(self):
return self._logical_units

def as_sdk_type(self):
return types.HostStorage(
type=self.storage_type,
address=self.address,
path=self.path,
logical_units=[lun.as_sdk_type() for lun in self.logical_units],
)

def __repr__(self):
return (
f'<{self.__class__.__name__}| logical_units:{self.logical_units}, domain_type:{self.domain_type}>'
)


class StorageDomainStatus(object):

Expand All @@ -111,24 +163,17 @@ def status(self):
def wait_for_unattached_status(self):
self._wait_for_status(StorageDomainStatus.UNATTACHED)

def create(self, name, host, domain_type, host_storage_data):
def create(self, name, host, host_storage_data):
"""
:param name: string
:param host: hostlib.Host
:param domain_type: StorageDomainType
:param host_storage_data: HostStorageData
"""
sdk_type = types.StorageDomain(
name=name,
host=host.get_sdk_type(),
type=domain_type,
storage=types.HostStorage(
type=host_storage_data.type,
address=host_storage_data.address,
path=host_storage_data.path,
nfs_version=host_storage_data.nfs_version,
logical_units=self._get_sdk_type_logical_units(host_storage_data.logical_units),
),
type=host_storage_data.domain_type,
storage=host_storage_data.as_sdk_type(),
)
self._create_sdk_entity(sdk_type)

Expand Down Expand Up @@ -180,20 +225,9 @@ def create_disk(self, name):
disk.wait_for_up_status()
return disk

def _get_sdk_type_logical_units(self, logical_units):
return [
types.LogicalUnit(
id=lundata.id,
address=lundata.address,
port=lundata.port,
target=lundata.target,
)
for lundata in logical_units
]

def __repr__(self):
return self._execute_without_raising(
lambda: (f'<{self.__class__.__name__}| ' f'name:{self.name}, ' f'status:{self.status}, ' f'id:{self.id}>')
lambda: f'<{self.__class__.__name__}| name:{self.name}, status:{self.status}, id:{self.id}>'
)


Expand Down Expand Up @@ -233,8 +267,8 @@ def wait_for_up_status(self):


class LogicalUnit(object):
def __init__(self, id, address, port, target):
self._id = id
def __init__(self, lun_id, address, port, target):
self._id = lun_id
self._address = address
self._port = port
self._target = target
Expand All @@ -255,13 +289,20 @@ def port(self):
def target(self):
return self._target

def as_sdk_type(self):
return types.LogicalUnit(id=self.id, address=self.address, port=self.port, target=self.target)

def __repr__(self):
return (
f'<{self.__class__.__name__}| address:{self.address}, port:{self.port}, target:{self.target}, id:{self.id}>'
)


@contextlib.contextmanager
def storage_domain(system, name, domain_type, host, host_storage_data):
def storage_domain(system, name, host, host_storage_data):
sd = StorageDomain(system)
sd.create(
name=name,
domain_type=domain_type,
host=host,
host_storage_data=host_storage_data,
)
Expand Down
5 changes: 2 additions & 3 deletions network-suite-master/test-scenarios/conftest.py
Original file line number Diff line number Diff line change
Expand Up @@ -30,9 +30,6 @@
from fixtures.engine import api
from fixtures.engine import test_invocation_logger

from fixtures.fqdn import engine_storage_ipv6
from fixtures.fqdn import host0_eth1_ipv6
from fixtures.fqdn import host0_eth2_ipv6
from fixtures.fqdn import ovirt_provider_ovn_with_ip_fqdn

from fixtures.storage import default_storage_domain
Expand Down Expand Up @@ -87,6 +84,7 @@
from ost_utils.pytest.fixtures.engine import engine_ip
from ost_utils.pytest.fixtures.engine import engine_ip_url
from ost_utils.pytest.fixtures.engine import engine_ips_for_network
from ost_utils.pytest.fixtures.engine import engine_storage_ips
from ost_utils.pytest.fixtures.engine import engine_username
from ost_utils.pytest.fixtures.env import ost_images_distro
from ost_utils.pytest.fixtures.env import root_dir
Expand All @@ -95,6 +93,7 @@
from ost_utils.pytest.fixtures.env import working_dir
from ost_utils.pytest.fixtures.network import management_network_name
from ost_utils.pytest.fixtures.network import management_subnet
from ost_utils.pytest.fixtures.network import storage_network_name
from ost_utils.pytest.fixtures.network import storage_subnet
from ost_utils.pytest.fixtures.sdk import get_user_service_for_user
from ost_utils.pytest.fixtures.sdk import system_service
Expand Down
Loading

0 comments on commit a780d33

Please sign in to comment.