Michał Dulko 1c2320e11e Prevent pyroute2.IPDB threads leaking
pyroute2.IPDB is an interesting entity. It's much more than a simple
interface to `ip` command, as it is more similar to a database process.
When created IPDB object spawns a thread that will be responsible for
updating the object with changes to the underlying OS. Thread stays up
until the user will call `release()` method.

Turns out code in kuryr_kubernetes.cni.binding wasn't taking that into
account and was slowly leaking threads (and possibly processes). This
became apparent when running Kuryr with CNI daemon enabled.

This commit fixes the problem by switching all IPDB usages to context
managers, so `release()` method is called automatically.  Also the IPDB
objects cache is removed as already released IPDB objects cannot be
reused. kuryr_kubernetes.cni.binding modules were missing unit tests,
this commit adds them as well.

Change-Id: I82afda3f217dac56228677bb66703c3d80e5d751
Closes-Bug: 1728996
2017-11-17 12:30:54 +01:00

74 lines
2.6 KiB
Python

# Copyright (c) 2016 Mirantis, Inc.
# All Rights Reserved.
#
# 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.
import os
from kuryr_kubernetes.cni.binding import base as b_base
from kuryr_kubernetes import linux_net_utils as net_utils
class BaseBridgeDriver(object):
def connect(self, vif, ifname, netns):
host_ifname = vif.vif_name
with b_base.get_ipdb(netns) as c_ipdb:
with c_ipdb.create(ifname=ifname, peer=host_ifname,
kind='veth') as c_iface:
c_iface.mtu = vif.network.mtu
c_iface.address = str(vif.address)
c_iface.up()
if netns:
with c_ipdb.interfaces[host_ifname] as h_iface:
h_iface.net_ns_pid = os.getpid()
with b_base.get_ipdb() as h_ipdb:
with h_ipdb.interfaces[host_ifname] as h_iface:
h_iface.mtu = vif.network.mtu
h_iface.up()
def disconnect(self, vif, ifname, netns):
pass
class BridgeDriver(BaseBridgeDriver):
def connect(self, vif, ifname, netns):
super(BridgeDriver, self).connect(vif, ifname, netns)
host_ifname = vif.vif_name
bridge_name = vif.bridge_name
with b_base.get_ipdb() as h_ipdb:
with h_ipdb.interfaces[bridge_name] as h_br:
h_br.add_port(host_ifname)
def disconnect(self, vif, ifname, netns):
# NOTE(ivc): veth pair is destroyed automatically along with the
# container namespace
pass
class VIFOpenVSwitchDriver(BaseBridgeDriver):
def connect(self, vif, ifname, netns):
super(VIFOpenVSwitchDriver, self).connect(vif, ifname, netns)
# FIXME(irenab) use pod_id (neutron port device_id)
instance_id = 'kuryr'
net_utils.create_ovs_vif_port(vif.bridge_name, vif.vif_name,
vif.port_profile.interface_id,
vif.address, instance_id)
def disconnect(self, vif, ifname, netns):
super(VIFOpenVSwitchDriver, self).disconnect(vif, ifname, netns)
net_utils.delete_ovs_vif_port(vif.bridge_name, vif.vif_name)