Merge "Raise an SDKException/Error on duplicate hostnames"

This commit is contained in:
Zuul 2019-01-17 12:53:02 +00:00 committed by Gerrit Code Review
commit 4c7a9cb886
2 changed files with 85 additions and 6 deletions

View File

@ -16,6 +16,7 @@
import contextlib
import re
from openstack import exceptions as sdk_exc
import six
from metalsmith import exceptions
@ -100,6 +101,12 @@ def parse_checksums(checksums):
return result
# NOTE(dtantsur): make this private since it will no longer be possible with
# transition to allocation API.
class DuplicateHostname(sdk_exc.SDKException, exceptions.Error):
pass
class GetNodeMixin(object):
"""A helper mixin for getting nodes with hostnames."""
@ -123,11 +130,10 @@ class GetNodeMixin(object):
existing = [n for n in nodes
if n.instance_info.get(self.HOSTNAME_FIELD) == hostname]
if len(existing) > 1:
raise RuntimeError("More than one node found with hostname "
"%(host)s: %(nodes)s" %
{'host': hostname,
'nodes': ', '.join(log_res(n)
for n in existing)})
raise DuplicateHostname(
"More than one node found with hostname %(host)s: %(nodes)s" %
{'host': hostname,
'nodes': ', '.join(log_res(n) for n in existing)})
elif not existing:
return None
else:
@ -150,7 +156,7 @@ class GetNodeMixin(object):
node = node
if refresh:
return self.connection.baremetal.get_node(node)
return self.connection.baremetal.get_node(node.id)
else:
return node

View File

@ -13,9 +13,11 @@
# See the License for the specific language governing permissions and
# limitations under the License.
import mock
import testtools
from metalsmith import _utils
from metalsmith import exceptions
class TestIsHostnameSafe(testtools.TestCase):
@ -66,3 +68,74 @@ class TestIsHostnameSafe(testtools.TestCase):
# Need to ensure a binary response for success or fail
self.assertIsNotNone(_utils.is_hostname_safe('spam'))
self.assertIsNotNone(_utils.is_hostname_safe('-spam'))
class TestGetNodeMixin(testtools.TestCase):
def setUp(self):
super(TestGetNodeMixin, self).setUp()
self.mixin = _utils.GetNodeMixin()
self.mixin.connection = mock.Mock(spec=['baremetal'])
self.api = self.mixin.connection.baremetal
def test__get_node_with_node(self):
node = mock.Mock(spec=['id', 'name'])
result = self.mixin._get_node(node)
self.assertIs(result, node)
self.assertFalse(self.api.get_node.called)
def test__get_node_with_node_refresh(self):
node = mock.Mock(spec=['id', 'name'])
result = self.mixin._get_node(node, refresh=True)
self.assertIs(result, self.api.get_node.return_value)
self.api.get_node.assert_called_once_with(node.id)
def test__get_node_with_instance(self):
node = mock.Mock(spec=['uuid', 'node'])
result = self.mixin._get_node(node)
self.assertIs(result, node.node)
self.assertFalse(self.api.get_node.called)
def test__get_node_with_instance_refresh(self):
node = mock.Mock(spec=['uuid', 'node'])
result = self.mixin._get_node(node, refresh=True)
self.assertIs(result, self.api.get_node.return_value)
self.api.get_node.assert_called_once_with(node.node.id)
def test__get_node_with_string(self):
result = self.mixin._get_node('node')
self.assertIs(result, self.api.get_node.return_value)
self.api.get_node.assert_called_once_with('node')
def test__get_node_with_string_hostname_allowed(self):
nodes = [
mock.Mock(instance_info={'metalsmith_hostname': host})
for host in ['host1', 'host2', 'host3']
]
self.api.nodes.return_value = nodes
result = self.mixin._get_node('host2', accept_hostname=True)
self.assertIs(result, self.api.get_node.return_value)
self.api.get_node.assert_called_once_with(nodes[1].id)
def test__get_node_with_string_hostname_allowed_fallback(self):
nodes = [
mock.Mock(instance_info={'metalsmith_hostname': host})
for host in ['host1', 'host2', 'host3']
]
self.api.nodes.return_value = nodes
result = self.mixin._get_node('node', accept_hostname=True)
self.assertIs(result, self.api.get_node.return_value)
self.api.get_node.assert_called_once_with('node')
def test__get_node_with_string_hostname_not_unique(self):
nodes = [
mock.Mock(instance_info={'metalsmith_hostname': host})
for host in ['host1', 'host2', 'host2']
]
self.api.nodes.return_value = nodes
self.assertRaises(exceptions.Error,
self.mixin._get_node,
'host2', accept_hostname=True)
self.assertFalse(self.api.get_node.called)