Add segment panel
Added segment panel and implemented list and create segment functionality.Added test cases that actually not covering the line of code but tested the list and create functionally. Change-Id: I1366bfdc188f4e0d53fa46f2a6ea3790c9f295fc
This commit is contained in:
parent
48b361a3a9
commit
42c47241e4
|
@ -0,0 +1,96 @@
|
|||
# Copyright (c) 2018 NTT DATA
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
import itertools
|
||||
|
||||
from django.conf import settings
|
||||
from django.utils.translation import ugettext_lazy as _
|
||||
|
||||
from horizon.utils import functions as utils
|
||||
from horizon.utils import memoized
|
||||
|
||||
from masakariclient import client as masakari_client
|
||||
from masakaridashboard.handle_errors import handle_errors
|
||||
|
||||
|
||||
@memoized.memoized
|
||||
def masakariclient(request):
|
||||
return masakari_client.Client(1,
|
||||
username=request.user.username,
|
||||
password='admin',
|
||||
user_domain_name='default',
|
||||
project_domain_name='default',
|
||||
auth_token=request.user.token.id,
|
||||
project_id=request.user.tenant_id,
|
||||
auth_url=getattr(settings,
|
||||
'OPENSTACK_KEYSTONE_URL'),
|
||||
endpoint_type=getattr(
|
||||
settings, 'OPENSTACK_ENDPOINT_TYPE',
|
||||
'internalURL')
|
||||
)
|
||||
|
||||
|
||||
@handle_errors(_("Unable to retrieve list"), [])
|
||||
def pagination_list(request, marker='', paginate=False):
|
||||
"""Retrieve a listing of specific entity and handles pagination.
|
||||
|
||||
:param request: Request data
|
||||
:param marker: Pagination marker for large data sets: entity id
|
||||
:param sort_dirs: Sorting Directions (asc/desc). Default:asc
|
||||
:param paginate: If true will perform pagination based on settings.
|
||||
Default:False
|
||||
"""
|
||||
limit = getattr(settings, 'API_RESULT_LIMIT', 100)
|
||||
page_size = utils.get_page_size(request)
|
||||
|
||||
if paginate:
|
||||
request_size = page_size + 1
|
||||
else:
|
||||
request_size = limit
|
||||
client = masakariclient(request)
|
||||
entities_iter = client.service.segments(marker=marker, limit=request_size)
|
||||
has_prev_data = has_more_data = False
|
||||
if paginate:
|
||||
entities = list(itertools.islice(entities_iter, request_size))
|
||||
# first and middle page condition
|
||||
if len(entities) > page_size:
|
||||
entities.pop()
|
||||
has_more_data = True
|
||||
# middle page condition
|
||||
if marker is not None:
|
||||
has_prev_data = True
|
||||
elif marker is not None:
|
||||
has_prev_data = True
|
||||
else:
|
||||
entities = list(entities_iter)
|
||||
|
||||
return entities, has_more_data, has_prev_data
|
||||
|
||||
|
||||
@handle_errors(_("Unable to retrieve segment."), [])
|
||||
def segment_list(request):
|
||||
"""Returns all segments."""
|
||||
lst = list(masakariclient(request).service.segments())
|
||||
return lst
|
||||
|
||||
|
||||
@handle_errors(_("Unable to create segment."), [])
|
||||
def segment_create(request, data):
|
||||
"""Create segment."""
|
||||
return masakariclient(request).service.create_segment(**data)
|
||||
|
||||
|
||||
def get_segment(request, segment_id):
|
||||
"""Returns segment by id"""
|
||||
return masakariclient(request).service.get_segment(segment_id)
|
|
@ -0,0 +1,31 @@
|
|||
# Copyright (c) 2018 NTT DATA
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
from django.utils.translation import ugettext_lazy as _
|
||||
|
||||
import horizon
|
||||
|
||||
from masakaridashboard.default import panel
|
||||
|
||||
|
||||
class MasakariDashboard(horizon.Dashboard):
|
||||
slug = "masakaridashboard"
|
||||
name = _("Masakari Dashboard")
|
||||
panels = ('default', 'segment')
|
||||
default_panel = 'default'
|
||||
roles = ('admin',)
|
||||
|
||||
|
||||
horizon.register(MasakariDashboard)
|
||||
MasakariDashboard.register(panel.Default)
|
|
@ -0,0 +1,24 @@
|
|||
# Copyright (c) 2018 NTT DATA
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
from django.utils.translation import ugettext_lazy as _
|
||||
|
||||
import horizon
|
||||
|
||||
|
||||
class Default(horizon.Panel):
|
||||
name = _("Default")
|
||||
slug = 'default'
|
||||
urls = 'masakaridashboard.segment.urls'
|
||||
nav = False
|
|
@ -0,0 +1,7 @@
|
|||
{% extends 'base.html' %}
|
||||
{% load i18n %}
|
||||
|
||||
{% block css %}
|
||||
{% include "_stylesheets.html" %}
|
||||
<link href='{{ STATIC_URL }}masakaridashboard/css/style.css' type='text/css' media='screen' rel='stylesheet' />
|
||||
{% endblock %}
|
|
@ -0,0 +1,7 @@
|
|||
{% extends 'masakaridashboard/default/base.html' %}
|
||||
|
||||
{% block main %}
|
||||
<div class="masakari-wrapper">
|
||||
{{ table.render }}
|
||||
</div>
|
||||
{% endblock %}
|
|
@ -0,0 +1,25 @@
|
|||
# Copyright (c) 2018 NTT DATA
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
from masakaridashboard import exceptions
|
||||
|
||||
DASHBOARD = 'masakaridashboard'
|
||||
ADD_INSTALLED_APPS = ['masakaridashboard']
|
||||
DEFAULT = True
|
||||
|
||||
ADD_EXCEPTIONS = {
|
||||
'recoverable': exceptions.RECOVERABLE,
|
||||
'not_found': exceptions.NOT_FOUND,
|
||||
'unauthorized': exceptions.UNAUTHORIZED,
|
||||
}
|
|
@ -0,0 +1,19 @@
|
|||
# Copyright (c) 2018 NTT DATA
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License"); you may
|
||||
# not use this file except in compliance with the License. You may obtain
|
||||
# a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
# License for the specific language governing permissions and limitations
|
||||
# under the License.
|
||||
|
||||
from openstack_dashboard import exceptions
|
||||
|
||||
NOT_FOUND = exceptions.NOT_FOUND
|
||||
RECOVERABLE = exceptions.RECOVERABLE
|
||||
UNAUTHORIZED = exceptions.UNAUTHORIZED
|
|
@ -0,0 +1,74 @@
|
|||
# Copyright (c) 2018 NTT DATA
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License"); you may
|
||||
# not use this file except in compliance with the License. You may obtain
|
||||
# a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
# License for the specific language governing permissions and limitations
|
||||
# under the License.
|
||||
|
||||
import functools
|
||||
import inspect
|
||||
|
||||
import horizon.exceptions
|
||||
|
||||
|
||||
def handle_errors(error_message, error_default=None, request_arg=None):
|
||||
"""A decorator for adding default error handling to API calls.
|
||||
|
||||
It wraps the original method in a try-except block, with horizon's
|
||||
error handling added.
|
||||
|
||||
Note: it should only be used on functions or methods that take request as
|
||||
their argument (it has to be named "request", or ``request_arg`` has to be
|
||||
provided, indicating which argument is the request).
|
||||
|
||||
The decorated method accepts a number of additional parameters:
|
||||
|
||||
:param _error_handle: whether to handle the errors in this call
|
||||
:param _error_message: override the error message
|
||||
:param _error_default: override the default value returned on error
|
||||
:param _error_redirect: specify a redirect url for errors
|
||||
:param _error_ignore: ignore known errors
|
||||
"""
|
||||
def decorator(func):
|
||||
if request_arg is None:
|
||||
_request_arg = 'request'
|
||||
if _request_arg not in inspect.getargspec(func).args:
|
||||
raise RuntimeError(
|
||||
"The handle_errors decorator requires 'request' as "
|
||||
"an argument of the function or method being decorated")
|
||||
else:
|
||||
_request_arg = request_arg
|
||||
|
||||
@functools.wraps(func)
|
||||
def wrapper(*args, **kwargs):
|
||||
_error_handle = kwargs.pop('_error_handle', True)
|
||||
_error_message = kwargs.pop('_error_message', error_message)
|
||||
_error_default = kwargs.pop('_error_default', error_default)
|
||||
_error_redirect = kwargs.pop('_error_redirect', None)
|
||||
_error_ignore = kwargs.pop('_error_ignore', False)
|
||||
|
||||
if not _error_handle:
|
||||
return func(*args, **kwargs)
|
||||
try:
|
||||
return func(*args, **kwargs)
|
||||
except Exception as e:
|
||||
callargs = inspect.getcallargs(func, *args, **kwargs)
|
||||
request = callargs[_request_arg]
|
||||
_error_message += ': ' + str(e)
|
||||
horizon.exceptions.handle(request, _error_message,
|
||||
ignore=_error_ignore,
|
||||
redirect=_error_redirect)
|
||||
return _error_default
|
||||
|
||||
wrapper.wrapped = func
|
||||
|
||||
return wrapper
|
||||
|
||||
return decorator
|
|
@ -0,0 +1,107 @@
|
|||
# Copyright (c) 2018 NTT DATA
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
import six
|
||||
|
||||
from django.core.urlresolvers import reverse
|
||||
from django.utils.translation import ugettext_lazy as _
|
||||
|
||||
from horizon import exceptions
|
||||
from horizon import forms
|
||||
from horizon import messages
|
||||
|
||||
from masakaridashboard.api import api
|
||||
|
||||
|
||||
class ValidateSegmentForm(forms.SelfHandlingForm):
|
||||
name = forms.CharField(
|
||||
label=_('Segment Name'),
|
||||
widget=forms.TextInput())
|
||||
recovery_method = forms.ChoiceField(
|
||||
label=_('Recovery Method'),
|
||||
choices=[('auto', 'auto'),
|
||||
('reserved_host', 'reserved_host'),
|
||||
('auto_priority', 'auto_priority'),
|
||||
('rh_priority', 'rh_priority')],
|
||||
widget=forms.Select(
|
||||
attrs={'class': 'switchable',
|
||||
'data-slug': 'recovery_method'})
|
||||
)
|
||||
service_type = forms.CharField(
|
||||
label=_('Service Type'),
|
||||
widget=forms.TextInput())
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
self.next_view = kwargs.pop('next_view')
|
||||
super(ValidateSegmentForm, self).__init__(*args, **kwargs)
|
||||
|
||||
def clean(self):
|
||||
cleaned_data = super(ValidateSegmentForm, self).clean()
|
||||
# validation code
|
||||
name = cleaned_data.get('name')
|
||||
service_type = cleaned_data.get('service_type')
|
||||
if name is not None:
|
||||
if len(name) < 255 and isinstance(name, six.text_type):
|
||||
cleaned_data['name'] = name
|
||||
else:
|
||||
error_msg = _("validation failed")
|
||||
self._errors['name'] = self.error_class([error_msg])
|
||||
return cleaned_data
|
||||
else:
|
||||
error_msg = _("You must specify name")
|
||||
self._errors['name'] = self.error_class([error_msg])
|
||||
return cleaned_data
|
||||
if service_type is not None:
|
||||
if len(service_type) < 255 and isinstance(
|
||||
service_type, six.text_type):
|
||||
cleaned_data['service_type'] = service_type
|
||||
else:
|
||||
error_msg = _("validation failed")
|
||||
self._errors['service_type'] = self.error_class([error_msg])
|
||||
return cleaned_data
|
||||
else:
|
||||
error_msg = _("You must specify service_type")
|
||||
self._errors['service_type'] = self.error_class([error_msg])
|
||||
return cleaned_data
|
||||
return cleaned_data
|
||||
|
||||
def handle(self, request, data):
|
||||
kwargs = {'name': data['name'],
|
||||
'recovery_method': data['recovery_method'],
|
||||
'service_type': data['service_type']
|
||||
}
|
||||
|
||||
request.method = 'GET'
|
||||
|
||||
return self.next_view.as_view()(request, **kwargs)
|
||||
|
||||
|
||||
class CreateForm(forms.SelfHandlingForm):
|
||||
name = forms.CharField(widget=forms.TextInput(
|
||||
attrs={'readonly': 'readonly'}))
|
||||
recovery_method = forms.CharField(widget=forms.TextInput(
|
||||
attrs={'readonly': 'readonly'}))
|
||||
service_type = forms.CharField(widget=forms.TextInput(
|
||||
attrs={'readonly': 'readonly'}))
|
||||
|
||||
def handle(self, request, data):
|
||||
try:
|
||||
api.segment_create(request, data)
|
||||
msg = _('Successfully created segment.')
|
||||
messages.success(request, msg)
|
||||
return True
|
||||
except Exception:
|
||||
msg = _('Failed to create segments.')
|
||||
redirect = reverse('horizon:masakaridashboard:segment:index')
|
||||
exceptions.handle(request, msg, redirect=redirect)
|
|
@ -0,0 +1,27 @@
|
|||
# Copyright (c) 2018 NTT DATA
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
from django.utils.translation import ugettext_lazy as _
|
||||
|
||||
import horizon
|
||||
|
||||
from masakaridashboard import dashboard
|
||||
|
||||
|
||||
class Segment(horizon.Panel):
|
||||
name = _("Segment")
|
||||
slug = 'segment'
|
||||
|
||||
|
||||
dashboard.MasakariDashboard.register(Segment)
|
|
@ -0,0 +1,47 @@
|
|||
# Copyright (c) 2018 NTT DATA
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
from django.utils.translation import ugettext_lazy as _
|
||||
|
||||
from horizon import tables
|
||||
|
||||
|
||||
class CreateSegment(tables.LinkAction):
|
||||
name = "create"
|
||||
verbose_name = _("Create Segment")
|
||||
url = "horizon:masakaridashboard:segment:validate_segment"
|
||||
classes = ("ajax-modal",)
|
||||
icon = "plus"
|
||||
|
||||
|
||||
class FailoverSegmentTable(tables.DataTable):
|
||||
|
||||
name = tables.Column('name', verbose_name=_("Name"))
|
||||
uuid = tables.Column('uuid', verbose_name=_("UUID"))
|
||||
recovery_method = tables.Column(
|
||||
'recovery_method', verbose_name=_("Recovery Method"))
|
||||
service_type = tables.Column(
|
||||
'service_type', verbose_name=_("Service Type"))
|
||||
created_at = tables.Column(
|
||||
'created_at', verbose_name=_("Created At"))
|
||||
|
||||
def get_object_id(self, datum):
|
||||
return datum.uuid
|
||||
|
||||
class Meta(object):
|
||||
name = "failover_segment"
|
||||
verbose_name = _("FailoverSegment")
|
||||
table_actions = (CreateSegment,
|
||||
tables.FilterAction
|
||||
)
|
|
@ -0,0 +1,5 @@
|
|||
{% extends "horizon/common/_modal_form.html" %}
|
||||
{% load i18n %}
|
||||
{% block modal-body-right %}
|
||||
|
||||
{% endblock %}
|
|
@ -0,0 +1,4 @@
|
|||
{% extends "horizon/common/_modal_form.html" %}
|
||||
{% load i18n %}
|
||||
{% block form_attrs %}enctype="multipart/form-data"{% endblock %}
|
||||
|
|
@ -0,0 +1,8 @@
|
|||
{% extends 'base.html' %}
|
||||
{% load i18n %}
|
||||
{% block title %}{% trans "Create Segment" %}{% endblock %}
|
||||
|
||||
{% block main %}
|
||||
{% include 'masakaridashboard/segment/_create.html' %}
|
||||
{% endblock %}
|
||||
|
|
@ -0,0 +1,7 @@
|
|||
{% extends 'masakaridashboard/default/table.html' %}
|
||||
{% load i18n %}
|
||||
{% block title %}{% trans "Segments" %}{% endblock %}
|
||||
|
||||
{% block page_header %}
|
||||
{% include "horizon/common/_page_header.html" with title=_("Segments") %}
|
||||
{% endblock page_header %}
|
|
@ -0,0 +1,7 @@
|
|||
{% extends 'base.html' %}
|
||||
{% load i18n %}
|
||||
{% block title %}{% trans "Validate Segment" %}{% endblock %}
|
||||
|
||||
{% block main %}
|
||||
{% include 'masakaridashboard/segment/_validate_segment.html' %}
|
||||
{% endblock %}
|
|
@ -0,0 +1,26 @@
|
|||
# Copyright (c) 2018 NTT DATA
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
from django.conf.urls import url
|
||||
|
||||
from masakaridashboard.segment import views
|
||||
|
||||
|
||||
urlpatterns = [
|
||||
url(r'^$', views.IndexView.as_view(), name='index'),
|
||||
url(r'^validate_segment$',
|
||||
views.ValidateSegmentView.as_view(),
|
||||
name='validate_segment'),
|
||||
url(r'^create$', views.CreateView.as_view(), name='create'),
|
||||
]
|
|
@ -0,0 +1,99 @@
|
|||
# Copyright (c) 2018 NTT DATA
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
from django.core.urlresolvers import reverse_lazy
|
||||
from django.utils.translation import ugettext_lazy as _
|
||||
|
||||
from horizon import tables
|
||||
from masakaridashboard.api import api
|
||||
from masakaridashboard.segment import tables as masakari_tab
|
||||
|
||||
from horizon import exceptions
|
||||
from horizon import forms
|
||||
from masakaridashboard.segment import forms as segment_forms
|
||||
|
||||
|
||||
class IndexView(tables.DataTableView):
|
||||
table_class = masakari_tab.FailoverSegmentTable
|
||||
template_name = 'masakaridashboard/segment/index.html'
|
||||
|
||||
_more = False
|
||||
_prev = False
|
||||
|
||||
def has_more_data(self, table):
|
||||
return self._more
|
||||
|
||||
def has_prev_data(self, table):
|
||||
return self._prev
|
||||
|
||||
def get_data(self):
|
||||
segments = []
|
||||
marker = self.request.GET.get(
|
||||
masakari_tab.FailoverSegmentTable._meta.pagination_param,
|
||||
None
|
||||
)
|
||||
if marker is not None:
|
||||
segment = api.get_segment(self.request, marker)
|
||||
marker = segment.id
|
||||
|
||||
try:
|
||||
segments, self._more, self._prev = api.pagination_list(
|
||||
request=self.request,
|
||||
marker=marker,
|
||||
paginate=True
|
||||
)
|
||||
except Exception:
|
||||
self._prev = False
|
||||
self._more = False
|
||||
msg = _('Unable to retrieve segment list.')
|
||||
exceptions.handle(self.request, msg)
|
||||
|
||||
return segments
|
||||
|
||||
|
||||
class ValidateSegmentView(forms.ModalFormView):
|
||||
template_name = 'masakaridashboard/segment/validate_segment.html'
|
||||
modal_header = _("Create Segment")
|
||||
form_id = "validate_segment"
|
||||
form_class = segment_forms.ValidateSegmentForm
|
||||
submit_label = _("Validate")
|
||||
submit_url = reverse_lazy(
|
||||
"horizon:masakaridashboard:segment:validate_segment")
|
||||
success_url = reverse_lazy('horizon:masakaridashboard:segment:create')
|
||||
page_title = _("Validate Segment")
|
||||
|
||||
def get_form_kwargs(self):
|
||||
kwargs = super(ValidateSegmentView, self).get_form_kwargs()
|
||||
kwargs['next_view'] = CreateView
|
||||
|
||||
return kwargs
|
||||
|
||||
|
||||
class CreateView(forms.ModalFormView):
|
||||
template_name = 'masakaridashboard/segment/create.html'
|
||||
modal_header = _("Create Segment")
|
||||
form_id = "create_segment"
|
||||
form_class = segment_forms.CreateForm
|
||||
submit_label = _("Create")
|
||||
submit_url = reverse_lazy("horizon:masakaridashboard:segment:create")
|
||||
success_url = reverse_lazy("horizon:masakaridashboard:segment:index")
|
||||
page_title = _("Create Segment")
|
||||
|
||||
def get_initial(self):
|
||||
initial = {}
|
||||
initial['name'] = self.kwargs.get('name')
|
||||
initial['recovery_method'] = self.kwargs.get('recovery_method')
|
||||
initial['service_type'] = self.kwargs.get('service_type')
|
||||
|
||||
return initial
|
|
@ -0,0 +1,51 @@
|
|||
.masakari-wrapper.list{
|
||||
list-style: inherit;
|
||||
}
|
||||
|
||||
.masakari-wrapper #actions{
|
||||
width:100%;
|
||||
}
|
||||
|
||||
.masakari-wrapper #actions a.btn{
|
||||
width:initial;
|
||||
}
|
||||
|
||||
.masakari-wrapper.detail-screen .page-breadcrumb ol li{
|
||||
max-width: inherit;
|
||||
}
|
||||
|
||||
.masakari-wrapper.detail-screen .page-breadcrumb li:last-child{
|
||||
display:none;
|
||||
}
|
||||
|
||||
.masakari-wrapper .navbar-brand{
|
||||
padding: 6px 10px;
|
||||
}
|
||||
|
||||
.boolfield{
|
||||
font-style: italic;
|
||||
}
|
||||
|
||||
.boolfield i{
|
||||
padding-right: .2em;
|
||||
}
|
||||
|
||||
.boolfield i.green{
|
||||
color: green;
|
||||
}
|
||||
|
||||
.boolfield i.red{
|
||||
color: red;
|
||||
}
|
||||
|
||||
.line-space{
|
||||
margin: .3em 0;
|
||||
}
|
||||
|
||||
.line-space dd{
|
||||
display:inline-block;
|
||||
margin-left: 1.5em;
|
||||
}
|
||||
|
||||
|
||||
|
|
@ -0,0 +1,112 @@
|
|||
# Copyright (c) 2018 NTT DATA
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License"); you may
|
||||
# not use this file except in compliance with the License. You may obtain
|
||||
# a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
# License for the specific language governing permissions and limitations
|
||||
# under the License.
|
||||
|
||||
from django.core.urlresolvers import reverse
|
||||
|
||||
from openstack_dashboard.test import helpers as test
|
||||
|
||||
import mock
|
||||
|
||||
from masakariclient.sdk.ha.v1 import _proxy as proxy_obj
|
||||
from masakariclient.sdk.ha.v1 import segment
|
||||
from masakaridashboard.api import api
|
||||
|
||||
|
||||
SEGMENT_LIST = [
|
||||
segment.Segment(uuid='1', name='test', recovery_method='auto',
|
||||
service_type='service')
|
||||
]
|
||||
INDEX_URL = reverse('horizon:masakaridashboard:segment:index')
|
||||
CREATE_URL = reverse('horizon:masakaridashboard:segment:create')
|
||||
|
||||
|
||||
class SegmentTest(test.TestCase):
|
||||
|
||||
def test_index(self):
|
||||
with mock.patch('masakaridashboard.api.api.pagination_list',
|
||||
return_value=SEGMENT_LIST):
|
||||
res = self.client.get(INDEX_URL)
|
||||
self.assertTemplateUsed(res, 'masakaridashboard/segment/index.html')
|
||||
|
||||
def test_create_get(self):
|
||||
res = self.client.get(CREATE_URL)
|
||||
self.assertTemplateUsed(res, 'masakaridashboard/segment/create.html')
|
||||
|
||||
def test_create_post(self):
|
||||
|
||||
segment = SEGMENT_LIST[0]
|
||||
url = reverse('horizon:masakaridashboard:segment:validate_segment')
|
||||
res = self.client.get(url)
|
||||
self.assertTemplateUsed(
|
||||
res,
|
||||
'masakaridashboard/segment/validate_segment.html'
|
||||
)
|
||||
form_data = {
|
||||
'name': segment.name,
|
||||
'recovery_method': segment.recovery_method,
|
||||
'service_type': segment.service_type
|
||||
}
|
||||
with mock.patch('masakaridashboard.api.api.segment_create',
|
||||
return_value=segment) as mocked_create:
|
||||
res = self.client.post(CREATE_URL, form_data)
|
||||
self.assertNoFormErrors(res)
|
||||
self.assertEqual(res.status_code, 302)
|
||||
self.assertRedirectsNoFollow(res, INDEX_URL)
|
||||
|
||||
mocked_create.assert_called_once_with(
|
||||
mock.ANY,
|
||||
form_data
|
||||
)
|
||||
|
||||
@mock.patch.object(proxy_obj.Proxy, 'segments')
|
||||
def test_segment_list(self, mock_segments):
|
||||
mock_segments.return_value = SEGMENT_LIST
|
||||
result = api.segment_list(self.request)
|
||||
self.assertEqual(SEGMENT_LIST, result)
|
||||
mock_segments.assert_called_once_with()
|
||||
|
||||
@mock.patch.object(proxy_obj.Proxy, 'create_segment')
|
||||
def test_segment_create(self, mock_segments_create):
|
||||
segment = SEGMENT_LIST[0]
|
||||
mock_segments_create.return_value = segment
|
||||
data = {
|
||||
'name': segment.name,
|
||||
'recovery_method': segment.recovery_method,
|
||||
'service_type': segment.service_type
|
||||
}
|
||||
result = api.segment_create(self.request, data)
|
||||
self.assertEqual(segment, result)
|
||||
mock_segments_create.assert_called_once_with(**data)
|
||||
|
||||
@mock.patch.object(proxy_obj.Proxy, 'get_segment')
|
||||
def test_get_segment(self, mock_get_segment):
|
||||
segment = SEGMENT_LIST[0]
|
||||
mock_get_segment.return_value = segment
|
||||
result = api.get_segment(self.request, segment.uuid)
|
||||
self.assertEqual(segment, result)
|
||||
mock_get_segment.assert_called_once_with(segment.uuid)
|
||||
|
||||
@mock.patch.object(proxy_obj.Proxy, 'segments')
|
||||
def test_pagination_list_with_paginate_false(self, mock_segments):
|
||||
mock_segments.return_value = SEGMENT_LIST
|
||||
result = api.pagination_list(self.request, marker='', paginate=False)
|
||||
self.assertIn(SEGMENT_LIST, result)
|
||||
mock_segments.assert_called_once_with(limit=100, marker='')
|
||||
|
||||
@mock.patch.object(proxy_obj.Proxy, 'segments')
|
||||
def test_pagination_list_with_paginate_true(self, mock_segments):
|
||||
mock_segments.return_value = SEGMENT_LIST
|
||||
result = api.pagination_list(self.request, marker='', paginate=True)
|
||||
self.assertIn(SEGMENT_LIST, result)
|
||||
mock_segments.assert_called_once_with(limit=21, marker='')
|
|
@ -14,3 +14,4 @@ Django>=1.8,<2.0 # BSD
|
|||
django-babel>=0.5.1 # BSD
|
||||
django-compressor>=2.0 # MIT
|
||||
django-pyscss>=2.0.2 # BSD License (2 clause)
|
||||
python-masakariclient>=3.0.1 # Apache-2.0
|
||||
|
|
Loading…
Reference in New Issue