Merge "Allow passing multiple VIFs to CNI"
This commit is contained in:
commit
db61a5f991
|
@ -100,7 +100,7 @@ class CNIRunner(object):
|
|||
cni_ip = result.setdefault("ip%s" % ip.version, {})
|
||||
cni_ip['ip'] = "%s/%s" % (ip, subnet.cidr.prefixlen)
|
||||
|
||||
if subnet.gateway:
|
||||
if hasattr(subnet, 'gateway'):
|
||||
cni_ip['gateway'] = str(subnet.gateway)
|
||||
|
||||
if subnet.routes.objects:
|
||||
|
|
|
@ -55,7 +55,7 @@ def _enable_ipv6(netns):
|
|||
pyroute2.netns.setns(self_ns_fd)
|
||||
|
||||
|
||||
def _configure_l3(vif, ifname, netns):
|
||||
def _configure_l3(vif, ifname, netns, is_default_gateway):
|
||||
with get_ipdb(netns) as ipdb:
|
||||
with ipdb.interfaces[ifname] as iface:
|
||||
for subnet in vif.network.subnets.objects:
|
||||
|
@ -70,21 +70,23 @@ def _configure_l3(vif, ifname, netns):
|
|||
for route in subnet.routes.objects:
|
||||
routes.add(gateway=str(route.gateway),
|
||||
dst=str(route.cidr)).commit()
|
||||
if subnet.gateway:
|
||||
if is_default_gateway and hasattr(subnet, 'gateway'):
|
||||
routes.add(gateway=str(subnet.gateway),
|
||||
dst='default').commit()
|
||||
|
||||
|
||||
def connect(vif, instance_info, ifname, netns=None, report_health=None):
|
||||
def connect(vif, instance_info, ifname, netns=None, report_health=None,
|
||||
is_default_gateway=True):
|
||||
driver = _get_binding_driver(vif)
|
||||
if report_health:
|
||||
report_health(driver.is_healthy())
|
||||
os_vif.plug(vif, instance_info)
|
||||
driver.connect(vif, ifname, netns)
|
||||
_configure_l3(vif, ifname, netns)
|
||||
_configure_l3(vif, ifname, netns, is_default_gateway)
|
||||
|
||||
|
||||
def disconnect(vif, instance_info, ifname, netns=None, report_health=None):
|
||||
def disconnect(vif, instance_info, ifname, netns=None, report_health=None,
|
||||
**kwargs):
|
||||
driver = _get_binding_driver(vif)
|
||||
if report_health:
|
||||
report_health(driver.is_healthy())
|
||||
|
|
|
@ -209,24 +209,32 @@ class CNIDaemonWatcherService(cotyledon.Service):
|
|||
self.healthy.value = False
|
||||
time.sleep(HEALTH_CHECKER_DELAY)
|
||||
|
||||
def on_done(self, pod, vif):
|
||||
def on_done(self, pod, vifs):
|
||||
pod_name = utils.get_pod_unique_name(pod)
|
||||
vif_dict = vif.obj_to_primitive()
|
||||
vif_dict = {
|
||||
ifname: vif.obj_to_primitive() for
|
||||
ifname, vif in vifs.items()
|
||||
}
|
||||
# NOTE(dulek): We need a lock when modifying shared self.registry dict
|
||||
# to prevent race conditions with other processes/threads.
|
||||
with lockutils.lock(pod_name, external=True):
|
||||
if pod_name not in self.registry:
|
||||
self.registry[pod_name] = {'pod': pod, 'vif': vif_dict,
|
||||
self.registry[pod_name] = {'pod': pod, 'vifs': vif_dict,
|
||||
'containerid': None}
|
||||
else:
|
||||
# NOTE(dulek): Only update vif if its status changed, we don't
|
||||
# need to care about other changes now.
|
||||
old_vif = base.VersionedObject.obj_from_primitive(
|
||||
self.registry[pod_name]['vif'])
|
||||
if old_vif.active != vif.active:
|
||||
pod_dict = self.registry[pod_name]
|
||||
pod_dict['vif'] = vif_dict
|
||||
self.registry[pod_name] = pod_dict
|
||||
old_vifs = {
|
||||
ifname:
|
||||
base.VersionedObject.obj_from_primitive(vif_obj) for
|
||||
ifname, vif_obj in (
|
||||
self.registry[pod_name]['vifs'].items())
|
||||
}
|
||||
for iface in vifs.keys():
|
||||
if old_vifs[iface].active != vifs[iface].active:
|
||||
pod_dict = self.registry[pod_name]
|
||||
pod_dict['vifs'] = vif_dict
|
||||
self.registry[pod_name] = pod_dict
|
||||
|
||||
def on_deleted(self, pod):
|
||||
pod_name = utils.get_pod_unique_name(pod)
|
||||
|
|
|
@ -35,29 +35,52 @@ class CNIHandlerBase(k8s_base.ResourceEventHandler):
|
|||
def __init__(self, cni, on_done):
|
||||
self._cni = cni
|
||||
self._callback = on_done
|
||||
self._vif = None
|
||||
self._vifs = {}
|
||||
|
||||
def on_present(self, pod):
|
||||
vif = self._get_vif(pod)
|
||||
vifs = self._get_vifs(pod)
|
||||
|
||||
if vif:
|
||||
self.on_vif(pod, vif)
|
||||
for ifname, vif in vifs.items():
|
||||
self.on_vif(pod, vif, ifname)
|
||||
|
||||
if self.should_callback(pod, vifs):
|
||||
self.callback()
|
||||
|
||||
@abc.abstractmethod
|
||||
def on_vif(self, pod, vif):
|
||||
def should_callback(self, pod, vifs):
|
||||
"""Called after all vifs have been processed
|
||||
|
||||
Should determine if the CNI is ready to call the callback
|
||||
|
||||
:param pod: dict containing Kubernetes Pod object
|
||||
:param vifs: dict containing os_vif VIF objects and ifnames
|
||||
:returns True/False
|
||||
"""
|
||||
raise NotImplementedError()
|
||||
|
||||
def _get_vif(self, pod):
|
||||
@abc.abstractmethod
|
||||
def callback(self):
|
||||
"""Called if should_callback returns True"""
|
||||
raise NotImplementedError()
|
||||
|
||||
@abc.abstractmethod
|
||||
def on_vif(self, pod, vif, ifname):
|
||||
raise NotImplementedError()
|
||||
|
||||
def _get_vifs(self, pod):
|
||||
# TODO(ivc): same as VIFHandler._get_vif
|
||||
try:
|
||||
annotations = pod['metadata']['annotations']
|
||||
vif_annotation = annotations[k_const.K8S_ANNOTATION_VIF]
|
||||
vifs_annotation = annotations[k_const.K8S_ANNOTATION_VIF]
|
||||
except KeyError:
|
||||
return None
|
||||
vif_dict = jsonutils.loads(vif_annotation)
|
||||
vif = obj_vif.vif.VIFBase.obj_from_primitive(vif_dict)
|
||||
LOG.debug("Got VIF from annotation: %r", vif)
|
||||
return vif
|
||||
return {}
|
||||
vifs_annotation = jsonutils.loads(vifs_annotation)
|
||||
vifs_dict = {
|
||||
ifname: obj_vif.vif.VIFBase.obj_from_primitive(vif)
|
||||
for ifname, vif in vifs_annotation.items()
|
||||
}
|
||||
LOG.debug("Got VIFs from annotation: %r", vifs_dict)
|
||||
return vifs_dict
|
||||
|
||||
def _get_inst(self, pod):
|
||||
return obj_vif.instance_info.InstanceInfo(
|
||||
|
@ -69,25 +92,79 @@ class AddHandler(CNIHandlerBase):
|
|||
def __init__(self, cni, on_done):
|
||||
LOG.debug("AddHandler called with CNI env: %r", cni)
|
||||
super(AddHandler, self).__init__(cni, on_done)
|
||||
self._vif = None
|
||||
|
||||
def on_vif(self, pod, vif):
|
||||
if not self._vif:
|
||||
self._vif = vif.obj_clone()
|
||||
self._vif.active = True
|
||||
b_base.connect(self._vif, self._get_inst(pod),
|
||||
self._cni.CNI_IFNAME, self._cni.CNI_NETNS)
|
||||
def on_vif(self, pod, vif, ifname):
|
||||
"""Called once for every vif of a Pod on every event.
|
||||
|
||||
if vif.active:
|
||||
self._callback(vif)
|
||||
If it is the first time we see this vif, plug it in.
|
||||
|
||||
:param pod: dict containing Kubernetes Pod object
|
||||
:param vif: os_vif VIF object
|
||||
:param ifname: string, name of the interfaces inside container
|
||||
"""
|
||||
if ifname not in self._vifs:
|
||||
|
||||
self._vifs[ifname] = vif
|
||||
_vif = vif.obj_clone()
|
||||
_vif.active = True
|
||||
|
||||
# set eth0's gateway as default
|
||||
is_default_gateway = (ifname == self._cni.CNI_IFNAME)
|
||||
b_base.connect(_vif, self._get_inst(pod),
|
||||
ifname, self._cni.CNI_NETNS,
|
||||
is_default_gateway=is_default_gateway)
|
||||
|
||||
def should_callback(self, pod, vifs):
|
||||
"""Called after all vifs have been processed
|
||||
|
||||
Determines if CNI is ready to call the callback and stop watching for
|
||||
more events. For AddHandler the callback should be called if there
|
||||
is at least one VIF in the annotation and all the
|
||||
VIFs recieved are marked active
|
||||
|
||||
:param pod: dict containing Kubernetes Pod object
|
||||
:param vifs: dict containing os_vif VIF objects and ifnames
|
||||
:returns True/False
|
||||
"""
|
||||
all_vifs_active = vifs and all(vif.active for vif in vifs.values())
|
||||
|
||||
if all_vifs_active:
|
||||
if self._cni.CNI_IFNAME in self._vifs:
|
||||
self.callback_vif = self._vifs[self._cni.CNI_IFNAME]
|
||||
else:
|
||||
self.callback_vif = self._vifs.values()[0]
|
||||
LOG.debug("All VIFs are active, exiting. Will return %s",
|
||||
self.callback_vif)
|
||||
return True
|
||||
else:
|
||||
LOG.debug("Waiting for all vifs to become active")
|
||||
return False
|
||||
|
||||
def callback(self):
|
||||
self._callback(self.callback_vif)
|
||||
|
||||
|
||||
class DelHandler(CNIHandlerBase):
|
||||
|
||||
def on_vif(self, pod, vif):
|
||||
def on_vif(self, pod, vif, ifname):
|
||||
b_base.disconnect(vif, self._get_inst(pod),
|
||||
self._cni.CNI_IFNAME, self._cni.CNI_NETNS)
|
||||
self._callback(vif)
|
||||
|
||||
def should_callback(self, pod, vifs):
|
||||
"""Called after all vifs have been processed
|
||||
|
||||
Calls callback if there was at least one vif in the Pod
|
||||
|
||||
:param pod: dict containing Kubernetes Pod object
|
||||
:param vifs: dict containing os_vif VIF objects and ifnames
|
||||
:returns True/False
|
||||
"""
|
||||
if vifs:
|
||||
return True
|
||||
return False
|
||||
|
||||
def callback(self):
|
||||
self._callback(None)
|
||||
|
||||
|
||||
class CallbackHandler(CNIHandlerBase):
|
||||
|
@ -95,9 +172,29 @@ class CallbackHandler(CNIHandlerBase):
|
|||
def __init__(self, on_vif, on_del=None):
|
||||
super(CallbackHandler, self).__init__(None, on_vif)
|
||||
self._del_callback = on_del
|
||||
self._pod = None
|
||||
self._callback_vifs = None
|
||||
|
||||
def on_vif(self, pod, vif):
|
||||
self._callback(pod, vif)
|
||||
def on_vif(self, pod, vif, ifname):
|
||||
pass
|
||||
|
||||
def should_callback(self, pod, vifs):
|
||||
"""Called after all vifs have been processed
|
||||
|
||||
Calls callback if there was at least one vif in the Pod
|
||||
|
||||
:param pod: dict containing Kubernetes Pod object
|
||||
:param vifs: dict containing os_vif VIF objects and ifnames
|
||||
:returns True/False
|
||||
"""
|
||||
self._pod = pod
|
||||
self._callback_vifs = vifs
|
||||
if vifs:
|
||||
return True
|
||||
return False
|
||||
|
||||
def callback(self):
|
||||
self._callback(self._pod, self._callback_vifs)
|
||||
|
||||
def on_deleted(self, pod):
|
||||
LOG.debug("Got pod %s deletion event.", pod['metadata']['name'])
|
||||
|
|
|
@ -22,6 +22,7 @@ from oslo_log import log as logging
|
|||
|
||||
from kuryr_kubernetes.cni.binding import base as b_base
|
||||
from kuryr_kubernetes.cni.plugins import base as base_cni
|
||||
from kuryr_kubernetes import constants as k_const
|
||||
from kuryr_kubernetes import exceptions
|
||||
|
||||
LOG = logging.getLogger(__name__)
|
||||
|
@ -47,7 +48,7 @@ class K8sCNIRegistryPlugin(base_cni.CNIPlugin):
|
|||
'name': params.args.K8S_POD_NAME}
|
||||
|
||||
def add(self, params):
|
||||
vif = self._do_work(params, b_base.connect)
|
||||
vifs = self._do_work(params, b_base.connect)
|
||||
|
||||
pod_name = self._get_pod_name(params)
|
||||
|
||||
|
@ -62,21 +63,26 @@ class K8sCNIRegistryPlugin(base_cni.CNIPlugin):
|
|||
LOG.debug('Saved containerid = %s for pod %s',
|
||||
params.CNI_CONTAINERID, pod_name)
|
||||
|
||||
# Wait for VIF to become active.
|
||||
# Wait for VIFs to become active.
|
||||
timeout = CONF.cni_daemon.vif_annotation_timeout
|
||||
|
||||
# Wait for timeout sec, 1 sec between tries, retry when vif not active.
|
||||
# Wait for timeout sec, 1 sec between tries, retry when even one
|
||||
# vif is not active.
|
||||
@retrying.retry(stop_max_delay=timeout * 1000, wait_fixed=RETRY_DELAY,
|
||||
retry_on_result=lambda x: not x.active)
|
||||
retry_on_result=lambda x: any(
|
||||
map(lambda y: not y[1].active, x.items())))
|
||||
def wait_for_active(pod_name):
|
||||
return base.VersionedObject.obj_from_primitive(
|
||||
self.registry[pod_name]['vif'])
|
||||
return {
|
||||
ifname: base.VersionedObject.obj_from_primitive(vif_obj) for
|
||||
ifname, vif_obj in self.registry[pod_name]['vifs'].items()
|
||||
}
|
||||
|
||||
vif = wait_for_active(pod_name)
|
||||
if not vif.active:
|
||||
raise exceptions.ResourceNotReady(pod_name)
|
||||
vifs = wait_for_active(pod_name)
|
||||
for vif in vifs.values():
|
||||
if not vif.active:
|
||||
raise exceptions.ResourceNotReady(pod_name)
|
||||
|
||||
return vif
|
||||
return vifs[k_const.DEFAULT_IFNAME]
|
||||
|
||||
def delete(self, params):
|
||||
pod_name = self._get_pod_name(params)
|
||||
|
@ -114,13 +120,19 @@ class K8sCNIRegistryPlugin(base_cni.CNIPlugin):
|
|||
try:
|
||||
d = find()
|
||||
pod = d['pod']
|
||||
vif = base.VersionedObject.obj_from_primitive(d['vif'])
|
||||
vifs = {
|
||||
ifname: base.VersionedObject.obj_from_primitive(vif_obj) for
|
||||
ifname, vif_obj in d['vifs'].items()
|
||||
}
|
||||
except KeyError:
|
||||
raise exceptions.ResourceNotReady(pod_name)
|
||||
|
||||
fn(vif, self._get_inst(pod), params.CNI_IFNAME, params.CNI_NETNS,
|
||||
self.report_drivers_health)
|
||||
return vif
|
||||
for ifname, vif in vifs.items():
|
||||
is_default_gateway = (ifname == params.CNI_IFNAME)
|
||||
fn(vif, self._get_inst(pod), ifname, params.CNI_NETNS,
|
||||
report_health=self.report_drivers_health,
|
||||
is_default_gateway=is_default_gateway)
|
||||
return vifs
|
||||
|
||||
def _get_inst(self, pod):
|
||||
return obj_vif.instance_info.InstanceInfo(
|
||||
|
|
|
@ -43,3 +43,5 @@ VIF_POOL_POPULATE = '/populatePool'
|
|||
VIF_POOL_FREE = '/freePool'
|
||||
VIF_POOL_LIST = '/listPools'
|
||||
VIF_POOL_SHOW = '/showPool'
|
||||
|
||||
DEFAULT_IFNAME = 'eth0'
|
||||
|
|
|
@ -33,7 +33,7 @@ class VIFHandler(k8s_base.ResourceEventHandler):
|
|||
the CNI driver (that runs on 'kubelet' nodes) is responsible for providing
|
||||
networking to Kubernetes pods. `VIFHandler` relies on a set of drivers
|
||||
(which are responsible for managing Neutron resources) to define the VIF
|
||||
object and pass it to the CNI driver in form of the Kubernetes pod
|
||||
objects and pass them to the CNI driver in form of the Kubernetes pod
|
||||
annotation.
|
||||
"""
|
||||
|
||||
|
@ -60,38 +60,54 @@ class VIFHandler(k8s_base.ResourceEventHandler):
|
|||
# where certain pods/namespaces/nodes can be managed by other
|
||||
# networking solutions/CNI drivers.
|
||||
return
|
||||
vifs = self._get_vifs(pod)
|
||||
|
||||
vif = self._get_vif(pod)
|
||||
if not vifs:
|
||||
vifs = {}
|
||||
|
||||
if not vif:
|
||||
project_id = self._drv_project.get_project(pod)
|
||||
security_groups = self._drv_sg.get_security_groups(pod, project_id)
|
||||
subnets = self._drv_subnets.get_subnets(pod, project_id)
|
||||
vif = self._drv_vif_pool.request_vif(pod, project_id, subnets,
|
||||
security_groups)
|
||||
|
||||
# NOTE(danil): There is currently no way to actually request
|
||||
# multiple VIFs. However we're packing the main_vif 'eth0' in a
|
||||
# dict here to facilitate future work in this area
|
||||
main_vif = self._drv_vif_pool.request_vif(
|
||||
pod, project_id, subnets, security_groups)
|
||||
vifs[constants.DEFAULT_IFNAME] = main_vif
|
||||
|
||||
try:
|
||||
self._set_vif(pod, vif)
|
||||
self._set_vifs(pod, vifs)
|
||||
except k_exc.K8sClientException as ex:
|
||||
LOG.debug("Failed to set annotation: %s", ex)
|
||||
# FIXME(ivc): improve granularity of K8sClient exceptions:
|
||||
# only resourceVersion conflict should be ignored
|
||||
self._drv_vif_pool.release_vif(pod, vif, project_id,
|
||||
security_groups)
|
||||
elif not vif.active:
|
||||
self._drv_vif_pool.activate_vif(pod, vif)
|
||||
self._set_vif(pod, vif)
|
||||
for ifname, vif in vifs.items():
|
||||
self._drv_for_vif(vif).release_vif(pod, vif, project_id,
|
||||
security_groups)
|
||||
else:
|
||||
changed = False
|
||||
for ifname, vif in vifs.items():
|
||||
if not vif.active:
|
||||
self._drv_for_vif(vif).activate_vif(pod, vif)
|
||||
changed = True
|
||||
if changed:
|
||||
self._set_vifs(pod, vifs)
|
||||
|
||||
def on_deleted(self, pod):
|
||||
if self._is_host_network(pod):
|
||||
return
|
||||
project_id = self._drv_project.get_project(pod)
|
||||
security_groups = self._drv_sg.get_security_groups(pod, project_id)
|
||||
|
||||
vif = self._get_vif(pod)
|
||||
vifs = self._get_vifs(pod)
|
||||
for ifname, vif in vifs.items():
|
||||
self._drv_for_vif(vif).release_vif(pod, vif, project_id,
|
||||
security_groups)
|
||||
|
||||
if vif:
|
||||
project_id = self._drv_project.get_project(pod)
|
||||
security_groups = self._drv_sg.get_security_groups(pod, project_id)
|
||||
self._drv_vif_pool.release_vif(pod, vif, project_id,
|
||||
security_groups)
|
||||
def _drv_for_vif(self, vif):
|
||||
# TODO(danil): a better polymorphism is required here
|
||||
return self._drv_vif_pool
|
||||
|
||||
@staticmethod
|
||||
def _is_host_network(pod):
|
||||
|
@ -106,29 +122,36 @@ class VIFHandler(k8s_base.ResourceEventHandler):
|
|||
except KeyError:
|
||||
return False
|
||||
|
||||
def _set_vif(self, pod, vif):
|
||||
def _set_vifs(self, pod, vifs):
|
||||
# TODO(ivc): extract annotation interactions
|
||||
if vif is None:
|
||||
LOG.debug("Removing VIF annotation: %r", vif)
|
||||
if not vifs:
|
||||
LOG.debug("Removing VIFs annotation: %r", vifs)
|
||||
annotation = None
|
||||
else:
|
||||
vif.obj_reset_changes(recursive=True)
|
||||
LOG.debug("Setting VIF annotation: %r", vif)
|
||||
annotation = jsonutils.dumps(vif.obj_to_primitive(),
|
||||
vifs_dict = {}
|
||||
for ifname, vif in vifs.items():
|
||||
vif.obj_reset_changes(recursive=True)
|
||||
vifs_dict[ifname] = vif.obj_to_primitive()
|
||||
|
||||
annotation = jsonutils.dumps(vifs_dict,
|
||||
sort_keys=True)
|
||||
LOG.debug("Setting VIFs annotation: %r", annotation)
|
||||
k8s = clients.get_kubernetes_client()
|
||||
k8s.annotate(pod['metadata']['selfLink'],
|
||||
{constants.K8S_ANNOTATION_VIF: annotation},
|
||||
resource_version=pod['metadata']['resourceVersion'])
|
||||
|
||||
def _get_vif(self, pod):
|
||||
def _get_vifs(self, pod):
|
||||
# TODO(ivc): same as '_set_vif'
|
||||
try:
|
||||
annotations = pod['metadata']['annotations']
|
||||
vif_annotation = annotations[constants.K8S_ANNOTATION_VIF]
|
||||
except KeyError:
|
||||
return None
|
||||
vif_dict = jsonutils.loads(vif_annotation)
|
||||
vif = obj_vif.vif.VIFBase.obj_from_primitive(vif_dict)
|
||||
LOG.debug("Got VIF from annotation: %r", vif)
|
||||
return vif
|
||||
return {}
|
||||
vif_annotation = jsonutils.loads(vif_annotation)
|
||||
vifs = {
|
||||
ifname: obj_vif.vif.VIFBase.obj_from_primitive(vif_obj) for
|
||||
ifname, vif_obj in vif_annotation.items()
|
||||
}
|
||||
LOG.debug("Got VIFs from annotation: %r", vifs)
|
||||
return vifs
|
||||
|
|
|
@ -59,3 +59,27 @@ def _fake_vif_string(dictionary=None):
|
|||
return jsonutils.dumps(dictionary)
|
||||
else:
|
||||
return jsonutils.dumps(_fake_vif_dict())
|
||||
|
||||
|
||||
def _fake_vifs(cls=osv_vif.VIFOpenVSwitch):
|
||||
return {'eth0': _fake_vif(cls)}
|
||||
|
||||
|
||||
def _fake_vifs_dict(obj=None):
|
||||
if obj:
|
||||
return {
|
||||
ifname: vif.obj_to_primitive() for
|
||||
ifname, vif in obj.items()
|
||||
}
|
||||
else:
|
||||
return {
|
||||
ifname: vif.obj_to_primitive() for
|
||||
ifname, vif in _fake_vifs().items()
|
||||
}
|
||||
|
||||
|
||||
def _fake_vifs_string(dictionary=None):
|
||||
if dictionary:
|
||||
return jsonutils.dumps(dictionary)
|
||||
else:
|
||||
return jsonutils.dumps(_fake_vifs_dict())
|
||||
|
|
|
@ -27,8 +27,8 @@ class TestK8sCNIRegistryPlugin(base.TestCase):
|
|||
super(TestK8sCNIRegistryPlugin, self).setUp()
|
||||
self.pod = {'metadata': {'name': 'foo', 'uid': 'bar',
|
||||
'namespace': 'default'}}
|
||||
self.vif = fake._fake_vif_dict()
|
||||
registry = {'default/foo': {'pod': self.pod, 'vif': self.vif,
|
||||
self.vifs = fake._fake_vifs_dict()
|
||||
registry = {'default/foo': {'pod': self.pod, 'vifs': self.vifs,
|
||||
'containerid': None}}
|
||||
healthy = mock.Mock()
|
||||
self.plugin = k8s_cni_registry.K8sCNIRegistryPlugin(registry, healthy)
|
||||
|
@ -43,7 +43,9 @@ class TestK8sCNIRegistryPlugin(base.TestCase):
|
|||
self.plugin.add(self.params)
|
||||
|
||||
m_lock.assert_called_with('default/foo', external=True)
|
||||
m_connect.assert_called_with(mock.ANY, mock.ANY, 'baz', 123, mock.ANY)
|
||||
m_connect.assert_called_with(mock.ANY, mock.ANY, 'eth0', 123,
|
||||
report_health=mock.ANY,
|
||||
is_default_gateway=mock.ANY)
|
||||
self.assertEqual('cont_id',
|
||||
self.plugin.registry['default/foo']['containerid'])
|
||||
|
||||
|
@ -51,12 +53,13 @@ class TestK8sCNIRegistryPlugin(base.TestCase):
|
|||
def test_del_present(self, m_disconnect):
|
||||
self.plugin.delete(self.params)
|
||||
|
||||
m_disconnect.assert_called_with(mock.ANY, mock.ANY, 'baz', 123,
|
||||
mock.ANY)
|
||||
m_disconnect.assert_called_with(mock.ANY, mock.ANY, 'eth0', 123,
|
||||
report_health=mock.ANY,
|
||||
is_default_gateway=mock.ANY)
|
||||
|
||||
@mock.patch('kuryr_kubernetes.cni.binding.base.disconnect')
|
||||
def test_del_wrong_container_id(self, m_disconnect):
|
||||
registry = {'default/foo': {'pod': self.pod, 'vif': self.vif,
|
||||
registry = {'default/foo': {'pod': self.pod, 'vifs': self.vifs,
|
||||
'containerid': 'different'}}
|
||||
healthy = mock.Mock()
|
||||
self.plugin = k8s_cni_registry.K8sCNIRegistryPlugin(registry, healthy)
|
||||
|
@ -69,9 +72,9 @@ class TestK8sCNIRegistryPlugin(base.TestCase):
|
|||
@mock.patch('kuryr_kubernetes.cni.binding.base.connect')
|
||||
def test_add_present_on_5_try(self, m_connect, m_lock):
|
||||
se = [KeyError] * 5
|
||||
se.append({'pod': self.pod, 'vif': self.vif, 'containerid': None})
|
||||
se.append({'pod': self.pod, 'vif': self.vif, 'containerid': None})
|
||||
se.append({'pod': self.pod, 'vif': self.vif, 'containerid': None})
|
||||
se.append({'pod': self.pod, 'vifs': self.vifs, 'containerid': None})
|
||||
se.append({'pod': self.pod, 'vifs': self.vifs, 'containerid': None})
|
||||
se.append({'pod': self.pod, 'vifs': self.vifs, 'containerid': None})
|
||||
m_getitem = mock.Mock(side_effect=se)
|
||||
m_setitem = mock.Mock()
|
||||
m_registry = mock.Mock(__getitem__=m_getitem, __setitem__=m_setitem)
|
||||
|
@ -81,9 +84,11 @@ class TestK8sCNIRegistryPlugin(base.TestCase):
|
|||
m_lock.assert_called_with('default/foo', external=True)
|
||||
m_setitem.assert_called_once_with('default/foo',
|
||||
{'pod': self.pod,
|
||||
'vif': self.vif,
|
||||
'vifs': self.vifs,
|
||||
'containerid': 'cont_id'})
|
||||
m_connect.assert_called_with(mock.ANY, mock.ANY, 'baz', 123, mock.ANY)
|
||||
m_connect.assert_called_with(mock.ANY, mock.ANY, 'eth0', 123,
|
||||
report_health=mock.ANY,
|
||||
is_default_gateway=mock.ANY)
|
||||
|
||||
@mock.patch('time.sleep', mock.Mock())
|
||||
def test_add_not_present(self):
|
||||
|
|
|
@ -33,6 +33,7 @@ class TestVIFHandler(test_base.TestCase):
|
|||
self._vif = mock.Mock()
|
||||
self._vif.active = True
|
||||
self._vif_serialized = mock.sentinel.vif_serialized
|
||||
self._vifs = {k_const.DEFAULT_IFNAME: self._vif}
|
||||
|
||||
self._pod_version = mock.sentinel.pod_version
|
||||
self._pod_link = mock.sentinel.pod_link
|
||||
|
@ -55,25 +56,28 @@ class TestVIFHandler(test_base.TestCase):
|
|||
self._get_project = self._handler._drv_project.get_project
|
||||
self._get_subnets = self._handler._drv_subnets.get_subnets
|
||||
self._get_security_groups = self._handler._drv_sg.get_security_groups
|
||||
self._set_vif_driver = self._handler._drv_vif_pool.set_vif_driver
|
||||
self._set_vifs_driver = self._handler._drv_vif_pool.set_vif_driver
|
||||
self._request_vif = self._handler._drv_vif_pool.request_vif
|
||||
self._release_vif = self._handler._drv_vif_pool.release_vif
|
||||
self._activate_vif = self._handler._drv_vif_pool.activate_vif
|
||||
self._get_vif = self._handler._get_vif
|
||||
self._set_vif = self._handler._set_vif
|
||||
self._get_vifs = self._handler._get_vifs
|
||||
self._set_vifs = self._handler._set_vifs
|
||||
self._is_host_network = self._handler._is_host_network
|
||||
self._is_pending_node = self._handler._is_pending_node
|
||||
|
||||
self._request_vif.return_value = self._vif
|
||||
self._get_vif.return_value = self._vif
|
||||
self._get_vifs.return_value = self._vifs
|
||||
self._is_host_network.return_value = False
|
||||
self._is_pending_node.return_value = True
|
||||
self._get_project.return_value = self._project_id
|
||||
self._get_subnets.return_value = self._subnets
|
||||
self._get_security_groups.return_value = self._security_groups
|
||||
self._set_vif_driver.return_value = mock.Mock(
|
||||
self._set_vifs_driver.return_value = mock.Mock(
|
||||
spec=drivers.PodVIFDriver)
|
||||
|
||||
self._handler._drv_for_vif = h_vif.VIFHandler._drv_for_vif.__get__(
|
||||
self._handler)
|
||||
|
||||
@mock.patch.object(drivers.VIFPoolDriver, 'set_vif_driver')
|
||||
@mock.patch.object(drivers.VIFPoolDriver, 'get_instance')
|
||||
@mock.patch.object(drivers.PodVIFDriver, 'get_instance')
|
||||
|
@ -82,7 +86,7 @@ class TestVIFHandler(test_base.TestCase):
|
|||
@mock.patch.object(drivers.PodProjectDriver, 'get_instance')
|
||||
def test_init(self, m_get_project_driver, m_get_subnets_driver,
|
||||
m_get_sg_driver, m_get_vif_driver, m_get_vif_pool_driver,
|
||||
m_set_vif_driver):
|
||||
m_set_vifs_driver):
|
||||
project_driver = mock.sentinel.project_driver
|
||||
subnets_driver = mock.sentinel.subnets_driver
|
||||
sg_driver = mock.sentinel.sg_driver
|
||||
|
@ -131,62 +135,62 @@ class TestVIFHandler(test_base.TestCase):
|
|||
def test_on_present(self):
|
||||
h_vif.VIFHandler.on_present(self._handler, self._pod)
|
||||
|
||||
self._get_vif.assert_called_once_with(self._pod)
|
||||
self._get_vifs.assert_called_once_with(self._pod)
|
||||
self._request_vif.assert_not_called()
|
||||
self._activate_vif.assert_not_called()
|
||||
self._set_vif.assert_not_called()
|
||||
self._set_vifs.assert_not_called()
|
||||
|
||||
def test_on_present_host_network(self):
|
||||
self._is_host_network.return_value = True
|
||||
|
||||
h_vif.VIFHandler.on_present(self._handler, self._pod)
|
||||
|
||||
self._get_vif.assert_not_called()
|
||||
self._get_vifs.assert_not_called()
|
||||
self._request_vif.assert_not_called()
|
||||
self._activate_vif.assert_not_called()
|
||||
self._set_vif.assert_not_called()
|
||||
self._set_vifs.assert_not_called()
|
||||
|
||||
def test_on_present_not_pending(self):
|
||||
self._is_pending_node.return_value = False
|
||||
|
||||
h_vif.VIFHandler.on_present(self._handler, self._pod)
|
||||
|
||||
self._get_vif.assert_not_called()
|
||||
self._get_vifs.assert_not_called()
|
||||
self._request_vif.assert_not_called()
|
||||
self._activate_vif.assert_not_called()
|
||||
self._set_vif.assert_not_called()
|
||||
self._set_vifs.assert_not_called()
|
||||
|
||||
def test_on_present_activate(self):
|
||||
self._vif.active = False
|
||||
|
||||
h_vif.VIFHandler.on_present(self._handler, self._pod)
|
||||
|
||||
self._get_vif.assert_called_once_with(self._pod)
|
||||
self._get_vifs.assert_called_once_with(self._pod)
|
||||
self._activate_vif.assert_called_once_with(self._pod, self._vif)
|
||||
self._set_vif.assert_called_once_with(self._pod, self._vif)
|
||||
self._set_vifs.assert_called_once_with(self._pod, self._vifs)
|
||||
self._request_vif.assert_not_called()
|
||||
|
||||
def test_on_present_create(self):
|
||||
self._get_vif.return_value = None
|
||||
self._get_vifs.return_value = {}
|
||||
|
||||
h_vif.VIFHandler.on_present(self._handler, self._pod)
|
||||
|
||||
self._get_vif.assert_called_once_with(self._pod)
|
||||
self._get_vifs.assert_called_once_with(self._pod)
|
||||
self._request_vif.assert_called_once_with(
|
||||
self._pod, self._project_id, self._subnets, self._security_groups)
|
||||
self._set_vif.assert_called_once_with(self._pod, self._vif)
|
||||
self._set_vifs.assert_called_once_with(self._pod, self._vifs)
|
||||
self._activate_vif.assert_not_called()
|
||||
|
||||
def test_on_present_rollback(self):
|
||||
self._get_vif.return_value = None
|
||||
self._set_vif.side_effect = k_exc.K8sClientException
|
||||
self._get_vifs.return_value = {}
|
||||
self._set_vifs.side_effect = k_exc.K8sClientException
|
||||
|
||||
h_vif.VIFHandler.on_present(self._handler, self._pod)
|
||||
|
||||
self._get_vif.assert_called_once_with(self._pod)
|
||||
self._get_vifs.assert_called_once_with(self._pod)
|
||||
self._request_vif.assert_called_once_with(
|
||||
self._pod, self._project_id, self._subnets, self._security_groups)
|
||||
self._set_vif.assert_called_once_with(self._pod, self._vif)
|
||||
self._set_vifs.assert_called_once_with(self._pod, self._vifs)
|
||||
self._release_vif.assert_called_once_with(self._pod, self._vif,
|
||||
self._project_id,
|
||||
self._security_groups)
|
||||
|
@ -195,7 +199,7 @@ class TestVIFHandler(test_base.TestCase):
|
|||
def test_on_deleted(self):
|
||||
h_vif.VIFHandler.on_deleted(self._handler, self._pod)
|
||||
|
||||
self._get_vif.assert_called_once_with(self._pod)
|
||||
self._get_vifs.assert_called_once_with(self._pod)
|
||||
self._release_vif.assert_called_once_with(self._pod, self._vif,
|
||||
self._project_id,
|
||||
self._security_groups)
|
||||
|
@ -205,13 +209,13 @@ class TestVIFHandler(test_base.TestCase):
|
|||
|
||||
h_vif.VIFHandler.on_deleted(self._handler, self._pod)
|
||||
|
||||
self._get_vif.assert_not_called()
|
||||
self._get_vifs.assert_not_called()
|
||||
self._release_vif.assert_not_called()
|
||||
|
||||
def test_on_deleted_no_annotation(self):
|
||||
self._get_vif.return_value = None
|
||||
self._get_vifs.return_value = {}
|
||||
|
||||
h_vif.VIFHandler.on_deleted(self._handler, self._pod)
|
||||
|
||||
self._get_vif.assert_called_once_with(self._pod)
|
||||
self._get_vifs.assert_called_once_with(self._pod)
|
||||
self._release_vif.assert_not_called()
|
||||
|
|
Loading…
Reference in New Issue