diff options
author | Jenkins <jenkins@review.openstack.org> | 2013-11-20 06:37:25 +0000 |
---|---|---|
committer | Gerrit Code Review <review@openstack.org> | 2013-11-20 06:37:25 +0000 |
commit | d45187a0c163187649e29931d21c4607379d1e73 (patch) | |
tree | a693cd9d92735a2e0ec750c79563978a95b0bca5 | |
parent | b70b1d04e447bb3748fcfd8cf25794fb8ea64b65 (diff) | |
parent | 200ed62054847336235288c7785424be416bed06 (diff) | |
download | python-openstackclient-d45187a0c163187649e29931d21c4607379d1e73.tar.gz |
Merge "Add server image create command"
-rw-r--r-- | openstackclient/compute/v2/server.py | 67 | ||||
-rw-r--r-- | openstackclient/tests/compute/v2/fakes.py | 13 | ||||
-rw-r--r-- | openstackclient/tests/compute/v2/test_server.py | 91 | ||||
-rw-r--r-- | openstackclient/tests/image/v2/fakes.py | 5 | ||||
-rw-r--r-- | setup.cfg | 1 |
5 files changed, 169 insertions, 8 deletions
diff --git a/openstackclient/compute/v2/server.py b/openstackclient/compute/v2/server.py index 1de9f1ba..87f5f689 100644 --- a/openstackclient/compute/v2/server.py +++ b/openstackclient/compute/v2/server.py @@ -384,6 +384,73 @@ class CreateServer(show.ShowOne): return zip(*sorted(six.iteritems(details))) +class CreateServerImage(show.ShowOne): + """Create a new disk image from a running server""" + + log = logging.getLogger(__name__ + '.CreateServerImage') + + def get_parser(self, prog_name): + parser = super(CreateServerImage, self).get_parser(prog_name) + parser.add_argument( + 'server', + metavar='<server', + help='Server (name or ID)', + ) + parser.add_argument( + '--name', + metavar='<image-name>', + help='Name of new image (default is server name)', + ) + parser.add_argument( + '--wait', + action='store_true', + help='Wait for image create to complete', + ) + return parser + + def take_action(self, parsed_args): + self.log.debug('take_action(%s)' % parsed_args) + compute_client = self.app.client_manager.compute + image_client = self.app.client_manager.image + server = utils.find_resource( + compute_client.servers, + parsed_args.server, + ) + if parsed_args.name: + name = parsed_args.name + else: + name = server.name + + image = compute_client.servers.create_image( + server, + name, + ) + + if parsed_args.wait: + if utils.wait_for_status( + image_client.images.get, + image, + callback=_show_progress, + ): + sys.stdout.write('\n') + else: + self.log.error( + 'Error creating server snapshot: %s' % + parsed_args.image_name, + ) + sys.stdout.write('\nError creating server snapshot') + raise SystemExit + + image = utils.find_resource( + image_client.images, + image.id, + ) + + info = {} + info.update(image._info) + return zip(*sorted(six.iteritems(info))) + + class DeleteServer(command.Command): """Delete server command""" diff --git a/openstackclient/tests/compute/v2/fakes.py b/openstackclient/tests/compute/v2/fakes.py index 8154449f..03ebd67c 100644 --- a/openstackclient/tests/compute/v2/fakes.py +++ b/openstackclient/tests/compute/v2/fakes.py @@ -16,16 +16,10 @@ import mock from openstackclient.tests import fakes +from openstackclient.tests.image.v2 import fakes as image_fakes from openstackclient.tests import utils -image_id = 'im1' - -IMAGE = { - 'id': image_id, -} - - server_id = 'serv1' server_name = 'waiter' @@ -53,3 +47,8 @@ class TestComputev2(utils.TestCommand): endpoint=fakes.AUTH_URL, token=fakes.AUTH_TOKEN, ) + + self.app.client_manager.image = image_fakes.FakeImagev2Client( + endpoint=fakes.AUTH_URL, + token=fakes.AUTH_TOKEN, + ) diff --git a/openstackclient/tests/compute/v2/test_server.py b/openstackclient/tests/compute/v2/test_server.py index 7e68808e..4cd294cc 100644 --- a/openstackclient/tests/compute/v2/test_server.py +++ b/openstackclient/tests/compute/v2/test_server.py @@ -18,6 +18,7 @@ import copy from openstackclient.compute.v2 import server from openstackclient.tests.compute.v2 import fakes as compute_fakes from openstackclient.tests import fakes +from openstackclient.tests.image.v2 import fakes as image_fakes class TestServer(compute_fakes.TestComputev2): @@ -29,6 +30,10 @@ class TestServer(compute_fakes.TestComputev2): self.servers_mock = self.app.client_manager.compute.servers self.servers_mock.reset_mock() + # Get a shortcut to the ImageManager Mock + self.images_mock = self.app.client_manager.image.images + self.images_mock.reset_mock() + class TestServerDelete(TestServer): @@ -61,3 +66,89 @@ class TestServerDelete(TestServer): self.servers_mock.delete.assert_called_with( compute_fakes.server_id, ) + + +class TestServerImageCreate(TestServer): + + def setUp(self): + super(TestServerImageCreate, self).setUp() + + # This is the return value for utils.find_resource() + self.servers_mock.get.return_value = fakes.FakeResource( + None, + copy.deepcopy(compute_fakes.SERVER), + loaded=True, + ) + + self.servers_mock.create_image.return_value = fakes.FakeResource( + None, + copy.deepcopy(image_fakes.IMAGE), + loaded=True, + ) + + self.images_mock.get.return_value = fakes.FakeResource( + None, + copy.deepcopy(image_fakes.IMAGE), + loaded=True, + ) + + # Get the command object to test + self.cmd = server.CreateServerImage(self.app, None) + + def test_server_image_create_no_options(self): + arglist = [ + compute_fakes.server_id, + ] + verifylist = [ + ('server', compute_fakes.server_id), + ] + parsed_args = self.check_parser(self.cmd, arglist, verifylist) + + # DisplayCommandBase.take_action() returns two tuples + columns, data = self.cmd.take_action(parsed_args) + + # ServerManager.create_image(server, image_name, metadata=) + self.servers_mock.create_image.assert_called_with( + self.servers_mock.get.return_value, + compute_fakes.server_name, + ) + + collist = ('id', 'is_public', 'name', 'owner') + self.assertEqual(columns, collist) + datalist = ( + image_fakes.image_id, + False, + image_fakes.image_name, + image_fakes.image_owner, + ) + self.assertEqual(data, datalist) + + def test_server_image_create_name(self): + arglist = [ + '--name', 'img-nam', + compute_fakes.server_id, + ] + verifylist = [ + ('name', 'img-nam'), + ('server', compute_fakes.server_id), + ] + parsed_args = self.check_parser(self.cmd, arglist, verifylist) + + # DisplayCommandBase.take_action() returns two tuples + columns, data = self.cmd.take_action(parsed_args) + + # ServerManager.create_image(server, image_name, metadata=) + self.servers_mock.create_image.assert_called_with( + self.servers_mock.get.return_value, + 'img-nam', + ) + + collist = ('id', 'is_public', 'name', 'owner') + self.assertEqual(columns, collist) + datalist = ( + image_fakes.image_id, + False, + image_fakes.image_name, + image_fakes.image_owner, + ) + self.assertEqual(data, datalist) diff --git a/openstackclient/tests/image/v2/fakes.py b/openstackclient/tests/image/v2/fakes.py index df6b8072..96255cd4 100644 --- a/openstackclient/tests/image/v2/fakes.py +++ b/openstackclient/tests/image/v2/fakes.py @@ -21,10 +21,13 @@ from openstackclient.tests import utils image_id = 'im1' image_name = 'graven' +image_owner = 'baal' IMAGE = { 'id': image_id, - 'name': image_name + 'name': image_name, + 'is_public': False, + 'owner': image_owner, } @@ -94,6 +94,7 @@ openstack.compute.v2 = server_add_volume = openstackclient.compute.v2.server:AddServerVolume server_create = openstackclient.compute.v2.server:CreateServer server_delete = openstackclient.compute.v2.server:DeleteServer + server_image_create = openstackclient.compute.v2.server:CreateServerImage server_list = openstackclient.compute.v2.server:ListServer server_lock = openstackclient.compute.v2.server:LockServer server_migrate = openstackclient.compute.v2.server:MigrateServer |