[apic-mapping] Allowed VM Name extension for L3 Policy
This patch defines a new extension: cisco_apic_gbp_allowed_vm_name, for the apic policy drivers. An extension attribute: allowed_vm_names, that extends the L3 Policy definition, is being introduced in this extension. A corresponding extension driver: apic_allowed_vm_name, that processes this extension, is also being added. This extension driver should be configured for this extension to be available. The driver name should be added to the existing list of extension drivers under: [group_policy] extension_drivers=<existing_ext_drivers>,apic_allowed_vm_name The allowed_vm_names attribute is a list of regexes. Each regex can be up to 255 characters long. While during the port-binding phase, we will also enforce the regex checking against the VM name from Nova. Only those VM names matching one of those regexes will be allowed. A CLI option: --allowed_vm_names will be provided for the L3 Policy create and update operations. This CLI option will accept a comma separated string as the option value. Change-Id: I4602919df9a0458eb255b93399c70f64dfeeb863
This commit is contained in:
parent
7dc9e64c94
commit
29cd855015
@ -0,0 +1,50 @@
|
|||||||
|
# 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 neutron.db import model_base
|
||||||
|
import sqlalchemy as sa
|
||||||
|
|
||||||
|
|
||||||
|
class ApicAllowedVMNameDB(model_base.BASEV2):
|
||||||
|
__tablename__ = 'gp_apic_mapping_allowed_vm_names'
|
||||||
|
l3_policy_id = sa.Column(sa.String(36),
|
||||||
|
sa.ForeignKey('gp_l3_policies.id',
|
||||||
|
ondelete="CASCADE"),
|
||||||
|
primary_key=True)
|
||||||
|
allowed_vm_name = sa.Column(sa.String(255), primary_key=True)
|
||||||
|
|
||||||
|
|
||||||
|
class ApicAllowedVMNameDBMixin(object):
|
||||||
|
|
||||||
|
def get_l3_policy_allowed_vm_names(self, session, l3_policy_id):
|
||||||
|
rows = (session.query(ApicAllowedVMNameDB).filter_by(
|
||||||
|
l3_policy_id=l3_policy_id).all())
|
||||||
|
return rows
|
||||||
|
|
||||||
|
def get_l3_policy_allowed_vm_name(self, session, l3_policy_id,
|
||||||
|
allowed_vm_name):
|
||||||
|
row = (session.query(ApicAllowedVMNameDB).filter_by(
|
||||||
|
l3_policy_id=l3_policy_id,
|
||||||
|
allowed_vm_name=allowed_vm_name).one())
|
||||||
|
return row
|
||||||
|
|
||||||
|
def add_l3_policy_allowed_vm_name(self, session, l3_policy_id,
|
||||||
|
allowed_vm_name):
|
||||||
|
row = ApicAllowedVMNameDB(l3_policy_id=l3_policy_id,
|
||||||
|
allowed_vm_name=allowed_vm_name)
|
||||||
|
session.add(row)
|
||||||
|
|
||||||
|
def delete_l3_policy_allowed_vm_name(self, session, l3_policy_id,
|
||||||
|
allowed_vm_name):
|
||||||
|
row = self.get_l3_policy_allowed_vm_name(
|
||||||
|
session, l3_policy_id, allowed_vm_name)
|
||||||
|
session.delete(row)
|
@ -0,0 +1,45 @@
|
|||||||
|
# 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.
|
||||||
|
|
||||||
|
"""allowed_vm_names
|
||||||
|
|
||||||
|
Revision ID: 5629167be1d1
|
||||||
|
Revises: 092e4b1aeb0a
|
||||||
|
Create Date: 2016-10-11 14:14:06.648609
|
||||||
|
|
||||||
|
"""
|
||||||
|
|
||||||
|
# revision identifiers, used by Alembic.
|
||||||
|
revision = '5629167be1d1'
|
||||||
|
down_revision = '092e4b1aeb0a'
|
||||||
|
|
||||||
|
from alembic import op
|
||||||
|
import sqlalchemy as sa
|
||||||
|
|
||||||
|
|
||||||
|
def upgrade():
|
||||||
|
|
||||||
|
op.create_table(
|
||||||
|
'gp_apic_mapping_allowed_vm_names',
|
||||||
|
sa.Column('l3_policy_id', sa.String(length=36), nullable=False),
|
||||||
|
sa.Column('allowed_vm_name', sa.String(length=255),
|
||||||
|
nullable=False),
|
||||||
|
sa.ForeignKeyConstraint(
|
||||||
|
['l3_policy_id'], ['gp_l3_policies.id'],
|
||||||
|
name='gp_apic_mapping_allowed_vm_name_fk_l3pid',
|
||||||
|
ondelete='CASCADE'),
|
||||||
|
sa.PrimaryKeyConstraint('l3_policy_id', 'allowed_vm_name')
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def downgrade():
|
||||||
|
pass
|
@ -1 +1 @@
|
|||||||
092e4b1aeb0a
|
5629167be1d1
|
55
gbpservice/neutron/extensions/apic_allowed_vm_name.py
Normal file
55
gbpservice/neutron/extensions/apic_allowed_vm_name.py
Normal file
@ -0,0 +1,55 @@
|
|||||||
|
# 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 neutron.api import extensions
|
||||||
|
from neutron.api.v2 import attributes as attr
|
||||||
|
|
||||||
|
from gbpservice.neutron.extensions import group_policy as gp
|
||||||
|
|
||||||
|
|
||||||
|
CISCO_APIC_GBP_ALLOWED_VM_NAME_EXT = 'cisco_apic_gbp_allowed_vm_name'
|
||||||
|
|
||||||
|
EXTENDED_ATTRIBUTES_2_0 = {
|
||||||
|
gp.L3_POLICIES: {
|
||||||
|
'allowed_vm_names': {
|
||||||
|
'allow_post': True, 'allow_put': True, 'default': None,
|
||||||
|
'validate': {'type:list_of_unique_strings': None},
|
||||||
|
'convert_to': attr.convert_none_to_empty_list,
|
||||||
|
'is_visible': True},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
class Apic_allowed_vm_name(extensions.ExtensionDescriptor):
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def get_name(cls):
|
||||||
|
return "APIC GBP Allowed VM Name Extension"
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def get_alias(cls):
|
||||||
|
return CISCO_APIC_GBP_ALLOWED_VM_NAME_EXT
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def get_description(cls):
|
||||||
|
return _("This extension supports a list of allowed VM name regexes "
|
||||||
|
"that can be applied to the L3 policy resource.")
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def get_updated(cls):
|
||||||
|
return "2016-10-10T10:00:00-00:00"
|
||||||
|
|
||||||
|
def get_extended_resources(self, version):
|
||||||
|
if version == "2.0":
|
||||||
|
return EXTENDED_ATTRIBUTES_2_0
|
||||||
|
else:
|
||||||
|
return {}
|
@ -14,6 +14,7 @@
|
|||||||
# under the License.
|
# under the License.
|
||||||
|
|
||||||
import copy
|
import copy
|
||||||
|
import re
|
||||||
|
|
||||||
from neutron._i18n import _LW
|
from neutron._i18n import _LW
|
||||||
from neutron.common import constants as n_constants
|
from neutron.common import constants as n_constants
|
||||||
@ -27,6 +28,8 @@ from oslo_utils import importutils
|
|||||||
|
|
||||||
from gbpservice.neutron.services.grouppolicy.drivers.cisco.apic import (
|
from gbpservice.neutron.services.grouppolicy.drivers.cisco.apic import (
|
||||||
apic_mapping as amap)
|
apic_mapping as amap)
|
||||||
|
from gbpservice.neutron.services.grouppolicy.drivers.cisco.apic import (
|
||||||
|
nova_client as nclient)
|
||||||
|
|
||||||
|
|
||||||
LOG = log.getLogger(__name__)
|
LOG = log.getLogger(__name__)
|
||||||
@ -42,6 +45,7 @@ class APICMechanismGBPDriver(api.MechanismDriver):
|
|||||||
def __init__(self):
|
def __init__(self):
|
||||||
super(APICMechanismGBPDriver, self).__init__()
|
super(APICMechanismGBPDriver, self).__init__()
|
||||||
self._dvs_notifier = None
|
self._dvs_notifier = None
|
||||||
|
self._apic_allowed_vm_name_driver = None
|
||||||
|
|
||||||
def _agent_bind_port(self, context, agent_list, bind_strategy):
|
def _agent_bind_port(self, context, agent_list, bind_strategy):
|
||||||
"""Attempt port binding per agent.
|
"""Attempt port binding per agent.
|
||||||
@ -69,22 +73,54 @@ class APICMechanismGBPDriver(api.MechanismDriver):
|
|||||||
AgentMechanismDriverBase class, but is modified
|
AgentMechanismDriverBase class, but is modified
|
||||||
to support multiple L2 agent types (DVS and OpFlex).
|
to support multiple L2 agent types (DVS and OpFlex).
|
||||||
"""
|
"""
|
||||||
|
port = context.current
|
||||||
LOG.debug("Attempting to bind port %(port)s on "
|
LOG.debug("Attempting to bind port %(port)s on "
|
||||||
"network %(network)s",
|
"network %(network)s",
|
||||||
{'port': context.current['id'],
|
{'port': port['id'],
|
||||||
'network': context.network.current['id']})
|
'network': context.network.current['id']})
|
||||||
vnic_type = context.current.get(portbindings.VNIC_TYPE,
|
vnic_type = port.get(portbindings.VNIC_TYPE,
|
||||||
portbindings.VNIC_NORMAL)
|
portbindings.VNIC_NORMAL)
|
||||||
if vnic_type not in [portbindings.VNIC_NORMAL]:
|
if vnic_type not in [portbindings.VNIC_NORMAL]:
|
||||||
LOG.debug("Refusing to bind due to unsupported vnic_type: %s",
|
LOG.debug("Refusing to bind due to unsupported vnic_type: %s",
|
||||||
vnic_type)
|
vnic_type)
|
||||||
return
|
return
|
||||||
|
|
||||||
# Attempt to bind ports for DVS agents for nova-compute daemons
|
if port['device_owner'].startswith('compute:'):
|
||||||
# first. This allows having network agents (dhcp, metadata)
|
# enforce the allowed_vm_names rules if possible
|
||||||
# that typically run on a network node using an OpFlex agent to
|
if (port['device_id'] and self.apic_allowed_vm_name_driver):
|
||||||
# co-exist with nova-compute daemons for ESX, which host DVS agents.
|
ptg, pt = self.apic_gbp._port_id_to_ptg(
|
||||||
if context.current['device_owner'].startswith('compute:'):
|
context._plugin_context, port['id'])
|
||||||
|
if ptg is None:
|
||||||
|
LOG.warning(_LW("PTG for port %s does not exist"),
|
||||||
|
port['id'])
|
||||||
|
return
|
||||||
|
l2p = self.apic_gbp._get_l2_policy(context._plugin_context,
|
||||||
|
ptg['l2_policy_id'])
|
||||||
|
l3p = self.apic_gbp.gbp_plugin.get_l3_policy(
|
||||||
|
context._plugin_context, l2p['l3_policy_id'])
|
||||||
|
|
||||||
|
ok_to_bind = True
|
||||||
|
if l3p.get('allowed_vm_names'):
|
||||||
|
ok_to_bind = False
|
||||||
|
vm = nclient.NovaClient().get_server(port['device_id'])
|
||||||
|
for allowed_vm_name in l3p['allowed_vm_names']:
|
||||||
|
match = re.search(allowed_vm_name, vm.name)
|
||||||
|
if match:
|
||||||
|
ok_to_bind = True
|
||||||
|
break
|
||||||
|
if not ok_to_bind:
|
||||||
|
LOG.warning(_LW("Failed to bind the port due to "
|
||||||
|
"allowed_vm_names rules %(rules)s "
|
||||||
|
"for VM: %(vm)s"),
|
||||||
|
{'rules': l3p['allowed_vm_names'],
|
||||||
|
'vm': vm.name})
|
||||||
|
return
|
||||||
|
|
||||||
|
# Attempt to bind ports for DVS agents for nova-compute daemons
|
||||||
|
# first. This allows having network agents (dhcp, metadata)
|
||||||
|
# that typically run on a network node using an OpFlex agent to
|
||||||
|
# co-exist with nova-compute daemons for ESX, which host DVS
|
||||||
|
# agents.
|
||||||
agent_list = context.host_agents(AGENT_TYPE_DVS)
|
agent_list = context.host_agents(AGENT_TYPE_DVS)
|
||||||
if self._agent_bind_port(context, agent_list, self._bind_dvs_port):
|
if self._agent_bind_port(context, agent_list, self._bind_dvs_port):
|
||||||
return
|
return
|
||||||
@ -205,6 +241,21 @@ class APICMechanismGBPDriver(api.MechanismDriver):
|
|||||||
self._dvs_notifier = None
|
self._dvs_notifier = None
|
||||||
return self._dvs_notifier
|
return self._dvs_notifier
|
||||||
|
|
||||||
|
@property
|
||||||
|
def apic_allowed_vm_name_driver(self):
|
||||||
|
if self._apic_allowed_vm_name_driver is False:
|
||||||
|
return False
|
||||||
|
if not self._apic_allowed_vm_name_driver:
|
||||||
|
ext_drivers = (self.apic_gbp.gbp_plugin.extension_manager.
|
||||||
|
ordered_ext_drivers)
|
||||||
|
for driver in ext_drivers:
|
||||||
|
if 'apic_allowed_vm_name' == driver.name:
|
||||||
|
self._apic_allowed_vm_name_driver = driver.obj
|
||||||
|
break
|
||||||
|
if not self._apic_allowed_vm_name_driver:
|
||||||
|
self._apic_allowed_vm_name_driver = False
|
||||||
|
return self._apic_allowed_vm_name_driver
|
||||||
|
|
||||||
def create_port_postcommit(self, context):
|
def create_port_postcommit(self, context):
|
||||||
self.apic_gbp.process_port_added(context)
|
self.apic_gbp.process_port_added(context)
|
||||||
|
|
||||||
|
@ -0,0 +1,85 @@
|
|||||||
|
# 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 oslo_log import log as logging
|
||||||
|
import re
|
||||||
|
|
||||||
|
from gbpservice.neutron.db.grouppolicy.extensions import (
|
||||||
|
apic_allowed_vm_name_db as db)
|
||||||
|
from gbpservice.neutron.extensions import apic_allowed_vm_name as aavnext
|
||||||
|
from gbpservice.neutron.services.grouppolicy import (
|
||||||
|
group_policy_driver_api as api)
|
||||||
|
from gbpservice.neutron.services.grouppolicy.common import exceptions as gpexc
|
||||||
|
|
||||||
|
LOG = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
|
||||||
|
class AllowedVMNameBadRegex(gpexc.GroupPolicyBadRequest):
|
||||||
|
message = _("Bad regex: %(regex)s is defined for the allowed-vm-names "
|
||||||
|
"attribute.")
|
||||||
|
|
||||||
|
|
||||||
|
class ApicAllowedVMNameExtensionDriver(api.ExtensionDriver,
|
||||||
|
db.ApicAllowedVMNameDBMixin):
|
||||||
|
_supported_extension_alias = aavnext.CISCO_APIC_GBP_ALLOWED_VM_NAME_EXT
|
||||||
|
_extension_dict = aavnext.EXTENDED_ATTRIBUTES_2_0
|
||||||
|
|
||||||
|
def __init__(self):
|
||||||
|
LOG.debug("APIC Allowed VM Name Extension Driver __init__")
|
||||||
|
self._policy_driver = None
|
||||||
|
|
||||||
|
def initialize(self):
|
||||||
|
pass
|
||||||
|
|
||||||
|
@property
|
||||||
|
def extension_alias(self):
|
||||||
|
return self._supported_extension_alias
|
||||||
|
|
||||||
|
def process_create_l3_policy(self, session, data, result):
|
||||||
|
l3p = data['l3_policy']
|
||||||
|
if 'allowed_vm_names' in l3p:
|
||||||
|
for vm_name in l3p['allowed_vm_names']:
|
||||||
|
try:
|
||||||
|
re.compile(vm_name)
|
||||||
|
except re.error:
|
||||||
|
raise AllowedVMNameBadRegex(regex=vm_name)
|
||||||
|
self.add_l3_policy_allowed_vm_name(
|
||||||
|
session, l3_policy_id=result['id'],
|
||||||
|
allowed_vm_name=vm_name)
|
||||||
|
|
||||||
|
def process_update_l3_policy(self, session, data, result):
|
||||||
|
l3p = data['l3_policy']
|
||||||
|
if not 'allowed_vm_names' in l3p:
|
||||||
|
return
|
||||||
|
rows = self.get_l3_policy_allowed_vm_names(
|
||||||
|
session, l3_policy_id=result['id'])
|
||||||
|
old_vm_names = [r.allowed_vm_name for r in rows]
|
||||||
|
add_vm_names = list(set(l3p['allowed_vm_names']) - set(old_vm_names))
|
||||||
|
for vm_name in add_vm_names:
|
||||||
|
try:
|
||||||
|
re.compile(vm_name)
|
||||||
|
except re.error:
|
||||||
|
raise AllowedVMNameBadRegex(regex=vm_name)
|
||||||
|
self.add_l3_policy_allowed_vm_name(
|
||||||
|
session, l3_policy_id=result['id'],
|
||||||
|
allowed_vm_name=vm_name)
|
||||||
|
rm_vm_names = list(set(old_vm_names) - set(l3p['allowed_vm_names']))
|
||||||
|
for vm_name in rm_vm_names:
|
||||||
|
self.delete_l3_policy_allowed_vm_name(
|
||||||
|
session, l3_policy_id=result['id'],
|
||||||
|
allowed_vm_name=vm_name)
|
||||||
|
|
||||||
|
def extend_l3_policy_dict(self, session, result):
|
||||||
|
rows = self.get_l3_policy_allowed_vm_names(
|
||||||
|
session, l3_policy_id=result['id'])
|
||||||
|
allowed_vm_names = [r.allowed_vm_name for r in rows]
|
||||||
|
result['allowed_vm_names'] = allowed_vm_names
|
@ -0,0 +1,86 @@
|
|||||||
|
# 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 neutron.db import api as db_api
|
||||||
|
|
||||||
|
from gbpservice.neutron.db.grouppolicy.extensions import (
|
||||||
|
apic_allowed_vm_name_db as db)
|
||||||
|
from gbpservice.neutron.tests.unit.services.grouppolicy import (
|
||||||
|
test_extension_driver_api as test_ext_base)
|
||||||
|
|
||||||
|
|
||||||
|
class ExtensionDriverTestCase(test_ext_base.ExtensionDriverTestBase):
|
||||||
|
_extension_drivers = ['apic_allowed_vm_name']
|
||||||
|
_extension_path = None
|
||||||
|
|
||||||
|
def test_l3p_lifecycle(self):
|
||||||
|
l3p = self.create_l3_policy(name='myl3')['l3_policy']
|
||||||
|
self.assertEqual([], l3p['allowed_vm_names'])
|
||||||
|
l3p = self.show_l3_policy(
|
||||||
|
l3p['id'], expected_res_status=200)['l3_policy']
|
||||||
|
self.assertEqual([], l3p['allowed_vm_names'])
|
||||||
|
self.delete_l3_policy(l3p['id'], tenant_id=l3p['tenant_id'],
|
||||||
|
expected_res_status=204)
|
||||||
|
|
||||||
|
allowed_vm_names = []
|
||||||
|
l3p = self.create_l3_policy(
|
||||||
|
name='myl3',
|
||||||
|
allowed_vm_names=allowed_vm_names)['l3_policy']
|
||||||
|
self.assertItemsEqual(allowed_vm_names, l3p['allowed_vm_names'])
|
||||||
|
l3p = self.show_l3_policy(
|
||||||
|
l3p['id'], expected_res_status=200)['l3_policy']
|
||||||
|
self.assertItemsEqual([], l3p['allowed_vm_names'])
|
||||||
|
self.delete_l3_policy(l3p['id'], tenant_id=l3p['tenant_id'],
|
||||||
|
expected_res_status=204)
|
||||||
|
|
||||||
|
allowed_vm_names = ['safe_vm*', '^secure_vm*']
|
||||||
|
l3p = self.create_l3_policy(
|
||||||
|
name='myl3',
|
||||||
|
allowed_vm_names=allowed_vm_names)['l3_policy']
|
||||||
|
self.assertItemsEqual(allowed_vm_names, l3p['allowed_vm_names'])
|
||||||
|
l3p = self.show_l3_policy(
|
||||||
|
l3p['id'], expected_res_status=200)['l3_policy']
|
||||||
|
self.assertItemsEqual(allowed_vm_names, l3p['allowed_vm_names'])
|
||||||
|
|
||||||
|
allowed_vm_names = ['good_vm*', '^ok_vm*', 'safe_vm*']
|
||||||
|
l3p = self.update_l3_policy(
|
||||||
|
l3p['id'], allowed_vm_names=allowed_vm_names,
|
||||||
|
expected_res_status=200)['l3_policy']
|
||||||
|
self.assertItemsEqual(allowed_vm_names, l3p['allowed_vm_names'])
|
||||||
|
l3p = self.show_l3_policy(
|
||||||
|
l3p['id'], expected_res_status=200)['l3_policy']
|
||||||
|
self.assertItemsEqual(allowed_vm_names, l3p['allowed_vm_names'])
|
||||||
|
|
||||||
|
allowed_vm_names = []
|
||||||
|
l3p = self.update_l3_policy(
|
||||||
|
l3p['id'], allowed_vm_names=allowed_vm_names,
|
||||||
|
expected_res_status=200)['l3_policy']
|
||||||
|
self.assertItemsEqual(allowed_vm_names, l3p['allowed_vm_names'])
|
||||||
|
l3p = self.show_l3_policy(
|
||||||
|
l3p['id'], expected_res_status=200)['l3_policy']
|
||||||
|
self.assertItemsEqual(allowed_vm_names, l3p['allowed_vm_names'])
|
||||||
|
|
||||||
|
allowed_vm_names = ['^ok_vm*']
|
||||||
|
l3p = self.update_l3_policy(
|
||||||
|
l3p['id'], allowed_vm_names=allowed_vm_names,
|
||||||
|
expected_res_status=200)['l3_policy']
|
||||||
|
self.assertItemsEqual(allowed_vm_names, l3p['allowed_vm_names'])
|
||||||
|
l3p = self.show_l3_policy(
|
||||||
|
l3p['id'], expected_res_status=200)['l3_policy']
|
||||||
|
self.assertItemsEqual(allowed_vm_names, l3p['allowed_vm_names'])
|
||||||
|
|
||||||
|
self.delete_l3_policy(l3p['id'], tenant_id=l3p['tenant_id'],
|
||||||
|
expected_res_status=204)
|
||||||
|
session = db_api.get_session()
|
||||||
|
rows = (session.query(db.ApicAllowedVMNameDB).filter_by(
|
||||||
|
l3_policy_id=l3p['id']).all())
|
||||||
|
self.assertEqual([], rows)
|
@ -94,7 +94,7 @@ class MockCallRecorder(mock.Mock):
|
|||||||
class ApicMappingTestCase(
|
class ApicMappingTestCase(
|
||||||
test_rmd.ResourceMappingTestCase,
|
test_rmd.ResourceMappingTestCase,
|
||||||
mocked.ControllerMixin, mocked.ConfigMixin):
|
mocked.ControllerMixin, mocked.ConfigMixin):
|
||||||
_extension_drivers = ['apic_segmentation_label']
|
_extension_drivers = ['apic_segmentation_label', 'apic_allowed_vm_name']
|
||||||
_extension_path = None
|
_extension_path = None
|
||||||
|
|
||||||
def setUp(self, sc_plugin=None, nat_enabled=True,
|
def setUp(self, sc_plugin=None, nat_enabled=True,
|
||||||
@ -1532,7 +1532,6 @@ class FakePortContext(object):
|
|||||||
|
|
||||||
|
|
||||||
class TestPolicyTargetDvs(ApicMappingTestCase):
|
class TestPolicyTargetDvs(ApicMappingTestCase):
|
||||||
|
|
||||||
def setUp(self):
|
def setUp(self):
|
||||||
super(TestPolicyTargetDvs, self).setUp()
|
super(TestPolicyTargetDvs, self).setUp()
|
||||||
self.driver.apic_manager.app_profile_name = mocked.APIC_AP
|
self.driver.apic_manager.app_profile_name = mocked.APIC_AP
|
||||||
@ -1715,6 +1714,38 @@ class TestPolicyTargetDvs(ApicMappingTestCase):
|
|||||||
self.ml2.delete_port_postcommit(port_ctx)
|
self.ml2.delete_port_postcommit(port_ctx)
|
||||||
self._verify_dvs_notifier('delete_port_call', newp1['port'], 'h1')
|
self._verify_dvs_notifier('delete_port_call', newp1['port'], 'h1')
|
||||||
|
|
||||||
|
def test_bind_port_with_allowed_vm_names(self):
|
||||||
|
allowed_vm_names = ['safe_vm*', '^secure_vm*']
|
||||||
|
l3p = self.create_l3_policy(name='myl3',
|
||||||
|
allowed_vm_names=allowed_vm_names)['l3_policy']
|
||||||
|
l2p = self.create_l2_policy(
|
||||||
|
name='myl2', l3_policy_id=l3p['id'])['l2_policy']
|
||||||
|
ptg = self.create_policy_target_group(
|
||||||
|
name="ptg1", l2_policy_id=l2p['id'])['policy_target_group']
|
||||||
|
pt = self.create_policy_target(
|
||||||
|
policy_target_group_id=ptg['id'])['policy_target']
|
||||||
|
|
||||||
|
nova_client = mock.patch(
|
||||||
|
'gbpservice.neutron.services.grouppolicy.drivers.cisco.'
|
||||||
|
'apic.nova_client.NovaClient.get_server').start()
|
||||||
|
vm = mock.Mock()
|
||||||
|
vm.name = 'secure_vm1'
|
||||||
|
nova_client.return_value = vm
|
||||||
|
newp1 = self._bind_port_to_host(pt['port_id'], 'h1')
|
||||||
|
self.assertEqual(newp1['port']['binding:vif_type'], 'ovs')
|
||||||
|
|
||||||
|
# bind again
|
||||||
|
vm.name = 'bad_vm1'
|
||||||
|
newp1 = self._bind_port_to_host(pt['port_id'], 'h2')
|
||||||
|
self.assertEqual(newp1['port']['binding:vif_type'], 'binding_failed')
|
||||||
|
|
||||||
|
# update l3p with empty allowed_vm_names
|
||||||
|
l3p = self.update_l3_policy(l3p['id'], tenant_id=l3p['tenant_id'],
|
||||||
|
allowed_vm_names=[],
|
||||||
|
expected_res_status=200)['l3_policy']
|
||||||
|
newp1 = self._bind_port_to_host(pt['port_id'], 'h3')
|
||||||
|
self.assertEqual(newp1['port']['binding:vif_type'], 'ovs')
|
||||||
|
|
||||||
|
|
||||||
class TestPolicyTargetGroup(ApicMappingTestCase):
|
class TestPolicyTargetGroup(ApicMappingTestCase):
|
||||||
|
|
||||||
|
@ -60,6 +60,7 @@ gbpservice.neutron.group_policy.extension_drivers =
|
|||||||
proxy_group = gbpservice.neutron.services.grouppolicy.drivers.extensions.proxy_group_driver:ProxyGroupDriver
|
proxy_group = gbpservice.neutron.services.grouppolicy.drivers.extensions.proxy_group_driver:ProxyGroupDriver
|
||||||
aim_extension = gbpservice.neutron.services.grouppolicy.drivers.extensions.aim_mapping_extension_driver:AIMExtensionDriver
|
aim_extension = gbpservice.neutron.services.grouppolicy.drivers.extensions.aim_mapping_extension_driver:AIMExtensionDriver
|
||||||
apic_segmentation_label = gbpservice.neutron.services.grouppolicy.drivers.extensions.apic_segmentation_label_driver:ApicSegmentationLabelExtensionDriver
|
apic_segmentation_label = gbpservice.neutron.services.grouppolicy.drivers.extensions.apic_segmentation_label_driver:ApicSegmentationLabelExtensionDriver
|
||||||
|
apic_allowed_vm_name = gbpservice.neutron.services.grouppolicy.drivers.extensions.apic_allowed_vm_name_driver:ApicAllowedVMNameExtensionDriver
|
||||||
gbpservice.neutron.group_policy.policy_drivers =
|
gbpservice.neutron.group_policy.policy_drivers =
|
||||||
dummy = gbpservice.neutron.services.grouppolicy.drivers.dummy_driver:NoopDriver
|
dummy = gbpservice.neutron.services.grouppolicy.drivers.dummy_driver:NoopDriver
|
||||||
implicit_policy = gbpservice.neutron.services.grouppolicy.drivers.implicit_policy:ImplicitPolicyDriver
|
implicit_policy = gbpservice.neutron.services.grouppolicy.drivers.implicit_policy:ImplicitPolicyDriver
|
||||||
|
Loading…
Reference in New Issue
Block a user