Idoit-Tests 01

This commit is contained in:
Sven Riwoldt
2024-12-15 14:38:48 +01:00
parent 16d9b8bd2c
commit e06c448a46
51 changed files with 1181 additions and 0 deletions

90
idoit_scaleup/__init__.py Executable file
View File

@@ -0,0 +1,90 @@
from .object import IDoitObject
from . import consts
from pprint import pprint
from .cat_access import IDoitAccess
from .cat_application import IDoitApplication
from .cat_connector import IDoitConnector
from .cat_cpu import IDoitCpu
from .cat_ip import IDoitIP
from .cat_location import IDoitLocation
from .cat_memory import IDoitMemory
from .cat_network import IDoitNetwork
from .cat_networkport import IDoitNetworkPort
from .cat_network_log_port import IDoitNetworkLogicalPort
from .cat_power_consumer import IDoitPowerConsumer
#from .cat_racktables import Racktables
from .cat_vlan import IDoitVlan
from .category import IDoitCategory
from .conditional_read import IDoitConditionalRead
from .dialog import IDoitDialog
from .search import IDoitSearch
from .cat_storage_device import IDoitStorageDevice
from .api_log import IDoitApiLog
import sys
import inspect
def createApiCall(cfg, category):
current_module = sys.modules[__name__]
for name, obj in inspect.getmembers(current_module):
if inspect.isclass(obj):
if issubclass(obj, IDoitCategory):
try:
found = False
found = (obj.CATEGORY == category)
if found:
return obj(cfg)
except AttributeError:
pass
if category.startswith('C__OBJTYPE__'):
return IDoitObject(cfg, category)
if category.startswith('C__CATS__') or category.startswith('C__CATG__'):
return IDoitCategory(cfg, category)
return None
def createApiCalls(cfg):
rtn = {}
for varname in consts.__dict__.keys():
if not (varname in rtn.keys()):
rtn[varname] = createApiCall(cfg, varname)
return rtn
def createApiDialogs(cfg, category, field):
if 'dialogs' not in cfg.keys():
cfg['dialogs'] = {}
if category not in cfg['dialogs'].keys():
cfg['dialogs'][category] = {}
if field not in cfg['dialogs'][category].keys():
cfg['dialogs'][category][field] = IDoitDialog(cfg, category, field)
return cfg['dialogs'][category][field]
def search(cfg) -> IDoitSearch:
return IDoitSearch(cfg)
def conditional_read(cfg) -> IDoitConditionalRead:
return IDoitConditionalRead(cfg)
def get_all_classes():
rtn = []
current_module = sys.modules[__name__]
for name, obj in inspect.getmembers(current_module):
if inspect.isclass(obj):
rtn.append(name)
return rtn
def turn_on_api_logging():
IDoitApiLog.instance().turn_on()
def turn_off_api_logging():
IDoitApiLog.instance().turn_off()
def get_api_log():
return IDoitApiLog.instance().get_api_log()

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

30
idoit_scaleup/api_log.py Executable file
View File

@@ -0,0 +1,30 @@
class IDoitApiLog:
_instance = None
def __init__(self):
raise RuntimeError('Call instance() instead')
@classmethod
def instance(cls):
if cls._instance is None:
cls._instance = cls.__new__(cls)
cls.log = []
cls.do_log = False
# Put any initialization here.
return cls._instance
def turn_on(cls):
cls.do_log = True
def append_api_log(cls, url: str, payload, response):
if cls.do_log:
cls.log.append({
'url': url,
'payload': payload,
'response': response
})
def get_api_log(cls):
return cls.log

54
idoit_scaleup/base.py Executable file
View File

@@ -0,0 +1,54 @@
import json
import requests
from pprint import pprint
from .api_log import IDoitApiLog
from json.decoder import JSONDecodeError
class IDoitApiBase:
def __init__(self, cfg):
self.cfg = cfg
self.debug = False
def set_debug_mode(self, debug=True):
self.debug = debug
def xml_rpc_call(self, method, params, debug=False):
headers = {'content-type': 'application/json'}
payload = {
"method": method,
"params": params,
"jsonrpc": "2.0",
"id": 1,
}
basic_auth = (self.cfg['user'], self.cfg['password'])
params['apikey'] = self.cfg['api_key']
try:
response = requests.post(
self.cfg['jrpc_url'],
data=json.dumps(payload),
auth=basic_auth,
headers=headers
).json()
except JSONDecodeError:
print('JSON DECODE ERROR')
print('Url')
print(self.cfg['jrpc_url'])
print('Payload')
payload['params']['apikey'] = 'xxx'
pprint(payload)
response = {}
IDoitApiLog.instance().append_api_log(
self.cfg['jrpc_url'], payload, response)
if self.debug or debug or 'error' in response.keys():
print('Url')
print(self.cfg['jrpc_url'])
print('Payload')
payload['params']['apikey'] = 'xxx'
pprint(payload)
print('Resonse')
pprint(response)
return response

