diff --git a/openstack/resource.py b/openstack/resource.py index f3d776464..a6ab26d06 100644 --- a/openstack/resource.py +++ b/openstack/resource.py @@ -630,6 +630,22 @@ class Resource(dict): # remotes or "unknown" return self._attributes() + def items(self): + # This method is critically required for Ansible "jsonify" + # NOTE(gtema) For some reason when running from SDK itself the native + # implementation of the method is absolutely sifficient, when called + # from Ansible - the values are often empty. Even integrating all + # Ansible internal methods did not help to find the root cause. Another + # fact is that under Py2 everything is fine, while under Py3 it fails. + # There is currently no direct test for Ansible-SDK issue. It is tested + # implicitely in the keypair role for ansible module, where an assert + # verifies presence of attributes. + res = [] + for attr in self._attributes(): + # Append key, value tuple to result list + res.append((attr, self[attr])) + return res + def _update(self, **attrs): """Given attributes, update them on this instance diff --git a/openstack/tests/ansible/roles/keypair/tasks/main.yml b/openstack/tests/ansible/roles/keypair/tasks/main.yml index 53a856e2f..636bf1aca 100644 --- a/openstack/tests/ansible/roles/keypair/tasks/main.yml +++ b/openstack/tests/ansible/roles/keypair/tasks/main.yml @@ -4,6 +4,14 @@ cloud: "{{ cloud }}" name: "{{ keypair_name }}" state: present + register: + keypair + +# This assert verifies that Ansible is capable serializing data returned by SDK +- name: Ensure private key is returned + assert: + that: + - keypair.key.public_key is defined and keypair.key.public_key - name: Delete keypair (non-existing) os_keypair: diff --git a/openstack/tests/unit/test_resource.py b/openstack/tests/unit/test_resource.py index d51a2b560..d435a89ae 100644 --- a/openstack/tests/unit/test_resource.py +++ b/openstack/tests/unit/test_resource.py @@ -896,6 +896,24 @@ class TestResource(base.TestCase): actual = json.dumps(res, sort_keys=True) self.assertEqual(expected, actual) + def test_items(self): + class Test(resource.Resource): + foo = resource.Body('foo') + bar = resource.Body('bar') + foot = resource.Body('foot') + + data = { + 'foo': 'bar', + 'bar': 'foo\n', + 'foot': 'a:b:c:d' + } + + res = Test(**data) + for k, v in res.items(): + expected = data.get(k) + if expected: + self.assertEqual(v, expected) + def test_access_by_aka(self): class Test(resource.Resource): foo = resource.Header('foo_remote', aka='foo_alias') diff --git a/tox.ini b/tox.ini index aab8ea678..5322f1012 100644 --- a/tox.ini +++ b/tox.ini @@ -69,7 +69,7 @@ commands = [testenv:ansible] # Need to pass some env vars for the Ansible playbooks -basepython = {env:OPENSTACKSDK_TOX_PYTHON:python2} +basepython = {env:OPENSTACKSDK_TOX_PYTHON:python3} passenv = HOME USER ANSIBLE_VAR_* deps = {[testenv]deps}