Add Magnum config for default network driver per COE

Problem description:
Magnum should provide support for configuration of default network drivers per
COE. An example use case could be a cloud operator who would like to have
control of what default container network driver should be used on a per-COE
basis. The cloud operator in this case should be able to set the default
network driver per COE in /etc/magnum/magnum.conf.

Proposed fix:
Add 3 configuration list options to the config in /etc/magnum/magnum.conf:
- kubernetes_default_network_driver
  (default='flannel')
- swarm_default_network_driver
  (default='docker')
- mesos_default_network_driver
  (default='docker')
When a baymodel is created and the --network-driver attribute is not supplied,
then the configured default network driver for the selected COE will first be
checked against the list of allowed network drivers for that COE, and if
allowed, the configured default network driver will be used for the new
baymodel.

Change-Id: I1e1d68c3348f609975b914926994bd79c1ef6d28
Closes-Bug: #1504664
This commit is contained in:
Dane LeBlanc 2015-11-05 12:39:07 -05:00 committed by Daneyon Hansen
parent 58cbafdc87
commit 471aa924fc
7 changed files with 112 additions and 61 deletions

View File

@ -375,16 +375,25 @@
# network drivers include flannel. (list value) # network drivers include flannel. (list value)
#kubernetes_allowed_network_drivers = all #kubernetes_allowed_network_drivers = all
# Allowed network drivers for docker swarm baymodels. Use 'all' # Default network driver for kubernetes baymodels.
# keyword to allow all drivers supported for swarm baymodels. #kubernetes_default_network_driver = flannel
# Supported network drivers include docker. (list value)
# Allowed network drivers for docker swarm baymodels. Use 'all' keyword
# to allow all drivers supported for swarm baymodels. Supported
# network drivers include docker. (list value)
#swarm_allowed_network_drivers = all #swarm_allowed_network_drivers = all
# Allowed network drivers for mesos baymodels. Use 'all' keyword to # Default network driver for docker swarm baymodels.
# allow all drivers supported for mesos baymodels. Supported network #swarm_default_network_driver = docker
# drivers include docker. (list value)
# Allowed network drivers for mesos baymodels. Use 'all' keyword
# to allow all drivers supported for mesos baymodels. Supported
# network drivers include docker. (list value)
#mesos_allowed_network_drivers = all #mesos_allowed_network_drivers = all
# Default network driver for mesos baymodels.
#mesos_default_network_driver = docker
[certificates] [certificates]

View File

@ -14,7 +14,6 @@
import glanceclient.exc import glanceclient.exc
import novaclient.exceptions as nova_exc import novaclient.exceptions as nova_exc
from oslo_config import cfg
from oslo_utils import timeutils from oslo_utils import timeutils
import pecan import pecan
from pecan import rest from pecan import rest
@ -34,29 +33,6 @@ from magnum.common import policy
from magnum import objects from magnum import objects
baymodel_opts = [
cfg.ListOpt('kubernetes_allowed_network_drivers',
default=['all'],
help="Allowed network drivers for kubernetes baymodels. "
"Use 'all' keyword to allow all drivers supported "
"for kubernetes baymodels. Supported network drivers "
"include flannel."),
cfg.ListOpt('swarm_allowed_network_drivers',
default=['all'],
help="Allowed network drivers for docker swarm baymodels. "
"Use 'all' keyword to allow all drivers supported "
"for swarm baymodels. Supported network drivers "
"include docker."),
cfg.ListOpt('mesos_allowed_network_drivers',
default=['all'],
help="Allowed network drivers for mesos baymodels. "
"Use 'all' keyword to allow all drivers supported "
"for mesos baymodels. Supported network drivers "
"include docker.")
]
cfg.CONF.register_opts(baymodel_opts, group='baymodel')
class BayModelPatchType(types.JsonPatchType): class BayModelPatchType(types.JsonPatchType):
pass pass

View File

