diff --git a/cloudbaseinit/metadata/services/base.py b/cloudbaseinit/metadata/services/base.py index 8bf31e8c..8f80ec85 100644 --- a/cloudbaseinit/metadata/services/base.py +++ b/cloudbaseinit/metadata/services/base.py @@ -14,6 +14,7 @@ import abc +import copy import gzip import io import time @@ -221,6 +222,45 @@ class BaseMetadataService(object): def get_ephemeral_disk_data_loss_warning(self): raise NotExistingMetadataException() + def get_instance_data(self): + """Returns a dictionary with instance data from the metadata source + + The instance data structure is based on the cloud-init specifications: + https://cloudinit.readthedocs.io/en/latest/topics/instancedata.html + + The v1 namespace contains a subset of the cloud-init standard + for the instance data. In the future, it should reach parity with the + cloud-init standard. + + The ds.meta_data namespace contains all the values the v1 namespace + contains, in order to be compatible with cloud-init, plus a subset of + other instance data. + The ds namespace can change without prior notice and should not be + used in production. + """ + + instance_id = self.get_instance_id() + hostname = self.get_host_name() + + v1_data = { + "instance_id": instance_id, + "local_hostname": hostname, + "public_ssh_keys": self.get_public_keys() + } + + # Copy the v1 data to the ds.meta_data and add more fields + ds_meta_data = copy.deepcopy(v1_data) + ds_meta_data.update({ + "hostname": hostname + }) + + return { + "v1": v1_data, + "ds": { + "meta_data": ds_meta_data, + } + } + class BaseHTTPMetadataService(BaseMetadataService): diff --git a/cloudbaseinit/tests/metadata/services/test_base.py b/cloudbaseinit/tests/metadata/services/test_base.py index ad47e87b..d8c77653 100644 --- a/cloudbaseinit/tests/metadata/services/test_base.py +++ b/cloudbaseinit/tests/metadata/services/test_base.py @@ -61,6 +61,38 @@ class TestBase(unittest.TestCase): result = self._service.get_user_pwd_encryption_key() self.assertEqual(result, mock_get_public_keys.return_value[0]) + @mock.patch('cloudbaseinit.metadata.services.base.' + 'BaseMetadataService.get_public_keys') + @mock.patch('cloudbaseinit.metadata.services.base.' + 'BaseMetadataService.get_host_name') + @mock.patch('cloudbaseinit.metadata.services.base.' + 'BaseMetadataService.get_instance_id') + def test_get_instance_data(self, mock_instance_id, mock_hostname, + mock_public_keys): + fake_instance_id = 'id' + mock_instance_id.return_value = fake_instance_id + fake_hostname = 'host' + mock_hostname.return_value = fake_hostname + fake_keys = ['ssh1', 'ssh2'] + mock_public_keys.return_value = fake_keys + + expected_response = { + 'v1': { + "instance_id": fake_instance_id, + "local_hostname": fake_hostname, + "public_ssh_keys": fake_keys + }, + 'ds': { + 'meta_data': { + "instance_id": fake_instance_id, + "local_hostname": fake_hostname, + "public_ssh_keys": fake_keys, + "hostname": fake_hostname + }, + } + } + self.assertEqual(expected_response, self._service.get_instance_data()) + class TestBaseHTTPMetadataService(unittest.TestCase):