Skip to content

Commit eef2054

Browse files
author
Dean Troyer
committed
Move server image create command to its own resource file.
Change-Id: If37e82072bd7a32b81bfb1a8bb048f018dd5b04f
1 parent 3078540 commit eef2054

7 files changed

Lines changed: 346 additions & 224 deletions

File tree

doc/source/command-objects/server-image.rst

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ Compute v2
1010
server image create
1111
-------------------
1212

13-
Create a new disk image from a running server
13+
Create a new server disk image from an existing server
1414

1515
.. program:: server image create
1616
.. code:: bash
@@ -22,12 +22,12 @@ Create a new disk image from a running server
2222
2323
.. option:: --name <image-name>
2424

25-
Name of new image (default is server name)
25+
Name of new disk image (default: server name)
2626

2727
.. option:: --wait
2828

29-
Wait for image create to complete
29+
Wait for operation to complete
3030

3131
.. describe:: <server>
3232

33-
Server (name or ID)
33+
Server to create image (name or ID)

functional/tests/common/test_help.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,11 +19,12 @@ class HelpTests(test.TestCase):
1919
SERVER_COMMANDS = [
2020
('server add security group', 'Add security group to server'),
2121
('server add volume', 'Add volume to server'),
22+
('server backup create', 'Create a server backup image'),
2223
('server create', 'Create a new server'),
2324
('server delete', 'Delete server(s)'),
2425
('server dump create', 'Create a dump file in server(s)'),
2526
('server image create',
26-
'Create a new disk image from a running server'),
27+
'Create a new server disk image from an existing server'),
2728
('server list', 'List servers'),
2829
('server lock',
2930
'Lock server(s). '

openstackclient/compute/v2/server.py

Lines changed: 0 additions & 74 deletions
Original file line numberDiff line numberDiff line change
@@ -164,23 +164,6 @@ def _prep_server_detail(compute_client, server):
164164
return info
165165

166166

167-
def _prep_image_detail(image_client, image_id):
168-
"""Prepare the detailed image dict for printing
169-
170-
:param image_client: an image client instance
171-
:param image_id: id of image created
172-
:rtype: a dict of image details
173-
"""
174-
175-
info = utils.find_resource(
176-
image_client.images,
177-
image_id,
178-
)
179-
# Glance client V2 doesn't have _info attribute
180-
# The following condition deals with it.
181-
return getattr(info, "_info", info)
182-
183-
184167
def _show_progress(progress):
185168
if progress:
186169
sys.stdout.write('\rProgress: %s' % progress)
@@ -597,63 +580,6 @@ def take_action(self, parsed_args):
597580
).trigger_crash_dump()
598581

599582

600-
class CreateServerImage(command.ShowOne):
601-
"""Create a new disk image from a running server"""
602-
603-
def get_parser(self, prog_name):
604-
parser = super(CreateServerImage, self).get_parser(prog_name)
605-
parser.add_argument(
606-
'server',
607-
metavar='<server>',
608-
help=_('Server (name or ID)'),
609-
)
610-
parser.add_argument(
611-
'--name',
612-
metavar='<image-name>',
613-
help=_('Name of new image (default is server name)'),
614-
)
615-
parser.add_argument(
616-
'--wait',
617-
action='store_true',
618-
help=_('Wait for image create to complete'),
619-
)
620-
return parser
621-
622-
def take_action(self, parsed_args):
623-
compute_client = self.app.client_manager.compute
624-
image_client = self.app.client_manager.image
625-
server = utils.find_resource(
626-
compute_client.servers,
627-
parsed_args.server,
628-
)
629-
if parsed_args.name:
630-
name = parsed_args.name
631-
else:
632-
name = server.name
633-
634-
image_id = compute_client.servers.create_image(
635-
server,
636-
name,
637-
)
638-
639-
if parsed_args.wait:
640-
if utils.wait_for_status(
641-
image_client.images.get,
642-
image_id,
643-
callback=_show_progress,
644-
):
645-
sys.stdout.write('\n')
646-
else:
647-
self.log.error(_('Error creating snapshot of server: %s'),
648-
parsed_args.server)
649-
sys.stdout.write(_('Error creating server snapshot\n'))
650-
raise SystemExit
651-
652-
image = _prep_image_detail(image_client, image_id)
653-
654-
return zip(*sorted(six.iteritems(image)))
655-
656-
657583
class DeleteServer(command.Command):
658584
"""Delete server(s)"""
659585

