diff --git a/__init__.py b/__init__.py
index d95ce28..e69de29 100644
--- a/__init__.py
+++ b/__init__.py
@@ -1 +0,0 @@
-__author__ = 'jonas'
diff --git a/freezer_ui/actions/tables.py b/freezer_ui/actions/tables.py
deleted file mode 100644
index 6015ba7..0000000
--- a/freezer_ui/actions/tables.py
+++ /dev/null
@@ -1,73 +0,0 @@
-# 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
-from horizon.utils import functions as utils
-
-from horizon_web_ui.freezer_ui.django_utils import timestamp_to_string
-
-
-class ActionsTable(tables.DataTable):
- METADATA_LOADED_CHOICES = (
- (False, None),
- (True, True),
- )
-
- STATUS_DISPLAY = (
- ('pending', 'Pending'),
- ('started', 'Started'),
- ('abort_req', 'Abort Requested'),
- ('aborting', 'Aborting'),
- ('aborted', 'Aborted'),
- ('success', 'Success'),
- ('fail', 'Failed')
- )
-
- TYPE_DISPLAY = (
- ('restore', 'Restore'),
- ('backup', 'Backup (Unscheduled)')
- )
-
- client_id = tables.Column("client_id", verbose_name=_("Client Id"))
- type = tables.Column('action', verbose_name=_("Type"),
- display_choices=TYPE_DISPLAY)
- description = tables.Column("description", verbose_name=_("Description"))
- status = tables.Column('status',
- verbose_name=_("Status"),
- display_choices=STATUS_DISPLAY)
- created = tables.Column('time_created', verbose_name=_("Created"),
- filters=(timestamp_to_string,))
- started = tables.Column('time_started', verbose_name=_("Started"),
- filters=(timestamp_to_string,))
- ended = tables.Column('time_ended', verbose_name=_("Ended"),
- filters=(timestamp_to_string,))
-
- def get_object_id(self, action):
- return action.id
-
- def __init__(self, *args, **kwargs):
- super(ActionsTable, self).__init__(*args, **kwargs)
-
- if 'offset' in self.request.GET:
- self.offset = self.request.GET['offset']
- else:
- self.offset = 0
-
- def get_pagination_string(self):
- page_size = utils.get_page_size(self.request)
- return "=".join(['offset', str(self.offset + page_size)])
-
- class Meta(object):
- name = "jobs"
- verbose_name = _("Jobs")
diff --git a/freezer_ui/actions/urls.py b/freezer_ui/actions/urls.py
deleted file mode 100644
index 07913af..0000000
--- a/freezer_ui/actions/urls.py
+++ /dev/null
@@ -1,22 +0,0 @@
-# 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 patterns
-from django.conf.urls import url
-
-from horizon_web_ui.freezer_ui.actions import views
-
-
-urlpatterns = patterns(
- '',
- url(r'^$', views.IndexView.as_view(), name='index'),
-)
diff --git a/freezer_ui/actions/views.py b/freezer_ui/actions/views.py
deleted file mode 100644
index 5158086..0000000
--- a/freezer_ui/actions/views.py
+++ /dev/null
@@ -1,34 +0,0 @@
-# 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
-from horizon_web_ui.freezer_ui.actions import tables as actions_tables
-from horizon_web_ui.freezer_ui.api import api as freezer_api
-
-
-class IndexView(tables.DataTableView):
- name = _("Jobs")
- slug = "actions"
- table_class = actions_tables.ActionsTable
- template_name = ("freezer_ui/actions/index.html")
-
- def has_more_data(self, table):
- return self._has_more
-
- def get_data(self):
- backups, self._has_more = freezer_api.actions_list(
- self.request,
- offset=self.table.offset)
-
- return backups
diff --git a/freezer_ui/api/api.py b/freezer_ui/api/api.py
index c664448..4047e5a 100644
--- a/freezer_ui/api/api.py
+++ b/freezer_ui/api/api.py
@@ -17,8 +17,8 @@
from django.conf import settings
import warnings
import freezer.apiclient.client
+from horizon_web_ui.freezer_ui.utils import create_dict_action
-from horizon.utils import functions as utils
from horizon.utils.memoized import memoized # noqa
@@ -51,19 +51,19 @@ class Dict2Object(object):
class Action(Dict2Object):
- nested_dict = 'job'
+ nested_dict = 'job_action'
@property
def id(self):
- return self.action_id
+ return self.job_id
-class Configuration(Dict2Object):
- nested_dict = 'config_file'
+class Job(Dict2Object):
+ nested_dict = 'job_actions'
@property
def id(self):
- return self.config_id
+ return self.job_id
class Backup(Dict2Object):
@@ -81,17 +81,13 @@ class Client(Dict2Object):
def id(self):
return self.client_id
- @property
- def name(self):
- return self.client_id
-
-class ConfigClient(object):
-
- def __init__(self, name, last_backup):
- self.id = name
- self.name = name
- self.last_backup = last_backup
+class ActionJob(object):
+ def __init__(self, job_id, action_id, action, backup_name):
+ self.job_id = job_id
+ self.action_id = action_id
+ self.action = action
+ self.backup_name = backup_name
@memoized
@@ -125,188 +121,145 @@ def _freezerclient(request):
endpoint=api_url)
-def configuration_create(request, name=None, container_name=None,
- src_file=None, levels=None, optimize=None,
- compression=None, encryption_password=None,
- clients=[], start_datetime=None, interval=None,
- exclude=None, log_file=None, proxy=None,
- max_priority=False):
- """Create a new configuration file """
-
- data = {
- "name": name,
- "container_name": container_name,
- "src_file": src_file,
- "levels": levels,
- "optimize": optimize,
- "compression": compression,
- "encryption_password": encryption_password,
- "clients": clients,
- "start_datetime": start_datetime,
- "interval": interval,
- "exclude": exclude,
- "log_file": log_file,
- "proxy": proxy,
- "max_priority": max_priority
+def job_create(request, context):
+ """Create a new job file """
+ job = create_dict_action(**context)
+ job['description'] = job.pop('description', None)
+ job['client_id'] = job.pop('client_id', None)
+ schedule = {
+ 'end_datetime': job.pop('end_datetime', None),
+ 'interval': job.pop('interval', None),
+ 'start_datetime': job.pop('start_datetime', None),
}
- return _freezerclient(request).configs.create(data)
+ job['job_schedule'] = schedule
+ job['job_actions'] = []
+ return _freezerclient(request).jobs.create(job)
-def configuration_update(request, config_id=None, name=None,
- src_file=None, levels=None, optimize=None,
- compression=None, encryption_password=None,
- clients=[], start_datetime=None, interval=None,
- exclude=None, log_file=None, proxy=None,
- max_priority=False, container_name=None,):
-
- """Update a new configuration file """
- data = {
- "name": name,
- "container_name": container_name,
- "src_file": src_file,
- "levels": levels,
- "optimize": optimize,
- "compression": compression,
- "encryption_password": encryption_password,
- "clients": clients,
- "start_datetime": start_datetime,
- "interval": interval,
- "exclude": exclude,
- "log_file": log_file,
- "proxy": proxy,
- "max_priority": max_priority
+def job_edit(request, context):
+ """Edit an existing job file, but leave the actions to actions_edit"""
+ job = create_dict_action(**context)
+ job['description'] = job.pop('description', None)
+ job['client_id'] = job.pop('client_id', None)
+ schedule = {
+ 'end_datetime': job.pop('end_datetime', None),
+ 'interval': job.pop('interval', None),
+ 'start_datetime': job.pop('start_datetime', None),
}
- return _freezerclient(request).configs.update(config_id, data)
+ job['job_schedule'] = schedule
+ job_id = job.pop('original_name', None)
+ return _freezerclient(request).jobs.update(job_id, job)
-def configuration_delete(request, obj_id):
- return _freezerclient(request).configs.delete(obj_id)
+def job_delete(request, obj_id):
+ return _freezerclient(request).jobs.delete(obj_id)
-def configuration_clone(request, config_id):
- config_file = _freezerclient(request).configs.get(config_id)
- data = config_file[0]['config_file']
- data['name'] = '{0}_clone'.format(data['name'])
- return _freezerclient(request).configs.create(data)
+def job_clone(request, job_id):
+ job_file = _freezerclient(request).jobs.get(job_id)
+ job_file['description'] = \
+ '{0}_clone'.format(job_file['description'])
+ job_file.pop('job_id', None)
+ job_file.pop('_version', None)
+ return _freezerclient(request).jobs.create(job_file)
-def configuration_get(request, config_id):
- config_file = _freezerclient(request).configs.get(config_id)
- if config_file:
- return [Configuration(data) for data in config_file]
+def job_get(request, job_id):
+ job_file = _freezerclient(request).jobs.get(job_id)
+ if job_file:
+ job_item = [job_file]
+ job = [Job(data) for data in job_item]
+ return job
return []
-def configuration_list(request):
- configurations = _freezerclient(request).configs.list()
- configurations = [Configuration(data) for data in configurations]
- return configurations
+def job_list(request):
+ jobs = _freezerclient(request).jobs.list_all()
+ jobs = [Job(data) for data in jobs]
+ return jobs
-def clients_in_config(request, config_id):
- configuration = configuration_get(request, config_id)
- clients = []
- last_backup = None
- clients_dict = [c.get_dict() for c in configuration]
- for client in clients_dict:
- for client_id in client['config_file']['clients']:
- backups, has_more = backups_list(request, text_match=client_id)
- backups = [Backup(data) for data in backups]
- backups = [b.get_dict() for b in backups]
- for backup in backups:
- last_backup = backup.data_dict['backup_metadata']['timestamp']
- clients.append(ConfigClient(client_id, last_backup))
- return clients
+def action_create(request, context):
+ """Create a new action for a job """
+ action = {}
+
+ if context['max_retries']:
+ action['max_retries'] = context.pop('max_retries')
+ if context['max_retries_interval']:
+ action['max_retries_interval'] = context.pop('max_retries_interval')
+ if context['mandatory']:
+ action['mandatory'] = context.pop('mandatory')
+
+ job_id = context.pop('original_name')
+ job_action = create_dict_action(**context)
+ action['freezer_action'] = job_action
+ action_id = _freezerclient(request).actions.create(action)
+ action['action_id'] = action_id
+ job = _freezerclient(request).jobs.get(job_id)
+ job['job_actions'].append(action)
+ return _freezerclient(request).jobs.update(job_id, job)
-def client_list(request, limit=20):
- clients = _freezerclient(request).registration.list(limit=limit)
+def action_list(request):
+ actions = _freezerclient(request).actions.list()
+ actions = [Action(data) for data in actions]
+ return actions
+
+
+def actions_in_job(request, job_id):
+ job = _freezerclient(request).jobs.get(job_id)
+ actions = []
+ try:
+ job_id = job['job_id']
+ actions = [ActionJob(job_id,
+ action['action_id'],
+ action['freezer_action']['action'],
+ action['freezer_action']['backup_name'])
+ for action in job['job_actions']]
+ except Exception:
+ warnings.warn('No more actions in your job')
+ return actions
+
+
+def action_get(request, action_id):
+ action = _freezerclient(request).actions.get(action_id)
+ return action
+
+
+def action_update(request, context):
+ job_id = context.pop('original_name')
+ action_id = context.pop('action_id')
+
+ job = _freezerclient(request).jobs.get(job_id)
+
+ for a in job['job_actions']:
+ if a['action_id'] == action_id:
+
+ if context['max_retries']:
+ a['max_retries'] = context.pop('max_retries')
+ if context['max_retries_interval']:
+ a['max_retries_interval'] = \
+ context.pop('max_retries_interval')
+ if context['mandatory']:
+ a['mandatory'] = context.pop('mandatory')
+
+ updated_action = create_dict_action(**context)
+
+ a['freezer_action'].update(updated_action)
+
+ return _freezerclient(request).jobs.update(job_id, job)
+
+
+def action_delete(request, ids):
+ action_id, job_id = ids.split('===')
+ job = _freezerclient(request).jobs.get(job_id)
+ for action in job['job_actions']:
+ if action['action_id'] == action_id:
+ job['job_actions'].remove(action)
+ return _freezerclient(request).jobs.update(job_id, job)
+
+
+def client_list(request):
+ clients = _freezerclient(request).registration.list()
clients = [Client(client) for client in clients]
return clients
-
-
-def backups_list(request, offset=0, time_after=None, time_before=None,
- text_match=None):
- page_size = utils.get_page_size(request)
-
- search = {}
-
- if time_after:
- search['time_after'] = time_after
- if time_before:
- search['time_before'] = time_before
-
- if text_match:
- search['match'] = [
- {
- "_all": text_match,
- }
- ]
-
- backups = _freezerclient(request).backups.list(
- limit=page_size + 1,
- offset=offset,
- search=search)
-
- if len(backups) > page_size:
- backups.pop()
- has_more = True
- else:
- has_more = False
-
- # Wrap data in object for easier handling
- backups = [Backup(data) for data in backups]
-
- return backups, has_more
-
-
-def backup_get(request, backup_id):
- data = _freezerclient(request).backups.get(backup_id)
- if data:
- return Backup(data[0])
-
-
-def restore_action_create(request,
- backup_id,
- destination_client_id,
- destination_path,
- description=None,
- dry_run=False,
- max_prio=False):
- c = _freezerclient(request)
- backup = c.backups.get(backup_id)[0]
-
- action = {
- "job": {
- "action": "restore",
- "container_name": backup['backup_metadata']['container'],
- "restore-abs-path": destination_path,
- "backup-name": backup['backup_metadata']['backup_name'],
- "restore-from-host": backup['backup_metadata']['host_name'],
- "max_cpu_priority": max_prio,
- "dry_run": dry_run
- },
- "description": description,
- "client_id": destination_client_id
- }
-
- c.actions.create(action)
-
-
-def actions_list(request, offset=0):
- page_size = utils.get_page_size(request)
-
- actions = _freezerclient(request).actions.list(
- limit=page_size + 1,
- offset=offset)
-
- if len(actions) > page_size:
- actions.pop()
- has_more = True
- else:
- has_more = False
-
- # Wrap data in object for easier handling
- actions = [Action(data['action']) for data in actions]
-
- return actions, has_more
diff --git a/freezer_ui/backups/models.py b/freezer_ui/backups/models.py
deleted file mode 100644
index 1b3d5f9..0000000
--- a/freezer_ui/backups/models.py
+++ /dev/null
@@ -1,3 +0,0 @@
-"""
-Stub file to work around django bug: https://code.djangoproject.com/ticket/7198
-"""
diff --git a/freezer_ui/backups/restore_workflow.py b/freezer_ui/backups/restore_workflow.py
deleted file mode 100644
index 43f56ec..0000000
--- a/freezer_ui/backups/restore_workflow.py
+++ /dev/null
@@ -1,107 +0,0 @@
-# Copyright 2012 United States Government as represented by the
-# Administrator of the National Aeronautics and Space Administration.
-# All Rights Reserved.
-#
-# Copyright 2012 Nebula, Inc.
-#
-# 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.core.exceptions import ValidationError
-from django.utils.translation import ugettext_lazy as _
-
-from horizon import forms
-from horizon import workflows
-
-import horizon_web_ui.freezer_ui.api.api as freezer_api
-
-LOG = logging.getLogger(__name__)
-
-
-class DestinationAction(workflows.MembershipAction):
- path = forms.CharField(label=_("Destination Path"),
- initial='/home/',
- help_text="The path in which the backup should be "
- "restored",
- required=True)
- backup_id = forms.CharField(widget=forms.HiddenInput())
-
- def clean(self):
- if 'client' in self.request.POST:
- self.cleaned_data['client'] = self.request.POST['client']
- else:
- raise ValidationError('Client is required')
-
- return self.cleaned_data
-
- class Meta(object):
- name = _("Destination")
- slug = "destination"
-
-
-class Destination(workflows.Step):
- template_name = 'freezer_ui/backups/restore.html'
- action_class = DestinationAction
- contributes = ('client', 'path', 'backup_id')
-
- def has_required_fields(self):
- return True
-
-
-class OptionsAction(workflows.Action):
- description = forms.CharField(widget=forms.Textarea,
- label="Description",
- required=False,
- help_text="Free text description of this "
- "restore.")
-
- dry_run = forms.BooleanField(label=_("Dry Run"),
- required=False)
- max_prio = forms.BooleanField(label=_("Max Process Priority"),
- required=False)
-
- class Meta(object):
- name = _("Options")
-
-
-class Options(workflows.Step):
- action_class = OptionsAction
- contributes = ('description', 'dry_run', 'max_prio')
- after = Destination
-
-
-class ConfigureBackups(workflows.Workflow):
- slug = "restore"
- name = _("Restore")
- success_url = "horizon:freezer_ui:backups:index"
- success_message = "Restore job successfully queued. It will get " \
- "executed soon."
- wizard = False
- default_steps = (Destination, Options)
-
- def __init__(self, *args, **kwargs):
- super(ConfigureBackups, self).__init__(*args, **kwargs)
- pass
-
- def handle(self, request, data):
- freezer_api.restore_action_create(
- request,
- backup_id=data['backup_id'],
- destination_client_id=data['client'],
- destination_path=data['path'],
- description=data['description'],
- dry_run=data['dry_run'],
- max_prio=data['max_prio']
- )
- return True
diff --git a/freezer_ui/backups/tables.py b/freezer_ui/backups/tables.py
deleted file mode 100644
index 7dfc068..0000000
--- a/freezer_ui/backups/tables.py
+++ /dev/null
@@ -1,111 +0,0 @@
-# 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 django.utils import safestring
-from django.utils.translation import ugettext_lazy as _
-from horizon import tables
-from horizon.utils import functions as utils
-from horizon_web_ui.freezer_ui.django_utils import timestamp_to_string
-
-
-class Restore(tables.LinkAction):
- name = "restore"
- verbose_name = _("Restore")
- classes = ("ajax-modal", "btn-launch")
- ajax = True
-
- def get_link_url(self, datum=None):
- return reverse("horizon:freezer_ui:backups:restore",
- kwargs={'backup_id': datum.id})
-
- def allowed(self, request, instance):
- return True # is_loaded(instance)
-
-
-class BackupFilter(tables.FilterAction):
- filter_type = "server"
- filter_choices = (("before", "Created before", True),
- ("after", "Created after", True),
- ("between", "Created between", True),
- ("contains", "Contains text", True))
-
-
-def icons(backup):
- result = []
-
- placeholder = ''
-
- level_txt = "Level: {} ({} backup) out of {}".format(
- backup.level, "Full" if backup.level == 0 else "Incremental",
- backup.max_level)
- result.append(
- '{}'.format(
- level_txt, backup.level))
-
- if backup.encrypted:
- result.append(
- '')
- else:
- result.append(placeholder)
-
- if int(backup.total_broken_links) > 0:
- result.append(
- ''.format(backup.total_broken_links))
- else:
- result.append(placeholder)
-
- if backup.excluded_files:
- result.append(
- ''.format(len(backup.excluded_files)))
- else:
- result.append(placeholder)
-
- return safestring.mark_safe("".join(result))
-
-
-def backup_detail_view(backup):
- return reverse("horizon:freezer_ui:backups:detail", args=[backup.id])
-
-
-class BackupsTable(tables.DataTable):
- backup_name = tables.Column('backup_name', verbose_name=_("Backup Name"),
- link=backup_detail_view)
- host_name = tables.Column('host_name', verbose_name=_("Host Name"))
- created_by = tables.Column("user_name", verbose_name=_("Created By"))
- created = tables.Column("timestamp",
- verbose_name=_("Created At"),
- filters=[timestamp_to_string])
- icons = tables.Column(icons, verbose_name='Info')
-
- def __init__(self, *args, **kwargs):
- super(BackupsTable, self).__init__(*args, **kwargs)
-
- if 'offset' in self.request.GET:
- self.offset = self.request.GET['offset']
- else:
- self.offset = 0
-
- def get_object_id(self, backup):
- return backup.id
-
- def get_pagination_string(self):
- page_size = utils.get_page_size(self.request)
- return "=".join(['offset', str(self.offset + page_size)])
-
- class Meta(object):
- name = "vms"
- verbose_name = _("Backups")
- row_actions = (Restore,)
- table_actions = (BackupFilter, )
- multi_select = False
diff --git a/freezer_ui/backups/templates/backups/detail.html b/freezer_ui/backups/templates/backups/detail.html
deleted file mode 100644
index 1a5e67a..0000000
--- a/freezer_ui/backups/templates/backups/detail.html
+++ /dev/null
@@ -1,17 +0,0 @@
-{% extends 'base.html' %}
-
-{% load i18n %}
-{% block title %}{% trans "Backups" %}{% endblock %}
-
-{% block page_header %}
- {% include "horizon/common/_page_header.html" with title=_("Backups") %}
-{% endblock page_header %}
-
-{% block main %}
-
-
-{% endblock %}
diff --git a/freezer_ui/backups/templates/backups/index.html b/freezer_ui/backups/templates/backups/index.html
deleted file mode 100644
index 4987dcd..0000000
--- a/freezer_ui/backups/templates/backups/index.html
+++ /dev/null
@@ -1,17 +0,0 @@
-{% extends 'base.html' %}
-
-{% block css %}
- {% include "_stylesheets.html" %}
-
-{% endblock %}
-
-{% load i18n %}
-{% block title %}{% trans "VMs" %}{% endblock %}
-
-{% block page_header %}
- {% include "horizon/common/_page_header.html" with title=_("Backups") %}
-{% endblock page_header %}
-
-{% block main %}
- {{ table.render }}
-{% endblock %}
\ No newline at end of file
diff --git a/freezer_ui/backups/templates/backups/restore.html b/freezer_ui/backups/templates/backups/restore.html
deleted file mode 100644
index 0e744f7..0000000
--- a/freezer_ui/backups/templates/backups/restore.html
+++ /dev/null
@@ -1,46 +0,0 @@
-
-
-
-
- {% include "horizon/common/_form_fields.html" %}
- {{ table.render }}
-
-
- {{ step.get_help_text }}
-
-
diff --git a/freezer_ui/backups/urls.py b/freezer_ui/backups/urls.py
deleted file mode 100644
index 971b4e1..0000000
--- a/freezer_ui/backups/urls.py
+++ /dev/null
@@ -1,26 +0,0 @@
-# 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 patterns
-from django.conf.urls import url
-
-from horizon_web_ui.freezer_ui.backups import views
-
-
-urlpatterns = patterns(
- '',
- url(r'^$', views.IndexView.as_view(), name='index'),
- url(r'^(?P[^/]*)$', views.DetailView.as_view(), name='detail'),
- url(r'^restore/(?P.*)$',
- views.RestoreView.as_view(),
- name='restore'),
-)
diff --git a/freezer_ui/backups/views.py b/freezer_ui/backups/views.py
deleted file mode 100644
index a781eef..0000000
--- a/freezer_ui/backups/views.py
+++ /dev/null
@@ -1,141 +0,0 @@
-# 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 datetime
-import pprint
-import time
-
-from django.core.urlresolvers import reverse
-from django.template.defaultfilters import date as django_date
-from django.utils.translation import ugettext_lazy as _
-from django.views import generic
-import parsedatetime as pdt
-
-from horizon import exceptions
-from horizon import messages
-from horizon import tables
-from horizon import workflows
-from horizon_web_ui.freezer_ui.backups import tables as freezer_tables
-
-import horizon_web_ui.freezer_ui.api.api as freezer_api
-import restore_workflow
-
-
-class IndexView(tables.DataTableView):
- name = _("Backups")
- slug = "backups"
- table_class = freezer_tables.BackupsTable
- template_name = ("freezer_ui/backups/index.html")
-
- def has_more_data(self, table):
- return self._has_more
-
- def get_data(self):
- filter = self.get_filters(self.request,
- self.table.get_filter_field(),
- self.table.get_filter_string())
-
- backups, self._has_more = freezer_api.backups_list(
- self.request,
- offset=self.table.offset,
- time_after=filter['from'],
- time_before=filter['to'],
- text_match=filter['contains']
- )
-
- return backups
-
- def get_filters(self, request, filter_field, filter_string):
- cal = pdt.Calendar()
-
- filters = {}
- filters['from'] = None
- filters['to'] = None
- filters['contains'] = None
-
- if filter_field == 'between':
- result_range = cal.nlp(filter_string)
-
- if result_range and len(result_range) == 2:
- filters['from'] = int(
- time.mktime(result_range[0][0].timetuple()))
- filters['to'] = int(
- time.mktime(result_range[1][0].timetuple()))
- else:
- messages.warning(
- request,
- "Please enter two dates. E.g: '01/01/2014 - 05/09/2015'.")
- elif filter_field in ['before', 'after']:
- result, what = cal.parse(filter_string)
-
- if what == 0:
- messages.warning(
- self.table.request,
- "Please enter a date/time. E.g: '01/01/2014 12pm' or '1 we"
- "ek ago'.")
- else:
- field = 'to' if filter_field == 'before' else 'from'
-
- dt = datetime.datetime(*result[:6])
-
- if what == 1: # a date without time
- # use .date() to remove time part
- filters[field] = int(time.mktime(dt.date().timetuple()))
- elif what in [2, 3]: # date and time or time with current date
- filters[field] = int(time.mktime(dt.timetuple()))
- else:
- raise Exception(
- 'Unknown result when parsing date: {}'.format(what))
- elif filter_field == 'contains':
- filters['contains'] = filter_string.lower()
-
- return filters
-
-
-class DetailView(generic.TemplateView):
- template_name = 'freezer_ui/backups/detail.html'
-
- def get_context_data(self, **kwargs):
-
- backup = freezer_api.get_backup(self.request, kwargs['backup_id'])
- return {'data': pprint.pformat(backup.data_dict)}
-
-
-class RestoreView(workflows.WorkflowView):
- workflow_class = restore_workflow.ConfigureBackups
-
- def get_object(self, *args, **kwargs):
- id = self.kwargs['backup_id']
- try:
- return freezer_api.get_backup(self.request, id)
- except Exception:
- redirect = reverse("horizon:freezer_ui:backups:index")
- msg = _('Unable to retrieve details.')
- exceptions.handle(self.request, msg, redirect=redirect)
-
- def is_update(self):
- return 'name' in self.kwargs and bool(self.kwargs['name'])
-
- def get_workflow_name(self):
- backup = freezer_api.backup_get(self.request, self.kwargs['backup_id'])
- backup_date = datetime.datetime.fromtimestamp(int(backup.timestamp))
- backup_date_str = django_date(backup_date, 'SHORT_DATETIME_FORMAT')
- return "Restore '{}' from {}".format(
- backup.backup_name, backup_date_str)
-
- def get_initial(self):
- return {"backup_id": self.kwargs['backup_id']}
-
- def get_workflow(self, *args, **kwargs):
- workflow = super(RestoreView, self).get_workflow(*args, **kwargs)
- workflow.name = self.get_workflow_name()
-
- return workflow
diff --git a/freezer_ui/configurations/__init__.py b/freezer_ui/configurations/__init__.py
deleted file mode 100644
index d95ce28..0000000
--- a/freezer_ui/configurations/__init__.py
+++ /dev/null
@@ -1 +0,0 @@
-__author__ = 'jonas'
diff --git a/freezer_ui/configurations/browsers.py b/freezer_ui/configurations/browsers.py
deleted file mode 100644
index 5a0e4dd..0000000
--- a/freezer_ui/configurations/browsers.py
+++ /dev/null
@@ -1,28 +0,0 @@
-# Copyright 2012 Nebula, Inc.
-#
-# 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 browsers
-
-from horizon_web_ui.freezer_ui.configurations import tables
-
-
-class ContainerBrowser(browsers.ResourceBrowser):
- name = "backup_configuration"
- verbose_name = _("Backup Configuration")
- navigation_table_class = tables.BackupConfigsTable
- content_table_class = tables.InstancesTable
- navigable_item_name = _("Backup Configuration")
- navigation_kwarg_name = "name"
diff --git a/freezer_ui/configurations/models.py b/freezer_ui/configurations/models.py
deleted file mode 100644
index 1b3d5f9..0000000
--- a/freezer_ui/configurations/models.py
+++ /dev/null
@@ -1,3 +0,0 @@
-"""
-Stub file to work around django bug: https://code.djangoproject.com/ticket/7198
-"""
diff --git a/freezer_ui/configurations/panel.py b/freezer_ui/configurations/panel.py
deleted file mode 100644
index 082e3fd..0000000
--- a/freezer_ui/configurations/panel.py
+++ /dev/null
@@ -1,24 +0,0 @@
-# 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 horizon_web_ui.freezer_ui import dashboard
-
-
-class BackupConfigsPanel(horizon.Panel):
- name = _("Configurations")
- slug = "configurations"
-
-
-dashboard.Freezer.register(BackupConfigsPanel)
diff --git a/freezer_ui/configurations/tables.py b/freezer_ui/configurations/tables.py
deleted file mode 100644
index 3351ee4..0000000
--- a/freezer_ui/configurations/tables.py
+++ /dev/null
@@ -1,161 +0,0 @@
-# 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 datetime
-
-from django import shortcuts
-from django.utils import safestring
-from django.utils.translation import ugettext_lazy as _
-from django.utils.translation import ungettext_lazy
-
-from horizon import messages
-from horizon import tables
-from horizon.utils.urlresolvers import reverse
-
-import horizon_web_ui.freezer_ui.api.api as freezer_api
-from horizon_web_ui.freezer_ui.django_utils import timestamp_to_string
-
-
-def format_last_backup(last_backup):
- last_backup_ts = datetime.datetime.fromtimestamp(last_backup)
- ten_days_later = last_backup_ts + datetime.timedelta(days=10)
- today = datetime.datetime.today()
-
- if last_backup is None:
- colour = 'red'
- icon = 'fire'
- text = 'Never'
- elif ten_days_later < today:
- colour = 'orange'
- icon = 'thumbs-down'
- text = timestamp_to_string(last_backup)
- else:
- colour = 'green'
- icon = 'thumbs-up'
- text = timestamp_to_string(last_backup)
-
- return safestring.mark_safe(
- ' {}'.format(colour, icon, text))
-
-
-class Restore(tables.Action):
- name = "restore"
- verbose_name = _("Restore")
-
- def single(self, table, request, instance):
- messages.info(request, "Needs to be implemented")
-
- def allowed(self, request, instance):
- return True
-
-
-class DeleteConfig(tables.DeleteAction):
- name = "delete"
- classes = ("btn-danger",)
- icon = "remove"
- help_text = _("Delete configurations are not recoverable.")
-
- @staticmethod
- def action_present(count):
- return ungettext_lazy(
- u"Delete Configuration File",
- u"Delete Configuration Files",
- count
- )
-
- @staticmethod
- def action_past(count):
- return ungettext_lazy(
- u"Deleted Configuration File",
- u"Deleted Configuration Files",
- count
- )
-
- def delete(self, request, obj_id):
- return freezer_api.configuration_delete(request, obj_id)
-
-
-class CloneConfig(tables.Action):
- name = "clone"
- verbose_name = _("Clone")
- # classes = ("ajax-modal",)
- help_text = _("Clone and edit a configuration file")
-
- def single(self, table, request, obj_id):
- freezer_api.configuration_clone(request, obj_id)
- return shortcuts.redirect('horizon:freezer_ui:configurations:index')
-
-
-class EditConfig(tables.LinkAction):
- name = "edit"
- verbose_name = _("Edit")
- classes = ("ajax-modal",)
-
- def get_link_url(self, datum=None):
- return reverse("horizon:freezer_ui:configurations:configure",
- kwargs={'name': datum.config_id})
-
-
-def get_backup_configs_link(backup_config):
- return reverse('horizon:freezer_ui:configurations:index',
- kwargs={'config_id': backup_config.config_id})
-
-
-class CreateConfig(tables.LinkAction):
- name = "create"
- verbose_name = _("Create Configuration")
- url = "horizon:freezer_ui:configurations:create"
- classes = ("ajax-modal",)
- icon = "plus"
-
-
-class BackupConfigsTable(tables.DataTable):
- name = tables.Column("name", link=get_backup_configs_link,
- verbose_name=_("Configuration Name"))
-
- def get_object_id(self, backup_config):
- return backup_config.id
-
- class Meta(object):
- name = "backup_configuration"
- verbose_name = _("Backup Configurations")
- table_actions = (CreateConfig,)
- footer = False
- multi_select = False
- row_actions = (EditConfig,
- CloneConfig,
- DeleteConfig, )
-
-
-class ObjectFilterAction(tables.FilterAction):
- def allowed(self, request, datum):
- return bool(self.table.kwargs['config_id'])
-
-
-class InstancesTable(tables.DataTable):
- client = tables.Column('name', verbose_name=_("Client Name"))
-
- created = tables.Column('last_backup',
- filters=(format_last_backup,),
- verbose_name=_("Last backup"))
-
- def get_object_id(self, container):
- return container.name
-
- class Meta(object):
- name = "clients"
- verbose_name = _("Clients")
- table_actions = (ObjectFilterAction,)
- row_actions = (Restore,)
- footer = False
- multi_select = False
diff --git a/freezer_ui/configurations/templates/configurations/browser.html b/freezer_ui/configurations/templates/configurations/browser.html
deleted file mode 100644
index a5e354f..0000000
--- a/freezer_ui/configurations/templates/configurations/browser.html
+++ /dev/null
@@ -1,11 +0,0 @@
-{% extends 'base.html' %}
-{% load i18n %}
-{% block title %}{% trans "Backup Configurations" %}{% endblock %}
-
-{% block page_header %}
- {% include "horizon/common/_page_header.html" with title=_("Backup Configurations") %}
-{% endblock page_header %}
-
-{% block main %}
- {{ backup_configuration_browser.render }}
-{% endblock %}
diff --git a/freezer_ui/configurations/utils.py b/freezer_ui/configurations/utils.py
deleted file mode 100644
index f62b258..0000000
--- a/freezer_ui/configurations/utils.py
+++ /dev/null
@@ -1,40 +0,0 @@
-# Copyright 2014 Hewlett-Packard
-#
-# 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.
-
-
-class Configuration(object):
- def __init__(self, data_dict):
- self.data_dict = data_dict
-
- @property
- def id(self):
- return self.config_id
-
- def __getattr__(self, attr):
- """Make data_dict fields available via class interface """
- if attr in self.data_dict:
- return self.data_dict[attr]
- elif attr in self.data_dict['config_file']:
- return self.data_dict['config_file'][attr]
- else:
- return object.__getattribute__(self, attr)
-
-
-class Client(object):
- """Aggregate clients and metadata """
-
- def __init__(self, client):
- self.name = client
- self.clients = client
- self.client_id = client
diff --git a/freezer_ui/configurations/views.py b/freezer_ui/configurations/views.py
deleted file mode 100644
index 1dd2026..0000000
--- a/freezer_ui/configurations/views.py
+++ /dev/null
@@ -1,94 +0,0 @@
-# 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.core.urlresolvers import reverse
-from django.utils.translation import ugettext_lazy as _
-
-from horizon import workflows
-
-from horizon import browsers
-from horizon import exceptions
-import horizon_web_ui.freezer_ui.api.api as freezer_api
-import horizon_web_ui.freezer_ui.configurations.browsers as project_browsers
-import workflows.configure as configure_workflow
-
-
-LOG = logging.getLogger(__name__)
-
-
-class ConfigureWorkflowView(workflows.WorkflowView):
- workflow_class = configure_workflow.ConfigureBackups
-
- def get_object(self, *args, **kwargs):
- config_id = self.kwargs['name']
- try:
- return freezer_api.configuration_get(self.request, config_id)[0]
- except Exception:
- redirect = reverse("horizon:freezer_ui:configurations:index")
- msg = _('Unable to retrieve details.')
- exceptions.handle(self.request, msg, redirect=redirect)
-
- def is_update(self):
- return 'name' in self.kwargs and bool(self.kwargs['name'])
-
- def get_initial(self):
- initial = super(ConfigureWorkflowView, self).get_initial()
- if self.is_update():
- initial.update({'original_name': None})
- config = self.get_object()
- initial['name'] = config.name
- initial['container_name'] = config.container_name
- initial['config_id'] = config.config_id
- initial['src_file'] = config.src_file
- initial['levels'] = config.levels
- initial['optimize'] = config.optimize
- initial['compression'] = config.compression
- initial['encryption_password'] = config.encryption_password
- initial['start_datetime'] = config.start_datetime
- initial['interval'] = config.interval
- initial['exclude'] = config.exclude
- initial['log_file'] = config.log_file
- initial['encryption_password'] = config.encryption_password
- initial['proxy'] = config.proxy
- initial['max_priority'] = config.max_priority
- initial['clients'] = config.clients
- initial['original_name'] = config.config_id
- initial.update({'original_name': config.config_id})
- return initial
-
-
-class BackupConfigsView(browsers.ResourceBrowserView):
- browser_class = project_browsers.ContainerBrowser
- template_name = "freezer_ui/configurations/browser.html"
-
- def get_backup_configuration_data(self):
- configurations = []
- try:
- configurations = freezer_api.configuration_list(self.request)
- except Exception:
- msg = _('Unable to retrieve configuration file list.')
- exceptions.handle(self.request, msg)
- return configurations
-
- def get_clients_data(self):
- configuration = []
- try:
- if self.kwargs['config_id']:
- configuration = freezer_api.clients_in_config(
- self.request, self.kwargs['config_id'])
-
- except Exception:
- msg = _('Unable to retrieve instances for this configuration.')
- exceptions.handle(self.request, msg)
- return configuration
diff --git a/freezer_ui/configurations/workflows/configure.py b/freezer_ui/configurations/workflows/configure.py
deleted file mode 100644
index 8fbc061..0000000
--- a/freezer_ui/configurations/workflows/configure.py
+++ /dev/null
@@ -1,315 +0,0 @@
-# Copyright 2012 United States Government as represented by the
-# Administrator of the National Aeronautics and Space Administration.
-# All Rights Reserved.
-#
-# Copyright 2012 Nebula, Inc.
-#
-# 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.utils.translation import ugettext_lazy as _
-from django.views.decorators.debug import sensitive_variables # noqa
-from horizon import exceptions
-from horizon import forms
-from horizon import workflows
-
-import horizon_web_ui.freezer_ui.api.api as freezer_api
-
-LOG = logging.getLogger(__name__)
-
-
-class BackupConfigurationAction(workflows.Action):
- original_name = forms.CharField(
- widget=forms.HiddenInput(),
- required=False)
-
- name = forms.CharField(
- label=_("Configuration Name"),
- required=True)
-
- container_name = forms.CharField(
- label=_("Swift Container Name"),
- required=True)
-
- mode = forms.ChoiceField(
- help_text="Choose what you want to backup",
- required=True)
-
- src_file = forms.CharField(
- label=_("Source File/Directory"),
- help_text="The file or directory you want to back up to Swift",
- required=True)
-
- def populate_mode_choices(self, request, context):
- return [
- ('fs', _("File system")),
- ('snapshot', _("Snapshot")),
- ('mongo', _("MongoDB")),
- ('mysql', _("MySQL")),
- ('mssql', _("Microsoft SQL Server")),
- ('elastic', _("ElasticSearch")),
- ('postgres', _("Postgres")),
- ]
-
- class Meta(object):
- name = _("Backup")
-
-
-class BackupConfiguration(workflows.Step):
- action_class = BackupConfigurationAction
- contributes = ('mode',
- 'name',
- 'container_name',
- 'src_file',
- 'original_name')
-
-
-class OptionsConfigurationAction(workflows.Action):
- levels = forms.IntegerField(
- label=_("Number of incremental backups"),
- initial=0,
- min_value=0,
- required=False,
- help_text="Set the backup level used with tar"
- " to implement incremental backup. "
- "If a level 1 is specified but no "
- "level 0 is already available, a "
- "level 0 will be done and "
- "subsequently backs to level 1. "
- "Default 0 (No Incremental)")
-
- optimize = forms.ChoiceField(
- choices=[('speed', _("Speed (tar)")),
- ('bandwith', "Bandwith/Space (rsync)")],
- help_text="",
- label='Optimize for...',
- required=False)
-
- compression = forms.ChoiceField(
- choices=[('gzip', _("Minimum Compression (GZip/Zip)")),
- ('bzip', _("Medium Compression (BZip2")),
- ('xz', _("Maximum Compression (XZ)"))],
- help_text="",
- label='Compression Level',
- required=False)
-
- encryption_password = forms.CharField(
- label=_("Encryption Password"), # encryption key
- widget=forms.PasswordInput(),
- help_text="",
- required=False)
-
- class Meta(object):
- name = _("Options")
-
-
-class OptionsConfiguration(workflows.Step):
- action_class = OptionsConfigurationAction
- contributes = ('levels',
- 'optimize',
- 'compression',
- 'encryption_password',)
-
-
-class ClientsConfigurationAction(workflows.MembershipAction):
- def __init__(self, request, *args, **kwargs):
- super(ClientsConfigurationAction, self).__init__(request,
- *args,
- **kwargs)
-
- err_msg_configured = 'Unable to retrieve list of configured clients.'
- err_msg_all = 'Unable to retrieve list of clients.'
-
- default_role_field_name = self.get_default_role_field_name()
- self.fields[default_role_field_name] = forms.CharField(required=False)
- self.fields[default_role_field_name].initial = 'member'
-
- field_name = self.get_member_field_name('member')
- self.fields[field_name] = forms.MultipleChoiceField(required=False)
-
- all_clients = []
- try:
- all_clients = freezer_api.client_list(request)
- except Exception:
- exceptions.handle(request, err_msg_all)
-
- clients = [(c.client_id, c.name) for c in all_clients]
-
- self.fields[field_name].choices = clients
-
- if request.method == 'POST':
- return
-
- initial_clients = []
- try:
- original_name = args[0].get('original_name', None)
- if original_name:
- configured_clients = \
- freezer_api.clients_in_config(request, original_name)
- initial_clients = [client.id for client in configured_clients]
- except Exception:
- exceptions.handle(request, err_msg_configured)
-
- self.fields[field_name].initial = initial_clients
-
- class Meta(object):
- name = _("Clients")
- slug = "configure_clients"
-
-
-class ClientsConfiguration(workflows.UpdateMembersStep):
- action_class = ClientsConfigurationAction
- help_text = _(
- "Select the clients that will be backed up using this configuration.")
- available_list_title = _("All Clients")
- members_list_title = _("Selected Clients")
- no_available_text = _("No clients found.")
- no_members_text = _("No clients selected.")
- show_roles = False
- contributes = ("clients",)
-
- def contribute(self, data, context):
- if data:
- member_field_name = self.get_member_field_name('member')
- context['clients'] = data.get(member_field_name, [])
- return context
-
-
-class SchedulingConfigurationAction(workflows.Action):
- start_datetime = forms.CharField(
- label=_("Start Date and Time"),
- required=False,
- help_text=_("Set a start date and time for backups"))
-
- interval = forms.CharField(
- label=_("Interval"),
- required=False,
- help_text=_("Repeat this configuration in an interval. e.g. 24 hours"))
-
- class Meta(object):
- name = _("Scheduling")
-
-
-class SchedulingConfiguration(workflows.Step):
- action_class = SchedulingConfigurationAction
- contributes = ('start_datetime',
- 'interval',)
-
-
-class AdvancedConfigurationAction(workflows.Action):
- exclude = forms.CharField(
- label=_("Exclude Files"),
- help_text="Exclude files, given as a PATTERN.Ex:"
- " --exclude '*.log' will exclude any "
- "file with name ending with .log. "
- "Default no exclude",
- required=False)
- log_file = forms.CharField(
- label=_("Log File Path"),
- help_text="Set log file. By default logs to "
- "/var/log/freezer.log If that file "
- "is not writable, freezer tries to "
- "log to ~/.freezer/freezer.log",
- required=False)
-
- proxy = forms.CharField(
- label=_("Proxy URL"),
- help_text="Enforce proxy that alters system "
- "HTTP_PROXY and HTTPS_PROXY",
- widget=forms.URLInput(),
- required=False)
-
- max_priority = forms.BooleanField(
- label=_("Max Priority"),
- help_text="Set the cpu process to the "
- "highest priority (i.e. -20 "
- "on Linux) and real-time for "
- "I/O. The process priority "
- "will be set only if nice and "
- "ionice are installed Default "
- "disabled. Use with caution.",
- widget=forms.CheckboxInput(),
- required=False)
-
- class Meta(object):
- name = _("Advanced Configuration")
-
-
-class AdvancedConfiguration(workflows.Step):
- action_class = AdvancedConfigurationAction
- contributes = ('exclude',
- 'log_file',
- 'proxy',
- 'max_priority')
-
-
-class ConfigureBackups(workflows.Workflow):
- slug = "configuration"
- name = _("Configuration")
- finalize_button_name = _("Save")
- success_message = _('Configuration file saved correctly.')
- failure_message = _('Unable to save configuration file.')
- success_url = "horizon:freezer_ui:configurations:index"
-
- default_steps = (BackupConfiguration,
- OptionsConfiguration,
- ClientsConfiguration,
- SchedulingConfiguration,
- AdvancedConfiguration)
-
- @sensitive_variables('encryption_password',
- 'confirm_encryption_password')
- def handle(self, request, context):
- try:
- if context['original_name'] == '':
- freezer_api.configuration_create(
- request,
- name=context['name'],
- container_name=context['container_name'],
- src_file=context['src_file'],
- levels=context['levels'], # if empty save 0 not null
- optimize=context['optimize'],
- compression=context['compression'],
- encryption_password=context['encryption_password'],
- clients=context['clients'], # save the name of the client
- start_datetime=context['start_datetime'],
- interval=context['interval'],
- exclude=context['exclude'],
- log_file=context['log_file'],
- proxy=context['proxy'],
- max_priority=context['max_priority'],
- )
- else:
- freezer_api.configuration_update(
- request,
- config_id=context['original_name'],
- name=context['name'],
- container_name=context['container_name'],
- src_file=context['src_file'],
- levels=context['levels'], # if empty save 0 not null
- optimize=context['optimize'],
- compression=context['compression'],
- encryption_password=context['encryption_password'],
- clients=context['clients'], # save the name of the client
- start_datetime=context['start_datetime'],
- interval=context['interval'],
- exclude=context['exclude'],
- log_file=context['log_file'],
- proxy=context['proxy'],
- max_priority=context['max_priority'],
- )
- return True
- except Exception:
- exceptions.handle(request)
- return False
diff --git a/freezer_ui/dashboard.py b/freezer_ui/dashboard.py
index b90b42a..d0604e2 100644
--- a/freezer_ui/dashboard.py
+++ b/freezer_ui/dashboard.py
@@ -15,17 +15,17 @@ from django.utils.translation import ugettext_lazy as _
import horizon
-class Mygroup(horizon.PanelGroup):
- slug = "mygroup"
- name = _("Freezer")
- panels = ('overview', 'configurations', 'backups', 'actions')
+class FreezerDR(horizon.PanelGroup):
+ slug = "freezerdr"
+ name = _("Backup and Restore")
+ panels = ('jobs',)
class Freezer(horizon.Dashboard):
- name = _("Backup Restore DR")
+ name = _("Disaster Recovery")
slug = "freezer_ui"
- panels = (Mygroup,)
- default_panel = 'overview'
+ panels = (FreezerDR,)
+ default_panel = 'jobs'
horizon.register(Freezer)
diff --git a/freezer_ui/actions/__init__.py b/freezer_ui/jobs/__init__.py
similarity index 100%
rename from freezer_ui/actions/__init__.py
rename to freezer_ui/jobs/__init__.py
diff --git a/freezer_ui/backups/panel.py b/freezer_ui/jobs/browsers.py
similarity index 57%
rename from freezer_ui/backups/panel.py
rename to freezer_ui/jobs/browsers.py
index 919a73c..17d7a12 100644
--- a/freezer_ui/backups/panel.py
+++ b/freezer_ui/jobs/browsers.py
@@ -2,7 +2,7 @@
# 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
+# 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
@@ -11,15 +11,14 @@
# under the License.
from django.utils.translation import ugettext_lazy as _
-
-import horizon
-
-import horizon_web_ui.freezer_ui.dashboard as dashboard
+from horizon import browsers
+from horizon_web_ui.freezer_ui.jobs import tables
-class BackupsPanel(horizon.Panel):
- name = _("Backups")
- slug = "backups"
-
-
-dashboard.Freezer.register(BackupsPanel)
+class ContainerBrowser(browsers.ResourceBrowser):
+ name = "backup_configuration"
+ verbose_name = _("Job Configuration")
+ navigation_table_class = tables.JobsTable
+ content_table_class = tables.ActionsTable
+ navigable_item_name = _("Jobs")
+ navigation_kwarg_name = "name"
diff --git a/freezer_ui/actions/models.py b/freezer_ui/jobs/models.py
similarity index 100%
rename from freezer_ui/actions/models.py
rename to freezer_ui/jobs/models.py
diff --git a/freezer_ui/actions/panel.py b/freezer_ui/jobs/panel.py
similarity index 81%
rename from freezer_ui/actions/panel.py
rename to freezer_ui/jobs/panel.py
index 7e35a68..43a1886 100644
--- a/freezer_ui/actions/panel.py
+++ b/freezer_ui/jobs/panel.py
@@ -2,7 +2,7 @@
# 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
+# 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
@@ -13,13 +13,12 @@
from django.utils.translation import ugettext_lazy as _
import horizon
-
from horizon_web_ui.freezer_ui import dashboard
-class ActionsPanel(horizon.Panel):
+class JobsPanel(horizon.Panel):
name = _("Jobs")
- slug = "actions"
+ slug = "jobs"
-dashboard.Freezer.register(ActionsPanel)
+dashboard.Freezer.register(JobsPanel)
diff --git a/freezer_ui/jobs/tables.py b/freezer_ui/jobs/tables.py
new file mode 100644
index 0000000..dd3a27d
--- /dev/null
+++ b/freezer_ui/jobs/tables.py
@@ -0,0 +1,226 @@
+# 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 datetime
+from django import shortcuts
+from django.utils import safestring
+from django.utils.translation import ugettext_lazy as _
+from django.utils.translation import ungettext_lazy
+
+from horizon import messages
+from horizon import tables
+from horizon.utils.urlresolvers import reverse
+
+import horizon_web_ui.freezer_ui.api.api as freezer_api
+from horizon_web_ui.freezer_ui.django_utils import timestamp_to_string
+
+
+def format_last_backup(last_backup):
+ last_backup_ts = datetime.datetime.fromtimestamp(last_backup)
+ ten_days_later = last_backup_ts + datetime.timedelta(days=10)
+ today = datetime.datetime.today()
+
+ if last_backup is None:
+ colour = 'red'
+ icon = 'fire'
+ text = 'Never'
+ elif ten_days_later < today:
+ colour = 'orange'
+ icon = 'thumbs-down'
+ text = timestamp_to_string(last_backup)
+ else:
+ colour = 'green'
+ icon = 'thumbs-up'
+ text = timestamp_to_string(last_backup)
+
+ return safestring.mark_safe(
+ ' {}'.format(colour, icon, text))
+
+
+class Restore(tables.Action):
+ name = "restore"
+ verbose_name = _("Restore")
+
+ def single(self, table, request, instance):
+ messages.info(request, "Needs to be implemented")
+
+ def allowed(self, request, instance):
+ return True
+
+
+class DeleteJob(tables.DeleteAction):
+ name = "delete"
+ classes = ("btn-danger",)
+ icon = "remove"
+ help_text = _("Delete jobs is not recoverable.")
+
+ @staticmethod
+ def action_present(count):
+ return ungettext_lazy(
+ u"Delete Job File",
+ u"Delete Job Files",
+ count
+ )
+
+ @staticmethod
+ def action_past(count):
+ return ungettext_lazy(
+ u"Deleted Job File",
+ u"Deleted Job Files",
+ count
+ )
+
+ def delete(self, request, obj_id):
+ return freezer_api.job_delete(request, obj_id)
+
+
+class CloneJob(tables.Action):
+ name = "clone"
+ verbose_name = _("Clone Job")
+ help_text = _("Clone and edit a job file")
+
+ def single(self, table, request, obj_id):
+ freezer_api.job_clone(request, obj_id)
+ return shortcuts.redirect('horizon:freezer_ui:jobs:index')
+
+
+class EditJob(tables.LinkAction):
+ name = "edit"
+ verbose_name = _("Edit Job")
+ classes = ("ajax-modal",)
+ icon = "pencil"
+
+ def get_link_url(self, datum=None):
+ return reverse("horizon:freezer_ui:jobs:configure",
+ kwargs={'backup_name': datum.job_id})
+
+
+def get_backup_configs_link(backup_config):
+ return reverse('horizon:freezer_ui:jobs:index',
+ kwargs={'job_id': backup_config.job_id})
+
+
+class CreateJob(tables.LinkAction):
+ name = "create"
+ verbose_name = _("Create Job")
+ url = "horizon:freezer_ui:jobs:create"
+ classes = ("ajax-modal",)
+ icon = "plus"
+
+
+class CreateAction(tables.LinkAction):
+ name = "create_action"
+ verbose_name = _("Create Action")
+ url = "horizon:freezer_ui:jobs:create_action"
+ classes = ("ajax-modal",)
+ icon = "plus"
+
+ def get_link_url(self, datum=None):
+ return reverse("horizon:freezer_ui:jobs:create_action",
+ kwargs={'job_id': datum.job_id})
+
+
+class JobsTable(tables.DataTable):
+ job_name = tables.Column("description",
+ link=get_backup_configs_link,
+ verbose_name=_("Job Name"))
+
+ result = tables.Column("result",
+ verbose_name=_("Last Result"))
+
+ def get_object_id(self, backup_config):
+ return backup_config.id
+
+ class Meta(object):
+ name = "jobs"
+ verbose_name = _("Jobs")
+ table_actions = (CreateJob,)
+ footer = False
+ multi_select = False
+ row_actions = (CreateAction,
+ EditJob,
+ CloneJob,
+ DeleteJob,)
+
+
+class DeleteAction(tables.DeleteAction):
+ name = "delete"
+ classes = ("btn-danger",)
+ icon = "remove"
+ help_text = _("Delete actions is not recoverable.")
+
+ @staticmethod
+ def action_present(count):
+ return ungettext_lazy(
+ u"Delete Action",
+ u"Delete Action",
+ count
+ )
+
+ @staticmethod
+ def action_past(count):
+ return ungettext_lazy(
+ u"Deleted action File",
+ u"Deleted action Files",
+ count
+ )
+
+ def delete(self, request, obj_id):
+ freezer_api.action_delete(request, obj_id)
+ return reverse("horizon:freezer_ui:jobs:index")
+
+
+class EditAction(tables.LinkAction):
+ name = "edit"
+ verbose_name = _("Edit")
+ classes = ("ajax-modal",)
+ icon = "pencil"
+
+ def get_link_url(self, datum=None):
+ # this is used to pass to values as an url
+ # TODO: look for a way to improve this
+ ids = '{0}==={1}'.format(datum.action_id, datum.job_id)
+ return reverse("horizon:freezer_ui:jobs:create_action",
+ kwargs={'job_id': ids})
+
+
+class DeleteMultipleActions(DeleteAction):
+ name = "delete_multiple_actions"
+
+
+class ObjectFilterAction(tables.FilterAction):
+ def allowed(self, request, datum):
+ return bool(self.table.kwargs['job_id'])
+
+
+class ActionsTable(tables.DataTable):
+ action_name = tables.Column('action',
+ verbose_name=_("Action"))
+
+ backup_name = tables.Column('backup_name',
+ verbose_name=_("Action Name"))
+
+ def get_object_id(self, container):
+ # this is used to pass to values as an url
+ # TODO: look for a way to improve this
+ ids = '{0}==={1}'.format(container.action_id, container.job_id)
+ return ids
+
+ class Meta(object):
+ name = "status"
+ verbose_name = _("Status")
+ table_actions = (ObjectFilterAction,)
+ row_actions = (EditAction,
+ DeleteAction,)
+ footer = False
+ multi_select = True
diff --git a/freezer_ui/jobs/templates/jobs/_action.html b/freezer_ui/jobs/templates/jobs/_action.html
new file mode 100644
index 0000000..84a70e8
--- /dev/null
+++ b/freezer_ui/jobs/templates/jobs/_action.html
@@ -0,0 +1,7 @@
+{% load i18n horizon humanize %}
+
+{% block help_message %}
+{% endblock %}
+
+
+
diff --git a/freezer_ui/jobs/templates/jobs/_actions.html b/freezer_ui/jobs/templates/jobs/_actions.html
new file mode 100644
index 0000000..311bf4e
--- /dev/null
+++ b/freezer_ui/jobs/templates/jobs/_actions.html
@@ -0,0 +1,7 @@
+{% load i18n horizon humanize %}
+
+{% block help_message %}
+{% endblock %}
+
+
+
diff --git a/freezer_ui/jobs/templates/jobs/_advanced.html b/freezer_ui/jobs/templates/jobs/_advanced.html
new file mode 100644
index 0000000..b514a7f
--- /dev/null
+++ b/freezer_ui/jobs/templates/jobs/_advanced.html
@@ -0,0 +1,7 @@
+{% load i18n horizon humanize %}
+
+{% block help_message %}
+{% endblock %}
+
+
+
\ No newline at end of file
diff --git a/freezer_ui/jobs/templates/jobs/_scheduling.html b/freezer_ui/jobs/templates/jobs/_scheduling.html
new file mode 100644
index 0000000..b2f15cc
--- /dev/null
+++ b/freezer_ui/jobs/templates/jobs/_scheduling.html
@@ -0,0 +1,21 @@
+{% load i18n horizon humanize %}
+
+{% block help_message %}
+{% blocktrans %}Start and End Date Time{% endblocktrans %}
+{% blocktrans %}Set a start date and time to execute jobs in ISO format:{% endblocktrans %}
+
+
+{% blocktrans %}Interval{% endblocktrans %}
+{% blocktrans %}Set the interval in the following format:{% endblocktrans %}
+
+ - continuous
+ - N weeks
+ - N days
+ - N hours
+ - N minutes
+ - N seconds
+
+
+{% endblock %}
\ No newline at end of file
diff --git a/freezer_ui/jobs/templates/jobs/_snapshot.html b/freezer_ui/jobs/templates/jobs/_snapshot.html
new file mode 100644
index 0000000..36c0a71
--- /dev/null
+++ b/freezer_ui/jobs/templates/jobs/_snapshot.html
@@ -0,0 +1,7 @@
+{% load i18n horizon humanize %}
+
+{% block help_message %}
+{% endblock %}
+
+
+
\ No newline at end of file
diff --git a/freezer_ui/configurations/templates/configurations/_workflow_step_update_members.html b/freezer_ui/jobs/templates/jobs/_workflow_step_update_members.html
similarity index 100%
rename from freezer_ui/configurations/templates/configurations/_workflow_step_update_members.html
rename to freezer_ui/jobs/templates/jobs/_workflow_step_update_members.html
diff --git a/freezer_ui/actions/templates/actions/index.html b/freezer_ui/jobs/templates/jobs/browser.html
similarity index 59%
rename from freezer_ui/actions/templates/actions/index.html
rename to freezer_ui/jobs/templates/jobs/browser.html
index 46ac305..2f4b58e 100644
--- a/freezer_ui/actions/templates/actions/index.html
+++ b/freezer_ui/jobs/templates/jobs/browser.html
@@ -1,11 +1,11 @@
{% extends 'base.html' %}
{% load i18n %}
-{% block title %}{% trans "VMs" %}{% endblock %}
+{% block title %}{% trans "Job Configurations" %}{% endblock %}
{% block page_header %}
- {% include "horizon/common/_page_header.html" with title=_("Jobs") %}
+ {% include "horizon/common/_page_header.html" with title=_("Job Configurations") %}
{% endblock page_header %}
{% block main %}
- {{ table.render }}
+ {{ backup_configuration_browser.render }}
{% endblock %}
diff --git a/freezer_ui/jobs/templates/jobs/scheduling.html b/freezer_ui/jobs/templates/jobs/scheduling.html
new file mode 100644
index 0000000..b2f15cc
--- /dev/null
+++ b/freezer_ui/jobs/templates/jobs/scheduling.html
@@ -0,0 +1,21 @@
+{% load i18n horizon humanize %}
+
+{% block help_message %}
+{% blocktrans %}Start and End Date Time{% endblocktrans %}
+{% blocktrans %}Set a start date and time to execute jobs in ISO format:{% endblocktrans %}
+
+
+{% blocktrans %}Interval{% endblocktrans %}
+{% blocktrans %}Set the interval in the following format:{% endblocktrans %}
+
+ - continuous
+ - N weeks
+ - N days
+ - N hours
+ - N minutes
+ - N seconds
+
+
+{% endblock %}
\ No newline at end of file
diff --git a/freezer_ui/jobs/templates/jobs/snapshot.html b/freezer_ui/jobs/templates/jobs/snapshot.html
new file mode 100644
index 0000000..36c0a71
--- /dev/null
+++ b/freezer_ui/jobs/templates/jobs/snapshot.html
@@ -0,0 +1,7 @@
+{% load i18n horizon humanize %}
+
+{% block help_message %}
+{% endblock %}
+
+
+
\ No newline at end of file
diff --git a/freezer_ui/configurations/urls.py b/freezer_ui/jobs/urls.py
similarity index 67%
rename from freezer_ui/configurations/urls.py
rename to freezer_ui/jobs/urls.py
index d73d025..6840fbd 100644
--- a/freezer_ui/configurations/urls.py
+++ b/freezer_ui/jobs/urls.py
@@ -13,22 +13,25 @@
from django.conf.urls import patterns
from django.conf.urls import url
-from horizon_web_ui.freezer_ui.configurations import views
+from horizon_web_ui.freezer_ui.jobs import views
urlpatterns = patterns(
'',
- # url(r'^$', views.BackupConfigsView.as_view(), name='test'),
- url(r'^(?P[^/]+)?$',
- views.BackupConfigsView.as_view(),
+ url(r'^(?P[^/]+)?$',
+ views.JobsView.as_view(),
name='index'),
url(r'^create/$',
- views.ConfigureWorkflowView.as_view(),
+ views.JobWorkflowView.as_view(),
name='create'),
- url(r'^configure/(?P[^/]+)?$',
- views.ConfigureWorkflowView.as_view(),
+ url(r'^create_action/(?P[^/]+)?$',
+ views.ActionWorkflowView.as_view(),
+ name='create_action'),
+
+ url(r'^configure/(?P[^/]+)?$',
+ views.JobWorkflowView.as_view(),
name='configure'),
)
diff --git a/freezer_ui/jobs/views.py b/freezer_ui/jobs/views.py
new file mode 100644
index 0000000..ba18e49
--- /dev/null
+++ b/freezer_ui/jobs/views.py
@@ -0,0 +1,133 @@
+# 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 django.utils.translation import ugettext_lazy as _
+from django.core.urlresolvers import reverse_lazy
+
+from horizon import workflows
+
+from horizon import browsers
+from horizon import exceptions
+import horizon_web_ui.freezer_ui.api.api as freezer_api
+import horizon_web_ui.freezer_ui.jobs.browsers as project_browsers
+import workflows.configure as configure_workflow
+import workflows.action as action_workflow
+from horizon_web_ui.freezer_ui.utils import create_dict_action
+
+
+class JobWorkflowView(workflows.WorkflowView):
+ workflow_class = configure_workflow.ConfigureJob
+
+ def get_object(self, *args, **kwargs):
+ job_id = self.kwargs['backup_name']
+ try:
+ return freezer_api.job_get(self.request, job_id)
+ except Exception:
+ redirect = reverse("horizon:freezer_ui:jobs:index")
+ msg = _('Unable to retrieve details.')
+ exceptions.handle(self.request, msg, redirect=redirect)
+
+ def is_update(self):
+ return 'backup_name' in self.kwargs and \
+ bool(self.kwargs['backup_name'])
+
+ def get_initial(self):
+ initial = super(JobWorkflowView, self).get_initial()
+ if self.is_update():
+ initial.update({'original_name': None})
+ job = self.get_object()[0]
+ d = job.get_dict()
+ schedule = create_dict_action(**d['job_schedule'])
+ initial.update(**schedule)
+ info = {k: v for k, v in d.items()
+ if not k == 'job_schedule'}
+ initial.update(**info)
+ initial.update({'original_name': d.get('job_id', None)})
+ return initial
+
+
+class JobsView(browsers.ResourceBrowserView):
+ browser_class = project_browsers.ContainerBrowser
+ template_name = "freezer_ui/jobs/browser.html"
+
+ def get_jobs_data(self):
+ jobs = []
+ try:
+ jobs = freezer_api.job_list(self.request)
+ except Exception:
+ msg = _('Unable to retrieve job file list.')
+ exceptions.handle(self.request, msg)
+ return jobs
+
+ def get_status_data(self):
+ job = []
+ try:
+ if self.kwargs['job_id']:
+ job = freezer_api.actions_in_job(
+ self.request, self.kwargs['job_id'])
+ except Exception:
+ msg = _('Unable to retrieve instances for this job.')
+ exceptions.handle(self.request, msg)
+ return job
+
+
+class ActionWorkflowView(workflows.WorkflowView):
+ workflow_class = action_workflow.ConfigureAction
+ success_url = reverse_lazy("horizon:freezer_ui:jobs:index")
+
+ def get_context_data(self, **kwargs):
+ context = super(ActionWorkflowView, self).get_context_data(**kwargs)
+ job_id = self.kwargs['job_id']
+ context['job_id'] = job_id
+ return context
+
+ def get_object(self, *args, **kwargs):
+ ids = self.kwargs['job_id']
+ try:
+ action_id, job_id = ids.split('===')
+ except ValueError:
+ action_id = None
+ job_id = self.kwargs['job_id']
+ try:
+ return freezer_api.job_get(self.request, job_id)
+ except Exception:
+ redirect = reverse("horizon:freezer_ui:jobs:index")
+ msg = _('Unable to retrieve details.')
+ exceptions.handle(self.request, msg, redirect=redirect)
+
+ def is_update(self):
+ return 'job_id' in self.kwargs and \
+ bool(self.kwargs['job_id'])
+
+ def get_initial(self, **kwargs):
+ initial = super(ActionWorkflowView, self).get_initial()
+ try:
+ action_id, job_id = self.kwargs['job_id'].split('===')
+ except ValueError:
+ job_id = self.kwargs['job_id']
+ action_id = None
+
+ if self.is_update():
+ initial.update({'original_name': None})
+ job = self.get_object()[0]
+ d = job.get_dict()
+ for action in d['job_actions']:
+ if action['action_id'] == action_id:
+ actions = create_dict_action(**action)
+ rules = {k: v for k, v in action.items()
+ if not k == 'freezer_action'}
+ initial.update(**actions['freezer_action'])
+ initial.update(**rules)
+ initial.update({'original_name': job.id})
+ return initial
+
diff --git a/freezer_ui/backups/__init__.py b/freezer_ui/jobs/workflows/__init__.py
similarity index 100%
rename from freezer_ui/backups/__init__.py
rename to freezer_ui/jobs/workflows/__init__.py
diff --git a/freezer_ui/jobs/workflows/action.py b/freezer_ui/jobs/workflows/action.py
new file mode 100644
index 0000000..b2d837b
--- /dev/null
+++ b/freezer_ui/jobs/workflows/action.py
@@ -0,0 +1,580 @@
+# 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 workflows
+from horizon import exceptions
+from horizon import forms
+import horizon_web_ui.freezer_ui.api.api as freezer_api
+
+
+class ActionConfigurationAction(workflows.Action):
+ action = forms.ChoiceField(
+ help_text=_("Set the action to be taken"),
+ required=True)
+
+ mode = forms.ChoiceField(
+ help_text=_("Choose what you want to backup"),
+ required=False)
+
+ original_name = forms.CharField(
+ widget=forms.HiddenInput(),
+ required=False)
+
+ action_id = forms.CharField(
+ widget=forms.HiddenInput(),
+ required=False)
+
+ backup_name = forms.CharField(
+ label=_("Backup Name"),
+ required=False)
+
+ mysql_conf = forms.CharField(
+ label=_("MySQL Configuration File"),
+ help_text=_("Set the path where the MySQL configuration file "
+ "is on the file system "),
+ required=False)
+
+ sql_server_conf = forms.CharField(
+ label=_("SQL Server Configuration File"),
+ help_text=_("Set the path where the SQL Server configuration file"
+ " is on the file system"),
+ required=False)
+
+ path_to_backup = forms.CharField(
+ label=_("Source File/Directory"),
+ help_text=_("The file or directory you want to back up."),
+ required=False)
+
+ container = forms.CharField(
+ label=_("Swift Container Name"),
+ required=False)
+
+ restore_abs_path = forms.CharField(
+ label=_("Restore Absolute Path"),
+ help_text=_("Set the absolute path where you"
+ " want your data restored."),
+ required=False)
+
+ restore_from_host = forms.CharField(
+ label=_("Restore From Host"),
+ help_text=_("Set the hostname used to identify the"
+ " data you want to restore from."
+ " If you want to restore data in the same"
+ " host where the backup was executed just"
+ " type from your shell: '$ hostname' and"
+ " the output is the value that needs to"
+ " be passed to this option. Mandatory"
+ " with Restore"),
+ required=False)
+
+ restore_from_date = forms.CharField(
+ label=_("Restore From Date"),
+ help_text=_("Set the absolute path where you want "
+ "your data restored.Please provide "
+ "datetime in format 'YYYY-MM-DDThh:mm:ss' "
+ "i.e. '1979-10-03T23:23:23'. Make sure the "
+ "'T' is between date and time"),
+ required=False)
+
+ cinder_vol_id = forms.CharField(
+ label=_("Cinder Volume ID"),
+ help_text=_("Id of cinder volume for backup"),
+ required=False)
+
+ nova_inst_id = forms.CharField(
+ label=_("Nova Volume ID"),
+ help_text=_("Id of nova instance for backup"),
+ required=False)
+
+ get_object = forms.CharField(
+ label=_("Get A Single Object"),
+ help_text=_("The Object name you want to download on "
+ "the local file system."),
+ required=False)
+
+ dst_file = forms.CharField(
+ label=_("Destination File"),
+ help_text=_("The file name used to save the object "
+ "on your local disk and upload file in swift."),
+ required=False)
+
+ remove_older_than = forms.CharField(
+ label=_("Remove Older Than"),
+ help_text=_("Checks in the specified container for"
+ " object older than the specified days."
+ "If i.e. 30 is specified, it will remove"
+ " the remote object older than 30 days."
+ " Default False (Disabled) The option "
+ "--remove-older-then is deprecated and "
+ "will be removed soon"),
+ required=False)
+
+ remove_from_date = forms.CharField(
+ label=_("Remove From Date"),
+ help_text=_("Checks the specified container and removes"
+ " objects older than the provided datetime"
+ " in the format YYYY-MM-DDThh:mm:ss "
+ "i.e. 1974-03-25T23:23:23. Make sure the "
+ "'T' is between date and time "),
+ required=False)
+
+ def clean(self):
+ cleaned_data = super(ActionConfigurationAction, self).clean()
+
+ if cleaned_data.get('action') == 'backup':
+ self._check_container(cleaned_data)
+ self._check_backup_name(cleaned_data)
+ self._check_path_to_backup(cleaned_data)
+
+ elif cleaned_data.get('action') == 'restore':
+ self._check_container(cleaned_data)
+ self._check_backup_name(cleaned_data)
+ self._check_restore_abs_path(cleaned_data)
+
+ return cleaned_data
+
+ def _check_restore_abs_path(self, cleaned_data):
+ if not cleaned_data.get('restore_abs_path'):
+ msg = _("You must define a path to restore.")
+ self._errors['restore_abs_path'] = self.error_class([msg])
+
+ def _check_container(self, cleaned_data):
+ if not cleaned_data.get('container'):
+ msg = _("You must define a container.")
+ self._errors['container'] = self.error_class([msg])
+
+ def _check_backup_name(self, cleaned_data):
+ if not cleaned_data.get('backup_name'):
+ msg = _("You must define an backup name.")
+ self._errors['backup_name'] = self.error_class([msg])
+
+ def _check_path_to_backup(self, cleaned_data):
+ if not cleaned_data.get('path_to_backup'):
+ msg = _("You must define a path to backup.")
+ self._errors['path_to_backup'] = self.error_class([msg])
+
+ def populate_mode_choices(self, request, context):
+ return [
+ ('fs', _("File system")),
+ ('mongo', _("MongoDB")),
+ ('mysql', _("MySQL")),
+ ('mssql', _("Microsoft SQL Server")),
+ ('cinder', _("Cinder")),
+ ('nova', _("Nova")),
+ ]
+
+ def populate_action_choices(self, request, context):
+ return [
+ ('', _("Select an action")),
+ ('backup', _("Backup")),
+ ('restore', _("Restore")),
+ ('admin', _("Admin")),
+ ]
+
+ def __init__(self, request, context, *args, **kwargs):
+ self.request = request
+ self.context = context
+ super(ActionConfigurationAction, self).__init__(
+ request, context, *args, **kwargs)
+
+ class Meta(object):
+ name = _("Action")
+ help_text_template = "freezer_ui/jobs" \
+ "/_action.html"
+
+
+class ActionConfiguration(workflows.Step):
+ action_class = ActionConfigurationAction
+ contributes = ('action',
+ 'mode',
+ 'original_name',
+ 'backup_name',
+ 'mysql_conf',
+ 'sql_server_conf',
+ 'path_to_backup',
+ 'container',
+ 'restore_abs_path',
+ 'restore_from_host',
+ 'restore_from_date',
+ 'cinder_vol_id',
+ 'nova_inst_id',
+ 'get_object',
+ 'dst_file',
+ 'remove_older_than',
+ 'remove_from_date',
+ 'original_name',
+ 'action_id')
+
+
+class SnapshotConfigurationAction(workflows.Action):
+ use_snapshot = forms.BooleanField(
+ label=_("Snapshot"),
+ help_text=_("Use a LVM or Shadow Copy snapshot "
+ "to have point in time consistent backups"),
+ widget=forms.CheckboxInput(),
+ initial=False,
+ required=False)
+
+ is_windows = forms.BooleanField(
+ label=_("Job For Windows"),
+ help_text=_("Is this job going to "
+ "execute on windows?"),
+ widget=forms.CheckboxInput(),
+ required=False)
+
+ vssadmin = forms.BooleanField(
+ label=_("VSSAdmin"),
+ help_text=_("Create a backup using a snapshot on windows "
+ "using vssadmin. Options are: "
+ "True and False, default is True"),
+ widget=forms.CheckboxInput(),
+ initial=True,
+ required=False)
+
+ lvm_auto_snap = forms.CharField(
+ label=_("LVM Auto Snapshot"),
+ help_text=_("Automatically guess the volume group and "
+ "volume name for given PATH."),
+ required=False)
+
+ lvm_srcvol = forms.CharField(
+ label=_("Set The Volume For Snapshot"),
+ help_text=_("Set the lvm volume you want to take a "
+ "snapshot from. Default no volume"),
+ required=False)
+
+ lvm_snapname = forms.CharField(
+ label=_("Set A Snapshot Name"),
+ help_text=_("Set the lvm snapshot name to use. "
+ "If the snapshot name already exists, "
+ "the old one will be used a no new one "
+ "will be created. Default freezer_backup_snap."),
+ required=False)
+
+ lvm_snapsize = forms.CharField(
+ label=_("Snapshot Size"),
+ help_text=_("Set the lvm snapshot size when creating "
+ "a new snapshot. Please add G for Gigabytes "
+ "or M for Megabytes, i.e. 500M or 8G. Default 5G."),
+ required=False)
+
+ lvm_dirmount = forms.CharField(
+ label=_("Snapshot Directory"),
+ help_text=_("Set the directory you want to mount "
+ "the lvm snapshot to. Default not set"),
+ required=False)
+
+ lvm_volgroup = forms.CharField(
+ label=_("Volume Group"),
+ help_text=_("Specify the volume group of your logical volume."
+ "This is important to mount your snapshot volume."
+ "Default not set"),
+ required=False)
+
+ class Meta(object):
+ name = _("Snapshot")
+ help_text_template = "freezer_ui/jobs" \
+ "/_snapshot.html"
+
+
+class SnapshotConfiguration(workflows.Step):
+ action_class = SnapshotConfigurationAction
+ contributes = ('use_snapshot',
+ 'is_windows',
+ 'vssadmin',
+ 'lvm_auto_snap',
+ 'lvm_srcvol',
+ 'lvm_snapname',
+ 'lvm_snapsize',
+ 'lvm_dirmount',
+ 'lvm_volgroup',)
+
+
+class AdvancedConfigurationAction(workflows.Action):
+
+ log_file = forms.CharField(
+ label=_("Log File Path"),
+ help_text=_("Set log file. By default logs to "
+ "/var/log/freezer.log If that file "
+ "is not writable, freezer tries to "
+ "log to ~/.freezer/freezer.log"),
+ required=False)
+
+ exclude = forms.CharField(
+ label=_("Exclude Files"),
+ help_text=_("Exclude files, given as a PATTERN.Ex:"
+ " '*.log, *.pyc' will exclude any "
+ "file with name ending with .log. "
+ "Default no exclude"),
+ widget=forms.widgets.Textarea(),
+ required=False)
+
+ proxy = forms.CharField(
+ label=_("Proxy URL"),
+ help_text=_("Enforce proxy that alters system "
+ "HTTP_PROXY and HTTPS_PROXY"),
+ widget=forms.URLInput(),
+ required=False)
+
+ os_auth_ver = forms.ChoiceField(
+ label=_("OpenStack Authentication Version"),
+ help_text=_("Swift auth version, could be 1, 2 or 3"),
+ required=False)
+
+ upload_limit = forms.IntegerField(
+ label=_("Upload Limit"),
+ help_text=_("Upload bandwidth limit in Bytes per sec."
+ " Can be invoked with dimensions "
+ "(10K, 120M, 10G)."),
+ initial=-1,
+ min_value=-1,
+ required=False)
+
+ download_limit = forms.IntegerField(
+ label=_("Download Limit"),
+ help_text=_("Download bandwidth limit in Bytes per sec. "
+ "Can be invoked with dimensions"
+ " (10K, 120M, 10G)."),
+ initial=-1,
+ min_value=-1,
+ required=False)
+
+ optimize = forms.ChoiceField(
+ choices=[('speed', _("Speed (tar)")),
+ ('bandwidth', _("Bandwidth/Space (rsync)"))],
+ help_text="",
+ label=_('Optimize For...'),
+ required=False)
+
+ compression = forms.ChoiceField(
+ choices=[('gzip', _("Minimum Compression (GZip/Zip/Zlib)"))],
+ help_text="",
+ label=_('Compression Level'),
+ required=False)
+
+ max_segment_size = forms.IntegerField(
+ label=_("Maximum Segment Size"),
+ help_text=_("Set the maximum file chunk size in bytes"
+ " to upload to swift."
+ " Default 67108864 bytes (64MB)"),
+ initial=67108864,
+ min_value=1,
+ required=False)
+
+ hostname = forms.CharField(
+ label=_("Hostname"),
+ help_text=_("Set hostname to execute actions. If you are "
+ "executing freezer from one host but you want"
+ " to delete objects belonging to another host "
+ "then you can set this option that hostname and "
+ "execute appropriate actions. Default current "
+ "node hostname."),
+ required=False)
+
+ encryption_password = forms.CharField(
+ label=_("Encryption Key"),
+ help_text=_("Set the path where the encryption key"
+ "is on the file system"),
+ required=False)
+
+ no_incremental = forms.BooleanField(
+ label=_("No Incremental"),
+ help_text=_("Disable incremental feature. By default"
+ " freezer build the meta data even for "
+ "level 0 backup. By setting this option "
+ "incremental meta data is not created at all."
+ " Default disabled"),
+ widget=forms.CheckboxInput(),
+ initial=True,
+ required=False)
+
+ max_level = forms.IntegerField(
+ label=_("Max Level"),
+ initial=0,
+ min_value=0,
+ help_text=_("Set the backup level used with tar to implement"
+ " incremental backup. If a level 1 is specified "
+ "but no level 0 is already available, a level 0"
+ " will be done and subsequently backs to level 1."
+ " Default 0 (No Incremental)"),
+ required=False)
+
+ always_level = forms.IntegerField(
+ label=_("Always Level"),
+ initial=0,
+ min_value=0,
+ help_text=_("Set backup maximum level used with tar to"
+ " implement incremental backup. If a level "
+ "3 is specified, the backup will be executed "
+ "from level 0 to level 3 and to that point "
+ "always a backup level 3 will be executed. "
+ "It will not restart from level 0. This option "
+ "has precedence over --max-backup-level. "
+ "Default False (Disabled)"),
+ required=False)
+
+ restart_always_level = forms.IntegerField(
+ label=_("Restart Always Level"),
+ initial=0,
+ min_value=0,
+ help_text=_("Restart the backup from level 0 after n days. "
+ "Valid only if --always-level option if set. "
+ "If --always-level is used together with "
+ "--remove-older-then, there might be the "
+ "chance where the initial level 0 will be "
+ "removed Default False (Disabled)"),
+ required=False)
+
+ insecure = forms.BooleanField(
+ label=_("insecure"),
+ help_text=_("Allow to access swift servers without"
+ " checking SSL certs."),
+ widget=forms.CheckboxInput(),
+ required=False)
+
+ dereference_symlink = forms.BooleanField(
+ label=_("Follow Symlinks"),
+ help_text=_("Follow hard and soft links and archive "
+ "and dump the files they refer to. "
+ "Default False"),
+ widget=forms.CheckboxInput(),
+ required=False)
+
+ dry_run = forms.BooleanField(
+ label=_("Dry Run"),
+ help_text=_("Do everything except writing or "
+ "removing objects"),
+ widget=forms.CheckboxInput(),
+ required=False)
+
+ max_priority = forms.BooleanField(
+ label=_("Max Priority"),
+ help_text=_("Set the cpu process to the "
+ "highest priority (i.e. -20 "
+ "on Linux) and real-time for "
+ "I/O. The process priority "
+ "will be set only if nice and "
+ "ionice are installed Default "
+ "disabled. Use with caution."),
+ widget=forms.CheckboxInput(),
+ required=False)
+
+ quiet = forms.BooleanField(
+ label=_("Quiet"),
+ help_text=_("Suppress error messages"),
+ widget=forms.CheckboxInput(),
+ required=False)
+
+ def populate_os_auth_ver_choices(self, request, context):
+ return [
+ ('2', _("v2")),
+ ('1', _("v1")),
+ ('3', _("v3")),
+ ]
+
+ class Meta(object):
+ name = _("Advanced")
+ help_text_template = "freezer_ui/jobs" \
+ "/_advanced.html"
+
+
+class AdvancedConfiguration(workflows.Step):
+ action_class = AdvancedConfigurationAction
+ contributes = ('log_file',
+ 'exclude',
+ 'proxy',
+ 'os_auth_ver',
+ 'upload_limit',
+ 'download_limit',
+ 'optimize',
+ 'compression',
+ 'max_segment_size',
+ 'hostname',
+ 'encryption_password',
+ 'no_incremental',
+ 'max_level',
+ 'always_level',
+ 'restart_always_level',
+ 'insecure',
+ 'dereference_symlink',
+ 'dry_run',
+ 'max_priority',
+ 'quiet',)
+
+
+class RulesConfigurationAction(workflows.Action):
+ max_retries = forms.IntegerField(
+ label=_("Max Retries"),
+ initial=0,
+ min_value=0,
+ help_text=_("In case of error, set the amount"
+ " of retries for this job"),
+ required=False)
+
+ max_retries_interval = forms.IntegerField(
+ label=_("Max Retries Interval"),
+ initial=0,
+ min_value=0,
+ help_text=_("Set the interval between intervals "
+ "for retries in seconds"),
+ required=False)
+
+ mandatory = forms.BooleanField(
+ label=_("Mandatory"),
+ help_text=_("Set this job as mandatory"),
+ widget=forms.CheckboxInput(),
+ required=False)
+
+ class Meta(object):
+ name = _("Rules")
+
+
+class RulesConfiguration(workflows.Step):
+ action_class = RulesConfigurationAction
+ contributes = ('max_retries',
+ 'max_retries_interval',
+ 'mandatory')
+
+
+class ConfigureAction(workflows.Workflow):
+ slug = "action"
+ name = _("Action Configuration")
+ finalize_button_name = _("Save")
+ success_message = _('Action file saved correctly.')
+ failure_message = _('Unable to save action file.')
+ success_url = "horizon:freezer_ui:jobs:index"
+
+ default_steps = (ActionConfiguration,
+ SnapshotConfiguration,
+ RulesConfiguration,
+ AdvancedConfiguration)
+
+ def handle(self, request, context):
+ try:
+ if context['is_windows']:
+ client_os = 'Windows'
+ else:
+ client_os = 'Linux'
+
+ if context['use_snapshot'] and client_os == 'Windows':
+ context['vssadmin'] = True
+ else:
+ context['vssadmin'] = False
+
+ if context['action_id'] == '':
+ return freezer_api.action_create(request, context)
+ else:
+ return freezer_api.action_update(request, context)
+ except Exception:
+ exceptions.handle(request)
+ return False
diff --git a/freezer_ui/jobs/workflows/configure.py b/freezer_ui/jobs/workflows/configure.py
new file mode 100644
index 0000000..192354d
--- /dev/null
+++ b/freezer_ui/jobs/workflows/configure.py
@@ -0,0 +1,231 @@
+# 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 datetime
+from horizon import exceptions
+from horizon import forms
+from horizon import workflows
+
+import horizon_web_ui.freezer_ui.api.api as freezer_api
+
+
+class ClientsConfigurationAction(workflows.Action):
+
+ client_id = forms.ChoiceField(
+ help_text=_("Set the client for this job"),
+ required=True)
+
+ def populate_client_id_choices(self, request, context):
+ clients = []
+ try:
+ clients = freezer_api.client_list(request)
+ except Exception:
+ exceptions.handle(request, _('Error getting client list'))
+
+ client_id = [(c.client_id, c.hostname) for c in clients]
+ client_id.insert(0, ('', _('Select A Client')))
+ return client_id
+
+ class Meta(object):
+ name = _("Clients")
+ slug = "clients"
+
+
+class ClientsConfiguration(workflows.Step):
+ action_class = ClientsConfigurationAction
+ contributes = ('client_id',)
+
+
+class ActionsConfigurationAction(workflows.MembershipAction):
+ def __init__(self, request, *args, **kwargs):
+ super(ActionsConfigurationAction, self).__init__(request,
+ *args,
+ **kwargs)
+
+ original_name = args[0].get('original_name', None)
+
+ err_msg = _('Unable to retrieve list of actions.')
+
+ if original_name:
+ default_role_field_name = self.get_default_role_field_name()
+ self.fields[default_role_field_name] = \
+ forms.CharField(required=False,
+ widget=forms.HiddenInput())
+ self.fields[default_role_field_name].initial = 'member'
+
+ actions = self.get_member_field_name('member')
+ self.fields[actions] = \
+ forms.MultipleChoiceField(required=False,
+ widget=forms.HiddenInput())
+ else:
+ default_role_field_name = self.get_default_role_field_name()
+ self.fields[default_role_field_name] = \
+ forms.CharField(required=False)
+ self.fields[default_role_field_name].initial = 'member'
+
+ actions = self.get_member_field_name('member')
+ self.fields[actions] = forms.MultipleChoiceField(required=False)
+
+ all_actions = []
+ try:
+ all_actions = freezer_api.action_list(request)
+ except Exception:
+ exceptions.handle(request, err_msg)
+
+ all_actions = [(a.action_id, a.freezer_action['backup_name'])
+ for a in all_actions]
+
+ self.fields[actions].choices = all_actions
+
+ initial_actions = []
+
+ if request.method == 'POST':
+ return
+
+ try:
+ if original_name:
+ configured_actions = \
+ freezer_api.actions_in_job(request, original_name)
+ initial_actions = [a.action_id for a in configured_actions]
+ except Exception:
+ exceptions.handle(request, err_msg)
+
+ self.fields[actions].initial = initial_actions
+
+ class Meta(object):
+ name = _("Actions")
+ slug = "selected_actions"
+ help_text_template = "freezer_ui/jobs" \
+ "/_actions.html"
+
+
+class ActionsConfiguration(workflows.UpdateMembersStep):
+ action_class = ActionsConfigurationAction
+ help_text = _(
+ "Select the clients that will be backed up using this configuration.")
+ available_list_title = _("All Actions")
+ members_list_title = _("Selected Actions")
+ no_available_text = _("No actions found.")
+ no_members_text = _("No actions selected.")
+ show_roles = False
+ contributes = ("actions",)
+
+ def contribute(self, data, context):
+ if data:
+ member_field_name = self.get_member_field_name('member')
+ context['actions'] = data.get(member_field_name, [])
+ return context
+
+
+class SchedulingConfigurationAction(workflows.Action):
+ start_datetime = forms.CharField(
+ label=_("Start Date and Time"),
+ required=False,
+ help_text=_(""))
+
+ interval = forms.CharField(
+ label=_("Interval"),
+ required=False,
+ help_text=_("Repeat this configuration in a minutes interval."))
+
+ end_datetime = forms.CharField(
+ label=_("End Date and Time"),
+ required=False,
+ help_text=_(""))
+
+ def __init__(self, request, context, *args, **kwargs):
+ self.request = request
+ self.context = context
+ super(SchedulingConfigurationAction, self).__init__(
+ request, context, *args, **kwargs)
+
+ def clean(self):
+ cleaned_data = super(SchedulingConfigurationAction, 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('start_datetime')):
+ msg = _("Start date time is not in ISO format.")
+ self._errors['start_datetime'] = 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('end_datetime')):
+ msg = _("End date time is not in ISO format.")
+ self._errors['end_datetime'] = self.error_class([msg])
+
+ class Meta(object):
+ name = _("Scheduling")
+ slug = "scheduling"
+ help_text_template = "freezer_ui/jobs" \
+ "/_scheduling.html"
+
+
+class SchedulingConfiguration(workflows.Step):
+ action_class = SchedulingConfigurationAction
+ contributes = ('start_datetime',
+ 'interval',
+ 'end_datetime')
+
+
+class InfoConfigurationAction(workflows.Action):
+ description = forms.CharField(
+ label=_("Job Name"),
+ help_text=_("Set a short description for this job"),
+ required=True)
+
+ original_name = forms.CharField(
+ widget=forms.HiddenInput(),
+ required=False)
+
+ class Meta(object):
+ name = _("Job Info")
+ slug = "info"
+
+
+class InfoConfiguration(workflows.Step):
+ action_class = InfoConfigurationAction
+ contributes = ('description',
+ 'original_name')
+
+
+class ConfigureJob(workflows.Workflow):
+ slug = "job"
+ name = _("Job Configuration")
+ finalize_button_name = _("Save")
+ success_message = _('Job file saved correctly.')
+ failure_message = _('Unable to save job file.')
+ success_url = "horizon:freezer_ui:jobs:index"
+ default_steps = (InfoConfiguration,
+ ClientsConfiguration,
+ SchedulingConfiguration)
+
+ def handle(self, request, context):
+ try:
+ if context['original_name'] == '':
+ return freezer_api.job_create(request, context)
+ else:
+ return freezer_api.job_edit(request, context)
+ except Exception:
+ exceptions.handle(request)
+ return False
diff --git a/freezer_ui/overview/__init__.py b/freezer_ui/overview/__init__.py
deleted file mode 100644
index d95ce28..0000000
--- a/freezer_ui/overview/__init__.py
+++ /dev/null
@@ -1 +0,0 @@
-__author__ = 'jonas'
diff --git a/freezer_ui/overview/models.py b/freezer_ui/overview/models.py
deleted file mode 100644
index 1b3d5f9..0000000
--- a/freezer_ui/overview/models.py
+++ /dev/null
@@ -1,3 +0,0 @@
-"""
-Stub file to work around django bug: https://code.djangoproject.com/ticket/7198
-"""
diff --git a/freezer_ui/overview/panel.py b/freezer_ui/overview/panel.py
deleted file mode 100644
index 8139f85..0000000
--- a/freezer_ui/overview/panel.py
+++ /dev/null
@@ -1,24 +0,0 @@
-# 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 horizon_web_ui.freezer_ui import dashboard
-
-
-class OverviewPanel(horizon.Panel):
- name = _("Overview")
- slug = "overview"
-
-
-dashboard.Freezer.register(OverviewPanel)
diff --git a/freezer_ui/overview/templates/overview/overview.html b/freezer_ui/overview/templates/overview/overview.html
deleted file mode 100644
index 09fdfa7..0000000
--- a/freezer_ui/overview/templates/overview/overview.html
+++ /dev/null
@@ -1,112 +0,0 @@
-{% extends 'base.html' %}
-{% load i18n %}
-{% block title %}{% trans "Backup Restore DR Overview" %}{% endblock %}
-
-{% block css %}
- {% include "_stylesheets.html" %}
-
-{% endblock %}
-
-
-
-{% block main %}
-
-
-
{% trans "Overview" %}
-
-
-
-
{% trans "Nodes without backup in the last week" %}
- 18 of 50
-
-
-
-
-
-
{% trans "Total space used for backups" %}
- 150gb of 200gb
-
-
-
-
-
-
{% trans "Storage price per month" %}
- 60 dls
-
-
-
-
-
-
-
{% trans "Backup Summary" %}
-
-
-
-
{% trans "Backups older than 1 week" %}
- 60 of 120
-
-
-
-
-
-
{% trans "Average backup size" %}
- 7gb for 18 backups
-
-
-
-
-
-
{% trans "Average backup time" %}
- 18 min
-
-
-
-
-
-
-
{% trans "Restore Summary" %}
-
-
-
-
{% trans "Average restore time" %}
- 15 min
-
-
-
-
-
-
{% trans "Restore ratio success to failure" %}
- 100% success
-
-
-
-
-
-
-
{% trans "OS Summary" %}
-
-
-
-
-
-
-
-
-
-
-
-
-
-{% endblock %}
\ No newline at end of file
diff --git a/freezer_ui/overview/views.py b/freezer_ui/overview/views.py
deleted file mode 100644
index a974306..0000000
--- a/freezer_ui/overview/views.py
+++ /dev/null
@@ -1,21 +0,0 @@
-# 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 django.views import generic
-
-
-class IndexView(generic.TemplateView):
- name = _("Overview")
- slug = "overview"
- template_name = ("freezer_ui/overview/overview.html")
diff --git a/freezer_ui/static/freezer/js/freezer.actions.action.js b/freezer_ui/static/freezer/js/freezer.actions.action.js
new file mode 100644
index 0000000..24a0286
--- /dev/null
+++ b/freezer_ui/static/freezer/js/freezer.actions.action.js
@@ -0,0 +1,131 @@
+function hideEverything() {
+ // Common controls
+ $("#id_backup_name").closest(".form-group").hide();
+ $("#id_container").closest(".form-group").hide();
+ $("#id_path_to_backup").closest(".form-group").hide();
+
+ // Backup specific controls
+ $("#id_mysql_conf").closest(".form-group").hide();
+ $("#id_mode").closest(".form-group").hide();
+ $("#id_sql_server_conf").closest(".form-group").hide();
+ $("#id_cinder_vol_id").closest(".form-group").hide();
+ $("#id_nova_inst_id").closest(".form-group").hide();
+
+ // Restore specific controls
+ $("#id_restore_abs_path").closest(".form-group").hide();
+ $("#id_restore_from_host").closest(".form-group").hide();
+ $("#id_restore_from_date").closest(".form-group").hide();
+
+ // Admin specific controls
+ $("#id_remove_older_than").closest(".form-group").hide();
+ $("#id_remove_from_date").closest(".form-group").hide();
+ $("#id_get_object").closest(".form-group").hide();
+ $("#id_dst_file").closest(".form-group").hide();
+}
+
+function showAdminOptions() {
+ $("#id_remove_older_than").closest(".form-group").show();
+ $("#id_remove_from_date").closest(".form-group").show();
+ $("#id_get_object").closest(".form-group").show();
+ $("#id_dst_file").closest(".form-group").show();
+}
+
+function showBackupOptions() {
+ $("#id_is_windows").closest(".form-group").show();
+ $("#id_mode").closest(".form-group").show();
+ $("#id_container").closest(".form-group").show();
+ $("#id_path_to_backup").closest(".form-group").show();
+ $("#id_backup_name").closest(".form-group").show();
+}
+
+function showRestoreOptions() {
+ $("#id_container").closest(".form-group").show();
+ $("#id_backup_name").closest(".form-group").show();
+ $("#id_restore_abs_path").closest(".form-group").show();
+ $("#id_restore_from_host").closest(".form-group").show();
+ $("#id_restore_from_date").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();
+}
+
+hideEverything();
+
+$("#id_action").change(function() {
+ // Update the inputs according freezer action
+
+ if ($("#id_action").val() == 'backup') {
+ hideEverything();
+ showBackupOptions();
+ }
+ else if ($("#id_action").val() == 'restore') {
+ hideEverything();
+ showRestoreOptions();
+ }
+ else if ($("#id_action").val() == 'admin') {
+ hideEverything();
+ showAdminOptions();
+ }
+ else {
+ hideEverything();
+ }
+});
+
+
+$("#id_mode").change(function() {
+ if ($("#id_action").val() == 'backup') {
+ if ($("#id_mode").val() == 'fs') {
+ hideEverything();
+ showBackupOptions();
+ $("#id_advanced_configuration").closest(".form-group").show();
+ }
+ else if ($("#id_mode").val() == 'mysql') {
+ hideEverything();
+ showBackupOptions();
+ $("#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();
+ $("#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();
+ }
+ 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();
+ }
+ 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();
+ }
+ else {
+
+ }
+ }
+});
+
diff --git a/freezer_ui/static/freezer/js/freezer.actions.advanced.js b/freezer_ui/static/freezer/js/freezer.actions.advanced.js
new file mode 100644
index 0000000..41773a6
--- /dev/null
+++ b/freezer_ui/static/freezer/js/freezer.actions.advanced.js
@@ -0,0 +1,21 @@
+function hideIncrementalOptions() {
+ $("#id_max_level").closest(".form-group").hide();
+ $("#id_always_level").closest(".form-group").hide();
+ $("#id_restart_always_level").closest(".form-group").hide();
+}
+
+$("#id_no_incremental").click(function() {
+ if ($("#id_no_incremental").is(":checked")) {
+ $("#id_max_level").closest(".form-group").hide();
+ $("#id_always_level").closest(".form-group").hide();
+ $("#id_restart_always_level").closest(".form-group").hide();
+ }
+ else {
+ $("#id_max_level").closest(".form-group").show();
+ $("#id_always_level").closest(".form-group").show();
+ $("#id_restart_always_level").closest(".form-group").show();
+ }
+});
+
+
+hideIncrementalOptions();
\ No newline at end of file
diff --git a/freezer_ui/static/freezer/js/freezer.actions.snapshot.js b/freezer_ui/static/freezer/js/freezer.actions.snapshot.js
new file mode 100644
index 0000000..7e1adb9
--- /dev/null
+++ b/freezer_ui/static/freezer/js/freezer.actions.snapshot.js
@@ -0,0 +1,81 @@
+function hideOptions() {
+ // Snapshot specific controls
+ $("#id_is_windows").closest(".form-group").hide();
+ $("#id_lvm_auto_snap").closest(".form-group").hide();
+ $("#id_lvm_srcvol").closest(".form-group").hide();
+ $("#id_lvm_snapname").closest(".form-group").hide();
+ $("#id_lvm_snapsize").closest(".form-group").hide();
+ $("#id_lvm_dirmount").closest(".form-group").hide();
+ $("#id_lvm_volgroup").closest(".form-group").hide();
+ $("#id_vssadmin").closest(".form-group").hide();
+}
+
+function is_windows() {
+ if ($("#id_is_windows").is(":checked")) {
+ return true;
+ }
+}
+
+function showWindowsSnapshotOptions() {
+ $("#id_vssadmin").closest(".form-group").show();
+}
+
+function hideWindowsSnapshotOptions() {
+ $("#id_vssadmin").closest(".form-group").hide();
+}
+
+function showLinuxSnapshotOptions() {
+ $("#id_lvm_auto_snap").closest(".form-group").show();
+ $("#id_lvm_srcvol").closest(".form-group").show();
+ $("#id_lvm_snapname").closest(".form-group").show();
+ $("#id_lvm_snapsize").closest(".form-group").show();
+ $("#id_lvm_dirmount").closest(".form-group").show();
+ $("#id_lvm_volgroup").closest(".form-group").show();
+}
+
+function hideLinuxSnapshotOptions() {
+ $("#id_lvm_srcvol").closest(".form-group").hide();
+ $("#id_lvm_snapname").closest(".form-group").hide();
+ $("#id_lvm_snapsize").closest(".form-group").hide();
+ $("#id_lvm_dirmount").closest(".form-group").hide();
+ $("#id_lvm_volgroup").closest(".form-group").hide();
+ $("#id_lvm_auto_snap").closest(".form-group").hide();
+}
+
+function hideSnapshotOptions() {
+ hideWindowsSnapshotOptions();
+ hideLinuxSnapshotOptions();
+ $("#id_is_windows").closest(".form-group").hide();
+}
+
+function showSnapshotOptions() {
+ $("#id_is_windows").closest(".form-group").show();
+ if (is_windows()) {
+ hideLinuxSnapshotOptions();
+ showWindowsSnapshotOptions();
+ }
+ else {
+ hideWindowsSnapshotOptions();
+ showLinuxSnapshotOptions();
+ }
+}
+
+hideOptions();
+
+$("#id_use_snapshot").click(function() {
+ if ($("#id_use_snapshot").is(":checked")) {
+ showSnapshotOptions();
+ }
+ else {
+ hideSnapshotOptions();
+ }
+});
+
+$("#id_is_windows").click(function() {
+ if ($("#id_use_snapshot").is(":checked")) {
+ showSnapshotOptions();
+ }
+ else {
+ hideSnapshotOptions();
+ }
+});
\ No newline at end of file
diff --git a/freezer_ui/configurations/workflows/__init__.py b/freezer_ui/static/freezer/js/freezer.jobs.actions.action.js
similarity index 100%
rename from freezer_ui/configurations/workflows/__init__.py
rename to freezer_ui/static/freezer/js/freezer.jobs.actions.action.js
diff --git a/freezer_ui/static/freezer/js/freezer.jobs.js b/freezer_ui/static/freezer/js/freezer.jobs.js
new file mode 100644
index 0000000..0a4d59e
--- /dev/null
+++ b/freezer_ui/static/freezer/js/freezer.jobs.js
@@ -0,0 +1,361 @@
+/* Launch Jobs workflow */
+
+function hideEverything() {
+ // Common controls
+ $("#id_is_windows").closest(".form-group").hide();
+ $("#id_backup_name").closest(".form-group").hide();
+ $("#id_container").closest(".form-group").hide();
+ $("#id_path_to_backup").closest(".form-group").hide();
+ $("#id_insecure").closest(".form-group").hide();
+ $("#id_os_auth_ver").closest(".form-group").hide();
+ $("#id_dry_run").closest(".form-group").hide();
+ $("#id_encryption_password").closest(".form-group").hide();
+ $("#id_exclude").closest(".form-group").hide();
+ $("#id_log_file").closest(".form-group").hide();
+ $("#id_proxy").closest(".form-group").hide();
+ $("#id_max_priority").closest(".form-group").hide();
+ $("#id_quiet").closest(".form-group").hide();
+ $("#id_advanced_configuration").closest(".form-group").hide();
+ $("#id_description").closest(".form-group").hide();
+ $("#id_client_id").closest(".form-group").hide();
+ $("#id_tag").closest(".form-group").hide();
+
+
+ // Backup specific controls
+ $("#id_mysql_conf").closest(".form-group").hide();
+ $("#id_compression").closest(".form-group").hide();
+ $("#id_optimize").closest(".form-group").hide();
+ $("#id_upload_limit").closest(".form-group").hide();
+ $("#id_dereference_symlink").closest(".form-group").hide();
+ $("#id_max_segment_size").closest(".form-group").hide();
+ $("#id_dst_file").closest(".form-group").hide();
+ $("#id_mode").closest(".form-group").hide();
+ $("#id_sql_server_conf").closest(".form-group").hide();
+ $("#id_cinder_vol_id").closest(".form-group").hide();
+ $("#id_nova_inst_id").closest(".form-group").hide();
+ $("#id_max_level").closest(".form-group").hide();
+ $("#id_always_level").closest(".form-group").hide();
+ $("#id_restart_always_level").closest(".form-group").hide();
+ $("#id_no_incremental").closest(".form-group").hide();
+ $("#id_hostname").closest(".form-group").hide();
+ $("#id_upload").closest(".form-group").hide();
+
+ // Snapshot specific controls
+ $("#id_use_snapshot").closest(".form-group").hide();
+ $("#id_lvm_auto_snap").closest(".form-group").hide();
+ $("#id_lvm_srcvol").closest(".form-group").hide();
+ $("#id_lvm_snapname").closest(".form-group").hide();
+ $("#id_lvm_snapsize").closest(".form-group").hide();
+ $("#id_lvm_dirmount").closest(".form-group").hide();
+ $("#id_lvm_volgroup").closest(".form-group").hide();
+ $("#id_vssadmin").closest(".form-group").hide();
+
+ // Restore specific controls
+ $("#id_download_limit").closest(".form-group").hide();
+ $("#id_restore_abs_path").closest(".form-group").hide();
+ $("#id_restore_from_host").closest(".form-group").hide();
+ $("#id_restore_from_date").closest(".form-group").hide();
+
+ // Admin specific controls
+ $("#id_remove_older_than").closest(".form-group").hide();
+ $("#id_remove_from_date").closest(".form-group").hide();
+ $("#id_get_object").closest(".form-group").hide();
+
+}
+
+function showAdminOptions() {
+ $("#id_remove_older_than").closest(".form-group").show();
+ $("#id_remove_from_date").closest(".form-group").show();
+ $("#id_get_object").closest(".form-group").show();
+}
+
+function showBackupOptions() {
+ $("#id_is_windows").closest(".form-group").show();
+ $("#id_mode").closest(".form-group").show();
+ $("#id_upload").closest(".form-group").show();
+ $("#id_container").closest(".form-group").show();
+ $("#id_use_snapshot").closest(".form-group").show();
+ $("#id_path_to_backup").closest(".form-group").show();
+ $("#id_backup_name").closest(".form-group").show();
+ $("#id_dereference_symlink").closest(".form-group").show();
+ $("#id_os_auth_ver").closest(".form-group").show();
+ $("#id_upload_limit").closest(".form-group").show();
+ $("#id_max_priority").closest(".form-group").show();
+ $("#id_quiet").closest(".form-group").show();
+ $("#id_proxy").closest(".form-group").show();
+ $("#id_log_file").closest(".form-group").show();
+ $("#id_exclude").closest(".form-group").show();
+ $("#id_optimize").closest(".form-group").show();
+ $("#id_compression").closest(".form-group").show();
+ $("#id_encryption_password").closest(".form-group").show();
+ $("#id_max_segment_size").closest(".form-group").show();
+ $("#id_no_incremental").closest(".form-group").show();
+ $("#id_hostname").closest(".form-group").show();
+
+ $("#id_container").closest(".form-group").addClass("required");
+
+}
+
+function showRestoreOptions() {
+ $("#id_container").closest(".form-group").show();
+ $("#id_backup_name").closest(".form-group").show();
+ $("#id_restore_abs_path").closest(".form-group").show();
+ $("#id_restore_from_host").closest(".form-group").show();
+ $("#id_restore_from_date").closest(".form-group").show();
+ $("#id_os_auth_ver").closest(".form-group").show();
+ $("#id_download_limit").closest(".form-group").show();
+ $("#id_max_priority").closest(".form-group").show();
+ $("#id_quiet").closest(".form-group").show();
+ $("#id_proxy").closest(".form-group").show();
+ $("#id_log_file").closest(".form-group").show();
+}
+
+function showLinuxSnapshotOptions() {
+ $("#id_lvm_auto_snap").closest(".form-group").show();
+ $("#id_lvm_srcvol").closest(".form-group").show();
+ $("#id_lvm_snapname").closest(".form-group").show();
+ $("#id_lvm_snapsize").closest(".form-group").show();
+ $("#id_lvm_dirmount").closest(".form-group").show();
+ $("#id_lvm_volgroup").closest(".form-group").show();
+}
+
+function hideLinuxSnapshotOptions() {
+ $("#id_lvm_srcvol").closest(".form-group").hide();
+ $("#id_lvm_snapname").closest(".form-group").hide();
+ $("#id_lvm_snapsize").closest(".form-group").hide();
+ $("#id_lvm_dirmount").closest(".form-group").hide();
+ $("#id_lvm_volgroup").closest(".form-group").hide();
+ $("#id_lvm_auto_snap").closest(".form-group").hide();
+}
+
+function showWindowsSnapshotOptions() {
+ // TODO: windows doesn't need to display this option
+ // because is redundant
+ $("#id_vssadmin").closest(".form-group").show();
+}
+
+function hideWindowsSnapshotOptions() {
+ $("#id_vssadmin").closest(".form-group").hide();
+}
+
+function is_windows() {
+ if ($("#id_is_windows").is(":checked")) {
+ return true;
+ }
+}
+
+function showSnapshotOptions() {
+ if (is_windows()) {
+ hideLinuxSnapshotOptions();
+ showWindowsSnapshotOptions();
+ }
+ else {
+ hideWindowsSnapshotOptions();
+ showLinuxSnapshotOptions();
+ }
+}
+
+function hideSnapshotOptions() {
+ hideWindowsSnapshotOptions();
+ hideLinuxSnapshotOptions();
+}
+
+function showNovaOptions() {
+ $("#id_client_id").closest(".form-group").show();
+ $("#id_mode").closest(".form-group").show();
+ $("#id_proxy").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();
+ $("#id_nova_inst_id").closest(".form-group").show().addClass("required");
+}
+
+function showCinderOptions() {
+ $("#id_client_id").closest(".form-group").show();
+ $("#id_mode").closest(".form-group").show();
+ $("#id_proxy").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();
+ $("#id_path_to_backup").closest(".form-group").show();
+ $("#id_cinder_vol_id").closest(".form-group").show().addClass("required");
+}
+
+function showIncrementalOptions() {
+ $("#id_max_level").closest(".form-group").show();
+ $("#id_always_level").closest(".form-group").show();
+ $("#id_restart_always_level").closest(".form-group").show();
+}
+
+function hideIncrementalOptions() {
+ $("#id_max_level").closest(".form-group").hide();
+ $("#id_always_level").closest(".form-group").hide();
+ $("#id_restart_always_level").closest(".form-group").hide();
+ $("#id_advanced_configuration").closest(".form-group").show();
+}
+
+function showAdvancedConfigurationOptions() {
+ hideEverything();
+ showBackupOptions();
+ $("#id_tag").closest(".form-group").show();
+}
+
+function hideAdvancedConfigurationOptions() {
+ hideEverything();
+ hideIncrementalOptions();
+ $("#id_backup_name").closest(".form-group").show();
+ $("#id_container").closest(".form-group").show();
+ $("#id_action").closest(".form-group").show();
+ $("#id_path_to_backup").closest(".form-group").show();
+ $("#id_advanced_configuration").closest(".form-group").show();
+ $("#id_mode").closest(".form-group").show();
+ $("#id_tag").closest(".form-group").hide();
+}
+
+function hideRestoreAdvancedConfigurationOptions() {
+ hideEverything();
+ $("#id_backup_name").closest(".form-group").show();
+ $("#id_container").closest(".form-group").show();
+ $("#id_action").closest(".form-group").show();
+ $("#id_advanced_configuration").closest(".form-group").show();
+ $("#id_restore_abs_path").closest(".form-group").show();
+ $("#id_restore_from_host").closest(".form-group").show();
+ $("#id_restore_from_date").closest(".form-group").show();
+}
+
+function showRestoreAdvancedConfigurationOptions() {
+ hideEverything();
+ showRestoreOptions();
+}
+
+hideEverything();
+
+$("#id_action").change(function() {
+ // Update the inputs according freezer action
+
+ if ($("#id_action").val() == 'backup') {
+ hideEverything();
+ showBackupOptions();
+ hideAdvancedConfigurationOptions();
+ $("#id_description").closest(".form-group").show();
+ $("#id_client_id").closest(".form-group").show();
+ }
+ else if ($("#id_action").val() == 'restore') {
+ hideEverything();
+ showRestoreOptions();
+ hideRestoreAdvancedConfigurationOptions();
+ $("#id_description").closest(".form-group").show();
+ $("#id_client_id").closest(".form-group").show();
+ }
+ else if ($("#id_action").val() == 'admin') {
+ hideEverything();
+ showAdminOptions();
+ $("#id_client_id").closest(".form-group").show();
+ $("#id_description").closest(".form-group").show();
+ }
+ else if ($("#id_action").val() == 'info') {
+ hideEverything();
+ }
+ else {
+ hideEverything();
+ }
+});
+
+$("#id_use_snapshot").click(function() {
+ if ($("#id_use_snapshot").is(":checked")) {
+ showSnapshotOptions();
+ }
+ else {
+ hideSnapshotOptions();
+ }
+});
+
+$("#id_is_windows").click(function() {
+ if ($("#id_use_snapshot").is(":checked")) {
+ showSnapshotOptions();
+ }
+ else {
+ hideSnapshotOptions();
+ }
+});
+
+$("#id_mode").change(function() {
+ if ($("#id_action").val() == 'backup') {
+ if ($("#id_mode").val() == 'fs') {
+ hideEverything();
+ showBackupOptions();
+ showSnapshotOptions();
+ $("#id_advanced_configuration").closest(".form-group").show();
+ }
+ else if ($("#id_mode").val() == 'mysql') {
+ hideEverything();
+ showBackupOptions();
+ showSnapshotOptions();
+ $("#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();
+ showSnapshotOptions();
+ $("#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() == 'cinder') {
+ hideEverything();
+ showCinderOptions();
+ $("#id_cinder_vol_id").closest(".form-group").show().addClass("required");
+ $("#id_advanced_configuration").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();
+ }
+ else {
+
+ }
+ }
+});
+
+$("#id_upload").change(function() {
+ if ($("#id_upload").is(":checked")) {
+ $("#id_container").closest(".form-group").show().addClass("required");
+ }
+ else {
+ $("#id_container").closest(".form-group").hide().removeClass("required");
+ }
+});
+
+$("#id_no_incremental").click(function() {
+ if ($("#id_no_incremental").is(":checked")) {
+ hideIncrementalOptions();
+ }
+ else {
+ showIncrementalOptions();
+ }
+});
+
+$("#id_advanced_configuration").click(function() {
+ if ($("#id_action").val() == 'backup') {
+ if ($("#id_advanced_configuration").is(":checked")) {
+ showAdvancedConfigurationOptions();
+ $("#id_advanced_configuration").closest(".form-group").show();
+ }
+ else {
+ hideAdvancedConfigurationOptions();
+ }
+ }
+ else if ($("#id_action").val() == 'restore') {
+ if ($("#id_advanced_configuration").is(":checked")) {
+ showRestoreAdvancedConfigurationOptions();
+ $("#id_advanced_configuration").closest(".form-group").show();
+ }
+ else {
+ hideRestoreAdvancedConfigurationOptions();
+ }
+ }
+});
\ No newline at end of file
diff --git a/freezer_ui/overview/urls.py b/freezer_ui/utils.py
similarity index 71%
rename from freezer_ui/overview/urls.py
rename to freezer_ui/utils.py
index 5427446..745ad88 100644
--- a/freezer_ui/overview/urls.py
+++ b/freezer_ui/utils.py
@@ -10,13 +10,10 @@
# License for the specific language governing permissions and limitations
# under the License.
-from django.conf.urls import patterns
-from django.conf.urls import url
-from horizon_web_ui.freezer_ui.overview import views
-
-
-urlpatterns = patterns(
- '',
- url(r'^$', views.IndexView.as_view(), name='index'),
-)
+def create_dict_action(**kwargs):
+ """
+ Create a dict only with values that exists so we avoid send keys with
+ None values
+ """
+ return {k: v for k, v in kwargs.items() if v}