1062 lines
37 KiB
Python
1062 lines
37 KiB
Python
"""
|
|
Copyright 2018 Attunity
|
|
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.
|
|
"""
|
|
|
|
# coding: utf-8
|
|
import os, sys, ssl, base64
|
|
from collections import OrderedDict
|
|
import json
|
|
|
|
use_python_env_3X = sys.version_info > (3,)
|
|
if use_python_env_3X:
|
|
from urllib.parse import quote
|
|
from urllib.request import Request, urlopen
|
|
from urllib.error import HTTPError, URLError
|
|
base_string_type = str
|
|
else:
|
|
from urllib2 import Request, urlopen, HTTPError, URLError, quote
|
|
base_string_type = basestring
|
|
|
|
HEADERS_CONTENT_TYPE = 'Content-Type'
|
|
HEADERS_CONTENT_LENGTH = 'Content-Length'
|
|
|
|
# import Enum # if 3.4 its supported in python, else use: pip install enum34
|
|
from enum import Enum
|
|
|
|
|
|
#region models
|
|
|
|
#Enums
|
|
class AemTaskStopReason(Enum):
|
|
NONE = 0
|
|
NORMAL = 1
|
|
RECOVERABLE_ERROR = 2
|
|
FATAL_ERROR = 3
|
|
FULL_LOAD_ONLY_FINISHED = 4
|
|
STOPPED_AFTER_FULL_LOAD = 5
|
|
STOPPED_AFTER_CACHED_EVENTS = 6
|
|
EXPRESS_LICENSE_LIMITS_REACHED = 7
|
|
STOPPED_AFTER_DDL_APPLY = 8
|
|
STOPPED_LOW_MEMORY = 9
|
|
STOPPED_LOW_DISK_SPACE = 10
|
|
|
|
class AemEndpointState(Enum):
|
|
UNKNOWN = 0
|
|
CONNECTED = 1
|
|
ERROR = 2
|
|
|
|
class EndpointRole(Enum):
|
|
ALL = 0
|
|
SOURCE = 1
|
|
TARGET = 2
|
|
BOTH = 3
|
|
|
|
class AemLicenseState(Enum):
|
|
VALID_LICENSE = 0
|
|
INVALID_LICENSE_CHECKSUM = 1
|
|
EXPIRED_LICENSE = 2
|
|
NO_LICENSE = 3
|
|
MACHINE_NOT_LICENSED = 4
|
|
INVALID_LICENSE = 5
|
|
|
|
class AemServerState(Enum):
|
|
NOT_MONITORED = 0
|
|
MONITORED = 1
|
|
ERROR = 2
|
|
|
|
class AemTableState(Enum):
|
|
TABLE_QUEUED = 0
|
|
TABLE_LOADING = 1
|
|
TABLE_COMPLETED = 2
|
|
TABLE_CHANGE_PROCESSING = 3
|
|
TABLE_ERROR = 4
|
|
|
|
class AemRunTaskOptions(Enum):
|
|
RESUME_PROCESSING = 1
|
|
RELOAD_TARGET = 2
|
|
RESUME_PROCESSING_FROM_TIMESTAMP = 3
|
|
METADATA_ONLY_RECREATE_ALL_TABLES = 4
|
|
METADATA_ONLY_CREATE_MISSING_TABLES = 5
|
|
RECOVER_USING_LOCALLY_STORED_CHECKPOINT = 6
|
|
RECOVER_USING_CHECKPOINT_STORED_ON_TARGET = 7
|
|
|
|
class AemTaskState(Enum):
|
|
NOT_EXIST = 0
|
|
RUNNING = 1
|
|
ERROR = 2
|
|
STOPPED = 3
|
|
PAUSED = 4
|
|
RECOVERY = 5
|
|
STARTING = 6
|
|
STOPPING = 7
|
|
|
|
class AemPlatform(Enum):
|
|
UNKNOWN = 0
|
|
WINDOWS = 1
|
|
LINUX = 2
|
|
|
|
class ServerType(Enum):
|
|
REPLICATE = 1
|
|
COMPOSE_FDL = 3
|
|
COMPOSE = 4
|
|
COMPOSE_FDW = 5
|
|
|
|
#Base classes
|
|
class AemServer(object):
|
|
def __init__(self, j = None):
|
|
if not j:
|
|
self.name = None
|
|
self.description = None
|
|
self.host = None
|
|
self.port = None
|
|
self.username = None
|
|
self.password = None
|
|
self.monitored = True
|
|
self.verify_server_certificate = False
|
|
self.type = ServerType.REPLICATE
|
|
else:
|
|
self.__dict__ = AttUtil.attobject_from_json(j)
|
|
self.type = ServerType[self.type]
|
|
|
|
#class AemComposeTaskInfoDetailed(AemTaskInfoDetailedBase):
|
|
# def __init__(self, j = None):
|
|
# AemTaskInfoDetailedBase.__init__(self, j)
|
|
|
|
class AemServerInfo(object):
|
|
def __init__(self, j = None):
|
|
if not j:
|
|
self.name = None
|
|
self.description = None
|
|
self.host = None
|
|
self.port = None
|
|
self.state = AemServerState.NOT_MONITORED
|
|
self.message = None
|
|
self.platform = AemPlatform.UNKNOWN
|
|
self.version = None
|
|
self.last_connection = None
|
|
self.type = ServerType.REPLICATE
|
|
else:
|
|
self.__dict__ = AttUtil.attobject_from_json(j)
|
|
self.state = AemServerState[self.state]
|
|
self.platform = AemPlatform[self.platform]
|
|
self.type = ServerType[self.type]
|
|
|
|
class AemTaskInfoDetailedBase(object):
|
|
def __init__(self, j = None):
|
|
if not j:
|
|
self.name = None
|
|
self.state = AemTaskState.NOT_EXIST
|
|
self.description = None
|
|
self.source_endpoint = None
|
|
self.target_endpoint = None
|
|
self.assigned_tags = []
|
|
self.message = None
|
|
self.profile = None
|
|
else:
|
|
self.__dict__ = AttUtil.attobject_from_json(j)
|
|
self.state = AemTaskState[self.state]
|
|
self.source_endpoint = TaskEndpoint(self.source_endpoint)
|
|
self.target_endpoint = TaskEndpoint(self.target_endpoint)
|
|
|
|
class AemComposeTaskInfoDetailed(AemTaskInfoDetailedBase):
|
|
def __init__(self, j = None):
|
|
AemTaskInfoDetailedBase.__init__(self, j)
|
|
|
|
class AemServerDetails(object):
|
|
def __init__(self, j = None):
|
|
if not j:
|
|
self.name = None
|
|
self.description = None
|
|
self.configuration = None
|
|
self.state = AemServerState.NOT_MONITORED
|
|
self.message = None
|
|
self.version = None
|
|
self.license = None
|
|
self.last_connection = None
|
|
self.task_summary = None
|
|
self.resource_utilization = None
|
|
self.type = ServerType.REPLICATE
|
|
else:
|
|
self.__dict__ = AttUtil.attobject_from_json(j)
|
|
self.configuration = Configuration(self.configuration)
|
|
self.state = AemServerState[self.state]
|
|
self.license = ApiLicense(self.license)
|
|
self.task_summary = AemTasksSummary(self.task_summary)
|
|
self.resource_utilization = AemServerUtilization(self.resource_utilization)
|
|
self.type = ServerType[self.type]
|
|
|
|
#child classes
|
|
class AemTaskInfoDetailed(AemTaskInfoDetailedBase):
|
|
def __init__(self, j = None):
|
|
AemTaskInfoDetailedBase.__init__(self, j)
|
|
|
|
class ReplicateServerInfo(AemServerInfo):
|
|
def __init__(self, j = None):
|
|
AemServerInfo.__init__(self, j)
|
|
|
|
class AemComposeDMTaskInfoDetailed(AemComposeTaskInfoDetailed):
|
|
def __init__(self, j = None):
|
|
AemComposeTaskInfoDetailed.__init__(self, j)
|
|
|
|
class AemComposeServer(AemServer):
|
|
def __init__(self, j = None):
|
|
AemServer.__init__(self, j)
|
|
|
|
class AemReplicateServer(AemServer):
|
|
def __init__(self, j = None):
|
|
AemServer.__init__(self, j)
|
|
|
|
class ComposeServerDetails(AemServerDetails):
|
|
def __init__(self, j = None):
|
|
AemServerDetails.__init__(self, j)
|
|
|
|
class ReplicateServerDetails(AemServerDetails):
|
|
def __init__(self, j = None):
|
|
AemServerDetails.__init__(self, j)
|
|
|
|
class ComposeServerInfo(AemServerInfo):
|
|
def __init__(self, j = None):
|
|
AemServerInfo.__init__(self, j)
|
|
|
|
class AemComposeDWTaskInfoDetailed(AemComposeTaskInfoDetailed):
|
|
def __init__(self, j = None):
|
|
AemComposeTaskInfoDetailed.__init__(self, j)
|
|
|
|
class AemComposeDLTaskInfoDetailed(AemComposeTaskInfoDetailed):
|
|
def __init__(self, j = None):
|
|
AemComposeTaskInfoDetailed.__init__(self, j)
|
|
|
|
#simple classes
|
|
class AemAuthorizationAcl(object):
|
|
def __init__(self, j = None):
|
|
if not j:
|
|
self.admin_role = None
|
|
self.designer_role = None
|
|
self.operator_role = None
|
|
self.viewer_role = None
|
|
self.disable_inheritance = False
|
|
else:
|
|
self.__dict__ = AttUtil.attobject_from_json(j)
|
|
self.admin_role = AemRoleDef(self.admin_role)
|
|
self.designer_role = AemRoleDef(self.designer_role)
|
|
self.operator_role = AemRoleDef(self.operator_role)
|
|
self.viewer_role = AemRoleDef(self.viewer_role)
|
|
|
|
class AemGetTableStatusesResp(object):
|
|
def __init__(self, j = None):
|
|
if not j:
|
|
self.table_details = []
|
|
else:
|
|
self.__dict__ = AttUtil.attobject_from_json(j)
|
|
for i, k in enumerate(self.table_details):
|
|
self.table_details[i] = AemTableDetails(self.table_details[i])
|
|
|
|
class AemGetTaskListResp(object):
|
|
def __init__(self, j = None):
|
|
if not j:
|
|
self.taskList = []
|
|
else:
|
|
self.__dict__ = AttUtil.attobject_from_json(j)
|
|
for i, k in enumerate(self.taskList):
|
|
self.taskList[i] = AemTaskInfo(self.taskList[i])
|
|
|
|
class AemSetChangeDataRetentionBarrierReq(object):
|
|
def __init__(self, j = None):
|
|
if not j:
|
|
self.application = None
|
|
self.retention_point = None
|
|
else:
|
|
self.__dict__ = AttUtil.attobject_from_json(j)
|
|
|
|
class AemGetServerListResp(object):
|
|
def __init__(self, j = None):
|
|
if not j:
|
|
self.serverList = []
|
|
else:
|
|
self.__dict__ = AttUtil.attobject_from_json(j)
|
|
for i, k in enumerate(self.serverList):
|
|
if self.serverList[i]['$type'] == 'ReplicateServerInfo':
|
|
self.serverList[i] = ReplicateServerInfo(self.serverList[i])
|
|
continue
|
|
if self.serverList[i]['$type'] == 'ComposeServerInfo':
|
|
self.serverList[i] = ComposeServerInfo(self.serverList[i])
|
|
continue
|
|
|
|
class AemTaskInfo(object):
|
|
def __init__(self, j = None):
|
|
if not j:
|
|
self.name = None
|
|
self.state = AemTaskState.STOPPED
|
|
self.stop_reason = AemTaskStopReason.NORMAL
|
|
self.message = None
|
|
self.assigned_tags = []
|
|
else:
|
|
self.__dict__ = AttUtil.attobject_from_json(j)
|
|
self.state = AemTaskState[self.state]
|
|
self.stop_reason = AemTaskStopReason[self.stop_reason]
|
|
|
|
class AemTableDetails(object):
|
|
def __init__(self, j = None):
|
|
if not j:
|
|
self.schema_on_source = None
|
|
self.table_on_source = None
|
|
self.schema_on_target = None
|
|
self.table_on_target = None
|
|
self.state = AemTableState.TABLE_QUEUED
|
|
self.data_errors_count = 0
|
|
self.table_full_load_info = None
|
|
self.table_cdc_info = None
|
|
else:
|
|
self.__dict__ = AttUtil.attobject_from_json(j)
|
|
self.state = AemTableState[self.state]
|
|
self.table_full_load_info = AemTableFullLoadInfo(self.table_full_load_info)
|
|
self.table_cdc_info = AemTableCdcInfo(self.table_cdc_info)
|
|
|
|
class AemTableFullLoadInfo(object):
|
|
def __init__(self, j = None):
|
|
if not j:
|
|
self.start_time = None
|
|
self.end_time = None
|
|
self.estimated_row_count = 0
|
|
self.estimated_end_time = None
|
|
self.transferred_row_count = 0
|
|
self.transferred_volume_mb = 0
|
|
else:
|
|
self.__dict__ = AttUtil.attobject_from_json(j)
|
|
|
|
class AemGetTableListResp(object):
|
|
def __init__(self, j = None):
|
|
if not j:
|
|
self.tablelist = []
|
|
else:
|
|
self.__dict__ = AttUtil.attobject_from_json(j)
|
|
for i, k in enumerate(self.tablelist):
|
|
self.tablelist[i] = AemTableInfo(self.tablelist[i])
|
|
|
|
class AemDeleteOldChangeDataReq(object):
|
|
def __init__(self, j = None):
|
|
if not j:
|
|
self.timestamp_or_offset = None
|
|
else:
|
|
self.__dict__ = AttUtil.attobject_from_json(j)
|
|
|
|
class AemGroupRef(object):
|
|
def __init__(self, j = None):
|
|
if not j:
|
|
self.name = None
|
|
else:
|
|
self.__dict__ = AttUtil.attobject_from_json(j)
|
|
|
|
class Endpoint(object):
|
|
def __init__(self, j = None):
|
|
if not j:
|
|
self.name = None
|
|
self.description = None
|
|
self.role = EndpointRole.ALL
|
|
self.type = None
|
|
self.is_licensed = False
|
|
else:
|
|
self.__dict__ = AttUtil.attobject_from_json(j)
|
|
self.role = EndpointRole[self.role]
|
|
|
|
class AemGetEndpointListResp(object):
|
|
def __init__(self, j = None):
|
|
if not j:
|
|
self.endpointList = []
|
|
else:
|
|
self.__dict__ = AttUtil.attobject_from_json(j)
|
|
for i, k in enumerate(self.endpointList):
|
|
self.endpointList[i] = Endpoint(self.endpointList[i])
|
|
|
|
class AemServerUtilization(object):
|
|
def __init__(self, j = None):
|
|
if not j:
|
|
self.disk_usage_mb = 0
|
|
self.memory_mb = 0
|
|
self.attunity_cpu_percentage = 0
|
|
self.machine_cpu_percentage = 0
|
|
else:
|
|
self.__dict__ = AttUtil.attobject_from_json(j)
|
|
|
|
class AemGetChangeDataRetentionBarrierResp(object):
|
|
def __init__(self, j = None):
|
|
if not j:
|
|
self.application = None
|
|
self.retention_point = None
|
|
else:
|
|
self.__dict__ = AttUtil.attobject_from_json(j)
|
|
|
|
class AemGetServerDetailsResp(object):
|
|
def __init__(self, j = None):
|
|
if not j:
|
|
self.server_details = None
|
|
else:
|
|
self.__dict__ = AttUtil.attobject_from_json(j)
|
|
if self.server_details['$type'] == 'ReplicateServerDetails':
|
|
self.server_details = ReplicateServerDetails(self.server_details)
|
|
elif self.server_details['$type'] == 'ComposeServerDetails':
|
|
self.server_details = ComposeServerDetails(self.server_details)
|
|
|
|
class AemRoleDef(object):
|
|
def __init__(self, j = None):
|
|
if not j:
|
|
self.users = []
|
|
self.groups = []
|
|
else:
|
|
self.__dict__ = AttUtil.attobject_from_json(j)
|
|
for i, k in enumerate(self.users):
|
|
self.users[i] = AemUserRef(self.users[i])
|
|
for i, k in enumerate(self.groups):
|
|
self.groups[i] = AemGroupRef(self.groups[i])
|
|
|
|
class AemRunTaskReq(object):
|
|
def __init__(self, j = None):
|
|
if not j:
|
|
self.cdcposition = None
|
|
else:
|
|
self.__dict__ = AttUtil.attobject_from_json(j)
|
|
|
|
class AemStopTaskResp(object):
|
|
def __init__(self, j = None):
|
|
if not j:
|
|
self.state = AemTaskState.NOT_EXIST
|
|
self.error_message = None
|
|
else:
|
|
self.__dict__ = AttUtil.attobject_from_json(j)
|
|
self.state = AemTaskState[self.state]
|
|
|
|
class AemTasksSummary(object):
|
|
def __init__(self, j = None):
|
|
if not j:
|
|
self.total = 0
|
|
self.running = 0
|
|
self.stopped = 0
|
|
self.recovering = 0
|
|
self.error = 0
|
|
else:
|
|
self.__dict__ = AttUtil.attobject_from_json(j)
|
|
|
|
class TaskEndpoint(object):
|
|
def __init__(self, j = None):
|
|
if not j:
|
|
self.name = None
|
|
self.type = None
|
|
else:
|
|
self.__dict__ = AttUtil.attobject_from_json(j)
|
|
|
|
class AemTableCdcInfo(object):
|
|
def __init__(self, j = None):
|
|
if not j:
|
|
self.insert_count = 0
|
|
self.update_count = 0
|
|
self.delete_count = 0
|
|
self.ddl_count = 0
|
|
self.last_update_time = None
|
|
self.cached_insert_count = 0
|
|
self.cached_update_count = 0
|
|
self.cached_delete_count = 0
|
|
else:
|
|
self.__dict__ = AttUtil.attobject_from_json(j)
|
|
|
|
class AemRunTaskResp(object):
|
|
def __init__(self, j = None):
|
|
if not j:
|
|
self.state = AemTaskState.NOT_EXIST
|
|
self.error_message = None
|
|
else:
|
|
self.__dict__ = AttUtil.attobject_from_json(j)
|
|
self.state = AemTaskState[self.state]
|
|
|
|
class AemUserRef(object):
|
|
def __init__(self, j = None):
|
|
if not j:
|
|
self.name = None
|
|
else:
|
|
self.__dict__ = AttUtil.attobject_from_json(j)
|
|
|
|
class AemTableInfo(object):
|
|
def __init__(self, j = None):
|
|
if not j:
|
|
self.schema = None
|
|
self.table = None
|
|
self.state = AemTableState.TABLE_QUEUED
|
|
else:
|
|
self.__dict__ = AttUtil.attobject_from_json(j)
|
|
self.state = AemTableState[self.state]
|
|
|
|
class AemTestEndpointResp(object):
|
|
def __init__(self, j = None):
|
|
if not j:
|
|
self.status = AemEndpointState.UNKNOWN
|
|
self.message = None
|
|
self.detailed_message = None
|
|
else:
|
|
self.__dict__ = AttUtil.attobject_from_json(j)
|
|
self.status = AemEndpointState[self.status]
|
|
|
|
class ApiLicense(object):
|
|
def __init__(self, j = None):
|
|
if not j:
|
|
self.issue_date = None
|
|
self.state = AemLicenseState.VALID_LICENSE
|
|
self.expiration = None
|
|
self.days_to_expiration = 0
|
|
else:
|
|
self.__dict__ = AttUtil.attobject_from_json(j)
|
|
self.state = AemLicenseState[self.state]
|
|
|
|
class Configuration(object):
|
|
def __init__(self, j = None):
|
|
if not j:
|
|
self.host = None
|
|
self.platform = AemPlatform.UNKNOWN
|
|
self.port = None
|
|
self.user_name = None
|
|
else:
|
|
self.__dict__ = AttUtil.attobject_from_json(j)
|
|
self.platform = AemPlatform[self.platform]
|
|
|
|
|
|
#endregion models
|
|
|
|
#region utils
|
|
|
|
class AuthenticationMethod(Enum):
|
|
ACTIVE_DIRECTORY = 0
|
|
SAML = 1
|
|
|
|
class AttUtil(object):
|
|
@staticmethod
|
|
def quote_param(url_param):
|
|
if isinstance(url_param, Enum):
|
|
url_param = url_param.name
|
|
url_param = str(url_param).encode('utf-8')
|
|
url_param = quote(quote(url_param))
|
|
return url_param
|
|
# END function AttUtil.quote_param
|
|
|
|
@staticmethod
|
|
def attobject_from_json(obj):
|
|
base_obj = obj
|
|
if type(obj) is dict:
|
|
return base_obj
|
|
try:
|
|
if isinstance(obj, base_string_type) or isinstance(obj, str) or isinstance(obj.decode('utf-8'), str):
|
|
base_obj = json.loads(obj)
|
|
except Exception as ex:
|
|
print(ex)
|
|
return base_obj
|
|
# END function AttUtil.attobject_from_json
|
|
|
|
@staticmethod
|
|
def attobject_to_json(obj):
|
|
if isinstance(obj, Enum):
|
|
return obj.name
|
|
elif (obj is None or (type(obj) is str) or (type(obj) is int) or (type(obj) is bool) or (type(obj) is bytes) or isinstance(obj, base_string_type) or (str(type(obj)) == "<type 'unicode'>") ):
|
|
return obj
|
|
elif ( (type(obj) is list) or isinstance(obj, list) ):
|
|
arr = []
|
|
for item in obj:
|
|
arr.append( AttUtil.attobject_to_json(item))
|
|
return arr
|
|
elif ( (type(obj) is dict) or (obj.__dict__ != None) ):
|
|
# keep the object Type
|
|
obj_type = obj.__class__.__name__
|
|
sorted_dict = OrderedDict()
|
|
# set $type as first
|
|
sorted_dict['$type'] = obj_type
|
|
for key in obj.__dict__:
|
|
sorted_dict[key] = AttUtil.attobject_to_json(obj.__dict__[key])
|
|
return sorted_dict
|
|
else:
|
|
return obj
|
|
# END function AttUtil.attobject_to_json
|
|
|
|
@staticmethod
|
|
def validate_params(param_dict):
|
|
for key in param_dict:
|
|
item = param_dict[key]
|
|
if not isinstance(item["value"], item["type"]):
|
|
raise Exception('Param: "{0}" should be of type: "{1}", but was: "{2}"'.format(key, item["type"], type(item["value"]) ) )
|
|
# END function AttUtil.validate_params
|
|
|
|
@staticmethod
|
|
def get_b64_user_pass(username, password):
|
|
username_pass_tpl = str.encode('{0}:{1}'.format(username, password))
|
|
return base64.b64encode(username_pass_tpl).decode('ascii')
|
|
# END function AttUtil.get_b64_user_pass
|
|
# END class AttUtil
|
|
|
|
class AemClientException(Exception):
|
|
def __init__(self, error_code, error_message):
|
|
self.error_code = error_code
|
|
self.message = error_message
|
|
Exception.__init__(self, error_code, error_message)
|
|
|
|
class AttConnector(object):
|
|
def __init__(self, b64_username_password, verify_certificate=True, authentication_method=AuthenticationMethod.ACTIVE_DIRECTORY):
|
|
self.verify_certificate = verify_certificate
|
|
if authentication_method == AuthenticationMethod.ACTIVE_DIRECTORY:
|
|
self.headers = { 'Authorization' : 'Basic %s' % b64_username_password }
|
|
else:
|
|
self.headers = dict()
|
|
if verify_certificate:
|
|
ssl._create_default_https_context = ssl.create_default_context
|
|
else:
|
|
ssl._create_default_https_context = ssl._create_unverified_context
|
|
|
|
def att_request(self, method, url, payload=None, get_raw_error=False, content_type='application/json'):
|
|
req_headers = {}
|
|
for key in self.headers:
|
|
req_headers[key] = self.headers[key]
|
|
req_headers[HEADERS_CONTENT_TYPE] = content_type
|
|
if payload:
|
|
payload = payload.encode('utf-8')
|
|
req_headers[HEADERS_CONTENT_LENGTH] = str(len(payload))
|
|
elif HEADERS_CONTENT_LENGTH in req_headers:
|
|
del req_headers[HEADERS_CONTENT_LENGTH]
|
|
att_response = {}
|
|
request_pyx = Request(url, data=payload, headers=req_headers)
|
|
request_pyx.get_method = lambda: method
|
|
try:
|
|
att_response = urlopen(request_pyx)
|
|
except HTTPError as ex:
|
|
if get_raw_error:
|
|
att_response = ex
|
|
else:
|
|
# TODO: G.G. - remove read, and adjust calls and errors
|
|
att_response = ex.read()
|
|
except URLError as ex:
|
|
att_response = ex
|
|
except Exception as ex:
|
|
att_response = ex
|
|
return att_response
|
|
# end of att_request
|
|
def save_headers(self, response):
|
|
headers_dict = {}
|
|
try:
|
|
resp_info = response.info()
|
|
for key in resp_info:
|
|
if key != HEADERS_CONTENT_LENGTH:
|
|
headers_dict[key] = response.headers[key]
|
|
except Exception as ex:
|
|
print(ex)
|
|
self.headers = headers_dict
|
|
# end of save_headers
|
|
# END of class AttConnector
|
|
|
|
#endregion utils
|
|
|
|
#region infrastructure
|
|
|
|
class AttClient(object):
|
|
def __init__(self, b64_username_password, url="", verify_certificate=True, authentication_method=AuthenticationMethod.ACTIVE_DIRECTORY):
|
|
if 'https' not in url:
|
|
raise Exception('The Aem access URL must start with "https".')
|
|
if not isinstance(authentication_method, AuthenticationMethod):
|
|
raise Exception('authentication_method must be of type AuthenticationMethod')
|
|
self.url = url
|
|
self.attconnector = AttConnector(b64_username_password, verify_certificate, authentication_method)
|
|
login_url = '{0}/api/v1/login'.format(self.url)
|
|
if authentication_method == AuthenticationMethod.ACTIVE_DIRECTORY:
|
|
saml_message = None
|
|
else:
|
|
saml_message = b64_username_password
|
|
response = self.attconnector.att_request(method='POST', url=login_url, payload=saml_message, get_raw_error=True, content_type='application/x-www-form-urlencoded')
|
|
if hasattr(response, 'code') and response.code == 200:
|
|
self.attconnector.save_headers(response)
|
|
else:
|
|
self.attconnector = None
|
|
if hasattr(response, 'reason') and response.reason:
|
|
raise Exception("Http Error: {0}".format(response.reason))
|
|
else:
|
|
resp_json = json.loads(response)
|
|
raise AemClientException(resp_json['error_code'], resp_json['error_message'])
|
|
# END function __init__
|
|
|
|
def do_web_request(self, resp_class=None, address=None, http_method='GET', req = None, stream_req = False):
|
|
full_url = '{0}/{1}'.format(self.url, address)
|
|
payload = None
|
|
if req:
|
|
if stream_req:
|
|
payload = req
|
|
else:
|
|
att_json = AttUtil.attobject_to_json(req)
|
|
payload = json.dumps( att_json, sort_keys=True )
|
|
response_t = self.attconnector.att_request(method=http_method, url=full_url, payload=payload)
|
|
response_text = None
|
|
try:
|
|
response_text = response_t.read()
|
|
except Exception as ex:
|
|
if hasattr(response_t, 'reason') and response_t.reason:
|
|
raise Exception('Http Error: {0}'.format(response_t.reason))
|
|
else:
|
|
response_t = json.loads(response_t)
|
|
if 'error_code' in response_t or 'status_code' in response_t:
|
|
raise AemClientException(response_t['error_code'], response_t['error_message'])
|
|
if resp_class:
|
|
return resp_class(response_text)
|
|
return response_text
|
|
# END function do_web_request
|
|
|
|
#endregion infrastructure
|
|
|
|
|
|
class AemClient(AttClient):
|
|
def __init__(self, b64_username_password, machine_name, port=443, url="https://{0}/attunityenterprisemanager", verify_certificate=True, authentication_method=AuthenticationMethod.ACTIVE_DIRECTORY):
|
|
if port != 443:
|
|
machine_name = '{0}:{1}'.format(machine_name, port)
|
|
if url.find('{0}'):
|
|
url = url.format(machine_name)
|
|
self.attclient = AttClient(b64_username_password, url, verify_certificate, authentication_method)
|
|
def delete_endpoint(self, server, endpoint):
|
|
"""
|
|
parameters:
|
|
server - string
|
|
endpoint - string
|
|
"""
|
|
AttUtil.validate_params({ 'server':{'value':server,'type':base_string_type }, 'endpoint':{'value':endpoint,'type':base_string_type } })
|
|
address = "api/v1/servers/" + AttUtil.quote_param(server) + "/endpoints/" + AttUtil.quote_param(endpoint) + "?action=delete"
|
|
self.attclient.do_web_request(None, address, 'POST', None)
|
|
|
|
def delete_old_change_data(self, payload, server, task):
|
|
"""
|
|
request payload: AemDeleteOldChangeDataReq
|
|
parameters:
|
|
server - string
|
|
task - string
|
|
"""
|
|
AttUtil.validate_params({ 'payload':{'value':payload,'type':AemDeleteOldChangeDataReq }, 'server':{'value':server,'type':base_string_type }, 'task':{'value':task,'type':base_string_type } })
|
|
address = "api/v1/servers/" + AttUtil.quote_param(server) + "/tasks/" + AttUtil.quote_param(task) + "?action=delete_old_change_data"
|
|
self.attclient.do_web_request(None, address, 'POST', payload)
|
|
|
|
def delete_server_acl(self, server):
|
|
"""
|
|
parameters:
|
|
server - string
|
|
"""
|
|
AttUtil.validate_params({ 'server':{'value':server,'type':base_string_type } })
|
|
address = "api/v1/servers/" + AttUtil.quote_param(server) + "?action=acl"
|
|
self.attclient.do_web_request(None, address, 'DELETE', None)
|
|
|
|
def delete_server(self, server):
|
|
"""
|
|
parameters:
|
|
server - string
|
|
"""
|
|
AttUtil.validate_params({ 'server':{'value':server,'type':base_string_type } })
|
|
address = "api/v1/servers/" + AttUtil.quote_param(server) + "/def"
|
|
self.attclient.do_web_request(None, address, 'DELETE', None)
|
|
|
|
def delete_task(self, server, task, deletetasklogs = False):
|
|
"""
|
|
parameters:
|
|
server - string
|
|
task - string
|
|
deletetasklogs - bool
|
|
"""
|
|
AttUtil.validate_params({ 'server':{'value':server,'type':base_string_type }, 'task':{'value':task,'type':base_string_type }, 'deletetasklogs':{'value':deletetasklogs,'type':bool } })
|
|
address = "api/v1/servers/" + AttUtil.quote_param(server) + "/tasks/" + AttUtil.quote_param(task) + "?action=delete&deletetasklogs=" + AttUtil.quote_param(deletetasklogs) + ""
|
|
self.attclient.do_web_request(None, address, 'POST', None)
|
|
|
|
def export_all(self, server):
|
|
"""
|
|
response payload: STREAM
|
|
parameters:
|
|
server - string
|
|
"""
|
|
AttUtil.validate_params({ 'server':{'value':server,'type':base_string_type } })
|
|
address = "api/v1/servers/" + AttUtil.quote_param(server) + "?action=export"
|
|
resp = self.attclient.do_web_request(None, address, 'GET', None)
|
|
return resp
|
|
|
|
def export_audit_trail(self, start_timestamp = None, end_timestamp = None):
|
|
"""
|
|
response payload: STREAM
|
|
parameters:
|
|
start_timestamp - string
|
|
end_timestamp - string
|
|
"""
|
|
AttUtil.validate_params({ 'start_timestamp':{'value':start_timestamp,'type':base_string_type }, 'end_timestamp':{'value':end_timestamp,'type':base_string_type } })
|
|
address = "api/v1/security/audit_trail?start_timestamp=" + AttUtil.quote_param(start_timestamp) + "&end_timestamp=" + AttUtil.quote_param(end_timestamp) + ""
|
|
resp = self.attclient.do_web_request(None, address, 'GET', None)
|
|
return resp
|
|
|
|
def export_task(self, server, task, withendpoints = False):
|
|
"""
|
|
response payload: STREAM
|
|
parameters:
|
|
server - string
|
|
task - string
|
|
withendpoints - bool
|
|
"""
|
|
AttUtil.validate_params({ 'server':{'value':server,'type':base_string_type }, 'task':{'value':task,'type':base_string_type }, 'withendpoints':{'value':withendpoints,'type':bool } })
|
|
address = "api/v1/servers/" + AttUtil.quote_param(server) + "/tasks/" + AttUtil.quote_param(task) + "?action=export&withendpoints=" + AttUtil.quote_param(withendpoints) + ""
|
|
resp = self.attclient.do_web_request(None, address, 'GET', None)
|
|
return resp
|
|
|
|
def get_change_data_retention_barrier(self, server, task):
|
|
"""
|
|
response payload: AemGetChangeDataRetentionBarrierResp
|
|
parameters:
|
|
server - string
|
|
task - string
|
|
"""
|
|
AttUtil.validate_params({ 'server':{'value':server,'type':base_string_type }, 'task':{'value':task,'type':base_string_type } })
|
|
address = "api/v1/servers/" + AttUtil.quote_param(server) + "/tasks/" + AttUtil.quote_param(task) + "?action=get_change_data_retention_barrier"
|
|
resp = self.attclient.do_web_request(AemGetChangeDataRetentionBarrierResp, address, 'GET', None)
|
|
return resp
|
|
|
|
def get_endpoint_list(self, server):
|
|
"""
|
|
response payload: AemGetEndpointListResp
|
|
parameters:
|
|
server - string
|
|
"""
|
|
AttUtil.validate_params({ 'server':{'value':server,'type':base_string_type } })
|
|
address = "api/v1/servers/" + AttUtil.quote_param(server) + "/endpoints"
|
|
resp = self.attclient.do_web_request(AemGetEndpointListResp, address, 'GET', None)
|
|
return resp
|
|
|
|
def get_server_acl(self, server):
|
|
"""
|
|
response payload: AemAuthorizationAcl
|
|
parameters:
|
|
server - string
|
|
"""
|
|
AttUtil.validate_params({ 'server':{'value':server,'type':base_string_type } })
|
|
address = "api/v1/servers/" + AttUtil.quote_param(server) + "?action=acl"
|
|
resp = self.attclient.do_web_request(AemAuthorizationAcl, address, 'GET', None)
|
|
return resp
|
|
|
|
def get_server_details(self, server):
|
|
"""
|
|
response payload: AemGetServerDetailsResp
|
|
parameters:
|
|
server - string
|
|
"""
|
|
AttUtil.validate_params({ 'server':{'value':server,'type':base_string_type } })
|
|
address = "api/v1/servers/" + AttUtil.quote_param(server) + ""
|
|
resp = self.attclient.do_web_request(AemGetServerDetailsResp, address, 'GET', None)
|
|
return resp
|
|
|
|
def get_server_list(self, ):
|
|
"""
|
|
response payload: AemGetServerListResp
|
|
parameters:
|
|
"""
|
|
address = "api/v1/servers"
|
|
resp = self.attclient.do_web_request(AemGetServerListResp, address, 'GET', None)
|
|
return resp
|
|
|
|
def get_server(self, server):
|
|
"""
|
|
response payload: AemServer
|
|
parameters:
|
|
server - string
|
|
"""
|
|
AttUtil.validate_params({ 'server':{'value':server,'type':base_string_type } })
|
|
address = "api/v1/servers/" + AttUtil.quote_param(server) + "/def"
|
|
resp = self.attclient.do_web_request(AemServer, address, 'GET', None)
|
|
return resp
|
|
|
|
def get_table_list(self, server, task, schema = None, table = None, includequeued = False, includeloading = False, includecompleted = False, includechangeprocessing = False, includeerror = False):
|
|
"""
|
|
response payload: AemGetTableListResp
|
|
parameters:
|
|
server - string
|
|
task - string
|
|
schema - string
|
|
table - string
|
|
includequeued - bool
|
|
includeloading - bool
|
|
includecompleted - bool
|
|
includechangeprocessing - bool
|
|
includeerror - bool
|
|
"""
|
|
AttUtil.validate_params({ 'server':{'value':server,'type':base_string_type }, 'task':{'value':task,'type':base_string_type }, 'schema':{'value':schema,'type':base_string_type }, 'table':{'value':table,'type':base_string_type }, 'includequeued':{'value':includequeued,'type':bool }, 'includeloading':{'value':includeloading,'type':bool }, 'includecompleted':{'value':includecompleted,'type':bool }, 'includechangeprocessing':{'value':includechangeprocessing,'type':bool }, 'includeerror':{'value':includeerror,'type':bool } })
|
|
address = "api/v1/servers/" + AttUtil.quote_param(server) + "/tasks/" + AttUtil.quote_param(task) + "/tables?schema=" + AttUtil.quote_param(schema) + "&table=" + AttUtil.quote_param(table) + "&includequeued=" + AttUtil.quote_param(includequeued) + "&includeloading=" + AttUtil.quote_param(includeloading) + "&includecompleted=" + AttUtil.quote_param(includecompleted) + "&includechangeprocessing=" + AttUtil.quote_param(includechangeprocessing) + "&includeerror=" + AttUtil.quote_param(includeerror) + ""
|
|
resp = self.attclient.do_web_request(AemGetTableListResp, address, 'GET', None)
|
|
return resp
|
|
|
|
def get_table_statuses(self, server, task, schema = None, table = None, includequeued = False, includeloading = False, includecompleted = False, includechangeprocessing = False, includeerror = False):
|
|
"""
|
|
response payload: AemGetTableStatusesResp
|
|
parameters:
|
|
server - string
|
|
task - string
|
|
schema - string
|
|
table - string
|
|
includequeued - bool
|
|
includeloading - bool
|
|
includecompleted - bool
|
|
includechangeprocessing - bool
|
|
includeerror - bool
|
|
"""
|
|
AttUtil.validate_params({ 'server':{'value':server,'type':base_string_type }, 'task':{'value':task,'type':base_string_type }, 'schema':{'value':schema,'type':base_string_type }, 'table':{'value':table,'type':base_string_type }, 'includequeued':{'value':includequeued,'type':bool }, 'includeloading':{'value':includeloading,'type':bool }, 'includecompleted':{'value':includecompleted,'type':bool }, 'includechangeprocessing':{'value':includechangeprocessing,'type':bool }, 'includeerror':{'value':includeerror,'type':bool } })
|
|
address = "api/v1/servers/" + AttUtil.quote_param(server) + "/tasks/" + AttUtil.quote_param(task) + "/tables?action=getstatus&schema=" + AttUtil.quote_param(schema) + "&table=" + AttUtil.quote_param(table) + "&includequeued=" + AttUtil.quote_param(includequeued) + "&includeloading=" + AttUtil.quote_param(includeloading) + "&includecompleted=" + AttUtil.quote_param(includecompleted) + "&includechangeprocessing=" + AttUtil.quote_param(includechangeprocessing) + "&includeerror=" + AttUtil.quote_param(includeerror) + ""
|
|
resp = self.attclient.do_web_request(AemGetTableStatusesResp, address, 'GET', None)
|
|
return resp
|
|
|
|
def get_task_details(self, server, task):
|
|
"""
|
|
response payload: AemTaskInfoDetailedBase
|
|
parameters:
|
|
server - string
|
|
task - string
|
|
"""
|
|
AttUtil.validate_params({ 'server':{'value':server,'type':base_string_type }, 'task':{'value':task,'type':base_string_type } })
|
|
address = "api/v1/servers/" + AttUtil.quote_param(server) + "/tasks/" + AttUtil.quote_param(task) + ""
|
|
resp = self.attclient.do_web_request(AemTaskInfoDetailedBase, address, 'GET', None)
|
|
return resp
|
|
|
|
def get_task_list(self, server):
|
|
"""
|
|
response payload: AemGetTaskListResp
|
|
parameters:
|
|
server - string
|
|
"""
|
|
AttUtil.validate_params({ 'server':{'value':server,'type':base_string_type } })
|
|
address = "api/v1/servers/" + AttUtil.quote_param(server) + "/tasks"
|
|
resp = self.attclient.do_web_request(AemGetTaskListResp, address, 'GET', None)
|
|
return resp
|
|
|
|
def import_all(self, payload, server):
|
|
"""
|
|
request payload: STREAM
|
|
parameters:
|
|
server - string
|
|
"""
|
|
AttUtil.validate_params({ 'payload':{'value':payload,'type':base_string_type }, 'server':{'value':server,'type':base_string_type } })
|
|
address = "api/v1/servers/" + AttUtil.quote_param(server) + "?action=import"
|
|
self.attclient.do_web_request(None, address, 'POST', payload, True)
|
|
|
|
def import_task(self, payload, server, task):
|
|
"""
|
|
request payload: STREAM
|
|
parameters:
|
|
server - string
|
|
task - string
|
|
"""
|
|
AttUtil.validate_params({ 'payload':{'value':payload,'type':base_string_type }, 'server':{'value':server,'type':base_string_type }, 'task':{'value':task,'type':base_string_type } })
|
|
address = "api/v1/servers/" + AttUtil.quote_param(server) + "/tasks/" + AttUtil.quote_param(task) + "?action=import"
|
|
self.attclient.do_web_request(None, address, 'POST', payload, True)
|
|
|
|
def put_server_acl(self, payload, server):
|
|
"""
|
|
request payload: AemAuthorizationAcl
|
|
parameters:
|
|
server - string
|
|
"""
|
|
AttUtil.validate_params({ 'payload':{'value':payload,'type':AemAuthorizationAcl }, 'server':{'value':server,'type':base_string_type } })
|
|
address = "api/v1/servers/" + AttUtil.quote_param(server) + "?action=acl"
|
|
self.attclient.do_web_request(None, address, 'PUT', payload)
|
|
|
|
def put_server_license(self, payload, server):
|
|
"""
|
|
request payload: STREAM
|
|
parameters:
|
|
server - string
|
|
"""
|
|
AttUtil.validate_params({ 'payload':{'value':payload,'type':base_string_type }, 'server':{'value':server,'type':base_string_type } })
|
|
address = "api/v1/servers/" + AttUtil.quote_param(server) + "/license/def"
|
|
self.attclient.do_web_request(None, address, 'PUT', payload, True)
|
|
|
|
def put_server(self, payload, server):
|
|
"""
|
|
request payload: AemServer
|
|
parameters:
|
|
server - string
|
|
"""
|
|
AttUtil.validate_params({ 'payload':{'value':payload,'type':AemServer }, 'server':{'value':server,'type':base_string_type } })
|
|
address = "api/v1/servers/" + AttUtil.quote_param(server) + "/def"
|
|
self.attclient.do_web_request(None, address, 'PUT', payload)
|
|
|
|
def reconfigure_endpoint_no_wait(self, server, endpoint, configuration = None, recycle = True):
|
|
"""
|
|
parameters:
|
|
server - string
|
|
endpoint - string
|
|
configuration - string
|
|
recycle - bool
|
|
"""
|
|
AttUtil.validate_params({ 'server':{'value':server,'type':base_string_type }, 'endpoint':{'value':endpoint,'type':base_string_type }, 'configuration':{'value':configuration,'type':base_string_type }, 'recycle':{'value':recycle,'type':bool } })
|
|
address = "api/v1/servers/" + AttUtil.quote_param(server) + "/endpoints/" + AttUtil.quote_param(endpoint) + "?action=reconfigure&configuration=" + AttUtil.quote_param(configuration) + "&recycle=" + AttUtil.quote_param(recycle) + ""
|
|
self.attclient.do_web_request(None, address, 'PUT', None)
|
|
|
|
def reload_table(self, server, task, schema = None, table = None):
|
|
"""
|
|
parameters:
|
|
server - string
|
|
task - string
|
|
schema - string
|
|
table - string
|
|
"""
|
|
AttUtil.validate_params({ 'server':{'value':server,'type':base_string_type }, 'task':{'value':task,'type':base_string_type }, 'schema':{'value':schema,'type':base_string_type }, 'table':{'value':table,'type':base_string_type } })
|
|
address = "api/v1/servers/" + AttUtil.quote_param(server) + "/tasks/" + AttUtil.quote_param(task) + "/tables?action=reload&schema=" + AttUtil.quote_param(schema) + "&table=" + AttUtil.quote_param(table) + ""
|
|
self.attclient.do_web_request(None, address, 'POST', None)
|
|
|
|
def run_task(self, payload, server, task, option = AemRunTaskOptions.RESUME_PROCESSING, timeout = 60):
|
|
"""
|
|
request payload: AemRunTaskReq
|
|
response payload: AemRunTaskResp
|
|
parameters:
|
|
server - string
|
|
task - string
|
|
option - AemRunTaskOptions
|
|
timeout - int32
|
|
"""
|
|
AttUtil.validate_params({ 'payload':{'value':payload,'type':AemRunTaskReq }, 'server':{'value':server,'type':base_string_type }, 'task':{'value':task,'type':base_string_type }, 'option':{'value':option,'type':AemRunTaskOptions }, 'timeout':{'value':timeout,'type':int } })
|
|
address = "api/v1/servers/" + AttUtil.quote_param(server) + "/tasks/" + AttUtil.quote_param(task) + "?action=run&option=" + AttUtil.quote_param(option) + "&timeout=" + AttUtil.quote_param(timeout) + ""
|
|
resp = self.attclient.do_web_request(AemRunTaskResp, address, 'POST', payload)
|
|
return resp
|
|
|
|
def set_change_data_retention_barrier(self, payload, server, task):
|
|
"""
|
|
request payload: AemSetChangeDataRetentionBarrierReq
|
|
parameters:
|
|
server - string
|
|
task - string
|
|
"""
|
|
AttUtil.validate_params({ 'payload':{'value':payload,'type':AemSetChangeDataRetentionBarrierReq }, 'server':{'value':server,'type':base_string_type }, 'task':{'value':task,'type':base_string_type } })
|
|
address = "api/v1/servers/" + AttUtil.quote_param(server) + "/tasks/" + AttUtil.quote_param(task) + "?action=set_change_data_retention_barrier"
|
|
self.attclient.do_web_request(None, address, 'PUT', payload)
|
|
|
|
def stop_task(self, server, task, timeout = 30):
|
|
"""
|
|
response payload: AemStopTaskResp
|
|
parameters:
|
|
server - string
|
|
task - string
|
|
timeout - int32
|
|
"""
|
|
AttUtil.validate_params({ 'server':{'value':server,'type':base_string_type }, 'task':{'value':task,'type':base_string_type }, 'timeout':{'value':timeout,'type':int } })
|
|
address = "api/v1/servers/" + AttUtil.quote_param(server) + "/tasks/" + AttUtil.quote_param(task) + "?action=stop&timeout=" + AttUtil.quote_param(timeout) + ""
|
|
resp = self.attclient.do_web_request(AemStopTaskResp, address, 'POST', None)
|
|
return resp
|
|
|
|
def test_endpoint(self, server, endpoint, timeout = 60):
|
|
"""
|
|
response payload: AemTestEndpointResp
|
|
parameters:
|
|
server - string
|
|
endpoint - string
|
|
timeout - int32
|
|
"""
|
|
AttUtil.validate_params({ 'server':{'value':server,'type':base_string_type }, 'endpoint':{'value':endpoint,'type':base_string_type }, 'timeout':{'value':timeout,'type':int } })
|
|
address = "api/v1/servers/" + AttUtil.quote_param(server) + "/endpoints/" + AttUtil.quote_param(endpoint) + "?action=test&timeout=" + AttUtil.quote_param(timeout) + ""
|
|
resp = self.attclient.do_web_request(AemTestEndpointResp, address, 'GET', None)
|
|
return resp
|
|
|