9e97c8b8a7
For the 'devicemapper' storage driver, must specify volume and the minimum value is 3GB. Change-Id: I2b5ab83ac00b4a5bc6f113924e022f8952dd7766 Closes-Bug: #1772782
343 lines
12 KiB
Python
343 lines
12 KiB
Python
# Copyright 2015 Huawei Technologies Co.,LTD.
|
|
#
|
|
# 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 decorator
|
|
|
|
import pecan
|
|
|
|
from keystoneauth1 import exceptions as ka_exception
|
|
|
|
from magnum.api import utils as api_utils
|
|
from magnum.common import clients
|
|
from magnum.common import exception
|
|
import magnum.conf
|
|
from magnum.drivers.common import driver
|
|
from magnum.i18n import _
|
|
from magnum import objects
|
|
|
|
CONF = magnum.conf.CONF
|
|
|
|
cluster_update_allowed_properties = set(['node_count'])
|
|
federation_update_allowed_properties = set(['member_ids', 'properties'])
|
|
|
|
|
|
def enforce_cluster_type_supported():
|
|
@decorator.decorator
|
|
def wrapper(func, *args, **kwargs):
|
|
cluster = args[1]
|
|
cluster_template = objects.ClusterTemplate.get_by_uuid(
|
|
pecan.request.context, cluster.cluster_template_id)
|
|
cluster_type = (cluster_template.server_type,
|
|
cluster_template.cluster_distro,
|
|
cluster_template.coe)
|
|
driver.Driver.get_driver(*cluster_type)
|
|
return func(*args, **kwargs)
|
|
|
|
return wrapper
|
|
|
|
|
|
def enforce_driver_supported():
|
|
@decorator.decorator
|
|
def wrapper(func, *args, **kwargs):
|
|
cluster_template = args[1]
|
|
cluster_distro = cluster_template.cluster_distro
|
|
if not cluster_distro:
|
|
try:
|
|
cli = clients.OpenStackClients(pecan.request.context)
|
|
image_id = cluster_template.image_id
|
|
image = api_utils.get_openstack_resource(cli.glance().images,
|
|
image_id,
|
|
'images')
|
|
cluster_distro = image.get('os_distro')
|
|
except Exception:
|
|
pass
|
|
cluster_type = (cluster_template.server_type,
|
|
cluster_distro,
|
|
cluster_template.coe)
|
|
driver.Driver.get_driver(*cluster_type)
|
|
return func(*args, **kwargs)
|
|
|
|
return wrapper
|
|
|
|
|
|
def enforce_cluster_volume_storage_size():
|
|
@decorator.decorator
|
|
def wrapper(func, *args, **kwargs):
|
|
cluster = args[1]
|
|
cluster_template = objects.ClusterTemplate.get_by_uuid(
|
|
pecan.request.context, cluster.cluster_template_id)
|
|
_enforce_volume_storage_size(
|
|
cluster_template.as_dict(), cluster.as_dict())
|
|
return func(*args, **kwargs)
|
|
|
|
return wrapper
|
|
|
|
|
|
def enforce_valid_project_id_on_create():
|
|
@decorator.decorator
|
|
def wrapper(func, *args, **kwargs):
|
|
quota = args[1]
|
|
_validate_project_id(quota.project_id)
|
|
return func(*args, **kwargs)
|
|
|
|
return wrapper
|
|
|
|
|
|
def _validate_project_id(project_id):
|
|
try:
|
|
context = pecan.request.context
|
|
osc = clients.OpenStackClients(context)
|
|
osc.keystone().domain_admin_client.projects.get(project_id)
|
|
except ka_exception.http.NotFound:
|
|
raise exception.ProjectNotFound(name='project_id',
|
|
id=project_id)
|
|
|
|
|
|
def enforce_network_driver_types_create():
|
|
@decorator.decorator
|
|
def wrapper(func, *args, **kwargs):
|
|
cluster_template = args[1]
|
|
_enforce_network_driver_types(cluster_template)
|
|
return func(*args, **kwargs)
|
|
|
|
return wrapper
|
|
|
|
|
|
def enforce_network_driver_types_update():
|
|
@decorator.decorator
|
|
def wrapper(func, *args, **kwargs):
|
|
cluster_template_ident = args[1]
|
|
patch = args[2]
|
|
cluster_template = api_utils.get_resource('ClusterTemplate',
|
|
cluster_template_ident)
|
|
try:
|
|
cluster_template_dict = api_utils.apply_jsonpatch(
|
|
cluster_template.as_dict(), patch)
|
|
except api_utils.JSONPATCH_EXCEPTIONS as e:
|
|
raise exception.PatchError(patch=patch, reason=e)
|
|
cluster_template = objects.ClusterTemplate(pecan.request.context,
|
|
**cluster_template_dict)
|
|
_enforce_network_driver_types(cluster_template)
|
|
return func(*args, **kwargs)
|
|
|
|
return wrapper
|
|
|
|
|
|
def _enforce_network_driver_types(cluster_template):
|
|
validator = Validator.get_coe_validator(cluster_template.coe)
|
|
if not cluster_template.network_driver:
|
|
cluster_template.network_driver = validator.default_network_driver
|
|
validator.validate_network_driver(cluster_template.network_driver)
|
|
|
|
|
|
def enforce_server_type():
|
|
@decorator.decorator
|
|
def wrapper(func, *args, **kwargs):
|
|
cluster_template = args[1]
|
|
_enforce_server_type(cluster_template)
|
|
return func(*args, **kwargs)
|
|
|
|
return wrapper
|
|
|
|
|
|
def _enforce_server_type(cluster_template):
|
|
validator = Validator.get_coe_validator(cluster_template.coe)
|
|
validator.validate_server_type(cluster_template.server_type)
|
|
|
|
|
|
def enforce_volume_driver_types_create():
|
|
@decorator.decorator
|
|
def wrapper(func, *args, **kwargs):
|
|
cluster_template = args[1]
|
|
_enforce_volume_driver_types(cluster_template.as_dict())
|
|
return func(*args, **kwargs)
|
|
|
|
return wrapper
|
|
|
|
|
|
def enforce_volume_storage_size_create():
|
|
@decorator.decorator
|
|
def wrapper(func, *args, **kwargs):
|
|
cluster_template = args[1]
|
|
_enforce_volume_storage_size(cluster_template.as_dict(), {})
|
|
return func(*args, **kwargs)
|
|
|
|
return wrapper
|
|
|
|
|
|
def enforce_volume_driver_types_update():
|
|
@decorator.decorator
|
|
def wrapper(func, *args, **kwargs):
|
|
cluster_template_ident = args[1]
|
|
patch = args[2]
|
|
cluster_template = api_utils.get_resource('ClusterTemplate',
|
|
cluster_template_ident)
|
|
try:
|
|
cluster_template_dict = api_utils.apply_jsonpatch(
|
|
cluster_template.as_dict(), patch)
|
|
except api_utils.JSONPATCH_EXCEPTIONS as e:
|
|
raise exception.PatchError(patch=patch, reason=e)
|
|
_enforce_volume_driver_types(cluster_template_dict)
|
|
return func(*args, **kwargs)
|
|
|
|
return wrapper
|
|
|
|
|
|
def _enforce_volume_driver_types(cluster_template):
|
|
validator = Validator.get_coe_validator(cluster_template['coe'])
|
|
if not cluster_template.get('volume_driver'):
|
|
return
|
|
validator.validate_volume_driver(cluster_template['volume_driver'])
|
|
|
|
|
|
def _enforce_volume_storage_size(cluster_template, cluster):
|
|
volume_size = cluster.get('docker_volume_size') \
|
|
or cluster_template.get('docker_volume_size')
|
|
storage_driver = cluster_template.get('docker_storage_driver')
|
|
|
|
if storage_driver == 'devicemapper':
|
|
if not volume_size or volume_size < 3:
|
|
raise exception.InvalidParameterValue(
|
|
'docker volume size %s GB is not valid, '
|
|
'expecting minimum value 3GB for %s storage '
|
|
'driver.' % (volume_size, storage_driver))
|
|
|
|
|
|
def validate_cluster_properties(delta):
|
|
|
|
update_disallowed_properties = delta - cluster_update_allowed_properties
|
|
if update_disallowed_properties:
|
|
err = (_("cannot change cluster property(ies) %s.") %
|
|
", ".join(update_disallowed_properties))
|
|
raise exception.InvalidParameterValue(err=err)
|
|
|
|
|
|
def validate_federation_properties(delta):
|
|
|
|
update_disallowed_properties = delta - federation_update_allowed_properties
|
|
if update_disallowed_properties:
|
|
err = (_("cannot change federation property(ies) %s.") %
|
|
", ".join(update_disallowed_properties))
|
|
raise exception.InvalidParameterValue(err=err)
|
|
|
|
|
|
class Validator(object):
|
|
|
|
@classmethod
|
|
def get_coe_validator(cls, coe):
|
|
if coe == 'kubernetes':
|
|
return K8sValidator()
|
|
elif coe == 'swarm' or coe == 'swarm-mode':
|
|
return SwarmValidator()
|
|
elif coe == 'mesos':
|
|
return MesosValidator()
|
|
else:
|
|
raise exception.InvalidParameterValue(
|
|
_('Requested COE type %s is not supported.') % coe)
|
|
|
|
@classmethod
|
|
def validate_network_driver(cls, driver):
|
|
cls._validate_network_driver_supported(driver)
|
|
cls._validate_network_driver_allowed(driver)
|
|
|
|
@classmethod
|
|
def _validate_network_driver_supported(cls, driver):
|
|
"""Confirm that driver is supported by Magnum for this COE."""
|
|
if driver not in cls.supported_network_drivers:
|
|
raise exception.InvalidParameterValue(_(
|
|
'Network driver type %(driver)s is not supported, '
|
|
'expecting a %(supported_drivers)s network driver.') % {
|
|
'driver': driver,
|
|
'supported_drivers': '/'.join(
|
|
cls.supported_network_drivers + ['unspecified'])})
|
|
|
|
@classmethod
|
|
def _validate_network_driver_allowed(cls, driver):
|
|
"""Confirm that driver is allowed via configuration for this COE."""
|
|
if ('all' not in cls.allowed_network_drivers and
|
|
driver not in cls.allowed_network_drivers):
|
|
raise exception.InvalidParameterValue(_(
|
|
'Network driver type %(driver)s is not allowed, '
|
|
'expecting a %(allowed_drivers)s network driver. ') % {
|
|
'driver': driver,
|
|
'allowed_drivers': '/'.join(
|
|
cls.allowed_network_drivers + ['unspecified'])})
|
|
|
|
@classmethod
|
|
def validate_volume_driver(cls, driver):
|
|
cls._validate_volume_driver_supported(driver)
|
|
|
|
@classmethod
|
|
def _validate_volume_driver_supported(cls, driver):
|
|
"""Confirm that volume driver is supported by Magnum for this COE."""
|
|
if driver not in cls.supported_volume_driver:
|
|
raise exception.InvalidParameterValue(_(
|
|
'Volume driver type %(driver)s is not supported, '
|
|
'expecting a %(supported_volume_driver)s volume driver.') % {
|
|
'driver': driver,
|
|
'supported_volume_driver': '/'.join(
|
|
cls.supported_volume_driver + ['unspecified'])})
|
|
|
|
@classmethod
|
|
def validate_server_type(cls, server_type):
|
|
cls._validate_server_type(server_type)
|
|
|
|
@classmethod
|
|
def _validate_server_type(cls, server_type):
|
|
"""Confirm that server type is supported by Magnum for this COE."""
|
|
if server_type not in cls.supported_server_types:
|
|
raise exception.InvalidParameterValue(_(
|
|
'Server type %(server_type)s is not supported, '
|
|
'expecting a %(supported_server_types)s server type.') % {
|
|
'server_type': server_type,
|
|
'supported_server_types': '/'.join(
|
|
cls.supported_server_types + ['unspecified'])})
|
|
|
|
|
|
class K8sValidator(Validator):
|
|
|
|
supported_network_drivers = ['flannel', 'calico']
|
|
supported_server_types = ['vm', 'bm']
|
|
allowed_network_drivers = (
|
|
CONF.cluster_template.kubernetes_allowed_network_drivers)
|
|
default_network_driver = (
|
|
CONF.cluster_template.kubernetes_default_network_driver)
|
|
|
|
supported_volume_driver = ['cinder']
|
|
|
|
|
|
class SwarmValidator(Validator):
|
|
|
|
supported_network_drivers = ['docker', 'flannel']
|
|
supported_server_types = ['vm', 'bm']
|
|
allowed_network_drivers = (CONF.cluster_template.
|
|
swarm_allowed_network_drivers)
|
|
default_network_driver = (CONF.cluster_template.
|
|
swarm_default_network_driver)
|
|
|
|
supported_volume_driver = ['rexray']
|
|
|
|
|
|
class MesosValidator(Validator):
|
|
|
|
supported_network_drivers = ['docker']
|
|
supported_server_types = ['vm', 'bm']
|
|
allowed_network_drivers = (CONF.cluster_template.
|
|
mesos_allowed_network_drivers)
|
|
default_network_driver = (CONF.cluster_template.
|
|
mesos_default_network_driver)
|
|
|
|
supported_volume_driver = ['rexray']
|