13
idoit_scaleup/cat_access.py Executable file
View File

@@ -0,0 +1,13 @@
from .consts import C__CATG__ACCESS
from .category import IDoitCategory
class IDoitAccess(IDoitCategory):
CATEGORY = C__CATG__ACCESS
def __init__(self, cfg):
super().__init__(cfg, self.CATEGORY)
def convert_field_with_name_primary(self, data):
return int(data['primary']['value'])

View File

@@ -0,0 +1,42 @@
from .consts import C__CATG__APPLICATION
from .category import IDoitCategory
from copy import deepcopy
class IDoitApplication(IDoitCategory):
CATEGORY = C__CATG__APPLICATION
def __init__(self, cfg):
super().__init__(cfg, self.CATEGORY)
# FIXME Skip, must be implemented later
def convert_field_with_name_assigned_license(self, data):
return 0
# FIXME Skip, must be implemented later
def convert_field_with_name_assigned_database_schema(self, data):
return 0
# FIXME Skip, must be implemented later
def convert_field_with_name_assigned_it_service(self, data):
return 0
def convert_field_with_name_assigned_version(self, data):
return int(data['assigned_version']['ref_id'])
def convert_field_with_name_bequest_nagios_services(self, data):
return int(data['bequest_nagios_services']['value'])
# def fix_obj(self, cdata):
# if ('assigned_version' in cdata.keys()) and (cdata['assigned_version'] is not None):
# cdata['assigned_version'] = str(cdata['assigned_version'])
# def save_category(self, objId, data):
# cdata = deepcopy(data)
# self.fix_obj(cdata)
# return super().save_category(objId, cdata)
# def update_category(self, objId, data):
# cdata = deepcopy(data)
# self.fix_obj(cdata)
# return super().update_category(objId, cdata)

31
idoit_scaleup/cat_connector.py Executable file
View File

@@ -0,0 +1,31 @@
from .consts import C__CATG__CONNECTOR
from .category import IDoitCategory
from pprint import pprint
class IDoitConnector(IDoitCategory):
CATEGORY = C__CATG__CONNECTOR
def __init__(self, cfg):
super().__init__(cfg, self.CATEGORY)
def convert_field_with_name_assigned_category(self, data):
return data['assigned_category']['const']
def convert_field_with_name_assigned_connector(self, data):
return self.conv_array_field('assigned_connector', data, 'ref_id')
def convert_field_with_name_cable_connection(self, data):
return self.conv_array_field('cable_connection', data, 'id')
def convert_field_with_name_relation_direction(self, data):
return int(data['relation_direction']['id'])
def convert_field_with_name_connector_sibling(self, data):
return int(data['connector_sibling']['id'])
def save_category_if_changed(self, objId, data):
raise Exception(
'Funktioniert nur wenn es nur eine Kategorie gibt, ' +
'muss mit ID spezifiziert werden')

13
idoit_scaleup/cat_cpu.py Executable file
View File

@@ -0,0 +1,13 @@
from .consts import C__CATG__CPU
from .category import IDoitCategory
class IDoitCpu(IDoitCategory):
CATEGORY = C__CATG__CPU
def __init__(self, cfg):
super().__init__(cfg, self.CATEGORY)
def convert_field_with_name_frequency(self, data):
return float(data['frequency']['title'])

41
idoit_scaleup/cat_ip.py Executable file
View File

@@ -0,0 +1,41 @@
from .consts import C__CATG__IP
from .category import IDoitCategory
class IDoitIP(IDoitCategory):
CATEGORY = C__CATG__IP
def __init__(self, cfg):
super().__init__(cfg, self.CATEGORY)
def convert_field_with_name_primary(self, data):
if data['primary']['value']==None:
return False
return int(data['primary']['value'])
def convert_field_with_name_active(self, data):
if data['active']['value']==None:
return False
return int(data['active']['value'])
def convert_field_with_name_use_standard_gateway(self, data):
if data['use_standard_gateway']['value']==None:
return False
return int(data['use_standard_gateway']['value'])
def convert_field_with_name_ipv4_address(self, data):
return data['ipv4_address']['ref_title']
def convert_field_with_name_ipv6_address(self, data):
return data['ipv6_address']['ref_title']
def convert_field_with_name_assigned_port(self,data):
return data['assigned_port']['title']
def convert_field_with_name_dns_domain(self, data):
rtn=[]
if 'dns_domain' in data and data['dns_domain'] is not None:
for ele in data['dns_domain']:
rtn.append(ele['title'])
return rtn

