· 4 years ago · Mar 11, 2021, 06:42 PM
1import check_mk_web_api
2from settings import checkmk_url, cmk_site_name, aut_secret
3
4def api():
5 return check_mk_web_api.WebApi(checkmk_url + cmk_site_name + '/check_mk/webapi.py', username='automation', secret=aut_secret)
6
7import sys
8import json
9import os
10import re
11import copy
12from _defs import *
13from _gs_data import *
14from _nagios import *
15
16from unidecode import unidecode
17
18class CMKAPI:
19 app_hosts = api().get_all_hosts()
20 app_contactgroups = api().get_all_contactgroups()
21 app_folders = api().get_all_folders()
22 app_users = api().get_all_users()
23 app_tags = api().get_hosttags()
24
25 with open('/tmp/learn-ping-data.json') as f:
26 ping_data = json.loads(f.read())
27
28 def activate_changes(self):
29 try:
30 self.write_to_screen('Activating Changes...')
31 #print('Activating Changes...\t\t', end='', flush=True)
32 api().activate_changes(sites='', allow_foreign_changes=True)
33 self.write_to_screen('Done')
34 #print('Done')
35 except check_mk_web_api.CheckMkWebApiException as e:
36 if 'no changes to activate' in str(e):
37 print('No Changes to Activate')
38 return False
39 else:
40 print(e)
41 os._exit(1)
42
43 def check_activation_interval(self, idx):
44 self.activation_interval = 100
45 if idx % self.activation_interval == 0:
46 if idx != 0:
47 return self.activate_changes()
48
49 def write_to_screen(self, data):
50 # Return Same Line
51 sys.stdout.write("\r\x1b[K"+data.__str__())
52 sys.stdout.flush()
53
54 def output(self, idx, host):
55 #data = '%d\tHost: %s\tFolder: %s\tAttributes: %s' % (idx, host['hostname'], host['folder'], host['attributes']) # Full
56 #data = '%d\tHost: %s\tFolder: %s' % (idx, host['hostname'], host['folder']) # Brief
57 #data = str(idx) + str(host) # Debug Print
58 data = '%d\tHost: %s\tFolder: %s' % (idx, host['hostname'], host['folder'])
59 self.write_to_screen(data)
60
61 def output_user(self, idx, user_name):
62 data = '%d\tUser: %s' % (idx, user_name)
63 self.write_to_screen(data)
64
65 def action_host(self, hostlist, action):
66 hostlist_len = len(hostlist)
67 if hostlist_len > 0:
68 print('%s: %d' % (action.capitalize(), hostlist_len))
69 for idx, host in enumerate(hostlist):
70 self.check_activation_interval(idx)
71
72 if action == 'delete':
73 data = '%d\tHost: %s ... ' % (idx, hostname)
74 self.write_to_screen(data)
75 api().delete_host(host)
76 else:
77 self.output(idx, host)
78 if action == 'add':
79 api().add_host(host['hostname'], folder=host['folder'], **host['attributes'])
80 elif action == 'update':
81 api().edit_host(host['hostname'], host['unset_attributes'], **host['attributes'])
82 elif action == 'recreate':
83 api().delete_host(host['hostname'])
84 api().add_host(host['hostname'], folder=host['folder'], **host['attributes'])
85 return self.activate_changes()
86
87 def add_contact_group(self, cg):
88 try:
89 api().add_contactgroup(cg, cg)
90 except check_mk_web_api.CheckMkWebApiException as e:
91 if 'Sorry, there is already a group with that name' in str(e):
92 return
93 else:
94 print(e)
95 os._exit(1)
96
97 def add_ruleset(self, ruleset_name, ruleset):
98 api().set_ruleset(ruleset_name, ruleset)
99 print('Done')
100
101 def add_new_user(self, userlist):
102 userlist_len = len(userlist)
103 if userlist_len > 0:
104 print('Creating %d new Contact Users' % userlist_len)
105 for idx, user in enumerate(userlist):
106 user_name = list(user.keys())[0]
107 self.output_user(idx, user_name)
108 api().add_user(user_name, user_name, **user[user_name])
109
110 def update_existing_user(self, userlist):
111 userlist_len = len(userlist)
112 if userlist_len > 0:
113 print('Creating %d new Contact Users' % userlist_len)
114 for idx, user in enumerate(userlist):
115 user_name = list(user.keys())[0]
116 self.output_user(idx, user_name)
117 api().edit_user(user_name, user[user_name], unset_attributes=None)
118
119 def update_folders(self, folderlist):
120 list_len = len(folderlist)
121 if list_len > 0:
122 print('Updating relevant Location Tags')
123 self.update_location_tags(folderlist)
124 print('Updating %d folders' % list_len)
125 for folder_obj in folderlist:
126 for folder, data in folder_obj.items():
127 api().edit_folder(folder, **data)
128
129 # TAGS
130 # Host Type = self.get_tags(6)
131 # Location Code = self.get_tags(3)
132 # Location Code with ID Filter = self.get_tags_filtered(3, 'id')
133 # self.thing = self.get_tags(4)
134 def get_tags(self, group):
135 return self.app_tags['tag_groups'][group]['tags']
136
137 def get_tags_filtered(self, group, tag_filter):
138 return [ tag[tag_filter] for tag in self.get_tags(group) ]
139
140 def update_location_tags(self, folderlist):
141 #tags = []
142 for folder_obj in folderlist:
143 for folder, data in folder_obj.items():
144 tag_template = {
145 'aux_tags': [],
146 'id': data['tag_location'],
147 'title': data['tag_location']
148 }
149 if tag_template['id'] not in self.get_tags_filtered(3, 'id'):
150 #tags.append(tag_template)
151 self.app_tags['tag_groups'][3]['tags'].append(tag_template)
152 #self.app_tags['tag_groups'][3]['tags'].extend(tags)
153 api().set_hosttags(self.app_tags)
154
155
156class CMKData: # Class for Storing all the shared dictionaries
157
158 site_name = cmk_site_name
159
160 template_host_dict = inherit_attributes_from_template('host')
161 template_service_dict = inherit_attributes_from_template('service')
162 unique_labels = []
163 unique_host_contactgroup_labels = []
164 unique_service_contactgroup_labels = []
165
166 # ContactGroups
167 contactgroups_hostlist = {}
168 contactgroups_add_list = []
169 contactgroups_generated_list = []
170 contactgroups_generated_add_list = []
171 user_based_contactgroup_list = []
172 hosts_with_contactgroups = []
173 repeated_services = {}
174
175 # Hosts Data
176 hosts = []
177 hosts_update_list = []
178 hosts_new_list = []
179 hosts_delete_list = []
180 recreate_host_list = []
181
182
183 # Folder Data
184 folder_update_list = []
185
186 # Service Adapter
187 native_service_adapter = {
188 'check_ssl': {
189 'rule': {
190 'condition': {
191 'host_name': []
192 },
193 'value': {
194 'host': {'address': '$HOSTNAME$'},
195 'name': 'SSL: Certificate Check',
196 'mode': ('cert', {'cert_days': (10, 5)})
197 }
198 },
199 'hostlist': [],
200 'parameters': {
201 'custom_attributes': [],
202 'labels': [],
203 'template': {
204 'value': [],
205 'condition': {
206 'service_description': [
207 {
208 '$regex': ''
209 }
210 ],
211 'host_name': []
212 },
213 'options': {
214 'description': 'Custom Attributes for Service - '
215 }
216 }
217 },
218 'unique_values': {
219 'custom_attributes': [],
220 'labels': []
221 }
222 }
223 }
224
225class CMKTools:
226 def remove_non_ascii(self, text):
227 return unidecode(text)
228
229 def convert_nagios_csv_field_to_list(self, field):
230 field = self.process_nagios_field(field)
231 return(field.split(','))
232
233 def tag_list(self):
234 device_type_tag_list = []
235 #print(api.get_hosttags()['tag_groups'][6]['tags'])
236 for tag in api().get_hosttags()['tag_groups'][6]['tags']:
237 device_type_tag_list.append(tag['id'])
238 return device_type_tag_list
239
240 def check_nrpe_condition(self, service):
241 if 'check_nrpe' in service['check_command']:
242 if service['cmk_command']:
243 return True
244 else:
245 return False
246 else:
247 return True
248
249 def process_nagios_field(self,field):
250 field = field.split(';')[0].strip(' ').replace('+','')
251 return field
252
253
254class CMK(CMKData, CMKTools, CMKAPI):
255 def inherit_from_nagios_template(self, record, record_type):
256 ##################### TEMPLATE LOOKUP ###################
257 # This section flattens Nagios|Naemon Templates into Service Rules which are handled by Labels i.e. max_check_attempts
258
259 # Lookup Parent Template Config, and ovewrite for each service.
260 #template_inherited = self.template_service_dict[record['use']].copy()
261 template_inherited = self.template_service_dict[record['use']].copy() if record_type == 'service' else self.template_host_dict[record['use']].copy()
262 # Updates values if they exist in service = however template_inherited will be missing some empty values
263 #template_inherited.update({k:v for k,v in self.record.items() if v}) #d2.update({k:v for k,v in d1.iteritems() if v}) #template_inherited_service.update(service)
264 for key, value in record.items():
265 if value:
266 if key == 'contact_groups':
267 contactgroup_list = self.convert_nagios_csv_field_to_list(value)
268 template_contactgroup_list = self.convert_nagios_csv_field_to_list(template_inherited[key])
269 #print(self.record['use'], contactgroup_list, template_contactgroup_list, template_inherited[key])
270 if '+' in value:
271 #print(contactgroup_list)
272 for contactgroup in contactgroup_list:
273 contactgroup = self.process_nagios_field(contactgroup)
274 #print(contactgroup)
275 if contactgroup not in template_contactgroup_list:
276 template_contactgroup_list.append(contactgroup)
277 template_inherited.update({key:','.join(template_contactgroup_list)})
278 #print(self.record['use'], template_inherited[key])
279 else:
280 template_inherited.update({key: value})
281 else:
282 template_inherited.update({key: value})
283 #print(template_inherited)
284 return template_inherited
285
286class CMKHost(CMK):
287 def __init__(self, record, settings):
288 #self.idx = idx
289 self.record = record
290 self.settings = settings
291 self.template_inherited_host = self.inherit_from_nagios_template(record, 'host')
292 self.extra_hostVars()
293 self.device_folder = self.folder_config()
294 self.folder = self.country + '/' + self.location + '/' + self.device_folder.replace(' ','_')
295 self.unset_attributes = ['site'] + self.check_unset_host_rtt()
296 self.skip_specified_tags = True
297 self.skip_empty_labels = True
298 self.labels = self.get_labels()
299 self.attributes = self.get_attributes()
300 self.tags = self.get_tags()
301 self.set_obj()
302
303 def extra_hostVars(self):
304 # Split Country & Location
305 try: self.country, self.location = self.record["TN_Host_Location_Complete"].split("-", 1)
306 except ValueError: self.country, self.location = 'UNK','UNK'
307 # If country & location still blank, Set to UNK
308 if self.country == '': self.country = 'UNK'
309 if self.location == '': self.location = 'UNK'
310 # If Host Type is Empty, set to UNK (Should be Default)
311 if self.record['TN_Host_Type'] == '':
312 self.record['TN_Host_Type'] = 'UNK'
313 # Set Default Value for Alert Desig
314 if self.record['TN_Alert_Designation'] == '#N/A':
315 self.record['TN_Alert_Designation'] = 'NONE'
316
317 def folder_config(self):
318 # Check if LAN or WAN, and put in MPLS Folder
319 if 'LAN' in self.record['TN_Host_Type'] or 'WAN' in self.record['TN_Host_Type']:
320 return 'MPLS/' + self.record['TN_Host_Type']
321 else:
322 return self.record['TN_Host_Type']
323
324 def get_unset_attributes(self):
325 if self.settings['Unset RTT if Defined at Country/Location Folder Level']:
326 return ['site'] + self.check_unset_host_rtt()
327 else: return ['site']
328
329 def check_unset_host_rtt(self):
330 location_folder_path = self.country + '/' + self.location
331
332 if location_folder_path in self.app_folders.keys():
333 if ('rtt_warn' in self.app_folders[location_folder_path]
334 and 'rtt_crit' in self.app_folders[location_folder_path]):
335 return ['rtt_warn', 'rtt_crit']
336 else: return []
337 else: return []
338
339 def get_labels(self):
340 # Start Empty Dictionary
341 labels = {}
342 # Cycle _defs.py list for allowed Labels
343 #for key in add_labels:
344 for key in host_table['Add Labels'].keys():
345 # If Record has value on key
346 #if self.record[key]:
347 if (
348 key in self.template_inherited_host.keys()
349 and self.template_inherited_host[key]
350 ):
351 #labels.update(label_lookup_table[key][key + '_' + str(self.record[key])]['label'])
352 # labels.update(label_lookup_table[key][key + '_' + str(self.template_inherited_host[key])]['label'])
353 #print(self.record['address'], key)
354 label_dict = {key: str(self.template_inherited_host[key])}
355 labels.update(label_dict)
356 #self.add_to_unique_labels({key: str(self.template_inherited_host[key])})
357 # Add to unique_host_labels
358 if label_dict not in self.unique_labels:
359 self.unique_labels.append(label_dict)
360
361 # Get Hosts with Special check_commands
362 #if self.record['check_command']:
363 # Add check_tcp label for hosts that need it
364 # if 'check_tcp' in self.record['check_command']:
365 #value = self.record['check_command'].split('!')[1]
366 #label_dict = {'check_tcp': value}
367 # label_dict = {'check_tcp': 'true'}
368 # labels.update(label_dict)
369
370 # Cycle CMK Labels
371 for key in host_table['Add CMK Labels'].keys():
372 # Separate routine for contact_groups - as this requires to be split on ,
373 #if key == 'contact_groups':
374 prefix = 'cont_grp-' if key == 'contact_groups' else 'cont_only-'
375
376 if (
377 key in self.template_inherited_host.keys()
378 and self.template_inherited_host[key]
379 ):
380
381 # Check if List
382 if ',' in self.template_inherited_host[key]:
383 #for item in self.convert_nagios_csv_field_to_list(self.record[key]):
384 for item in self.convert_nagios_csv_field_to_list(self.template_inherited_host[key]):
385 if item != '':
386 if key == 'contact_groups':
387 label_dict = {prefix + item: item}
388 if key == 'contacts':
389 item = item.strip('+')
390 label_dict = {prefix + item: prefix + item}
391 labels.update(label_dict)
392 # Add to unique_host_contactgroup_labels
393 if label_dict not in self.unique_host_contactgroup_labels:
394 self.unique_host_contactgroup_labels.append(label_dict)
395 else:
396 #labels.update({'contactgroup': self.record[key]})
397 if key == 'contact_groups':
398 label_dict = {prefix + self.template_inherited_host[key]: self.template_inherited_host[key]}
399 if key == 'contacts':
400 self.template_inherited_host[key] = self.template_inherited_host[key].strip('+')
401 label_dict = {prefix + self.template_inherited_host[key]: prefix + self.template_inherited_host[key]}
402 #label_dict = {prefix + self.template_inherited_host[key]: self.template_inherited_host[key]}
403 labels.update(label_dict)
404 # Add to unique_host_contactgroup_labels
405 if label_dict not in self.unique_host_contactgroup_labels:
406 self.unique_host_contactgroup_labels.append(label_dict)
407 # Return filled labels Dictionary
408 return labels
409
410 def get_attributes(self):
411 self.attributes = {}
412 # Cycle through Row Keys by Column addressable by Heading
413 for key in self.record:
414 #print(key)
415 if self.hasValue_notForbidden_inTagLookupTable(key):
416 continue
417 else:
418 self.set_attributes_from_dict(key)
419 # Check Command Attributes
420 if self.record['check_command']: # If Check Command Value is set, remove the IP requirement from the host
421 if 'dummy_success' in self.record['check_command']:
422 self.attributes.update({'tag_address_family': 'no-ip'})
423 if 'check_tcp' in self.record['check_command']:
424 value = self.record['check_command'].split('!')[1]
425 label_dict = {'check_tcp': value}
426 self.labels.update(label_dict) # Setting a label here, but labes should already be defined
427 self.attributes['tcp_port'] = value
428 if label_dict not in self.unique_labels:
429 self.unique_labels.append(label_dict)
430
431 # Ensure RTT Has a default Value
432 if 'rtt_warn' not in self.attributes.keys() or 'rtt_crit' not in self.attributes.keys():
433 #if [rtt not in self.attributes.keys() for rtt in ['rtt_warn', 'rtt_crit']]:
434 # Update Default Values
435 #print(self.obj['hostname'], 'Default RTT Not set, W:C Values: 50:80')
436 self.attributes['rtt_warn'] = 100
437 self.attributes['rtt_crit'] = 120
438 return self.attributes
439
440 def get_tags(self):
441 # Append net_ to device_type tag, as duplicates in CheckMK between a builtin immutable
442 # Network tag attribute, ensure lower, and any spaces replaced with '_'
443 tags = {}
444 for tag in tag_lookup_table:
445 if self.record[tag]:
446 if tag_lookup_table[tag] == 'tag_device_type':
447 if any(x in self.record[tag] for x in ['LAN', 'WAN']):
448 # Append net_ for tag recognition
449 data = 'net_' + self.record[tag].lower()
450 else:
451 # Replace any Spaces with underscore
452 data = self.record[tag].lower().replace(' ','_')
453 else:
454 data = self.record[tag]
455 # SKIP RULE
456 if self.skip_specified_tags:
457 if tag_lookup_table[tag] not in skip_host_tags:
458 tags[tag_lookup_table[tag]] = data
459 else:
460 tags[tag_lookup_table[tag]] = data
461 return tags
462
463 def set_obj(self):
464 # Base Template
465 self.obj = {
466 #"hostname": re.sub(r"https?://", '', self.record["address"]).replace('/','').replace(' ',''),
467 'hostname': re.sub(r"https?://", '', self.record["address"]).split('/')[0].replace(' ',''),
468 'folder': self.folder,
469 'unset_attributes': self.unset_attributes,
470 'attributes': {
471 'site': self.site_name, # <------ REMOVE PARENT REF
472 #'site': '',
473 #'tag_agent': 'cmk-agent'
474 'labels': self.labels,
475 **self.attributes,
476 **self.tags
477 },
478 'create_folders': '1'
479 }
480
481 def hasValue_notForbidden_inTagLookupTable(self, key):
482 sr = 0
483 # If record contains value
484 if self.record[key]: pass
485 else: sr += 1
486 # Check if Key is in Ignore List
487 if key not in forbidden_heading: pass
488 else: sr += 1
489 # Check if Key is in Tag Lookup Table (Convert Na(emon|gios) headings to Check_MK)
490 if key not in tag_lookup_table: pass
491 else: sr += 1
492 # Main Logic
493 if sr > 0: return True
494 else: return False
495
496 def set_attributes_from_dict(self, key):
497 # Check if Key is in Lookup Table (Convert Na(emon|gios) headings to Check_MK)
498 if key in key_lookup_table:
499 effective_key = key_lookup_table[key]
500 else:
501 effective_key = key
502 # Add Changes
503 self.attributes[effective_key] = self.record[key]
504
505 def process_host(self):
506 #if self.enabled_addressSet():
507 if self.record['address'] != '':
508 # Add Host to relevant list and send to API
509 self.make_list()
510 else:
511 return
512
513 def make_list(self):
514 # Remove any attributes we must define; and Unset at apply
515 for val in self.obj['unset_attributes']:
516 self.obj['attributes'].pop(val, None)
517
518 ##### HOSTS #####
519 # Add Host to ALL list
520 self.hosts.append(copy.deepcopy(self.obj['hostname']))
521
522 # Add to Host New / Host Update List
523 if self.obj['hostname'] in self.app_hosts.keys():
524 # Set Existing Host
525 existing = self.app_hosts[self.obj['hostname']]['attributes']
526 # Remove 'meta_data'
527 existing.pop('meta_data', None)
528
529 # Check if current Host Template is a subset of the existing Host.
530 # Unset attribute 'tag_address_family' if it's set but not required
531 # Recreate the host if folder needs changing
532 if self.folder not in self.app_hosts[self.obj['hostname']]['path']:
533 print(self.folder, self.app_hosts[self.obj['hostname']]['path'])
534 self.recreate_host_list.append(copy.deepcopy(self.obj))
535 # Remove address for hosts that shouldn't be pingable
536 elif (
537 'tag_address_family' in existing.keys()
538 and 'tag_address_family' not in self.obj['attributes'].keys()
539 ):
540 self.obj['unset_attributes'].append('tag_address_family')
541 self.hosts_update_list.append(copy.deepcopy(self.obj))
542 # If Attributes Match; Pass
543 elif self.obj['attributes'].items() <= existing.items():
544 value = { k : existing[k] for k in set(existing) - set(self.obj['attributes']) }
545 for val in self.obj['unset_attributes']:
546 if val in value.keys():
547 update = True
548 break
549 else: update = False
550 if update:
551 self.hosts_update_list.append(copy.deepcopy(self.obj))
552 else: pass #print('Nothing to change')
553 else:
554 self.hosts_update_list.append(copy.deepcopy(self.obj))
555 else:
556 self.hosts_new_list.append(copy.deepcopy(self.obj))
557
558 ##### CONTACT GROUPS #####
559 #Populate Contactgroups List
560 if self.record['contact_groups']:
561 self.hosts_with_contactgroups.append(self.record)
562
563 def set_delete_list(self):
564 # Check if any Hosts need to be added to delete list
565 for host in self.app_hosts:
566 if host not in self.hosts:
567 self.hosts_delete_list.append(host)
568
569class CMKFolder(CMK):
570 def __init__(self, folder):
571 self.folder = folder
572 self.folder_template = self.app_folders[self.folder].copy()
573 self.folder_template.update({
574 **self.update_location_tag(),
575 **self.update_rtt_custom_attributes(),
576 #**self.update_country_tag()
577 })
578 self.append_folderlist()
579
580 def is_not_base_folder(self):
581 if '/' in self.folder: return True
582 else: return False
583
584 def is_location(self):
585 if self.is_not_base_folder():
586 if self.folder.count('/') == 1:
587 self.location = self.folder.rsplit('/', 1)[1]
588 return True
589 else: return False
590
591 def in_ping_data(self):
592 if self.is_location():
593 if self.location in self.ping_data.keys(): return True
594 else: return False
595
596 def is_country(self):
597 if not self.is_not_base_folder(): return True
598 else: return False
599
600 def update_location_tag(self):
601 if self.is_location(): return {'tag_location': self.location }
602 else: return {}
603
604 def update_rtt_custom_attributes(self):
605 if self.in_ping_data():
606 return {
607 'rtt_warn': self.ping_data[self.location]['Suggested']['WARN'],
608 'rtt_crit': self.ping_data[self.location]['Suggested']['CRIT']
609 }
610 else: return {}
611
612 def update_country_tag(self):
613 if self.is_country(): return {'tag_country': self.folder }
614 else: return {}
615
616 def template_not_match_existing(self):
617 if self.app_folders[self.folder].items() >= self.folder_template.items(): return False
618 else: return True
619
620 def append_folderlist(self):
621 if self.template_not_match_existing():
622 self.folder_update_list.append({self.folder: self.folder_template})
623
624
625# class CMKTag(CMK):
626# def __init__(self):
627# self.host = self.get_tags(6)
628# self.location = self.get_tags(3)
629# self.location_list = self.get_tags_filtered(3, 'id')
630# self.thing = self.get_tags(4)
631
632class CMKService(CMK):
633
634 # Define Lists
635 ruleType_collection = []
636 service_label_collection = []
637 uniq_labels = []
638 custom_service_attribute_list = []
639 # Base Dict for custom_attribute
640
641 template_dict = inherit_attributes_from_template('service')
642 # Retrieve the Base Template
643 base_template = template_dict['centrica_generic_service']
644 # Create dict for Rules
645
646 def __init__(self):
647 self.base_template_custom_attribute = {
648 'value': [],
649 'condition': {},
650 'options': {
651 'description': 'Base Template Service Custom Attributes'
652 }
653 }
654 self.base_service_ruleset = self.get_base_template()
655
656 def get_base_template(self):
657 ############################### Create Base Template Ruleset ################################
658 # Create Template Ruleset
659 # Create dict for Rules
660 base_service_ruleset = {}
661 # Cycle through base_template
662 for nagios_ruleType, value in self.base_template.items():
663 # Set Custom Attributes
664 # If the key is in Custom Attributes, make template and add to list
665 if nagios_ruleType in service_table['Custom Attributes']:
666
667 attribute_tuple = (nagios_ruleType, value)
668 self.base_template_custom_attribute['value'].append(tuple(attribute_tuple))
669 #base_custom_attributes.append(base_template_custom_attribute)
670 #print(base_template_custom_attribute)
671 # If the key has a service lookup - add to Service.
672 # Set Parameters
673 try:
674 cmk_ruleType = 'extra_service_conf:' + nagios_ruleType
675 cmk_lookup = service_table['Add Labels']
676
677 # Convert the Values of the rules based on the requirements for each rule type.
678 if cmk_lookup[nagios_ruleType] == 'str':
679 rule_value = str(value)
680 elif cmk_lookup[nagios_ruleType] == 'float':
681 rule_value = float(value)
682 elif cmk_lookup[nagios_ruleType] == 'int':
683 rule_value = int(value)
684 base_template_rule = {
685 'value': rule_value,
686 'condition': {},
687 'options': {
688 'description': 'Base Template Service Rule - ' + cmk_ruleType + ' Value - ' + value,
689 'comment': 'Automatic rule creation.'
690 }
691 }
692 #print(base_template_rule)
693 # Operation Complete - Add Template to our Lookup Dictionary
694 base_service_ruleset[cmk_ruleType] = base_template_rule
695 except KeyError:
696 continue
697 return base_service_ruleset
698
699 def skip_condition(self, service):
700 if (
701 service['CheckMK'] != 'Yes'
702 #and service['CI Active?'] == 'Yes'
703 and service['check_command'] != ''
704 #and 'check_nrpe' not in service['check_command']
705 and self.check_nrpe_condition(service)
706 and 'cmd_check_nwc_health' not in service['check_command']
707 ):
708 return True
709 else: return False
710
711
712class Parameters(CMKService): # Requires CMKHost has run, to generate unique_label List
713 def __init__(self, parameter_type):
714 self.parameter_type = parameter_type
715 self.label_list = self.unique_labels if parameter_type == 'host' else self.uniq_labels # Tody - unique_labels == host uniq_labels == service
716 self.nagios_rulePrefix = 'extra_host_conf:' if parameter_type == 'host' else 'extra_service_conf:' # Set Prefix to avoid repetition in the _defs.py
717 self.parameter_rulesets = {}
718 self.service_name_conditions = {} # List of Service names to use as conditions in case Service labels can't be used
719 self.parameter_ruleFolder = ''
720 #self.cmd_lookup = nagios_cmd_lookup[self.parameter_type]
721 self.cmd_lookup = host_table['Add Labels'] if parameter_type == 'host' else service_table['Add Labels']
722 self.process_labels()
723
724 def process_labels(self):
725 # Process Label list for hosts which was generated during the initial Host Cycle.
726 for self.label in self.label_list:
727 for self.nagios_ruleType, self.value in self.label.items():
728 self.cmk_ruleType = self.nagios_rulePrefix + self.nagios_ruleType
729 if self.nagios_ruleType == 'check_tcp':
730 self.cmk_ruleType = self.nagios_ruleType
731 self.formatted_value = self.get_value_type() # Type formatted Value that CMK Expects
732 if self.parameter_type == 'service': # Break out for service to set service names as conditions instead of Labels
733 self.get_service_name_conditions()
734 self.get_host_name_conditions()
735 template_rule = self.set_rule_template()
736 # Temp Workaround to set the check_tcp CMK Service Name
737 if self.nagios_ruleType == 'check_tcp':
738 self.cmk_ruleType = 'host_check_commands'
739 self.set_ruleset_dict() # Ensure Ruleset Dict is set to: ruleType: 'folder' {}
740 self.parameter_rulesets[self.cmk_ruleType][self.parameter_ruleFolder].append(template_rule) # Add Rule to Ruleset
741
742 def get_value_type(self):
743 if self.cmd_lookup[self.nagios_ruleType] == 'str':
744 rule_value = str(self.value)
745 elif self.cmd_lookup[self.nagios_ruleType] == 'float':
746 rule_value = float(self.value)
747 elif self.cmd_lookup[self.nagios_ruleType] == 'int':
748 rule_value = int(self.value)
749 if self.nagios_ruleType == 'check_tcp':
750 if self.value == '$_HOSTPRXYPORT$':
751 rule_value = ('custom', '$USER1$/check_tcp -H $HOSTNAME$ -p $HOST_PROXY_PORT$')
752 else:
753 rule_value = ('tcp', int(self.value))
754 return rule_value
755
756 def set_ruleset_dict(self):
757 try:
758 self.parameter_rulesets[self.cmk_ruleType]
759 except KeyError:
760 self.parameter_rulesets[self.cmk_ruleType] = {self.parameter_ruleFolder: []}
761
762 def set_rule_template(self):
763 template_rule = {
764 'value': self.formatted_value,
765 'condition': {
766 #'host_labels': { self.nagios_ruleType: self.value}, # Host Condition
767 #'service_description': service_names[nagios_ruleType + value] # Service Condition
768 },
769 'options': {
770 'description': 'Label - ' + self.cmk_ruleType + ' Rule - ' + self.value,
771 'comment': 'Automatic rule creation.'
772 }
773 }
774 if self.parameter_type == 'host':
775 condition = {
776 'host_labels': {
777 self.nagios_ruleType: self.value
778 }
779 }
780 elif self.parameter_type == 'service':
781 condition = {
782 'service_description': self.service_name_conditions[self.nagios_ruleType + self.value],
783 **self.host_definition
784 }
785 # Set Condition
786 template_rule['condition'] = condition
787 return template_rule
788
789 def get_service_name_conditions(self):
790 self.service_name_conditions[self.nagios_ruleType + self.value] = []
791 for s in self.service_label_collection:
792 if self.label.items() <= s['value'].items():
793 service_definition = { '$regex' : s['condition']['service_description'][0]['$regex'] }
794 if service_definition not in self.service_name_conditions[self.nagios_ruleType + self.value]:
795 self.service_name_conditions[self.nagios_ruleType + self.value].append(service_definition)
796 def get_host_name_conditions(self):
797 self.host_definition = {}
798 for s in self.service_label_collection:
799 #print(self.label, s['condition'])
800 if self.label.items() <= s['value'].items():
801 # print(self.label, s['condition'])
802 try:
803 hostlist = s['condition']['host_name']
804 print(hostlist)
805 except KeyError:
806 return
807 # print('hi')
808 # self.host_definition = {'host_name': hostlist}
809
810
811class ConGRP(CMKService):
812 def __init__(self, data):
813 self.data = data
814 self.get_contactgroup_hosts()
815
816 def check_contactgroups_not_exist_in_app(self, cg):
817 if cg not in self.app_contactgroups.keys():
818 self.contactgroups_add_list.append(cg)
819
820 def get_contactgroup_hosts(self):
821 for cg in self.data:
822 self.contactgroups_hostlist[cg] = []
823 for host in self.hosts_with_contactgroups:
824 if cg in host['contact_groups']:
825 if host ['address'] in self.app_hosts.keys():
826 self.contactgroups_hostlist[cg].append(host['address'])
827 if self.check_contactgroups_not_exist_in_app(cg):
828 self.contactgroups_add_list.append(cg)
829
830 def make_generated_contactgroups_list(self, data):
831 for cg in data:
832 generated_cg = 'cont_only-' + cg['contact_name'].replace('æ', 'a')
833 self.contactgroups_generated_list.append(generated_cg)
834 if self.check_contactgroups_not_exist_in_app(generated_cg):
835 self.contactgroups_generated_add_list.append(generated_cg)
836
837
838class ContactGRP(CMKService):
839 def __init__(self, grp_type):
840 self.contactgroup_rules = []
841 self.grp_type = grp_type
842 self.service_name_conditions = {} # List of Service names to use as conditions in case Service labels can't be used
843 self.label_dict = self.unique_host_contactgroup_labels if self.grp_type == 'host' else self.unique_service_contactgroup_labels
844 self.process_labels()
845
846 def process_labels(self):
847 for self.label in self.label_dict:
848 for self.label_name, self.label_value in self.label.items():
849 #self.label_value = 'cont_only-' + self.label_value if 'cont_only-' in self.label_name
850 if self.grp_type == 'service': # Break out for service to set service names as conditions instead of Labels
851 self.get_service_name_conditions()
852 template_rule = self.set_template_rule()
853 self.contactgroup_rules.append(template_rule)
854
855 def set_template_rule(self):
856 template_rule = {
857 'condition': {
858 #'host_name': hostlist
859 #'host_labels' : {'cont_grp-' + cg: cg}
860 },
861 'value': self.label_value,
862 'options': {
863 'description': 'Set host Contactgroup to ' + self.label_value
864 }
865 }
866 if self.grp_type == 'host':
867 condition = {
868 'host_labels': self.label
869 }
870 elif self.grp_type == 'service':
871 condition = {
872 'service_description': self.service_name_conditions[self.label_name + self.label_value]
873 }
874 template_rule['condition'] = condition
875 return template_rule
876
877 def get_service_name_conditions(self):
878 self.service_name_conditions[self.label_name + self.label_value] = []
879 for s in self.service_label_collection:
880 if self.label.items() <= s['value'].items():
881 service_definition = { '$regex' : s['condition']['service_description'][0]['$regex'] }
882 if service_definition not in self.service_name_conditions[self.label_name + self.label_value]:
883 self.service_name_conditions[self.label_name + self.label_value].append(service_definition)
884
885
886class CMKServiceRule(CMKService):
887 def __init__(self, service, hostnames):
888 self.service = service
889 # Define Hostnames list by Collection Lookup
890 self.hostnames = hostnames
891 # Define Service Description (visible in Service View), it could be either 'service_description' or 'name' but 'service_description' is preferred
892 self.service_description = self.remove_non_ascii(service['service_description'] if service['service_description'] else service['name'])
893 # Define Service Description (visible in Service Only)
894 self.description = self.remove_non_ascii(service['display_name'] + '\n' + service['notes'])
895 # Nagios Template Lookup
896 self.template_inherited_service = self.inherit_from_nagios_template(service, 'service')
897 # Define Template for the Service Rule
898 # Example can be obtained using api().get_ruleset('custom_checks')
899 if self.service_description not in self.repeated_services.keys():
900 self.repeated_services[self.service_description] = 1
901 else:
902 self.repeated_services[self.service_description] += 1
903 self.template_custom_checks = {
904 'condition': {
905 'host_name': self.hostnames
906 },
907 'value': {
908 'service_description': self.service_description,
909 'command_line': self.service['cmk_check_command'],
910 'has_perfdata': True
911 },
912 'options': {
913 #'description': service['display_name'] + '\n' + service['notes']
914 'description': self.description
915 }
916 }
917 # Define Template for Custom Service Attributes
918 # Example can be obtained using api().get_ruleset('custom_service_attributes')
919 self.template_custom_attributes = {
920 #'value': [],
921 'value': self.get_service_attributes(),
922 'condition': {
923 'service_description': [
924 {
925 '$regex': self.service_description
926 }
927 ]
928 },
929 'options': {
930 'description': 'Custom Attributes for Service - ' + self.service_description
931 }
932 }
933 ###################### SERVICE PARAMETER LABELS ####################
934 # This section creates labels for rules which are chosen to be processed as labels.
935 # Idea being that we need to label each service, so that the rule itself only has to have the label as a condition, not the regex for the service name.
936 # Define Template for Label
937 # Example can be obtained using api().get_ruleset('service_label_rules')
938 self.template_label = {
939 'condition': {
940 'service_description': [
941 {
942 '$regex': self.service_description
943 }
944 ]
945 },
946 "value": {},
947 'options': {
948 'description': 'Labels for Service - ' + self.service_description
949 }
950 }
951 self.get_service_labels()
952 # Native Check Adapter
953 self.get_native_service_adapter()
954
955 def get_service_attributes(self):
956 attribute_list = []
957 # Cycle Fields that we have identified as needing Custom Attributes
958 for attribute in service_table['Custom Attributes']:
959 # If Custom Attribute Field is set for Service: Add Tuple to template
960 if self.service[attribute]:
961 # Define Tuple to be appended to the 'value' field in our Template
962 attribute_tuple = (str(self.remove_non_ascii(attribute)), str(self.remove_non_ascii(self.service[attribute])))
963 # Append the Tuple
964 attribute_list.append(attribute_tuple)
965 #self.custom_service_attribute_template['value'].append(attribute_tuple)
966 return attribute_list
967
968 def get_service_labels(self):
969 labels = {}
970 # Cycle Fields that we have identified as needing Labels
971 for label in service_table['Add Labels'].keys():
972
973 # Because of Template inheritance - we drop fields that do not have values;
974 # So rather than checking if they contain values, we need to try to access the value, and skip iteration on 'KeyError'
975 try:
976 service_label = self.template_inherited_service[label]
977 # Check Service Label Contains Value, if not = skip
978 if service_label:
979 # Strip anything after the ';' char, which is used for Comments in Nagios|Naemon; Strip Whitespace
980 label_data = str(service_label).split(';')[0].strip(' ')
981 # If Remaining data is empty = skip
982 if label_data == '':
983 continue
984
985 # Append Label & Label Data to the Label Template
986 label_dict = {label: label_data}
987 labels.update(label_dict)
988 #self.template_label['value'][label] = label_data
989
990 # Define a k,v object, and check if it's in uniq_labels. Append the object if it isn't
991 lbl_obj_solo = {label: str(service_label)}
992 if lbl_obj_solo not in self.uniq_labels:
993 self.uniq_labels.append({label: label_data})
994 except KeyError:
995 continue
996 #labels = {}
997 for key in service_table['Add CMK Labels'].keys():
998 prefix = 'cont_grp-' if key == 'contact_groups' else 'cont_only-'
999 #if key == 'contact_groups':
1000 if (
1001 key in self.template_inherited_service.keys()
1002 and self.template_inherited_service[key]
1003 ):
1004
1005 # Check if List
1006 if ',' in self.template_inherited_service[key]:
1007 #for item in self.convert_nagios_csv_field_to_list(self.record[key]):
1008 for item in self.convert_nagios_csv_field_to_list(self.template_inherited_service[key]):
1009 if item != '':
1010 if key == 'contact_groups':
1011 label_dict = {prefix + item: item}
1012 if key == 'contacts':
1013 item = item.strip('+')
1014 label_dict = {prefix + item: prefix + item}
1015 labels.update(label_dict)
1016 # Add to unique_service_contactgroup_labels
1017 if label_dict not in self.unique_service_contactgroup_labels:
1018 self.unique_service_contactgroup_labels.append(label_dict)
1019 else:
1020 #labels.update({'contactgroup': self.record[key]})
1021 if key == 'contact_groups':
1022 label_dict = {prefix + self.template_inherited_service[key]: self.template_inherited_service[key]}
1023 if key == 'contacts':
1024 self.template_inherited_service[key] = self.template_inherited_service[key].strip('+')
1025 label_dict = {prefix + self.template_inherited_service[key]: prefix + self.template_inherited_service[key]}
1026 #label_dict = {'cont_grp-' + self.template_inherited_service[key]: self.template_inherited_service[key]}
1027 labels.update(label_dict)
1028 # Add to unique_service_contactgroup_labels
1029 if label_dict not in self.unique_service_contactgroup_labels:
1030 self.unique_service_contactgroup_labels.append(label_dict)
1031 self.template_label['value'] = labels
1032
1033 def get_native_service_adapter(self):
1034 # CUSTOM SERVICE
1035 for cmk_service in self.native_service_adapter:
1036 if cmk_service in self.service['check_command']:
1037 service_name = self.native_service_adapter[cmk_service]['rule']['value']['name']
1038 # Add Hosts to Hostlist for Single Rule Creation
1039 template_list = self.native_service_adapter[cmk_service]['hostlist']
1040 template_list.extend([host for host in self.hostnames if host not in template_list])
1041 self.native_service_adapter[cmk_service]['hostlist'] = template_list
1042
1043 # Prepare Common Value Template
1044 cv_template = self.native_service_adapter[cmk_service]['parameters']['template']
1045 #cv_template['condition']['host_name'] = self.hostnames
1046 cv_template['condition']['service_description'][0]['$regex'] = service_name
1047 cv_template['options']['description'] = 'Custom Attributes for Service - ' + service_name
1048
1049 # Set Custom Attributes for Each host that has customization
1050 if self.template_custom_attributes['value'] != []:
1051 nc_custom_attributes = copy.deepcopy(cv_template)
1052 nc_custom_attributes['value'] = self.template_custom_attributes['value']
1053
1054 self.flatten_service(cmk_service, nc_custom_attributes, 'custom_attributes')
1055
1056 if self.template_label['value'] != {}:
1057 nc_template_label = copy.deepcopy(cv_template)
1058 nc_template_label['value'] = self.template_label['value']
1059
1060 self.flatten_service(cmk_service, nc_template_label, 'labels')
1061
1062 def flatten_service(self, cmk_service, template, template_type):
1063 # Add to Unique ${cmk_service} list - this flattens the parameters to just Uniques, and matches against the flattened service, and flattened hosts per unique parameter set.
1064 if template['value'] not in self.native_service_adapter[cmk_service]['unique_values'][template_type]:
1065 self.native_service_adapter[cmk_service]['unique_values'][template_type].append(template['value'])
1066 template['condition']['host_name'] = self.hostnames
1067 self.native_service_adapter[cmk_service]['parameters'][template_type].append(template)
1068 else:
1069 for idx, entry in enumerate(self.native_service_adapter[cmk_service]['parameters'][template_type]):
1070 if entry['value'] == template['value']:
1071 existing_hostlist = self.native_service_adapter[cmk_service]['parameters'][template_type][idx]['condition']['host_name']
1072 filtered_hostlist = [host for host in self.hostnames if host not in existing_hostlist]
1073 self.native_service_adapter[cmk_service]['parameters'][template_type][idx]['condition']['host_name'].extend(filtered_hostlist)
1074
1075
1076class User(CMK):
1077 def __init__(self, data):
1078 self.data = data
1079
1080 self.all_users = []
1081 self.add_user = []
1082 self.update_user = []
1083 self.delete_user = []
1084
1085 self.user_based_contactgroup_list = []
1086
1087 self.process_data()
1088
1089 def process_data(self):
1090 for self.record in self.data:
1091 if self.record['CI Active?'] == 'Yes' and self.record['email'] != '':
1092 self.user_name = 'cont_only-' + self.record['contact_name'].replace('æ', 'a')
1093 self.record_contactgroup_list = self.record['contactgroups'].strip(' ').strip('+').split(',')
1094 self.record_contactgroup_list.append(self.user_name)
1095 self.user_based_contactgroup_list.append(self.user_name)
1096 self.user_template = self.get_user_template()
1097 #print(self.app_users)
1098 self.make_lists()
1099
1100 def get_user_template(self):
1101 user = { self.user_name: {
1102 "force_authuser_webservice": False,
1103 "locked": True,
1104 "roles": [
1105 "guest"
1106 ],
1107 "alias": self.record['alias'].replace('æ', 'a'),
1108 "force_authuser": False,
1109 "ui_theme": None,
1110 "contactgroups": self.record_contactgroup_list,
1111 "disable_notifications": {},
1112 "start_url": None,
1113 "enforce_pw_change": False,
1114 "num_failed_logins": 0,
1115 "serial": 1,
1116 "password": "$5$rounds=535000$/zv/llLZp0o4YXz1$Tdyvl1MFzN1LvoyAEADEPkVYOpsHNJ4PjoHisZ3aDqC",
1117 #'password':
1118 "pager": "",
1119 "email": self.record['email'].strip(' ').replace('æ', 'a'),
1120 "last_pw_change": 1612266456,
1121 "fallback_contact": False
1122 },
1123 }
1124 return user
1125
1126 def make_lists(self):
1127 self.all_users.append(self.user_template)
1128 # Check if User exists in CheckMK
1129 if self.user_name in self.app_users.keys():
1130 # User Exists
1131 # Remove the Password from the Dict, as we don't want to include that in our match
1132 self.user_template[self.user_name].pop('password')
1133 if self.user_template[self.user_name].items() <= self.app_users[self.user_name].items():
1134 #if self.user_template.items() <= self.app_users.items():
1135 # Template Matches Existing User
1136 pass
1137 else:
1138 # Template does not match user
1139 self.update_user.append(self.user_template)
1140
1141 else:
1142 #print('user %s does not exist... Adding User' % self.user_name)
1143 self.add_user.append(self.user_template)
1144 # User does not exist