[compute] Add server backup function
Add server backup function There is no return value for this command per following doc http://developer.openstack.org/api-ref-compute-v2.1.html#createBackup, also novaclient can't be updated now due to backward compatible issue http://lists.openstack.org/pipermail/openstack-dev/2016-March/089376.html, so we have to get the information ourselves. The Image tests were not using warlock images, so that needed to be fixed before we could completely test things like --wait. Change-Id: I30159518c4d3fdec89f15963bda641a0b03962d1
This commit is contained in:
		
							
								
								
									
										44
									
								
								doc/source/command-objects/server-backup.rst
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										44
									
								
								doc/source/command-objects/server-backup.rst
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,44 @@
 | 
				
			|||||||
 | 
					=============
 | 
				
			||||||
 | 
					server backup
 | 
				
			||||||
 | 
					=============
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					A server backup is a disk image created in the Image store from a running server
 | 
				
			||||||
 | 
					instance.  The backup command manages the number of archival copies to retain.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Compute v2
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					server backup create
 | 
				
			||||||
 | 
					--------------------
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Create a server backup image
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					.. program:: server create
 | 
				
			||||||
 | 
					.. code:: bash
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    os server backup create
 | 
				
			||||||
 | 
					        [--name <image-name>]
 | 
				
			||||||
 | 
					        [--type <backup-type>]
 | 
				
			||||||
 | 
					        [--rotate <count>]
 | 
				
			||||||
 | 
					        [--wait]
 | 
				
			||||||
 | 
					        <server>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					.. option:: --name <image-name>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    Name of the backup image (default: server name)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					.. option:: --type <backup-type>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    Used to populate the ``backup_type`` property of the backup
 | 
				
			||||||
 | 
					    image (default: empty)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					.. option:: --rotate <count>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    Number of backup images to keep (default: 1)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					.. option:: --wait
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    Wait for operation to complete
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					.. describe:: <server>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    Server to back up (name or ID)
 | 
				
			||||||
@@ -118,6 +118,7 @@ referring to both Compute and Volume quotas.
 | 
				
			|||||||
* ``security group``: (**Compute**, **Network**) - groups of network access rules
 | 
					* ``security group``: (**Compute**, **Network**) - groups of network access rules
 | 
				
			||||||
* ``security group rule``: (**Compute**, **Network**) - the individual rules that define protocol/IP/port access
 | 
					* ``security group rule``: (**Compute**, **Network**) - the individual rules that define protocol/IP/port access
 | 
				
			||||||
* ``server``: (**Compute**) virtual machine instance
 | 
					* ``server``: (**Compute**) virtual machine instance
 | 
				
			||||||
 | 
					* ``server backup``: (**Compute**) backup server disk image by using snapshot method
 | 
				
			||||||
* ``server dump``: (**Compute**) a dump file of a server created by features like kdump
 | 
					* ``server dump``: (**Compute**) a dump file of a server created by features like kdump
 | 
				
			||||||
* ``server group``: (**Compute**) a grouping of servers
 | 
					* ``server group``: (**Compute**) a grouping of servers
 | 
				
			||||||
