diff --git a/cinderclient/tests/unit/v3/fakes.py b/cinderclient/tests/unit/v3/fakes.py index 9fd614abe..910633ef3 100644 --- a/cinderclient/tests/unit/v3/fakes.py +++ b/cinderclient/tests/unit/v3/fakes.py @@ -20,6 +20,42 @@ from cinderclient.tests.unit import fakes from cinderclient.tests.unit.v2 import fakes as fake_v2 +fake_attachment = {'attachment': { + 'status': 'reserved', + 'detached_at': '', + 'connection_info': {}, + 'attached_at': '', + 'attach_mode': None, + 'id': 'a232e9ae', + 'instance': 'e84fda45-4de4-4ce4-8f39-fc9d3b0aa05e', + 'volume_id': '557ad76c-ce54-40a3-9e91-c40d21665cc3', }} + +fake_connection_info = { + 'auth_password': 'i6h9E5HQqSkcGX3H', + 'attachment_id': 'a232e9ae', + 'target_discovered': False, + 'encrypted': False, + 'driver_volume_type': 'iscsi', + 'qos_specs': None, + 'target_iqn': 'iqn.2010-10.org.openstack:volume-557ad76c', + 'target_portal': '10.117.36.28:3260', + 'volume_id': '557ad76c-ce54-40a3-9e91-c40d21665cc3', + 'target_lun': 0, + 'access_mode': 'rw', + 'auth_username': 'MwRrnAFLHN7enw5R95yM', + 'auth_method': 'CHAP'} + +fake_connector = { + 'initiator': 'iqn.1993-08.org.debian:01:b79dbce99387', + 'mount_device': '/dev/vdb', + 'ip': '10.117.36.28', + 'platform': 'x86_64', + 'host': 'os-2', + 'do_local_attach': False, + 'os_type': 'linux2', + 'multipath': False} + + def _stub_group(detailed=True, **kwargs): group = { "name": "test-1", @@ -241,12 +277,9 @@ class FakeHTTPClient(fake_v2.FakeHTTPClient): # # Attachments # + def post_attachments(self, **kw): - return (202, {}, { - 'attachment': {'instance': 1234, - 'name': 'attachment-1', - 'volume_id': 'fake_volume_1', - 'status': 'reserved'}}) + return (200, {}, fake_attachment) def get_attachments(self, **kw): return (200, {}, { @@ -259,6 +292,16 @@ class FakeHTTPClient(fake_v2.FakeHTTPClient): 'volume_id': 'fake_volume_2', 'status': 'reserverd'}]}) + def post_attachments_a232e9ae_action(self, **kw): # noqa: E501 + attached_fake = fake_attachment + attached_fake['status'] = 'attached' + return (200, {}, attached_fake) + + def post_attachments_1234_action(self, **kw): # noqa: E501 + attached_fake = fake_attachment + attached_fake['status'] = 'attached' + return (200, {}, attached_fake) + def get_attachments_1234(self, **kw): return (200, {}, { 'attachment': {'instance': 1234, @@ -294,7 +337,7 @@ class FakeHTTPClient(fake_v2.FakeHTTPClient): return (200, {}, {'group_type': {'id': 1, 'name': 'test-type-1', 'description': 'test_type-1-desc', - 'group_specs': {u'key': u'value'}}}) + 'group_specs': {'key': 'value'}}}) def get_group_types_2(self, **kw): return (200, {}, {'group_type': {'id': 2, diff --git a/cinderclient/tests/unit/v3/test_attachments.py b/cinderclient/tests/unit/v3/test_attachments.py new file mode 100644 index 000000000..5fee5b4c4 --- /dev/null +++ b/cinderclient/tests/unit/v3/test_attachments.py @@ -0,0 +1,36 @@ +# Copyright (C) 2016 EMC Corporation. +# +# All Rights Reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); you may +# not use this file except in compliance with the License. You may obtain +# a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. + +from cinderclient.tests.unit import utils +from cinderclient.tests.unit.v3 import fakes + +cs = fakes.FakeClient() + + +class AttachmentsTest(utils.TestCase): + + def test_create_attachment(self): + att = cs.attachments.create( + 'e84fda45-4de4-4ce4-8f39-fc9d3b0aa05e', + {}, + '557ad76c-ce54-40a3-9e91-c40d21665cc3') + cs.assert_called('POST', '/attachments') + self.assertEqual(fakes.fake_attachment['attachment'], att) + + def test_complete_attachment(self): + att = cs.attachments.complete( + 'a232e9ae') + self.assertTrue(att.ok) diff --git a/cinderclient/tests/unit/v3/test_shell.py b/cinderclient/tests/unit/v3/test_shell.py index a7be695d4..ce24763dd 100644 --- a/cinderclient/tests/unit/v3/test_shell.py +++ b/cinderclient/tests/unit/v3/test_shell.py @@ -376,6 +376,12 @@ class ShellTest(utils.TestCase): self.assert_called('PUT', '/attachments/1234', body={'attachment': body}) + @ddt.unpack + def test_attachment_complete(self): + command = '--os-volume-api-version 3.44 attachment-complete 1234' + self.run_command(command) + self.assert_called('POST', '/attachments/1234/action', body=None) + def test_attachment_delete(self): self.run_command('--os-volume-api-version 3.27 ' 'attachment-delete 1234') diff --git a/cinderclient/v3/attachments.py b/cinderclient/v3/attachments.py index 614662684..aaa8bcf2f 100644 --- a/cinderclient/v3/attachments.py +++ b/cinderclient/v3/attachments.py @@ -12,6 +12,7 @@ """Attachment interface.""" +from cinderclient import api_versions from cinderclient import base @@ -64,9 +65,12 @@ class VolumeAttachmentManager(base.ManagerWithFind): """Attachment update.""" body = {'attachment': {'connector': connector}} resp = self._update('/attachments/%s' % id, body) + # NOTE(jdg): This kinda sucks, + # create returns a dict, but update returns an object :( return self.resource_class(self, resp['attachment'], loaded=True, resp=resp) + @api_versions.wraps('3.44') def complete(self, attachment): """Mark the attachment as completed.""" resp, body = self._action_return_resp_and_body('os-complete',