Implement container unique name space for etcd driver
This patch implements https://review.openstack.org/#/c/394347/, for etcd driver. Change-Id: I85cdd16302ad8e333c468a1b07e0182fe5c7de4c
This commit is contained in:
parent
2fd682e2a6
commit
c9c8a6a178
@ -31,11 +31,12 @@ from zun.db.etcd import models
|
||||
|
||||
|
||||
LOG = log.getLogger(__name__)
|
||||
CONF = zun.conf.CONF
|
||||
|
||||
|
||||
def get_connection():
|
||||
connection = EtcdAPI(host=zun.conf.CONF.etcd.etcd_host,
|
||||
port=zun.conf.CONF.etcd.etcd_port)
|
||||
connection = EtcdAPI(host=CONF.etcd.etcd_host,
|
||||
port=CONF.etcd.etcd_port)
|
||||
return connection
|
||||
|
||||
|
||||
@ -159,13 +160,39 @@ class EtcdAPI(object):
|
||||
return self._process_list_result(filtered_containers,
|
||||
limit=limit, sort_key=sort_key)
|
||||
|
||||
def _validate_unique_container_name(self, context, name):
|
||||
if not CONF.compute.unique_container_name_scope:
|
||||
return
|
||||
lowername = name.lower()
|
||||
filters = {'name': name}
|
||||
if CONF.compute.unique_container_name_scope == 'project':
|
||||
filters['project_id'] = context.project_id
|
||||
elif CONF.compute.unique_container_name_scope == 'global':
|
||||
pass
|
||||
else:
|
||||
return
|
||||
|
||||
try:
|
||||
containers = self.list_container(context, filters=filters)
|
||||
except etcd.EtcdKeyNotFound:
|
||||
return
|
||||
except Exception as e:
|
||||
LOG.error(_LE('Error occurred while retrieving container: %s'),
|
||||
six.text_type(e))
|
||||
raise
|
||||
if len(containers) > 0:
|
||||
raise exception.ContainerAlreadyExists(field='name',
|
||||
value=lowername)
|
||||
|
||||
def create_container(self, context, container_data):
|
||||
# ensure defaults are present for new containers
|
||||
# TODO(pksingh): need to add validation for same container
|
||||
# name validation in project and global scope
|
||||
if not container_data.get('uuid'):
|
||||
container_data['uuid'] = uuidutils.generate_uuid()
|
||||
|
||||
if container_data.get('name'):
|
||||
self._validate_unique_container_name(context,
|
||||
container_data['name'])
|
||||
|
||||
container = models.Container(container_data)
|
||||
try:
|
||||
container.save()
|
||||
|
@ -23,6 +23,7 @@ import six
|
||||
from zun.common import exception
|
||||
import zun.conf
|
||||
from zun.db import api as dbapi
|
||||
from zun.db.etcd.api import EtcdAPI as etcd_api
|
||||
from zun.tests.unit.db import base
|
||||
from zun.tests.unit.db import utils
|
||||
|
||||
@ -254,6 +255,9 @@ class EtcdDbContainerTestCase(base.DbTestCase):
|
||||
@mock.patch.object(etcd_client, 'read')
|
||||
@mock.patch.object(etcd_client, 'write')
|
||||
def test_create_container_already_exists(self, mock_write, mock_read):
|
||||
CONF.set_override("unique_container_name_scope", "",
|
||||
group="compute",
|
||||
enforce_type=True)
|
||||
mock_read.side_effect = etcd.EtcdKeyNotFound
|
||||
utils.create_test_container(context=self.context)
|
||||
mock_read.side_effect = lambda *args: None
|
||||
@ -446,3 +450,62 @@ class EtcdDbContainerTestCase(base.DbTestCase):
|
||||
self.assertRaises(exception.InvalidParameterValue,
|
||||
dbapi.Connection.update_container, self.context,
|
||||
container.id, {'uuid': ''})
|
||||
|
||||
@mock.patch.object(etcd_client, 'read')
|
||||
@mock.patch.object(etcd_client, 'write')
|
||||
@mock.patch.object(etcd_api, 'list_container')
|
||||
def test_create_container_already_exists_in_project_name_space(
|
||||
self, mock_list_container, mock_write, mock_read):
|
||||
mock_read.side_effect = etcd.EtcdKeyNotFound
|
||||
mock_list_container.return_value = []
|
||||
CONF.set_override("unique_container_name_scope", "project",
|
||||
group="compute",
|
||||
enforce_type=True)
|
||||
container1 = utils.create_test_container(
|
||||
context=self.context, name='cont1')
|
||||
mock_list_container.return_value = [container1]
|
||||
with self.assertRaisesRegexp(exception.ContainerAlreadyExists,
|
||||
'A container with name.*'):
|
||||
utils.create_test_container(uuid=uuidutils.generate_uuid(),
|
||||
context=self.context,
|
||||
name='cont1')
|
||||
|
||||
@mock.patch.object(etcd_client, 'read')
|
||||
@mock.patch.object(etcd_client, 'write')
|
||||
@mock.patch.object(etcd_api, 'list_container')
|
||||
def test_create_container_already_exists_in_global_name_space(
|
||||
self, mock_list_container, mock_write, mock_read):
|
||||
mock_read.side_effect = etcd.EtcdKeyNotFound
|
||||
mock_list_container.return_value = []
|
||||
CONF.set_override("unique_container_name_scope", "global",
|
||||
group="compute",
|
||||
enforce_type=True)
|
||||
container1 = utils.create_test_container(
|
||||
context=self.context, name='cont1')
|
||||
self.context.project_id = 'fake_project_1'
|
||||
self.context.user_id = 'fake_user_1'
|
||||
mock_list_container.return_value = [container1]
|
||||
with self.assertRaisesRegexp(exception.ContainerAlreadyExists,
|
||||
'A container with name.*'):
|
||||
utils.create_test_container(uuid=uuidutils.generate_uuid(),
|
||||
context=self.context,
|
||||
name='cont1')
|
||||
|
||||
@mock.patch.object(etcd_client, 'read')
|
||||
@mock.patch.object(etcd_client, 'write')
|
||||
@mock.patch.object(etcd_api, 'list_container')
|
||||
def test_create_container_already_exists_in_default_name_space(
|
||||
self, mock_list_container, mock_write, mock_read):
|
||||
mock_read.side_effect = etcd.EtcdKeyNotFound
|
||||
mock_list_container.return_value = []
|
||||
CONF.set_override("unique_container_name_scope", "",
|
||||
group="compute",
|
||||
enforce_type=True)
|
||||
container1 = utils.create_test_container(
|
||||
context=self.context, name='cont1',
|
||||
uuid=uuidutils.generate_uuid())
|
||||
mock_list_container.return_value = [container1]
|
||||
self.context.project_id = 'fake_project_1'
|
||||
self.context.user_id = 'fake_user_1'
|
||||
utils.create_test_container(
|
||||
context=self.context, name='cont1', uuid=uuidutils.generate_uuid())
|
||||
|
Loading…
x
Reference in New Issue
Block a user