Skip to content

Commit f74f0f7

Browse files
committed
add network system of multi-host migration
add support for network subsystem. Signed-off-by: Houqi (Nick) Zuo <[email protected]>
1 parent df34975 commit f74f0f7

File tree

13 files changed

+433
-0
lines changed

13 files changed

+433
-0
lines changed

virttest/vt_agent/managers/resource_backings/__init__.py

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,10 +4,15 @@
44
_NfsPoolConnection,
55
_NfsVolumeBacking,
66
)
7+
from .network import (
8+
_TapPortBacking,
9+
_TapNetworkConnection,
10+
)
711

812
_pool_conn_classes = dict()
913
_pool_conn_classes[_DirPoolConnection.get_pool_type()] = _DirPoolConnection
1014
_pool_conn_classes[_NfsPoolConnection.get_pool_type()] = _NfsPoolConnection
15+
_pool_conn_classes[_TapNetworkConnection.get_pool_type()] = _TapNetworkConnection
1116

1217
_backing_classes = dict()
1318
_backing_classes[_DirVolumeBacking.get_pool_type()] = {
@@ -16,6 +21,9 @@
1621
_backing_classes[_NfsVolumeBacking.get_pool_type()] = {
1722
_NfsVolumeBacking.get_resource_type(): _NfsVolumeBacking,
1823
}
24+
_backing_classes[_TapPortBacking.get_pool_type()] = {
25+
_TapPortBacking.get_resource_type(): _TapPortBacking,
26+
}
1927

2028

2129
def get_resource_backing_class(pool_type, resource_type):
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
from .tap import _TapPortBacking, _TapNetworkConnection
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
from .tap_backing import _TapPortBacking
2+
from .tap_network_connection import _TapNetworkConnection
Lines changed: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,78 @@
1+
import logging
2+
3+
from virttest import utils_misc
4+
from virttest.vt_utils.net import interface, tap
5+
from virttest.vt_utils.net.drivers import bridge
6+
7+
from ...backing import _ResourceBacking
8+
9+
LOG = logging.getLogger("avocado.service.resource_backings.network.tap" + __name__)
10+
11+
12+
class _TapPortBacking(_ResourceBacking):
13+
_SOURCE_POOL_TYPE = "linux_bridge"
14+
_BINDING_RESOURCE_TYPE = "port"
15+
16+
def __init__(self, backing_config):
17+
super().__init__(backing_config)
18+
self.switch = None
19+
self.tap_fd = None
20+
self.tap_ifname = None
21+
22+
def create(self, network_connection):
23+
if not self.switch:
24+
self.switch = network_connection.switch
25+
26+
def destroy(self, network_connection):
27+
super().destroy(network_connection)
28+
self.switch = None
29+
30+
def allocate_resource(self, network_connection, arguments=None):
31+
"""
32+
Create a tap device and put this device in to network_connection.
33+
34+
:params network_connection: the _TapNetworkConnection object.
35+
:type network_connection: class _TapNetworkConnection.
36+
:params arguments: the device's params
37+
:type arguments: dict.
38+
39+
:return: the resource info.
40+
:rtype: dict.
41+
"""
42+
if not self.tap_ifname:
43+
self.tap_ifname = "tap_" + utils_misc.generate_random_string(8)
44+
self.tap_fd = tap.open_tap("/dev/net/tun", self.tap_ifname, vnet_hdr=True)
45+
self.tap_fd = self.tap_fd.split(":")
46+
interface.bring_up_ifname(self.tap_ifname)
47+
bridge.add_to_bridge(self.tap_ifname, self.switch)
48+
49+
return self.get_resource_info(network_connection)
50+
51+
def release_resource(self, network_connection, arguments=None):
52+
bridge.del_from_bridge(self.tap_ifname)
53+
interface.bring_down_ifname(self.tap_ifname)
54+
self.tap_fd = None
55+
self.tap_ifname = None
56+
57+
return self.get_resource_info(network_connection)
58+
59+
def get_resource_info(self, network_connection=None, arguments=None):
60+
if self.switch and self.tap_fd and self.tap_ifname:
61+
allocated = (
62+
True
63+
if self.switch in (bridge.find_bridge_name(self.tap_ifname),)
64+
else False
65+
)
66+
else:
67+
allocated = False
68+
69+
return {
70+
"meta": {
71+
"allocated": allocated,
72+
},
73+
"spec": {
74+
"switch": self.switch,
75+
"fds": self.tap_fd,
76+
"ifname": self.tap_ifname,
77+
},
78+
}
Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
import logging
2+
3+
from virttest.vt_utils.net import interface
4+
from virttest.vt_utils.net.drivers import bridge
5+
6+
from ...pool_connection import _ResourcePoolConnection
7+
8+
LOG = logging.getLogger("avocado.service.resource_backings.network.tap." + __name__)
9+
10+
11+
class _TapNetworkConnection(_ResourcePoolConnection):
12+
_CONNECT_POOL_TYPE = "linux_bridge"
13+
14+
def __init__(self, pool_config):
15+
super().__init__(pool_config)
16+
self._switch = pool_config["spec"]["switch"]
17+
self._export = pool_config["spec"]["export"]
18+
19+
def open(self):
20+
# TODO
21+
pass
22+
23+
def close(self):
24+
# TODO
25+
pass
26+
27+
@property
28+
def connected(self):
29+
if_info = interface.net_get_iface_info(self._switch)
30+
if (
31+
if_info[0]
32+
and if_info[0]["operstate"] in ("UP",)
33+
and (
34+
bridge.find_bridge_name(self._export) in (self._switch,)
35+
or self._export is ""
36+
)
37+
):
38+
return True
39+
return False
40+
41+
@property
42+
def switch(self):
43+
return self._switch
44+
45+
@property
46+
def export(self):
47+
return self._export

virttest/vt_netmgr/__init__.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
from .vt_netmgr import vt_netmgr

virttest/vt_netmgr/vt_netmgr.py

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
import logging
2+
3+
from virttest.vt_resmgr import resmgr
4+
5+
LOG = logging.getLogger("avocado." + __name__)
6+
7+
8+
class _VTNetworkManager(object):
9+
def __init__(self):
10+
self._res_config = dict()
11+
self._resource_id = dict()
12+
13+
def define_and_create_network(self, network_name, params, net_type="port"):
14+
LOG.debug(f"Defining the network configuration for {network_name}")
15+
self._res_config[network_name] = resmgr.define_resource_config(
16+
network_name, net_type, params
17+
)
18+
LOG.debug(f"Done to define the network configuration for {network_name}")
19+
20+
LOG.debug(f"Create the network object for {network_name}")
21+
self._resource_id[network_name] = resmgr.create_resource_object(
22+
self._res_config[network_name]
23+
)
24+
LOG.debug(f"Done to create the network object for {network_name}")
25+
26+
return self._resource_id[network_name]
27+
28+
def operation(self, resource_id, operation_params):
29+
resmgr.update_resource(resource_id, operation_params)
30+
31+
def query_resource_id(self, network_name):
32+
"""
33+
Return all network names.
34+
35+
:return: All network names.
36+
:rtype: list
37+
"""
38+
return self._resource_id[network_name]
39+
40+
def query_all_network_names(self):
41+
"""
42+
Return all network names.
43+
44+
:return: All network names.
45+
:rtype: list
46+
"""
47+
return list(self._resource_id.keys())
48+
49+
50+
vt_netmgr = _VTNetworkManager()

virttest/vt_resmgr/resources/__init__.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,13 +2,15 @@
22
# from .cvm import _TdxPool
33
# from .storage import _CephPool
44
from .storage import _DirPool, _NfsPool
5+
from .network import _LinuxBridgeNetwork
56

67
_pool_classes = dict()
78
# _pool_classes[_SnpPool.get_pool_type()] = _SnpPool
89
# _pool_classes[_TdxPool.get_pool_type()] = _TdxPool
910
# _pool_classes[_CephPool.get_pool_type()] = _CephPool
1011
_pool_classes[_DirPool.get_pool_type()] = _DirPool
1112
_pool_classes[_NfsPool.get_pool_type()] = _NfsPool
13+
_pool_classes[_LinuxBridgeNetwork.get_pool_type()] = _LinuxBridgeNetwork
1214

1315

1416
def get_resource_pool_class(pool_type):
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
from .tap import _LinuxBridgeNetwork
2+
3+
4+
__all__ = (
5+
_LinuxBridgeNetwork,
6+
)
Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
import uuid
2+
from abc import abstractmethod
3+
4+
from ..resource import _Resource
5+
6+
7+
class _PortResource(_Resource):
8+
"""
9+
This class, inherited from _Resource, defines the port resource model.
10+
"""
11+
12+
_RESOURCE_TYPE = "port"
13+
14+
def __init__(self, resource_config):
15+
super().__init__(resource_config)
16+
self._handlers = {
17+
"bind": self.bind,
18+
"unbind": self.unbind,
19+
"allocate": self.allocate,
20+
"release": self.release,
21+
"sync": self.sync,
22+
}
23+
24+
def bind(self, arguments):
25+
"""
26+
Bind the port resource to one worker node.
27+
"""
28+
raise NotImplemented
29+
30+
def unbind(self, arguments):
31+
"""
32+
Unbind the port resource from the worker node.
33+
"""
34+
raise NotImplemented
35+
36+
def allocate(self, arguments):
37+
raise NotImplemented
38+
39+
def release(self, arguments):
40+
raise NotImplemented
41+
42+
def sync(self, arguments):
43+
raise NotImplemented
44+
45+
def create_object(self):
46+
pass
47+
48+
def destroy_object(self):
49+
pass
50+
51+
def define_config_from_self(self, pool_id):
52+
pass
53+
54+
@classmethod
55+
def _define_config_legacy(cls, resource_name, resource_params):
56+
return {
57+
"meta": {
58+
"name": resource_name,
59+
"uuid": None,
60+
"type": cls._RESOURCE_TYPE,
61+
"pool": None,
62+
"allocated": False,
63+
"bindings": dict(),
64+
},
65+
"spec": {},
66+
}
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
from .tap_network import _LinuxBridgeNetwork
2+
from .tap_port import _TapPort
Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
import logging
2+
3+
from virttest.vt_cluster import cluster
4+
5+
from ...pool import _ResourcePool
6+
from .tap_port import get_port_resource_class
7+
8+
LOG = logging.getLogger("avocado." + __name__)
9+
10+
11+
class _LinuxBridgeNetwork(_ResourcePool):
12+
_POOL_TYPE = "linux_bridge"
13+
14+
@classmethod
15+
def define_config(cls, pool_name, pool_params):
16+
config = super().define_config(pool_name, pool_params)
17+
config["spec"].update(
18+
{
19+
"switch": pool_params["switch"],
20+
"export": pool_params.get("export"),
21+
}
22+
)
23+
return config
24+
25+
def customize_pool_config(self, node_name):
26+
config = self.pool_config
27+
config["spec"]["switch"] = config["spec"]["switch"][node_name]["ifname"]
28+
config["spec"]["export"] = config["spec"]["export"][node_name]["ifname"]
29+
return config
30+
31+
@classmethod
32+
def get_resource_class(cls, resource_type):
33+
return get_port_resource_class(resource_type)
34+
35+
def meet_resource_request(self, resource_type, resource_params):
36+
if resource_type not in ("port",) or resource_params.get("nettype") not in (
37+
"bridge",
38+
):
39+
return False
40+
41+
if not self._check_nodes_access(resource_params):
42+
return False
43+
44+
return True
45+
46+
def _check_nodes_access(self, resource_params):
47+
# Note if you want the image is created from a specific pool or
48+
# the image is handled on a specific worker node, you should
49+
# specify its image_pool_name
50+
vm_node_tag = resource_params.get("vm_node")
51+
if vm_node_tag:
52+
# Check if the pool can be accessed by the vm node
53+
vm_node = cluster.get_node_by_tag(vm_node_tag)
54+
if vm_node.name not in self.attaching_nodes:
55+
return False
56+
else:
57+
# Check if the pool can be accessed by one of the partition nodes
58+
node_names = [node.name for node in cluster.partition.nodes]
59+
if not set(self.attaching_nodes).intersection(set(node_names)):
60+
return False
61+
62+
return True

0 commit comments

Comments
 (0)