Add new volume commands: create, attach and detach
Change-Id: I2854e7f071108aa92e20bec9ca30ef9468aa383d
This commit is contained in:
		
							
								
								
									
										35
									
								
								almanachclient/commands/attach_volume.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										35
									
								
								almanachclient/commands/attach_volume.py
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,35 @@ | |||||||
|  | # Copyright 2017 INAP | ||||||
|  | # | ||||||
|  | # 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 dateutil import parser as date_parser | ||||||
|  |  | ||||||
|  | from cliff.command import Command | ||||||
|  |  | ||||||
|  |  | ||||||
|  | class AttachVolumeCommand(Command): | ||||||
|  |     """Attach volume""" | ||||||
|  |  | ||||||
|  |     def get_parser(self, prog_name): | ||||||
|  |         parser = super().get_parser(prog_name) | ||||||
|  |         parser.add_argument('volume_id', help='Volume ID') | ||||||
|  |         parser.add_argument('--date', help='Start date') | ||||||
|  |         parser.add_argument('--attachment', action='append', help='Instance attached to the volume') | ||||||
|  |         return parser | ||||||
|  |  | ||||||
|  |     def take_action(self, parsed_args): | ||||||
|  |         date = date_parser.parse(parsed_args.date) if parsed_args.date else None | ||||||
|  |         self.app.get_client().attach_volume(parsed_args.volume_id, | ||||||
|  |                                             attachments=parsed_args.attachment, | ||||||
|  |                                             attachment_date=date) | ||||||
|  |         return 'Success' | ||||||
							
								
								
									
										44
									
								
								almanachclient/commands/create_volume.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										44
									
								
								almanachclient/commands/create_volume.py
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,44 @@ | |||||||
|  | # Copyright 2017 INAP | ||||||
|  | # | ||||||
|  | # 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 dateutil import parser as date_parser | ||||||
|  |  | ||||||
|  | from cliff.command import Command | ||||||
|  |  | ||||||
|  |  | ||||||
|  | class CreateVolumeCommand(Command): | ||||||
|  |     """Create volume""" | ||||||
|  |  | ||||||
|  |     def get_parser(self, prog_name): | ||||||
|  |         parser = super().get_parser(prog_name) | ||||||
|  |         parser.add_argument('tenant_id', help='Tenant ID') | ||||||
|  |         parser.add_argument('volume_id', help='Volume ID') | ||||||
|  |         parser.add_argument('volume_type_id', help='Volume type ID') | ||||||
|  |         parser.add_argument('volume_name', help='Volume name') | ||||||
|  |         parser.add_argument('volume_size', help='Volume size') | ||||||
|  |         parser.add_argument('--start', help='Start date') | ||||||
|  |         parser.add_argument('--attachment', action='append', help='Instance attached to the volume') | ||||||
|  |         return parser | ||||||
|  |  | ||||||
|  |     def take_action(self, parsed_args): | ||||||
|  |         start_date = date_parser.parse(parsed_args.start) if parsed_args.start else None | ||||||
|  |  | ||||||
|  |         self.app.get_client().create_volume(parsed_args.tenant_id, | ||||||
|  |                                             parsed_args.volume_id, | ||||||
|  |                                             parsed_args.volume_type_id, | ||||||
|  |                                             parsed_args.volume_name, | ||||||
|  |                                             parsed_args.volume_size, | ||||||
|  |                                             attachments=parsed_args.attachment, | ||||||
|  |                                             start=start_date) | ||||||
|  |         return 'Success' | ||||||
							
								
								
									
										35
									
								
								almanachclient/commands/detach_volume.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										35
									
								
								almanachclient/commands/detach_volume.py
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,35 @@ | |||||||
|  | # Copyright 2017 INAP | ||||||
|  | # | ||||||
|  | # 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 dateutil import parser as date_parser | ||||||
|  |  | ||||||
|  | from cliff.command import Command | ||||||
|  |  | ||||||
|  |  | ||||||
|  | class DetachVolumeCommand(Command): | ||||||
|  |     """Detach volume""" | ||||||
|  |  | ||||||
|  |     def get_parser(self, prog_name): | ||||||
|  |         parser = super().get_parser(prog_name) | ||||||
|  |         parser.add_argument('volume_id', help='Volume ID') | ||||||
|  |         parser.add_argument('--date', help='Start date') | ||||||
|  |         parser.add_argument('--attachment', action='append', help='Instance attached to the volume') | ||||||
|  |         return parser | ||||||
|  |  | ||||||
|  |     def take_action(self, parsed_args): | ||||||
|  |         date = date_parser.parse(parsed_args.date) if parsed_args.date else None | ||||||
|  |         self.app.get_client().detach_volume(parsed_args.volume_id, | ||||||
|  |                                             attachments=parsed_args.attachment, | ||||||
|  |                                             attachment_date=date) | ||||||
|  |         return 'Success' | ||||||
| @@ -18,10 +18,13 @@ import sys | |||||||
| from cliff import app | from cliff import app | ||||||
| from cliff import commandmanager | from cliff import commandmanager | ||||||
|  |  | ||||||
|  | from almanachclient.commands.attach_volume import AttachVolumeCommand | ||||||
| from almanachclient.commands.create_instance import CreateInstanceCommand | from almanachclient.commands.create_instance import CreateInstanceCommand | ||||||
|  | from almanachclient.commands.create_volume import CreateVolumeCommand | ||||||
| from almanachclient.commands.create_volume_type import CreateVolumeTypeCommand | from almanachclient.commands.create_volume_type import CreateVolumeTypeCommand | ||||||
| from almanachclient.commands.delete_instance import DeleteInstanceCommand | from almanachclient.commands.delete_instance import DeleteInstanceCommand | ||||||
| from almanachclient.commands.delete_volume_type import DeleteVolumeTypeCommand | from almanachclient.commands.delete_volume_type import DeleteVolumeTypeCommand | ||||||
|  | from almanachclient.commands.detach_volume import DetachVolumeCommand | ||||||
| from almanachclient.commands.endpoint import EndpointCommand | from almanachclient.commands.endpoint import EndpointCommand | ||||||
| from almanachclient.commands.get_entity import GetEntityCommand | from almanachclient.commands.get_entity import GetEntityCommand | ||||||
| from almanachclient.commands.get_volume_type import GetVolumeTypeCommand | from almanachclient.commands.get_volume_type import GetVolumeTypeCommand | ||||||
| @@ -47,7 +50,10 @@ class AlmanachCommandManager(commandmanager.CommandManager): | |||||||
|         'list-volume-types': ListVolumeTypeCommand, |         'list-volume-types': ListVolumeTypeCommand, | ||||||
|         'get-volume-type': GetVolumeTypeCommand, |         'get-volume-type': GetVolumeTypeCommand, | ||||||
|         'list-volumes': ListVolumeCommand, |         'list-volumes': ListVolumeCommand, | ||||||
|  |         'create-volume': CreateVolumeCommand, | ||||||
|         'resize-volume': ResizeVolumeCommand, |         'resize-volume': ResizeVolumeCommand, | ||||||
|  |         'attach-volume': AttachVolumeCommand, | ||||||
|  |         'detach-volume': DetachVolumeCommand, | ||||||
|         'list-instances': ListInstanceCommand, |         'list-instances': ListInstanceCommand, | ||||||
|         'create-instance': CreateInstanceCommand, |         'create-instance': CreateInstanceCommand, | ||||||
|         'delete-instance': DeleteInstanceCommand, |         'delete-instance': DeleteInstanceCommand, | ||||||
|   | |||||||
							
								
								
									
										47
									
								
								almanachclient/tests/commands/test_attach_volume.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										47
									
								
								almanachclient/tests/commands/test_attach_volume.py
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,47 @@ | |||||||
|  | # Copyright 2017 INAP | ||||||
|  | # | ||||||
|  | # 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 argparse import Namespace | ||||||
|  | import datetime | ||||||
|  | from unittest import mock | ||||||
|  |  | ||||||
|  | from almanachclient.commands.attach_volume import AttachVolumeCommand | ||||||
|  |  | ||||||
|  | from almanachclient.tests import base | ||||||
|  |  | ||||||
|  |  | ||||||
|  | class TestAttachVolumeCommand(base.TestCase): | ||||||
|  |  | ||||||
|  |     def setUp(self): | ||||||
|  |         super().setUp() | ||||||
|  |         self.app = mock.Mock() | ||||||
|  |         self.app_args = mock.Mock() | ||||||
|  |         self.args = Namespace(volume_id='some uuid', attachment=['vm1', 'vm2'], date=None) | ||||||
|  |  | ||||||
|  |         self.client = mock.Mock() | ||||||
|  |         self.app.get_client.return_value = self.client | ||||||
|  |         self.command = AttachVolumeCommand(self.app, self.app_args) | ||||||
|  |  | ||||||
|  |     def test_execute_command(self): | ||||||
|  |         self.assertEqual('Success', self.command.take_action(self.args)) | ||||||
|  |         self.client.attach_volume.assert_called_once_with('some uuid', | ||||||
|  |                                                           attachments=['vm1', 'vm2'], | ||||||
|  |                                                           attachment_date=None) | ||||||
|  |  | ||||||
|  |     def test_execute_command_with_date(self): | ||||||
|  |         self.args.date = '2017-01-01' | ||||||
|  |         self.assertEqual('Success', self.command.take_action(self.args)) | ||||||
|  |         self.client.attach_volume.assert_called_once_with('some uuid', | ||||||
|  |                                                           attachments=['vm1', 'vm2'], | ||||||
|  |                                                           attachment_date=datetime.datetime(2017, 1, 1, 0, 0)) | ||||||
							
								
								
									
										50
									
								
								almanachclient/tests/commands/test_create_volume.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										50
									
								
								almanachclient/tests/commands/test_create_volume.py
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,50 @@ | |||||||
|  | # Copyright 2017 INAP | ||||||
|  | # | ||||||
|  | # 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 argparse import Namespace | ||||||
|  | import datetime | ||||||
|  | from unittest import mock | ||||||
|  |  | ||||||
|  | from almanachclient.commands.create_volume import CreateVolumeCommand | ||||||
|  |  | ||||||
|  | from almanachclient.tests import base | ||||||
|  |  | ||||||
|  |  | ||||||
|  | class TestCreateVolumeCommand(base.TestCase): | ||||||
|  |  | ||||||
|  |     def setUp(self): | ||||||
|  |         super().setUp() | ||||||
|  |         self.app = mock.Mock() | ||||||
|  |         self.app_args = mock.Mock() | ||||||
|  |         self.args = Namespace(tenant_id='tenant uuid', | ||||||
|  |                               volume_id='volume uuid', | ||||||
|  |                               volume_type_id='volume type uuid', | ||||||
|  |                               volume_name='volume', | ||||||
|  |                               volume_size=2, | ||||||
|  |                               start='2017-01-01', | ||||||
|  |                               attachment=None) | ||||||
|  |  | ||||||
|  |         self.client = mock.Mock() | ||||||
|  |         self.app.get_client.return_value = self.client | ||||||
|  |         self.command = CreateVolumeCommand(self.app, self.app_args) | ||||||
|  |  | ||||||
|  |     def test_execute_command(self): | ||||||
|  |         self.assertEqual('Success', self.command.take_action(self.args)) | ||||||
|  |         self.client.create_volume.assert_called_once_with('tenant uuid', | ||||||
|  |                                                           'volume uuid', | ||||||
|  |                                                           'volume type uuid', | ||||||
|  |                                                           'volume', | ||||||
|  |                                                           2, | ||||||
|  |                                                           start=datetime.datetime(2017, 1, 1, 0, 0), | ||||||
|  |                                                           attachments=None) | ||||||
							
								
								
									
										47
									
								
								almanachclient/tests/commands/test_detach_volume.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										47
									
								
								almanachclient/tests/commands/test_detach_volume.py
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,47 @@ | |||||||
|  | # Copyright 2017 INAP | ||||||
|  | # | ||||||
|  | # 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 argparse import Namespace | ||||||
|  | import datetime | ||||||
|  | from unittest import mock | ||||||
|  |  | ||||||
|  | from almanachclient.commands.detach_volume import DetachVolumeCommand | ||||||
|  |  | ||||||
|  | from almanachclient.tests import base | ||||||
|  |  | ||||||
|  |  | ||||||
|  | class TestDetachVolumeCommand(base.TestCase): | ||||||
|  |  | ||||||
|  |     def setUp(self): | ||||||
|  |         super().setUp() | ||||||
|  |         self.app = mock.Mock() | ||||||
|  |         self.app_args = mock.Mock() | ||||||
|  |         self.args = Namespace(volume_id='some uuid', attachment=['vm1', 'vm2'], date=None) | ||||||
|  |  | ||||||
|  |         self.client = mock.Mock() | ||||||
|  |         self.app.get_client.return_value = self.client | ||||||
|  |         self.command = DetachVolumeCommand(self.app, self.app_args) | ||||||
|  |  | ||||||
|  |     def test_execute_command(self): | ||||||
|  |         self.assertEqual('Success', self.command.take_action(self.args)) | ||||||
|  |         self.client.detach_volume.assert_called_once_with('some uuid', | ||||||
|  |                                                           attachments=['vm1', 'vm2'], | ||||||
|  |                                                           attachment_date=None) | ||||||
|  |  | ||||||
|  |     def test_execute_command_with_date(self): | ||||||
|  |         self.args.date = '2017-01-01' | ||||||
|  |         self.assertEqual('Success', self.command.take_action(self.args)) | ||||||
|  |         self.client.detach_volume.assert_called_once_with('some uuid', | ||||||
|  |                                                           attachments=['vm1', 'vm2'], | ||||||
|  |                                                           attachment_date=datetime.datetime(2017, 1, 1, 0, 0)) | ||||||
| @@ -250,3 +250,58 @@ class TestClient(base.TestCase): | |||||||
|                                          data=json.dumps({'size': 3, |                                          data=json.dumps({'size': 3, | ||||||
|                                                           'date': date.strftime(Client.DATE_FORMAT_BODY)}), |                                                           'date': date.strftime(Client.DATE_FORMAT_BODY)}), | ||||||
|                                          headers=self.headers) |                                          headers=self.headers) | ||||||
|  |  | ||||||
|  |     @mock.patch('requests.post') | ||||||
|  |     def test_create_volume(self, requests): | ||||||
|  |         date = datetime.now() | ||||||
|  |         requests.return_value = self.response | ||||||
|  |  | ||||||
|  |         self.response.headers['Content-Length'] = 0 | ||||||
|  |         self.response.status_code = 201 | ||||||
|  |  | ||||||
|  |         self.assertTrue(self.client.create_volume('tenant_id', 'my_volume_id', 'volume_type_id', | ||||||
|  |                                                   'volume name', 2, start=date)) | ||||||
|  |  | ||||||
|  |         requests.assert_called_once_with('{}{}'.format(self.url, '/v1/project/tenant_id/volume'), | ||||||
|  |                                          params=None, | ||||||
|  |                                          data=json.dumps({ | ||||||
|  |                                              'volume_id': 'my_volume_id', | ||||||
|  |                                              'volume_type': 'volume_type_id', | ||||||
|  |                                              'volume_name': 'volume name', | ||||||
|  |                                              'size': 2, | ||||||
|  |                                              'attached_to': [], | ||||||
|  |                                              'start': date.strftime(Client.DATE_FORMAT_BODY), | ||||||
|  |                                          }), | ||||||
|  |                                          headers=self.headers) | ||||||
|  |  | ||||||
|  |     @mock.patch('requests.put') | ||||||
|  |     def test_attach_volume(self, requests): | ||||||
|  |         date = datetime.now() | ||||||
|  |         requests.return_value = self.response | ||||||
|  |  | ||||||
|  |         self.response.headers['Content-Length'] = 0 | ||||||
|  |         self.response.status_code = 200 | ||||||
|  |  | ||||||
|  |         self.assertTrue(self.client.attach_volume('my_volume_id', ['instance_id'], date)) | ||||||
|  |  | ||||||
|  |         requests.assert_called_once_with('{}{}'.format(self.url, '/v1/volume/my_volume_id/attach'), | ||||||
|  |                                          params=None, | ||||||
|  |                                          data=json.dumps({'attachments': ['instance_id'], | ||||||
|  |                                                           'date': date.strftime(Client.DATE_FORMAT_BODY)}), | ||||||
|  |                                          headers=self.headers) | ||||||
|  |  | ||||||
|  |     @mock.patch('requests.put') | ||||||
|  |     def test_detach_volume(self, requests): | ||||||
|  |         date = datetime.now() | ||||||
|  |         requests.return_value = self.response | ||||||
|  |  | ||||||
|  |         self.response.headers['Content-Length'] = 0 | ||||||
|  |         self.response.status_code = 200 | ||||||
|  |  | ||||||
|  |         self.assertTrue(self.client.detach_volume('my_volume_id', ['instance_id'], date)) | ||||||
|  |  | ||||||
|  |         requests.assert_called_once_with('{}{}'.format(self.url, '/v1/volume/my_volume_id/detach'), | ||||||
|  |                                          params=None, | ||||||
|  |                                          data=json.dumps({'attachments': ['instance_id'], | ||||||
|  |                                                           'date': date.strftime(Client.DATE_FORMAT_BODY)}), | ||||||
|  |                                          headers=self.headers) | ||||||
|   | |||||||
| @@ -85,6 +85,31 @@ class Client(HttpClient): | |||||||
|         params = {'start': self._format_qs_datetime(start), 'end': self._format_qs_datetime(end)} |         params = {'start': self._format_qs_datetime(start), 'end': self._format_qs_datetime(end)} | ||||||
|         return self._get(url, params) |         return self._get(url, params) | ||||||
|  |  | ||||||
|  |     def create_volume(self, tenant_id, volume_id, volume_type_id, name, size, attachments=None, start=None): | ||||||
|  |         """Create a volume. | ||||||
|  |  | ||||||
|  |         :arg str tenant_id: Tenant UUID | ||||||
|  |         :arg str volume_id: Volume UUID | ||||||
|  |         :arg str volume_type_id: Volume type | ||||||
|  |         :arg str name: Volume name | ||||||
|  |         :arg int size: Volume size | ||||||
|  |         :arg list attachments: List of instance attached to the volume | ||||||
|  |         :arg datetime start: Creation date or now if None | ||||||
|  |         :raises: ClientError | ||||||
|  |         :rtype: bool | ||||||
|  |         """ | ||||||
|  |         data = { | ||||||
|  |             'volume_id': volume_id, | ||||||
|  |             'volume_type': volume_type_id, | ||||||
|  |             'volume_name': name, | ||||||
|  |             'size': size, | ||||||
|  |             'attached_to': attachments or [], | ||||||
|  |             'start': self._format_body_datetime(start or datetime.now()), | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         self._post('{}/{}/project/{}/volume'.format(self.url, self.api_version, tenant_id), data=data) | ||||||
|  |         return True | ||||||
|  |  | ||||||
|     def resize_volume(self, volume_id, size, resize_date=None): |     def resize_volume(self, volume_id, size, resize_date=None): | ||||||
|         """Resize a volume. |         """Resize a volume. | ||||||
|  |  | ||||||
| @@ -102,6 +127,40 @@ class Client(HttpClient): | |||||||
|         self._put('{}/{}/volume/{}/resize'.format(self.url, self.api_version, volume_id), data=data) |         self._put('{}/{}/volume/{}/resize'.format(self.url, self.api_version, volume_id), data=data) | ||||||
|         return True |         return True | ||||||
|  |  | ||||||
|  |     def attach_volume(self, volume_id, attachments, attachment_date=None): | ||||||
|  |         """Attach instances to a volume. | ||||||
|  |  | ||||||
|  |         :arg str volume_id: Volume UUID | ||||||
|  |         :arg list attachments: List of instance ID | ||||||
|  |         :arg datetime attachment_date: Attachment date | ||||||
|  |         :raises: ClientError | ||||||
|  |         :rtype: bool | ||||||
|  |         """ | ||||||
|  |         data = { | ||||||
|  |             'attachments': attachments, | ||||||
|  |             'date': self._format_body_datetime(attachment_date or datetime.now()), | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         self._put('{}/{}/volume/{}/attach'.format(self.url, self.api_version, volume_id), data=data) | ||||||
|  |         return True | ||||||
|  |  | ||||||
|  |     def detach_volume(self, volume_id, attachments, attachment_date=None): | ||||||
|  |         """Detach instances from a volume. | ||||||
|  |  | ||||||
|  |         :arg str volume_id: Volume UUID | ||||||
|  |         :arg list attachments: List of instance ID | ||||||
|  |         :arg datetime attachment_date: Attachment date | ||||||
|  |         :raises: ClientError | ||||||
|  |         :rtype: bool | ||||||
|  |         """ | ||||||
|  |         data = { | ||||||
|  |             'attachments': attachments, | ||||||
|  |             'date': self._format_body_datetime(attachment_date or datetime.now()), | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         self._put('{}/{}/volume/{}/detach'.format(self.url, self.api_version, volume_id), data=data) | ||||||
|  |         return True | ||||||
|  |  | ||||||
|     def get_instances(self, tenant_id, start, end): |     def get_instances(self, tenant_id, start, end): | ||||||
|         """List instances for a tenant. |         """List instances for a tenant. | ||||||
|  |  | ||||||
|   | |||||||
| @@ -2,7 +2,14 @@ | |||||||
| Installation | Installation | ||||||
| ============ | ============ | ||||||
|  |  | ||||||
| The client requires at least the version 4.0.9 of Almanach. | Requirements | ||||||
|  | ------------ | ||||||
|  |  | ||||||
|  | - Python >= 3.4 | ||||||
|  | - Almanach >= 4.0.9 | ||||||
|  |  | ||||||
|  | Instructions | ||||||
|  | ------------ | ||||||
|  |  | ||||||
| At the command line:: | At the command line:: | ||||||
|  |  | ||||||
|   | |||||||
| @@ -208,6 +208,35 @@ Arguments: | |||||||
| * :code:`start`: Start date (ISO8601 format) | * :code:`start`: Start date (ISO8601 format) | ||||||
| * :code:`end`: End date (ISO8601 format) | * :code:`end`: End date (ISO8601 format) | ||||||
|  |  | ||||||
|  | Create Volume | ||||||
|  | ------------- | ||||||
|  |  | ||||||
|  | Usage: :code:`almanach create-volume <tenant_id> <volume_id> <volume_type_id> <volume_name> <size> --date <creation_date> --attachment <instance_id>` | ||||||
|  |  | ||||||
|  | .. code:: bash | ||||||
|  |  | ||||||
|  |     almanach create-volume \ | ||||||
|  |         8c3bc3aa-28d6-4863-b5ae-72e1b415f79d \ | ||||||
|  |         3e3b22e6-a10c-4c00-b8e5-05fcc8422b11 \ | ||||||
|  |         f3786e9f-f8e6-4944-a3bc-e11b9f112706 \ | ||||||
|  |         my-volume \ | ||||||
|  |         5 \ | ||||||
|  |         --attachment=86dd5189-d9d6-40f7-a319-19231fbd4e07 \ | ||||||
|  |         --attachment=252e49d8-abf2-486c-8478-b5f775134f54 | ||||||
|  |  | ||||||
|  |     Success | ||||||
|  |  | ||||||
|  | Arguments: | ||||||
|  |  | ||||||
|  | * :code:`tenant_id`: Tenant ID (UUID) | ||||||
|  | * :code:`volume_id`: Volume ID (UUID) | ||||||
|  | * :code:`volume_type_id`: Volume ID (UUID) | ||||||
|  | * :code:`volume_name`: Volume name (string) | ||||||
|  | * :code:`size`: Volume size (integer) | ||||||
|  | * :code:`date`: Creation date (ISO8601 format), if not specified the current datetime is used | ||||||
|  | * :code:`attachment`: Attach the volume to one or many instances (UUID) | ||||||
|  |  | ||||||
|  |  | ||||||
| Resize Volume | Resize Volume | ||||||
| ------------- | ------------- | ||||||
|  |  | ||||||
| @@ -225,6 +254,45 @@ Arguments: | |||||||
| * :code:`size`: Volume size (integer) | * :code:`size`: Volume size (integer) | ||||||
| * :code:`date`: Resize date (ISO8601 format), if not specified the current datetime is used | * :code:`date`: Resize date (ISO8601 format), if not specified the current datetime is used | ||||||
|  |  | ||||||
|  | Attach Volume | ||||||
|  | ------------- | ||||||
|  |  | ||||||
|  | Usage: :code:`almanach attach-volume <volume_id> --date <creation_date> --attachment <instance_id>` | ||||||
|  |  | ||||||
|  | .. code:: bash | ||||||
|  |  | ||||||
|  |     almanach attach-volume \ | ||||||
|  |         8c3bc3aa-28d6-4863-b5ae-72e1b415f79d \ | ||||||
|  |         --attachment=86dd5189-d9d6-40f7-a319-19231fbd4e07 | ||||||
|  |  | ||||||
|  |     Success | ||||||
|  |  | ||||||
|  | Arguments: | ||||||
|  |  | ||||||
|  | * :code:`volume_id`: Volume ID (UUID) | ||||||
|  | * :code:`date`: Attachment date (ISO8601 format), if not specified the current datetime is used | ||||||
|  | * :code:`attachment`: Attach the volume to one or many instances (UUID) | ||||||
|  |  | ||||||
|  |  | ||||||
|  | Detach Volume | ||||||
|  | ------------- | ||||||
|  |  | ||||||
|  | Usage: :code:`almanach detach-volume <volume_id> --date <creation_date> --attachment <instance_id>` | ||||||
|  |  | ||||||
|  | .. code:: bash | ||||||
|  |  | ||||||
|  |     almanach detach-volume \ | ||||||
|  |         8c3bc3aa-28d6-4863-b5ae-72e1b415f79d \ | ||||||
|  |         --attachment=86dd5189-d9d6-40f7-a319-19231fbd4e07 | ||||||
|  |  | ||||||
|  |     Success | ||||||
|  |  | ||||||
|  | Arguments: | ||||||
|  |  | ||||||
|  | * :code:`volume_id`: Volume ID (UUID) | ||||||
|  | * :code:`date`: Attachment date (ISO8601 format), if not specified the current datetime is used | ||||||
|  | * :code:`attachment`: Attach the volume to one or many instances (UUID) | ||||||
|  |  | ||||||
| List Volume Types | List Volume Types | ||||||
| ----------------- | ----------------- | ||||||
|  |  | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user
	 Frédéric Guillot
					Frédéric Guillot