summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMike Gerdts <mike.gerdts@joyent.com>2018-04-20 20:30:44 -0400
committerScott Moser <smoser@brickies.net>2018-04-20 20:30:44 -0400
commit8e111502a0f9d437ff6045f1269c95e5756fc43b (patch)
treea36d599593f7df10c2bad069ed5f2ddab43866a6
parent5037252ca5dc54c6d978b23dba063ac5fabc98fa (diff)
downloadvyos-cloud-init-8e111502a0f9d437ff6045f1269c95e5756fc43b.tar.gz
vyos-cloud-init-8e111502a0f9d437ff6045f1269c95e5756fc43b.zip
DataSourceSmartOS: list() should always return a list
If customer_metadata has no keys, the KEYS request returns an empty string. Callers of the list() method expect a list to be returned and will give a stack trace if this expectation is not met. LP: #1763480
-rw-r--r--cloudinit/sources/DataSourceSmartOS.py6
-rw-r--r--tests/unittests/test_datasource/test_smartos.py26
2 files changed, 27 insertions, 5 deletions
diff --git a/cloudinit/sources/DataSourceSmartOS.py b/cloudinit/sources/DataSourceSmartOS.py
index c8998b40..d4386fec 100644
--- a/cloudinit/sources/DataSourceSmartOS.py
+++ b/cloudinit/sources/DataSourceSmartOS.py
@@ -455,9 +455,9 @@ class JoyentMetadataClient(object):
def list(self):
result = self.request(rtype='KEYS')
- if result:
- result = result.split('\n')
- return result
+ if not result:
+ return []
+ return result.split('\n')
def put(self, key, val):
param = b' '.join([base64.b64encode(i.encode())
diff --git a/tests/unittests/test_datasource/test_smartos.py b/tests/unittests/test_datasource/test_smartos.py
index 2bea7a17..6fd431f9 100644
--- a/tests/unittests/test_datasource/test_smartos.py
+++ b/tests/unittests/test_datasource/test_smartos.py
@@ -319,6 +319,12 @@ MOCK_RETURNS = {
DMI_DATA_RETURN = 'smartdc'
+# Useful for calculating the length of a frame body. A SUCCESS body will be
+# followed by more characters or be one character less if SUCCESS with no
+# payload. See Section 4.3 of https://eng.joyent.com/mdata/protocol.html.
+SUCCESS_LEN = len('0123abcd SUCCESS ')
+NOTFOUND_LEN = len('0123abcd NOTFOUND')
+
class PsuedoJoyentClient(object):
def __init__(self, data=None):
@@ -651,7 +657,7 @@ class TestJoyentMetadataClient(FilesystemMockingTestCase):
self.response_parts = {
'command': 'SUCCESS',
'crc': 'b5a9ff00',
- 'length': 17 + len(b64e(self.metadata_value)),
+ 'length': SUCCESS_LEN + len(b64e(self.metadata_value)),
'payload': b64e(self.metadata_value),
'request_id': '{0:08x}'.format(self.request_id),
}
@@ -787,7 +793,7 @@ class TestJoyentMetadataClient(FilesystemMockingTestCase):
def test_get_metadata_returns_None_if_value_not_found(self):
self.response_parts['payload'] = ''
self.response_parts['command'] = 'NOTFOUND'
- self.response_parts['length'] = 17
+ self.response_parts['length'] = NOTFOUND_LEN
client = self._get_client()
client._checksum = lambda _: self.response_parts['crc']
self.assertIsNone(client.get('some_key'))
@@ -838,6 +844,22 @@ class TestJoyentMetadataClient(FilesystemMockingTestCase):
client.open_transport()
self.assertTrue(reader.emptied)
+ def test_list_metadata_returns_list(self):
+ parts = ['foo', 'bar']
+ value = b64e('\n'.join(parts))
+ self.response_parts['payload'] = value
+ self.response_parts['crc'] = '40873553'
+ self.response_parts['length'] = SUCCESS_LEN + len(value)
+ client = self._get_client()
+ self.assertEqual(client.list(), parts)
+
+ def test_list_metadata_returns_empty_list_if_no_customer_metadata(self):
+ del self.response_parts['payload']
+ self.response_parts['length'] = SUCCESS_LEN - 1
+ self.response_parts['crc'] = '14e563ba'
+ client = self._get_client()
+ self.assertEqual(client.list(), [])
+
class TestNetworkConversion(TestCase):
def test_convert_simple(self):