Only update necessary metadata
When issuing a metadata update, it is better to simply update the key/value pairs that we need to update rather than completely deleting and recreating the dictionary from scratch. It avoids problems such as when parts of the server metadata have been tagged as immutable by admins. Metadata keys that cannot be updated due to permissions are simply skipped over now. Change-Id: I6f928ce992d48e062ffd2017a665dc16641ac4b3
This commit is contained in:
parent
4764595ac7
commit
985b77a031
|
@ -10,6 +10,7 @@
|
|||
# License for the specific language governing permissions and limitations
|
||||
# under the License.
|
||||
|
||||
from openstack import exceptions as sdk_exc
|
||||
from oslo_config import cfg
|
||||
from oslo_log import log
|
||||
|
||||
|
@ -195,17 +196,26 @@ class NovaClient(base.DriverBase):
|
|||
res = self.conn.compute.get_server_metadata(server)
|
||||
return res.metadata
|
||||
|
||||
def _ignore_forbidden_call(self, func, *args, **kwargs):
|
||||
try:
|
||||
return func(*args, **kwargs)
|
||||
except sdk_exc.HttpException as exc:
|
||||
if exc.status_code != 403:
|
||||
raise
|
||||
|
||||
@sdk.translate_exception
|
||||
def server_metadata_update(self, server, metadata):
|
||||
# Clean all existing metadata first
|
||||
res = self.conn.compute.get_server_metadata(server)
|
||||
if res.metadata:
|
||||
self.conn.compute.delete_server_metadata(
|
||||
server, list(res.metadata.keys()))
|
||||
|
||||
# Then reset metadata to given value if it is not {}
|
||||
for key in res.metadata:
|
||||
self._ignore_forbidden_call(
|
||||
self.conn.compute.delete_server_metadata, server, [key])
|
||||
if metadata:
|
||||
return self.conn.compute.set_server_metadata(server, **metadata)
|
||||
for key, value in metadata.items():
|
||||
self._ignore_forbidden_call(
|
||||
self.conn.compute.set_server_metadata,
|
||||
server, **{key: value})
|
||||
|
||||
@sdk.translate_exception
|
||||
def server_metadata_delete(self, server, keys):
|
||||
|
|
|
@ -1496,7 +1496,7 @@ class ServerProfile(base.Profile):
|
|||
|
||||
driver = self.compute(obj)
|
||||
try:
|
||||
metadata = driver.server_metadata_get(obj.physical_id) or {}
|
||||
metadata = {}
|
||||
metadata['cluster_id'] = cluster_id
|
||||
metadata['cluster_node_index'] = six.text_type(obj.index)
|
||||
driver.server_metadata_update(obj.physical_id, metadata)
|
||||
|
|
|
@ -11,6 +11,7 @@
|
|||
# under the License.
|
||||
|
||||
import mock
|
||||
from openstack import exceptions as sdk_exc
|
||||
from oslo_config import cfg
|
||||
|
||||
from senlin.drivers.os import nova_v2
|
||||
|
@ -435,16 +436,42 @@ class TestNovaV2(base.SenlinTestCase):
|
|||
server = mock.Mock()
|
||||
res_server = mock.Mock()
|
||||
res_server.metadata = {
|
||||
'k1': 'v1'
|
||||
'k1': 'v1',
|
||||
'k2': 'v2'
|
||||
}
|
||||
self.compute.get_server_metadata.return_value = res_server
|
||||
|
||||
d = nova_v2.NovaClient(self.conn_params)
|
||||
d.server_metadata_update(server, {'k2': 'v2'})
|
||||
self.compute.delete_server_metadata.assert_called_once_with(
|
||||
server, ['k1'])
|
||||
self.compute.set_server_metadata.assert_called_once_with(
|
||||
server, k2='v2')
|
||||
d.server_metadata_update(server, {'k3': 'v3', 'k4': 'v4'})
|
||||
self.compute.set_server_metadata.assert_has_calls(
|
||||
[mock.call(server, k3='v3'), mock.call(server, k4='v4')],
|
||||
any_order=True)
|
||||
self.compute.delete_server_metadata.assert_has_calls(
|
||||
[mock.call(server, ['k1']), mock.call(server, ['k2'])],
|
||||
any_order=True)
|
||||
|
||||
def test_server_metadata_update_forbidden(self):
|
||||
server = mock.Mock()
|
||||
res_server = mock.Mock()
|
||||
res_server.metadata = {
|
||||
'k1': 'v1',
|
||||
'forbidden_key': 'forbidden_data',
|
||||
'k2': 'v2'
|
||||
}
|
||||
self.compute.get_server_metadata.return_value = res_server
|
||||
self.compute.delete_server_metadata.side_effect = [
|
||||
None, sdk_exc.HttpException(http_status=403), None]
|
||||
self.compute.set_server_metadata.side_effect = [
|
||||
None, sdk_exc.HttpException(http_status=403), None]
|
||||
|
||||
d = nova_v2.NovaClient(self.conn_params)
|
||||
d.server_metadata_update(server, {'k3': 'v3', 'k4': 'v4', 'k5': 'v5'})
|
||||
self.compute.set_server_metadata.assert_has_calls(
|
||||
[mock.call(server, k3='v3'), mock.call(server, k4='v4'),
|
||||
mock.call(server, k5='v5')], any_order=True)
|
||||
self.compute.delete_server_metadata.assert_has_calls(
|
||||
[mock.call(server, ['k1']), mock.call(server, ['forbidden_key']),
|
||||
mock.call(server, ['k2'])], any_order=True)
|
||||
|
||||
def test_server_metadata_delete(self):
|
||||
server = mock.Mock()
|
||||
|
|
Loading…
Reference in New Issue