Remove empty tabs in freezer dashboard
remove empty tab for job edition remove possibility to add job without interval if start and end date are provided show a message when a job is started/stoped Resolves bug: 1523497 Change-Id: Iff39fc9e813969672eecd48d9084fd100bcf611c
This commit is contained in:
parent
f6d896edbf
commit
b48b27fb8c
@ -44,7 +44,7 @@ symbols=no
|
||||
# --enable=similarities". If you want to run only the classes checker, but have
|
||||
# no Warning level messages displayed, use"--disable=all --enable=classes
|
||||
# --disable=W"
|
||||
disable=E1002,W,C,R,method-hidden
|
||||
disable=E1002,W,C,R,method-hidden,import-error
|
||||
|
||||
|
||||
|
||||
|
@ -208,7 +208,6 @@ class ActionConfigurationAction(workflows.Action):
|
||||
|
||||
def populate_action_choices(self, request, context):
|
||||
return [
|
||||
('', _("Select an action")),
|
||||
('backup', _("Backup")),
|
||||
('restore', _("Restore")),
|
||||
('admin', _("Admin")),
|
||||
|
@ -335,7 +335,8 @@ class Action(object):
|
||||
action['freezer_action'].get('backup_name'),
|
||||
action['freezer_action'].get('path_to_backup')
|
||||
or action['freezer_action'].get('restore_abs_path'),
|
||||
action['freezer_action'].get('storage')
|
||||
action['freezer_action'].get('storage'),
|
||||
mode=action['freezer_action'].get('mode')
|
||||
) for action in actions]
|
||||
|
||||
def get(self, job_id, json=False):
|
||||
|
@ -19,6 +19,7 @@ from django.utils.translation import ugettext_lazy as _
|
||||
from django.utils.translation import ungettext_lazy
|
||||
|
||||
from horizon import tables
|
||||
from horizon import messages
|
||||
from horizon.utils.urlresolvers import reverse
|
||||
|
||||
import disaster_recovery.api.api as freezer_api
|
||||
@ -93,7 +94,7 @@ class EditJob(tables.LinkAction):
|
||||
icon = "pencil"
|
||||
|
||||
def get_link_url(self, datum=None):
|
||||
return reverse("horizon:disaster_recovery:jobs:configure",
|
||||
return reverse("horizon:disaster_recovery:jobs:edit_job",
|
||||
kwargs={'job_id': datum.job_id})
|
||||
|
||||
|
||||
@ -114,6 +115,7 @@ class StartJob(tables.Action):
|
||||
|
||||
def single(self, table, request, job_id):
|
||||
freezer_api.Job(request).start(job_id)
|
||||
messages.success(request, _("Job has started"))
|
||||
return shortcuts.redirect('horizon:disaster_recovery:jobs:index')
|
||||
|
||||
|
||||
@ -123,6 +125,7 @@ class StopJob(tables.Action):
|
||||
|
||||
def single(self, table, request, job_id):
|
||||
freezer_api.Job(request).stop(job_id)
|
||||
messages.success(request, _("Job has stopped"))
|
||||
return shortcuts.redirect('horizon:disaster_recovery:jobs:index')
|
||||
|
||||
|
||||
|
@ -10,6 +10,12 @@
|
||||
}
|
||||
</style>
|
||||
|
||||
<div class="row">
|
||||
<div class="col-sm-12">
|
||||
<p>Drag actions in the order they will be executed on the client.</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="sortable_lists row">
|
||||
|
||||
<div class="col-md-6">
|
||||
|
@ -33,6 +33,10 @@ urlpatterns = patterns(
|
||||
views.JobWorkflowView.as_view(),
|
||||
name='configure'),
|
||||
|
||||
url(r'^edit/(?P<job_id>[^/]+)?$',
|
||||
views.EditJobWorkflowView.as_view(),
|
||||
name='edit_job'),
|
||||
|
||||
url(r'^edit_actions/(?P<job_id>[^/]+)?$',
|
||||
views.ActionsInJobView.as_view(),
|
||||
name='edit_action'),
|
||||
|
@ -16,7 +16,8 @@ from horizon import browsers
|
||||
from horizon import workflows
|
||||
|
||||
import workflows.create as configure_workflow
|
||||
import workflows.actions as actions_workflow
|
||||
import workflows.update_job as update_job_workflow
|
||||
import workflows.update_actions as update_actions_workflow
|
||||
|
||||
import disaster_recovery.api.api as freezer_api
|
||||
import disaster_recovery.jobs.browsers as project_browsers
|
||||
@ -65,8 +66,31 @@ class JobWorkflowView(workflows.WorkflowView):
|
||||
return initial
|
||||
|
||||
|
||||
class EditJobWorkflowView(workflows.WorkflowView):
|
||||
workflow_class = update_job_workflow.UpdateJob
|
||||
|
||||
@shield("Unable to get job", redirect="jobs:index")
|
||||
def get_object(self):
|
||||
return freezer_api.Job(self.request).get(self.kwargs['job_id'])
|
||||
|
||||
def is_update(self):
|
||||
return 'job_id' in self.kwargs and bool(self.kwargs['job_id'])
|
||||
|
||||
@shield("Unable to get job", redirect="jobs:index")
|
||||
def get_initial(self):
|
||||
initial = super(EditJobWorkflowView, self).get_initial()
|
||||
if self.is_update():
|
||||
initial.update({'job_id': None})
|
||||
job = freezer_api.Job(self.request).get(self.kwargs['job_id'],
|
||||
json=True)
|
||||
initial.update(**job)
|
||||
initial.update(**job['job_schedule'])
|
||||
|
||||
return initial
|
||||
|
||||
|
||||
class ActionsInJobView(workflows.WorkflowView):
|
||||
workflow_class = actions_workflow.ConfigureActions
|
||||
workflow_class = update_actions_workflow.UpdateActions
|
||||
|
||||
@shield("Unable to get job", redirect="jobs:index")
|
||||
def get_object(self):
|
||||
|
@ -141,12 +141,24 @@ class InfoConfigurationAction(workflows.Action):
|
||||
return False
|
||||
|
||||
def _check_start_datetime(self, cleaned_data):
|
||||
if cleaned_data.get('start_datetime') and not \
|
||||
if cleaned_data.get('schedule_start_date') and not \
|
||||
self._validate_iso_format(
|
||||
cleaned_data.get('schedule_start_date')):
|
||||
msg = _("Start date time is not in ISO format.")
|
||||
self._errors['schedule_start_date'] = self.error_class([msg])
|
||||
|
||||
if (cleaned_data.get('schedule_start_date') and
|
||||
cleaned_data.get('schedule_end_date')) and\
|
||||
not cleaned_data.get('schedule_interval'):
|
||||
msg = _("Please provide this value.")
|
||||
self._errors['schedule_interval'] = self.error_class([msg])
|
||||
|
||||
if (cleaned_data.get('schedule_end_date') and
|
||||
not cleaned_data.get('schedule_start_date')) and\
|
||||
not cleaned_data.get('schedule_interval'):
|
||||
msg = _("Please provide this value.")
|
||||
self._errors['schedule_start_date'] = self.error_class([msg])
|
||||
|
||||
def _check_end_datetime(self, cleaned_data):
|
||||
if cleaned_data.get('end_datetime') and not \
|
||||
self._validate_iso_format(
|
||||
|
65
disaster_recovery/jobs/workflows/update_actions.py
Normal file
65
disaster_recovery/jobs/workflows/update_actions.py
Normal file
@ -0,0 +1,65 @@
|
||||
# (c) Copyright 2014,2015 Hewlett-Packard Development Company, L.P.
|
||||
#
|
||||
# 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 logging
|
||||
|
||||
from django import shortcuts
|
||||
from django.utils.translation import ugettext_lazy as _
|
||||
|
||||
from horizon import exceptions
|
||||
from horizon import forms
|
||||
from horizon import workflows
|
||||
|
||||
import disaster_recovery.api.api as freezer_api
|
||||
|
||||
|
||||
LOG = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class ActionsConfigurationAction(workflows.Action):
|
||||
actions = forms.CharField(
|
||||
required=False)
|
||||
|
||||
job_id = forms.CharField(
|
||||
required=False)
|
||||
|
||||
class Meta(object):
|
||||
name = _("Actions")
|
||||
slug = "actions"
|
||||
help_text_template = "disaster_recovery/jobs" \
|
||||
"/_actions.html"
|
||||
|
||||
|
||||
class ActionsConfiguration(workflows.Step):
|
||||
action_class = ActionsConfigurationAction
|
||||
contributes = ('actions', 'job_id')
|
||||
|
||||
|
||||
class UpdateActions(workflows.Workflow):
|
||||
slug = "update_actions"
|
||||
name = _("Update Actions")
|
||||
finalize_button_name = _("Save")
|
||||
success_message = _('Actions updated correctly.')
|
||||
failure_message = _('Unable to update actions.')
|
||||
success_url = "horizon:disaster_recovery:jobs:index"
|
||||
default_steps = (ActionsConfiguration,)
|
||||
|
||||
def handle(self, request, context):
|
||||
try:
|
||||
if context['job_id'] != '':
|
||||
freezer_api.Job(request).update(context['job_id'], context)
|
||||
return shortcuts.redirect('horizon:disaster_recovery:jobs:index')
|
||||
except Exception:
|
||||
exceptions.handle(request)
|
||||
return False
|
122
disaster_recovery/jobs/workflows/update_job.py
Normal file
122
disaster_recovery/jobs/workflows/update_job.py
Normal file
@ -0,0 +1,122 @@
|
||||
# (c) Copyright 2014,2015 Hewlett-Packard Development Company, L.P.
|
||||
#
|
||||
# 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 logging
|
||||
|
||||
import datetime
|
||||
|
||||
from django import shortcuts
|
||||
from django.utils.translation import ugettext_lazy as _
|
||||
|
||||
from horizon import exceptions
|
||||
from horizon import forms
|
||||
from horizon import workflows
|
||||
|
||||
import disaster_recovery.api.api as freezer_api
|
||||
|
||||
|
||||
LOG = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class InfoConfigurationAction(workflows.Action):
|
||||
|
||||
description = forms.CharField(
|
||||
label=_("Job Name"),
|
||||
help_text=_("Set a name for this job"),
|
||||
required=True)
|
||||
|
||||
job_id = forms.CharField(
|
||||
widget=forms.HiddenInput(),
|
||||
required=False)
|
||||
|
||||
schedule_start_date = forms.CharField(
|
||||
label=_("Start Date and Time"),
|
||||
required=False)
|
||||
|
||||
schedule_interval = forms.CharField(
|
||||
label=_("Interval"),
|
||||
required=False,
|
||||
help_text=_("Repeat this configuration in a minutes interval."))
|
||||
|
||||
schedule_end_date = forms.CharField(
|
||||
label=_("End Date and Time"),
|
||||
required=False)
|
||||
|
||||
def __init__(self, request, context, *args, **kwargs):
|
||||
self.request = request
|
||||
self.context = context
|
||||
super(InfoConfigurationAction, self).__init__(
|
||||
request, context, *args, **kwargs)
|
||||
|
||||
def clean(self):
|
||||
cleaned_data = super(InfoConfigurationAction, self).clean()
|
||||
self._check_start_datetime(cleaned_data)
|
||||
self._check_end_datetime(cleaned_data)
|
||||
return cleaned_data
|
||||
|
||||
def _validate_iso_format(self, start_date):
|
||||
try:
|
||||
return datetime.datetime.strptime(
|
||||
start_date, "%Y-%m-%dT%H:%M:%S")
|
||||
except ValueError:
|
||||
return False
|
||||
|
||||
def _check_start_datetime(self, cleaned_data):
|
||||
if cleaned_data.get('start_datetime') and not \
|
||||
self._validate_iso_format(
|
||||
cleaned_data.get('schedule_start_date')):
|
||||
msg = _("Start date time is not in ISO format.")
|
||||
self._errors['schedule_start_date'] = self.error_class([msg])
|
||||
|
||||
def _check_end_datetime(self, cleaned_data):
|
||||
if cleaned_data.get('end_datetime') and not \
|
||||
self._validate_iso_format(
|
||||
cleaned_data.get('schedule_end_date')):
|
||||
msg = _("End date time is not in ISO format.")
|
||||
self._errors['schedule_end_date'] = self.error_class([msg])
|
||||
|
||||
class Meta(object):
|
||||
name = _("Job Info")
|
||||
slug = "info"
|
||||
help_text_template = "disaster_recovery/jobs" \
|
||||
"/_scheduling.html"
|
||||
|
||||
|
||||
class InfoConfiguration(workflows.Step):
|
||||
action_class = InfoConfigurationAction
|
||||
contributes = ('description',
|
||||
'job_id',
|
||||
'actions',
|
||||
'schedule_start_date',
|
||||
'schedule_interval',
|
||||
'schedule_end_date')
|
||||
|
||||
|
||||
class UpdateJob(workflows.Workflow):
|
||||
slug = "update_job"
|
||||
name = _("Update Job")
|
||||
finalize_button_name = _("Save")
|
||||
success_message = _('Job created correctly.')
|
||||
failure_message = _('Unable to created job.')
|
||||
success_url = "horizon:disaster_recovery:jobs:index"
|
||||
default_steps = (InfoConfiguration,)
|
||||
|
||||
def handle(self, request, context):
|
||||
try:
|
||||
if context['job_id'] != '':
|
||||
freezer_api.Job(request).update(context['job_id'], context)
|
||||
return shortcuts.redirect('horizon:disaster_recovery:jobs:index')
|
||||
except Exception:
|
||||
exceptions.handle(request)
|
||||
return False
|
@ -75,31 +75,33 @@ function showRestoreOptions() {
|
||||
$("#id_storage").closest(".form-group").show();
|
||||
}
|
||||
|
||||
function showNovaOptions() {
|
||||
$("#id_mode").closest(".form-group").show();
|
||||
$("#id_nova_inst_id").closest(".form-group").show();
|
||||
$("#id_backup_name").closest(".form-group").show();
|
||||
$("#id_container").closest(".form-group").show();
|
||||
}
|
||||
|
||||
function showCinderOptions() {
|
||||
$("#id_mode").closest(".form-group").show();
|
||||
$("#id_cinder_vol_id").closest(".form-group").show();
|
||||
$("#id_backup_name").closest(".form-group").show();
|
||||
$("#id_container").closest(".form-group").show();
|
||||
}
|
||||
|
||||
function showSSHOptions() {
|
||||
$("#id_ssh_key").closest(".form-group").show();
|
||||
$("#id_ssh_username").closest(".form-group").show();
|
||||
$("#id_ssh_host").closest(".form-group").show();
|
||||
}
|
||||
|
||||
hideEverything();
|
||||
function triggerChanges() {
|
||||
$("#id_action").trigger('change');
|
||||
$("#id_mode").trigger('change');
|
||||
$("#id_storage").trigger('change');
|
||||
}
|
||||
|
||||
function hideModeOptions() {
|
||||
$("#id_cinder_vol_id").closest(".form-group").hide();
|
||||
$("#id_nova_inst_id").closest(".form-group").hide();
|
||||
$("#id_mysql_conf").closest(".form-group").hide();
|
||||
$("#id_sql_server_conf").closest(".form-group").hide();
|
||||
}
|
||||
|
||||
function hideSSHOptions() {
|
||||
$("#id_ssh_key").closest(".form-group").hide();
|
||||
$("#id_ssh_username").closest(".form-group").hide();
|
||||
$("#id_ssh_host").closest(".form-group").hide();
|
||||
}
|
||||
|
||||
$("#id_action").change(function () {
|
||||
// Update the inputs according freezer action
|
||||
|
||||
if ($("#id_action").val() === 'backup') {
|
||||
hideEverything();
|
||||
showBackupOptions();
|
||||
@ -117,22 +119,18 @@ $("#id_action").change(function () {
|
||||
|
||||
$("#id_storage").change(function () {
|
||||
// Update the inputs according freezer storage backend
|
||||
|
||||
if ($("#id_storage").val() === 'swift') {
|
||||
hideEverything();
|
||||
//hideEverything();
|
||||
showBackupOptions();
|
||||
("#id_mode").closest(".form-group").show();
|
||||
hideSSHOptions();
|
||||
} else if ($("#id_storage").val() === 'ssh') {
|
||||
hideEverything();
|
||||
//hideEverything();
|
||||
showBackupOptions();
|
||||
$("#id_mode").closest(".form-group").show();
|
||||
showSSHOptions();
|
||||
} else if ($("#id_storage").val() === 'local') {
|
||||
hideEverything();
|
||||
//hideEverything();
|
||||
showBackupOptions();
|
||||
$("#id_mode").closest(".form-group").show();
|
||||
} else {
|
||||
hideEverything();
|
||||
hideSSHOptions();
|
||||
}
|
||||
});
|
||||
|
||||
@ -141,37 +139,27 @@ $("#id_mode").change(function () {
|
||||
// Update the inputs according freezer mode
|
||||
if ($("#id_action").val() === 'backup') {
|
||||
if ($("#id_mode").val() === 'fs') {
|
||||
hideEverything();
|
||||
showBackupOptions();
|
||||
$("#id_advanced_configuration").closest(".form-group").show();
|
||||
hideModeOptions();
|
||||
} else if ($("#id_mode").val() === 'mysql') {
|
||||
hideEverything();
|
||||
showBackupOptions();
|
||||
hideModeOptions();
|
||||
$("#id_mysql_conf").closest(".form-group").show();
|
||||
$("#id_sql_server_conf").closest(".form-group").hide();
|
||||
$("#id_advanced_configuration").closest(".form-group").show();
|
||||
} else if ($("#id_mode").val() === 'mssql') {
|
||||
hideEverything();
|
||||
showBackupOptions();
|
||||
hideModeOptions();
|
||||
$("#id_sql_server_conf").closest(".form-group").show();
|
||||
$("#id_mysql_conf").closest(".form-group").hide();
|
||||
$("#id_advanced_configuration").closest(".form-group").show();
|
||||
} else if ($("#id_mode").val() === 'mongo') {
|
||||
hideEverything();
|
||||
showBackupOptions();
|
||||
$("#id_sql_server_conf").closest(".form-group").hide();
|
||||
$("#id_mysql_conf").closest(".form-group").hide();
|
||||
$("#id_advanced_configuration").closest(".form-group").show();
|
||||
hideModeOptions();
|
||||
} else if ($("#id_mode").val() === 'cinder') {
|
||||
hideEverything();
|
||||
showCinderOptions();
|
||||
$("#id_cinder_vol_id").closest(".form-group").show().addClass("required");
|
||||
$("#id_advanced_configuration").closest(".form-group").show();
|
||||
hideModeOptions();
|
||||
$("#id_cinder_vol_id").closest(".form-group").show();
|
||||
} else if ($("#id_mode").val() === 'nova') {
|
||||
hideEverything();
|
||||
showNovaOptions();
|
||||
$("#id_nova_inst_id").closest(".form-group").show().addClass("required");
|
||||
$("#id_advanced_configuration").closest(".form-group").show();
|
||||
hideModeOptions();
|
||||
$("#id_nova_inst_id").closest(".form-group").show();
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
$(function () {
|
||||
hideEverything();
|
||||
triggerChanges();
|
||||
});
|
@ -14,7 +14,7 @@ var parent = $(".sortable_lists").parent();
|
||||
parent.removeClass("col-sm-6");
|
||||
parent.addClass("col-sm-12");
|
||||
var siblings = parent.siblings();
|
||||
siblings.remove();
|
||||
siblings.hide();
|
||||
|
||||
|
||||
$("form").submit(function (event) {
|
||||
@ -29,6 +29,7 @@ $("form").submit(function (event) {
|
||||
|
||||
var job_id = $('#id_job_id').val();
|
||||
|
||||
|
||||
function get_url() {
|
||||
var url = $(location).attr("origin");
|
||||
url += '/disaster_recovery/api/actions/job/';
|
||||
|
Loading…
Reference in New Issue
Block a user