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:
Pradeep Kumar Singh 2016-12-19 04:56:55 +00:00
parent 2fd682e2a6
commit c9c8a6a178
2 changed files with 94 additions and 4 deletions

View File

@ -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()

View File

@ -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())