Skip to content

Commit

Permalink
Fix exception in set-temp-url-secret action
Browse files Browse the repository at this point in the history
There are two issues fixed in this bug. The first is that the
keystone_session exception block does not return on failure. The
second, and the reason that create_keystone_session is failing,
is due to the use of setuptools 60.9.0+ with the
importlib-metadata in wheelhouse.txt that is pinned to <3.0.0.
For more details see: pypa/setuptools#3452

Closes-Bug: #2018018
Change-Id: I266c1fb92d531aded2f3253766de0a79accd9577
  • Loading branch information
Corey Bryant committed Apr 28, 2023
1 parent 298f5a1 commit 9f221f1
Show file tree
Hide file tree
Showing 5 changed files with 152 additions and 1 deletion.
1 change: 1 addition & 0 deletions src/actions/actions.py
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,7 @@ def set_temp_url_secret(*args):
except Exception as e:
ch_core.hookenv.action_fail('Failed to create keystone session ("{}")'
.format(e))
return

os_cli = api_utils.OSClients(keystone_session)
if os_cli.has_swift() is False:
Expand Down
3 changes: 2 additions & 1 deletion src/wheelhouse.txt
Original file line number Diff line number Diff line change
Expand Up @@ -21,8 +21,9 @@ cryptography
pyrsistent<0.18.0
iso8601<1.0.0

importlib-metadata<3.0.0
importlib-metadata==4.3.0
importlib-resources<3.0.0
setuptools<60.9.0

git+https://github.com/openstack/charms.openstack.git#egg=charms.openstack

Expand Down
4 changes: 4 additions & 0 deletions unit_tests/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,10 @@
sys.modules['charmhelpers.core.decorators'] = (
charms_openstack.test_mocks.charmhelpers.core.decorators)

global snap
snap = mock.MagicMock()
sys.modules['charms.layer'] = snap


class _fake_decorator(object):

Expand Down
46 changes: 46 additions & 0 deletions unit_tests/test_actions.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
import src.actions.actions as actions
import unit_tests.test_utils
import reactive.ironic_handlers as handlers
import charm.openstack.ironic.api_utils as api_utils
import charmhelpers.core as ch_core
import charms.leadership as leadership

import mock


class TestActions(unit_tests.test_utils.CharmTestCase):

def setUp(self):
super(TestActions, self).setUp()
self.patches = []
self.patch_all()
self.ironic_charm = mock.MagicMock()
self.patch_object(handlers.charm, 'provide_charm_instance',
new=mock.MagicMock())
self.provide_charm_instance().__enter__.return_value = \
self.ironic_charm
self.provide_charm_instance().__exit__.return_value = None

def test_set_temp_url_secret_keystone_session_successful(self):
self.patch_object(ch_core.hookenv, 'action_fail')
self.patch_object(leadership, 'leader_get')

actions.set_temp_url_secret()

self.leader_get.assert_called_with('temp_url_secret')

def test_set_temp_url_secret_keystone_session_exception(self):
self.patch_object(api_utils, 'create_keystone_session')
self.patch_object(ch_core.hookenv, 'action_fail')
self.patch_object(leadership, 'leader_get')

def raise_exception(*args):
raise Exception("doh!")

self.create_keystone_session.side_effect = raise_exception

actions.set_temp_url_secret()

self.action_fail.assert_called_with(
'Failed to create keystone session ("doh!")')
self.leader_get.assert_not_called()
99 changes: 99 additions & 0 deletions unit_tests/test_utils.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,99 @@
from unittest import mock
import unittest


class CharmTestCase(unittest.TestCase):

def setUp(self):
self._patches = {}
self._patches_start = {}

def tearDown(self):
for k, v in self._patches.items():
v.stop()
setattr(self, k, None)
self._patches = None
self._patches_start = None

def _patch(self, method):
_m = unittest.mock.patch.object(self.obj, method)
mock = _m.start()
self.addCleanup(_m.stop)
return mock

def patch_all(self):
for method in self.patches:
setattr(self, method, self._patch(method))

def patch_object(self, obj, attr, return_value=None, name=None, new=None,
**kwargs):
if name is None:
name = attr
if new is not None:
mocked = mock.patch.object(obj, attr, new=new, **kwargs)
else:
mocked = mock.patch.object(obj, attr, **kwargs)
self._patches[name] = mocked
started = mocked.start()
if new is None:
started.return_value = return_value
self._patches_start[name] = started
setattr(self, name, started)

def patch(self, item, return_value=None, name=None, new=None, **kwargs):
if name is None:
raise RuntimeError("Must pass 'name' to .patch()")
if new is not None:
mocked = mock.patch(item, new=new, **kwargs)
else:
mocked = mock.patch(item, **kwargs)
self._patches[name] = mocked
started = mocked.start()
if new is None:
started.return_value = return_value
self._patches_start[name] = started


class TestConfig(object):

def __init__(self):
self.config = {}
self.config_prev = {}

def __call__(self, key=None):
if key:
return self.get(key)
else:
return self

def previous(self, k):
return self.config_prev[k] if k in self.config_prev else self.config[k]

def set_previous(self, k, v):
self.config_prev[k] = v

def unset_previous(self, k):
if k in self.config_prev:
self.config_prev.pop(k)

def changed(self, k):
if not self.config_prev:
return True
return self.get(k) != self.previous(k)

def get(self, attr=None):
if not attr:
return self
try:
return self.config[attr]
except KeyError:
return None

def get_all(self):
return self.config

def set(self, attr, value):
self.config[attr] = value

def __getitem__(self, k):
return self.get(k)

0 comments on commit 9f221f1

Please sign in to comment.