Fix improper EOL handling between the public keys

Every metadata service should return public keys as lists of
space-stripped strings without counting on the existence of
the current present (or not) new lines. The sshpublickeys plugin
will explicitly add EOLs between the keys, therefore having a
valid authorized_keys file when multiple ssh keys are retrieved.

Change-Id: Idad2b9d469a544066ab4090c30dd3f274e36844e
This commit is contained in:
Cosmin Poieana 2015-05-26 17:07:22 +03:00
parent 30bab776b2
commit a2d07e1478
9 changed files with 27 additions and 20 deletions

View File

@ -110,6 +110,7 @@ class BaseMetadataService(object):
pass
def get_public_keys(self):
"""Get a list of space-stripped strings as public keys."""
pass
def get_network_details(self):

View File

@ -65,7 +65,7 @@ class BaseOpenStackService(base.BaseMetadataService):
"""Get a list of all unique public keys found among the metadata."""
public_keys = []
meta_data = self._get_meta_data()
public_keys_dict = meta_data.get('public_keys')
public_keys_dict = meta_data.get("public_keys")
if public_keys_dict:
public_keys = list(public_keys_dict.values())
keys = meta_data.get("keys")
@ -73,7 +73,7 @@ class BaseOpenStackService(base.BaseMetadataService):
for key_dict in keys:
if key_dict["type"] == "ssh":
public_keys.append(key_dict["data"])
return list(set(public_keys))
return list(set((key.strip() for key in public_keys)))
def get_network_details(self):
network_config = self._get_meta_data().get('network_config')

View File

@ -97,6 +97,6 @@ class EC2Service(base.BaseMetadataService):
ssh_key = self._get_cache_data(
'%(version)s/meta-data/public-keys/%(idx)s/openssh-key' %
{'version': self._metadata_version, 'idx': idx})
ssh_keys.append(ssh_key)
ssh_keys.append(ssh_key.strip())
return ssh_keys

View File

@ -118,9 +118,8 @@ class MaaSHttpService(base.BaseMetadataService):
return [v + delimiter for v in text.split(delimiter)]
def get_public_keys(self):
return self._get_list_from_text(
self._get_cache_data('%s/meta-data/public-keys' %
self._metadata_version), "\n")
return self._get_cache_data('%s/meta-data/public-keys' %
self._metadata_version).splitlines()
def get_client_auth_certs(self):
return self._get_list_from_text(

View File

@ -195,7 +195,7 @@ class OpenNebulaService(base.BaseMetadataService):
return self._get_cache_data(USER_DATA)
def get_public_keys(self):
return [self._get_cache_data(PUBLIC_KEY)]
return self._get_cache_data(PUBLIC_KEY).splitlines()
def get_network_details(self):
"""Return a list of NetworkDetails objects.

View File

@ -52,6 +52,7 @@ class SetUserSSHPublicKeysPlugin(base.BasePlugin):
LOG.info("Writing SSH public keys in: %s" % authorized_keys_path)
with open(authorized_keys_path, 'w') as f:
for public_key in public_keys:
f.write(public_key)
# All public keys are space-stripped.
f.write(public_key + "\n")
return (base.PLUGIN_EXECUTION_DONE, False)

View File

@ -101,13 +101,18 @@ class TestBaseOpenStackService(unittest.TestCase):
mock_get_meta_data.return_value.get.side_effect = \
[self._fake_public_keys, self._fake_keys]
response = self._service.get_public_keys()
mock_get_meta_data.assert_called_once_with()
mock_get_meta_data.return_value.get.assert_any_call("public_keys")
mock_get_meta_data.return_value.get.assert_any_call("keys")
values = (list(self._fake_public_keys.values()) +
[key["data"] for key in self._fake_keys
if key["type"] == "ssh"])
self.assertEqual(sorted(list(set(values))), sorted(response))
public_keys = (list(self._fake_public_keys.values()) +
[key["data"] for key in self._fake_keys
if key["type"] == "ssh"])
public_keys = [key.strip() for key in public_keys]
self.assertEqual(sorted(list(set(public_keys))),
sorted(response))
@mock.patch(MODPATH +
".BaseOpenStackService._get_meta_data")

View File

@ -113,7 +113,7 @@ class EC2ServiceTest(unittest.TestCase):
@mock.patch('cloudbaseinit.metadata.services.ec2service.EC2Service'
'._get_cache_data')
def test_get_public_keys(self, mock_get_cache_data):
mock_get_cache_data.side_effect = ['key=info', 'fake key']
mock_get_cache_data.side_effect = ['key=info', 'fake key\n']
response = self._service.get_public_keys()
expected = [
mock.call('%s/meta-data/public-keys' %

View File

@ -163,18 +163,19 @@ class MaaSHttpServiceTest(unittest.TestCase):
response = self._maasservice._get_list_from_text('fake:text', ':')
self.assertEqual(['fake:', 'text:'], response)
@mock.patch("cloudbaseinit.metadata.services.maasservice.MaaSHttpService"
"._get_list_from_text")
@mock.patch("cloudbaseinit.metadata.services.maasservice.MaaSHttpService"
"._get_cache_data")
def test_get_public_keys(self, mock_get_cache_data,
mock_get_list_from_text):
def test_get_public_keys(self, mock_get_cache_data):
public_keys = [
"fake key 1",
"fake key 2"
]
public_key = "\n".join(public_keys) + "\n"
mock_get_cache_data.return_value = public_key
response = self._maasservice.get_public_keys()
mock_get_cache_data.assert_called_with(
'%s/meta-data/public-keys' % self._maasservice._metadata_version)
mock_get_list_from_text.assert_called_once_with(mock_get_cache_data(),
"\n")
self.assertEqual(mock_get_list_from_text.return_value, response)
self.assertEqual(public_keys, response)
@mock.patch("cloudbaseinit.metadata.services.maasservice.MaaSHttpService"
"._get_list_from_text")