Support use of json for relation data

In order to provide consistent presentation of relation data
in Python 3 based charms, support passing of data using JSON
format which ensures that data on relations won't continually
change due to non-deterministic dictionary iteration in py3.

Change-Id: I364a60ca7b91327fe88ee729cf49ff8ab3f5e2b6
Closes-Bug: 1741304
This commit is contained in:
James Page 2018-01-04 18:01:28 +00:00
parent fe46216882
commit 22d30c2294
2 changed files with 41 additions and 3 deletions

View File

@ -17,6 +17,7 @@
import ast
import pcmk
import maas
import json
import os
import re
import subprocess
@ -457,10 +458,14 @@ def get_cluster_nodes():
def parse_data(relid, unit, key):
"""Simple helper to ast parse relation data"""
data = relation_get(key, unit, relid)
"""Helper to detect and parse json or ast based relation data"""
_key = 'json_{}'.format(key)
data = relation_get(_key, unit, relid) or relation_get(key, unit, relid)
if data:
return ast.literal_eval(data)
try:
return json.loads(data)
except (TypeError, ValueError):
return ast.literal_eval(data)
return {}

View File

@ -12,6 +12,7 @@
# See the License for the specific language governing permissions and
# limitations under the License.
import json
import mock
import os
import re
@ -408,3 +409,35 @@ class UtilsTestCase(unittest.TestCase):
mkdir.assert_called_once_with("/etc/maas_dns")
write_file.assert_called_once_with(
"/etc/maas_dns/res_keystone_public_hostname", content="172.16.0.1")
@mock.patch.object(utils, 'relation_get')
def test_parse_data_legacy(self, relation_get):
_rel_data = {
'testkey': repr({'test': 1})
}
relation_get.side_effect = lambda key, relid, unit: _rel_data.get(key)
self.assertEqual(utils.parse_data('hacluster:1',
'neutron-api/0',
'testkey'),
{'test': 1})
relation_get.assert_has_calls([
mock.call('json_testkey', 'neutron-api/0', 'hacluster:1'),
mock.call('testkey', 'neutron-api/0', 'hacluster:1'),
])
@mock.patch.object(utils, 'relation_get')
def test_parse_data_json(self, relation_get):
_rel_data = {
'json_testkey': json.dumps({'test': 1}),
'testkey': repr({'test': 1})
}
relation_get.side_effect = lambda key, relid, unit: _rel_data.get(key)
self.assertEqual(utils.parse_data('hacluster:1',
'neutron-api/0',
'testkey'),
{'test': 1})
# NOTE(jamespage): as json is the preferred format, the call for
# testkey should not occur.
relation_get.assert_has_calls([
mock.call('json_testkey', 'neutron-api/0', 'hacluster:1'),
])