@ -21,6 +21,38 @@ from magnum.common import exception
from magnum import objects from magnum import objects
baymodel_opts = [
cfg.ListOpt('kubernetes_allowed_network_drivers',
default=['all'],
help="Allowed network drivers for kubernetes baymodels. "
"Use 'all' keyword to allow all drivers supported "
"for kubernetes baymodels. Supported network drivers "
"include flannel."),
cfg.StrOpt('kubernetes_default_network_driver',
default='flannel',
help="Default network driver for kubernetes baymodels."),
cfg.ListOpt('swarm_allowed_network_drivers',
default=['all'],
help="Allowed network drivers for docker swarm baymodels. "
"Use 'all' keyword to allow all drivers supported "
"for swarm baymodels. Supported network drivers "
"include docker."),
cfg.StrOpt('swarm_default_network_driver',
default='docker',
help="Default network driver for docker swarm baymodels."),
cfg.ListOpt('mesos_allowed_network_drivers',
default=['all'],
help="Allowed network drivers for mesos baymodels. "
"Use 'all' keyword to allow all drivers supported "
"for mesos baymodels. Supported network drivers "
"include docker."),
cfg.StrOpt('mesos_default_network_driver',
default='docker',
help="Default network driver for mesos baymodels."),
]
cfg.CONF.register_opts(baymodel_opts, group='baymodel')
def enforce_bay_types(*bay_types): def enforce_bay_types(*bay_types):
@decorator.decorator @decorator.decorator
def wrapper(func, *args, **kwargs): def wrapper(func, *args, **kwargs):
@ -62,24 +94,29 @@ def enforce_network_driver_types_update():
def _enforce_network_driver_types(baymodel): def _enforce_network_driver_types(baymodel):
driver = baymodel.network_driver validator = Validator.get_coe_validator(baymodel.coe)
if driver: if not baymodel.network_driver:
validator = Validator.get_coe_validator(baymodel.coe) baymodel.network_driver = validator.default_driver
validator.validate_network_driver(driver) validator.validate_network_driver(baymodel.network_driver)
class Validator(object): class Validator(object):
@staticmethod validators = {}
def get_coe_validator(coe):
if coe == 'kubernetes': @classmethod
return K8sValidator() def get_coe_validator(cls, coe):
if coe == 'swarm': if not cls.validators:
return SwarmValidator() cls.validators = {
if coe == 'mesos': 'kubernetes': K8sValidator(),
return MesosValidator() 'swarm': SwarmValidator(),
raise exception.InvalidParameterValue( 'mesos': MesosValidator(),
'Requested COE type %s is not supported.' % coe) }
if coe in cls.validators:
return cls.validators[coe]
else:
raise exception.InvalidParameterValue(
'Requested COE type %s is not supported.' % coe)
@classmethod @classmethod
def validate_network_driver(cls, driver): def validate_network_driver(cls, driver):
@ -100,32 +137,32 @@ class Validator(object):
@classmethod @classmethod
def _validate_network_driver_allowed(cls, driver): def _validate_network_driver_allowed(cls, driver):
"""Confirm that driver is allowed via configuration for this COE.""" """Confirm that driver is allowed via configuration for this COE."""
allowed_drivers = cfg.CONF.baymodel[cls.allowed_driver_config] if ('all' not in cls.allowed_drivers and
if ('all' not in allowed_drivers and driver not in cls.allowed_drivers):
driver not in allowed_drivers):
raise exception.InvalidParameterValue( raise exception.InvalidParameterValue(
'Network driver type %(driver)s is not allowed, ' 'Network driver type %(driver)s is not allowed, '
'expecting a %(allowed_drivers)s network driver. ' 'expecting a %(allowed_drivers)s network driver. ' % {
'Check %(config)s configuration.' % {
'driver': driver, 'driver': driver,
'allowed_drivers': '/'.join( 'allowed_drivers': '/'.join(
allowed_drivers + ['unspecified']), cls.allowed_drivers + ['unspecified'])})
'config': cls.allowed_driver_config})
class K8sValidator(Validator): class K8sValidator(Validator):
supported_drivers = ['flannel'] supported_drivers = ['flannel']
allowed_driver_config = 'kubernetes_allowed_network_drivers' allowed_drivers = cfg.CONF.baymodel.kubernetes_allowed_network_drivers
default_driver = cfg.CONF.baymodel.kubernetes_default_network_driver
class SwarmValidator(Validator): class SwarmValidator(Validator):
supported_drivers = ['docker'] supported_drivers = ['docker']
allowed_driver_config = 'swarm_allowed_network_drivers' allowed_drivers = cfg.CONF.baymodel.swarm_allowed_network_drivers
default_driver = cfg.CONF.baymodel.swarm_default_network_driver
class MesosValidator(Validator): class MesosValidator(Validator):
supported_drivers = ['docker'] supported_drivers = ['docker']
allowed_driver_config = 'mesos_allowed_network_drivers' allowed_drivers = cfg.CONF.baymodel.mesos_allowed_network_drivers
default_driver = cfg.CONF.baymodel.mesos_default_network_driver

View File

@ -17,7 +17,7 @@ import itertools
import magnum.api.app import magnum.api.app
import magnum.api.auth import magnum.api.auth
import magnum.api.controllers.v1.baymodel import magnum.api.validation
import magnum.common.cert_manager import magnum.common.cert_manager
from magnum.common.cert_manager import local_cert_manager from magnum.common.cert_manager import local_cert_manager
import magnum.common.clients import magnum.common.clients
@ -57,5 +57,5 @@ def list_opts():
itertools.chain(magnum.common.cert_manager.cert_manager_opts, itertools.chain(magnum.common.cert_manager.cert_manager_opts,
local_cert_manager.local_cert_manager_opts, local_cert_manager.local_cert_manager_opts,
)), )),
('baymodel', magnum.api.controllers.v1.baymodel.baymodel_opts), ('baymodel', magnum.api.validation.baymodel_opts),
] ]

