OpenstackClient plugin for stack adopt

This change implements the "openstack stack adopt" command.

Blueprint: heat-support-python-openstackclient

Change-Id: Id2e74970937c04f095b4f14be047cff6e2bf3891
This commit is contained in:
Steve Baker 2016-02-03 14:30:02 +13:00
parent 0a4f2af09c
commit f225c4e956
4 changed files with 184 additions and 0 deletions

View File

@ -20,6 +20,7 @@ from cliff import show
from openstackclient.common import exceptions as exc from openstackclient.common import exceptions as exc
from openstackclient.common import parseractions from openstackclient.common import parseractions
from openstackclient.common import utils from openstackclient.common import utils
from six.moves.urllib import request
from heatclient.common import http from heatclient.common import http
from heatclient.common import template_utils from heatclient.common import template_utils
@ -566,3 +567,88 @@ def _list(client, args=None):
columns, columns,
(utils.get_item_properties(s, columns) for s in data) (utils.get_item_properties(s, columns) for s in data)
) )
class AdoptStack(show.ShowOne):
"""Adopt a stack."""
log = logging.getLogger(__name__ + '.AdoptStack')
def get_parser(self, prog_name):
parser = super(AdoptStack, self).get_parser(prog_name)
parser.add_argument(
'name',
metavar='<STACK_NAME>',
help=_('Name of the stack to adopt')
)
parser.add_argument(
'-e', '--environment',
metavar='<FILE or URL>',
action='append',
help=_('Path to the environment. Can be specified multiple times')
)
parser.add_argument(
'--timeout',
metavar='<TIMEOUT>',
type=int,
help=_('Stack creation timeout in minutes')
)
parser.add_argument(
'--adopt-file',
metavar='<FILE or URL>',
required=True,
help=_('Path to adopt stack data file')
)
parser.add_argument(
'--enable-rollback',
action='store_true',
help=_('Enable rollback on create/update failure')
)
parser.add_argument(
'--parameter',
metavar='<KEY=VALUE>',
action='append',
help=_('Parameter values used to create the stack. Can be '
'specified multiple times')
)
parser.add_argument(
'--wait',
action='store_true',
help=_('Wait until stack adopt completes')
)
return parser
def take_action(self, parsed_args):
self.log.debug('take_action(%s)', parsed_args)
client = self.app.client_manager.orchestration
env_files, env = (
template_utils.process_multiple_environments_and_files(
env_paths=parsed_args.environment))
adopt_url = heat_utils.normalise_file_path_to_url(
parsed_args.adopt_file)
adopt_data = request.urlopen(adopt_url).read().decode('utf-8')
fields = {
'stack_name': parsed_args.name,
'disable_rollback': not parsed_args.enable_rollback,
'adopt_stack_data': adopt_data,
'parameters': heat_utils.format_parameters(parsed_args.parameter),
'files': dict(list(env_files.items())),
'environment': env,
'timeout': parsed_args.timeout
}
stack = client.stacks.create(**fields)['stack']
if parsed_args.wait:
if not utils.wait_for_status(client.stacks.get, parsed_args.name,
status_field='stack_status',
success_status='create_complete',
error_status=['create_failed']):
msg = _('Stack %s failed to create.') % parsed_args.name
raise exc.CommandError(msg)
return _show_stack(client, stack['id'], format='table', short=True)

View File

@ -0,0 +1,32 @@
{
'files': {},
'status': 'COMPLETE',
'name': 'my_stack',
'tags': None,
'stack_user_project_id': '123456',
'environment': {},
'template': {
'heat_template_version': '2016-04-08',
'resources': {
'thing': {
'type': 'OS::Heat::TestResource'
}
}
},
'action': 'CREATE',
'project_id': '56789',
'id': '2468',
'resources': {
'thing': {
'status': 'COMPLETE',
'name': 'thing',
'resource_data': {
'value': 'test_string',
},
'resource_id': 'my_stack-thing-1234',
'action': 'CREATE',
'type': 'OS::Heat::TestResource',
'metadata': {}
}
}
}

View File

@ -520,3 +520,68 @@ class TestStackList(TestStack):
parsed_args = self.check_parser(self.cmd, arglist, []) parsed_args = self.check_parser(self.cmd, arglist, [])
self.assertRaises(exc.CommandError, self.cmd.take_action, parsed_args) self.assertRaises(exc.CommandError, self.cmd.take_action, parsed_args)
class TestStackAdopt(TestStack):
adopt_file = 'heatclient/tests/test_templates/adopt.json'
with open(adopt_file, 'r') as f:
adopt_data = f.read()
defaults = {
'stack_name': 'my_stack',
'disable_rollback': True,
'adopt_stack_data': adopt_data,
'parameters': {},
'files': {},
'environment': {},
'timeout': None
}
def setUp(self):
super(TestStackAdopt, self).setUp()
self.cmd = stack.AdoptStack(self.app, None)
self.stack_client.create = mock.MagicMock(
return_value={'stack': {'id': '1234'}})
def test_stack_adopt_defaults(self):
arglist = ['my_stack', '--adopt-file', self.adopt_file]
cols = ['id', 'stack_name', 'description', 'creation_time',
'updated_time', 'stack_status', 'stack_status_reason']
parsed_args = self.check_parser(self.cmd, arglist, [])
columns, data = self.cmd.take_action(parsed_args)
self.stack_client.create.assert_called_with(**self.defaults)
self.assertEqual(cols, columns)
def test_stack_adopt_enable_rollback(self):
arglist = ['my_stack', '--adopt-file', self.adopt_file,
'--enable-rollback']
kwargs = copy.deepcopy(self.defaults)
kwargs['disable_rollback'] = False
parsed_args = self.check_parser(self.cmd, arglist, [])
self.cmd.take_action(parsed_args)
self.stack_client.create.assert_called_with(**kwargs)
def test_stack_adopt_wait(self):
arglist = ['my_stack', '--adopt-file', self.adopt_file, '--wait']
self.stack_client.get = mock.MagicMock(return_value=(
stacks.Stack(None, {'stack_status': 'CREATE_COMPLETE'})))
parsed_args = self.check_parser(self.cmd, arglist, [])
self.cmd.take_action(parsed_args)
self.stack_client.create.assert_called_with(**self.defaults)
self.stack_client.get.assert_called_with(**{'stack_id': '1234'})
def test_stack_adopt_wait_fail(self):
arglist = ['my_stack', '--adopt-file', self.adopt_file, '--wait']
self.stack_client.get = mock.MagicMock(return_value=(
stacks.Stack(None, {'stack_status': 'CREATE_FAILED'})))
parsed_args = self.check_parser(self.cmd, arglist, [])
self.assertRaises(exc.CommandError, self.cmd.take_action, parsed_args)

View File

@ -35,6 +35,7 @@ openstack.orchestration.v1 =
stack_create = heatclient.osc.v1.stack:CreateStack stack_create = heatclient.osc.v1.stack:CreateStack
stack_update = heatclient.osc.v1.stack:UpdateStack stack_update = heatclient.osc.v1.stack:UpdateStack
stack_snapshot_list = heatclient.osc.v1.snapshot:ListSnapshot stack_snapshot_list = heatclient.osc.v1.snapshot:ListSnapshot
stack_adopt = heatclient.osc.v1.stack:AdoptStack
[global] [global]