42
idoit_scaleup/cat_location.py Executable file
View File

@@ -0,0 +1,42 @@
from .consts import C__CATG__LOCATION
from .category import IDoitCategory
from pprint import pprint
from copy import deepcopy
class IDoitLocation(IDoitCategory):
CATEGORY = C__CATG__LOCATION
def __init__(self, cfg):
super().__init__(cfg, self.CATEGORY)
def convert_field_with_name_pos(self, data):
return int(data['pos']['visually_from'])
def convert_field_with_name_latitude(self, data):
if data['latitude'] == '':
return None
return float(data['latitude'])
def convert_field_with_name_longitude(self, data):
if data['longitude'] == '':
return None
return float(data['longitude'])
def fix_empty_position(self, data):
for pos_key in ['latitude', 'longitude']:
if not (pos_key in data):
data[pos_key] = None
elif data[pos_key] == '':
data[pos_key] = None
def save_category(self, objId, data):
cdata = deepcopy(data)
self.fix_empty_position(cdata)
return super().save_category(objId, cdata)
def update_category(self, objId, data):
cdata = deepcopy(data)
self.fix_empty_position(cdata)
return super().update_category(objId, cdata)

13
idoit_scaleup/cat_memory.py Executable file
View File

@@ -0,0 +1,13 @@
from .consts import C__CATG__MEMORY
from .category import IDoitCategory
class IDoitMemory(IDoitCategory):
CATEGORY = C__CATG__MEMORY
def __init__(self, cfg):
super().__init__(cfg, self.CATEGORY)
def convert_field_with_name_capacity(self, data):
return float(data['capacity']['title'])

40
idoit_scaleup/cat_network.py Executable file
View File

@@ -0,0 +1,40 @@
from .consts import C__CATS__NET
from .category import IDoitCategory
from pprint import pprint
from copy import deepcopy
from ipaddress import IPv4Network
from ipaddress import IPv6Network
class IDoitNetwork(IDoitCategory):
CATEGORY = C__CATS__NET
def __init__(self, cfg):
super().__init__(cfg, self.CATEGORY)
def convert_field_with_name_layer2_assignments(self, data):
rtn = []
for ele in data['layer2_assignments']:
rtn.append(int(ele['id']))
return rtn
def fix_mask_and_range(self, data):
net_str=f"{data['address']}/{data['cidr_suffix']}"
if int(data['type'])==1:
net= IPv4Network(net_str)
elif int(data['type'])==1000:
net= IPv6Network(net_str)
data['netmask']= str(net.netmask)
data['range_from'] = str(net[0])
data['range_to'] = str(net[-1])
def save_category(self, objId, data):
cdata = deepcopy(data)
self.fix_mask_and_range(cdata)
return super().save_category(objId, cdata)
def update_category(self, objId, data):
cdata = deepcopy(data)
self.fix_mask_and_range(cdata)
return super().update_category(objId, cdata)

View File

