Heat Stack update view/form
2 Part view for updating Heat Templates. The first page allows you to select a new template for your stack. The second allows you to set new template parameters for your stack. Like the launch stack workflow, this is not a horizon workflow, but two separate forms. Implements: blueprint heat-stack-update Change-Id: I2854e9e4bb578be5187ef962808b93f11ac6b1f1
This commit is contained in:
parent
d4fb9c49de
commit
eabc890792
|
@ -64,10 +64,20 @@ def stack_get(request, stack_id):
|
||||||
return heatclient(request).stacks.get(stack_id)
|
return heatclient(request).stacks.get(stack_id)
|
||||||
|
|
||||||
|
|
||||||
|
def template_get(request, stack_id):
|
||||||
|
return heatclient(request).stacks.template(stack_id)
|
||||||
|
|
||||||
|
|
||||||
def stack_create(request, password=None, **kwargs):
|
def stack_create(request, password=None, **kwargs):
|
||||||
return heatclient(request, password).stacks.create(**kwargs)
|
return heatclient(request, password).stacks.create(**kwargs)
|
||||||
|
|
||||||
|
|
||||||
|
def stack_update(request, stack_id, **kwargs):
|
||||||
|
if kwargs.get('password'):
|
||||||
|
kwargs.pop('password')
|
||||||
|
return heatclient(request).stacks.update(stack_id, **kwargs)
|
||||||
|
|
||||||
|
|
||||||
def events_list(request, stack_name):
|
def events_list(request, stack_name):
|
||||||
return heatclient(request).events.list(stack_name)
|
return heatclient(request).events.list(stack_name)
|
||||||
|
|
||||||
|
|
|
@ -145,18 +145,39 @@ class TemplateForm(forms.SelfHandlingForm):
|
||||||
|
|
||||||
return cleaned
|
return cleaned
|
||||||
|
|
||||||
def handle(self, request, data):
|
def create_kwargs(self, data):
|
||||||
kwargs = {'parameters': data['template_validate'],
|
kwargs = {'parameters': data['template_validate'],
|
||||||
'template_data': data['template_data'],
|
'template_data': data['template_data'],
|
||||||
'template_url': data['template_url']}
|
'template_url': data['template_url']}
|
||||||
|
if data.get('stack_id'):
|
||||||
|
kwargs['stack_id'] = data['stack_id']
|
||||||
|
return kwargs
|
||||||
|
|
||||||
|
def handle(self, request, data):
|
||||||
|
kwargs = self.create_kwargs(data)
|
||||||
# NOTE (gabriel): This is a bit of a hack, essentially rewriting this
|
# NOTE (gabriel): This is a bit of a hack, essentially rewriting this
|
||||||
# request so that we can chain it as an input to the next view...
|
# request so that we can chain it as an input to the next view...
|
||||||
# but hey, it totally works.
|
# but hey, it totally works.
|
||||||
request.method = 'GET'
|
request.method = 'GET'
|
||||||
|
|
||||||
return self.next_view.as_view()(request, **kwargs)
|
return self.next_view.as_view()(request, **kwargs)
|
||||||
|
|
||||||
|
|
||||||
class StackCreateForm(forms.SelfHandlingForm):
|
class ChangeTemplateForm(TemplateForm):
|
||||||
|
class Meta:
|
||||||
|
name = _('Edit Template')
|
||||||
|
help_text = _('From here you can select a new template to re-launch '
|
||||||
|
'a stack.')
|
||||||
|
stack_id = forms.CharField(label=_('Stack ID'),
|
||||||
|
widget=forms.widgets.HiddenInput,
|
||||||
|
required=True)
|
||||||
|
stack_name = forms.CharField(label=_('Stack Name'),
|
||||||
|
widget=forms.TextInput(
|
||||||
|
attrs={'readonly': 'readonly'}
|
||||||
|
))
|
||||||
|
|
||||||
|
|
||||||
|
class CreateStackForm(forms.SelfHandlingForm):
|
||||||
|
|
||||||
param_prefix = '__param_'
|
param_prefix = '__param_'
|
||||||
|
|
||||||
|
@ -193,11 +214,13 @@ class StackCreateForm(forms.SelfHandlingForm):
|
||||||
|
|
||||||
def __init__(self, *args, **kwargs):
|
def __init__(self, *args, **kwargs):
|
||||||
parameters = kwargs.pop('parameters')
|
parameters = kwargs.pop('parameters')
|
||||||
super(StackCreateForm, self).__init__(*args, **kwargs)
|
# special case: load template data from API, not passed in params
|
||||||
|
if(kwargs.get('validate_me')):
|
||||||
|
parameters = kwargs.pop('validate_me')
|
||||||
|
super(CreateStackForm, self).__init__(*args, **kwargs)
|
||||||
self._build_parameter_fields(parameters)
|
self._build_parameter_fields(parameters)
|
||||||
|
|
||||||
def _build_parameter_fields(self, template_validate):
|
def _build_parameter_fields(self, template_validate):
|
||||||
|
|
||||||
self.fields['password'] = forms.CharField(
|
self.fields['password'] = forms.CharField(
|
||||||
label=_('Password for user "%s"') % self.request.user.username,
|
label=_('Password for user "%s"') % self.request.user.username,
|
||||||
help_text=_('This is required for operations to be performed '
|
help_text=_('This is required for operations to be performed '
|
||||||
|
@ -267,3 +290,49 @@ class StackCreateForm(forms.SelfHandlingForm):
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
msg = exception_to_validation_msg(e)
|
msg = exception_to_validation_msg(e)
|
||||||
exceptions.handle(request, msg or _('Stack creation failed.'))
|
exceptions.handle(request, msg or _('Stack creation failed.'))
|
||||||
|
|
||||||
|
|
||||||
|
class EditStackForm(CreateStackForm):
|
||||||
|
|
||||||
|
class Meta:
|
||||||
|
name = _('Update Stack Parameters')
|
||||||
|
|
||||||
|
stack_id = forms.CharField(label=_('Stack ID'),
|
||||||
|
widget=forms.widgets.HiddenInput,
|
||||||
|
required=True)
|
||||||
|
stack_name = forms.CharField(label=_('Stack Name'),
|
||||||
|
widget=forms.TextInput(
|
||||||
|
attrs={'readonly': 'readonly'}
|
||||||
|
))
|
||||||
|
|
||||||
|
@sensitive_variables('password')
|
||||||
|
def handle(self, request, data):
|
||||||
|
prefix_length = len(self.param_prefix)
|
||||||
|
params_list = [(k[prefix_length:], v) for (k, v) in data.iteritems()
|
||||||
|
if k.startswith(self.param_prefix)]
|
||||||
|
|
||||||
|
stack_id = data.get('stack_id')
|
||||||
|
fields = {
|
||||||
|
'stack_name': data.get('stack_name'),
|
||||||
|
'timeout_mins': data.get('timeout_mins'),
|
||||||
|
'disable_rollback': not(data.get('enable_rollback')),
|
||||||
|
'parameters': dict(params_list),
|
||||||
|
'password': data.get('password')
|
||||||
|
}
|
||||||
|
|
||||||
|
# if the user went directly to this form, resubmit the existing
|
||||||
|
# template data. otherwise, submit what they had from the first form
|
||||||
|
if data.get('template_data'):
|
||||||
|
fields['template'] = data.get('template_data')
|
||||||
|
elif data.get('template_url'):
|
||||||
|
fields['template_url'] = data.get('template_url')
|
||||||
|
elif data.get('parameters'):
|
||||||
|
fields['template'] = data.get('parameters')
|
||||||
|
|
||||||
|
try:
|
||||||
|
api.heat.stack_update(self.request, stack_id=stack_id, **fields)
|
||||||
|
messages.success(request, _("Stack update started."))
|
||||||
|
return True
|
||||||
|
except Exception as e:
|
||||||
|
msg = exception_to_validation_msg(e)
|
||||||
|
exceptions.handle(request, msg or _('Stack update failed.'))
|
||||||
|
|
|
@ -12,9 +12,11 @@
|
||||||
# License for the specific language governing permissions and limitations
|
# License for the specific language governing permissions and limitations
|
||||||
# under the License.
|
# under the License.
|
||||||
|
|
||||||
|
from django.core import urlresolvers
|
||||||
from django.http import Http404 # noqa
|
from django.http import Http404 # noqa
|
||||||
from django.template.defaultfilters import timesince # noqa
|
from django.template.defaultfilters import timesince # noqa
|
||||||
from django.template.defaultfilters import title # noqa
|
from django.template.defaultfilters import title # noqa
|
||||||
|
from django.utils.http import urlencode # noqa
|
||||||
from django.utils.translation import ugettext_lazy as _
|
from django.utils.translation import ugettext_lazy as _
|
||||||
|
|
||||||
from horizon import messages
|
from horizon import messages
|
||||||
|
@ -34,6 +36,16 @@ class LaunchStack(tables.LinkAction):
|
||||||
classes = ("btn-create", "ajax-modal")
|
classes = ("btn-create", "ajax-modal")
|
||||||
|
|
||||||
|
|
||||||
|
class ChangeStackTemplate(tables.LinkAction):
|
||||||
|
name = "edit"
|
||||||
|
verbose_name = _("Change Stack Template")
|
||||||
|
url = "horizon:project:stacks:change_template"
|
||||||
|
classes = ("ajax-modal", "btn-edit")
|
||||||
|
|
||||||
|
def get_link_url(self, stack):
|
||||||
|
return urlresolvers.reverse(self.url, args=[stack.id])
|
||||||
|
|
||||||
|
|
||||||
class DeleteStack(tables.BatchAction):
|
class DeleteStack(tables.BatchAction):
|
||||||
name = "delete"
|
name = "delete"
|
||||||
action_present = _("Delete")
|
action_present = _("Delete")
|
||||||
|
@ -100,7 +112,8 @@ class StacksTable(tables.DataTable):
|
||||||
status_columns = ["status", ]
|
status_columns = ["status", ]
|
||||||
row_class = StacksUpdateRow
|
row_class = StacksUpdateRow
|
||||||
table_actions = (LaunchStack, DeleteStack,)
|
table_actions = (LaunchStack, DeleteStack,)
|
||||||
row_actions = (DeleteStack, )
|
row_actions = (DeleteStack,
|
||||||
|
ChangeStackTemplate)
|
||||||
|
|
||||||
|
|
||||||
class EventsTable(tables.DataTable):
|
class EventsTable(tables.DataTable):
|
||||||
|
|
|
@ -0,0 +1,28 @@
|
||||||
|
{% extends "horizon/common/_modal_form.html" %}
|
||||||
|
{% load i18n %}
|
||||||
|
{% load url from future %}
|
||||||
|
|
||||||
|
{% block form_id %}select_template{% endblock %}
|
||||||
|
{% block form_action %}{% url 'horizon:project:stacks:change_template' stack.id%}{% endblock %}
|
||||||
|
{% block form_attrs %}enctype="multipart/form-data"{% endblock %}
|
||||||
|
|
||||||
|
{% block modal-header %}{% trans "Select Template" %}{% endblock %}
|
||||||
|
{% block modal_id %}select_template_modal{% endblock %}
|
||||||
|
|
||||||
|
{% block modal-body %}
|
||||||
|
<div class="left">
|
||||||
|
<fieldset>
|
||||||
|
{% include "horizon/common/_form_fields.html" %}
|
||||||
|
</fieldset>
|
||||||
|
</div>
|
||||||
|
<div class="right">
|
||||||
|
<h3>{% trans "Description" %}:</h3>
|
||||||
|
<p>{% trans "Use one of the available template source options to specify the template to be used in creating this stack." %}</p>
|
||||||
|
</div>
|
||||||
|
{% endblock %}
|
||||||
|
|
||||||
|
{% block modal-footer %}
|
||||||
|
<input class="btn btn-primary pull-right" type="submit" value="{% trans "Next" %}" />
|
||||||
|
<a href="{% url 'horizon:project:stacks:index' %}" class="btn secondary cancel close">{% trans "Cancel" %}</a>
|
||||||
|
{% endblock %}
|
||||||
|
|
|
@ -0,0 +1,26 @@
|
||||||
|
{% extends "horizon/common/_modal_form.html" %}
|
||||||
|
{% load i18n %}
|
||||||
|
{% load url from future %}
|
||||||
|
|
||||||
|
{% block form_id %}update_stack{% endblock %}
|
||||||
|
{% block form_action %}{% url 'horizon:project:stacks:edit_stack' stack.id %}{% endblock %}
|
||||||
|
|
||||||
|
{% block modal-header %}{% trans "Update Stack Parameters" %}{% endblock %}
|
||||||
|
{% block modal_id %}update_stack_modal{% endblock %}
|
||||||
|
|
||||||
|
{% block modal-body %}
|
||||||
|
<div class="left">
|
||||||
|
<fieldset>
|
||||||
|
{% include "horizon/common/_form_fields.html" %}
|
||||||
|
</fieldset>
|
||||||
|
</div>
|
||||||
|
<div class="right">
|
||||||
|
<h3>{% trans "Description" %}:</h3>
|
||||||
|
<p>{% trans "Update a stack with the provided values. Please note that any encrypted parameters, such as passwords, will be reset to default if you don't change them here." %}</p>
|
||||||
|
</div>
|
||||||
|
{% endblock %}
|
||||||
|
|
||||||
|
{% block modal-footer %}
|
||||||
|
<input class="btn btn-primary pull-right" type="submit" value="{% trans "Update" %}" />
|
||||||
|
<a href="{% url 'horizon:project:stacks:index' %}" class="btn secondary cancel close">{% trans "Cancel" %}</a>
|
||||||
|
{% endblock %}
|
|
@ -0,0 +1,12 @@
|
||||||
|
{% extends 'base.html' %}
|
||||||
|
{% load i18n %}
|
||||||
|
{% block title %}{% trans "Change Template" %}{% endblock %}
|
||||||
|
|
||||||
|
{% block page_header %}
|
||||||
|
{% include "horizon/common/_page_header.html" with title=_("Change Template") %}
|
||||||
|
{% endblock page_header %}
|
||||||
|
|
||||||
|
{% block main %}
|
||||||
|
{% include 'project/stacks/_change_template.html' %}
|
||||||
|
{% endblock %}
|
||||||
|
|
|
@ -0,0 +1,11 @@
|
||||||
|
{% extends 'base.html' %}
|
||||||
|
{% load i18n %}
|
||||||
|
{% block title %}{% trans "Update Stack Parameters" %}{% endblock %}
|
||||||
|
|
||||||
|
{% block page_header %}
|
||||||
|
{% include "horizon/common/_page_header.html" with title=_("Update Stack") %}
|
||||||
|
{% endblock page_header %}
|
||||||
|
|
||||||
|
{% block main %}
|
||||||
|
{% include 'project/stacks/_update.html' %}
|
||||||
|
{% endblock %}
|
|
@ -151,7 +151,76 @@ class StackTests(test.TestCase):
|
||||||
"__param_DBPassword": "admin",
|
"__param_DBPassword": "admin",
|
||||||
"__param_DBRootPassword": "admin",
|
"__param_DBRootPassword": "admin",
|
||||||
"__param_DBName": "wordpress",
|
"__param_DBName": "wordpress",
|
||||||
'method': forms.StackCreateForm.__name__}
|
'method': forms.CreateStackForm.__name__}
|
||||||
|
res = self.client.post(url, form_data)
|
||||||
|
self.assertRedirectsNoFollow(res, INDEX_URL)
|
||||||
|
|
||||||
|
@test.create_stubs({api.heat: ('stack_update', 'stack_get',
|
||||||
|
'template_get', 'template_validate')})
|
||||||
|
def test_edit_stack_template(self):
|
||||||
|
template = self.stack_templates.first()
|
||||||
|
stack = self.stacks.first()
|
||||||
|
|
||||||
|
# GET to template form
|
||||||
|
api.heat.stack_get(IsA(http.HttpRequest),
|
||||||
|
stack.id).AndReturn(stack)
|
||||||
|
# POST template form, validation
|
||||||
|
api.heat.template_validate(IsA(http.HttpRequest),
|
||||||
|
template=template.data) \
|
||||||
|
.AndReturn(json.loads(template.validate))
|
||||||
|
|
||||||
|
# GET to edit form
|
||||||
|
api.heat.stack_get(IsA(http.HttpRequest),
|
||||||
|
stack.id).AndReturn(stack)
|
||||||
|
api.heat.template_get(IsA(http.HttpRequest),
|
||||||
|
stack.id) \
|
||||||
|
.AndReturn(json.loads(template.validate))
|
||||||
|
|
||||||
|
# POST to edit form
|
||||||
|
api.heat.stack_get(IsA(http.HttpRequest),
|
||||||
|
stack.id).AndReturn(stack)
|
||||||
|
|
||||||
|
fields = {
|
||||||
|
'stack_name': stack.stack_name,
|
||||||
|
'disable_rollback': True,
|
||||||
|
'timeout_mins': 61,
|
||||||
|
'password': 'password',
|
||||||
|
'template': IsA(unicode),
|
||||||
|
'parameters': IsA(dict)
|
||||||
|
}
|
||||||
|
api.heat.stack_update(IsA(http.HttpRequest),
|
||||||
|
stack_id=stack.id,
|
||||||
|
**fields)
|
||||||
|
self.mox.ReplayAll()
|
||||||
|
|
||||||
|
url = reverse('horizon:project:stacks:change_template',
|
||||||
|
args=[stack.id])
|
||||||
|
res = self.client.get(url)
|
||||||
|
self.assertTemplateUsed(res, 'project/stacks/change_template.html')
|
||||||
|
|
||||||
|
form_data = {'template_source': 'raw',
|
||||||
|
'template_data': template.data,
|
||||||
|
'method': forms.ChangeTemplateForm.__name__}
|
||||||
|
res = self.client.post(url, form_data)
|
||||||
|
|
||||||
|
url = reverse('horizon:project:stacks:edit_stack',
|
||||||
|
args=[stack.id, ])
|
||||||
|
form_data = {'template_source': 'raw',
|
||||||
|
'template_data': template.data,
|
||||||
|
'password': 'password',
|
||||||
|
'parameters': template.validate,
|
||||||
|
'stack_name': stack.stack_name,
|
||||||
|
'stack_id': stack.id,
|
||||||
|
"timeout_mins": 61,
|
||||||
|
"disable_rollback": True,
|
||||||
|
"__param_DBUsername": "admin",
|
||||||
|
"__param_LinuxDistribution": "F17",
|
||||||
|
"__param_InstanceType": "m1.small",
|
||||||
|
"__param_KeyName": "test",
|
||||||
|
"__param_DBPassword": "admin",
|
||||||
|
"__param_DBRootPassword": "admin",
|
||||||
|
"__param_DBName": "wordpress",
|
||||||
|
'method': forms.EditStackForm.__name__}
|
||||||
res = self.client.post(url, form_data)
|
res = self.client.post(url, form_data)
|
||||||
self.assertRedirectsNoFollow(res, INDEX_URL)
|
self.assertRedirectsNoFollow(res, INDEX_URL)
|
||||||
|
|
||||||
|
@ -177,7 +246,7 @@ class StackTests(test.TestCase):
|
||||||
"__param_DBPassword": "admin",
|
"__param_DBPassword": "admin",
|
||||||
"__param_DBRootPassword": "admin",
|
"__param_DBRootPassword": "admin",
|
||||||
"__param_DBName": "wordpress",
|
"__param_DBName": "wordpress",
|
||||||
'method': forms.StackCreateForm.__name__}
|
'method': forms.CreateStackForm.__name__}
|
||||||
|
|
||||||
res = self.client.post(url, form_data)
|
res = self.client.post(url, form_data)
|
||||||
error = ('Name must start with a letter and may only contain letters, '
|
error = ('Name must start with a letter and may only contain letters, '
|
||||||
|
|
|
@ -26,6 +26,10 @@ urlpatterns = patterns(
|
||||||
url(r'^launch$', views.CreateStackView.as_view(), name='launch'),
|
url(r'^launch$', views.CreateStackView.as_view(), name='launch'),
|
||||||
url(r'^stack/(?P<stack_id>[^/]+)/$',
|
url(r'^stack/(?P<stack_id>[^/]+)/$',
|
||||||
views.DetailView.as_view(), name='detail'),
|
views.DetailView.as_view(), name='detail'),
|
||||||
|
url(r'^(?P<stack_id>[^/]+)/change_template$',
|
||||||
|
views.ChangeTemplateView.as_view(), name='change_template'),
|
||||||
|
url(r'^(?P<stack_id>[^/]+)/edit_stack$',
|
||||||
|
views.EditStackView.as_view(), name='edit_stack'),
|
||||||
url(r'^stack/(?P<stack_id>[^/]+)/(?P<resource_name>[^/]+)/$',
|
url(r'^stack/(?P<stack_id>[^/]+)/(?P<resource_name>[^/]+)/$',
|
||||||
views.ResourceView.as_view(), name='resource'),
|
views.ResourceView.as_view(), name='resource'),
|
||||||
url(r'^get_d3_data/(?P<stack_id>[^/]+)/$',
|
url(r'^get_d3_data/(?P<stack_id>[^/]+)/$',
|
||||||
|
|
|
@ -67,8 +67,41 @@ class SelectTemplateView(forms.ModalFormView):
|
||||||
return kwargs
|
return kwargs
|
||||||
|
|
||||||
|
|
||||||
|
class ChangeTemplateView(forms.ModalFormView):
|
||||||
|
form_class = project_forms.ChangeTemplateForm
|
||||||
|
template_name = 'project/stacks/change_template.html'
|
||||||
|
success_url = reverse_lazy('horizon:project:stacks:edit_stack')
|
||||||
|
|
||||||
|
def get_context_data(self, **kwargs):
|
||||||
|
context = super(ChangeTemplateView, self).get_context_data(**kwargs)
|
||||||
|
context['stack'] = self.get_object()
|
||||||
|
return context
|
||||||
|
|
||||||
|
@memoized.memoized_method
|
||||||
|
def get_object(self):
|
||||||
|
stack_id = self.kwargs['stack_id']
|
||||||
|
try:
|
||||||
|
self._stack = api.heat.stack_get(self.request, stack_id)
|
||||||
|
except Exception:
|
||||||
|
msg = _("Unable to retrieve stack.")
|
||||||
|
redirect = reverse('horizon:project:stacks:index')
|
||||||
|
exceptions.handle(self.request, msg, redirect=redirect)
|
||||||
|
return self._stack
|
||||||
|
|
||||||
|
def get_initial(self):
|
||||||
|
stack = self.get_object()
|
||||||
|
return {'stack_id': stack.id,
|
||||||
|
'stack_name': stack.stack_name
|
||||||
|
}
|
||||||
|
|
||||||
|
def get_form_kwargs(self):
|
||||||
|
kwargs = super(ChangeTemplateView, self).get_form_kwargs()
|
||||||
|
kwargs['next_view'] = EditStackView
|
||||||
|
return kwargs
|
||||||
|
|
||||||
|
|
||||||
class CreateStackView(forms.ModalFormView):
|
class CreateStackView(forms.ModalFormView):
|
||||||
form_class = project_forms.StackCreateForm
|
form_class = project_forms.CreateStackForm
|
||||||
template_name = 'project/stacks/create.html'
|
template_name = 'project/stacks/create.html'
|
||||||
success_url = reverse_lazy('horizon:project:stacks:index')
|
success_url = reverse_lazy('horizon:project:stacks:index')
|
||||||
|
|
||||||
|
@ -92,6 +125,42 @@ class CreateStackView(forms.ModalFormView):
|
||||||
return kwargs
|
return kwargs
|
||||||
|
|
||||||
|
|
||||||
|
# edit stack parameters, coming from template selector
|
||||||
|
class EditStackView(CreateStackView):
|
||||||
|
form_class = project_forms.EditStackForm
|
||||||
|
template_name = 'project/stacks/update.html'
|
||||||
|
success_url = reverse_lazy('horizon:project:stacks:index')
|
||||||
|
|
||||||
|
def get_initial(self):
|
||||||
|
initial = super(EditStackView, self).get_initial()
|
||||||
|
|
||||||
|
initial['stack'] = self.get_object()['stack']
|
||||||
|
if initial['stack']:
|
||||||
|
initial['stack_id'] = initial['stack'].id
|
||||||
|
initial['stack_name'] = initial['stack'].stack_name
|
||||||
|
|
||||||
|
return initial
|
||||||
|
|
||||||
|
def get_context_data(self, **kwargs):
|
||||||
|
context = super(EditStackView, self).get_context_data(**kwargs)
|
||||||
|
context['stack'] = self.get_object()['stack']
|
||||||
|
return context
|
||||||
|
|
||||||
|
@memoized.memoized_method
|
||||||
|
def get_object(self):
|
||||||
|
stack_id = self.kwargs['stack_id']
|
||||||
|
try:
|
||||||
|
stack = {}
|
||||||
|
stack['stack'] = api.heat.stack_get(self.request, stack_id)
|
||||||
|
stack['template'] = api.heat.template_get(self.request, stack_id)
|
||||||
|
self._stack = stack
|
||||||
|
except Exception:
|
||||||
|
msg = _("Unable to retrieve stack.")
|
||||||
|
redirect = reverse('horizon:project:stacks:index')
|
||||||
|
exceptions.handle(self.request, msg, redirect=redirect)
|
||||||
|
return self._stack
|
||||||
|
|
||||||
|
|
||||||
class DetailView(tabs.TabView):
|
class DetailView(tabs.TabView):
|
||||||
tab_group_class = project_tabs.StackDetailTabs
|
tab_group_class = project_tabs.StackDetailTabs
|
||||||
template_name = 'project/stacks/detail.html'
|
template_name = 'project/stacks/detail.html'
|
||||||
|
|
|
@ -24,6 +24,35 @@ class HeatApiTests(test.APITestCase):
|
||||||
heatclient.stacks = self.mox.CreateMockAnything()
|
heatclient.stacks = self.mox.CreateMockAnything()
|
||||||
heatclient.stacks.list().AndReturn(iter(api_stacks))
|
heatclient.stacks.list().AndReturn(iter(api_stacks))
|
||||||
self.mox.ReplayAll()
|
self.mox.ReplayAll()
|
||||||
|
|
||||||
stacks = api.heat.stacks_list(self.request)
|
stacks = api.heat.stacks_list(self.request)
|
||||||
self.assertItemsEqual(stacks, api_stacks)
|
self.assertItemsEqual(stacks, api_stacks)
|
||||||
|
|
||||||
|
def test_template_get(self):
|
||||||
|
api_stacks = self.stacks.list()
|
||||||
|
stack_id = api_stacks[0].id
|
||||||
|
mock_data_template = self.stack_templates.list()[0]
|
||||||
|
|
||||||
|
heatclient = self.stub_heatclient()
|
||||||
|
heatclient.stacks = self.mox.CreateMockAnything()
|
||||||
|
heatclient.stacks.template(stack_id).AndReturn(mock_data_template)
|
||||||
|
self.mox.ReplayAll()
|
||||||
|
|
||||||
|
template = api.heat.template_get(self.request, stack_id)
|
||||||
|
self.assertEqual(template.data, mock_data_template.data)
|
||||||
|
|
||||||
|
def test_stack_update(self):
|
||||||
|
api_stacks = self.stacks.list()
|
||||||
|
stack = api_stacks[0]
|
||||||
|
stack_id = stack.id
|
||||||
|
|
||||||
|
heatclient = self.stub_heatclient()
|
||||||
|
heatclient.stacks = self.mox.CreateMockAnything()
|
||||||
|
form_data = {'timeout_mins': 600}
|
||||||
|
heatclient.stacks.update(stack_id, **form_data).AndReturn(stack)
|
||||||
|
self.mox.ReplayAll()
|
||||||
|
|
||||||
|
returned_stack = api.heat.stack_update(self.request,
|
||||||
|
stack_id,
|
||||||
|
**form_data)
|
||||||
|
from heatclient.v1 import stacks
|
||||||
|
self.assertIsInstance(returned_stack, stacks.Stack)
|
||||||
|
|
Loading…
Reference in New Issue