* ``server image``: (**Compute**) saved server disk image
 | 
					* ``server image``: (**Compute**) saved server disk image
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										134
									
								
								openstackclient/compute/v2/server_backup.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										134
									
								
								openstackclient/compute/v2/server_backup.py
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,134 @@
 | 
				
			|||||||
 | 
					#   Copyright 2012-2013 OpenStack Foundation
 | 
				
			||||||
 | 
					#
 | 
				
			||||||
 | 
					#   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.
 | 
				
			||||||
 | 
					#
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					"""Compute v2 Server action implementations"""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import sys
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					from oslo_utils import importutils
 | 
				
			||||||
 | 
					import six
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					from openstackclient.common import command
 | 
				
			||||||
 | 
					from openstackclient.common import exceptions
 | 
				
			||||||
 | 
					from openstackclient.common import utils
 | 
				
			||||||
 | 
					from openstackclient.i18n import _
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					def _show_progress(progress):
 | 
				
			||||||
 | 
					    if progress:
 | 
				
			||||||
 | 
					        sys.stderr.write('\rProgress: %s' % progress)
 | 
				
			||||||
 | 
					        sys.stderr.flush()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class CreateServerBackup(command.ShowOne):
 | 
				
			||||||
 | 
					    """Create a server backup image"""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    IMAGE_API_VERSIONS = {
 | 
				
			||||||
 | 
					        "1": "openstackclient.image.v1.image",
 | 
				
			||||||
 | 
					        "2": "openstackclient.image.v2.image",
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def get_parser(self, prog_name):
 | 
				
			||||||
 | 
					        parser = super(CreateServerBackup, self).get_parser(prog_name)
 | 
				
			||||||
 | 
					        parser.add_argument(
 | 
				
			||||||
 | 
					            'server',
 | 
				
			||||||
 | 
					            metavar='<server>',
 | 
				
			||||||
 | 
					            help=_('Server to back up (name or ID)'),
 | 
				
			||||||
 | 
					        )
 | 
				
			||||||
 | 
					        parser.add_argument(
 | 
				
			||||||
 | 
					            '--name',
 | 
				
			||||||
 | 
					            metavar='<image-name>',
 | 
				
			||||||
 | 
					            help=_('Name of the backup image (default: server name)'),
 | 
				
			||||||
 | 
					        )
 | 
				
			||||||
 | 
					        parser.add_argument(
 | 
				
			||||||
 | 
					            '--type',
 | 
				
			||||||
 | 
					            metavar='<backup-type>',
 | 
				
			||||||
 | 
					            help=_(
 | 
				
			||||||
 | 
					                'Used to populate the backup_type property of the backup '
 | 
				
			||||||
 | 
					                'image (default: empty)'
 | 
				
			||||||
 | 
					            ),
 | 
				
			||||||
 | 
					        )
 | 
				
			||||||
 | 
					        parser.add_argument(
 | 
				
			||||||
 | 
					            '--rotate',
 | 
				
			||||||
 | 
					            metavar='<count>',
 | 
				
			||||||
 | 
					            type=int,
 | 
				
			||||||
 | 
					            help=_('Number of backups to keep (default: 1)'),
 | 
				
			||||||
 | 
					        )
 | 
				
			||||||
 | 
					        parser.add_argument(
 | 
				
			||||||
 | 
					            '--wait',
 | 
				
			||||||
 | 
					            action='store_true',
 | 
				
			||||||
 | 
					            help=_('Wait for backup image create to complete'),
 | 
				
			||||||
 | 
					        )
 | 
				
			||||||
 | 
					        return parser
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def take_action(self, parsed_args):
 | 
				
			||||||
 | 
					        compute_client = self.app.client_manager.compute
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        server = utils.find_resource(
 | 
				
			||||||
 | 
					            compute_client.servers,
 | 
				
			||||||
 | 
					            parsed_args.server,
 | 
				
			||||||
 | 
					        )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        # Set sane defaults as this API wants all mouths to be fed
 | 
				
			||||||
 | 
					        if parsed_args.name is None:
 | 
				
			||||||
 | 
					            backup_name = server.name
 | 
				
			||||||
 | 
					        else:
 | 
				
			||||||
 | 
					            backup_name = parsed_args.name
 | 
				
			||||||
 | 
					        if parsed_args.type is None:
 | 
				
			||||||
 | 
					            backup_type = ""
 | 
				
			||||||
 | 
					        else:
 | 
				
			||||||
 | 
					            backup_type = parsed_args.type
 | 
				
			||||||
 | 
					        if parsed_args.rotate is None:
 | 
				
			||||||
 | 
					            backup_rotation = 1
 | 
				
			||||||
 | 
					        else:
 | 
				
			||||||
 | 
					            backup_rotation = parsed_args.rotate
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        compute_client.servers.backup(
 | 
				
			||||||
 | 
					            server.id,
 | 
				
			||||||
 | 
					            backup_name,
 | 
				
			||||||
 | 
					            backup_type,
 | 
				
			||||||
 | 
					            backup_rotation,
 | 
				
			||||||
 | 
					        )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        image_client = self.app.client_manager.image
 | 
				
			||||||
 | 
					        image = utils.find_resource(
 | 
				
			||||||
 | 
					            image_client.images,
 | 
				
			||||||
 | 
					            backup_name,
 | 
				
			||||||
 | 
					        )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if parsed_args.wait:
 | 
				
			||||||
 | 
					            if utils.wait_for_status(
 | 
				
			||||||
 | 
					                image_client.images.get,
 | 
				
			||||||
 | 
					                image.id,
 | 
				
			||||||
 | 
					                callback=_show_progress,
 | 
				
			||||||
 | 
					            ):
 | 
				
			||||||
 | 
					                sys.stdout.write('\n')
 | 
				
			||||||
 | 
					            else:
 | 
				
			||||||
 | 
					                msg = _('Error creating server backup: %s') % parsed_args.name
 | 
				
			||||||
 | 
					                raise exceptions.CommandError(msg)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if self.app.client_manager._api_version['image'] == '1':
 | 
				
			||||||
 | 
					            info = {}
 | 
				
			||||||
 | 
					            info.update(image._info)
 | 
				
			||||||
 | 
					            info['properties'] = utils.format_dict(info.get('properties', {}))
 | 
				
			||||||
 | 
					        else:
 | 
				
			||||||
 | 
					            # Get the right image module to format the output
 | 
				
			||||||
 | 
					            image_module = importutils.import_module(
 | 
				
			||||||
 | 
					                self.IMAGE_API_VERSIONS[
 | 
				
			||||||
 | 
					                    self.app.client_manager._api_version['image']
 | 
				
			||||||
 | 
					                ]
 | 
				
			||||||
 | 
					            )
 | 
				
			||||||
 | 
					            info = image_module._format_image(image)
 | 
				
			||||||
 | 
					        return zip(*sorted(six.iteritems(info)))
 | 
				
			||||||
							
								
								
									
										270
									
								
								openstackclient/tests/compute/v2/test_server_backup.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										270
									
								
								openstackclient/tests/compute/v2/test_server_backup.py
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,270 @@
 | 
				
			|||||||
 | 
					#   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.
 | 
				
			||||||
 | 
					#
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import mock
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					from openstackclient.common import exceptions
 | 
				
			||||||
 | 
					from openstackclient.common import utils as common_utils
 | 
				
			||||||
 | 
					from openstackclient.compute.v2 import server_backup
 | 
				
			||||||
 | 
					from openstackclient.tests.compute.v2 import fakes as compute_fakes
 | 
				
			||||||
 | 
					from openstackclient.tests.image.v2 import fakes as image_fakes
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class TestServerBackup(compute_fakes.TestComputev2):
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def setUp(self):
 | 
				
			||||||
 | 
					        super(TestServerBackup, self).setUp()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        # Get a shortcut to the compute client ServerManager Mock
 | 
				
			||||||
 | 
					        self.servers_mock = self.app.client_manager.compute.servers
 | 
				
			||||||
 | 
					        self.servers_mock.reset_mock()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        # Get a shortcut to the image client ImageManager Mock
 | 
				
			||||||
 | 
					        self.images_mock = self.app.client_manager.image.images
 | 
				
			||||||
 | 
					        self.images_mock.reset_mock()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        # Set object attributes to be tested. Could be overwriten in subclass.
 | 
				
			||||||
 | 
					        self.attrs = {}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        # Set object methods to be tested. Could be overwriten in subclass.
 | 
				
			||||||
 | 
					        self.methods = {}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def setup_servers_mock(self, count):
 | 
				
			||||||
 | 
					        servers = compute_fakes.FakeServer.create_servers(
 | 
				
			||||||
 | 
					            attrs=self.attrs,
 | 
				
			||||||
 | 
					            methods=self.methods,
 | 
				
			||||||
 | 
					            count=count,
 | 
				
			||||||
 | 
					        )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        # This is the return value for utils.find_resource()
 | 
				
			||||||
 | 
					        self.servers_mock.get = compute_fakes.FakeServer.get_servers(
 | 
				
			||||||
 | 
					            servers,
 | 
				
			||||||
 | 
					            0,
 | 
				
			||||||
 | 
					        )
 | 
				
			||||||
 | 
					        return servers
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class TestServerBackupCreate(TestServerBackup):
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    # Just return whatever Image is testing with these days
 | 
				
			||||||
 | 
					    def image_columns(self, image):
 | 
				
			||||||
 | 
					        columnlist = tuple(sorted(image.keys()))
 | 
				
			||||||
 | 
					        return columnlist
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def image_data(self, image):
 | 
				
			||||||
 | 
					        datalist = (
 | 
				
			||||||
 | 
					            image['id'],
 | 
				
			||||||
 | 
					            image['name'],
 | 
				
			||||||
 | 
					            image['owner'],
 | 
				
			||||||
 | 
					            image['protected'],
 | 
				
			||||||
 | 
					            'active',
 | 
				
			||||||
 | 
					            common_utils.format_list(image.get('tags')),
 | 
				
			||||||
 | 
					            image['visibility'],
 | 
				
			||||||
 | 
					        )
 | 
				
			||||||
 | 
					        return datalist
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def setUp(self):
 | 
				
			||||||
 | 
					        super(TestServerBackupCreate, self).setUp()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        # Get the command object to test
 | 
				
			||||||
 | 
					        self.cmd = server_backup.CreateServerBackup(self.app, None)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        self.methods = {
 | 
				
			||||||
 | 
					            'backup': None,
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def setup_images_mock(self, count, servers=None):
 | 
				
			||||||
 | 
					        if servers:
 | 
				
			||||||
 | 
					            images = image_fakes.FakeImage.create_images(
 | 
				
			||||||
 | 
					                attrs={
 | 
				
			||||||
 | 
					                    'name': servers[0].name,
 | 
				
			||||||
 | 
					                    'status': 'active',
 | 
				
			||||||
 | 
					                },
 | 
				
			||||||
 | 
					                count=count,
 | 
				
			||||||
 | 
					            )
 | 
				
			||||||
 | 
					        else:
 | 
				
			||||||
 | 
					            images = image_fakes.FakeImage.create_images(
 | 
				
			||||||
 | 
					                attrs={
 | 
				
			||||||
 | 
					                    'status': 'active',
 | 
				
			||||||
 | 
					                },
 | 
				
			||||||
 | 
					                count=count,
 | 
				
			||||||
 | 
					            )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        self.images_mock.get = mock.MagicMock(side_effect=images)
 | 
				
			||||||
 | 
					        return images
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def test_server_backup_defaults(self):
 | 
				
			||||||
 | 
					        servers = self.setup_servers_mock(count=1)
 | 
				
			||||||
 | 
					        images = self.setup_images_mock(count=1, servers=servers)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        arglist = [
 | 
				
			||||||
 | 
					            servers[0].id,
 | 
				
			||||||
 | 
					        ]
 | 
				
			||||||
 | 
					        verifylist = [
 | 
				
			||||||
 | 
					            ('name', None),
 | 
				
			||||||
 | 
					            ('type', None),
 | 
				
			||||||
 | 
					            ('rotate', None),
 | 
				
			||||||
 | 
					            ('wait', False),
 | 
				
			||||||
 | 
					            ('server', servers[0].id),
 | 
				
			||||||
 | 
					        ]
 | 
				
			||||||
 | 
					        parsed_args = self.check_parser(self.cmd, arglist, verifylist)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        # In base command class ShowOne in cliff, abstract method take_action()
 | 
				
			||||||
 | 
					        # returns a two-part tuple with a tuple of column names and a tuple of
 | 
				
			||||||
 | 
					        # data to be shown.
 | 
				
			||||||
 | 
					        columns, data = self.cmd.take_action(parsed_args)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        # ServerManager.backup(server, backup_name, backup_type, rotation)
 | 
				
			||||||
 | 
					        self.servers_mock.backup.assert_called_with(
 | 
				
			||||||
 | 
					            servers[0].id,
 | 
				
			||||||
 | 
					            servers[0].name,
 | 
				
			||||||
 | 
					            '',
 | 
				
			||||||
 | 
					            1,
 | 
				
			||||||
 | 
					        )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        self.assertEqual(self.image_columns(images[0]), columns)
 | 
				
			||||||
 | 
					        self.assertEqual(self.image_data(images[0]), data)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def test_server_backup_create_options(self):
 | 
				
			||||||
 | 
					        servers = self.setup_servers_mock(count=1)
 | 
				
			||||||
 | 
					        images = self.setup_images_mock(count=1, servers=servers)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        arglist = [
 | 
				
			||||||
 | 
					            '--name', 'image',
 | 
				
			||||||
 | 
					            '--type', 'daily',
 | 
				
			||||||
 | 
					            '--rotate', '2',
 | 
				
			||||||
 | 
					            servers[0].id,
 | 
				
			||||||
 | 
					        ]
 | 
				
			||||||
 | 
					        verifylist = [
 | 
				
			||||||
 | 
					            ('name', 'image'),
 | 
				
			||||||
 | 
					            ('type', 'daily'),
 | 
				
			||||||
 | 
					            ('rotate', 2),
 | 
				
			||||||
 | 
					            ('server', servers[0].id),
 | 
				
			||||||
 | 
					        ]
 | 
				
			||||||
 | 
					        parsed_args = self.check_parser(self.cmd, arglist, verifylist)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        # In base command class ShowOne in cliff, abstract method take_action()
 | 
				
			||||||
 | 
					        # returns a two-part tuple with a tuple of column names and a tuple of
 | 
				
			||||||
 | 
					        # data to be shown.
 | 
				
			||||||
 | 
					        columns, data = self.cmd.take_action(parsed_args)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        # ServerManager.backup(server, backup_name, backup_type, rotation)
 | 
				
			||||||
 | 
					        self.servers_mock.backup.assert_called_with(
 | 
				
			||||||
 | 
					            servers[0].id,
 | 
				
			||||||
 | 
					            'image',
 | 
				
			||||||
 | 
					            'daily',
 | 
				
			||||||
 | 
					            2,
 | 
				
			||||||
 | 
					        )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        self.assertEqual(self.image_columns(images[0]), columns)
 | 
				
			||||||
 | 
					        self.assertEqual(self.image_data(images[0]), data)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    @mock.patch.object(common_utils, 'wait_for_status', return_value=False)
 | 
				
			||||||
 | 
					    def test_server_backup_wait_fail(self, mock_wait_for_status):
 | 
				
			||||||
 | 
					        servers = self.setup_servers_mock(count=1)
 | 
				
			||||||
 | 
					        images = image_fakes.FakeImage.create_images(
 | 
				
			||||||
 | 
					            attrs={
 | 
				
			||||||
 | 
					                'name': servers[0].name,
 | 
				
			||||||
 | 
					                'status': 'active',
 | 
				
			||||||
 | 
					            },
 | 
				
			||||||
 | 
					            count=5,
 | 
				
			||||||
 | 
					        )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        self.images_mock.get = mock.MagicMock(
 | 
				
			||||||
 | 
					            side_effect=images,
 | 
				
			||||||
 | 
					        )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        arglist = [
 | 
				
			||||||
 | 
					            '--name', 'image',
 | 
				
			||||||
 | 
					            '--type', 'daily',
 | 
				
			||||||
 | 
					            '--wait',
 | 
				
			||||||
 | 
					            servers[0].id,
 | 
				
			||||||
 | 
					        ]
 | 
				
			||||||
 | 
					        verifylist = [
 | 
				
			||||||
 | 
					            ('name', 'image'),
 | 
				
			||||||
 | 
					            ('type', 'daily'),
 | 
				
			||||||
 | 
					            ('wait', True),
 | 
				
			||||||
 | 
					            ('server', servers[0].id),
 | 
				
			||||||
 | 
					        ]
 | 
				
			||||||
 | 
					        parsed_args = self.check_parser(self.cmd, arglist, verifylist)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        self.assertRaises(
 | 
				
			||||||
 | 
					            exceptions.CommandError,
 | 
				
			||||||
 | 
					            self.cmd.take_action,
 | 
				
			||||||
 | 
					            parsed_args,
 | 
				
			||||||
 | 
					        )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        # ServerManager.backup(server, backup_name, backup_type, rotation)
 | 
				
			||||||
 | 
					        self.servers_mock.backup.assert_called_with(
 | 
				
			||||||
 | 
					            servers[0].id,
 | 
				
			||||||
 | 
					            'image',
 | 
				
			||||||
 | 
					            'daily',
 | 
				
			||||||
 | 
					            1,
 | 
				
			||||||
 | 
					        )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        mock_wait_for_status.assert_called_once_with(
 | 
				
			||||||
 | 
					            self.images_mock.get,
 | 
				
			||||||
 | 
					            images[0].id,
 | 
				
			||||||
 | 
					            callback=mock.ANY
 | 
				
			||||||
 | 
					        )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    @mock.patch.object(common_utils, 'wait_for_status', return_value=True)
 | 
				
			||||||
 | 
					    def test_server_backup_wait_ok(self, mock_wait_for_status):
 | 
				
			||||||
 | 
					        servers = self.setup_servers_mock(count=1)
 | 
				
			||||||
 | 
					        images = image_fakes.FakeImage.create_images(
 | 
				
			||||||
 | 
					            attrs={
 | 
				
			||||||
 | 
					                'name': servers[0].name,
 | 
				
			||||||
 | 
					                'status': 'active',
 | 
				
			||||||
 | 
					            },
 | 
				
			||||||
 | 
					            count=5,
 | 
				
			||||||
 | 
					        )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        self.images_mock.get = mock.MagicMock(
 | 
				
			||||||
 | 
					            side_effect=images,
 | 
				
			||||||
 | 
					        )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        arglist = [
 | 
				
			||||||
 | 
					            '--name', 'image',
 | 
				
			||||||
 | 
					            '--type', 'daily',
 | 
				
			||||||
 | 
					            '--wait',
 | 
				
			||||||
 | 
					            servers[0].id,
 | 
				
			||||||
 | 
					        ]
 | 
				
			||||||
 | 
					        verifylist = [
 | 
				
			||||||
 | 
					            ('name', 'image'),
 | 
				
			||||||
 | 
					            ('type', 'daily'),
 | 
				
			||||||
 | 
					            ('wait', True),
 | 
				
			||||||
 | 
					            ('server', servers[0].id),
 | 
				
			||||||
 | 
					        ]
 | 
				
			||||||
 | 
					        parsed_args = self.check_parser(self.cmd, arglist, verifylist)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        # In base command class ShowOne in cliff, abstract method take_action()
 | 
				
			||||||
 | 
					        # returns a two-part tuple with a tuple of column names and a tuple of
 | 
				
			||||||
 | 
					        # data to be shown.
 | 
				
			||||||
 | 
					        columns, data = self.cmd.take_action(parsed_args)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        # ServerManager.backup(server, backup_name, backup_type, rotation)
 | 
				
			||||||
 | 
					        self.servers_mock.backup.assert_called_with(
 | 
				
			||||||
 | 
					            servers[0].id,
 | 
				
			||||||
 | 
					            'image',
 | 
				
			||||||
 | 
					            'daily',
 | 
				
			||||||
 | 
					            1,
 | 
				
			||||||
 | 
					        )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        mock_wait_for_status.assert_called_once_with(
 | 
				
			||||||
 | 
					            self.images_mock.get,
 | 
				
			||||||
 | 
					            images[0].id,
 | 
				
			||||||
 | 
					            callback=mock.ANY
 | 
				
			||||||
 | 
					        )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        self.assertEqual(self.image_columns(images[0]), columns)
 | 
				
			||||||
 | 
					        self.assertEqual(self.image_data(images[0]), data)
 | 
				
			||||||
@@ -105,6 +105,9 @@ class FakeClient(object):
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class FakeClientManager(object):
 | 
					class FakeClientManager(object):
 | 
				
			||||||
 | 
					    _api_version = {
 | 
				
			||||||
 | 
					        'image': '2',
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def __init__(self):
 | 
					    def __init__(self):
 | 
				
			||||||
        self.compute = None
 | 
					        self.compute = None
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -0,0 +1,4 @@
 | 
				
			|||||||
 | 
					---
 | 
				
			||||||
 | 
					features:
 | 
				
			||||||
 | 
					  - |
 | 
				
			||||||
 | 
					    Add support for the ``server backup create`` command
 | 
				
			||||||
@@ -131,6 +131,8 @@ openstack.compute.v2 =
 | 
				
			|||||||
    server_unset = openstackclient.compute.v2.server:UnsetServer
 | 
					    server_unset = openstackclient.compute.v2.server:UnsetServer
 | 
				
			||||||
    server_unshelve = openstackclient.compute.v2.server:UnshelveServer
 | 
					    server_unshelve = openstackclient.compute.v2.server:UnshelveServer
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    server_backup_create = openstackclient.compute.v2.server_backup:CreateServerBackup
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    server_group_create = openstackclient.compute.v2.server_group:CreateServerGroup
 | 
					    server_group_create = openstackclient.compute.v2.server_group:CreateServerGroup
 | 
				
			||||||
    server_group_delete = openstackclient.compute.v2.server_group:DeleteServerGroup
 | 
					    server_group_delete = openstackclient.compute.v2.server_group:DeleteServerGroup
 | 
				
			||||||
    server_group_list = openstackclient.compute.v2.server_group:ListServerGroup
 | 
					    server_group_list = openstackclient.compute.v2.server_group:ListServerGroup
 | 
				
			||||||
 
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user