diff --git a/mistral/actions/generator_factory.py b/mistral/actions/generator_factory.py index 765d298c7..5b04a95bf 100644 --- a/mistral/actions/generator_factory.py +++ b/mistral/actions/generator_factory.py @@ -19,7 +19,7 @@ from mistral.actions.openstack.action_generator import base SUPPORTED_MODULES = [ 'Nova', 'Glance', 'Keystone', 'Heat', 'Neutron', 'Cinder', 'Ceilometer', - 'Trove', 'Ironic', 'Baremetal Introspection' + 'Trove', 'Ironic', 'Baremetal Introspection', 'Swift' ] diff --git a/mistral/actions/openstack/actions.py b/mistral/actions/openstack/actions.py index 5cec4a83a..f592654b7 100644 --- a/mistral/actions/openstack/actions.py +++ b/mistral/actions/openstack/actions.py @@ -24,6 +24,7 @@ from neutronclient.v2_0 import client as neutronclient from novaclient import client as novaclient from oslo_config import cfg from oslo_log import log +from swiftclient import client as swift_client from troveclient import client as troveclient from mistral.actions.openstack import base @@ -308,3 +309,21 @@ class BaremetalIntrospectionAction(base.OpenStackAction): inspector_url=inspector_endpoint.url, auth_token=ctx.auth_token, ) + + +class SwiftAction(base.OpenStackAction): + _client_class = swift_client.Connection + + def _get_client(self): + ctx = context.ctx() + + LOG.debug("Swift action security context: %s" % ctx) + + swift_endpoint = keystone_utils.get_endpoint_for_project('swift') + + kwargs = { + 'preauthurl': swift_endpoint.url % {'tenant_id': ctx.project_id}, + 'preauthtoken': ctx.auth_token + } + + return self._client_class(**kwargs) diff --git a/mistral/actions/openstack/mapping.json b/mistral/actions/openstack/mapping.json index 57ac432ba..da0c64666 100644 --- a/mistral/actions/openstack/mapping.json +++ b/mistral/actions/openstack/mapping.json @@ -922,5 +922,20 @@ "rules_from_json": "rules.from_json", "rules_get": "rules.get", "rules_get_all": "rules.get_all" + }, + "swift": { + "_comment": "It uses swiftclient.v1.", + "head_account": "head_account", + "get_account": "get_account", + "post_account": "post_account", + "head_container": "head_container", + "get_container": "get_container", + "put_container": "put_container", + "post_container": "post_container", + "delete_container": "delete_container", + "get_object": "get_object", + "put_object": "put_object", + "post_object": "post_object", + "get_capabilities": "get_capabilities" } } diff --git a/mistral/tests/unit/actions/openstack/test_generator.py b/mistral/tests/unit/actions/openstack/test_generator.py index 83ac4deff..b4a80ab0e 100644 --- a/mistral/tests/unit/actions/openstack/test_generator.py +++ b/mistral/tests/unit/actions/openstack/test_generator.py @@ -28,9 +28,10 @@ MODULE_MAPPING = { 'ironic': ['ironic.node_list', actions.IronicAction], 'baremetal_introspection': ['baremetal_introspection.introspect', actions.BaremetalIntrospectionAction], + 'swift': ['swift.head_account', actions.SwiftAction], } -EXTRA_MODULES = ['neutron'] +EXTRA_MODULES = ['neutron', 'swift'] class GeneratorTest(base.BaseTest): diff --git a/mistral/tests/unit/actions/openstack/test_openstack_actions.py b/mistral/tests/unit/actions/openstack/test_openstack_actions.py index 38a05e2c7..2f7166d02 100644 --- a/mistral/tests/unit/actions/openstack/test_openstack_actions.py +++ b/mistral/tests/unit/actions/openstack/test_openstack_actions.py @@ -138,3 +138,16 @@ class OpenStackActionTest(base.BaseTestCase): self.assertTrue(mocked().get_status.called) mocked().get_status.assert_called_once_with(uuid="1234") + + @mock.patch.object(actions.SwiftAction, '_get_client') + def test_swift_action(self, mocked): + method_name = "get_object" + action_class = actions.SwiftAction + action_class.client_method_name = method_name + params = {'container': 'foo', 'object': 'bar'} + action = action_class(**params) + action.run() + + self.assertTrue(mocked().get_object.called) + mocked().get_object.assert_called_once_with(container='foo', + object='bar') diff --git a/requirements.txt b/requirements.txt index 0cb22bde9..bc4c9b5e1 100644 --- a/requirements.txt +++ b/requirements.txt @@ -28,6 +28,7 @@ python-heatclient>=0.6.0 python-keystoneclient!=1.8.0,>=1.6.0 python-neutronclient>=2.6.0 python-novaclient!=2.33.0,>=2.29.0 +python-swiftclient>=2.2.0 python-troveclient>=1.2.0 python-ironicclient>=0.8.0 python-ironic-inspector-client>=1.3.0 diff --git a/tools/get_action_list.py b/tools/get_action_list.py index 0ebdd876d..10f4077d4 100644 --- a/tools/get_action_list.py +++ b/tools/get_action_list.py @@ -38,6 +38,8 @@ from troveclient.v1 import client as troveclient # TODO(nmakhotkin): (e.g. keystone). # TODO(dprince): Need to update ironic_inspector_client before we can # plug it in cleanly here. +# TODO(dprince): Swiftclient doesn't currently support discovery +# like we do in this class. """It is simple CLI tool which allows to see and update mapping.json file if needed. mapping.json contains all allowing OpenStack actions sorted by @@ -161,6 +163,7 @@ CLIENTS = { 'ironic': get_ironic_client, # 'neutron': get_nova_client # 'baremetal_introspection': ... + # 'swift': ... } BASE_MANAGERS = { 'nova': BASE_NOVA_MANAGER, @@ -173,6 +176,7 @@ BASE_MANAGERS = { 'ironic': BASE_IRONIC_MANAGER, # 'neutron': BASE_NOVA_MANAGER # 'baremetal_introspection': ... + # 'swift': ... } NAMESPACES = { 'glance': GLANCE_NAMESPACE_LIST,