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:
parent
4627c4a014
commit
c3ea4417a4
|
@ -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)
|
||||
|
|
|
@ -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):
|
||||
|
|
|
@ -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'),
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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 %}
|
|
@ -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
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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()
|
||||
|
|
|
@ -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')
|
||||
|
|
|
@ -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
|
||||
|
|
Loading…
Reference in New Issue