@@ -0,0 +1,64 @@
from .consts import C__CATG__NETWORK_LOG_PORT, C__CATG__IP, C__CATG__NETWORK_PORT
from .category import IDoitCategory
from copy import deepcopy
class IDoitNetworkLogicalPort(IDoitCategory):
CATEGORY = C__CATG__NETWORK_LOG_PORT
def __init__(self, cfg):
super().__init__(cfg, self.CATEGORY)
def convert_field_with_name_active(self, data):
return int(data['active']['value'])
def convert_field_with_name_interface(self, data):
if len(data['interface']) == 0:
return None
return int(data['interface'][0]['id'])
def convert_field_with_name_addresses(self, data):
return self.convert_list(data['addresses'])
def convert_field_with_name_layer2_assignment(self, data):
if data['layer2_assignment'] == []:
return None
# else:
raise Exception('unknown conversion ', data)
def convert_field_with_name_assigned_connector(self, data):
return self.conv_array_field('assigned_connector', data, 'ref_id')
def convert_field_with_name_net(self, data):
return self.convert_list(data['net'])
def save_category_if_changed(self, objId, data):
raise Exception(
'Funktioniert nur wenn es nur eine Kategorie gibt, ' +
'muss mit ID spezifiziert werden')
def fix_obj(self, cdata):
if ('interface' in cdata.keys()) and (cdata['interface'] is not None):
cdata['interface'] = "%d_C__CATG__NETWORK_INTERFACE" % cdata['interface']
if ('addresses' in cdata.keys()) and (cdata['addresses'] is not None):
rtn = []
for ele in cdata['addresses']:
rtn.append(str(ele))
cdata['addresses'] = rtn
if ('ports' in cdata.keys()) and (cdata['ports'] is not None):
rtn = []
for ele in cdata['ports']:
rtn.append("%d" % (ele))
cdata['ports'] = rtn
def save_category(self, objId, data):
cdata = deepcopy(data)
self.fix_obj(cdata)
return super().save_category(objId, cdata)
def update_category(self, objId, data):
cdata = deepcopy(data)
self.fix_obj(cdata)
return super().update_category(objId, cdata)

View File

@@ -0,0 +1,69 @@
from .consts import C__CATG__NETWORK_PORT
from .category import IDoitCategory
from copy import deepcopy
class IDoitNetworkPort(IDoitCategory):
CATEGORY = C__CATG__NETWORK_PORT
def __init__(self, cfg):
super().__init__(cfg, self.CATEGORY)
def convert_field_with_name_active(self, data):
return int(data['active']['value'])
def convert_field_with_name_interface(self, data):
if len(data['interface']) == 0:
return None
return int(data['interface'][0]['id'])
def convert_field_with_name_speed(self, data):
return float(data['speed']['title'])
def convert_field_with_name_cable(self, data):
return self.conv_array_field('cable', data, 'id')
def convert_field_with_name_addresses(self, data):
return self.convert_list(data['addresses'])
def convert_field_with_name_layer2_assignment(self, data):
if data['layer2_assignment'] == []:
return None
# else:
raise Exception('unknown conversion ', data)
def convert_field_with_name_assigned_connector(self, data):
return self.conv_array_field('assigned_connector', data, 'ref_id')
def convert_field_with_name_relation_direction(self, data):
return int(data['relation_direction']['id'])
def save_category_if_changed(self, objId, data):
raise Exception(
'Funktioniert nur wenn es nur eine Kategorie gibt, ' +
'muss mit ID spezifiziert werden')
def fix_obj(self, cdata):
#if ('interface' in cdata.keys()) and (cdata['interface'] is not None):
# cdata['interface'] = "%d_C__CATG__NETWORK_INTERFACE" % cdata['interface']
if ('addresses' in cdata.keys()) :
if cdata['addresses'] is None:
cdata['addresses'] = None
# FIXME Das geht im Moment nicht. siehe Idoit Bug #20429 (sanders)
else:
rtn = []
for ele in cdata['addresses']:
rtn.append(str(ele))
cdata['addresses'] = rtn
def save_category(self, objId, data):
cdata = deepcopy(data)
self.fix_obj(cdata)
return super().save_category(objId, cdata)
def update_category(self, objId, data):
cdata = deepcopy(data)
self.fix_obj(cdata)
return super().update_category(objId, cdata)

View File

@@ -0,0 +1,13 @@
from .consts import C__CATG__POWER_CONSUMER
from .category import IDoitCategory
class IDoitPowerConsumer(IDoitCategory):
CATEGORY = C__CATG__POWER_CONSUMER
def __init__(self, cfg):
super().__init__(cfg, self.CATEGORY)
def convert_field_with_name_active(self, data):
return int(data['active']['value'])

62
idoit_scaleup/cat_racktables.py Executable file
View File