Lines changed: 111 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,111 @@
1+
# Copyright 2012-2013 OpenStack Foundation
2+
#
3+
# Licensed under the Apache License, Version 2.0 (the "License"); you may
4+
# not use this file except in compliance with the License. You may obtain
5+
# a copy of the License at
6+
#
7+
# http://www.apache.org/licenses/LICENSE-2.0
8+
#
9+
# Unless required by applicable law or agreed to in writing, software
10+
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
11+
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
12+
# License for the specific language governing permissions and limitations
13+
# under the License.
14+
#
15+
16+
"""Compute v2 Server action implementations"""
17+
18+
import sys
19+
20+
from oslo_utils import importutils
21+
import six
22+
23+
from openstackclient.common import command
24+
from openstackclient.common import exceptions
25+
from openstackclient.common import utils
26+
from openstackclient.i18n import _
27+
28+
29+
def _show_progress(progress):
30+
if progress:
31+
sys.stdout.write('\rProgress: %s' % progress)
32+
sys.stdout.flush()
33+
34+
35+
class CreateServerImage(command.ShowOne):
36+
"""Create a new server disk image from an existing server"""
37+
38+
IMAGE_API_VERSIONS = {
39+
"1": "openstackclient.image.v1.image",
40+
"2": "openstackclient.image.v2.image",
41+
}
42+
43+
def get_parser(self, prog_name):
44+
parser = super(CreateServerImage, self).get_parser(prog_name)
45+
parser.add_argument(
46+
'server',
47+
metavar='<server>',
48+
help=_('Server to create image (name or ID)'),
49+
)
50+
parser.add_argument(
51+
'--name',
52+
metavar='<image-name>',
53+
help=_('Name of new disk image (default: server name)'),
54+
)
55+
parser.add_argument(
56+
'--wait',
57+
action='store_true',
58+
help=_('Wait for operation to complete'),
59+
)
60+
return parser
61+
62+
def take_action(self, parsed_args):
63+
compute_client = self.app.client_manager.compute
64+
65+
server = utils.find_resource(
66+
compute_client.servers,
67+
parsed_args.server,
68+
)
69+
if parsed_args.name:
70+
image_name = parsed_args.name
71+
else:
72+
image_name = server.name
73+
74+
image_id = compute_client.servers.create_image(
75+
server.id,
76+
image_name,
77+
)
78+
79+
image_client = self.app.client_manager.image
80+
image = utils.find_resource(
81+
image_client.images,
82+
image_id,
83+
)
84+
85+
if parsed_args.wait:
86+
if utils.wait_for_status(
87+
image_client.images.get,
88+
image_id,
89+
callback=_show_progress,
90+
):
91+
sys.stdout.write('\n')
92+
else:
93+
self.log.error(
94+
_('Error creating server image: %s') %
95+
parsed_args.server,
96+
)
97+
raise exceptions.CommandError
98+
99+
if self.app.client_manager._api_version['image'] == '1':
100+
info = {}
101+
info.update(image._info)
102+
info['properties'] = utils.format_dict(info.get('properties', {}))
103+
else:
104+
# Get the right image module to format the output
105+
image_module = importutils.import_module(
106+
self.IMAGE_API_VERSIONS[
107+
self.app.client_manager._api_version['image']
108+
]
109+
)
110+
info = image_module._format_image(image)
111+
return zip(*sorted(six.iteritems(info)))

openstackclient/tests/compute/v2/test_server.py

Lines changed: 0 additions & 144 deletions
Original file line numberDiff line numberDiff line change
@@ -509,150 +509,6 @@ def test_server_dump_multi_servers(self):
509509
self.run_method_with_servers('trigger_crash_dump', 3)
510510

511511

