Ensure isolation between namespaces

This patch ensures that a different security group is attached to
each newly created namespace. Thus providing extra isolation
between the pods allocated on the different namespaces.

Implements: blueprint openshift-project-isolation-support
Change-Id: Ibf63841b2a6b0c339c4c76980f1489e26af016d7
This commit is contained in:
Luis Tomas Bolivar 2018-06-29 14:38:18 +02:00
parent 68873beaf0
commit f02b2e99e9
13 changed files with 640 additions and 241 deletions

View File

@ -28,8 +28,8 @@ function ovs_bind_for_kubelet() {
project_id="$1"
port_number="$2"
security_group=$(openstack security group list \
--project "$project_id" -f value | \
awk '/default/ {print $1}')
--project "$project_id" -c ID -c Name -f value | \
awk '{if ($2=="default") print $1}')
port_id=$(openstack port create \
--device-owner compute:kuryr \
--project "$project_id" \
@ -49,6 +49,11 @@ function ovs_bind_for_kubelet() {
"$KURYR_K8S_OCTAVIA_MEMBER_MODE" == "L2" ]]; then
openstack port set "$port_id" --security-group octavia_pod_access
fi
if [[ "$KURYR_SG_DRIVER" == "namespace" ]]; then
openstack port set "$port_id" --security-group allow_from_namespace
openstack port set "$port_id" --security-group allow_from_default
fi
ifname="kubelet${port_id}"
ifname="${ifname:0:14}"
service_subnet_cidr=$(openstack --os-cloud devstack-admin \
@ -73,9 +78,16 @@ function ovs_bind_for_kubelet() {
sudo ip link set dev "$ifname" address "$port_mac"
sudo ip link set dev "$ifname" up
for ((i=0; i < ${#port_ips[@]}; i++)); do
prefix=$(openstack subnet show "${port_subnets[$i]}" \
-c cidr -f value | \
cut -f2 -d/)
if [[ "$KURYR_SG_DRIVER" == "namespace" ]]; then
subnetpool_id=$(openstack subnet show "${port_subnets[$i]}" \
-c subnetpool_id -f value | cut -f2)
prefix=$(openstack subnet pool show "${subnetpool_id}" \
-c prefixes -f value | cut -f2 -d/)
else
prefix=$(openstack subnet show "${port_subnets[$i]}" \
-c cidr -f value | \
cut -f2 -d/)
fi
sudo ip addr add "${port_ips[$i]}/${prefix}" dev "$ifname"
done
sudo ip route add "$service_subnet_cidr" via "$pod_subnet_gw" dev "$ifname"

View File

@ -71,6 +71,7 @@ function configure_kuryr {
iniset "$KURYR_CONFIG" kubernetes port_debug "$KURYR_PORT_DEBUG"
iniset "$KURYR_CONFIG" kubernetes pod_subnets_driver "$KURYR_SUBNET_DRIVER"
iniset "$KURYR_CONFIG" kubernetes pod_security_groups_driver "$KURYR_SG_DRIVER"
iniset "$KURYR_CONFIG" kubernetes enabled_handlers "$KURYR_ENABLED_HANDLERS"
# Let Kuryr retry connections to K8s API for 20 minutes.
@ -278,6 +279,8 @@ function configure_neutron_defaults {
local subnetpool_id
local router
local router_id
local ext_svc_net_id
local ext_svc_subnet_id
# If a subnetpool is not passed, we get the one created in devstack's
# Neutron module
@ -307,8 +310,10 @@ function configure_neutron_defaults {
service_subnet_id="$(openstack subnet show -c id -f value \
"${KURYR_NEUTRON_DEFAULT_SERVICE_SUBNET}")"
sg_ids=$(echo $(openstack security group list \
--project "$project_id" -c ID -f value) | tr ' ' ',')
if [ "$KURYR_SG_DRIVER" != "namespace" ]; then
sg_ids=$(echo $(openstack security group list \
--project "$project_id" -c ID -f value) | tr ' ' ',')
fi
ext_svc_net_id="$(openstack network show -c id -f value \
"${KURYR_NEUTRON_DEFAULT_EXT_SVC_NET}")"
@ -334,7 +339,11 @@ function configure_neutron_defaults {
--description "k8s service subnet allowed" \
--remote-ip "$service_cidr" --ethertype IPv4 --protocol tcp \
"$service_pod_access_sg_id"
sg_ids+=",${service_pod_access_sg_id}"
if [ -n "$sg_ids" ]; then
sg_ids+=",${service_pod_access_sg_id}"
else
sg_ids="${service_pod_access_sg_id}"
fi
elif [[ "$use_octavia" == "True" && \
"$KURYR_K8S_OCTAVIA_MEMBER_MODE" == "L2" ]]; then
# In case the member connectivity is L2, Octavia by default uses the
@ -357,7 +366,11 @@ function configure_neutron_defaults {
--description "k8s pod subnet allowed from k8s-pod-subnet" \
--remote-ip "$pod_cidr" --ethertype IPv4 --protocol tcp \
"$octavia_pod_access_sg_id"
sg_ids+=",${octavia_pod_access_sg_id}"
if [ -n "$sg_ids" ]; then
sg_ids+=",${octavia_pod_access_sg_id}"
else
sg_ids="${octavia_pod_access_sg_id}"
fi
fi
KURYR_K8S_CONTAINERIZED_DEPLOYMENT=$(trueorfalse False KURYR_K8S_CONTAINERIZED_DEPLOYMENT)
@ -384,6 +397,31 @@ function configure_neutron_defaults {
iniset "$KURYR_CONFIG" namespace_subnet pod_subnet_pool "$subnetpool_id"
iniset "$KURYR_CONFIG" namespace_subnet pod_router "$router_id"
fi
if [ "$KURYR_SG_DRIVER" == "namespace" ]; then
local allow_namespace_sg_id
local allow_default_sg_id
allow_namespace_sg_id=$(openstack --os-cloud devstack-admin \
--os-region "$REGION_NAME" \
security group create --project "$project_id" \
allow_from_namespace -f value -c id)
allow_default_sg_id=$(openstack --os-cloud devstack-admin \
--os-region "$REGION_NAME" \
security group create --project "$project_id" \
allow_from_default -f value -c id)
openstack --os-cloud devstack-admin --os-region "$REGION_NAME" \
security group rule create --project "$project_id" \
--description "allow traffic from default namespace" \
--remote-group "$allow_namespace_sg_id" --ethertype IPv4 --protocol tcp \
"$allow_default_sg_id"
openstack --os-cloud devstack-admin --os-region "$REGION_NAME" \
security group rule create --project "$project_id" \
--description "allow traffic from namespaces at default namespace" \
--remote-group "$allow_default_sg_id" --ethertype IPv4 --protocol tcp \
"$allow_namespace_sg_id"
iniset "$KURYR_CONFIG" namespace_sg sg_allow_from_namespaces "$allow_namespace_sg_id"
iniset "$KURYR_CONFIG" namespace_sg sg_allow_from_default "$allow_default_sg_id"
fi
if [ -n "$OVS_BRIDGE" ]; then
iniset "$KURYR_CONFIG" neutron_defaults ovs_bridge "$OVS_BRIDGE"
fi
@ -409,7 +447,7 @@ function configure_k8s_pod_sg_rules {
--os-region "$REGION_NAME" \
security group list \
--project "$project_id" -c ID -c Name -f value | \
awk '/default/ {print $1}')
awk '{if ($2=="default") print $1}')
create_k8s_icmp_sg_rules "$sg_id" ingress
}

View File

@ -48,6 +48,7 @@ KURYR_K8S_API_CACERT=${KURYR_K8S_API_CACERT:-"${KURYR_HYPERKUBE_DATA_DIR}/kuryr-
KURYR_K8S_API_LB_PORT=${KURYR_K8S_API_LB_PORT:-443}
KURYR_PORT_DEBUG=${KURYR_PORT_DEBUG:-True}
KURYR_SUBNET_DRIVER=${KURYR_SUBNET_DRIVER:-default}
KURYR_SG_DRIVER=${KURYR_SG_DRIVER:-default}
KURYR_ENABLED_HANDLERS=${KURYR_ENABLED_HANDLERS:-vif,lb,lbaasspec}
# OpenShift

View File

@ -20,6 +20,15 @@ the next steps are needed:
pod_subnets_driver = namespace
In addition, to ensure that pods at one given namespace cannot reach (or be
reached by) the ones at another namespace, except the pods at the default
namespace that can reach (and be reached by) any pod at a different
namespace, the next security group driver needs to be set too::
[kubernetes]
pod_security_groups_driver = namespace
3. Select (and create if needed) the subnet pool from where the new subnets
will get their CIDR (e.g., the default on devstack deployment is
shared-default-subnetpool-v4)::
@ -40,6 +49,15 @@ the next steps are needed:
the default subnet driver.
5. Select (and create if needed) the security groups to be attached to the
pods at the default namespace and to the others, enabling the cross access
between them::
[namespace_sg]
sg_allow_from_namespaces = SG_ID_1 # Makes SG_ID_1 allow traffic from the sg sg_allow_from_default
sg_allow_from_default = SG_ID_2 # Makes SG_ID_2 allow traffic from the sg sg_allow_from_namespaces
Note you need to restart the kuryr controller after applying the above
detailed steps. For devstack non-containerized deployments::
@ -56,6 +74,7 @@ For directly enabling the driver when deploying with devstack, you just need
to add the namespace handler and state the namespace subnet driver with::
KURYR_SUBNET_DRIVER=namespace
KURYR_SG_DRIVER=namespace
KURYR_ENABLED_HANDLERS=vif,lb,lbaasspec,namespace

View File

@ -149,11 +149,13 @@ class PodSubnetsDriver(DriverBase):
"""
raise NotImplementedError()
def create_namespace_network(self, namespace):
def create_namespace_network(self, namespace, project_id):
"""Create network resources for a namespace.
:param namespace: string with the namespace name
:return: CRD KuryrNet dict
:param project_id: OpenStack project ID
:return: dict with the keys and values for the CRD spec, such as
routerId or subnetId
"""
raise NotImplementedError()
@ -165,13 +167,11 @@ class PodSubnetsDriver(DriverBase):
"""
raise NotImplementedError()
def rollback_network_resources(self, router_id, net_id, subnet_id,
namespace):
def rollback_network_resources(self, crd_spec, namespace):
"""Rollback created network resources for a namespace.
:param router_id: OpenStack router ID where the network is connected
:param net_id: OpenStack network ID
:param subnet_id: OpenStack subnet ID
:param crd_spec: dict with the keys and values for the CRD spec, such
as routerId or subnetId
:param namespace: name of the Kubernetes namespace object
"""
raise NotImplementedError()
@ -213,6 +213,22 @@ class PodSecurityGroupsDriver(DriverBase):
"""
raise NotImplementedError()
def create_namespace_sg(self, namespace, project_id):
"""Create security group resources for a namespace.
:param namespace: string with the namespace name
:param project_id: OpenStack project ID
:return: dict with the keys and values for the CRD spec, such as sgId
"""
raise NotImplementedError()
def delete_sg(self, sg_id):
"""Delete security group associated to a namespace.
:param sg_id: OpenStack security group ID
"""
raise NotImplementedError()
@six.add_metaclass(abc.ABCMeta)
class ServiceSecurityGroupsDriver(DriverBase):

View File

@ -0,0 +1,130 @@
# Copyright (c) 2018 Red Hat, 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.
from kuryr.lib._i18n import _
from oslo_config import cfg
from oslo_log import log as logging
from kuryr_kubernetes import clients
from kuryr_kubernetes import config
from kuryr_kubernetes import constants
from kuryr_kubernetes.controller.drivers import base
from kuryr_kubernetes import exceptions
from neutronclient.common import exceptions as n_exc
LOG = logging.getLogger(__name__)
namespace_sg_driver_opts = [
cfg.StrOpt('sg_allow_from_namespaces',
help=_("Default security group to allow traffic from the "
"namespaces into the default namespace.")),
cfg.StrOpt('sg_allow_from_default',
help=_("Default security group to allow traffic from the "
"default namespaces into the other namespaces."))
]
cfg.CONF.register_opts(namespace_sg_driver_opts, "namespace_sg")
DEFAULT_NAMESPACE = 'default'
class NamespacePodSecurityGroupsDriver(base.PodSecurityGroupsDriver):
"""Provides security groups for Pod based on a configuration option."""
def get_security_groups(self, pod, project_id):
namespace = pod['metadata']['namespace']
net_crd = self._get_net_crd(namespace)
sg_list = config.CONF.neutron_defaults.pod_security_groups
sg_list.append(str(net_crd['spec']['sgId']))
extra_sgs = self._get_extra_sg(namespace)
for sg in extra_sgs:
sg_list.append(str(sg))
return sg_list[:]
def _get_net_crd(self, namespace):
kubernetes = clients.get_kubernetes_client()
try:
ns = kubernetes.get('%s/namespaces/%s' % (constants.K8S_API_BASE,
namespace))
except exceptions.K8sClientException:
LOG.exception("Kubernetes Client Exception.")
raise exceptions.ResourceNotReady(namespace)
try:
annotations = ns['metadata']['annotations']
net_crd_name = annotations[constants.K8S_ANNOTATION_NET_CRD]
except KeyError:
LOG.exception("Namespace missing CRD annotations for selecting "
"the corresponding security group.")
raise exceptions.ResourceNotReady(namespace)
try:
net_crd = kubernetes.get('%s/kuryrnets/%s' % (
constants.K8S_API_CRD, net_crd_name))
except exceptions.K8sClientException:
LOG.exception("Kubernetes Client Exception.")
raise
return net_crd
def _get_extra_sg(self, namespace):
# Differentiates between default namespace and the rest
if namespace == DEFAULT_NAMESPACE:
return [cfg.CONF.namespace_sg.sg_allow_from_namespaces]
else:
return [cfg.CONF.namespace_sg.sg_allow_from_default]
def create_namespace_sg(self, namespace, project_id):
neutron = clients.get_neutron_client()
sg_name = "ns/" + namespace + "-sg"
# create the associated SG for the namespace
try:
# default namespace is different from the rest
# Default allows traffic from everywhere
# The rest can be accessed from the default one
sg = neutron.create_security_group(
{
"security_group": {
"name": sg_name,
"project_id": project_id
}
}).get('security_group')
neutron.create_security_group_rule(
{
"security_group_rule": {
"direction": "ingress",
"remote_group_id": sg['id'],
"security_group_id": sg['id']
}
})
except n_exc.NeutronClientException as ex:
LOG.error("Error creating security group for the namespace "
"%s: %s", namespace, ex)
raise ex
return {'sgId': sg['id']}
def delete_sg(self, sg_id):
neutron = clients.get_neutron_client()
try:
neutron.delete_security_group(sg_id)
except n_exc.NotFound:
LOG.debug("Security Group not found: %s", sg_id)
except n_exc.NeutronClientException:
LOG.exception("Error deleting security group %s.", sg_id)
raise

View File

@ -72,18 +72,10 @@ class NamespacePodSubnetDriver(default_subnet.DefaultPodSubnetDriver):
return net_crd['spec']['subnetId']
def delete_namespace_subnet(self, net_crd_name):
router_id = oslo_cfg.CONF.namespace_subnet.pod_router
def delete_namespace_subnet(self, net_crd):
neutron = clients.get_neutron_client()
kubernetes = clients.get_kubernetes_client()
try:
net_crd = kubernetes.get('%s/kuryrnets/%s' % (
constants.K8S_API_CRD, net_crd_name))
except exceptions.K8sClientException:
LOG.exception("Kubernetes Client Exception.")
raise
router_id = oslo_cfg.CONF.namespace_subnet.pod_router
subnet_id = net_crd['spec']['subnetId']
net_id = net_crd['spec']['netId']
@ -111,8 +103,6 @@ class NamespacePodSubnetDriver(default_subnet.DefaultPodSubnetDriver):
LOG.exception("Error deleting network %s.", net_id)
raise
self._del_kuryrnet_crd(net_crd_name)
def create_namespace_network(self, namespace, project_id):
neutron = clients.get_neutron_client()
@ -151,64 +141,19 @@ class NamespacePodSubnetDriver(default_subnet.DefaultPodSubnetDriver):
LOG.error("Error creating neutron resources for the namespace "
"%s: %s", namespace, ex)
raise ex
return {'netId': neutron_net['id'],
'routerId': router_id,
'subnetId': neutron_subnet['id']}
# create CRD resource for the network
try:
net_crd = self._add_kuryrnet_crd(namespace, neutron_net['id'],
router_id, neutron_subnet['id'])
except exceptions.K8sClientException:
LOG.exception("Kuryrnet CRD could not be added. Rolling back "
"network resources created for the namespace.")
self.rollback_network_resources(router_id, neutron_net['id'],
neutron_subnet['id'], namespace)
raise
return net_crd
def rollback_network_resources(self, router_id, net_id, subnet_id,
namespace):
def rollback_network_resources(self, net_crd_spec, namespace):
neutron = clients.get_neutron_client()
try:
neutron.remove_interface_router(router_id,
{'subnet_id': subnet_id})
neutron.delete_network(net_id)
neutron.remove_interface_router(net_crd_spec['routerId'],
{'subnet_id':
net_crd_spec['subnetId']})
neutron.delete_network(net_crd_spec['netId'])
except n_exc.NeutronClientException:
LOG.exception("Failed to clean up network resources associated to "
"%(net_id)s, created for the namespace: "
"%(namespace)s." % {'net_id': net_id,
"%(namespace)s." % {'net_id': net_crd_spec['netId'],
'namespace': namespace})
def _add_kuryrnet_crd(self, namespace, net_id, router_id, subnet_id):
kubernetes = clients.get_kubernetes_client()
net_crd_name = "ns-" + namespace
net_crd = {
'apiVersion': 'openstack.org/v1',
'kind': 'KuryrNet',
'metadata': {
'name': net_crd_name,
'annotations': {
'namespaceName': namespace,
}
},
'spec': {
'netId': net_id,
'routerId': router_id,
'subnetId': subnet_id,
},
}
try:
kubernetes.post('%s/kuryrnets' % constants.K8S_API_CRD, net_crd)
except exceptions.K8sClientException:
LOG.exception("Kubernetes Client Exception creating kuryrnet "
"CRD.")
raise
return net_crd
def _del_kuryrnet_crd(self, net_crd_name):
kubernetes = clients.get_kubernetes_client()
try:
kubernetes.delete('%s/kuryrnets/%s' % (constants.K8S_API_CRD,
net_crd_name))
except exceptions.K8sClientException:
LOG.exception("Kubernetes Client Exception deleting kuryrnet "
"CRD.")
raise

View File

@ -20,6 +20,8 @@ from kuryr_kubernetes.controller.drivers import base as drivers
from kuryr_kubernetes import exceptions
from kuryr_kubernetes.handlers import k8s_base
from neutronclient.common import exceptions as n_exc
LOG = logging.getLogger(__name__)
@ -31,6 +33,7 @@ class NamespaceHandler(k8s_base.ResourceEventHandler):
super(NamespaceHandler, self).__init__()
self._drv_project = drivers.NamespaceProjectDriver.get_instance()
self._drv_subnets = drivers.PodSubnetsDriver.get_instance()
self._drv_sg = drivers.PodSecurityGroupsDriver.get_instance()
self._drv_vif_pool = drivers.VIFPoolDriver.get_instance(
driver_alias='multi_pool')
self._drv_vif_pool.set_vif_driver()
@ -38,42 +41,65 @@ class NamespaceHandler(k8s_base.ResourceEventHandler):
def on_present(self, namespace):
ns_name = namespace['metadata']['name']
project_id = self._drv_project.get_project(namespace)
net_crd = self._get_net_crd(namespace)
if net_crd:
net_crd_id = self._get_net_crd_id(namespace)
if net_crd_id:
LOG.debug("CRD existing at the new namespace")
return
LOG.debug("Creating network resources for namespace: %s", ns_name)
net_crd = self._drv_subnets.create_namespace_network(ns_name,
project_id)
net_crd_spec = self._drv_subnets.create_namespace_network(ns_name,
project_id)
try:
net_crd_sg = self._drv_sg.create_namespace_sg(ns_name, project_id)
except n_exc.NeutronClientException:
LOG.exception("Error creating security group for the namespace. "
"Rolling back created network resources.")
self._drv_subnets.rollback_network_resources(net_crd_spec, ns_name)
raise
net_crd_spec.update(net_crd_sg)
# create CRD resource for the network
try:
net_crd = self._add_kuryrnet_crd(ns_name, net_crd_spec)
self._set_net_crd(namespace, net_crd)
except exceptions.K8sClientException:
LOG.exception("Failed to set annotation")
crd_spec = net_crd['spec']
self._drv_subnets.rollback_network_resources(
crd_spec['routerId'], crd_spec['netId'], crd_spec['subnetId'],
ns_name)
LOG.exception("Kuryrnet CRD could not be added. Rolling back "
"network resources created for the namespace.")
self._drv_subnets.rollback_network_resources(net_crd_spec, ns_name)
self._drv_sg.delete_sg(net_crd_sg['sgId'])
def on_deleted(self, namespace):
LOG.debug("Deleting namespace: %s", namespace)
net_crd = self._get_net_crd(namespace)
if not net_crd:
net_crd_id = self._get_net_crd_id(namespace)
if not net_crd_id:
LOG.warning("There is no CRD annotated at the namespace %s",
namespace)
return
net_crd = self._get_net_crd(net_crd_id)
net_id = self._get_net_id_from_net_crd(net_crd)
self._drv_vif_pool.delete_network_pools(net_id)
self._drv_vif_pool.delete_network_pools(net_crd['spec']['netId'])
self._drv_subnets.delete_namespace_subnet(net_crd)
self._drv_sg.delete_sg(net_crd['spec']['sgId'])
def _get_net_crd(self, namespace):
self._del_kuryrnet_crd(net_crd_id)
def _get_net_crd_id(self, namespace):
try:
annotations = namespace['metadata']['annotations']
net_crd = annotations[constants.K8S_ANNOTATION_NET_CRD]
net_crd_id = annotations[constants.K8S_ANNOTATION_NET_CRD]
except KeyError:
return None
return net_crd
return net_crd_id
def _get_net_crd(self, net_crd_id):
k8s = clients.get_kubernetes_client()
try:
kuryrnet_crd = k8s.get('%s/kuryrnets/%s' % (constants.K8S_API_CRD,
net_crd_id))
except exceptions.K8sClientException:
LOG.exception("Kubernetes Client Exception.")
raise
return kuryrnet_crd
def _set_net_crd(self, namespace, net_crd):
LOG.debug("Setting CRD annotations: %s", net_crd)
@ -84,12 +110,35 @@ class NamespaceHandler(k8s_base.ResourceEventHandler):
net_crd['metadata']['name']},
resource_version=namespace['metadata']['resourceVersion'])
def _get_net_id_from_net_crd(self, net_crd):
k8s = clients.get_kubernetes_client()
def _add_kuryrnet_crd(self, namespace, net_crd_spec):
kubernetes = clients.get_kubernetes_client()
net_crd_name = "ns-" + namespace
spec = {k: v for k, v in net_crd_spec.items()}
net_crd = {
'apiVersion': 'openstack.org/v1',
'kind': 'KuryrNet',
'metadata': {
'name': net_crd_name,
'annotations': {
'namespaceName': namespace,
}
},
'spec': spec,
}
try:
kuryrnet_crd = k8s.get('%s/kuryrnets/%s' % (constants.K8S_API_CRD,
net_crd))
kubernetes.post('%s/kuryrnets' % constants.K8S_API_CRD, net_crd)
except exceptions.K8sClientException:
LOG.exception("Kubernetes Client Exception.")
LOG.exception("Kubernetes Client Exception creating kuryrnet "
"CRD.")
raise
return net_crd
def _del_kuryrnet_crd(self, net_crd_name):
kubernetes = clients.get_kubernetes_client()
try:
kubernetes.delete('%s/kuryrnets/%s' % (constants.K8S_API_CRD,
net_crd_name))
except exceptions.K8sClientException:
LOG.exception("Kubernetes Client Exception deleting kuryrnet "
"CRD.")
raise
return kuryrnet_crd['spec']['netId']

View File

@ -17,6 +17,7 @@ from kuryr.lib import opts as lib_opts
from kuryr_kubernetes.cni import health as cni_health
from kuryr_kubernetes import config
from kuryr_kubernetes.controller.drivers import default_subnet
from kuryr_kubernetes.controller.drivers import namespace_security_groups
from kuryr_kubernetes.controller.drivers import namespace_subnet
from kuryr_kubernetes.controller.drivers import nested_vif
from kuryr_kubernetes.controller.drivers import vif_pool
@ -38,6 +39,7 @@ _kuryr_k8s_opts = [
('health_server', health.health_server_opts),
('cni_health_server', cni_health.cni_health_server_opts),
('namespace_subnet', namespace_subnet.namespace_subnet_driver_opts),
('namespace_sg', namespace_security_groups.namespace_sg_driver_opts),
('ingress', config.ingress),
]

View File

@ -0,0 +1,181 @@
# Copyright (c) 2018 Red Hat, 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 mock
from kuryr_kubernetes import constants
from kuryr_kubernetes.controller.drivers import namespace_security_groups
from kuryr_kubernetes.tests import base as test_base
from kuryr_kubernetes.tests.unit import kuryr_fixtures as k_fix
from neutronclient.common import exceptions as n_exc
def get_pod_obj():
return {
'status': {
'qosClass': 'BestEffort',
'hostIP': '192.168.1.2',
},
'kind': 'Pod',
'spec': {
'schedulerName': 'default-scheduler',
'containers': [{
'name': 'busybox',
'image': 'busybox',
'resources': {}
}],
'nodeName': 'kuryr-devstack'
},
'metadata': {
'name': 'busybox-sleep1',
'namespace': 'default',
'resourceVersion': '53808',
'selfLink': '/api/v1/namespaces/default/pods/busybox-sleep1',
'uid': '452176db-4a85-11e7-80bd-fa163e29dbbb',
'annotations': {
'openstack.org/kuryr-vif': {}
}
}}
def get_namespace_obj():
return {
'metadata': {
'annotations': {
constants.K8S_ANNOTATION_NET_CRD: 'net_crd_url_sample'
}
}
}
class TestNamespacePodSecurityGroupsDriver(test_base.TestCase):
@mock.patch('kuryr_kubernetes.config.CONF')
def test_get_security_groups(self, m_cfg):
cls = namespace_security_groups.NamespacePodSecurityGroupsDriver
m_driver = mock.MagicMock(spec=cls)
pod = get_pod_obj()
project_id = mock.sentinel.project_id
sg_list = [mock.sentinel.sg_id]
m_cfg.neutron_defaults.pod_security_groups = sg_list
sg_id = mock.sentinel.sg_id
extra_sg = mock.sentinel.extra_sg
net_crd = {
'spec': {
'sgId': sg_id
}
}
m_driver._get_net_crd.return_value = net_crd
m_driver._get_extra_sg.return_value = [extra_sg]
ret = cls.get_security_groups(m_driver, pod, project_id)
expected_sg = [sg_list[0], str(sg_id), str(extra_sg)]
self.assertEqual(ret, expected_sg)
def test__get_net_crd(self):
cls = namespace_security_groups.NamespacePodSecurityGroupsDriver
m_driver = mock.MagicMock(spec=cls)
namespace = mock.sentinel.namespace
subnet_id = mock.sentinel.subnet_id
net_id = mock.sentinel.net_id
sg_id = mock.sentinel.sg_id
ns = get_namespace_obj()
crd = {
'spec': {
'netId': net_id,
'subnetId': subnet_id,
'sgId': sg_id
}
}
kubernetes = self.useFixture(k_fix.MockK8sClient()).client
kubernetes.get.side_effect = [ns, crd]
ret = cls._get_net_crd(m_driver, namespace)
self.assertEqual(ret, crd)
def test_create_namespace_sg(self):
cls = namespace_security_groups.NamespacePodSecurityGroupsDriver
m_driver = mock.MagicMock(spec=cls)
namespace = 'test'
project_id = mock.sentinel.project_id
sg = {'id': mock.sentinel.sg}
neutron = self.useFixture(k_fix.MockNeutronClient()).client
neutron.create_security_group.return_value = {'security_group': sg}
create_sg_resp = cls.create_namespace_sg(m_driver, namespace,
project_id)
self.assertEqual(create_sg_resp, {'sgId': sg['id']})
neutron.create_security_group.assert_called_once()
neutron.create_security_group_rule.assert_called_once()
def test_create_namespace_sg_exception(self):
cls = namespace_security_groups.NamespacePodSecurityGroupsDriver
m_driver = mock.MagicMock(spec=cls)
namespace = 'test'
project_id = mock.sentinel.project_id
neutron = self.useFixture(k_fix.MockNeutronClient()).client
neutron.create_security_group.side_effect = (
n_exc.NeutronClientException)
self.assertRaises(n_exc.NeutronClientException,
cls.create_namespace_sg, m_driver,
namespace, project_id)
neutron.create_security_group.assert_called_once()
neutron.create_security_group_rule.assert_not_called()
def test_delete_sg(self):
cls = namespace_security_groups.NamespacePodSecurityGroupsDriver
m_driver = mock.MagicMock(spec=cls)
neutron = self.useFixture(k_fix.MockNeutronClient()).client
sg_id = mock.sentinel.sg_id
cls.delete_sg(m_driver, sg_id)
neutron.delete_security_group.assert_called_once_with(sg_id)
def test_delete_sg_exception(self):
cls = namespace_security_groups.NamespacePodSecurityGroupsDriver
m_driver = mock.MagicMock(spec=cls)
neutron = self.useFixture(k_fix.MockNeutronClient()).client
sg_id = mock.sentinel.sg_id
neutron.delete_security_group.side_effect = (
n_exc.NeutronClientException)
self.assertRaises(n_exc.NeutronClientException, cls.delete_sg,
m_driver, sg_id)
neutron.delete_security_group.assert_called_once_with(sg_id)
def test_delete_sg_not_found(self):
cls = namespace_security_groups.NamespacePodSecurityGroupsDriver
m_driver = mock.MagicMock(spec=cls)
neutron = self.useFixture(k_fix.MockNeutronClient()).client
sg_id = mock.sentinel.sg_id
neutron.delete_security_group.side_effect = n_exc.NotFound
cls.delete_sg(m_driver, sg_id)
neutron.delete_security_group.assert_called_once_with(sg_id)

View File

@ -22,6 +22,7 @@ from kuryr_kubernetes.tests import base as test_base
from kuryr_kubernetes.tests.unit import kuryr_fixtures as k_fix
from neutronclient.common import exceptions as n_exc
from oslo_config import cfg as oslo_cfg
def get_pod_obj():
@ -176,69 +177,20 @@ class TestNamespacePodSubnetDriver(test_base.TestCase):
cls = subnet_drv.NamespacePodSubnetDriver
m_driver = mock.MagicMock(spec=cls)
net_crd_name = 'test'
net_id = mock.sentinel.net_id
subnet_id = mock.sentinel.subnet_id
sg_id = mock.sentinel.sg_id
crd = {
'spec': {
'subnetId': subnet_id,
'netId': net_id
'netId': net_id,
'sgId': sg_id
}
}
neutron = self.useFixture(k_fix.MockNeutronClient()).client
kubernetes = self.useFixture(k_fix.MockK8sClient()).client
kubernetes.get.return_value = crd
cls.delete_namespace_subnet(m_driver, crd)
cls.delete_namespace_subnet(m_driver, net_crd_name)
kubernetes.get.assert_called_once()
m_driver._del_kuryrnet_crd.assert_called_once_with(net_crd_name)
neutron.remove_interface_router.assert_called_once()
neutron.delete_network.assert_called_once_with(net_id)
def test_delete_namespace_subnet_k8s_get_exception(self):
cls = subnet_drv.NamespacePodSubnetDriver
m_driver = mock.MagicMock(spec=cls)
net_crd_name = 'test'
neutron = self.useFixture(k_fix.MockNeutronClient()).client
kubernetes = self.useFixture(k_fix.MockK8sClient()).client
kubernetes.get.side_effect = k_exc.K8sClientException
self.assertRaises(k_exc.K8sClientException,
cls.delete_namespace_subnet, m_driver, net_crd_name)
kubernetes.get.assert_called_once()
m_driver._del_kuryrnet_crd.assert_not_called()
neutron.remove_interface_router.assert_not_called()
neutron.delete_network.assert_not_called()
def test_delete_namespace_subnet_k8s_del_crd_exception(self):
cls = subnet_drv.NamespacePodSubnetDriver
m_driver = mock.MagicMock(spec=cls)
net_crd_name = 'test'
net_id = mock.sentinel.net_id
subnet_id = mock.sentinel.subnet_id
crd = {
'spec': {
'subnetId': subnet_id,
'netId': net_id
}
}
neutron = self.useFixture(k_fix.MockNeutronClient()).client
kubernetes = self.useFixture(k_fix.MockK8sClient()).client
kubernetes.get.return_value = crd
m_driver._del_kuryrnet_crd.side_effect = k_exc.K8sClientException
self.assertRaises(k_exc.K8sClientException,
cls.delete_namespace_subnet, m_driver, net_crd_name)
kubernetes.get.assert_called_once()
m_driver._del_kuryrnet_crd.assert_called_once_with(net_crd_name)
neutron.remove_interface_router.assert_called_once()
neutron.delete_network.assert_called_once_with(net_id)
@ -246,28 +198,24 @@ class TestNamespacePodSubnetDriver(test_base.TestCase):
cls = subnet_drv.NamespacePodSubnetDriver
m_driver = mock.MagicMock(spec=cls)
net_crd_name = 'test'
net_id = mock.sentinel.net_id
subnet_id = mock.sentinel.subnet_id
sg_id = mock.sentinel.sg_id
crd = {
'spec': {
'subnetId': subnet_id,
'netId': net_id
'netId': net_id,
'sgId': sg_id
}
}
neutron = self.useFixture(k_fix.MockNeutronClient()).client
kubernetes = self.useFixture(k_fix.MockK8sClient()).client
kubernetes.get.return_value = crd
neutron.delete_network.side_effect = n_exc.NetworkInUseClient
self.assertRaises(k_exc.ResourceNotReady,
cls.delete_namespace_subnet, m_driver, net_crd_name)
cls.delete_namespace_subnet, m_driver, crd)
kubernetes.get.assert_called_once()
neutron.remove_interface_router.assert_called_once()
neutron.delete_network.assert_called_once_with(net_id)
m_driver._del_kuryrnet_crd.assert_not_called()
def test_create_namespace_network(self):
cls = subnet_drv.NamespacePodSubnetDriver
@ -280,8 +228,13 @@ class TestNamespacePodSubnetDriver(test_base.TestCase):
neutron.create_network.return_value = {'network': net}
subnet = {'id': mock.sentinel.subnet}
neutron.create_subnet.return_value = {'subnet': subnet}
net_crd = mock.sentinel.net_crd
m_driver._add_kuryrnet_crd.return_value = net_crd
router_id = 'router1'
oslo_cfg.CONF.set_override('pod_router',
router_id,
group='namespace_subnet')
net_crd = {'netId': net['id'],
'routerId': router_id,
'subnetId': subnet['id']}
net_crd_resp = cls.create_namespace_network(m_driver, namespace,
project_id)
@ -290,7 +243,6 @@ class TestNamespacePodSubnetDriver(test_base.TestCase):
neutron.create_network.assert_called_once()
neutron.create_subnet.assert_called_once()
neutron.add_interface_router.assert_called_once()
m_driver._add_kuryrnet_crd.assert_called_once()
def test_create_namespace_network_net_exception(self):
cls = subnet_drv.NamespacePodSubnetDriver
@ -309,7 +261,6 @@ class TestNamespacePodSubnetDriver(test_base.TestCase):
neutron.create_network.assert_called_once()
neutron.create_subnet.assert_not_called()
neutron.add_interface_router.assert_not_called()
m_driver._add_kuryrnet_crd.assert_not_called()
def test_create_namespace_network_subnet_exception(self):
cls = subnet_drv.NamespacePodSubnetDriver
@ -329,10 +280,8 @@ class TestNamespacePodSubnetDriver(test_base.TestCase):
neutron.create_network.assert_called_once()
neutron.create_subnet.assert_called_once()
neutron.add_interface_router.assert_not_called()
m_driver._add_kuryrnet_crd.assert_not_called()
def test_create_namespace_network_router_exception(self):
pass
cls = subnet_drv.NamespacePodSubnetDriver
m_driver = mock.MagicMock(spec=cls)
@ -353,30 +302,6 @@ class TestNamespacePodSubnetDriver(test_base.TestCase):
neutron.create_network.assert_called_once()
neutron.create_subnet.assert_called_once()
neutron.add_interface_router.assert_called_once()
m_driver._add_kuryrnet_crd.assert_not_called()
def test_create_namespace_network_crd_exception(self):
cls = subnet_drv.NamespacePodSubnetDriver
m_driver = mock.MagicMock(spec=cls)
namespace = 'test'
project_id = mock.sentinel.project_id
neutron = self.useFixture(k_fix.MockNeutronClient()).client
net = {'id': mock.sentinel.net}
neutron.create_network.return_value = {'network': net}
subnet = {'id': mock.sentinel.subnet}
neutron.create_subnet.return_value = {'subnet': subnet}
m_driver._add_kuryrnet_crd.side_effect = k_exc.K8sClientException
self.assertRaises(k_exc.K8sClientException,
cls.create_namespace_network, m_driver, namespace,
project_id)
neutron.create_network.assert_called_once()
neutron.create_subnet.assert_called_once()
neutron.add_interface_router.assert_called_once()
m_driver._add_kuryrnet_crd.assert_called_once()
m_driver.rollback_network_resources.assert_called_once()
def test_rollback_network_resources(self):
cls = subnet_drv.NamespacePodSubnetDriver
@ -385,12 +310,18 @@ class TestNamespacePodSubnetDriver(test_base.TestCase):
router_id = mock.sentinel.router_id
net_id = mock.sentinel.net_id
subnet_id = mock.sentinel.subnet_id
sg_id = mock.sentinel.sg_id
crd_spec = {
'subnetId': subnet_id,
'routerId': router_id,
'netId': net_id,
'sgId': sg_id
}
namespace = mock.sentinel.namespace
neutron = self.useFixture(k_fix.MockNeutronClient()).client
cls.rollback_network_resources(m_driver, router_id, net_id,
subnet_id, namespace)
cls.rollback_network_resources(m_driver, crd_spec, namespace)
neutron.remove_interface_router.assert_called_with(
router_id, {'subnet_id': subnet_id})
neutron.delete_network.assert_called_with(net_id)
@ -402,14 +333,20 @@ class TestNamespacePodSubnetDriver(test_base.TestCase):
router_id = mock.sentinel.router_id
net_id = mock.sentinel.net_id
subnet_id = mock.sentinel.subnet_id
sg_id = mock.sentinel.sg_id
crd_spec = {
'subnetId': subnet_id,
'routerId': router_id,
'netId': net_id,
'sgId': sg_id
}
namespace = mock.sentinel.namespace
neutron = self.useFixture(k_fix.MockNeutronClient()).client
neutron.remove_interface_router.side_effect = (
n_exc.NeutronClientException)
cls.rollback_network_resources(m_driver, router_id, net_id,
subnet_id, namespace)
cls.rollback_network_resources(m_driver, crd_spec, namespace)
neutron.remove_interface_router.assert_called_with(
router_id, {'subnet_id': subnet_id})
neutron.delete_network.assert_not_called()

View File

@ -13,7 +13,6 @@
# License for the specific language governing permissions and limitations
# under the License.
import ddt
import mock
from neutronclient.common import exceptions as n_exc
@ -25,7 +24,6 @@ from kuryr_kubernetes import exceptions as k_exc
from kuryr_kubernetes.tests import base as test_base
@ddt.ddt
class TestNamespaceHandler(test_base.TestCase):
def setUp(self):
@ -50,6 +48,7 @@ class TestNamespaceHandler(test_base.TestCase):
self._handler._drv_project = mock.Mock(
spec=drivers.NamespaceProjectDriver)
self._handler._drv_subnets = mock.Mock(spec=drivers.PodSubnetsDriver)
self._handler._drv_sg = mock.Mock(spec=drivers.PodSecurityGroupsDriver)
self._handler._drv_vif_pool = mock.MagicMock(
spec=vif_pool.MultiVIFPool)
@ -60,10 +59,15 @@ class TestNamespaceHandler(test_base.TestCase):
self._handler._drv_subnets.create_namespace_network)
self._delete_namespace_subnet = (
self._handler._drv_subnets.delete_namespace_subnet)
self._create_namespace_sg = (
self._handler._drv_sg.create_namespace_sg)
self._delete_sg = (
self._handler._drv_sg.delete_sg)
self._get_net_crd = self._handler._get_net_crd
self._set_net_crd = self._handler._set_net_crd
self._get_net_id_from_net_crd = (
self._handler._get_net_id_from_net_crd)
self._get_net_crd_id = self._handler._get_net_crd_id
self._add_kuryrnet_crd = self._handler._add_kuryrnet_crd
self._del_kuryrnet_crd = self._handler._del_kuryrnet_crd
self._rollback_network_resources = (
self._handler._drv_subnets.rollback_network_resources)
self._delete_network_pools = (
@ -79,89 +83,144 @@ class TestNamespaceHandler(test_base.TestCase):
'routerId': mock.sentinel.router_id,
'netId': mock.sentinel.net_id,
'subnetId': mock.sentinel.subnet_id,
'sgId': mock.sentinel.sg_id,
}
}
return crd
@mock.patch.object(drivers.VIFPoolDriver, 'get_instance')
@mock.patch.object(drivers.PodSecurityGroupsDriver, 'get_instance')
@mock.patch.object(drivers.PodSubnetsDriver, 'get_instance')
@mock.patch.object(drivers.NamespaceProjectDriver, 'get_instance')
def test_init(self, m_get_project_driver, m_get_subnets_driver,
m_get_vif_pool_driver):
m_get_sg_driver, m_get_vif_pool_driver):
project_driver = mock.sentinel.project_driver
subnets_driver = mock.sentinel.subnets_driver
sg_driver = mock.sentinel.sg_driver
vif_pool_driver = mock.Mock(spec=vif_pool.MultiVIFPool)
m_get_project_driver.return_value = project_driver
m_get_subnets_driver.return_value = subnets_driver
m_get_sg_driver.return_value = sg_driver
m_get_vif_pool_driver.return_value = vif_pool_driver
handler = namespace.NamespaceHandler()
self.assertEqual(project_driver, handler._drv_project)
self.assertEqual(subnets_driver, handler._drv_subnets)
self.assertEqual(sg_driver, handler._drv_sg)
self.assertEqual(vif_pool_driver, handler._drv_vif_pool)
def test_on_present(self):
net_crd = self._get_crd()
self._get_net_crd.return_value = None
self._create_namespace_network.return_value = net_crd
self._get_net_crd_id.return_value = None
self._create_namespace_network.return_value = {'test_net': 'uuid'}
self._create_namespace_sg.return_value = {'test_sg': 'uuid'}
net_crd_spec = {'test_net': 'uuid', 'test_sg': 'uuid'}
self._add_kuryrnet_crd.return_value = net_crd
namespace.NamespaceHandler.on_present(self._handler, self._namespace)
self._get_net_crd.assert_called_once_with(self._namespace)
self._get_net_crd_id.assert_called_once_with(self._namespace)
self._create_namespace_network.assert_called_once_with(
self._namespace_name, self._project_id)
self._create_namespace_sg.assert_called_once_with(
self._namespace_name, self._project_id)
self._add_kuryrnet_crd.assert_called_once_with(self._namespace_name,
net_crd_spec)
self._set_net_crd.assert_called_once_with(self._namespace, net_crd)
self._rollback_network_resources.assert_not_called()
def test_on_present_existing(self):
net_crd = self._get_crd()
self._get_net_crd.return_value = net_crd
net_crd_id = mock.sentinel.net_crd_id
self._get_net_crd_id.return_value = net_crd_id
namespace.NamespaceHandler.on_present(self._handler, self._namespace)
self._get_net_crd.assert_called_once_with(self._namespace)
self._get_net_crd_id.assert_called_once_with(self._namespace)
self._create_namespace_network.assert_not_called()
self._set_net_crd.assert_not_called()
self._rollback_network_resources.assert_not_called()
@ddt.data((n_exc.NeutronClientException), (k_exc.K8sClientException))
def test_on_present_create_exception(self, m_create_net):
self._get_net_crd.return_value = None
self._create_namespace_network.side_effect = m_create_net
def test_on_present_create_network_exception(self):
self._get_net_crd_id.return_value = None
self._create_namespace_network.side_effect = (
n_exc.NeutronClientException)
self.assertRaises(m_create_net, namespace.NamespaceHandler.on_present,
self.assertRaises(n_exc.NeutronClientException,
namespace.NamespaceHandler.on_present,
self._handler, self._namespace)
self._get_net_crd.assert_called_once_with(self._namespace)
self._get_net_crd_id.assert_called_once_with(self._namespace)
self._create_namespace_network.assert_called_once_with(
self._namespace_name, self._project_id)
self._create_namespace_sg.assert_not_called()
self._set_net_crd.assert_not_called()
self._rollback_network_resources.assert_not_called()
def test_on_present_create_sg_exception(self):
self._get_net_crd_id.return_value = None
self._create_namespace_network.return_value = {'test_net': 'uuid'}
self._create_namespace_sg.side_effect = (
n_exc.NeutronClientException)
self.assertRaises(n_exc.NeutronClientException,
namespace.NamespaceHandler.on_present,
self._handler, self._namespace)
self._get_net_crd_id.assert_called_once_with(self._namespace)
self._create_namespace_network.assert_called_once_with(
self._namespace_name, self._project_id)
self._create_namespace_sg.assert_called_once_with(
self._namespace_name, self._project_id)
self._set_net_crd.assert_not_called()
def test_on_present_add_kuryrnet_crd_exception(self):
self._get_net_crd_id.return_value = None
self._create_namespace_network.return_value = {'test_net': 'uuid'}
self._create_namespace_sg.return_value = {'sgId': 'uuid'}
net_crd_spec = {'test_net': 'uuid', 'sgId': 'uuid'}
self._add_kuryrnet_crd.side_effect = k_exc.K8sClientException
namespace.NamespaceHandler.on_present(self._handler, self._namespace)
self._get_net_crd_id.assert_called_once_with(self._namespace)
self._create_namespace_network.assert_called_once_with(
self._namespace_name, self._project_id)
self._create_namespace_sg.assert_called_once_with(
self._namespace_name, self._project_id)
self._add_kuryrnet_crd.assert_called_once_with(self._namespace_name,
net_crd_spec)
self._set_net_crd.assert_not_called()
self._rollback_network_resources.assert_called_once()
def test_on_present_set_crd_exception(self):
net_crd = self._get_crd()
self._get_net_crd.return_value = None
self._create_namespace_network.return_value = net_crd
self._get_net_crd_id.return_value = None
self._create_namespace_network.return_value = {'test_net': 'uuid'}
self._create_namespace_sg.return_value = {'sgId': 'uuid'}
net_crd_spec = {'test_net': 'uuid', 'sgId': 'uuid'}
self._add_kuryrnet_crd.return_value = net_crd
self._set_net_crd.side_effect = k_exc.K8sClientException
namespace.NamespaceHandler.on_present(self._handler, self._namespace)
self._get_net_crd.assert_called_once_with(self._namespace)
self._get_net_crd_id.assert_called_once_with(self._namespace)
self._create_namespace_network.assert_called_once_with(
self._namespace_name, self._project_id)
self._create_namespace_sg.assert_called_once_with(
self._namespace_name, self._project_id)
self._add_kuryrnet_crd.assert_called_once_with(self._namespace_name,
net_crd_spec)
self._set_net_crd.assert_called_once_with(self._namespace, net_crd)
self._rollback_network_resources.assert_called_once()
def test_on_present_rollback_exception(self):
net_crd = self._get_crd()
self._get_net_crd.return_value = None
self._create_namespace_network.return_value = net_crd
self._get_net_crd_id.return_value = None
self._create_namespace_network.return_value = {'test_net': 'uuid'}
self._create_namespace_sg.return_value = {'sgId': 'uuid'}
net_crd_spec = {'test_net': 'uuid', 'sgId': 'uuid'}
self._add_kuryrnet_crd.return_value = net_crd
self._set_net_crd.side_effect = k_exc.K8sClientException
self._rollback_network_resources.side_effect = (
n_exc.NeutronClientException)
@ -170,47 +229,56 @@ class TestNamespaceHandler(test_base.TestCase):
namespace.NamespaceHandler.on_present,
self._handler, self._namespace)
self._get_net_crd.assert_called_once_with(self._namespace)
self._get_net_crd_id.assert_called_once_with(self._namespace)
self._create_namespace_network.assert_called_once_with(
self._namespace_name, self._project_id)
self._create_namespace_sg.assert_called_once_with(
self._namespace_name, self._project_id)
self._add_kuryrnet_crd.assert_called_once_with(self._namespace_name,
net_crd_spec)
self._set_net_crd.assert_called_once_with(self._namespace, net_crd)
self._rollback_network_resources.assert_called_once()
def test_on_deleted(self):
net_crd_id = mock.sentinel.net_crd_id
net_crd = self._get_crd()
net_id = mock.sentinel.net_id
self._get_net_crd_id.return_value = net_crd_id
self._get_net_crd.return_value = net_crd
self._get_net_id_from_net_crd.return_value = net_id
namespace.NamespaceHandler.on_deleted(self._handler, self._namespace)
self._get_net_crd.assert_called_once_with(self._namespace)
self._get_net_id_from_net_crd.assert_called_once_with(net_crd)
self._delete_network_pools.assert_called_once_with(net_id)
self._get_net_crd_id.assert_called_once_with(self._namespace)
self._get_net_crd.assert_called_once_with(net_crd_id)
self._delete_network_pools.assert_called_once_with(
net_crd['spec']['netId'])
self._delete_namespace_subnet.assert_called_once_with(net_crd)
self._delete_sg.assert_called_once_with(net_crd['spec']['sgId'])
self._del_kuryrnet_crd.assert_called_once_with(net_crd_id)
def test_on_deleted_missing_crd_annotation(self):
self._get_net_crd.return_value = None
self._get_net_crd_id.return_value = None
namespace.NamespaceHandler.on_deleted(self._handler, self._namespace)
self._get_net_crd.assert_called_once_with(self._namespace)
self._get_net_id_from_net_crd.assert_not_called()
self._get_net_crd_id.assert_called_once_with(self._namespace)
self._get_net_crd.assert_not_called()
self._delete_network_pools.assert_not_called()
self._delete_namespace_subnet.assert_not_called()
self._delete_sg.assert_not_called()
self._del_kuryrnet_crd.assert_not_called()
def test_on_deleted_k8s_exception(self):
net_crd = self._get_crd()
net_crd_id = mock.sentinel.net_crd_id
self._get_net_crd.return_value = net_crd
self._get_net_id_from_net_crd.side_effect = k_exc.K8sClientException
self._get_net_crd_id.return_value = net_crd_id
self._get_net_crd.side_effect = k_exc.K8sClientException
self.assertRaises(k_exc.K8sClientException,
namespace.NamespaceHandler.on_deleted,
self._handler, self._namespace)
self._get_net_crd.assert_called_once_with(self._namespace)
self._get_net_id_from_net_crd.assert_called_once_with(net_crd)
self._get_net_crd_id.assert_called_once_with(self._namespace)
self._get_net_crd.assert_called_once_with(net_crd_id)
self._delete_network_pools.assert_not_called()
self._delete_namespace_subnet.assert_not_called()

View File

@ -61,6 +61,7 @@ kuryr_kubernetes.controller.drivers.service_subnets =
kuryr_kubernetes.controller.drivers.pod_security_groups =
default = kuryr_kubernetes.controller.drivers.default_security_groups:DefaultPodSecurityGroupsDriver
namespace = kuryr_kubernetes.controller.drivers.namespace_security_groups:NamespacePodSecurityGroupsDriver
kuryr_kubernetes.controller.drivers.service_security_groups =
default = kuryr_kubernetes.controller.drivers.default_security_groups:DefaultServiceSecurityGroupsDriver