@@ -0,0 +1,62 @@
from .consts import C__CATG__CUSTOM_FIELDS_RACKTABLES
from pprint import pprint
from .category import IDoitCategory
class Racktables(IDoitCategory):
CATEGORY = C__CATG__CUSTOM_FIELDS_RACKTABLES
def __init__(self, cfg):
super().__init__(cfg, self.CATEGORY)
self.rt_link = ''
self.rt_id = ''
self.rt_type = ''
self.rt_content = ''
for field in self.fields:
title = self.fields[field]['title']
if title == 'Racktables URL':
self.rt_link = field
if title == 'Racktables ID':
self.rt_id = field
if title == 'Racktables Object Type':
self.rt_type = field
if title == 'Racktables Inhalt':
self.rt_content = field
if ((self.rt_link == '') or
(self.rt_id == '') or
(self.rt_type == '') or
(self.rt_content == '')):
raise Exception('Object nicht deifinert')
def save_category(self, objId, data):
mydata = {}
if 'id' in data.keys():
mydata[self.rt_id] = data['id']
if 'link' in data.keys():
mydata[self.rt_link] = data['link']
if 'type' in data.keys():
mydata[self.rt_type] = data['type']
if 'content' in data.keys():
mydata[self.rt_content] = data['content']
if 'description' in data.keys():
mydata['description'] = data['description']
return super().save_category(objId, mydata)
def convert_incomming_category(self, data):
rtn = {}
if self.rt_id in data.keys():
rtn['id'] = data[self.rt_id]
if self.rt_link in data.keys():
rtn['link'] = data[self.rt_link]
if self.rt_type in data.keys():
rtn['type'] = data[self.rt_type]
if self.rt_content in data.keys():
rtn['content'] = data[self.rt_content]
if 'description' in data.keys():
rtn['description'] = data['description']
rtn['_data'] = data
return rtn

View File

@@ -0,0 +1,16 @@
from .consts import C__CATG__STORAGE_DEVICE
from .category import IDoitCategory
class IDoitStorageDevice(IDoitCategory):
CATEGORY = C__CATG__STORAGE_DEVICE
def __init__(self, cfg):
super().__init__(cfg, self.CATEGORY)
def convert_field_with_name_capacity(self, data):
return float(data['capacity']['title'])
def convert_field_with_name_hotspare(self, data):
return int(data['hotspare']['value'])

20
idoit_scaleup/cat_vlan.py Executable file
View File

@@ -0,0 +1,20 @@
from .consts import C__CATS__LAYER2_NET
from .category import IDoitCategory
from pprint import pprint
class IDoitVlan(IDoitCategory):
CATEGORY = C__CATS__LAYER2_NET
def __init__(self, cfg):
super().__init__(cfg, self.CATEGORY)
def convert_field_with_name_standard(self, data):
return int(data['standard']['value'])
def convert_field_with_name_layer3_assignments(self, data):
rtn = []
for ele in data['layer3_assignments']:
rtn.append(int(ele['id']))
return rtn

252
idoit_scaleup/category.py Executable file
View File

