You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
160 lines
7.3 KiB
160 lines
7.3 KiB
# Copyright (C) 2005-2025 Splunk Inc. All Rights Reserved.
|
|
|
|
import itsi_py3
|
|
import sys
|
|
import os
|
|
from ITOA.itoa_object import ItoaObject, CRUDMethodTypes
|
|
from ITOA.setup_logging import logger
|
|
from time import time
|
|
|
|
from itsi.itsi_utils import ITOAInterfaceUtils, DEFAULT_SCHEDULED_BACKUP_KEY
|
|
|
|
from splunk.clilib.bundle_paths import make_splunkhome_path
|
|
|
|
from itsi.upgrade.file_manager import FileManager
|
|
|
|
sys.path.append(make_splunkhome_path(['etc', 'apps', 'SA-ITOA', 'lib', 'SA_ITOA_app_common']))
|
|
|
|
from SA_ITOA_app_common.solnlib.server_info import ServerInfo
|
|
|
|
BACKUP_PATH = make_splunkhome_path(['var', 'itsi', 'backups'])
|
|
|
|
|
|
class ItsiBackupRestore(ItoaObject):
|
|
"""
|
|
Implements ITSI Backup Restore
|
|
"""
|
|
logger = logger
|
|
log_prefix = '[ITSI Backup Restore] '
|
|
collection_name = 'itsi_backup_restore_queue'
|
|
ITOA_OBJECT_TYPE = 'backup_restore'
|
|
|
|
def __init__(self, session_key, current_user_name):
|
|
session_key = session_key
|
|
super(ItsiBackupRestore, self).__init__(session_key,
|
|
current_user_name,
|
|
'backup_restore',
|
|
collection_name=self.collection_name,
|
|
title_validation_required=True)
|
|
|
|
def do_object_validation(self, owner, objects, validate_name=True, dupname_tag=None, transaction_id=None, skip_local_failure=False):
|
|
super(ItsiBackupRestore, self).do_object_validation(owner, objects,
|
|
validate_name=validate_name, dupname_tag=dupname_tag, transaction_id=transaction_id, skip_local_failure=skip_local_failure)
|
|
for object_data in objects:
|
|
self.validate_keep_max_time(object_data)
|
|
|
|
def validate_keep_max_time(self, data):
|
|
"""
|
|
Validates that the keep_max_time field is set appropriately.
|
|
|
|
@param data: the backup/restore object data
|
|
@type data: dict
|
|
"""
|
|
frequency = data.get('frequency', None)
|
|
keep_max_time = data.get('keep_max_time', None)
|
|
if frequency is None or keep_max_time is None:
|
|
return
|
|
|
|
freq_to_min_days = {
|
|
'daily': 7,
|
|
'weekly': 14
|
|
}
|
|
|
|
min_days = freq_to_min_days[frequency]
|
|
min_keep_max_time = min_days * 24 * 60 * 60
|
|
if keep_max_time < min_keep_max_time:
|
|
logger.warn(
|
|
'The keep_max_time value is too low ({}). Setting it to {} for {} scheduled backup.'.format(
|
|
keep_max_time, min_keep_max_time, frequency)
|
|
)
|
|
data['keep_max_time'] = min_keep_max_time
|
|
|
|
"""
|
|
Not adding any validations here since its only used internally
|
|
In future if we see need, we could add validations.
|
|
|
|
Schema for this object and how its used internally:
|
|
|
|
create_time - set when it creates the job
|
|
start_time - set when the job starts running
|
|
end_time - set when the job ends running
|
|
last_queued_time - set when the job is queued
|
|
status - 'Not Started'/'Queued'/'Completed'/'Failed'
|
|
path - file path to the backup, uses upload/download endpoints
|
|
job_type - 'Backup' or 'Restore'
|
|
last_error - Last error seen when job tried to backup/restore, if any, else None
|
|
"""
|
|
|
|
def do_additional_setup(self, owner, objects, req_source='unknown', method=CRUDMethodTypes.METHOD_UPSERT, transaction_id=None, skip_local_failure=False):
|
|
info = ServerInfo(self.session_key)
|
|
local_search_head_id = info.guid
|
|
|
|
for json_data in objects:
|
|
# Assume json_data is valid
|
|
|
|
# If creating a backup job or a restore job, generate key and assign path
|
|
if method == CRUDMethodTypes.METHOD_CREATE:
|
|
# if it's default scheduled backup, no need to generate a new key
|
|
if not (json_data.get('_key') == DEFAULT_SCHEDULED_BACKUP_KEY and json_data.get('scheduled') == 1):
|
|
json_data['_key'] = ITOAInterfaceUtils.generate_backend_key()
|
|
if not json_data.get('search_head_id'):
|
|
json_data['search_head_id'] = local_search_head_id
|
|
if json_data.get('status') == 'Queued' and (
|
|
not isinstance(json_data.get('last_queued_time'), itsi_py3.string_type) or len(
|
|
json_data.get('last_queued_time')) < 1):
|
|
json_data['last_queued_time'] = time()
|
|
|
|
if method == CRUDMethodTypes.METHOD_UPDATE or method == CRUDMethodTypes.METHOD_UPSERT:
|
|
# if Backup zip file exists locally, populate search_head_id to current host's guid
|
|
path_to_backup_zip = os.path.join(BACKUP_PATH, json_data['_key'] + '.zip')
|
|
if FileManager.is_exists(path_to_backup_zip):
|
|
json_data['search_head_id'] = local_search_head_id
|
|
|
|
if json_data['status'] == 'Queued' and (
|
|
not isinstance(json_data.get('last_queued_time'), itsi_py3.string_type) or len(
|
|
json_data.get('last_queued_time')) < 1):
|
|
json_data['last_queued_time'] = time()
|
|
|
|
def identify_dependencies(self, owner, objects, method, req_source='unknown', transaction_id=None, skip_local_failure=False):
|
|
"""
|
|
Identifying dependencies due to the changes and instead of creating a refresh job, immediately handling the job
|
|
@param {string} owner: user which is performing this operation
|
|
@param {list} objects: list of object
|
|
@param {string} method: method name
|
|
@param {string} req_source: request source
|
|
@return: a tuple
|
|
{boolean} set to true/false if dependency update is required
|
|
{list} list - list of refresh job, each element has the following
|
|
change_type: <identifier of the change used to pick change handler>,
|
|
changed_object_key: <Array of changed objects' keys>,
|
|
changed_object_type: <string of the type of object>
|
|
"""
|
|
if method == CRUDMethodTypes.METHOD_DELETE:
|
|
for object in objects:
|
|
path_to_directory = os.path.join(BACKUP_PATH, object.get('_key'))
|
|
path_to_zip = os.path.join(BACKUP_PATH, object.get('_key') + '.zip')
|
|
if FileManager.is_exists(path_to_directory):
|
|
FileManager.delete_working_directory(path_to_directory)
|
|
if FileManager.is_exists(path_to_zip):
|
|
FileManager.delete_file(path_to_zip)
|
|
return False, None
|
|
|
|
def is_any_backup_restore_job_in_progress(self, owner, req_source='unknown'):
|
|
"""
|
|
Checks for any backup/restore job in progress. Returns True, if
|
|
there is at least on job is in progress. Else, returns False.
|
|
@type owner: basestring
|
|
@param owner: user performing operation
|
|
@type req_source: basestring
|
|
@param req_source: request source
|
|
@return: bool
|
|
"""
|
|
job_fetch_filter = {'status': 'In Progress'}
|
|
backup_restore_job = self.get_bulk(owner, filter_data=job_fetch_filter, limit=1, req_source=req_source)
|
|
|
|
is_job_in_progress = False
|
|
if backup_restore_job and len(backup_restore_job) > 0:
|
|
is_job_in_progress = True
|
|
|
|
return is_job_in_progress
|