View File

@ -49,8 +49,8 @@ def generate_random_coe():
def generate_random_coe_dep_network_driver(coe): def generate_random_coe_dep_network_driver(coe):
allowed_driver_types = { allowed_driver_types = {
'kubernetes': ['flannel', None], 'kubernetes': ['flannel', None],
'swarm': [None], 'swarm': ['docker', None],
'mesos': [None], 'mesos': ['docker', None],
} }
driver_types = allowed_driver_types[coe] driver_types = allowed_driver_types[coe]
return driver_types[random.randrange(0, len(driver_types))] return driver_types[random.randrange(0, len(driver_types))]

View File

@ -563,7 +563,11 @@ class TestPost(api_base.FunctionalTest):
if expect_errors: if expect_errors:
self.assertEqual(400, response.status_int) self.assertEqual(400, response.status_int)
else: else:
self.assertEqual(bdict['network_driver'], expected_driver = bdict.get('network_driver')
if not expected_driver:
expected_driver = (
cfg.CONF.baymodel.swarm_default_network_driver)
self.assertEqual(expected_driver,
response.json['network_driver']) response.json['network_driver'])
self.assertEqual(bdict['image_id'], self.assertEqual(bdict['image_id'],
response.json['image_id']) response.json['image_id'])

View File

@ -122,15 +122,18 @@ class TestValidation(base.BaseTestCase):
baymodel.network_driver = network_driver_type baymodel.network_driver = network_driver_type
baymodel.coe = coe baymodel.coe = coe
# Reload the validator module so that baymodel configs are
# re-evaluated.
reload(v)
validator = v.K8sValidator validator = v.K8sValidator
validator.supported_drivers = ['flannel', 'type1', 'type2'] validator.supported_drivers = ['flannel', 'type1', 'type2']
validator.allowed_driver_config = 'kubernetes_allowed_network_drivers'
if assert_raised: if assert_raised:
self.assertRaises(exception.InvalidParameterValue, self.assertRaises(exception.InvalidParameterValue,
test, self, baymodel) test, self, baymodel)
else: else:
test(self, baymodel) test(self, baymodel)
return baymodel
def test_enforce_network_driver_types_one_allowed_create(self): def test_enforce_network_driver_types_one_allowed_create(self):
self._test_enforce_network_driver_types_create( self._test_enforce_network_driver_types_create(
@ -165,6 +168,26 @@ class TestValidation(base.BaseTestCase):
coe='invalid_coe_type', coe='invalid_coe_type',
assert_raised=True) assert_raised=True)
def test_enforce_network_driver_types_default_create(self):
baymodel = self._test_enforce_network_driver_types_create(
network_driver_type=None,
network_driver_config_dict={})
self.assertEqual('flannel', baymodel.network_driver)
def test_enforce_network_driver_types_default_config_create(self):
baymodel = self._test_enforce_network_driver_types_create(
network_driver_type=None,
network_driver_config_dict={
'kubernetes_default_network_driver': 'type1'})
self.assertEqual('type1', baymodel.network_driver)
def test_enforce_network_driver_types_default_invalid_create(self):
self._test_enforce_network_driver_types_create(
network_driver_type=None,
network_driver_config_dict={
'kubernetes_default_network_driver': 'invalid_driver'},
assert_raised=True)
@mock.patch('pecan.request') @mock.patch('pecan.request')
@mock.patch('magnum.objects.BayModel.get_by_uuid') @mock.patch('magnum.objects.BayModel.get_by_uuid')
def _test_enforce_network_driver_types_update( def _test_enforce_network_driver_types_update(
@ -188,9 +211,11 @@ class TestValidation(base.BaseTestCase):
baymodel.coe = 'kubernetes' baymodel.coe = 'kubernetes'
mock_baymodel_get_by_uuid.return_value = baymodel mock_baymodel_get_by_uuid.return_value = baymodel
# Reload the validator module so that baymodel configs are
# re-evaluated.
reload(v)
validator = v.K8sValidator validator = v.K8sValidator
validator.supported_drivers = ['flannel', 'type1', 'type2'] validator.supported_drivers = ['flannel', 'type1', 'type2']
validator.allowed_driver_config = 'kubernetes_allowed_network_drivers'
if assert_raised: if assert_raised:
self.assertRaises(exception.InvalidParameterValue, self.assertRaises(exception.InvalidParameterValue,