Module cvpysdk.instances.sqlinstance
File for operating on a SQL Server Instance.
SQLServerInstance is the only class defined in this file.
SQLServerInstance: Derived class from Instance Base class, representing a sql server instance, and to perform operations on that instance
Sqlserverinstance
_get_instance_properties() – gets the instance related properties of SQL instance.
_get_instance_properties_json() – gets all the instance related properties of SQL instance.
_restore_request_json() – returns the restore request json
_process_restore_response() – processes response received for the Restore request
_get_sql_restore_options() – returns the dict containing destination sql server names
_run_backup() – runs full backup for this subclients and appends the job object to the return list
_process_browse_request() – processes response received for Browse request
_recoverypoint_request_json() – returns a json to be sent to server to create a recovery point
get_recovery_points() – lists all the recovery points
_process_recovery_point_request() – starts the recovery point job and process the response
backup() – runs full backup for all subclients associated with this instance
browse() – gets the content of the backup for this instance
browse_in_time() – gets the content of the backup for this instance in the time range specified
restore() – runs the restore job for specified
restore_to_destination_server() – restores the database on destination server
create_recovery_point() – creates a recovery point on destination server
table_level_restore() – starts the table level restore job
_table_level_restore_request_json() – returns a json to be sent to the server for table level restore job
mssql_instance_prop() – sets instance properties for the mssql instance
vss_option() – enables or disables VSS option on SQL instance
vdi_timeout() – sets the SQL VDI timeout value on SQL instance
impersonation() – sets impersonation on SQL instance with local system account or provided credentials
_get_ag_groups() – gets available Availability Groups from the primary replica and returns it
_get_ag_group_replicas() – gets replicas list from the Availability Group and returns it
create_sql_ag() – creates a new SQL Availability Group client and instance
SQLServerInstance Attributes:
mssql_instance_prop -- returns the mssql instance properties
ag_group_name -- returns the Availability Group Name
ag_primary_replica -- returns the Availability Group Primary Replica
ag_replicas_list -- returns the Availability Group Replicas List
ag_listener_list -- returns the Availability Group Listener List
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.
# --------------------------------------------------------------------------
"""File for operating on a SQL Server Instance.
SQLServerInstance is the only class defined in this file.
SQLServerInstance: Derived class from Instance Base class, representing a sql server instance,
and to perform operations on that instance
SQLServerInstance:
_get_instance_properties() -- gets the instance related properties of SQL instance.
_get_instance_properties_json() -- gets all the instance related properties of SQL instance.
_restore_request_json() -- returns the restore request json
_process_restore_response() -- processes response received for the Restore request
_get_sql_restore_options() -- returns the dict containing destination sql server names
_run_backup() -- runs full backup for this subclients and appends the
job object to the return list
_process_browse_request() -- processes response received for Browse request
_recoverypoint_request_json() -- returns a json to be sent to server to create
a recovery point
get_recovery_points() -- lists all the recovery points
_process_recovery_point_request() -- starts the recovery point job and process
the response
backup() -- runs full backup for all subclients associated
with this instance
browse() -- gets the content of the backup for this instance
browse_in_time() -- gets the content of the backup for this instance
in the time range specified
restore() -- runs the restore job for specified
restore_to_destination_server() -- restores the database on destination server
create_recovery_point() -- creates a recovery point on destination server
table_level_restore() -- starts the table level restore job
_table_level_restore_request_json() -- returns a json to be sent to the server for
table level restore job
mssql_instance_prop() -- sets instance properties for the mssql instance
vss_option() -- enables or disables VSS option on SQL instance
vdi_timeout() -- sets the SQL VDI timeout value on SQL instance
impersonation() -- sets impersonation on SQL instance with local system account or provided credentials
_get_ag_groups() -- gets available Availability Groups from the primary replica and returns it
_get_ag_group_replicas() -- gets replicas list from the Availability Group and returns it
create_sql_ag() -- creates a new SQL Availability Group client and instance
SQLServerInstance Attributes:
mssql_instance_prop -- returns the mssql instance properties
ag_group_name -- returns the Availability Group Name
ag_primary_replica -- returns the Availability Group Primary Replica
ag_replicas_list -- returns the Availability Group Replicas List
ag_listener_list -- returns the Availability Group Listener List
"""
import re
import time
import datetime
import threading
from base64 import b64encode
from ..instance import Instance
from ..exception import SDKException
from ..job import Job
from ..constants import SQLDefines
class SQLServerInstance(Instance):
"""Derived class from Instance Base class, representing a SQL Server instance,
and to perform operations on that Instance."""
def _get_instance_properties(self):
"""Gets the properties of this instance.
Raises:
SDKException:
if response is empty
if response is not success
"""
super(SQLServerInstance, self)._get_instance_properties()
self._ag_group_name = None
self._ag_primary_replica = None
self._ag_replicas_list = []
self._ag_group_listener_list = []
self._mssql_instance_prop = self._properties.get('mssqlInstance', {})
flag, response = self._commcell_object._cvpysdk_object.make_request(
'GET', self._commcell_object._services['INSTANCE'] %self._instance_id + "?propertyLevel=20"
)
if flag:
if response.json():
self._mssql_instance_prop = response.json()['instanceProperties'][0]['mssqlInstance']
if 'agProperties' in self._mssql_instance_prop:
self._ag_group_name = self.mssql_instance_prop.get(
'agProperties', {}).get('availabilityGroup', {}).get('name')
self._ag_primary_replica = self.mssql_instance_prop.get(
'agProperties', {}).get('availabilityGroup', {}).get('primaryReplicaServerName')
listener_list_tmp = []
listener_list = self.mssql_instance_prop.get(
'agProperties', {}).get('availabilityGroup', {}).get('SQLAvailabilityGroupListenerList', {})
for listener in listener_list:
listener_list_tmp.append(listener['availabilityGroupListenerName'])
self._ag_listener_list = listener_list_tmp
replica_list_tmp = []
replica_list = self.mssql_instance_prop.get(
'agProperties', {}).get('SQLAvailabilityReplicasList', {})
if replica_list:
for replica in replica_list['SQLAvailabilityReplicasList']:
replica_dict = {
"serverName" : replica['name'],
"clientId" : replica['replicaClient']['clientId'],
"clientName": replica['replicaClient']['clientName']
}
replica_list_tmp.append(replica_dict)
self._ag_replicas_list = replica_list_tmp
def _get_instance_properties_json(self):
"""get the all instance related properties of this instance.
Returns:
dict - all subclient properties put inside a dict
"""
instance_json = {
"instanceProperties":
{
"instance": self._instance,
"instanceActivityControl": self._instanceActivityControl,
"mssqlInstance": self._mssql_instance_prop,
"contentOperationType": 1
}
}
return instance_json
@property
def ag_group_name(self):
"""Returns the Availability Group Name"""
return self._ag_group_name
@property
def ag_primary_replica(self):
"""Returns the Availability Group Primary Replica"""
return self._ag_primary_replica
@property
def ag_replicas_list(self):
"""Returns the Availability Group Replicas List"""
return self._ag_replicas_list
@property
def ag_listener_list(self):
"""Returns the Availability Group Listener List"""
return self._ag_listener_list
def _restore_request_json(
self,
content_to_restore,
restore_path=None,
drop_connections_to_databse=False,
overwrite=True,
destination_instance=None,
to_time=None,
sql_restore_type=SQLDefines.DATABASE_RESTORE,
sql_recover_type=SQLDefines.STATE_RECOVER,
undo_path=None,
restricted_user=None
):
"""Returns the JSON request to pass to the API as per the options selected by the user.
Args:
content_to_restore (list): databases list to restore
restore_path (list, optional): list of dicts for restore paths of database files
drop_connections_to_databse (bool, optional): drop connections to database during restore
overwrite (bool, optional): overwrite database on restore
destination_instance (str): restore databases to this sql instance
to_time (str, optional): restore to time
sql_restore_type (str, optional): type of sql restore state
(DATABASE_RESTORE, STEP_RESTORE, RECOVER_ONLY)
sql_recover_type (str, optional): type of sql restore state
(STATE_RECOVER, STATE_NORECOVER, STATE_STANDBY)
undo_path (str, optional): file path for undo path for sql server standby restore
restricted_user (bool, optional): Restore database in restricted user mode
Returns:
dict - JSON request to pass to the API
"""
self._get_sql_restore_options(content_to_restore)
if destination_instance is None:
destination_instance = (self.instance_name).lower()
if destination_instance not in self.destination_instances_dict:
raise SDKException(
'Instance',
'102',
'SQL Instance [{0}] not suitable for restore destination or does not exist.'
.format(destination_instance)
)
destination_client_id = int(
self.destination_instances_dict[destination_instance]['clientId']
)
destination_instance_id = int(
self.destination_instances_dict[destination_instance]['instanceId']
)
request_json = {
"taskInfo": {
"associations": [{
"clientName": self._agent_object._client_object.client_name,
"appName": self._agent_object.agent_name,
"instanceName": self.instance_name
}],
"task": {
"initiatedFrom": 1,
"taskType": 1
},
"subTasks": [{
"subTask": {
"subTaskType": 3,
"operationType": 1001
},
"options": {
"restoreOptions": {
"sqlServerRstOption": {
"sqlRecoverType": sql_recover_type,
"dropConnectionsToDatabase": drop_connections_to_databse,
"overWrite": overwrite,
"sqlRestoreType": sql_restore_type,
"database": content_to_restore,
"restoreSource": content_to_restore
},
"commonOptions": {
},
"destination": {
"destinationInstance": {
"clientId": destination_client_id,
"instanceName": destination_instance,
"instanceId": destination_instance_id
},
"destClient": {
"clientId": destination_client_id
}
}
}
}
}]
}
}
if sql_recover_type == SQLDefines.STATE_STANDBY:
if undo_path is not None:
undo_path_dict = {
"fileOption": {
"mapFiles": {
"renameFilesSuffix": undo_path
}
}
}
request_json['taskInfo']['subTasks'][0]['options']['restoreOptions'].update(undo_path_dict)
else:
raise SDKException('Instance', '102', 'Failed to set Undo Path for Standby Restore.')
if restore_path is not None:
restore_path_dict = {
"device":
restore_path
}
request_json['taskInfo']['subTasks'][0]['options']['restoreOptions'][
'sqlServerRstOption'].update(restore_path_dict)
if restricted_user is not None:
restricted_user_dict = {
"dbOnly":
restricted_user
}
request_json['taskInfo']['subTasks'][0]['options']['restoreOptions'][
'sqlServerRstOption'].update(restricted_user_dict)
if to_time is not None:
to_time_dict = {
"browseOption": {
"timeRange": {
"toTimeValue": to_time
}
}
}
request_json['taskInfo']['subTasks'][0]['options']['restoreOptions'].update(to_time_dict)
return request_json
def _process_restore_response(self, request_json):
"""Runs the CreateTask API with the request JSON provided for Restore,
and returns the contents after parsing the response.
Args:
request_json (dict): JSON request to run for the API
Returns:
object - instance of the Job class for this restore job
Raises:
SDKException:
if restore job failed
if response is empty
if response is not success
"""
flag, response = self._commcell_object._cvpysdk_object.make_request(
'POST', self._commcell_object._services['RESTORE'], request_json
)
if flag:
if response.json():
if "jobIds" in response.json():
time.sleep(1)
return Job(self._commcell_object, response.json()['jobIds'][0])
elif "errorCode" in response.json():
error_message = response.json()['errorMessage']
o_str = 'Restore job failed\nError: "{0}"'.format(error_message)
raise SDKException('Instance', '102', o_str)
else:
raise SDKException('Instance', '102', 'Failed to run the restore job')
else:
raise SDKException('Response', '102')
else:
response_string = self._commcell_object._update_response_(response.text)
raise SDKException('Response', '101', response_string)
def _get_sql_restore_options(self, content_to_restore):
"""Runs the SQL/Restoreoptions API with the request JSON provided,
and returns the contents after parsing the response.
Args:
content_to_restore (list): Databases list to restore
Returns:
dict - dictionary consisting of the sql destination server options
Raises:
SDKException:
if failed to get SQL instances
if no instance exits on commcell
if response is empty
if response is not success
"""
contents_dict = []
for content in content_to_restore:
database_dict = {
"databaseName": content
}
contents_dict.append(database_dict)
request_json = {
"restoreDbType": 0,
"sourceInstanceId": int(self.instance_id),
"selectedDatabases": contents_dict
}
webservice = self._commcell_object._services['SQL_RESTORE_OPTIONS']
flag, response = self._commcell_object._cvpysdk_object.make_request(
"POST", webservice, request_json
)
self.destination_instances_dict = {}
if flag:
if response.json():
if 'sqlDestinationInstances' in response.json():
for instance in response.json()['sqlDestinationInstances']:
instances_dict = {
instance['genericEntity']['instanceName'].lower(): {
"instanceId": int(instance['genericEntity']['instanceId']),
"clientId": int(instance['genericEntity']['clientId'])
}
}
self.destination_instances_dict.update(instances_dict)
elif 'error' in response.json():
if 'errorMessage' in response.json()['error']:
error_message = response.json()['error']['errorMessage']
raise SDKException('Instance', '102', error_message)
else:
raise SDKException('Instance', '102', 'No Instance exists on commcell')
else:
raise SDKException('Response', '102')
else:
response_string = self._commcell_object._update_response_(response.text)
raise SDKException('Response', '101', response_string)
return response.json()
def _run_backup(self, subclient_name, return_list):
"""Triggers full backup job for the given subclient, and appends its Job object to list
The SDKExcpetion class instance is appended to the list,
if any exception is raised while running the backup job for the Subclient.
Args:
subclient_name (str): Name of the subclient to trigger the backup for
return_list (list): List to append the job object to
"""
try:
job = self.subclients.get(subclient_name).backup('Full')
if job:
return_list.append(job)
except SDKException as excp:
return_list.append(excp)
def _process_browse_request(self, browse_request, get_full_details=False):
"""Runs the SQL Instance Browse API with the request JSON provided for the operation
specified, and returns the contents after parsing the response.
Args:
browse_request (dict): JSON request to be sent to Server
Returns:
list - list of all databases
dict - database names along with details like backup created time
and database version
Raises:
SDKException:
if response is empty
if response is not success
"""
flag, response = self._commcell_object._cvpysdk_object.make_request("GET", browse_request)
full_result = []
databases = []
if flag:
if response.json():
if 'sqlDatabase' in response.json():
# returns whole dict if requested
if get_full_details:
return response.json()["sqlDatabase"]
for database in response.json()['sqlDatabase']:
database_name = database['databaseName']
created_time = datetime.datetime.fromtimestamp(
int(database['createdTime'])
).strftime('%d-%m-%Y %H:%M:%S')
version = database['version']
temp = {
database_name: [created_time, version]
}
databases.append(database_name)
full_result.append(temp)
return databases, full_result
else:
raise SDKException('Response', '102')
else:
response_string = self._commcell_object._update_response_(response.text)
raise SDKException('Response', '101', response_string)
def backup(self):
"""Run full backup job for all subclients in this instance.
Returns:
list - list containing the job objects for the full backup jobs started for
the subclients in the backupset
"""
return_list = []
thread_list = []
all_subclients = self.subclients._subclients
if all_subclients:
for subclient in all_subclients:
thread = threading.Thread(
target=self._run_backup, args=(subclient, return_list)
)
thread_list.append(thread)
thread.start()
for thread in thread_list:
thread.join()
return return_list
def browse(self, get_full_details=False):
"""Gets the list of the backed up databases for this instance.
Args:
get_full_details (bool) - if True returns dict with all databases
with last full backupjob details, default false
Returns:
list - list of all databases
dict - database names along with details like backup created time
and database version
Raises:
SDKException:
if response is empty
if response is not success
"""
browse_request = self._commcell_object._services['INSTANCE_BROWSE'] % (
self._agent_object._client_object.client_id, "SQL", self.instance_id
)
return self._process_browse_request(browse_request, get_full_details=get_full_details)
def browse_in_time(self, from_date=None, to_date=None):
"""Gets the list of the backed up databases for this instance in the given time frame.
Args:
from_date (str): date to get the contents after. Format: dd/MM/YYYY
Gets contents from 01/01/1970 if not specified. Defaults to None.
to_date (str): date to get the contents before. Format: dd/MM/YYYY
Gets contents till current day if not specified. Defaults to None.
Returns:
list - list of all databases
dict - database names along with details like backup created timen
and database version
Raises:
SDKException:
if response is empty
if response is not success
"""
if from_date and (from_date != '01/01/1970' and from_date != '1/1/1970'):
temp = from_date.split('/')
if (len(temp) == 3 and
0 < int(temp[0]) < 32 and
0 < int(temp[1]) < 13 and
int(temp[2]) > 1969 and
(re.search(r'\d\d/\d\d/\d\d\d\d', from_date) or
re.search(r'\d/\d/\d\d\d\d', from_date))):
from_date = int(time.mktime(time.strptime(from_date, '%d/%m/%Y')))
else:
raise SDKException('Instance', '103')
else:
from_date = 0
if to_date and (to_date != '01/01/1970' and to_date != '1/1/1970'):
temp = to_date.split('/')
if (len(temp) == 3 and
0 < int(temp[0]) < 32 and
0 < int(temp[1]) < 13 and
int(temp[2]) > 1969 and
(re.search(r'\d\d/\d\d/\d\d\d\d', to_date) or
re.search(r'\d/\d/\d\d\d\d', to_date))):
today = time.strftime('%d/%m/%Y')
if today == to_date:
to_date = int(time.time())
else:
to_date = int(time.mktime(time.strptime(to_date, '%d/%m/%Y')))
else:
raise SDKException('Instance', '103')
else:
to_date = int(time.time())
browse_request = self._commcell_object._services['INSTANCE_BROWSE'] % (
self._agent_object._client_object.client_id, "SQL", self.instance_id
)
browse_request += '?fromTime={0}&toTime={1}'.format(from_date, to_date)
return self._process_browse_request(browse_request)
def get_recovery_points(self):
"""
lists all the recovery points.
returns:
object (list) - list of all the recovery points and clones
"""
flag, response = self._commcell_object._cvpysdk_object.make_request(
'GET', self._commcell_object._services["SQL_CLONES"], None
)
if flag:
response_json = response.json()
if "rpObjectList" in response_json:
return response_json["total"], response_json["rpObjectList"]
return 0, None
raise SDKException('Response', '102', "failed to get recovery points")
def _recoverypoint_request_json(self,
dbname,
expire_days=1,
recovery_point_name=None,
point_in_time=0,
destination_instance=None,
snap=False
):
"""
creates and returns a request json for the recovery point creation
Args:
dbname (str) -- database to be restored
expire_days (int) -- days for which the database will be restored
default 1,. 1 day
recovery_point_name (str) -- name of the recovery point to be created
default None. creates a db with db_name + <timestamp>
point_in_time (timestamp) -- unix time for the point in time recovery point creation
default 0. performs restore to last backup
destination_instance (str) -- name of the destination instance in which recovery point is to be
created.
default None. creates in the same instance
snap (bool) -- If the recovery point to be created is for snap setup
default False
returns:
request_json (Dict) -- request json for create recovery points
"""
if recovery_point_name is None:
timestamp = datetime.datetime.timestamp(datetime.datetime.now())
recovery_point_name = dbname + str(int(timestamp))
instance = self
if destination_instance != self.instance_name:
instance = SQLServerInstance(self._agent_object, destination_instance)
# fetching db details
flag, response = self._commcell_object._cvpysdk_object.make_request(
'GET', self._commcell_object._services["SQL_DATABASES"] % dbname, None
)
if flag:
response = response.json()
db_id = response["SqlDatabase"][0]["dbId"]
else:
raise SDKException('Response', 102, "failed to fetch db details")
# fetching full database details
flag, response = self._commcell_object._cvpysdk_object.make_request(
'GET', self._commcell_object._services["SQL_DATABASE_DETAILS"] %(self.instance_id, db_id), None
)
if flag:
response = response.json()
db_details = response["SqlDatabase"][0]
else:
raise SDKException('Response', 102, "failed to fetch db details")
fullbackup_job = db_details["fBkpJob"]
if fullbackup_job is None:
raise Exception("failed to get last full backup job details")
job = self._commcell_object.job_controller.get(fullbackup_job)
# retrieving the physical paths and logical file names
restore_options = self._get_sql_restore_options([dbname])
physical_files = []
logical_files = []
for files in restore_options["sqlDbdeviceItem"]:
physical_files.append(files["fileName"])
logical_files.append(files["logicalFileName"])
request_json = {
"opType": 0,
"session": {},
"queries": [
{
"type": 0,
"queryId": "0"
}
],
"mode": {
"mode": 3
},
"advOptions": {
"copyPrecedence": 0,
"advConfig": {
"extendedConfig": {
"browseAdvConfigLiveBrowse": {
"useISCSIMount": False
}
},
"applicationMining": {
"appType": 81,
"agentVersion": 0,
"isApplicationMiningReq": True,
"browseInitReq": {
"database": dbname,
"bCreateRecoveryPoint": True,
"destDatabase": recovery_point_name,
"appMinType": 2 if not snap else 0,
"expireDays": expire_days,
"instance": {
"clientId": instance.properties["instance"]["clientId"],
"instanceName": instance.instance_name,
"instanceId": int(instance.instance_id),
"applicationId": 81
},
"miningJobs": [fullbackup_job],
"client": {
"clientId": self.properties["instance"]["clientId"]
},
"phyfileRename": physical_files,
"logfileRename": logical_files,
}
}
}
},
"ma": {
"clientId": self.properties["instance"]["clientId"]
},
"options": {
"instantSend": True,
"skipIndexRestore": False
},
"entity": {
"drivePoolId": 0,
"subclientId": job.details["jobDetail"]["generalInfo"]["subclient"]["subclientId"],
"applicationId": 81,
"libraryId": job.details["jobDetail"]["generalInfo"]["mediaLibrary"]["libraryId"],
"backupsetId": job.details["jobDetail"]["generalInfo"]["subclient"]["backupsetId"],
"instanceId": int(self.instance_id),
"clientId": self.properties["instance"]["clientId"]
},
"timeRange": {
"fromTime": 0,
"toTime": point_in_time
}
}
return request_json
def _process_recovery_point_request(self, request_json):
"""
process the create recovery job browse request
Args:
request_json (dict): JSON request to run for the API
Returns:
object (Job) - instance of the Job class for this restore job
recovery point Id (int) : id to uniquely access the recovery point
dbname (str) - name of the db that is created.
Raises:
SDKException:
if restore job failed
if response is empty
if response is not success
"""
flag, response = self._commcell_object._cvpysdk_object.make_request(
'POST', self._commcell_object._services['BROWSE'], request_json
)
if flag:
response_json = response.json()
if response_json:
if "browseResponses" in response_json:
d = response_json['browseResponses'][0]["browseResult"]["advConfig"]["applicationMining"]["browseInitResp"]
try:
return Job(self._commcell_object, d["recoveryPointJobID"]), d["recoveryPointID"], d["edbPath"]
except Exception as msg:
# server code 102 response is empty or doesn't contain required parameters
raise SDKException('Instance', 102, msg)
elif "errorCode" in response.json():
error_message = response.json()['errorMessage']
o_str = 'create recovery point job failed\nError: "{0}"'.format(error_message)
raise SDKException('Instance', '102', o_str)
else:
raise SDKException('Instance', '102', 'Failed to run the restore job')
else:
raise SDKException('Response', '102')
else:
response_string = self._commcell_object._update_response_(response.text)
raise SDKException('Response', '101', response_string)
def create_recovery_point(self,
database_name,
new_database_name=None,
destination_instance=None,
expire_days=1,
snap=False
):
"""stats a granular restore or recovery point job and creates a on demand restore of a database
agrs:
database_name (str) : Name of the database for granular restore
new_database_name (str) : Name of the newly created database database
default: None creates a database with original dbname+ <TIMESTAMP>
destination_instance (str): Destination server(instance) name.
default None .creates a database in the same instance
expire_days (int) : days for which the database will be available
default 1 day.
snap (bool) : create recovery point for the snap setup
dafault False
returns:
object (Job) : instance of the Job class for this restore job
recovery point Id (int) : id to uniquely access the recovery point
recovery_point_name (str) : name of the database created
"""
# write a wrapper over this to allow creating more than one recovery points at a time is neccessary
if not isinstance(database_name, str):
raise SDKException('Instance', '101')
if destination_instance is None:
destination_instance = self.instance_name
else:
destination_instance = destination_instance.lower()
recoverypoint_request = self._recoverypoint_request_json(
database_name,
expire_days=expire_days,
recovery_point_name=new_database_name,
destination_instance=destination_instance,
snap=snap
)
return self._process_recovery_point_request(recoverypoint_request)
def table_level_restore(self,
src_db_name,
tables_to_restore,
destination_db_name,
rp_name,
include_child_tables,
include_parent_tables):
"""Starts a table level restore
Args:
src_db_name(str) : Name of the source database
tables_to_restore(list) : List of tables to restore
destination_db_name(str) : Destination database name
rp_name(str) : Name of recovery point
include_child_tables(bool) : Includes all child tables in restore.
include_parent_tables(bool) : Includes all parent tables in restore.
Returns:
job : Instance of Job class for this restore job"""
if not (isinstance(src_db_name, str)
or isinstance(tables_to_restore, list)
or isinstance(destination_db_name, str)):
raise SDKException('Instance', '101')
request_json = self._table_level_restore_request_json(
src_db_name,
tables_to_restore,
destination_db_name,
rp_name,
include_child_tables,
include_parent_tables
)
return self._process_restore_response(request_json)
def _table_level_restore_request_json(self,
src_db,
tables_to_restore,
destination_db,
rp_name,
include_child_tables,
include_parent_tables):
"""Creates and returns a request json for table level restore
Args:
src_db(str) : Name of the source database
tables_to_restore(list) : List of tables to restore
destination_db(str) : Destination database name
rp_name(str) : Name of the corresponding recovery point
include_child_tables(bool) : Includes all child tables in restore.
include_parent_tables(bool) : Includes all parent tables in restore.
Returns:
request_json(dict) : Request json for table level restore"""
client_name = self._agent_object._client_object.client_name
client_id = int(self._agent_object._client_object.client_id)
instance_name = self.instance_name
instance_id = int(self.instance_id)
source_item = []
for table in tables_to_restore:
source_item.append('/' + table)
request_json = {
"taskInfo": {
"associations": [
{
"subclientId": -1,
"copyId": 0,
"applicationId": 81,
"clientName": client_name,
"backupsetId": -1,
"instanceId": instance_id,
"clientId": client_id,
"instanceName": instance_name,
"_type_": 5,
"appName": self._agent_object.agent_name
}
],
"task": {
"ownerId": 1,
"taskType": 1,
"ownerName": "admin",
"sequenceNumber": 0,
"initiatedFrom": 1,
"policyType": 0,
"taskId": 0,
"taskFlags": {
"isEZOperation": False,
"disabled": False
}
},
"subTasks": [
{
"subTask": {
"subTaskType": 3,
"operationType": 1001
},
"options": {
"adminOpts": {
"contentIndexingOption": {
"subClientBasedAnalytics": False
}
},
"restoreOptions": {
"virtualServerRstOption": {
"isBlockLevelReplication": False
},
"sqlServerRstOption": {
"cloneEnv": False,
"ffgRestore": False,
"cloneResrvTimePeriod": 0,
"vSSBackup": False,
},
"dbArchiveRestoreOptions": {
"restoreAllDependentTables": include_child_tables,
"isTableLevelRestore": True,
"destDatabaseName": destination_db,
"restoreToSourceDatabase": True,
"restoreToHistoryDatabase": False,
"restoreAllParentTables": include_parent_tables,
"databaseName": {
"clientId": client_id,
"instanceName": instance_name,
"instanceId": instance_id,
"applicationId": 81
},
"sqlArchiveOptions": {
"sourceDBName": src_db,
"sourceDatabaseInfo": {
"dbName": rp_name,
"instance": {
"clientId": client_id,
"instanceName": instance_name,
"instanceId": instance_id,
"applicationId": 81
}
}
}
},
"browseOption": {
"listMedia": False,
"useExactIndex": False,
"noImage": True,
"commCellId": self._commcell_object.commcell_id,
"mediaOption": {
"useISCSIMount": False,
"mediaAgent": {
"mediaAgentId": 0,
"_type_": 11
},
"library": {
"_type_": 9,
"libraryId": 0
},
"copyPrecedence": {
"copyPrecedenceApplicable": False
},
"drivePool": {
"_type_": 47,
"drivePoolId": 0
}
},
"backupset": {
"backupsetId": -1,
"clientId": client_id
},
"timeRange": {}
},
"commonOptions": {
"clusterDBBackedup": False,
"restoreToDisk": False,
"isDBArchiveRestore": True,
"copyToObjectStore": False,
"onePassRestore": False,
"syncRestore": False
},
"destination": {
"destClient": {
"clientId": client_id,
"clientName": client_name
}
},
"fileOption": {
"sourceItem": source_item,
"browseFilters": [
"<?xml version='1.0' encoding='UTF-8'?>"
"<databrowse_Query type=\"0\" queryId=\"0\" />"
]
},
"dbDataMaskingOptions": {
"isStandalone": False
}
},
"commonOpts": {
"notifyUserOnJobCompletion": False,
"perfJobOpts": {
"rstPerfJobOpts": {
"mediaReadSpeed": False,
"pipelineTransmittingSpeed": False
}
}
}
}
}
]
}
}
return request_json
def restore(
self,
content_to_restore,
drop_connections_to_databse=False,
overwrite=True,
restore_path=None,
to_time=None,
sql_restore_type=SQLDefines.DATABASE_RESTORE,
sql_recover_type=SQLDefines.STATE_RECOVER,
undo_path=None,
restricted_user=None,
destination_instance=None
):
"""Restores the databases specified in the input paths list.
Args:
content_to_restore (list): List of databases to restore.
drop_connections_to_databse (bool): Drop connections to database. Defaults to False.
overwrite (bool): Unconditional overwrite files during restore. Defaults to True.
restore_path (str): Existing path on disk to restore. Defaults to None.
to_time (str): Restore to time. Defaults to None.
sql_recover_type (str): Type of sql recovery state. (STATE_RECOVER, STATE_NORECOVER, STATE_STANDBY)
Defaults to STATE_RECOVER.
sql_restore_type (str): Type of sql restore state. (DATABASE_RESTORE, STEP_RESTORE, RECOVER_ONLY)
Defaults to DATABASE_RESTORE.
undo_path (str): File path for undo path for sql standby restores. Defaults to None.
restricted_user (bool): Restore database in restricted user mode. Defaults to None.
destination_instance (str): Destination instance to restore too. Defaults to None.
Returns:
object - instance of the Job class for this restore job
Raises:
SDKException:
if content_to_restore is not a list
if response is empty
if response is not success
"""
if not isinstance(content_to_restore, list):
raise SDKException('Instance', '101')
if destination_instance is not None:
destination_instance = destination_instance.lower()
request_json = self._restore_request_json(
content_to_restore,
drop_connections_to_databse=drop_connections_to_databse,
overwrite=overwrite,
restore_path=restore_path,
to_time=to_time,
sql_restore_type=sql_restore_type,
sql_recover_type=sql_recover_type,
undo_path=undo_path,
restricted_user=restricted_user,
destination_instance=destination_instance
)
return self._process_restore_response(request_json)
def restore_to_destination_server(
self,
content_to_restore,
destination_server,
drop_connections_to_databse=False,
overwrite=True,
restore_path=None):
"""Restores the databases specified in the input paths list.
Args:
content_to_restore (list): List of databases to restore.
destination_server (str): Destination server(instance) name.
drop_connections_to_databse (bool): Drop connections to database. Defaults to False.
overwrite (bool): Unconditional overwrite files during restore. Defaults to True.
restore_path (str): Existing path on disk to restore. Default to None.
Returns:
object - instance of the Job class for this restore job
Raises:
SDKException:
if content_to_restore is not a list
if response is empty
if response is not success
"""
if not isinstance(content_to_restore, list):
raise SDKException('Instance', '101')
request_json = self._restore_request_json(
content_to_restore,
drop_connections_to_databse=drop_connections_to_databse,
overwrite=overwrite,
restore_path=restore_path,
destination_instance=destination_server
)
return self._process_restore_response(request_json)
@property
def mssql_instance_prop(self):
""" getter for sql server instance properties """
return self._mssql_instance_prop
@mssql_instance_prop.setter
def mssql_instance_prop(self, value):
"""Setter for SQL server instance properties
Args:
value (list) -- list of the category and properties to update on the instance
Returns:
list - list of the appropriate JSON for an agent to send to the POST Instance API
"""
category, prop = value
self._set_instance_properties(category, prop)
def vss_option(self, value):
"""Enables or disables VSS option on SQL instance
Args:
value (bool) -- Boolean value whether to set VSS option on or off
"""
request_json = {
"useVss": value
}
self._set_instance_properties("_mssql_instance_prop", request_json)
def vdi_timeout(self, value):
"""Sets the SQL VDI timeout value on SQL instance
Args:
value (int) -- value of vdi timeout for sql vdi operations
"""
request_json = {
"vDITimeOut": value
}
self._set_instance_properties("_mssql_instance_prop", request_json)
def impersonation(self, enable, credentials=None):
"""Sets impersonation on SQL instance with local system account or provided credentials.
Args:
enable (bool) -- boolean value whether to set impersonation
credentials (str, optional) -- credentials to set for impersonation.
Defaults to local system account if enabled is True and credential name not provided.
"""
if enable and credentials is None:
impersonate_json = {
"overrideHigherLevelSettings": {
"overrideGlobalAuthentication": True,
"useLocalSystemAccount": True
}
}
elif enable and credentials is not None:
impersonate_json = {
"overrideHigherLevelSettings": {
"overrideGlobalAuthentication": True,
"useLocalSystemAccount": False
},
"MSSQLCredentialinfo": {
"credentialName": credentials
}
}
else:
impersonate_json = {
"overrideHigherLevelSettings": {
"overrideGlobalAuthentication": True,
"useLocalSystemAccount": False
}
}
self._set_instance_properties("_mssql_instance_prop", impersonate_json)
def _get_ag_groups(self):
"""Gets available Availability Groups from the primary replica and returns it.
Returns:
dict - dictionary consisting of the sql destination server options
Raises:
SDKException: if given AG group name does not exist for instance
"""
instance_id = int(self.instance_id)
client_id = int(self.properties['instance']['clientId'])
webservice = self._commcell_object._services['SQL_AG_GROUPS']
flag, response = self._commcell_object._cvpysdk_object.make_request(
"GET", webservice %(client_id, instance_id)
)
if flag:
if response.json():
if 'SQLAvailabilityGroupList' in response.json():
return response.json()['SQLAvailabilityGroupList']
else:
raise SDKException('Response', '102')
else:
raise SDKException('Instance', '102', 'No Availability Groups exist for given primary replica '
'or SQL services are down on target server.')
def _get_ag_group_replicas(self, ag_group_name):
"""Gets replicas list from the Availability Group and returns it.
Args:
ag_group_name (str) -- name of the Availability Group
Returns:
dict - dictionary consisting of the replicas of the SQL AG group
Raises:
SDKException: if no replicas exist for given AG group
"""
instance_id = int(self.instance_id)
client_id = int(self.properties['instance']['clientId'])
webservice = self._commcell_object._services['SQL_AG_GROUP_REPLICAS']
flag, response = self._commcell_object._cvpysdk_object.make_request(
"GET", webservice %(client_id, instance_id, ag_group_name)
)
if flag:
if response.json():
if 'SQLAvailabilityReplicasList' in response.json():
return response.json()
else:
raise SDKException('Instance', '102', 'No replicas exist for given Availability Group '
'or SQL services are down on target server.')
else:
raise SDKException('Response', '102')
def create_sql_ag(self, client_name, ag_group_name, credentials=None):
"""Creates a new SQL Availability Group client and instance.
Args:
client_name (str) -- name to use for Availability Group client
ag_group_name (str) -- name of the Availability Group to create
credentials (str, optional) -- name of credentials to use as impersonation
Default is no impersonation if credentials name is not provided.
Returns:
object - instance of the Instance class for the newly created Availability Group
Raises:
SDKException:
if Availability Group for given primary replica does not exist
if Availability Group client/instance fails to be created.
if Credentials for impersonation does not exist
"""
# If credentials passed, verify it exists
if credentials:
if not credentials in self._commcell_object.credentials.all_credentials:
raise SDKException(
'Credential', '102', 'Credential name provided does not exist in the commcell.'
)
# Get the available AG groups configured on SQL Instance
ag_groups_resp = self._get_ag_groups()
# Verify the provided AG group exists from available AG groups on primary replica
if not any(ag['name'] == ag_group_name for ag in ag_groups_resp):
raise SDKException(
'Instance', '102', 'Availability Group with provided name does not exist for given replica.'
)
for ag_group in ag_groups_resp:
if ag_group['name'].lower() == ag_group_name.lower():
ag_group_endpointURL = ag_group['endpointURL']
ag_group_backupPref = ag_group['backupPreference']
ag_primary_replica_server = ag_group['primaryReplicaServerName']
ag_group_listener_list = []
if 'SQLAvailabilityGroupListenerList' in ag_group:
for listener in ag_group['SQLAvailabilityGroupListenerList']:
listener_details = {
'availabilityGroupListenerName': listener['availabilityGroupListenerName']
}
ag_group_listener_list.append(listener_details)
# Get the replicas from the provided AG group
ag_group_replicas_resp = self._get_ag_group_replicas(ag_group_name)
request_json = {
"App_CreatePseudoClientRequest": {
"clientInfo": {
"clientType": 20,
"mssqlagClientProperties": {
"SQLServerInstance": {
"clientId": int(self.properties['instance']['clientId']),
"instanceId": int(self.instance_id)
},
"availabilityGroup": {
"name": ag_group_name,
"primaryReplicaServerName": ag_primary_replica_server,
"backupPreference": ag_group_backupPref,
"endpointURL": ag_group_endpointURL
},
"SQLAvailabilityReplicasList": ag_group_replicas_resp,
},
},
"entity": {
"clientName": client_name
}
}
}
if ag_group_listener_list:
request_json['App_CreatePseudoClientRequest']['clientInfo']['mssqlagClientProperties']\
['availabilityGroup']['SQLAvailabilityGroupListenerList'] = ag_group_listener_list
webservice = self._commcell_object._services['EXECUTE_QCOMMAND']
flag, response = self._cvpysdk_object.make_request(
'POST', webservice, request_json)
if flag:
if response.json():
if 'response' in response.json():
error_code = response.json()['response']['errorCode']
if error_code != 0:
error_string = response.json()['response']['errorString']
o_str = 'Failed to create client\nError: "{0}"'.format(error_string)
raise SDKException('Client', '102', o_str)
else:
self._commcell_object.refresh()
# Get newly created AG instance
ag_client = self._commcell_object.clients.get(
response.json()['response']['entity']['clientName']
)
agent = ag_client.agents.get(self._agent_object.agent_name)
if ag_group_listener_list:
ag_instance_name = ag_group_listener_list[0]['availabilityGroupListenerName'] \
+ '/' + ag_group_name
else:
ag_instance_name = ag_group_name
ag_instance = agent.instances.get(ag_instance_name)
if credentials is not None:
ag_instance.impersonation(True, credentials)
return ag_instance
elif 'errorMessage' in response.json():
error_string = response.json()['errorMessage']
o_str = 'Failed to create client\nError: "{0}"'.format(error_string)
raise SDKException('Client', '102', o_str)
else:
raise SDKException('Response', '102')
else:
raise SDKException('Response', '102')
else:
raise SDKException('Response', '101', self._update_response_(response.text))
Classes
class SQLServerInstance (agent_object, instance_name, instance_id=None)
-
Derived class from Instance Base class, representing a SQL Server instance, and to perform operations on that Instance.
Initialise the instance object.
Args
agent_object (object) – instance of the Agent class
instance_name (str) – name of the instance
instance_id (str) – id of the instance default: None
Returns
object - instance of the Instance class
Expand source code Browse git
class SQLServerInstance(Instance): """Derived class from Instance Base class, representing a SQL Server instance, and to perform operations on that Instance.""" def _get_instance_properties(self): """Gets the properties of this instance. Raises: SDKException: if response is empty if response is not success """ super(SQLServerInstance, self)._get_instance_properties() self._ag_group_name = None self._ag_primary_replica = None self._ag_replicas_list = [] self._ag_group_listener_list = [] self._mssql_instance_prop = self._properties.get('mssqlInstance', {}) flag, response = self._commcell_object._cvpysdk_object.make_request( 'GET', self._commcell_object._services['INSTANCE'] %self._instance_id + "?propertyLevel=20" ) if flag: if response.json(): self._mssql_instance_prop = response.json()['instanceProperties'][0]['mssqlInstance'] if 'agProperties' in self._mssql_instance_prop: self._ag_group_name = self.mssql_instance_prop.get( 'agProperties', {}).get('availabilityGroup', {}).get('name') self._ag_primary_replica = self.mssql_instance_prop.get( 'agProperties', {}).get('availabilityGroup', {}).get('primaryReplicaServerName') listener_list_tmp = [] listener_list = self.mssql_instance_prop.get( 'agProperties', {}).get('availabilityGroup', {}).get('SQLAvailabilityGroupListenerList', {}) for listener in listener_list: listener_list_tmp.append(listener['availabilityGroupListenerName']) self._ag_listener_list = listener_list_tmp replica_list_tmp = [] replica_list = self.mssql_instance_prop.get( 'agProperties', {}).get('SQLAvailabilityReplicasList', {}) if replica_list: for replica in replica_list['SQLAvailabilityReplicasList']: replica_dict = { "serverName" : replica['name'], "clientId" : replica['replicaClient']['clientId'], "clientName": replica['replicaClient']['clientName'] } replica_list_tmp.append(replica_dict) self._ag_replicas_list = replica_list_tmp def _get_instance_properties_json(self): """get the all instance related properties of this instance. Returns: dict - all subclient properties put inside a dict """ instance_json = { "instanceProperties": { "instance": self._instance, "instanceActivityControl": self._instanceActivityControl, "mssqlInstance": self._mssql_instance_prop, "contentOperationType": 1 } } return instance_json @property def ag_group_name(self): """Returns the Availability Group Name""" return self._ag_group_name @property def ag_primary_replica(self): """Returns the Availability Group Primary Replica""" return self._ag_primary_replica @property def ag_replicas_list(self): """Returns the Availability Group Replicas List""" return self._ag_replicas_list @property def ag_listener_list(self): """Returns the Availability Group Listener List""" return self._ag_listener_list def _restore_request_json( self, content_to_restore, restore_path=None, drop_connections_to_databse=False, overwrite=True, destination_instance=None, to_time=None, sql_restore_type=SQLDefines.DATABASE_RESTORE, sql_recover_type=SQLDefines.STATE_RECOVER, undo_path=None, restricted_user=None ): """Returns the JSON request to pass to the API as per the options selected by the user. Args: content_to_restore (list): databases list to restore restore_path (list, optional): list of dicts for restore paths of database files drop_connections_to_databse (bool, optional): drop connections to database during restore overwrite (bool, optional): overwrite database on restore destination_instance (str): restore databases to this sql instance to_time (str, optional): restore to time sql_restore_type (str, optional): type of sql restore state (DATABASE_RESTORE, STEP_RESTORE, RECOVER_ONLY) sql_recover_type (str, optional): type of sql restore state (STATE_RECOVER, STATE_NORECOVER, STATE_STANDBY) undo_path (str, optional): file path for undo path for sql server standby restore restricted_user (bool, optional): Restore database in restricted user mode Returns: dict - JSON request to pass to the API """ self._get_sql_restore_options(content_to_restore) if destination_instance is None: destination_instance = (self.instance_name).lower() if destination_instance not in self.destination_instances_dict: raise SDKException( 'Instance', '102', 'SQL Instance [{0}] not suitable for restore destination or does not exist.' .format(destination_instance) ) destination_client_id = int( self.destination_instances_dict[destination_instance]['clientId'] ) destination_instance_id = int( self.destination_instances_dict[destination_instance]['instanceId'] ) request_json = { "taskInfo": { "associations": [{ "clientName": self._agent_object._client_object.client_name, "appName": self._agent_object.agent_name, "instanceName": self.instance_name }], "task": { "initiatedFrom": 1, "taskType": 1 }, "subTasks": [{ "subTask": { "subTaskType": 3, "operationType": 1001 }, "options": { "restoreOptions": { "sqlServerRstOption": { "sqlRecoverType": sql_recover_type, "dropConnectionsToDatabase": drop_connections_to_databse, "overWrite": overwrite, "sqlRestoreType": sql_restore_type, "database": content_to_restore, "restoreSource": content_to_restore }, "commonOptions": { }, "destination": { "destinationInstance": { "clientId": destination_client_id, "instanceName": destination_instance, "instanceId": destination_instance_id }, "destClient": { "clientId": destination_client_id } } } } }] } } if sql_recover_type == SQLDefines.STATE_STANDBY: if undo_path is not None: undo_path_dict = { "fileOption": { "mapFiles": { "renameFilesSuffix": undo_path } } } request_json['taskInfo']['subTasks'][0]['options']['restoreOptions'].update(undo_path_dict) else: raise SDKException('Instance', '102', 'Failed to set Undo Path for Standby Restore.') if restore_path is not None: restore_path_dict = { "device": restore_path } request_json['taskInfo']['subTasks'][0]['options']['restoreOptions'][ 'sqlServerRstOption'].update(restore_path_dict) if restricted_user is not None: restricted_user_dict = { "dbOnly": restricted_user } request_json['taskInfo']['subTasks'][0]['options']['restoreOptions'][ 'sqlServerRstOption'].update(restricted_user_dict) if to_time is not None: to_time_dict = { "browseOption": { "timeRange": { "toTimeValue": to_time } } } request_json['taskInfo']['subTasks'][0]['options']['restoreOptions'].update(to_time_dict) return request_json def _process_restore_response(self, request_json): """Runs the CreateTask API with the request JSON provided for Restore, and returns the contents after parsing the response. Args: request_json (dict): JSON request to run for the API Returns: object - instance of the Job class for this restore job Raises: SDKException: if restore job failed if response is empty if response is not success """ flag, response = self._commcell_object._cvpysdk_object.make_request( 'POST', self._commcell_object._services['RESTORE'], request_json ) if flag: if response.json(): if "jobIds" in response.json(): time.sleep(1) return Job(self._commcell_object, response.json()['jobIds'][0]) elif "errorCode" in response.json(): error_message = response.json()['errorMessage'] o_str = 'Restore job failed\nError: "{0}"'.format(error_message) raise SDKException('Instance', '102', o_str) else: raise SDKException('Instance', '102', 'Failed to run the restore job') else: raise SDKException('Response', '102') else: response_string = self._commcell_object._update_response_(response.text) raise SDKException('Response', '101', response_string) def _get_sql_restore_options(self, content_to_restore): """Runs the SQL/Restoreoptions API with the request JSON provided, and returns the contents after parsing the response. Args: content_to_restore (list): Databases list to restore Returns: dict - dictionary consisting of the sql destination server options Raises: SDKException: if failed to get SQL instances if no instance exits on commcell if response is empty if response is not success """ contents_dict = [] for content in content_to_restore: database_dict = { "databaseName": content } contents_dict.append(database_dict) request_json = { "restoreDbType": 0, "sourceInstanceId": int(self.instance_id), "selectedDatabases": contents_dict } webservice = self._commcell_object._services['SQL_RESTORE_OPTIONS'] flag, response = self._commcell_object._cvpysdk_object.make_request( "POST", webservice, request_json ) self.destination_instances_dict = {} if flag: if response.json(): if 'sqlDestinationInstances' in response.json(): for instance in response.json()['sqlDestinationInstances']: instances_dict = { instance['genericEntity']['instanceName'].lower(): { "instanceId": int(instance['genericEntity']['instanceId']), "clientId": int(instance['genericEntity']['clientId']) } } self.destination_instances_dict.update(instances_dict) elif 'error' in response.json(): if 'errorMessage' in response.json()['error']: error_message = response.json()['error']['errorMessage'] raise SDKException('Instance', '102', error_message) else: raise SDKException('Instance', '102', 'No Instance exists on commcell') else: raise SDKException('Response', '102') else: response_string = self._commcell_object._update_response_(response.text) raise SDKException('Response', '101', response_string) return response.json() def _run_backup(self, subclient_name, return_list): """Triggers full backup job for the given subclient, and appends its Job object to list The SDKExcpetion class instance is appended to the list, if any exception is raised while running the backup job for the Subclient. Args: subclient_name (str): Name of the subclient to trigger the backup for return_list (list): List to append the job object to """ try: job = self.subclients.get(subclient_name).backup('Full') if job: return_list.append(job) except SDKException as excp: return_list.append(excp) def _process_browse_request(self, browse_request, get_full_details=False): """Runs the SQL Instance Browse API with the request JSON provided for the operation specified, and returns the contents after parsing the response. Args: browse_request (dict): JSON request to be sent to Server Returns: list - list of all databases dict - database names along with details like backup created time and database version Raises: SDKException: if response is empty if response is not success """ flag, response = self._commcell_object._cvpysdk_object.make_request("GET", browse_request) full_result = [] databases = [] if flag: if response.json(): if 'sqlDatabase' in response.json(): # returns whole dict if requested if get_full_details: return response.json()["sqlDatabase"] for database in response.json()['sqlDatabase']: database_name = database['databaseName'] created_time = datetime.datetime.fromtimestamp( int(database['createdTime']) ).strftime('%d-%m-%Y %H:%M:%S') version = database['version'] temp = { database_name: [created_time, version] } databases.append(database_name) full_result.append(temp) return databases, full_result else: raise SDKException('Response', '102') else: response_string = self._commcell_object._update_response_(response.text) raise SDKException('Response', '101', response_string) def backup(self): """Run full backup job for all subclients in this instance. Returns: list - list containing the job objects for the full backup jobs started for the subclients in the backupset """ return_list = [] thread_list = [] all_subclients = self.subclients._subclients if all_subclients: for subclient in all_subclients: thread = threading.Thread( target=self._run_backup, args=(subclient, return_list) ) thread_list.append(thread) thread.start() for thread in thread_list: thread.join() return return_list def browse(self, get_full_details=False): """Gets the list of the backed up databases for this instance. Args: get_full_details (bool) - if True returns dict with all databases with last full backupjob details, default false Returns: list - list of all databases dict - database names along with details like backup created time and database version Raises: SDKException: if response is empty if response is not success """ browse_request = self._commcell_object._services['INSTANCE_BROWSE'] % ( self._agent_object._client_object.client_id, "SQL", self.instance_id ) return self._process_browse_request(browse_request, get_full_details=get_full_details) def browse_in_time(self, from_date=None, to_date=None): """Gets the list of the backed up databases for this instance in the given time frame. Args: from_date (str): date to get the contents after. Format: dd/MM/YYYY Gets contents from 01/01/1970 if not specified. Defaults to None. to_date (str): date to get the contents before. Format: dd/MM/YYYY Gets contents till current day if not specified. Defaults to None. Returns: list - list of all databases dict - database names along with details like backup created timen and database version Raises: SDKException: if response is empty if response is not success """ if from_date and (from_date != '01/01/1970' and from_date != '1/1/1970'): temp = from_date.split('/') if (len(temp) == 3 and 0 < int(temp[0]) < 32 and 0 < int(temp[1]) < 13 and int(temp[2]) > 1969 and (re.search(r'\d\d/\d\d/\d\d\d\d', from_date) or re.search(r'\d/\d/\d\d\d\d', from_date))): from_date = int(time.mktime(time.strptime(from_date, '%d/%m/%Y'))) else: raise SDKException('Instance', '103') else: from_date = 0 if to_date and (to_date != '01/01/1970' and to_date != '1/1/1970'): temp = to_date.split('/') if (len(temp) == 3 and 0 < int(temp[0]) < 32 and 0 < int(temp[1]) < 13 and int(temp[2]) > 1969 and (re.search(r'\d\d/\d\d/\d\d\d\d', to_date) or re.search(r'\d/\d/\d\d\d\d', to_date))): today = time.strftime('%d/%m/%Y') if today == to_date: to_date = int(time.time()) else: to_date = int(time.mktime(time.strptime(to_date, '%d/%m/%Y'))) else: raise SDKException('Instance', '103') else: to_date = int(time.time()) browse_request = self._commcell_object._services['INSTANCE_BROWSE'] % ( self._agent_object._client_object.client_id, "SQL", self.instance_id ) browse_request += '?fromTime={0}&toTime={1}'.format(from_date, to_date) return self._process_browse_request(browse_request) def get_recovery_points(self): """ lists all the recovery points. returns: object (list) - list of all the recovery points and clones """ flag, response = self._commcell_object._cvpysdk_object.make_request( 'GET', self._commcell_object._services["SQL_CLONES"], None ) if flag: response_json = response.json() if "rpObjectList" in response_json: return response_json["total"], response_json["rpObjectList"] return 0, None raise SDKException('Response', '102', "failed to get recovery points") def _recoverypoint_request_json(self, dbname, expire_days=1, recovery_point_name=None, point_in_time=0, destination_instance=None, snap=False ): """ creates and returns a request json for the recovery point creation Args: dbname (str) -- database to be restored expire_days (int) -- days for which the database will be restored default 1,. 1 day recovery_point_name (str) -- name of the recovery point to be created default None. creates a db with db_name + <timestamp> point_in_time (timestamp) -- unix time for the point in time recovery point creation default 0. performs restore to last backup destination_instance (str) -- name of the destination instance in which recovery point is to be created. default None. creates in the same instance snap (bool) -- If the recovery point to be created is for snap setup default False returns: request_json (Dict) -- request json for create recovery points """ if recovery_point_name is None: timestamp = datetime.datetime.timestamp(datetime.datetime.now()) recovery_point_name = dbname + str(int(timestamp)) instance = self if destination_instance != self.instance_name: instance = SQLServerInstance(self._agent_object, destination_instance) # fetching db details flag, response = self._commcell_object._cvpysdk_object.make_request( 'GET', self._commcell_object._services["SQL_DATABASES"] % dbname, None ) if flag: response = response.json() db_id = response["SqlDatabase"][0]["dbId"] else: raise SDKException('Response', 102, "failed to fetch db details") # fetching full database details flag, response = self._commcell_object._cvpysdk_object.make_request( 'GET', self._commcell_object._services["SQL_DATABASE_DETAILS"] %(self.instance_id, db_id), None ) if flag: response = response.json() db_details = response["SqlDatabase"][0] else: raise SDKException('Response', 102, "failed to fetch db details") fullbackup_job = db_details["fBkpJob"] if fullbackup_job is None: raise Exception("failed to get last full backup job details") job = self._commcell_object.job_controller.get(fullbackup_job) # retrieving the physical paths and logical file names restore_options = self._get_sql_restore_options([dbname]) physical_files = [] logical_files = [] for files in restore_options["sqlDbdeviceItem"]: physical_files.append(files["fileName"]) logical_files.append(files["logicalFileName"]) request_json = { "opType": 0, "session": {}, "queries": [ { "type": 0, "queryId": "0" } ], "mode": { "mode": 3 }, "advOptions": { "copyPrecedence": 0, "advConfig": { "extendedConfig": { "browseAdvConfigLiveBrowse": { "useISCSIMount": False } }, "applicationMining": { "appType": 81, "agentVersion": 0, "isApplicationMiningReq": True, "browseInitReq": { "database": dbname, "bCreateRecoveryPoint": True, "destDatabase": recovery_point_name, "appMinType": 2 if not snap else 0, "expireDays": expire_days, "instance": { "clientId": instance.properties["instance"]["clientId"], "instanceName": instance.instance_name, "instanceId": int(instance.instance_id), "applicationId": 81 }, "miningJobs": [fullbackup_job], "client": { "clientId": self.properties["instance"]["clientId"] }, "phyfileRename": physical_files, "logfileRename": logical_files, } } } }, "ma": { "clientId": self.properties["instance"]["clientId"] }, "options": { "instantSend": True, "skipIndexRestore": False }, "entity": { "drivePoolId": 0, "subclientId": job.details["jobDetail"]["generalInfo"]["subclient"]["subclientId"], "applicationId": 81, "libraryId": job.details["jobDetail"]["generalInfo"]["mediaLibrary"]["libraryId"], "backupsetId": job.details["jobDetail"]["generalInfo"]["subclient"]["backupsetId"], "instanceId": int(self.instance_id), "clientId": self.properties["instance"]["clientId"] }, "timeRange": { "fromTime": 0, "toTime": point_in_time } } return request_json def _process_recovery_point_request(self, request_json): """ process the create recovery job browse request Args: request_json (dict): JSON request to run for the API Returns: object (Job) - instance of the Job class for this restore job recovery point Id (int) : id to uniquely access the recovery point dbname (str) - name of the db that is created. Raises: SDKException: if restore job failed if response is empty if response is not success """ flag, response = self._commcell_object._cvpysdk_object.make_request( 'POST', self._commcell_object._services['BROWSE'], request_json ) if flag: response_json = response.json() if response_json: if "browseResponses" in response_json: d = response_json['browseResponses'][0]["browseResult"]["advConfig"]["applicationMining"]["browseInitResp"] try: return Job(self._commcell_object, d["recoveryPointJobID"]), d["recoveryPointID"], d["edbPath"] except Exception as msg: # server code 102 response is empty or doesn't contain required parameters raise SDKException('Instance', 102, msg) elif "errorCode" in response.json(): error_message = response.json()['errorMessage'] o_str = 'create recovery point job failed\nError: "{0}"'.format(error_message) raise SDKException('Instance', '102', o_str) else: raise SDKException('Instance', '102', 'Failed to run the restore job') else: raise SDKException('Response', '102') else: response_string = self._commcell_object._update_response_(response.text) raise SDKException('Response', '101', response_string) def create_recovery_point(self, database_name, new_database_name=None, destination_instance=None, expire_days=1, snap=False ): """stats a granular restore or recovery point job and creates a on demand restore of a database agrs: database_name (str) : Name of the database for granular restore new_database_name (str) : Name of the newly created database database default: None creates a database with original dbname+ <TIMESTAMP> destination_instance (str): Destination server(instance) name. default None .creates a database in the same instance expire_days (int) : days for which the database will be available default 1 day. snap (bool) : create recovery point for the snap setup dafault False returns: object (Job) : instance of the Job class for this restore job recovery point Id (int) : id to uniquely access the recovery point recovery_point_name (str) : name of the database created """ # write a wrapper over this to allow creating more than one recovery points at a time is neccessary if not isinstance(database_name, str): raise SDKException('Instance', '101') if destination_instance is None: destination_instance = self.instance_name else: destination_instance = destination_instance.lower() recoverypoint_request = self._recoverypoint_request_json( database_name, expire_days=expire_days, recovery_point_name=new_database_name, destination_instance=destination_instance, snap=snap ) return self._process_recovery_point_request(recoverypoint_request) def table_level_restore(self, src_db_name, tables_to_restore, destination_db_name, rp_name, include_child_tables, include_parent_tables): """Starts a table level restore Args: src_db_name(str) : Name of the source database tables_to_restore(list) : List of tables to restore destination_db_name(str) : Destination database name rp_name(str) : Name of recovery point include_child_tables(bool) : Includes all child tables in restore. include_parent_tables(bool) : Includes all parent tables in restore. Returns: job : Instance of Job class for this restore job""" if not (isinstance(src_db_name, str) or isinstance(tables_to_restore, list) or isinstance(destination_db_name, str)): raise SDKException('Instance', '101') request_json = self._table_level_restore_request_json( src_db_name, tables_to_restore, destination_db_name, rp_name, include_child_tables, include_parent_tables ) return self._process_restore_response(request_json) def _table_level_restore_request_json(self, src_db, tables_to_restore, destination_db, rp_name, include_child_tables, include_parent_tables): """Creates and returns a request json for table level restore Args: src_db(str) : Name of the source database tables_to_restore(list) : List of tables to restore destination_db(str) : Destination database name rp_name(str) : Name of the corresponding recovery point include_child_tables(bool) : Includes all child tables in restore. include_parent_tables(bool) : Includes all parent tables in restore. Returns: request_json(dict) : Request json for table level restore""" client_name = self._agent_object._client_object.client_name client_id = int(self._agent_object._client_object.client_id) instance_name = self.instance_name instance_id = int(self.instance_id) source_item = [] for table in tables_to_restore: source_item.append('/' + table) request_json = { "taskInfo": { "associations": [ { "subclientId": -1, "copyId": 0, "applicationId": 81, "clientName": client_name, "backupsetId": -1, "instanceId": instance_id, "clientId": client_id, "instanceName": instance_name, "_type_": 5, "appName": self._agent_object.agent_name } ], "task": { "ownerId": 1, "taskType": 1, "ownerName": "admin", "sequenceNumber": 0, "initiatedFrom": 1, "policyType": 0, "taskId": 0, "taskFlags": { "isEZOperation": False, "disabled": False } }, "subTasks": [ { "subTask": { "subTaskType": 3, "operationType": 1001 }, "options": { "adminOpts": { "contentIndexingOption": { "subClientBasedAnalytics": False } }, "restoreOptions": { "virtualServerRstOption": { "isBlockLevelReplication": False }, "sqlServerRstOption": { "cloneEnv": False, "ffgRestore": False, "cloneResrvTimePeriod": 0, "vSSBackup": False, }, "dbArchiveRestoreOptions": { "restoreAllDependentTables": include_child_tables, "isTableLevelRestore": True, "destDatabaseName": destination_db, "restoreToSourceDatabase": True, "restoreToHistoryDatabase": False, "restoreAllParentTables": include_parent_tables, "databaseName": { "clientId": client_id, "instanceName": instance_name, "instanceId": instance_id, "applicationId": 81 }, "sqlArchiveOptions": { "sourceDBName": src_db, "sourceDatabaseInfo": { "dbName": rp_name, "instance": { "clientId": client_id, "instanceName": instance_name, "instanceId": instance_id, "applicationId": 81 } } } }, "browseOption": { "listMedia": False, "useExactIndex": False, "noImage": True, "commCellId": self._commcell_object.commcell_id, "mediaOption": { "useISCSIMount": False, "mediaAgent": { "mediaAgentId": 0, "_type_": 11 }, "library": { "_type_": 9, "libraryId": 0 }, "copyPrecedence": { "copyPrecedenceApplicable": False }, "drivePool": { "_type_": 47, "drivePoolId": 0 } }, "backupset": { "backupsetId": -1, "clientId": client_id }, "timeRange": {} }, "commonOptions": { "clusterDBBackedup": False, "restoreToDisk": False, "isDBArchiveRestore": True, "copyToObjectStore": False, "onePassRestore": False, "syncRestore": False }, "destination": { "destClient": { "clientId": client_id, "clientName": client_name } }, "fileOption": { "sourceItem": source_item, "browseFilters": [ "<?xml version='1.0' encoding='UTF-8'?>" "<databrowse_Query type=\"0\" queryId=\"0\" />" ] }, "dbDataMaskingOptions": { "isStandalone": False } }, "commonOpts": { "notifyUserOnJobCompletion": False, "perfJobOpts": { "rstPerfJobOpts": { "mediaReadSpeed": False, "pipelineTransmittingSpeed": False } } } } } ] } } return request_json def restore( self, content_to_restore, drop_connections_to_databse=False, overwrite=True, restore_path=None, to_time=None, sql_restore_type=SQLDefines.DATABASE_RESTORE, sql_recover_type=SQLDefines.STATE_RECOVER, undo_path=None, restricted_user=None, destination_instance=None ): """Restores the databases specified in the input paths list. Args: content_to_restore (list): List of databases to restore. drop_connections_to_databse (bool): Drop connections to database. Defaults to False. overwrite (bool): Unconditional overwrite files during restore. Defaults to True. restore_path (str): Existing path on disk to restore. Defaults to None. to_time (str): Restore to time. Defaults to None. sql_recover_type (str): Type of sql recovery state. (STATE_RECOVER, STATE_NORECOVER, STATE_STANDBY) Defaults to STATE_RECOVER. sql_restore_type (str): Type of sql restore state. (DATABASE_RESTORE, STEP_RESTORE, RECOVER_ONLY) Defaults to DATABASE_RESTORE. undo_path (str): File path for undo path for sql standby restores. Defaults to None. restricted_user (bool): Restore database in restricted user mode. Defaults to None. destination_instance (str): Destination instance to restore too. Defaults to None. Returns: object - instance of the Job class for this restore job Raises: SDKException: if content_to_restore is not a list if response is empty if response is not success """ if not isinstance(content_to_restore, list): raise SDKException('Instance', '101') if destination_instance is not None: destination_instance = destination_instance.lower() request_json = self._restore_request_json( content_to_restore, drop_connections_to_databse=drop_connections_to_databse, overwrite=overwrite, restore_path=restore_path, to_time=to_time, sql_restore_type=sql_restore_type, sql_recover_type=sql_recover_type, undo_path=undo_path, restricted_user=restricted_user, destination_instance=destination_instance ) return self._process_restore_response(request_json) def restore_to_destination_server( self, content_to_restore, destination_server, drop_connections_to_databse=False, overwrite=True, restore_path=None): """Restores the databases specified in the input paths list. Args: content_to_restore (list): List of databases to restore. destination_server (str): Destination server(instance) name. drop_connections_to_databse (bool): Drop connections to database. Defaults to False. overwrite (bool): Unconditional overwrite files during restore. Defaults to True. restore_path (str): Existing path on disk to restore. Default to None. Returns: object - instance of the Job class for this restore job Raises: SDKException: if content_to_restore is not a list if response is empty if response is not success """ if not isinstance(content_to_restore, list): raise SDKException('Instance', '101') request_json = self._restore_request_json( content_to_restore, drop_connections_to_databse=drop_connections_to_databse, overwrite=overwrite, restore_path=restore_path, destination_instance=destination_server ) return self._process_restore_response(request_json) @property def mssql_instance_prop(self): """ getter for sql server instance properties """ return self._mssql_instance_prop @mssql_instance_prop.setter def mssql_instance_prop(self, value): """Setter for SQL server instance properties Args: value (list) -- list of the category and properties to update on the instance Returns: list - list of the appropriate JSON for an agent to send to the POST Instance API """ category, prop = value self._set_instance_properties(category, prop) def vss_option(self, value): """Enables or disables VSS option on SQL instance Args: value (bool) -- Boolean value whether to set VSS option on or off """ request_json = { "useVss": value } self._set_instance_properties("_mssql_instance_prop", request_json) def vdi_timeout(self, value): """Sets the SQL VDI timeout value on SQL instance Args: value (int) -- value of vdi timeout for sql vdi operations """ request_json = { "vDITimeOut": value } self._set_instance_properties("_mssql_instance_prop", request_json) def impersonation(self, enable, credentials=None): """Sets impersonation on SQL instance with local system account or provided credentials. Args: enable (bool) -- boolean value whether to set impersonation credentials (str, optional) -- credentials to set for impersonation. Defaults to local system account if enabled is True and credential name not provided. """ if enable and credentials is None: impersonate_json = { "overrideHigherLevelSettings": { "overrideGlobalAuthentication": True, "useLocalSystemAccount": True } } elif enable and credentials is not None: impersonate_json = { "overrideHigherLevelSettings": { "overrideGlobalAuthentication": True, "useLocalSystemAccount": False }, "MSSQLCredentialinfo": { "credentialName": credentials } } else: impersonate_json = { "overrideHigherLevelSettings": { "overrideGlobalAuthentication": True, "useLocalSystemAccount": False } } self._set_instance_properties("_mssql_instance_prop", impersonate_json) def _get_ag_groups(self): """Gets available Availability Groups from the primary replica and returns it. Returns: dict - dictionary consisting of the sql destination server options Raises: SDKException: if given AG group name does not exist for instance """ instance_id = int(self.instance_id) client_id = int(self.properties['instance']['clientId']) webservice = self._commcell_object._services['SQL_AG_GROUPS'] flag, response = self._commcell_object._cvpysdk_object.make_request( "GET", webservice %(client_id, instance_id) ) if flag: if response.json(): if 'SQLAvailabilityGroupList' in response.json(): return response.json()['SQLAvailabilityGroupList'] else: raise SDKException('Response', '102') else: raise SDKException('Instance', '102', 'No Availability Groups exist for given primary replica ' 'or SQL services are down on target server.') def _get_ag_group_replicas(self, ag_group_name): """Gets replicas list from the Availability Group and returns it. Args: ag_group_name (str) -- name of the Availability Group Returns: dict - dictionary consisting of the replicas of the SQL AG group Raises: SDKException: if no replicas exist for given AG group """ instance_id = int(self.instance_id) client_id = int(self.properties['instance']['clientId']) webservice = self._commcell_object._services['SQL_AG_GROUP_REPLICAS'] flag, response = self._commcell_object._cvpysdk_object.make_request( "GET", webservice %(client_id, instance_id, ag_group_name) ) if flag: if response.json(): if 'SQLAvailabilityReplicasList' in response.json(): return response.json() else: raise SDKException('Instance', '102', 'No replicas exist for given Availability Group ' 'or SQL services are down on target server.') else: raise SDKException('Response', '102') def create_sql_ag(self, client_name, ag_group_name, credentials=None): """Creates a new SQL Availability Group client and instance. Args: client_name (str) -- name to use for Availability Group client ag_group_name (str) -- name of the Availability Group to create credentials (str, optional) -- name of credentials to use as impersonation Default is no impersonation if credentials name is not provided. Returns: object - instance of the Instance class for the newly created Availability Group Raises: SDKException: if Availability Group for given primary replica does not exist if Availability Group client/instance fails to be created. if Credentials for impersonation does not exist """ # If credentials passed, verify it exists if credentials: if not credentials in self._commcell_object.credentials.all_credentials: raise SDKException( 'Credential', '102', 'Credential name provided does not exist in the commcell.' ) # Get the available AG groups configured on SQL Instance ag_groups_resp = self._get_ag_groups() # Verify the provided AG group exists from available AG groups on primary replica if not any(ag['name'] == ag_group_name for ag in ag_groups_resp): raise SDKException( 'Instance', '102', 'Availability Group with provided name does not exist for given replica.' ) for ag_group in ag_groups_resp: if ag_group['name'].lower() == ag_group_name.lower(): ag_group_endpointURL = ag_group['endpointURL'] ag_group_backupPref = ag_group['backupPreference'] ag_primary_replica_server = ag_group['primaryReplicaServerName'] ag_group_listener_list = [] if 'SQLAvailabilityGroupListenerList' in ag_group: for listener in ag_group['SQLAvailabilityGroupListenerList']: listener_details = { 'availabilityGroupListenerName': listener['availabilityGroupListenerName'] } ag_group_listener_list.append(listener_details) # Get the replicas from the provided AG group ag_group_replicas_resp = self._get_ag_group_replicas(ag_group_name) request_json = { "App_CreatePseudoClientRequest": { "clientInfo": { "clientType": 20, "mssqlagClientProperties": { "SQLServerInstance": { "clientId": int(self.properties['instance']['clientId']), "instanceId": int(self.instance_id) }, "availabilityGroup": { "name": ag_group_name, "primaryReplicaServerName": ag_primary_replica_server, "backupPreference": ag_group_backupPref, "endpointURL": ag_group_endpointURL }, "SQLAvailabilityReplicasList": ag_group_replicas_resp, }, }, "entity": { "clientName": client_name } } } if ag_group_listener_list: request_json['App_CreatePseudoClientRequest']['clientInfo']['mssqlagClientProperties']\ ['availabilityGroup']['SQLAvailabilityGroupListenerList'] = ag_group_listener_list webservice = self._commcell_object._services['EXECUTE_QCOMMAND'] flag, response = self._cvpysdk_object.make_request( 'POST', webservice, request_json) if flag: if response.json(): if 'response' in response.json(): error_code = response.json()['response']['errorCode'] if error_code != 0: error_string = response.json()['response']['errorString'] o_str = 'Failed to create client\nError: "{0}"'.format(error_string) raise SDKException('Client', '102', o_str) else: self._commcell_object.refresh() # Get newly created AG instance ag_client = self._commcell_object.clients.get( response.json()['response']['entity']['clientName'] ) agent = ag_client.agents.get(self._agent_object.agent_name) if ag_group_listener_list: ag_instance_name = ag_group_listener_list[0]['availabilityGroupListenerName'] \ + '/' + ag_group_name else: ag_instance_name = ag_group_name ag_instance = agent.instances.get(ag_instance_name) if credentials is not None: ag_instance.impersonation(True, credentials) return ag_instance elif 'errorMessage' in response.json(): error_string = response.json()['errorMessage'] o_str = 'Failed to create client\nError: "{0}"'.format(error_string) raise SDKException('Client', '102', o_str) else: raise SDKException('Response', '102') else: raise SDKException('Response', '102') else: raise SDKException('Response', '101', self._update_response_(response.text))
Ancestors
Instance variables
var ag_group_name
-
Returns the Availability Group Name
Expand source code Browse git
@property def ag_group_name(self): """Returns the Availability Group Name""" return self._ag_group_name
var ag_listener_list
-
Returns the Availability Group Listener List
Expand source code Browse git
@property def ag_listener_list(self): """Returns the Availability Group Listener List""" return self._ag_listener_list
var ag_primary_replica
-
Returns the Availability Group Primary Replica
Expand source code Browse git
@property def ag_primary_replica(self): """Returns the Availability Group Primary Replica""" return self._ag_primary_replica
var ag_replicas_list
-
Returns the Availability Group Replicas List
Expand source code Browse git
@property def ag_replicas_list(self): """Returns the Availability Group Replicas List""" return self._ag_replicas_list
var mssql_instance_prop
-
getter for sql server instance properties
Expand source code Browse git
@property def mssql_instance_prop(self): """ getter for sql server instance properties """ return self._mssql_instance_prop
Methods
def backup(self)
-
Run full backup job for all subclients in this instance.
Returns
list - list containing the job objects for the full backup jobs started for the subclients in the backupset
Expand source code Browse git
def backup(self): """Run full backup job for all subclients in this instance. Returns: list - list containing the job objects for the full backup jobs started for the subclients in the backupset """ return_list = [] thread_list = [] all_subclients = self.subclients._subclients if all_subclients: for subclient in all_subclients: thread = threading.Thread( target=self._run_backup, args=(subclient, return_list) ) thread_list.append(thread) thread.start() for thread in thread_list: thread.join() return return_list
def browse(self, get_full_details=False)
-
Gets the list of the backed up databases for this instance.
Args
get_full_details (bool) - if True returns dict with all databases with last full backupjob details, default false
Returns
list - list of all databases
dict - database names along with details like backup created time and database version
Raises
SDKException: if response is empty
if response is not success
Expand source code Browse git
def browse(self, get_full_details=False): """Gets the list of the backed up databases for this instance. Args: get_full_details (bool) - if True returns dict with all databases with last full backupjob details, default false Returns: list - list of all databases dict - database names along with details like backup created time and database version Raises: SDKException: if response is empty if response is not success """ browse_request = self._commcell_object._services['INSTANCE_BROWSE'] % ( self._agent_object._client_object.client_id, "SQL", self.instance_id ) return self._process_browse_request(browse_request, get_full_details=get_full_details)
def browse_in_time(self, from_date=None, to_date=None)
-
Gets the list of the backed up databases for this instance in the given time frame.
Args
from_date
:str
- date to get the contents after. Format: dd/MM/YYYY
Gets contents from 01/01/1970 if not specified. Defaults to None.
to_date
:str
- date to get the contents before. Format: dd/MM/YYYY
Gets contents till current day if not specified. Defaults to None.
Returns
list - list of all databases
dict - database names along with details like backup created timen and database version
Raises
SDKException: if response is empty
if response is not success
Expand source code Browse git
def browse_in_time(self, from_date=None, to_date=None): """Gets the list of the backed up databases for this instance in the given time frame. Args: from_date (str): date to get the contents after. Format: dd/MM/YYYY Gets contents from 01/01/1970 if not specified. Defaults to None. to_date (str): date to get the contents before. Format: dd/MM/YYYY Gets contents till current day if not specified. Defaults to None. Returns: list - list of all databases dict - database names along with details like backup created timen and database version Raises: SDKException: if response is empty if response is not success """ if from_date and (from_date != '01/01/1970' and from_date != '1/1/1970'): temp = from_date.split('/') if (len(temp) == 3 and 0 < int(temp[0]) < 32 and 0 < int(temp[1]) < 13 and int(temp[2]) > 1969 and (re.search(r'\d\d/\d\d/\d\d\d\d', from_date) or re.search(r'\d/\d/\d\d\d\d', from_date))): from_date = int(time.mktime(time.strptime(from_date, '%d/%m/%Y'))) else: raise SDKException('Instance', '103') else: from_date = 0 if to_date and (to_date != '01/01/1970' and to_date != '1/1/1970'): temp = to_date.split('/') if (len(temp) == 3 and 0 < int(temp[0]) < 32 and 0 < int(temp[1]) < 13 and int(temp[2]) > 1969 and (re.search(r'\d\d/\d\d/\d\d\d\d', to_date) or re.search(r'\d/\d/\d\d\d\d', to_date))): today = time.strftime('%d/%m/%Y') if today == to_date: to_date = int(time.time()) else: to_date = int(time.mktime(time.strptime(to_date, '%d/%m/%Y'))) else: raise SDKException('Instance', '103') else: to_date = int(time.time()) browse_request = self._commcell_object._services['INSTANCE_BROWSE'] % ( self._agent_object._client_object.client_id, "SQL", self.instance_id ) browse_request += '?fromTime={0}&toTime={1}'.format(from_date, to_date) return self._process_browse_request(browse_request)
def create_recovery_point(self, database_name, new_database_name=None, destination_instance=None, expire_days=1, snap=False)
-
stats a granular restore or recovery point job and creates a on demand restore of a database
agrs: database_name (str) : Name of the database for granular restore
new_database_name (str) : Name of the newly created database database default: None creates a database with original dbname+ <TIMESTAMP> destination_instance (str): Destination server(instance) name. default None .creates a database in the same instance expire_days (int) : days for which the database will be available default 1 day. snap (bool) : create recovery point for the snap setup dafault False
returns: object (Job) : instance of the Job class for this restore job
recovery point Id (int) : id to uniquely access the recovery point recovery_point_name (str) : name of the database created
Expand source code Browse git
def create_recovery_point(self, database_name, new_database_name=None, destination_instance=None, expire_days=1, snap=False ): """stats a granular restore or recovery point job and creates a on demand restore of a database agrs: database_name (str) : Name of the database for granular restore new_database_name (str) : Name of the newly created database database default: None creates a database with original dbname+ <TIMESTAMP> destination_instance (str): Destination server(instance) name. default None .creates a database in the same instance expire_days (int) : days for which the database will be available default 1 day. snap (bool) : create recovery point for the snap setup dafault False returns: object (Job) : instance of the Job class for this restore job recovery point Id (int) : id to uniquely access the recovery point recovery_point_name (str) : name of the database created """ # write a wrapper over this to allow creating more than one recovery points at a time is neccessary if not isinstance(database_name, str): raise SDKException('Instance', '101') if destination_instance is None: destination_instance = self.instance_name else: destination_instance = destination_instance.lower() recoverypoint_request = self._recoverypoint_request_json( database_name, expire_days=expire_days, recovery_point_name=new_database_name, destination_instance=destination_instance, snap=snap ) return self._process_recovery_point_request(recoverypoint_request)
def create_sql_ag(self, client_name, ag_group_name, credentials=None)
-
Creates a new SQL Availability Group client and instance.
Args
client_name (str) – name to use for Availability Group client
ag_group_name (str) – name of the Availability Group to create
credentials (str, optional) – name of credentials to use as impersonation Default is no impersonation if credentials name is not provided.
Returns
object - instance of the Instance class for the newly created Availability Group
Raises
SDKException: if Availability Group for given primary replica does not exist if Availability Group client/instance fails to be created. if Credentials for impersonation does not exist
Expand source code Browse git
def create_sql_ag(self, client_name, ag_group_name, credentials=None): """Creates a new SQL Availability Group client and instance. Args: client_name (str) -- name to use for Availability Group client ag_group_name (str) -- name of the Availability Group to create credentials (str, optional) -- name of credentials to use as impersonation Default is no impersonation if credentials name is not provided. Returns: object - instance of the Instance class for the newly created Availability Group Raises: SDKException: if Availability Group for given primary replica does not exist if Availability Group client/instance fails to be created. if Credentials for impersonation does not exist """ # If credentials passed, verify it exists if credentials: if not credentials in self._commcell_object.credentials.all_credentials: raise SDKException( 'Credential', '102', 'Credential name provided does not exist in the commcell.' ) # Get the available AG groups configured on SQL Instance ag_groups_resp = self._get_ag_groups() # Verify the provided AG group exists from available AG groups on primary replica if not any(ag['name'] == ag_group_name for ag in ag_groups_resp): raise SDKException( 'Instance', '102', 'Availability Group with provided name does not exist for given replica.' ) for ag_group in ag_groups_resp: if ag_group['name'].lower() == ag_group_name.lower(): ag_group_endpointURL = ag_group['endpointURL'] ag_group_backupPref = ag_group['backupPreference'] ag_primary_replica_server = ag_group['primaryReplicaServerName'] ag_group_listener_list = [] if 'SQLAvailabilityGroupListenerList' in ag_group: for listener in ag_group['SQLAvailabilityGroupListenerList']: listener_details = { 'availabilityGroupListenerName': listener['availabilityGroupListenerName'] } ag_group_listener_list.append(listener_details) # Get the replicas from the provided AG group ag_group_replicas_resp = self._get_ag_group_replicas(ag_group_name) request_json = { "App_CreatePseudoClientRequest": { "clientInfo": { "clientType": 20, "mssqlagClientProperties": { "SQLServerInstance": { "clientId": int(self.properties['instance']['clientId']), "instanceId": int(self.instance_id) }, "availabilityGroup": { "name": ag_group_name, "primaryReplicaServerName": ag_primary_replica_server, "backupPreference": ag_group_backupPref, "endpointURL": ag_group_endpointURL }, "SQLAvailabilityReplicasList": ag_group_replicas_resp, }, }, "entity": { "clientName": client_name } } } if ag_group_listener_list: request_json['App_CreatePseudoClientRequest']['clientInfo']['mssqlagClientProperties']\ ['availabilityGroup']['SQLAvailabilityGroupListenerList'] = ag_group_listener_list webservice = self._commcell_object._services['EXECUTE_QCOMMAND'] flag, response = self._cvpysdk_object.make_request( 'POST', webservice, request_json) if flag: if response.json(): if 'response' in response.json(): error_code = response.json()['response']['errorCode'] if error_code != 0: error_string = response.json()['response']['errorString'] o_str = 'Failed to create client\nError: "{0}"'.format(error_string) raise SDKException('Client', '102', o_str) else: self._commcell_object.refresh() # Get newly created AG instance ag_client = self._commcell_object.clients.get( response.json()['response']['entity']['clientName'] ) agent = ag_client.agents.get(self._agent_object.agent_name) if ag_group_listener_list: ag_instance_name = ag_group_listener_list[0]['availabilityGroupListenerName'] \ + '/' + ag_group_name else: ag_instance_name = ag_group_name ag_instance = agent.instances.get(ag_instance_name) if credentials is not None: ag_instance.impersonation(True, credentials) return ag_instance elif 'errorMessage' in response.json(): error_string = response.json()['errorMessage'] o_str = 'Failed to create client\nError: "{0}"'.format(error_string) raise SDKException('Client', '102', o_str) else: raise SDKException('Response', '102') else: raise SDKException('Response', '102') else: raise SDKException('Response', '101', self._update_response_(response.text))
def get_recovery_points(self)
-
lists all the recovery points.
returns: object (list) - list of all the recovery points and clones
Expand source code Browse git
def get_recovery_points(self): """ lists all the recovery points. returns: object (list) - list of all the recovery points and clones """ flag, response = self._commcell_object._cvpysdk_object.make_request( 'GET', self._commcell_object._services["SQL_CLONES"], None ) if flag: response_json = response.json() if "rpObjectList" in response_json: return response_json["total"], response_json["rpObjectList"] return 0, None raise SDKException('Response', '102', "failed to get recovery points")
def impersonation(self, enable, credentials=None)
-
Sets impersonation on SQL instance with local system account or provided credentials.
Args
enable (bool) – boolean value whether to set impersonation
credentials (str, optional) – credentials to set for impersonation. Defaults to local system account if enabled is True and credential name not provided.
Expand source code Browse git
def impersonation(self, enable, credentials=None): """Sets impersonation on SQL instance with local system account or provided credentials. Args: enable (bool) -- boolean value whether to set impersonation credentials (str, optional) -- credentials to set for impersonation. Defaults to local system account if enabled is True and credential name not provided. """ if enable and credentials is None: impersonate_json = { "overrideHigherLevelSettings": { "overrideGlobalAuthentication": True, "useLocalSystemAccount": True } } elif enable and credentials is not None: impersonate_json = { "overrideHigherLevelSettings": { "overrideGlobalAuthentication": True, "useLocalSystemAccount": False }, "MSSQLCredentialinfo": { "credentialName": credentials } } else: impersonate_json = { "overrideHigherLevelSettings": { "overrideGlobalAuthentication": True, "useLocalSystemAccount": False } } self._set_instance_properties("_mssql_instance_prop", impersonate_json)
def restore(self, content_to_restore, drop_connections_to_databse=False, overwrite=True, restore_path=None, to_time=None, sql_restore_type='DATABASE_RESTORE', sql_recover_type='STATE_RECOVER', undo_path=None, restricted_user=None, destination_instance=None)
-
Restores the databases specified in the input paths list.
Args
content_to_restore
:list
- List of databases to restore.
drop_connections_to_databse
:bool
- Drop connections to database. Defaults to False.
overwrite
:bool
- Unconditional overwrite files during restore. Defaults to True.
restore_path
:str
- Existing path on disk to restore. Defaults to None.
to_time
:str
- Restore to time. Defaults to None.
sql_recover_type
:str
- Type of sql recovery state. (STATE_RECOVER, STATE_NORECOVER, STATE_STANDBY)
Defaults to STATE_RECOVER.
sql_restore_type
:str
- Type of sql restore state. (DATABASE_RESTORE, STEP_RESTORE, RECOVER_ONLY)
Defaults to DATABASE_RESTORE.
undo_path
:str
- File path for undo path for sql standby restores. Defaults to None.
restricted_user
:bool
- Restore database in restricted user mode. Defaults to None.
destination_instance
:str
- Destination instance to restore too. Defaults to None.
Returns
object - instance of the Job class for this restore job
Raises
SDKException: if content_to_restore is not a list
if response is empty if response is not success
Expand source code Browse git
def restore( self, content_to_restore, drop_connections_to_databse=False, overwrite=True, restore_path=None, to_time=None, sql_restore_type=SQLDefines.DATABASE_RESTORE, sql_recover_type=SQLDefines.STATE_RECOVER, undo_path=None, restricted_user=None, destination_instance=None ): """Restores the databases specified in the input paths list. Args: content_to_restore (list): List of databases to restore. drop_connections_to_databse (bool): Drop connections to database. Defaults to False. overwrite (bool): Unconditional overwrite files during restore. Defaults to True. restore_path (str): Existing path on disk to restore. Defaults to None. to_time (str): Restore to time. Defaults to None. sql_recover_type (str): Type of sql recovery state. (STATE_RECOVER, STATE_NORECOVER, STATE_STANDBY) Defaults to STATE_RECOVER. sql_restore_type (str): Type of sql restore state. (DATABASE_RESTORE, STEP_RESTORE, RECOVER_ONLY) Defaults to DATABASE_RESTORE. undo_path (str): File path for undo path for sql standby restores. Defaults to None. restricted_user (bool): Restore database in restricted user mode. Defaults to None. destination_instance (str): Destination instance to restore too. Defaults to None. Returns: object - instance of the Job class for this restore job Raises: SDKException: if content_to_restore is not a list if response is empty if response is not success """ if not isinstance(content_to_restore, list): raise SDKException('Instance', '101') if destination_instance is not None: destination_instance = destination_instance.lower() request_json = self._restore_request_json( content_to_restore, drop_connections_to_databse=drop_connections_to_databse, overwrite=overwrite, restore_path=restore_path, to_time=to_time, sql_restore_type=sql_restore_type, sql_recover_type=sql_recover_type, undo_path=undo_path, restricted_user=restricted_user, destination_instance=destination_instance ) return self._process_restore_response(request_json)
def restore_to_destination_server(self, content_to_restore, destination_server, drop_connections_to_databse=False, overwrite=True, restore_path=None)
-
Restores the databases specified in the input paths list.
Args
content_to_restore
:list
- List of databases to restore.
destination_server
:str
- Destination server(instance) name.
drop_connections_to_databse
:bool
- Drop connections to database. Defaults to False.
overwrite
:bool
- Unconditional overwrite files during restore. Defaults to True.
restore_path
:str
- Existing path on disk to restore. Default to None.
Returns
object - instance of the Job class for this restore job
Raises
SDKException: if content_to_restore is not a list
if response is empty if response is not success
Expand source code Browse git
def restore_to_destination_server( self, content_to_restore, destination_server, drop_connections_to_databse=False, overwrite=True, restore_path=None): """Restores the databases specified in the input paths list. Args: content_to_restore (list): List of databases to restore. destination_server (str): Destination server(instance) name. drop_connections_to_databse (bool): Drop connections to database. Defaults to False. overwrite (bool): Unconditional overwrite files during restore. Defaults to True. restore_path (str): Existing path on disk to restore. Default to None. Returns: object - instance of the Job class for this restore job Raises: SDKException: if content_to_restore is not a list if response is empty if response is not success """ if not isinstance(content_to_restore, list): raise SDKException('Instance', '101') request_json = self._restore_request_json( content_to_restore, drop_connections_to_databse=drop_connections_to_databse, overwrite=overwrite, restore_path=restore_path, destination_instance=destination_server ) return self._process_restore_response(request_json)
def table_level_restore(self, src_db_name, tables_to_restore, destination_db_name, rp_name, include_child_tables, include_parent_tables)
-
Starts a table level restore
Args
src_db_name(str) : Name of the source database
tables_to_restore(list) : List of tables to restore
destination_db_name(str) : Destination database name
rp_name(str) : Name of recovery point
include_child_tables(bool) : Includes all child tables in restore.
include_parent_tables(bool) : Includes all parent tables in restore.
Returns
job
- Instance of Job class for this restore job
Expand source code Browse git
def table_level_restore(self, src_db_name, tables_to_restore, destination_db_name, rp_name, include_child_tables, include_parent_tables): """Starts a table level restore Args: src_db_name(str) : Name of the source database tables_to_restore(list) : List of tables to restore destination_db_name(str) : Destination database name rp_name(str) : Name of recovery point include_child_tables(bool) : Includes all child tables in restore. include_parent_tables(bool) : Includes all parent tables in restore. Returns: job : Instance of Job class for this restore job""" if not (isinstance(src_db_name, str) or isinstance(tables_to_restore, list) or isinstance(destination_db_name, str)): raise SDKException('Instance', '101') request_json = self._table_level_restore_request_json( src_db_name, tables_to_restore, destination_db_name, rp_name, include_child_tables, include_parent_tables ) return self._process_restore_response(request_json)
def vdi_timeout(self, value)
-
Sets the SQL VDI timeout value on SQL instance
Args
value (int) – value of vdi timeout for sql vdi operations
Expand source code Browse git
def vdi_timeout(self, value): """Sets the SQL VDI timeout value on SQL instance Args: value (int) -- value of vdi timeout for sql vdi operations """ request_json = { "vDITimeOut": value } self._set_instance_properties("_mssql_instance_prop", request_json)
def vss_option(self, value)
-
Enables or disables VSS option on SQL instance
Args
value (bool) – Boolean value whether to set VSS option on or off
Expand source code Browse git
def vss_option(self, value): """Enables or disables VSS option on SQL instance Args: value (bool) -- Boolean value whether to set VSS option on or off """ request_json = { "useVss": value } self._set_instance_properties("_mssql_instance_prop", request_json)
Inherited members