512-
class TestServerImageCreate(TestServer):
513-
514-
columns = (
515-
'id',
516-
'name',
517-
'owner',
518-
'protected',
519-
'tags',
520-
'visibility',
521-
)
522-
523-
def datalist(self):
524-
datalist = (
525-
self.image.id,
526-
self.image.name,
527-
self.image.owner,
528-
self.image.protected,
529-
self.image.tags,
530-
self.image.visibility,
531-
)
532-
return datalist
533-
534-
def setUp(self):
535-
super(TestServerImageCreate, self).setUp()
536-
537-
self.server = compute_fakes.FakeServer.create_one_server()
538-
539-
# This is the return value for utils.find_resource()
540-
self.servers_mock.get.return_value = self.server
541-
542-
self.image = image_fakes.FakeImage.create_one_image()
543-
self.images_mock.get.return_value = self.image
544-
self.servers_mock.create_image.return_value = self.image.id
545-
546-
# Get the command object to test
547-
self.cmd = server.CreateServerImage(self.app, None)
548-
549-
def test_server_image_create_no_options(self):
550-
arglist = [
551-
self.server.id,
552-
]
553-
verifylist = [
554-
('server', self.server.id),
555-
]
556-
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
557-
558-
# In base command class ShowOne in cliff, abstract method take_action()
559-
# returns a two-part tuple with a tuple of column names and a tuple of
560-
# data to be shown.
561-
columns, data = self.cmd.take_action(parsed_args)
562-
563-
# ServerManager.create_image(server, image_name, metadata=)
564-
self.servers_mock.create_image.assert_called_with(
565-
self.servers_mock.get.return_value,
566-
self.server.name,
567-
)
568-
569-
self.assertEqual(self.columns, columns)
570-
self.assertEqual(self.datalist(), data)
571-
572-
def test_server_image_create_name(self):
573-
arglist = [
574-
'--name', 'img-nam',
575-
self.server.id,
576-
]
577-
verifylist = [
578-
('name', 'img-nam'),
579-
('server', self.server.id),
580-
]
581-
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
582-
583-
# In base command class ShowOne in cliff, abstract method take_action()
584-
# returns a two-part tuple with a tuple of column names and a tuple of
585-
# data to be shown.
586-
columns, data = self.cmd.take_action(parsed_args)
587-
588-
# ServerManager.create_image(server, image_name, metadata=)
589-
self.servers_mock.create_image.assert_called_with(
590-
self.servers_mock.get.return_value,
591-
'img-nam',
592-
)
593-
594-
self.assertEqual(self.columns, columns)
595-
self.assertEqual(self.datalist(), data)
596-
597-
@mock.patch.object(common_utils, 'wait_for_status', return_value=False)
598-
def test_server_create_image_with_wait_fails(self, mock_wait_for_status):
599-
arglist = [
600-
'--wait',
601-
self.server.id,
602-
]
603-
verifylist = [
604-
('wait', True),
605-
('server', self.server.id),
606-
]
607-
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
608-
609-
self.assertRaises(SystemExit, self.cmd.take_action, parsed_args)
610-
611-
mock_wait_for_status.assert_called_once_with(
612-
self.images_mock.get,
613-
self.image.id,
614-
callback=server._show_progress
615-
)
616-
617-
# ServerManager.create_image(server, image_name, metadata=)
618-
self.servers_mock.create_image.assert_called_with(
619-
self.servers_mock.get.return_value,
620-
self.server.name,
621-
)
622-
623-
@mock.patch.object(common_utils, 'wait_for_status', return_value=True)
624-
def test_server_create_image_with_wait_ok(self, mock_wait_for_status):
625-
arglist = [
626-
'--wait',
627-
self.server.id,
628-
]
629-
verifylist = [
630-
('wait', True),
631-
('server', self.server.id),
632-
]
633-
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
634-
635-
# In base command class ShowOne in cliff, abstract method take_action()
636-
# returns a two-part tuple with a tuple of column names and a tuple of
637-
# data to be shown.
638-
columns, data = self.cmd.take_action(parsed_args)
639-
640-
# ServerManager.create_image(server, image_name, metadata=)
641-
self.servers_mock.create_image.assert_called_with(
642-
self.servers_mock.get.return_value,
643-
self.server.name,
644-
)
645-
646-
mock_wait_for_status.assert_called_once_with(
647-
self.images_mock.get,
648-
self.image.id,
649-
callback=server._show_progress
650-
)
651-
652-
self.assertEqual(self.columns, columns)
653-
self.assertEqual(self.datalist(), data)
654-
655-
656512
class TestServerList(TestServer):
657513

658514
# Columns to be listed up.

0 commit comments

Comments
 (0)