Initial implementation of Actions UI

Actions are provided per Component, on Actions tab.
Currently each action is a simple link, after clicking it
user is redirected to the Components page. While any
action is being run in an environment (including deployment),
Actions tab is hidden.

Co-Authored-By: Ekaterina Chernova <efedorova@mirantis.com>
Change-Id: I52c462ef92f2b51f407521e7b8d9b1294de4d53f
Targets: blueprint actions-ui
This commit is contained in:
Timur Sufiev 2014-06-11 17:16:29 +04:00
parent 4627c4a014
commit c3ea4417a4
10 changed files with 129 additions and 6 deletions

View File

@ -195,6 +195,12 @@ def environment_update(request, environment_id, name):
return api.muranoclient(request).environments.update(environment_id, name)
def action_allowed(request, environment_id):
env = environment_get(request, environment_id)
status = getattr(env, 'status', None)
return status not in ('deploying',)
def services_list(request, environment_id):
def strip(msg, to=100):
return '%s...' % msg[:to] if len(msg) > to else msg
@ -273,6 +279,17 @@ def service_get(request, environment_id, service_id):
return service
def extract_actions_list(service):
actions_data = service['?'].get('_actions', {})
return dict((action_id, action.get('name')) for (action_id, action)
in actions_data.iteritems() if action.get('enabled'))
def run_action(request, environment_id, action_id):
mc = api.muranoclient(request)
return mc.actions.call(environment_id, action_id)
def deployments_list(request, environment_id):
LOG.debug('Deployments::List')
deployments = api.muranoclient(request).deployments.list(environment_id)

View File

@ -70,6 +70,22 @@ class OverviewTab(tabs.Tab):
return {'service': detail_info}
class AppActionsTab(tabs.Tab):
name = _('Actions')
slug = '_actions'
template_name = 'services/_actions.html'
def get_context_data(self, request):
data = self.tab_group.kwargs['service']
return {'actions': api.extract_actions_list(data),
'service_id': self.tab_group.kwargs['service_id'],
'environment_id': self.tab_group.kwargs['environment_id']}
def allowed(self, request):
environment_id = self.tab_group.kwargs['environment_id']
return api.action_allowed(request, environment_id)
class ServiceLogsTab(tabs.Tab):
name = _("Logs")
slug = "service_logs"
@ -193,7 +209,7 @@ class EnvironmentDetailsTabs(tabs.TabGroup):
class ServicesTabs(tabs.TabGroup):
slug = "services_details"
tabs = (OverviewTab, ServiceLogsTab, )
tabs = (OverviewTab, AppActionsTab, ServiceLogsTab)
class DeploymentDetailsTabs(tabs.TabGroup):

View File

@ -36,6 +36,11 @@ urlpatterns = urls.patterns(
views.EnvironmentDetails.as_view(),
name='services'),
urls.url(ENVIRONMENT_ID +
r'/(?P<service_id>[^/]+)/actions/(?P<action_id>[^/]+)$',
views.ApplicationActions.as_view(),
name='actions'),
urls.url(ENVIRONMENT_ID + r'/services/get_d3_data$',
views.JSONView.as_view(), name='d3_data'),

View File

@ -20,6 +20,7 @@ from django import http
from django.utils.translation import ugettext_lazy as _
from django.views import generic
from horizon import exceptions
from horizon import messages
from horizon import tables
from horizon import tabs
from horizon import workflows
@ -75,6 +76,26 @@ class EnvironmentDetails(tabs.TabbedTableView):
return context
class ApplicationActions(generic.View):
@staticmethod
def get(request, environment_id=None, service_id=None, action_id=None):
if api.action_allowed(request, environment_id):
api.run_action(request, environment_id, action_id)
service = api.service_get(request, environment_id, service_id)
action_name = api.extract_actions_list(service).get(action_id, '-')
component_name = getattr(service, 'name', '-')
msg = _("Action '{0}' was scheduled for component '{1}.").format(
action_name, component_name)
messages.success(request, msg)
else:
msg = _("There is some action being run in an environment")
messages.error(request, msg)
url = reverse('horizon:murano:environments:services',
args=(environment_id,))
return http.HttpResponseRedirect(url)
class DetailServiceView(tabs.TabView):
tab_group_class = env_tabs.ServicesTabs
template_name = 'services/details.html'
@ -82,7 +103,7 @@ class DetailServiceView(tabs.TabView):
def get_context_data(self, **kwargs):
context = super(DetailServiceView, self).get_context_data(**kwargs)
context["service"] = self.get_data()
context["service_name"] = self.service.name
context["service_name"] = getattr(self.service, 'name', '-')
env = api.environment_get(self.request, self.environment_id)
context["environment_name"] = env.name
return context