@@ -0,0 +1,252 @@
from pprint import pprint
from .base import IDoitApiBase
from copy import deepcopy
import json
class IDoitCategory(IDoitApiBase):
def __init__(self, cfg, obj_type: str):
super().__init__(cfg)
self.obj_type = obj_type
params = {
'category': obj_type
}
r = self.xml_rpc_call('cmdb.category_info', params)
self.fields = {}
for fieldname in r['result'].keys():
default = None
if 'default' in r['result'][fieldname]['ui']:
default = r['result'][fieldname]['ui']['default'] or None
self.fields[fieldname] = {
'data_type': r['result'][fieldname]['data']['type'],
'info_type': r['result'][fieldname]['info']['type'],
'ui_type': r['result'][fieldname]['ui']['type'],
'default': default,
'title': r['result'][fieldname]['info']['title']
}
def is_dialog_plus_field(self, fieldname):
return (self.fields[fieldname]['info_type'] == 'dialog_plus')
def save_category(self, objId, data):
sdata = deepcopy(data)
if "_data" in sdata.keys():
del (sdata["_data"])
params = {
"object": objId,
'category': self.obj_type,
'data': sdata}
if self.debug:
print('--Category Save---')
pprint(params)
print('--Category Save---')
return self.xml_rpc_call('cmdb.category.save', params)
def update_category(self, objId, data):
sdata = deepcopy(data)
if "_data" in sdata.keys():
del (sdata["_data"])
if "id" in sdata.keys():
sdata['category_id'] = sdata['id']
del (sdata["id"])
if sdata['category_id'] is None:
raise Exception('category_id is None')
params = {
"objID": objId,
'category': self.obj_type,
'data': sdata}
if self.debug:
print('--Category Update---')
pprint(params)
print('--Category Update---')
return self.xml_rpc_call('cmdb.category.update', params)
def read_categories(self, objId):
params = {
"objID": objId,
'category': self.obj_type,
}
r = self.xml_rpc_call('cmdb.category.read', params)
rtn = []
for item in r['result']:
rtn.append(self.convert_incomming_category(item))
return rtn
def read_category_by_id(self, objId, id):
for cat in self.read_categories(objId):
if cat['id'] == id:
return cat
# not found
return None
def delete_category(self, objId, id):
params = {
"objID": objId,
'category': self.obj_type,
'cateID': id
}
return self.xml_rpc_call('cmdb.category.delete', params)
def read_category(self, objId):
r = self.read_categories(objId)
if len(r) == 0:
return None
assert (len(r) == 1)
return r[0]
def conv_array_field(self, fieldname, data, ref_field):
if len(data[fieldname]) == 0:
return None
if type(data[fieldname]) is dict:
return int(data[fieldname][ref_field])
if len(data[fieldname]) != 1:
raise Exception('Field "%s" has more than one entry %s' %
(fieldname, json.dumps(data)))
return int(data[fieldname][0][ref_field])
def convert_list(self, list):
rtn = []
for ele in list:
rtn.append(int(ele['id']))
if len(rtn) == 0:
return None
return rtn
def convert_field(self, fieldname, data):
object_methods = [method_name for method_name in dir(self)
if callable(getattr(self, method_name))]
field = self.fields[fieldname]
if fieldname in data.keys():
if data[fieldname] is None:
return None
field_method_name = 'convert_field_with_name_%s' % fieldname
if field_method_name in object_methods:
method = getattr(self, field_method_name)
return method(data)
try:
if field['ui_type'] == 'popup':
if field['data_type'] == 'int':
return int(data[fieldname]['id'])
if field['ui_type'] == 'text':
if field['data_type'] == 'int':
return int(data[fieldname])
if field['data_type'] == 'double':
return float(data[fieldname])
if field['data_type'] == 'float':
return float(data[fieldname])
if field['data_type'] == 'link':
return data[fieldname]
if field['data_type'] == 'text':
return data[fieldname]
if field['ui_type'] == 'wysiwyg':
if field['data_type'] == 'text':
return data[fieldname]
if field['ui_type'] == 'textarea':
if field['data_type'] == 'text_area':
return data[fieldname]
if field['ui_type'] == 'dialog':
if field['data_type'] == 'int':
return int(data[fieldname]['id'])
if field['data_type'] == 'text':
return data[fieldname]['id']
if field['ui_type'] == 'f_dialog_list':
if field['data_type'] == 'int':
return self.convert_list(data[fieldname])
if field['ui_type'] == 'datetime':
if field['data_type'] == 'date_time':
try:
rtn=data[fieldname]['title']
except:
rtn=data[fieldname]
return rtn
if field['ui_type'] == 'numeric':
if field['data_type'] == 'text':
return float(data[fieldname])
except:
raise Exception('Wrong conversion ',
self.obj_type, fieldname, field, data)
raise Exception('Unknwown data_type/ ui_type',
self.obj_type, fieldname, field, data)
def convert_incomming_category(self, data):
rtn = {}
for fieldname in self.fields.keys():
rtn[fieldname] = self.convert_field(fieldname, data)
if 'id' in data.keys():
rtn['id'] = int(data['id'])
rtn['_data'] = data
return rtn
def partial_equal(self, obj1, obj2):
if isinstance(obj1, str):
return (obj1 == obj2)
if isinstance(obj1, int):
return (obj1 == obj2)
if obj1 is None and obj2 is None:
return True
if obj1 is None:
return False
if obj2 is None:
return False
if isinstance(obj1, list):
if isinstance(obj2, list):
if len(obj1) != len(obj2):
return False
for ele in obj1:
if ele not in obj2:
return False
return True
else:
return False
for key in obj1.keys():
if key not in obj2:
return False
if not (self.partial_equal(obj1[key], obj2[key])):
return False
return True
# Funktioniert nur wo es genau eine Kategory gibt
def save_category_if_changed(self, objId, data):
oldData = self.read_category(objId)
if not (self.partial_equal(data, oldData)):
print('save', objId, self.obj_type)
pprint(data)
print('old:')
pprint(oldData)
r = self.save_category(objId, data)
print(r)
def update_categorys(self, objId, equals_attr, new_data_arr):
old_data_arr = self.read_categories(objId)
for old_data in old_data_arr:
old_found = False
for new_data in new_data_arr:
if old_data[equals_attr] == new_data[equals_attr]:
old_found = True
if not (self.partial_equal(new_data, old_data)):
print('save', objId, self.obj_type)
pprint(new_data)
print('old:')
pprint(old_data)
new_data['id'] = old_data['id']
r = self.update_category(objId, new_data)
pprint(r)
if not old_found:
print('delete:', objId, self.obj_type)
pprint(old_data)
self.delete_category(objId, old_data['id'])
for new_data in new_data_arr:
new_found = False
for old_data in old_data_arr:
if old_data[equals_attr] == new_data[equals_attr]:
new_found = True
if not new_found:
print('save', objId, self.obj_type)
pprint(new_data)
r = self.save_category(objId, new_data)
pprint(r)

