Store external ports in Server data

We need to store info about all ports of server, so
add storing external ports in data. It will be useful
for rollback and replace.

Change-Id: I931315995fae05ded7b2593c69aca7d51ce490c4
implements bp rich-network-prop
This commit is contained in:
Sergey Kraynev 2015-09-16 09:59:52 -04:00 committed by Peter Razumovsky
parent 89548bb1d4
commit 54c26453a0
4 changed files with 109 additions and 9 deletions

View File

@ -115,6 +115,7 @@ class CloudServersTest(common.HeatTestCase):
server = cloud_server.CloudServer(server_name,
resource_defns['WebServer'],
stack)
self.patchobject(server, 'store_external_ports')
self._stub_server_validate(server, image_id or 'CentOS 5.2', 1)
if stub_create:
@ -322,6 +323,7 @@ class CloudServersTest(common.HeatTestCase):
resource_defns = tmpl.resource_definitions(stack)
server = cloud_server.CloudServer('WebServer',
resource_defns['WebServer'], stack)
self.patchobject(server, 'store_external_ports')
class Interface(object):
def __init__(self, id, addresses):
@ -453,6 +455,7 @@ class CloudServersTest(common.HeatTestCase):
resource_defns = tmpl.resource_definitions(stack)
server = cloud_server.CloudServer('WebServer',
resource_defns['WebServer'], stack)
self.patchobject(server, 'store_external_ports')
mock_servers_create = mock.Mock(return_value=return_server)
self.fc.servers.create = mock_servers_create
image_id = mock.ANY

View File