View File

@ -0,0 +1,18 @@
{% load i18n %}
<div class="clearfix">
<h3 class="pull-left">{% trans "Component Actions" %}</h3>
</div>
{% if actions%}
<ul class="nav nav-list">
{% for action_id, action_name in actions.items %}
<li><a href="{% url 'horizon:murano:environments:actions' environment_id service_id action_id %}">{{ action_name }}</a></li>
{% endfor %}
</ul>
{% else %}
<div class="row">
<div class="alert alert-block alert-info fade in">
<p>{% trans "Component does not provide any actions." %}</p>
</div>
</div>
{% endif %}

View File

@ -1,4 +1,3 @@
#Note: it is a fake application, it isn't intended to be deployed
Namespaces:
=: io.murano.apps
std: io.murano
@ -6,3 +5,11 @@ Namespaces:
Name: MockApp
Extends: std:Application
Properties:
name:
Contract: $.string().notNull()
Workflow:
deploy:
Usage: Action

View File

@ -54,12 +54,12 @@ Forms:
- name: name
type: string
label: String - Application Name
label: Application Name
description: >-
Requirements: Just A-Z, a-z, 0-9, dash and
underline are allowed, min/max value are defined.
minLength: 2
maxLength: 5
maxLength: 12
regexpValidator: '^[-\w]+$'
errorMessages:
invalid: Just letters, numbers, underscores and hyphens are allowed.

View File

@ -336,3 +336,17 @@ class ApplicationTestCase(ImageTestCase):
self.fill_field(by.By.ID, 'id_{0}'.format(param), value)
self.driver.find_element_by_xpath(consts.InputSubmit).click()
self.driver.refresh()
def start_deploy(self, app_id, app_name='TestApp'):
self.go_to_submenu('Applications')
self.select_and_click_action_for_app('quick-add', app_id)
field_id = "{0}_0-name".format(app_id)
self.fill_field(by.By.ID, field_id, value=app_name)
self.driver.find_element_by_xpath(consts.ButtonSubmit).click()
self.driver.find_element_by_xpath(consts.InputSubmit).click()
self.select_from_list('osImage', self.image.name)
self.driver.find_element_by_xpath(consts.InputSubmit).click()
self.driver.find_element_by_css_selector(
'#services__action_deploy_env').click()

View File

@ -625,3 +625,28 @@ class TestSuiteApplications(base.ApplicationTestCase):
c.Status.format('Ready'),
sec=90)
self.check_element_on_page(by.By.XPATH, c.CellStatus.format('up'))
def test_check_actions_tab(self):
"""Test check that action tab in deployed application is available
and actions are display in the corresponding tab
Scenario:
1. Navigate Applications and click MockApp 'Quick Deploy'
2. Click deploy
3. Wait 'Ready' status
4. Click on application
5. Check that 'Actions' tab is present
6. Click on 'Actions' tab
7. Check that application's actions are present
"""
self.start_deploy(self.mockapp_id)
self.check_element_on_page(by.By.XPATH,
c.Status.format('Ready'),
sec=90)
self.driver.find_element_by_link_text('TestApp').click()
self.check_element_on_page(by.By.LINK_TEXT, 'Actions')
self.driver.find_element_by_link_text('Actions').click()
self.check_element_on_page(by.By.LINK_TEXT, 'deploy')

View File

@ -5,4 +5,4 @@ six>=1.7.0
PyYAML>=3.1.0
django-floppyforms>=1.1
yaql>=0.2.3,<0.3
python-muranoclient>=0.5.4
python-muranoclient>=0.5.5