View File

@@ -0,0 +1,29 @@
from pprint import pprint
from .base import IDoitApiBase
class IDoitConditionalRead(IDoitApiBase):
def __init__(self, cfg):
super().__init__(cfg)
self.clear_search_list()
def clear_search_list(self):
self.search_list = []
def add_search_param(self, category: str, field: str, value: str, operator: str = None, compare: str = "=", ):
entry = {
'property': "%s-%s" % (category, field),
'comparison': compare,
'value': value,
}
if operator:
entry['operator'] = operator
self.search_list.append(entry)
def search(self):
params = {
'conditions': self.search_list,
}
rtn = self.xml_rpc_call('cmdb.condition.read', params)
return rtn['result']

38
idoit_scaleup/consts.py Executable file
View File

@@ -0,0 +1,38 @@
C__CATG__ACCESS = 'C__CATG__ACCESS'
C__CATG__APPLICATION = 'C__CATG__APPLICATION'
C__CATG__ADDRESS = 'C__CATG__ADDRESS'
C__CATG__CONNECTOR = 'C__CATG__CONNECTOR'
C__CATG__CPU = 'C__CATG__CPU'
#C__CATG__CUSTOM_FIELDS_RACKTABLES = 'C__CATG__CUSTOM_FIELDS_RACKTABLES'
C__CATG__FORMFACTOR = 'C__CATG__FORMFACTOR'
C__CATG__IDENTIFIER = 'C__CATG__IDENTIFIER'
C__CATG__IP = 'C__CATG__IP'
C__CATG__LOCATION = 'C__CATG__LOCATION'
C__CATG__MEMORY = 'C__CATG__MEMORY'
C__CATG__MODEL = 'C__CATG__MODEL'
C__CATG__NETWORK_LOG_PORT = 'C__CATG__NETWORK_LOG_PORT'
C__CATG__NETWORK_PORT = 'C__CATG__NETWORK_PORT'
C__CATG__POWER_CONSUMER = 'C__CATG__POWER_CONSUMER'
C__CATG__STORAGE_DEVICE = 'C__CATG__STORAGE_DEVICE'
C__CATS__ENCLOSURE = 'C__CATS__ENCLOSURE'
C__CATS__LAYER2_NET = 'C__CATS__LAYER2_NET'
C__CATS__NET = 'C__CATS__NET'
C__CATS__PERSON_MASTER = 'C__CATS__PERSON_MASTER'
C__OBJTYPE__BUILDING = 'C__OBJTYPE__BUILDING'
C__OBJTYPE__CABLE = 'C__OBJTYPE__CABLE'
C__OBJTYPE__CITY = 'C__OBJTYPE__CITY'
C__OBJTYPE__COUNTRY = 'C__OBJTYPE__COUNTRY'
C__OBJTYPE__ENCLOSURE = 'C__OBJTYPE__ENCLOSURE'
C__OBJTYPE__LAYER2_NET = 'C__OBJTYPE__LAYER2_NET'
C__OBJTYPE__LAYER3_NET = 'C__OBJTYPE__LAYER3_NET'
C__OBJTYPE__PATCH_PANEL = 'C__OBJTYPE__PATCH_PANEL'
C__OBJTYPE__PDU = 'C__OBJTYPE__PDU'
C__OBJTYPE__RACK_SEGMENT = 'C__OBJTYPE__RACK_SEGMENT'
C__OBJTYPE__ROOM = 'C__OBJTYPE__ROOM'
C__OBJTYPE__ROOM = 'C__OBJTYPE__ROOM'
C__OBJTYPE__SERVER = 'C__OBJTYPE__SERVER'
C__OBJTYPE__SWITCH = 'C__OBJTYPE__SWITCH'
C__OBJTYPE__WIRING_SYSTEM = 'C__OBJTYPE__WIRING_SYSTEM'
C__OBJTYPE__WHMCS_CUSTOMER = 'C__OBJTYPE__WHMCS_CUSTOMER'

67
idoit_scaleup/dialog.py Executable file
View File