@ -755,7 +755,10 @@ class Server(stack_user.StackUser, sh.SchedulerHintsMixin,
return server.id
def check_create_complete(self, server_id):
return self.client_plugin()._check_active(server_id)
check = self.client_plugin()._check_active(server_id)
if check:
self.store_external_ports()
return check
def handle_check(self):
server = self.client().servers.get(self.resource_id)
@ -1084,7 +1087,10 @@ class Server(stack_user.StackUser, sh.SchedulerHintsMixin,
prg.complete = check_complete(*prg.checker_args,
**prg.checker_kwargs)
break
return all(prg.complete for prg in updaters)
status = all(prg.complete for prg in updaters)
if status:
self.store_external_ports()
return status
def metadata_update(self, new_metadata=None):
'''
@ -1276,8 +1282,9 @@ class Server(stack_user.StackUser, sh.SchedulerHintsMixin,
self._delete_temp_url()
self._delete_queue()
if self.data().get('internal_ports'):
self._delete_internal_ports()
# remove internal and external ports
self._delete_internal_ports()
self.data_delete('external_ports')
try:
self.client().servers.delete(self.resource_id)

View File

@ -120,6 +120,7 @@ class ServerNetworkMixin(object):
return port['id']
def _delete_internal_port(self, port_id):
"""Delete physical port by id."""
try:
self.client('neutron').delete_port(port_id)
except Exception as ex:
@ -133,8 +134,8 @@ class ServerNetworkMixin(object):
self.data_delete('internal_ports')
def _data_update_ports(self, port_id, action):
data = self._data_get_ports()
def _data_update_ports(self, port_id, action, port_type='internal_ports'):
data = self._data_get_ports(port_type)
if action == 'add':
data.append({'id': port_id})
@ -144,12 +145,39 @@ class ServerNetworkMixin(object):
data.remove(port)
break
self.data_set('internal_ports', jsonutils.dumps(data))
self.data_set(port_type, jsonutils.dumps(data))
def _data_get_ports(self):
data = self.data().get('internal_ports')
def _data_get_ports(self, port_type='internal_ports'):
data = self.data().get(port_type)
return jsonutils.loads(data) if data else []
def store_external_ports(self):
"""Store in resource's data IDs of ports created by nova for server.
If no port property is specified and no internal port has been created,
nova client takes no port-id and calls port creating into server
creating. We need to store information about that ports, so store
their IDs to data with key `external_ports`.
"""
server = self.client().servers.get(self.resource_id)
ifaces = server.interface_list()
external_port_ids = set(iface.port_id for iface in ifaces)
# need to make sure external_ports data doesn't store ids of non-exist
# ports. Delete such port_id if it's needed.
data_external_port_ids = set(
port['id'] for port in self._data_get_ports('external_ports'))
for port_id in data_external_port_ids - external_port_ids:
self._data_update_ports(port_id, 'delete',
port_type='external_ports')
internal_port_ids = set(port['id'] for port in self._data_get_ports())
# add ids of new external ports which not contains in external_ports
# data yet. Also, exclude ids of internal ports.
new_ports = ((external_port_ids - internal_port_ids) -
data_external_port_ids)
for port_id in new_ports:
self._data_update_ports(port_id, 'add', port_type='external_ports')
def _build_nics(self, networks):
if not networks:
return None

View File

@ -150,6 +150,7 @@ class ServersTest(common.HeatTestCase):
res = self.stack['WebServer']
res.client = mock.Mock()
res.client().servers.get.return_value = server
self.patchobject(res, 'store_external_ports')
return res
def test_check(self):
@ -197,6 +198,8 @@ class ServersTest(common.HeatTestCase):
server = servers.Server(str(name), resource_defns['WebServer'],
self.stack)
self.patchobject(server, 'store_external_ports')
self._mock_get_image_id_success(image_id or 'CentOS 5.2', 1)
self.m.StubOutWithMock(nova.NovaClientPlugin, '_create')
@ -351,6 +354,7 @@ class ServersTest(common.HeatTestCase):
resource_defns = tmpl.resource_definitions(stack)
server = servers.Server('create_metadata_test_server',
resource_defns['WebServer'], stack)
self.patchobject(server, 'store_external_ports')
instance_meta = {'a': "1"}
image_id = mox.IgnoreArg()
@ -558,6 +562,7 @@ class ServersTest(common.HeatTestCase):
resource_defns = tmpl.resource_definitions(stack)
server = servers.Server('WebServer',
resource_defns['WebServer'], stack)
self.patchobject(server, 'store_external_ports')
self.m.StubOutWithMock(nova.NovaClientPlugin, '_create')
nova.NovaClientPlugin._create().AndReturn(self.fc)
@ -592,6 +597,7 @@ class ServersTest(common.HeatTestCase):
resource_defns = tmpl.resource_definitions(stack)
server = servers.Server('WebServer',
resource_defns['WebServer'], stack)
self.patchobject(server, 'store_external_ports')
self.rpc_client = mock.MagicMock()
server._rpc_client = self.rpc_client
@ -632,6 +638,7 @@ class ServersTest(common.HeatTestCase):
resource_defns = tmpl.resource_definitions(stack)
server = servers.Server('WebServer',
resource_defns['WebServer'], stack)
self.patchobject(server, 'store_external_ports')
self.rpc_client = mock.MagicMock()
server._rpc_client = self.rpc_client
@ -674,6 +681,7 @@ class ServersTest(common.HeatTestCase):
resource_defns = tmpl.resource_definitions(stack)
server = servers.Server('WebServer',
resource_defns['WebServer'], stack)
self.patchobject(server, 'store_external_ports')
self.m.StubOutWithMock(nova.NovaClientPlugin, '_create')
self.m.StubOutWithMock(server, 'heat')
@ -758,6 +766,7 @@ class ServersTest(common.HeatTestCase):
resource_defns = tmpl.resource_definitions(stack)
server = servers.Server('WebServer',
resource_defns['WebServer'], stack)
self.patchobject(server, 'store_external_ports')
self.m.StubOutWithMock(nova.NovaClientPlugin, '_create')
@ -837,6 +846,7 @@ class ServersTest(common.HeatTestCase):
resource_defns = tmpl.resource_definitions(stack)
server = servers.Server('WebServer',
resource_defns['WebServer'], stack)
self.patchobject(server, 'store_external_ports')
self.m.StubOutWithMock(nova.NovaClientPlugin, '_create')
self.m.StubOutWithMock(swift.SwiftClientPlugin, '_create')
@ -930,6 +940,7 @@ class ServersTest(common.HeatTestCase):
resource_defns = tmpl.resource_definitions(stack)
server = servers.Server('WebServer',
resource_defns['WebServer'], stack)
self.patchobject(server, 'store_external_ports')
ncp = self.patchobject(nova.NovaClientPlugin, '_create')
zcc = self.patchobject(zaqar.ZaqarClientPlugin, 'create_for_tenant')
@ -1017,6 +1028,7 @@ class ServersTest(common.HeatTestCase):
resource_defns = tmpl.resource_definitions(stack)
server = servers.Server('WebServer',
resource_defns['WebServer'], stack)
self.patchobject(server, 'store_external_ports')
mock_client.return_value = self.fc
self.fc.servers.create = mock.Mock(return_value=return_server)
@ -1044,6 +1056,7 @@ class ServersTest(common.HeatTestCase):
resource_defns = tmpl.resource_definitions(stack)
server = servers.Server('WebServer',
resource_defns['WebServer'], stack)
self.patchobject(server, 'store_external_ports')
mock_client.return_value = self.fc
self.fc.servers.create = mock.Mock(return_value=return_server)
@ -1073,6 +1086,7 @@ class ServersTest(common.HeatTestCase):
resource_defns = t.resource_definitions(stack)
server = servers.Server(server_name,
resource_defns['WebServer'], stack)
self.patchobject(server, 'store_external_ports')
# server.uuid is only available once the resource has been added.
stack.add_resource(server)
@ -3642,6 +3656,8 @@ class ServersTest(common.HeatTestCase):
self.m.StubOutWithMock(nova.NovaClientPlugin, '_create')
nova.NovaClientPlugin._create().MultipleTimes().AndReturn(self.fc)
self.patchobject(stack['server'], 'store_external_ports')
return_server = self.fc.servers.list()[1]
return_server.id = '1234'
@ -3702,6 +3718,8 @@ class ServersTest(common.HeatTestCase):
utils.dummy_context(), 'snapshot_policy', tmpl)
stack.store()
self.patchobject(stack['WebServer'], 'store_external_ports')
mock_plugin = self.patchobject(nova.NovaClientPlugin, '_create')
mock_plugin.return_value = self.fc
@ -3745,6 +3763,8 @@ class ServersTest(common.HeatTestCase):
utils.dummy_context(), 'snapshot_policy', tmpl)
stack.store()
self.patchobject(stack['WebServer'], 'store_external_ports')
mock_plugin = self.patchobject(nova.NovaClientPlugin, '_create')
mock_plugin.return_value = self.fc
@ -4101,3 +4121,45 @@ class ServerInternalPortTest(common.HeatTestCase):
server._data = {"internal_ports": ''}
data = server._data_get_ports()
self.assertEqual([], data)
def test_store_external_ports(self):
tmpl = """
heat_template_version: 2015-10-15
resources:
server:
type: OS::Nova::Server
properties:
flavor: m1.small
image: F17-x86_64-gold
networks:
- network: 4321
"""
t, stack, server = self._return_template_stack_and_rsrc_defn('test',
tmpl)
class Fake(object):
def interface_list(self):
return [iface('1122'),
iface('1122'),
iface('2233'),
iface('3344')]
server.client = mock.Mock()
server.client().servers.get.return_value = Fake()
server._data = {"internal_ports": '[{"id": "1122"}]',
"external_ports": '[{"id": "3344"},{"id": "5566"}]'}
iface = collections.namedtuple('iface', ['port_id'])
update_data = self.patchobject(server, '_data_update_ports')
server.store_external_ports()
self.assertEqual(2, update_data.call_count)
self.assertEqual(('5566', 'delete',),
update_data.call_args_list[0][0])
self.assertEqual({'port_type': 'external_ports'},
update_data.call_args_list[0][1])
self.assertEqual(('2233', 'add',),
update_data.call_args_list[1][0])
self.assertEqual({'port_type': 'external_ports'},
update_data.call_args_list[1][1])