# Licensed under the Apache License, Version 2.0 (the "License"); you may # not use this file except in compliance with the License. You may obtain # a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the # License for the specific language governing permissions and limitations # under the License. import logging import datetime import uuid import re from functools import wraps from django.core.urlresolvers import reverse from django.template.defaultfilters import date as django_date from django.utils.translation import ugettext_lazy as _ from horizon import exceptions LOG = logging.getLogger(__name__) def create_dict(**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} def timestamp_to_string(ts): return django_date( datetime.datetime.fromtimestamp(int(ts)), 'SHORT_DATETIME_FORMAT') def create_dummy_id(): """Generate a dummy id for documents generated by the scheduler. This is needed when the scheduler creates jobs with actions attached directly, those actions are not registered in the db. """ return uuid.uuid4().hex def get_action_ids(ids): """Return an ordered list of actions for a new job """ ids = ids.split('===') return [i for i in ids if i] def assign_and_remove(source_dict, dest_dict, key): """Assign a value to a destination dict from a source dict if the key exists """ if key in source_dict: dest_dict[key] = source_dict.pop(key) class SessionObject(object): def __init__(self, session_id, description, status, jobs, start_datetime, interval, end_datetime): self.session_id = session_id self.id = session_id self.description = description self.status = status self.jobs = jobs or [] self.schedule_start_date = start_datetime self.schedule_end_date = end_datetime self.schedule_interval = interval class JobObject(object): def __init__(self, job_id, description, result, event, client_id='_'): self.job_id = job_id self.id = job_id self.description = description self.result = result or 'pending' self.event = event or 'stop' # Checking if client_id composed like _ if re.search("^[a-z0-9]{32}_.+", client_id): self.client_id = client_id.split('_')[1] else: self.client_id = client_id class JobsInSessionObject(object): def __init__(self, job_id, session_id, client_id, result): self.job_id = job_id self.session_id = session_id self.id = session_id self.client_id = client_id self.result = result or 'pending' class ActionObject(object): def __init__(self, action_id=None, action=None, backup_name=None, job_id=None): # action basic info self.id = action_id self.action_id = action_id or create_dummy_id() self.action = action or 'backup' self.backup_name = backup_name or 'no backup name available' self.job_id = job_id class ActionObjectDetail(object): def __init__(self, action_id=None, action=None, backup_name=None, path_to_backup=None, storage=None, mode=None, container=None, mandatory=None, max_retries=None, max_retries_interval=None): # action basic info self.id = action_id self.action_id = action_id or create_dummy_id() self.action = action or 'backup' self.backup_name = backup_name or 'no backup name available' self.path_to_backup = path_to_backup self.storage = storage or 'swift' self.mode = mode or 'fs' self.container = container # action rules self.mandatory = mandatory self.max_retries = max_retries self.max_retries_interval = max_retries_interval class BackupObject(object): def __init__(self, backup_id=None, action=None, time_stamp=None, backup_name=None, backup_media=None, path_to_backup=None, hostname=None, level=None, container=None, curr_backup_level=None, encrypted=None, total_broken_links=None, excluded_files=None, storage=None, ssh_host=None, ssh_key=None, ssh_username=None, ssh_port=None, mode=None): self.backup_id = backup_id self.id = backup_id self.backup_name = backup_name self.action = action or 'backup' self.time_stamp = time_stamp self.backup_media = backup_media or 'fs' self.path_to_backup = path_to_backup self.hostname = hostname self.container = container self.level = level self.curr_backup_level = curr_backup_level or 0 self.encrypted = encrypted self.total_broken_links = total_broken_links or 0 self.excluded_files = excluded_files self.storage = storage self.ssh_host = ssh_host self.ssh_key = ssh_key self.ssh_username = ssh_username self.ssh_port = ssh_port or 22 self.mode = mode or 'fs' class ClientObject(object): def __init__(self, hostname, client_id, client_uuid): self.hostname = hostname self.client_id = client_id self.uuid = client_uuid self.id = client_id def shield(message, redirect=''): """decorator to reduce boilerplate try except blocks for horizon functions :param message: a str error message :param redirect: a str with the redirect namespace without including horizon:disaster_recovery: eg. @shield('error', redirect='jobs:index') """ def wrap(function): @wraps(function) def wrapped_function(request, *args, **kwargs): try: return function(request, *args, **kwargs) except Exception as error: LOG.error(error.message) namespace = "horizon:disaster_recovery:" r = reverse("{0}{1}".format(namespace, redirect)) exceptions.handle(request, _(message), redirect=r) return wrapped_function return wrap def timestamp_to_iso(ts): """Generate an iso date from time stamp :param ts: time stamp :return: iso date """ return datetime.datetime.fromtimestamp(ts).isoformat()