@@ -0,0 +1,67 @@
from .base import IDoitApiBase
class IDoitDialog(IDoitApiBase):
def __init__(self, cfg, obj_type: str, property: str):
super().__init__(cfg)
self.obj_type = obj_type
self.property = property
self.cache = {}
def get_all(self):
if self.cache == {}:
params = {
'category': self.obj_type,
'property': self.property
}
r = self.xml_rpc_call('cmdb.dialog.read', params)
# Workaround für Ticket #22087
# https://help.i-doit.com/hc/en-us/requests/22087
if len(r['result'])==1:
if isinstance(r['result'][0],list):
r['result']=r['result'][0]
self.cache = r
else:
r = self.cache
return self.cache['result']
def get(self, value: str, parent: int = None):
for entry in self.get_all():
if parent is None:
if value == entry['title']:
return int(entry['id'])
else:
if (value == entry['title'] and
entry['parent']['id'] == str(parent)):
return int(entry['id'])
return None
def get_ignore_case(self, value: str, parent: int = None):
for entry in self.get_all():
title=entry['title'].lower()
if parent is None:
if value.lower() == title:
return int(entry['id'])
else:
if (value.lower() == title and
entry['parent']['id'] == str(parent)):
return int(entry['id'])
return None
def create(self, value: str, parent: int = None):
params = {
'category': self.obj_type,
'property': self.property,
'value': value
}
self.cache = {}
if parent is not None:
params['parent'] = parent
r = self.xml_rpc_call('cmdb.dialog.create', params)
return r['result']['entry_id']
def create_or_get_id(self, value: str, parent: int = None):
id = self.get(value, parent)
if id is None:
id = self.create(value, parent)
return id

98
idoit_scaleup/object.py Executable file
View File

@@ -0,0 +1,98 @@
from typing import List
from .base import IDoitApiBase
class IDoitObject(IDoitApiBase):
def __init__(self, cfg, obj_type: str):
super().__init__(cfg)
self.obj_type = obj_type
def get_by_title(self, title: str, categories: List = []):
params = {
'filter': {
'type': self.obj_type,
'title': title,
},
}
if len(categories) > 0:
params['categories'] = categories
rtn = self.xml_rpc_call('cmdb.objects', params)
if len(rtn['result']) == 0:
return None
else:
return rtn['result'][0]
def get_by_id(self, obj_id: str, categories: List = []):
params = {
'id': obj_id
}
if len(categories) > 0:
params['categories'] = categories
rtn = self.xml_rpc_call('cmdb.object', params)
return rtn['result']
def get_all(self, categories: List = [], ids = None):
params = {
'filter': {
'type': self.obj_type
},
}
if ids:
params['filter']['ids'] = ids
if len(categories) > 0:
params['categories'] = categories
rtn = self.xml_rpc_call('cmdb.objects', params)
return rtn['result']
def create_object_with_title(self, title: str):
params = {
'title': title,
'type': self.obj_type
}
return self.xml_rpc_call('cmdb.object.create', params)
def create_object_if_not_there(self, title):
obj = self.get_by_title(title)
if obj is None:
r = self.create_object_with_title(title)
print('-------------------')
print("%s (%s) " % (title, self.obj_type))
print('-------------------')
objId = r['result']['id']
else:
objId = obj['id']
return objId
def update_object(self, obj_id: str, title: str):
params = {
'id': obj_id,
'title': title,
}
return self.xml_rpc_call('cmdb.object.update', params)
def archive_object(self, obj_id: str):
params = {
'id': obj_id,
'status': 'C__RECORD_STATUS__ARCHIVED',
}
return self.xml_rpc_call('cmdb.object.delete', params)
def delete_object(self, obj_id: str):
params = {
'id': obj_id,
'status': 'C__RECORD_STATUS__DELETED',
}
return self.xml_rpc_call('cmdb.object.delete', params)
def purge_object(self, obj_id: str):
params = {
'id': obj_id,
'status': 'C__RECORD_STATUS__PURGE',
}
return self.xml_rpc_call('cmdb.object.delete', params)
def recycle_object(self, obj_id: str):
params = {
'id': obj_id,
}
return self.xml_rpc_call('cmdb.object.recycle', params)

12
idoit_scaleup/search.py Executable file
View File

@@ -0,0 +1,12 @@
from pprint import pprint
from .base import IDoitApiBase
class IDoitSearch(IDoitApiBase):
def search(self, search: str):
params = {
'q': search,
}
rtn = self.xml_rpc_call('idoit.search', params)
return rtn['result']