Module cvpysdk.backupsets.vsbackupset
Module for performing operations on a Backupset for the Virtual Server Agent.
VSBackupset is the only class defined in this file.
Vsbackupset
browse() – browse the content of the backupset _process_browse_response() – retrieves the items from browse response
To add a new Virtual Backupset, create a class in a new module under _virtual_server sub package
The new module which is created has to named in the following manner: 1. Name the module with the name of the Virtual Server without special characters 2.Spaces alone must be replaced with underscores('_')
For eg:
The Virtual Server 'Red Hat Virtualization' is named as 'red_hat_virtualization.py'
The Virtual Server 'Hyper-V' is named as 'hyperv.py'
Expand source code Browse git
# -*- coding: utf-8 -*-
# --------------------------------------------------------------------------
# Copyright Commvault Systems, 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.
# --------------------------------------------------------------------------
"""Module for performing operations on a Backupset for the **Virtual Server** Agent.
VSBackupset is the only class defined in this file.
VSBackupset:
browse() -- browse the content of the backupset
_process_browse_response() -- retrieves the items from browse response
To add a new Virtual Backupset, create a class in a new module under _virtual_server sub package
The new module which is created has to named in the following manner:
1. Name the module with the name of the Virtual Server without special characters
2.Spaces alone must be replaced with underscores('_')
For eg:
The Virtual Server 'Red Hat Virtualization' is named as 'red_hat_virtualization.py'
The Virtual Server 'Hyper-V' is named as 'hyperv.py'
"""
from __future__ import unicode_literals
import re
import time
from importlib import import_module
from inspect import isabstract, isclass, getmembers
from ..backupset import Backupset
from ..client import Client
from ..exception import SDKException
from ..subclient import Subclient as subclient
class VSBackupset(Backupset):
"""Derived class from Backupset Base class, representing a vs backupset,
and to perform operations on that backupset."""
def __new__(cls, instance_object, backupset_name, backupset_id=None):
"""Decides which instance object needs to be created"""
instance_name = instance_object.instance_name
instance_name = re.sub('[^A-Za-z0-9_]+', '', instance_name.replace(" ", "_"))
try:
backupset_module = import_module("cvpysdk.backupsets._virtual_server.{}".format(instance_name))
except ImportError:
return object.__new__(cls)
classes = getmembers(backupset_module, lambda m: isclass(m) and not isabstract(m))
for name, _class in classes:
if issubclass(_class, Backupset) and _class.__module__.rsplit(".", 1)[-1] == instance_name:
return object.__new__(_class)
@property
def hidden_subclient(self):
"""Creates the object for the hidden subclient
Returns:
_hidden_subclient - object of the subclient
"""
if not self._hidden_subclient:
hidden_subclient_service = self._commcell_object._services['VSA_HIDDEN_SUBCLIENT'] % (
self._client_object.client_name, self.backupset_name)
flag, response = self._commcell_object._cvpysdk_object.make_request(
"GET", hidden_subclient_service)
if flag:
if response.json():
hidden_subclient_id = response.json().get('subclientId')
else:
raise SDKException('Response', '102')
else:
raise SDKException('Response', '101', self._update_response_(response.text))
self._hidden_subclient = subclient(self, 'Do Not Backup', hidden_subclient_id)
return self._hidden_subclient
def browse(self, *args, **kwargs):
"""Browses the content of the Backupset.
Args:
Dictionary of browse options:
Example:
browse({
'path': 'c:\\\\hello',
'show_deleted': True,
'from_time': '2014-04-20 12:00:00',
'to_time': '2016-04-21 12:00:00'
})
Kwargs:
Keyword argument of browse options:
Example:
browse(
path='c:\\hello',
show_deleted=True,
from_time='2014-04-20 12:00:00',
to_time='2016-04-21 12:00:00'
)
Returns:
(list, dict)
list - List of only the file, folder paths from the browse response
dict - Dictionary of all the paths with additional metadata retrieved
from browse operation
"""
if args and isinstance(args[0], dict):
options = args[0]
else:
options = kwargs
options['retry_count'] = 0
return self._do_browse(options)
def _process_browse_response(self, flag, response, options):
"""Retrieves the items from browse response.
Args:
flag (bool) -- boolean, whether the response was success or not
response (dict) -- JSON response received for the request from the Server
options (dict) -- The browse options dictionary
Returns:
list - List of only the file / folder paths from the browse response
dict - Dictionary of all the paths with additional metadata retrieved from browse
Raises:
SDKException:
if failed to browse/search for content
if response is empty
if response is not success
"""
paths_dict = {}
paths = []
result_set = None
browse_result = None
error_message = None
options['retry_count'] = options['retry_count'] + 1
if flag:
response_json = response.json()
if response_json and 'browseResponses' in response_json:
_browse_responses = response_json['browseResponses']
if not isinstance(_browse_responses, list):
_browse_responses = [_browse_responses]
for browse_response in _browse_responses:
resp_type = browse_response['respType']
if 'messages' in browse_response:
# checking if it is not a list, then converting it to list
if not isinstance(browse_response['messages'], list):
browse_response['messages'] = [browse_response['messages']]
message = browse_response['messages'][0]
error_message = message['errorMessage']
if resp_type == 2 or resp_type == 3 and 'No items found in the index, possibly index is being rebuilt' in \
error_message:
if options['retry_count'] <= 3:
time.sleep(180)
return self._do_browse(options)
else:
err = "Maximum browse attemps exhausted. Browse did not give full results"
raise Exception(err)
if "browseResult" in browse_response:
browse_result = browse_response['browseResult']
if 'dataResultSet' in browse_result:
result_set = browse_result['dataResultSet']
if not isinstance(result_set, list):
result_set = [result_set]
break
if not browse_result:
if not isinstance(response_json['browseResponses'], list):
response_json['browseResponses'] = [response_json['browseResponses']]
if 'messages' in response_json['browseResponses'][0]:
if not isinstance(response_json['browseResponses'][0]['messages'], list):
response_json['browseResponses'][0]['messages'] = [
response_json['browseResponses'][0]['messages']]
message = response_json['browseResponses'][0]['messages'][0]
error_message = message['errorMessage']
if error_message == 'Please note that this is a live browse operation. Live browse operations can take some time before the results appear in the browse window.':
return [], {}
raise SDKException('Backupset', '102', str(error_message))
else:
return [], {}
if not result_set:
raise SDKException('Backupset', '110', "Failed to browse for subclient backup content")
if 'all_versions' in options['operation']:
return self._process_browse_all_versions_response(result_set)
for result in result_set:
name = result.get('displayName')
snap_display_name = result.get('name')
if 'path' in result:
path = result['path']
else:
path = '\\'.join([options['path'], name])
if 'modificationTime' in result and int(result['modificationTime']) > 0:
mod_time = time.localtime(int(result['modificationTime']))
mod_time = time.strftime('%d/%m/%Y %H:%M:%S', mod_time)
else:
mod_time = None
if 'backupTime' in result['advancedData'] and int(result['advancedData']['backupTime']) > 0:
bkp_time = time.localtime(int(result['advancedData']['backupTime']))
bkp_time = time.strftime('%d/%m/%Y %H:%M:%S', bkp_time)
else:
bkp_time = None
if 'file' in result['flags']:
if result['flags']['file'] is True or result['flags']['file'] == "1":
file_or_folder = 'File'
else:
file_or_folder = 'Folder'
else:
file_or_folder = 'Folder'
if 'size' in result:
size = result['size']
else:
size = None
paths_dict[path] = {
'name': name,
'snap_display_name': snap_display_name,
'size': size,
'modified_time': mod_time,
'type': file_or_folder,
'backup_time': bkp_time,
'advanced_data': result['advancedData']
}
paths.append(path)
return paths, paths_dict
else:
raise SDKException('Response', '101', self._update_response_(response.text))
@property
def index_server(self):
"""Returns the index server client set for the backupset"""
client_name = None
if 'indexSettings' in self._properties:
if 'currentIndexServer' in self._properties['indexSettings']:
client_name = self._properties['indexSettings']['currentIndexServer']['clientName']
if client_name is not None:
return Client(self._commcell_object, client_name=client_name)
return None
@index_server.setter
def index_server(self, value):
"""Sets index server client for the backupset. Property value should be a client object
Args:
value (obj) -- The cvpysdk client object of the index server client
Raises:
SDKException:
if response is empty
if response is not success
"""
if not isinstance(value, Client):
raise SDKException('Backupset', '106')
properties = self._properties
index_server_id = int(value.client_id)
index_server_name = value.client_name
if 'indexSettings' in properties:
qualified_index_servers = []
if 'qualifyingIndexServers' in properties['indexSettings']:
for index_server in properties['indexSettings']['qualifyingIndexServers']:
qualified_index_servers.append(index_server['clientId'])
if index_server_id in qualified_index_servers:
properties['indexSettings']['currentIndexServer'] = {
'clientId': index_server_id,
'clientName': index_server_name
}
else:
raise SDKException(
'Backupset', '102', '{0} is not a qualified IndexServer client'.format(
index_server_name))
else:
properties['indexSettings'] = {
'currentIndexServer': {
'clientId': index_server_id,
'clientName': index_server_name
}
}
request_json = {
'backupsetProperties': properties
}
self._process_update_reponse(request_json)
@property
def vm_filter(self):
"""Returns the vm filters set at the backupset level
Returns:
list - list of content associated as the filters with the backupset
"""
return self.hidden_subclient.content
@vm_filter.setter
def vm_filter(self, content):
"""
Creates the list of content JSON to pass to the API to update
content of the vm filter of the backupset
Args:
content (list) -- list of the content to add as the filters to the
Backupset. list should contain name and type
"""
self.hidden_subclient.content = content
self.hidden_subclient.refresh()
@property
def vm_disk_filter(self):
"""Returns the vm disk filters set at the backupset level
Returns:
list - list of content associated as the disk filters with the backupset
"""
return self.hidden_subclient.vm_diskfilter
@vm_disk_filter.setter
def vm_disk_filter(self, vm_diskfilter):
"""
Creates the list of disk filter content JSON to pass to the API to update
content of the vm disk filter of the backupset
Args:
vm_diskfilter (list) -- list of the Disk filter to add
to the backupset
"""
self.hidden_subclient.vm_diskfilter = vm_diskfilter
self.hidden_subclient.refresh()
Classes
class VSBackupset (instance_object, backupset_name, backupset_id=None)
-
Derived class from Backupset Base class, representing a vs backupset, and to perform operations on that backupset.
Initialise the backupset object.
Args
instance_object (object) – instance of the Instance class
backupset_name (str) – name of the backupset
backupset_id (str) – id of the backupset default: None
Returns
object - instance of the Backupset class
Expand source code Browse git
class VSBackupset(Backupset): """Derived class from Backupset Base class, representing a vs backupset, and to perform operations on that backupset.""" def __new__(cls, instance_object, backupset_name, backupset_id=None): """Decides which instance object needs to be created""" instance_name = instance_object.instance_name instance_name = re.sub('[^A-Za-z0-9_]+', '', instance_name.replace(" ", "_")) try: backupset_module = import_module("cvpysdk.backupsets._virtual_server.{}".format(instance_name)) except ImportError: return object.__new__(cls) classes = getmembers(backupset_module, lambda m: isclass(m) and not isabstract(m)) for name, _class in classes: if issubclass(_class, Backupset) and _class.__module__.rsplit(".", 1)[-1] == instance_name: return object.__new__(_class) @property def hidden_subclient(self): """Creates the object for the hidden subclient Returns: _hidden_subclient - object of the subclient """ if not self._hidden_subclient: hidden_subclient_service = self._commcell_object._services['VSA_HIDDEN_SUBCLIENT'] % ( self._client_object.client_name, self.backupset_name) flag, response = self._commcell_object._cvpysdk_object.make_request( "GET", hidden_subclient_service) if flag: if response.json(): hidden_subclient_id = response.json().get('subclientId') else: raise SDKException('Response', '102') else: raise SDKException('Response', '101', self._update_response_(response.text)) self._hidden_subclient = subclient(self, 'Do Not Backup', hidden_subclient_id) return self._hidden_subclient def browse(self, *args, **kwargs): """Browses the content of the Backupset. Args: Dictionary of browse options: Example: browse({ 'path': 'c:\\\\hello', 'show_deleted': True, 'from_time': '2014-04-20 12:00:00', 'to_time': '2016-04-21 12:00:00' }) Kwargs: Keyword argument of browse options: Example: browse( path='c:\\hello', show_deleted=True, from_time='2014-04-20 12:00:00', to_time='2016-04-21 12:00:00' ) Returns: (list, dict) list - List of only the file, folder paths from the browse response dict - Dictionary of all the paths with additional metadata retrieved from browse operation """ if args and isinstance(args[0], dict): options = args[0] else: options = kwargs options['retry_count'] = 0 return self._do_browse(options) def _process_browse_response(self, flag, response, options): """Retrieves the items from browse response. Args: flag (bool) -- boolean, whether the response was success or not response (dict) -- JSON response received for the request from the Server options (dict) -- The browse options dictionary Returns: list - List of only the file / folder paths from the browse response dict - Dictionary of all the paths with additional metadata retrieved from browse Raises: SDKException: if failed to browse/search for content if response is empty if response is not success """ paths_dict = {} paths = [] result_set = None browse_result = None error_message = None options['retry_count'] = options['retry_count'] + 1 if flag: response_json = response.json() if response_json and 'browseResponses' in response_json: _browse_responses = response_json['browseResponses'] if not isinstance(_browse_responses, list): _browse_responses = [_browse_responses] for browse_response in _browse_responses: resp_type = browse_response['respType'] if 'messages' in browse_response: # checking if it is not a list, then converting it to list if not isinstance(browse_response['messages'], list): browse_response['messages'] = [browse_response['messages']] message = browse_response['messages'][0] error_message = message['errorMessage'] if resp_type == 2 or resp_type == 3 and 'No items found in the index, possibly index is being rebuilt' in \ error_message: if options['retry_count'] <= 3: time.sleep(180) return self._do_browse(options) else: err = "Maximum browse attemps exhausted. Browse did not give full results" raise Exception(err) if "browseResult" in browse_response: browse_result = browse_response['browseResult'] if 'dataResultSet' in browse_result: result_set = browse_result['dataResultSet'] if not isinstance(result_set, list): result_set = [result_set] break if not browse_result: if not isinstance(response_json['browseResponses'], list): response_json['browseResponses'] = [response_json['browseResponses']] if 'messages' in response_json['browseResponses'][0]: if not isinstance(response_json['browseResponses'][0]['messages'], list): response_json['browseResponses'][0]['messages'] = [ response_json['browseResponses'][0]['messages']] message = response_json['browseResponses'][0]['messages'][0] error_message = message['errorMessage'] if error_message == 'Please note that this is a live browse operation. Live browse operations can take some time before the results appear in the browse window.': return [], {} raise SDKException('Backupset', '102', str(error_message)) else: return [], {} if not result_set: raise SDKException('Backupset', '110', "Failed to browse for subclient backup content") if 'all_versions' in options['operation']: return self._process_browse_all_versions_response(result_set) for result in result_set: name = result.get('displayName') snap_display_name = result.get('name') if 'path' in result: path = result['path'] else: path = '\\'.join([options['path'], name]) if 'modificationTime' in result and int(result['modificationTime']) > 0: mod_time = time.localtime(int(result['modificationTime'])) mod_time = time.strftime('%d/%m/%Y %H:%M:%S', mod_time) else: mod_time = None if 'backupTime' in result['advancedData'] and int(result['advancedData']['backupTime']) > 0: bkp_time = time.localtime(int(result['advancedData']['backupTime'])) bkp_time = time.strftime('%d/%m/%Y %H:%M:%S', bkp_time) else: bkp_time = None if 'file' in result['flags']: if result['flags']['file'] is True or result['flags']['file'] == "1": file_or_folder = 'File' else: file_or_folder = 'Folder' else: file_or_folder = 'Folder' if 'size' in result: size = result['size'] else: size = None paths_dict[path] = { 'name': name, 'snap_display_name': snap_display_name, 'size': size, 'modified_time': mod_time, 'type': file_or_folder, 'backup_time': bkp_time, 'advanced_data': result['advancedData'] } paths.append(path) return paths, paths_dict else: raise SDKException('Response', '101', self._update_response_(response.text)) @property def index_server(self): """Returns the index server client set for the backupset""" client_name = None if 'indexSettings' in self._properties: if 'currentIndexServer' in self._properties['indexSettings']: client_name = self._properties['indexSettings']['currentIndexServer']['clientName'] if client_name is not None: return Client(self._commcell_object, client_name=client_name) return None @index_server.setter def index_server(self, value): """Sets index server client for the backupset. Property value should be a client object Args: value (obj) -- The cvpysdk client object of the index server client Raises: SDKException: if response is empty if response is not success """ if not isinstance(value, Client): raise SDKException('Backupset', '106') properties = self._properties index_server_id = int(value.client_id) index_server_name = value.client_name if 'indexSettings' in properties: qualified_index_servers = [] if 'qualifyingIndexServers' in properties['indexSettings']: for index_server in properties['indexSettings']['qualifyingIndexServers']: qualified_index_servers.append(index_server['clientId']) if index_server_id in qualified_index_servers: properties['indexSettings']['currentIndexServer'] = { 'clientId': index_server_id, 'clientName': index_server_name } else: raise SDKException( 'Backupset', '102', '{0} is not a qualified IndexServer client'.format( index_server_name)) else: properties['indexSettings'] = { 'currentIndexServer': { 'clientId': index_server_id, 'clientName': index_server_name } } request_json = { 'backupsetProperties': properties } self._process_update_reponse(request_json) @property def vm_filter(self): """Returns the vm filters set at the backupset level Returns: list - list of content associated as the filters with the backupset """ return self.hidden_subclient.content @vm_filter.setter def vm_filter(self, content): """ Creates the list of content JSON to pass to the API to update content of the vm filter of the backupset Args: content (list) -- list of the content to add as the filters to the Backupset. list should contain name and type """ self.hidden_subclient.content = content self.hidden_subclient.refresh() @property def vm_disk_filter(self): """Returns the vm disk filters set at the backupset level Returns: list - list of content associated as the disk filters with the backupset """ return self.hidden_subclient.vm_diskfilter @vm_disk_filter.setter def vm_disk_filter(self, vm_diskfilter): """ Creates the list of disk filter content JSON to pass to the API to update content of the vm disk filter of the backupset Args: vm_diskfilter (list) -- list of the Disk filter to add to the backupset """ self.hidden_subclient.vm_diskfilter = vm_diskfilter self.hidden_subclient.refresh()
Ancestors
Instance variables
-
Creates the object for the hidden subclient
Returns
_hidden_subclient - object of the subclient
Expand source code Browse git
@property def hidden_subclient(self): """Creates the object for the hidden subclient Returns: _hidden_subclient - object of the subclient """ if not self._hidden_subclient: hidden_subclient_service = self._commcell_object._services['VSA_HIDDEN_SUBCLIENT'] % ( self._client_object.client_name, self.backupset_name) flag, response = self._commcell_object._cvpysdk_object.make_request( "GET", hidden_subclient_service) if flag: if response.json(): hidden_subclient_id = response.json().get('subclientId') else: raise SDKException('Response', '102') else: raise SDKException('Response', '101', self._update_response_(response.text)) self._hidden_subclient = subclient(self, 'Do Not Backup', hidden_subclient_id) return self._hidden_subclient
var index_server
-
Returns the index server client set for the backupset
Expand source code Browse git
@property def index_server(self): """Returns the index server client set for the backupset""" client_name = None if 'indexSettings' in self._properties: if 'currentIndexServer' in self._properties['indexSettings']: client_name = self._properties['indexSettings']['currentIndexServer']['clientName'] if client_name is not None: return Client(self._commcell_object, client_name=client_name) return None
var vm_disk_filter
-
Returns the vm disk filters set at the backupset level
Returns
list - list of content associated as the disk filters with the backupset
Expand source code Browse git
@property def vm_disk_filter(self): """Returns the vm disk filters set at the backupset level Returns: list - list of content associated as the disk filters with the backupset """ return self.hidden_subclient.vm_diskfilter
var vm_filter
-
Returns the vm filters set at the backupset level
Returns
list - list of content associated as the filters with the backupset
Expand source code Browse git
@property def vm_filter(self): """Returns the vm filters set at the backupset level Returns: list - list of content associated as the filters with the backupset """ return self.hidden_subclient.content
Methods
def browse(self, *args, **kwargs)
-
Browses the content of the Backupset.
Args
Dictionary of browse options: Example:
browse({ 'path': 'c:\\hello', 'show_deleted': True, 'from_time': '2014-04-20 12:00:00', 'to_time': '2016-04-21 12:00:00' })
Kwargs
Keyword argument of browse options: Example:
browse( path='c:\hello', show_deleted=True, from_time='2014-04-20 12:00:00', to_time='2016-04-21 12:00:00' )
Returns
(list, dict) list - List of only the file, folder paths from the browse response
dict - Dictionary of all the paths with additional metadata retrieved from browse operation
Expand source code Browse git
def browse(self, *args, **kwargs): """Browses the content of the Backupset. Args: Dictionary of browse options: Example: browse({ 'path': 'c:\\\\hello', 'show_deleted': True, 'from_time': '2014-04-20 12:00:00', 'to_time': '2016-04-21 12:00:00' }) Kwargs: Keyword argument of browse options: Example: browse( path='c:\\hello', show_deleted=True, from_time='2014-04-20 12:00:00', to_time='2016-04-21 12:00:00' ) Returns: (list, dict) list - List of only the file, folder paths from the browse response dict - Dictionary of all the paths with additional metadata retrieved from browse operation """ if args and isinstance(args[0], dict): options = args[0] else: options = kwargs options['retry_count'] = 0 return self._do_browse(options)
Inherited members
-