├── .gitignore ├── README.md ├── README_cmk_host_agent.md ├── README_cmk_host_plugins.md ├── README_cmk_host_registration.md ├── ansible-example.yml ├── hosts.ini └── roles ├── cmk_host_agent ├── defaults │ └── main.yml ├── files │ └── check_mk.ini ├── meta │ └── main.yml ├── tasks │ ├── Debian-tasks.yml │ ├── RedHat-tasks.yml │ ├── Windows-tasks.yml │ └── main.yml └── vars │ └── cmk_agent_generic.yml ├── cmk_host_plugins ├── defaults │ └── main.yml ├── files │ ├── apache_status.cfg │ ├── ceph.cfg │ ├── dnsclient.cfg │ ├── jar_signature.cfg │ ├── logwatch.cfg │ └── mk_oracle_cfg.ps1 ├── meta │ └── main.yml ├── tasks │ ├── Linux-install.yml │ ├── Linux-main.yml │ ├── Linux-remove.yml │ ├── Linux-search.yml │ ├── Windows-install.yml │ ├── Windows-main.yml │ ├── Windows-remove.yml │ ├── Windows-search.yml │ └── main.yml └── vars │ ├── Linux-vars.yml │ └── Windows-vars.yml └── cmk_host_registration ├── defaults └── main.yml ├── handlers └── main.yml ├── library ├── checkmk_changes.py ├── checkmk_host.py └── checkmk_services.py ├── meta └── main.yml ├── module_utils └── checkmk_api.py └── tasks └── main.yml /.gitignore: -------------------------------------------------------------------------------- 1 | .*.swp 2 | .*.swo 3 | *~ 4 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Ansible roles and modules 2 | 3 | # This project is archived! 4 | We archived this project in favor of our very own official 5 | [Ansible Collection](https://github.com/tribe29/ansible-collection-tribe29.checkmk). We are confident, that it will 6 | deliver just as much value, as this project, while being up-to-date 7 | with the Ansible ecosystem. 8 | See you on the other side! 9 | 10 | # Original README 11 | 12 | check**mk** already provides the needed APIs to automate the basic 13 | configuration of your monitoring. With this project we want to create and 14 | share roles and modules of ansible to simplify your first steps with 15 | ansible in combination with check**mk**. 16 | 17 | ## Getting started 18 | 19 | At the beginning this project contains a simple **playbook** as an 20 | example, a **hosts.ini** and the needed roles to execute this playbook. 21 | Things to do for the first test run: 22 | * In each role: adjust the defaults, if needed. At the moment you still 23 | need to set the check**mk** version manually. 24 | * In the host.ini: Fill it with your hosts and remove the examples 25 | * In the playbook: Find the tags to run the roles you want 26 | 27 | Execute your playbook with a bunch of testhosts: 28 | 29 | ansible-playbook -i hosts.ini ansible-example.yml --tags all 30 | 31 | ## Further information to each role 32 | 33 | * [Installation of check**mk** agent](./README_cmk_host_agent.md) 34 | * [Installation of check**mk** agent plugins](./README_cmk_host_plugins.md) 35 | * [Registration of hosts in check**mk**](./README_cmk_host_registration.md) 36 | -------------------------------------------------------------------------------- /README_cmk_host_agent.md: -------------------------------------------------------------------------------- 1 | # Installation of the check**mk** agent 2 | 3 | With this role you are able to rollout the check**mk** agent on your 4 | hosts. 5 | 6 | This role currently covers 7 | * apt based systems like Debian or Ubuntu 8 | * rpm based systems like RedHat Enterprise Linux or CentOS 9 | * Microsoft Windows based systems that support winrm 10 | 11 | ## Variables that may need manual interaction 12 | 13 | Currently you need to specifiy the check**mk** manually to get this role 14 | work correctly. But this may change in the future. You are able to set the 15 | following default variables: 16 | 17 | * `cmk_version: "1.5.0p13"` 18 | * `cmk_site_url: "https://myserver.corp.org/mysite"` 19 | * `cmk_host_linux_tmp: "/tmp"` 20 | * `cmk_host_windows_tmp: "C:\\Users\\{{ ansible_user }}\\AppData\\Local\\Temp"` 21 | 22 | ## Wishlist of future features that may be added 23 | 24 | * Support for agent query via ssh 25 | * Support for automatic firewall configuration 26 | * Support for automatic SELinux configuration 27 | * Support for custom config files on the Windows agent 28 | * Support for new Windows agent 29 | * Support for more operating systems 30 | * ??? 31 | -------------------------------------------------------------------------------- /README_cmk_host_plugins.md: -------------------------------------------------------------------------------- 1 | # Installation of the check**mk** agent plugins 2 | 3 | With this role you are able to rollout check**mk** agent plugins on your 4 | hosts. Needed plugins (and it's configuration files) will be installed and 5 | obsolete plugins will be removed. This role makes currently only sense, if 6 | you want to ensure some standard plugins on all your hosts. If you have 7 | a generic configuration for a plugin, you may also want them to be rolled 8 | out. 9 | 10 | This role will not be useful if you need to have many individual 11 | configurations on your hosts or if you want your plugins only on a group 12 | of hosts. This may change in the future. 13 | 14 | This role currently covers the plugin rollout based on 15 | * Processes 16 | * Existing files 17 | * Installed Software 18 | 19 | It is additionally possible to enforce plugins. 20 | 21 | ## Basic default variables 22 | 23 | * `cmk_site_url: "https://myserver.corp.org/mysite"` 24 | * `cmk_agent_lnx_path: "/usr/lib/check_mk_agent"` 25 | * `cmk_agent_win_path: "C:\\Program Files (x86)\\check_mk"` 26 | * `by_process: true`: Turn detection by process on or off 27 | * `by_package: false`: Turn detection by installed software on or off 28 | * `by_files: false`: Turn detection by existing files on or off 29 | 30 | ## Plugin definition 31 | 32 | Only specified plugins will be considered for a rollout. If you don't need 33 | a plugin, simply remove the definition. Otherwise add a plugin definition 34 | and it's conditions, if you need a specific plugin. The name should be the 35 | file name of the plugin. Conditions are all optionally except you will 36 | need to specifiy at least one per plugin. 37 | 38 | Here is an example definition: 39 | 40 | cmk_host_plugins: 41 | Linux: 42 | apache_status: 43 | cmd: apache 44 | pkg: apache2 45 | cfg: apache_status.cfg 46 | mk_cups_queues: 47 | path: /usr/bin/lpstat 48 | mk_logwatch: 49 | cfg: logwatch.cfg 50 | force: true 51 | mk_logins: 52 | force: true 53 | Windows: 54 | mk_oracle.ps1: 55 | cmd: oracle 56 | cfg: mk_oracle_cfg.ps1 57 | 58 | Please consider, that 59 | * Process matches all process that contains that string 60 | * The package definition needs an exact match 61 | * The configuration file needs to be placed into the files folder 62 | 63 | ## Wishlist of possibly features 64 | 65 | * Prevent plugin installation for groups of hosts 66 | * Allow individual configuration files for groups of hosts 67 | * A module to identify needed plugins? 68 | * ??? 69 | -------------------------------------------------------------------------------- /README_cmk_host_registration.md: -------------------------------------------------------------------------------- 1 | # Registration of a host on a checkmk site 2 | 3 | This role ensures that a host is present on a check**mk** site. It adds 4 | a host if it is not present or readds the host, if it was deleted or 5 | modified. Additionally there will be a service discovery and the 6 | activation of changes. 7 | 8 | This role currently covers: 9 | * Keep a host with it's configuration present or absent in a check**mk** 10 | site 11 | * Do a service discovery for this host if resolving present/absent results 12 | in changes 13 | * Activate the changes on the site if resolving present/absent results in 14 | changes 15 | 16 | ## Variables that may need manual interaction 17 | 18 | * `cmk_site_url: "https://myserver.corp.org/mysite"` 19 | * `cmk_site_default_folder: "ansible"` 20 | 21 | ## Wishlist of features that may be added 22 | 23 | * More user friendly support of optional attributes 24 | * Support for cluster hosts? 25 | * ??? 26 | -------------------------------------------------------------------------------- /ansible-example.yml: -------------------------------------------------------------------------------- 1 | --- 2 | - hosts: g_cmk_hosts 3 | gather_facts: smart 4 | tags: [all, agent] 5 | roles: 6 | - cmk_host_agent 7 | 8 | - hosts: g_cmk_hosts 9 | gather_facts: smart 10 | tags: [all, plugins] 11 | roles: 12 | - cmk_host_plugins 13 | 14 | - hosts: g_cmk_hosts 15 | gather_facts: smart 16 | tags: [all, register] 17 | roles: 18 | - cmk_host_registration 19 | -------------------------------------------------------------------------------- /hosts.ini: -------------------------------------------------------------------------------- 1 | [g_cmk_hosts:children] 2 | g_cmk_windows 3 | g_cmk_linux 4 | 5 | 6 | [g_cmk_windows] 7 | win-local ansible_host=192.168.56.30 8 | 9 | [g_cmk_linux] 10 | debian-host ansible_host=192.168.56.10 11 | centos-host ansible_host=192.168.56.11 12 | ubuntu-host ansible_host=192.168.56.12 13 | 14 | 15 | [g_cmk_windows:vars] 16 | ansible_user=administrator 17 | ansible_password=Passw0rd! 18 | ansible_port=5986 19 | ansible_connection=winrm 20 | ansible_winrm_transport=ntlm 21 | ansible_winrm_Server_cert_validation=ignore 22 | 23 | [g_cmk_linux:vars] 24 | ansible_user=root 25 | ansible_port=22 26 | ansible_private_key_file=~/.ssh/ansible_rsa 27 | ansible_ssh_common_args='-o StrictHostKeyChecking=yes' 28 | -------------------------------------------------------------------------------- /roles/cmk_host_agent/defaults/main.yml: -------------------------------------------------------------------------------- 1 | --- 2 | # Site variables 3 | cmk_version: "1.5.0p13" 4 | cmk_site_url: "http://192.168.56.1/mysite" 5 | 6 | # temp directories for files 7 | cmk_host_linux_tmp: "/tmp" 8 | cmk_host_windows_tmp: "C:\\Users\\{{ ansible_user }}\\AppData\\Local\\Temp" 9 | 10 | -------------------------------------------------------------------------------- /roles/cmk_host_agent/files/check_mk.ini: -------------------------------------------------------------------------------- 1 | # Example configuration for Windows agent 2 | [global] 3 | # Restrict access to certain IP addresses 4 | # If ipv6 is enabled, all listed ipv4 adresses are also accepted as 5 | # source adresses in their ipv6-mapped form. I.e. if 6 | # 192.168.56.0/24 is listed, connections from ::ffff:c0a8:3800/120 7 | # are also possible 8 | # only_from = 127.0.0.1 192.168.56.0/24 ::1 9 | 10 | # Change port where the agent is listening ( default 6556 ) 11 | # port = 6556 12 | 13 | # Disable ipv6 support. By default, ipv4 is always supported 14 | # and ipv6 is enabled additionally if supported by the system. 15 | # ipv6 = no 16 | 17 | # Do only execute programs and scripts with 18 | # the following suffixes (in local and plugins). 19 | # Per default all extensions except txt and dir 20 | # are being executed. 21 | # execute = exe bat vbs 22 | 23 | # Run async scripts in parallel (to each other). Default is "sequential", 24 | # which means the scripts are run asynchronously to the agent itself but 25 | # one after the other. Setting this to parallel may improve the delay before 26 | # new data is reported but may also lead to the agent having more noticable 27 | # impact on the system performance 28 | # async_script_execution = parallel 29 | 30 | # Restrict the following configuration variables 31 | # in [global] to the following hosts 32 | # host = winsrv* zab???ad 33 | 34 | # Just output certain sections (e.g. for upper hosts) 35 | # sections = check_mk winperf 36 | 37 | # Disable specific sections (overrules sections parameter) 38 | # disabled_sections = logfiles 39 | 40 | # output sections in realtime updates. Please note that not all 41 | # sections can be used in realtime updates, the following is the 42 | # complete list 43 | # realtime_sections = mem df winperf_processor 44 | 45 | # specifies how long (in seconds) realtime updates are sent to 46 | # the last monitoring system that requested an update. 47 | # this should be longer than the request frequency (usually 48 | # one minute). 49 | # Please note that any new request cancels previous realtime 50 | # update schedules, so no more than one update is sent per second, 51 | # no matter if this timeout is "too high" or how many monitoring 52 | # systems are querying the agent. 53 | # realtime_timeout = 90 54 | 55 | # enable/disable encryption of regular agent output (default: disabled) 56 | # encrypted = yes 57 | 58 | # enable/disable encryption of realtime updates (default: enabled) 59 | # encrypted = yes 60 | 61 | # passphrase for encrypted communication. 62 | # passphrase = secret 63 | 64 | # Write a logfile for tackling down crashes of the agent 65 | # crash_debug = yes 66 | 67 | # by default the agent flushes the socket for each agent section. 68 | # this is mostly for debugging purposes in case the agent is slow 69 | # to respond. 70 | # Disabling this may (very) slightly reduce network traffic. 71 | # section_flush = no 72 | 73 | [winperf] 74 | # Select counters to extract. The following counters 75 | # are needed by checks shipped with check_mk. 76 | # counters = 10332:msx_queues 77 | # counters = 638:tcp_conn 78 | 79 | # Instead of specifying the counter start index, the name of the performance 80 | # counter can be used. 81 | # counters = Terminal Services:ts_sessions 82 | 83 | [logfiles] 84 | # # Define textfiles to be monitored, separated by | 85 | # textfile = C:\tmp logfiles\message_*.log|D:\log\sample.txt 86 | # # Set patterns for defined textfiles 87 | # ok = Successfully logged in* 88 | # crit = Error in* 89 | # warn = Unable to contact* 90 | # ignore = Backup * saved 91 | 92 | # # Define additional textfiles with different patterns 93 | # textfile = C:\tmp\memo.udf 94 | # # Set patterns for defined textfile 95 | # warn = *overdue* 96 | # ok = *mail sent* 97 | 98 | # # handling of the log can be customized through tags prepended to the name 99 | # # 100 | # # don't send context lines around relevant lines 101 | # textfile = nocontext d:\log\sample.txt 102 | # # read new files from the first line. Otherwise the agent will start at the 103 | # # last line at the time the agent first sees the file 104 | # textfile = from_start d:\log\sample*.txt 105 | # # treat the file as a rotated log (one where in certain intervals a new file is 106 | # # created and the previous file is at some point moved away). 107 | # # In this case all files matching this pattern are treated as one service 108 | # # and the agent will try to read each file to the end and then continue to the 109 | # # next newer one. 110 | # textfile = rotated d:\log\sample_*.txt 111 | # # Of course these tags can be combined 112 | # textfile = nocontext rotated d:\log\sample_*.txt 113 | 114 | [logwatch] 115 | # activate modern eventlog api introduced in vista 116 | # pro: supports new logs introduced with vista 117 | # contra: only on vista (server 2008) and newer, less well tested, maybe slower 118 | # Note: setting this does not change the default set of monitored logs that 119 | # are found in Windows registry. 120 | # vista_api = yes 121 | 122 | # Testing: output *all* messages from the eventlogs 123 | # sendall = yes 124 | 125 | # From application log send only critical messages 126 | # logfile application = crit 127 | 128 | # From system log send only warning/critical messages, 129 | # but suppress any context messages 130 | # logfile system = nocontext warn 131 | 132 | # Switch all other logfiles off. Default is warn: 133 | # send messages of type warn or crit 134 | # logfile * = off 135 | 136 | # Activate a specific log. Requires vista_api = yes. This can be used to 137 | # activate the monitoring of a log not found in Windows registry. Note: 138 | # wildcards only work with standard logs that are found in Windows registry. 139 | # To find the correct name for a log, right-click on the log in 140 | # event-viewer -> Properties and use the name from "Full Name" 141 | # logfile Microsoft-Windows-GroupPolicy/Operational = warn 142 | 143 | [mrpe] 144 | # Run classical monitoring plugins. The word before the command 145 | # line is the service description for the monitoring. Use backslashes 146 | # in Windows-paths. 147 | # Note: The windows agent will prefix all commands without an absolute 148 | # path with the agents executable dir. So if you want to use 149 | # system wide commands like cscript or ping, you need to specify 150 | # them with an absolute path 151 | # check = Dummy mrpe\check_crit 152 | # check = IP_Configuration mrpe\check_ipconfig 1.2.3.4 153 | # check = Whatever c:\myplugins\check_whatever -w 10 -c 20 154 | # 155 | # The option include allows you to define additional include files and the 156 | # user domain in which include files should be executed. 157 | # 158 | # include \\exampleuser = C:\includes\exampleuser_mrpe.cfg 159 | # 160 | # If you omit the user the file is executed with the current user 161 | # 162 | # include = C:\includes\default.cfg 163 | # 164 | # The syntax in the mrpe include file is the same as in the mrpe section, 165 | # with the exception that you cannot add further includes in a include file. 166 | # There is also no need to define a [mrpe] section in an included file. You 167 | # just need to define the check lines here. 168 | # 169 | # exampleuser_mrpe.cfg 170 | # check = Dummy mrpe\check_crit 171 | # check = IP_Configuration mrpe\check_ipconfig 1.2.3.4 172 | # 173 | # # Paths or plugin parameters containing spaces must be quoted: 174 | # check = Dummy "C:\Program Files (x86)\check_mk\mrpe\check_crit.bat" 175 | # some param "with space" 176 | # 177 | # Important: Keep in mind that the agent needs the permission to run 178 | # scripts as other user. Internally it uses the windows command runas /User: 179 | # which prompts for a password if agent has no permission to change to this user. 180 | # In this case the check_mk agent will get stuck! 181 | 182 | [fileinfo] 183 | # path = C:\Programs\Foo\*.log 184 | # path = M:\Bar Test\*.* 185 | # Recursive wildcards can also be used: 186 | # path = C:\MyDocuments\Foo\** 187 | 188 | [local] 189 | # define timeouts for local scripts matching 190 | # specific patterns - first match wins 191 | # timeout *.vbs = 20 192 | # timeout *.bat = 10 193 | # timeout * = 30 194 | 195 | [plugins] 196 | # example: the windows_updates.vbs 197 | # plugin is executed asynchronous 198 | # and is only updated every 3600 seconds 199 | # it may fail (timeout / error) up to 3 times before the last known data is discarded 200 | # execution windows_updates.vbs = async 201 | # timeout windows_updates.vbs = 120 202 | # cache_age windows_updates.vbs = 3600 203 | # retry_count windows_updates.vbs = 3 204 | 205 | # define timeouts for plugin scripts matching 206 | # specific patterns - first match wins 207 | # timeout ps_perf.ps1 = 20 208 | # timeout *.ps1 = 10 209 | # timeout * = 30 210 | 211 | # When using the Check_MK Inventory plugin, it is a good idea to make the 212 | # plugin being executed asynchronous to prevent it from hooking up the 213 | # whole agent processing. Additionally it should have a execution timeout. 214 | # execution mk_inventory.ps1 = async 215 | # timeout mk_inventory.ps1 = 240 216 | 217 | [ps] 218 | # Experimental: Set to yes to use wmi for retrieving process information. 219 | # This is required for the additional ps feature below. 220 | # use_wmi = no 221 | # Include the whole path of a process and its arguments in the process list. 222 | # full_path = no 223 | -------------------------------------------------------------------------------- /roles/cmk_host_agent/meta/main.yml: -------------------------------------------------------------------------------- 1 | galaxy_info: 2 | role_name: cmk_host_agent 3 | author: Marcel Arentz 4 | description: Installing and updating checkMK agents 5 | company: tribe29 GmbH 6 | 7 | license: GPLv2 8 | 9 | min_ansible_version: 2.4 10 | -------------------------------------------------------------------------------- /roles/cmk_host_agent/tasks/Debian-tasks.yml: -------------------------------------------------------------------------------- 1 | --- 2 | # Install Check_MK Agent on Debian/Ubuntu 3 | 4 | - name: Download agent -> {{ cmk_agent.url.deb }} 5 | get_url: 6 | url: "{{ cmk_agent.url.deb }}" 7 | dest: "{{ cmk_host_linux_tmp }}" 8 | 9 | - name: Install agent -> {{ cmk_agent.file.deb }} 10 | become: yes 11 | apt: 12 | deb: "{{ cmk_agent.file.deb }}" 13 | state: present 14 | -------------------------------------------------------------------------------- /roles/cmk_host_agent/tasks/RedHat-tasks.yml: -------------------------------------------------------------------------------- 1 | --- 2 | # Install Check_MK Agent on RedHat/CentOS/Fedora 3 | 4 | - name: Download agent -> {{ cmk_agent.url.rpm }} 5 | get_url: 6 | url: "{{ cmk_agent.url.rpm }}" 7 | dest: "{{ cmk_host_linux_tmp }}" 8 | 9 | - name: Install agent -> {{ cmk_agent.file.rpm }} 10 | become: yes 11 | yum: 12 | name: "{{ cmk_agent.file.rpm }}" 13 | state: present 14 | disable_gpg_check: yes 15 | -------------------------------------------------------------------------------- /roles/cmk_host_agent/tasks/Windows-tasks.yml: -------------------------------------------------------------------------------- 1 | --- 2 | # Install Check_MK Agent on Windows 3 | 4 | - name: Get current agent version 5 | win_shell: | 6 | $cmk = "C:\Program Files (x86)\check_mk\check_mk_agent.exe" 7 | If (Test-Path $cmk) { 8 | (Get-Item $cmk).VersionInfo.ProductVersion 9 | } Else { 10 | "No agent installed"} 11 | register: cmk_agent_version 12 | changed_when: cmk_agent_version.stdout_lines[0] != cmk_version 13 | 14 | - name: Download agent -> {{ cmk_agent.url.win }} 15 | win_get_url: 16 | url: "{{ cmk_agent.url.win }}" 17 | dest: "{{ cmk_host_windows_tmp }}" 18 | when: cmk_agent_version.changed 19 | 20 | - name: Install agent -> {{ cmk_agent.file.win }} 21 | win_package: 22 | path: "{{ cmk_agent.file.win }}" 23 | state: present 24 | wait: True 25 | when: cmk_agent_version.changed 26 | 27 | - name: Install agent config 28 | win_copy: 29 | src: "check_mk.ini" 30 | dest: "{{ cmk_agent.file.win_conf }}" 31 | -------------------------------------------------------------------------------- /roles/cmk_host_agent/tasks/main.yml: -------------------------------------------------------------------------------- 1 | --- 2 | #- include_vars: cmk_agent_win.yml 3 | - include_vars: cmk_agent_generic.yml 4 | - include_tasks: "{{ ansible_os_family }}-tasks.yml" 5 | -------------------------------------------------------------------------------- /roles/cmk_host_agent/vars/cmk_agent_generic.yml: -------------------------------------------------------------------------------- 1 | --- 2 | cmk_agent: 3 | url: 4 | deb: "{{ cmk_site_url }}/check_mk/agents/check-mk-agent_{{ cmk_version }}-1_all.deb" 5 | rpm: "{{ cmk_site_url }}/check_mk/agents/check-mk-agent-{{ cmk_version }}-1.noarch.rpm" 6 | win: "{{ cmk_site_url }}/check_mk/agents/windows/check_mk_agent.msi" 7 | win_conf: "check_mk.ini" 8 | file: 9 | deb: "{{ cmk_host_linux_tmp }}/check-mk-agent_{{ cmk_version }}-1_all.deb" 10 | rpm: "{{ cmk_host_linux_tmp }}/check-mk-agent-{{ cmk_version }}-1.noarch.rpm" 11 | win: "{{ cmk_host_windows_tmp }}\\check_mk_agent.msi" 12 | win_conf: "C:\\Program Files (x86)\\check_mk\\check_mk.ini" 13 | -------------------------------------------------------------------------------- /roles/cmk_host_plugins/defaults/main.yml: -------------------------------------------------------------------------------- 1 | --- 2 | # General variables 3 | cmk_site_url: "http://192.168.56.1/mysite" 4 | cmk_agent_lnx_path: "/usr/lib/check_mk_agent" 5 | cmk_agent_win_path: "C:\\Program Files (x86)\\check_mk" 6 | 7 | # Set optional search methods 8 | by_process: true 9 | by_package: false 10 | by_files: false 11 | 12 | 13 | # Definition of plugins 14 | # Example definition (none option is mandatory): 15 | # apache_status: 16 | # cmd: apache2 -> regex for process match 17 | # pkg: apache2 -> exact name of package 18 | # cfg: apache_status.cfg -> config file if the plugin needs one 19 | # path: /usr/sbin/apache2 -> path to file for match 20 | # force: true -> true/false to enforce the presence 21 | 22 | cmk_host_plugins: 23 | Linux: 24 | apache_status: 25 | cmd: apache 26 | pkg: apache2 27 | cfg: apache_status.cfg 28 | asmcmd.sh: 29 | force: false 30 | db2_mem: 31 | cmd: db2sysc 32 | dnsclient: 33 | force: false 34 | isc_dhcpd: 35 | cmd: dhcpd 36 | path: /etc/dhcp/dhcpd.conf 37 | jar_signature: 38 | path: /home/oracle/bin/jdk_latest_version 39 | cfg: jar_signature.cfg 40 | kaspersky_av: 41 | path: /opt/kaspersky/kav4fs/bin/kav4fs-control 42 | lnx_quota: 43 | path: /usr/sbin/repquota 44 | lvm: 45 | pkg: lvm2 46 | mailman_lists: 47 | pkg: mailman 48 | mk_apt: 49 | path: /usr/bin/apt 50 | mk_ceph: 51 | cmd: ceph 52 | cfg: ceph.cfg 53 | mk_cups_queues: 54 | cmd: cups 55 | path: /usr/bin/lpstat 56 | pkg: cups 57 | mk_db2.linux: 58 | cmd: db2wdog 59 | mk_filehandler: 60 | force: false 61 | mk_docker_node: 62 | cmd: docker 63 | pkg: docker-ce 64 | mk_docker_container_piggybacked: 65 | cmd: docker 66 | pkg: docker-ce 67 | mk_logwatch: 68 | cfg: logwatch.cfg 69 | force: false 70 | mk_logins: 71 | force: true 72 | mk_oracle: 73 | cmd: oracle 74 | cfg: mk_oracle.cfg 75 | Windows: 76 | mk_oracle.ps1: 77 | cmd: oracle 78 | cfg: mk_oracle_cfg.ps1 79 | -------------------------------------------------------------------------------- /roles/cmk_host_plugins/files/apache_status.cfg: -------------------------------------------------------------------------------- 1 | # +------------------------------------------------------------------+ 2 | # | ____ _ _ __ __ _ __ | 3 | # | / ___| |__ ___ ___| | __ | \/ | |/ / | 4 | # | | | | '_ \ / _ \/ __| |/ / | |\/| | ' / | 5 | # | | |___| | | | __/ (__| < | | | | . \ | 6 | # | \____|_| |_|\___|\___|_|\_\___|_| |_|_|\_\ | 7 | # | | 8 | # | Copyright Mathias Kettner 2014 mk@mathias-kettner.de | 9 | # +------------------------------------------------------------------+ 10 | # 11 | # This file is part of Check_MK. 12 | # The official homepage is at http://mathias-kettner.de/check_mk. 13 | # 14 | # check_mk is free software; you can redistribute it and/or modify it 15 | # under the terms of the GNU General Public License as published by 16 | # the Free Software Foundation in version 2. check_mk is distributed 17 | # in the hope that it will be useful, but WITHOUT ANY WARRANTY; with- 18 | # out even the implied warranty of MERCHANTABILITY or FITNESS FOR A 19 | # PARTICULAR PURPOSE. See the GNU General Public License for more de- 20 | # tails. You should have received a copy of the GNU General Public 21 | # License along with GNU Make; see the file COPYING. If not, write 22 | # to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, 23 | # Boston, MA 02110-1301 USA. 24 | 25 | # Example for configuration for apache_status plugin 26 | # Note: you need this file only if the autodetection fails 27 | # or you do not want to contact all servers it detects 28 | 29 | # Note: Activate this only if the autodetection fails. 30 | #servers = [ 31 | #{ 32 | # 'protocol' : 'http', 33 | # 'address' : 'localhost', 34 | # 'port' : 80 , 35 | #}, 36 | #{ 37 | # 'protocol' : 'http', 38 | # 'address' : 'localhost', 39 | # 'port' : 8080 , 40 | #}, 41 | #{ 42 | # 'protocol' : 'https', 43 | # 'address' : 'localhost', 44 | # 'port' : 443 , 45 | #}, 46 | #] 47 | 48 | -------------------------------------------------------------------------------- /roles/cmk_host_plugins/files/ceph.cfg: -------------------------------------------------------------------------------- 1 | USER=client.admin 2 | KEYRING=/etc/ceph/ceph.client.admin.keyring 3 | -------------------------------------------------------------------------------- /roles/cmk_host_plugins/files/dnsclient.cfg: -------------------------------------------------------------------------------- 1 | HOSTADDRESS=mathias-kettner.de 2 | -------------------------------------------------------------------------------- /roles/cmk_host_plugins/files/jar_signature.cfg: -------------------------------------------------------------------------------- 1 | JAVA_HOME=/home/oracle/bin/jdk_latest_version 2 | JAR_PATH=/home/oracle/fmw/11gR2/as_1/forms/java/*.jar 3 | -------------------------------------------------------------------------------- /roles/cmk_host_plugins/files/logwatch.cfg: -------------------------------------------------------------------------------- 1 | # +------------------------------------------------------------------+ 2 | # | ____ _ _ __ __ _ __ | 3 | # | / ___| |__ ___ ___| | __ | \/ | |/ / | 4 | # | | | | '_ \ / _ \/ __| |/ / | |\/| | ' / | 5 | # | | |___| | | | __/ (__| < | | | | . \ | 6 | # | \____|_| |_|\___|\___|_|\_\___|_| |_|_|\_\ | 7 | # | | 8 | # | Copyright Mathias Kettner 2014 mk@mathias-kettner.de | 9 | # +------------------------------------------------------------------+ 10 | # 11 | # This file is part of Check_MK. 12 | # The official homepage is at http://mathias-kettner.de/check_mk. 13 | # 14 | # check_mk is free software; you can redistribute it and/or modify it 15 | # under the terms of the GNU General Public License as published by 16 | # the Free Software Foundation in version 2. check_mk is distributed 17 | # in the hope that it will be useful, but WITHOUT ANY WARRANTY; with- 18 | # out even the implied warranty of MERCHANTABILITY or FITNESS FOR A 19 | # PARTICULAR PURPOSE. See the GNU General Public License for more de- 20 | # tails. You should have received a copy of the GNU General Public 21 | # License along with GNU Make; see the file COPYING. If not, write 22 | # to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, 23 | # Boston, MA 02110-1301 USA. 24 | 25 | # logwatch.cfg 26 | # This file configures mk_logwatch. Define your logfiles 27 | # and patterns to be looked for here. 28 | 29 | # Name one or more logfiles 30 | /var/log/messages 31 | # Patterns are indented with one space are prefixed with: 32 | # C: Critical messages 33 | # W: Warning messages 34 | # I: ignore these lines (OK) 35 | # R: Rewrite the output previous match. You can use \1, \2 etc. for refer to groups (.*) of this match 36 | # The first match decided. Lines that do not match any pattern 37 | # are ignored 38 | C Fail event detected on md device 39 | I mdadm.*: Rebuild.*event detected 40 | W mdadm\[ 41 | W ata.*hard resetting link 42 | W ata.*soft reset failed (.*FIS failed) 43 | W device-mapper: thin:.*reached low water mark 44 | C device-mapper: thin:.*no free space 45 | C Error: (.*) 46 | 47 | /var/log/auth.log 48 | W sshd.*Corrupted MAC on input 49 | 50 | /var/log/syslog /var/log/kern.log 51 | I registered panic notifier 52 | C panic 53 | C Oops 54 | W generic protection rip 55 | W .*Unrecovered read error - auto reallocate failed 56 | 57 | # Globbing patterns are allowed: 58 | # /sapdata/*/saptrans.log 59 | # C ORA- 60 | -------------------------------------------------------------------------------- /roles/cmk_host_plugins/files/mk_oracle_cfg.ps1: -------------------------------------------------------------------------------- 1 | # Example configuration for ORACLE plugin for Windows 2 | # Set the ORACLE_HOME if we have more than one oracle home on the server 3 | # then we can generate the PATH based on that. Note that the tnsnames.ora 4 | # must then be in %ORACLE_HOME%\network\admin, or use the the environment 5 | # variable %TBS_ADMIN% to set to another directory. 6 | # $ORACLE_HOME="C:\oracle\product\12.1.0.1" 7 | 8 | # $DBUSER=@("sys", "Secret12", "SYSDBA", "localhost", "1521") 9 | # $DBUSER_tst=@("sys", "Secret12", "SYSDBA", "localhost", "1521") 10 | # $DBUSER_orcl=@("sys", "Secret12", "SYSDBA", "localhost", "1521") 11 | # $DBUSER_orcl=@("sys", "Secret12", "SYSDBA", "localhost", "1521") 12 | # $ASMUSER=@("user", "password", "SYSDBA/SYSASM", "hostname", "port") 13 | 14 | -------------------------------------------------------------------------------- /roles/cmk_host_plugins/meta/main.yml: -------------------------------------------------------------------------------- 1 | galaxy_info: 2 | role_name: cmk_host_plugins 3 | author: Marcel Arentz 4 | description: Installing and updating checkMK agent plugins 5 | company: tribe29 GmbH 6 | 7 | license: GPLv2 8 | 9 | min_ansible_version: 2.4 10 | -------------------------------------------------------------------------------- /roles/cmk_host_plugins/tasks/Linux-install.yml: -------------------------------------------------------------------------------- 1 | --- 2 | 3 | - name: Install {{ needed_plugin }} 4 | get_url: 5 | url: "{{ cmk_site_url }}/check_mk/agents/plugins/{{ needed_plugin }}" 6 | dest: "{{ plugins_path }}/{{ needed_plugin }}" 7 | owner: root 8 | group: root 9 | mode: 0500 # Prevent users from editing this script on the host 10 | 11 | - name: Install config file for {{ needed_plugin }} 12 | copy: 13 | src: "{{ cmk_plugin_base[ needed_plugin ].cfg }}" 14 | dest: "{{ config_path }}/{{ cmk_plugin_base[ needed_plugin ].cfg }}" 15 | owner: root 16 | group: root 17 | mode: 0400 # Prevent users from editing this file on the host 18 | when: cmk_plugin_base[ needed_plugin ].cfg is defined 19 | -------------------------------------------------------------------------------- /roles/cmk_host_plugins/tasks/Linux-main.yml: -------------------------------------------------------------------------------- 1 | --- 2 | 3 | - name: Get installed plugins 4 | shell: "ls {{ plugins_path }}/" 5 | register: plugin_list 6 | changed_when: false 7 | 8 | - package_facts: 9 | when: by_package == true 10 | 11 | - include_tasks: "Linux-search.yml" 12 | with_dict: "{{ cmk_plugin_base }}" 13 | loop_control: 14 | loop_var: plugin_name 15 | 16 | - include_tasks: "Linux-install.yml" 17 | with_items: "{{ CMK_PLUGINS }}" 18 | loop_control: 19 | loop_var: needed_plugin 20 | when: CMK_PLUGINS|length > 0 21 | 22 | - name: Get obsolete installed Plugins 23 | set_fact: 24 | plugin_list: "{{ plugin_list.stdout_lines | difference(CMK_PLUGINS) }}" 25 | 26 | - include_tasks: "Linux-remove.yml" 27 | with_items: "{{ plugin_list }}" 28 | loop_control: 29 | loop_var: obsolete_plugin 30 | when: obsolete_plugin|length > 0 31 | 32 | -------------------------------------------------------------------------------- /roles/cmk_host_plugins/tasks/Linux-remove.yml: -------------------------------------------------------------------------------- 1 | --- 2 | 3 | - name: Remove obsolete {{ obsolete_plugin }} 4 | file: 5 | path: "{{ plugins_path }}/{{ obsolete_plugin }}" 6 | state: absent 7 | 8 | - name: Remove obsolete config of {{ obsolete_plugin }} 9 | file: 10 | path: "{{ config_path }}/{{ cmk_plugin_base[ obsolete_plugin ].cfg }}" 11 | state: absent 12 | when: cmk_plugin_base[ obsolete_plugin ].cfg is defined 13 | -------------------------------------------------------------------------------- /roles/cmk_host_plugins/tasks/Linux-search.yml: -------------------------------------------------------------------------------- 1 | --- 2 | 3 | - name: Get process needed for {{ plugin_name.key }} 4 | shell: "pgrep -c {{ plugin_name.value.cmd }}" 5 | register: get_process 6 | failed_when: get_process.stdout == "" 7 | changed_when: false 8 | when: by_process == true and plugin_name.value.cmd is defined 9 | 10 | - name: Get file needed for {{ plugin_name.key }} 11 | stat: 12 | path: "{{ plugin_name.value.path }}" 13 | register: get_file 14 | changed_when: false 15 | when: by_files == true and plugin_name.value.path is defined 16 | 17 | - name: Add {{ plugin_name.key }} to needed plugins 18 | set_fact: 19 | CMK_PLUGINS: "{{ CMK_PLUGINS + [ plugin_name.key ] }}" 20 | when: (get_process.rc is defined and get_process.rc == 0) or 21 | (get_file.stat is defined and get_file.stat.exists == true) or 22 | (by_package == true and plugin_name.value.pkg is defined and plugin_name.value.pkg in packages) or 23 | (plugin_name.value.force is defined and plugin_name.value.force == true) 24 | -------------------------------------------------------------------------------- /roles/cmk_host_plugins/tasks/Windows-install.yml: -------------------------------------------------------------------------------- 1 | --- 2 | 3 | - name: Install {{ needed_plugin }} 4 | win_get_url: 5 | url: "{{ cmk_site_url }}/check_mk/agents/windows/plugins/{{ needed_plugin }}" 6 | dest: "{{ plugins_path }}/{{ needed_plugin }}" 7 | 8 | - name: Install config file for {{ needed_plugin }} 9 | win_copy: 10 | src: "{{ cmk_plugin_base[ needed_plugin ].cfg }}" 11 | dest: "{{ config_path }}/{{ cmk_plugin_base[ needed_plugin ].cfg }}" 12 | when: cmk_plugin_base[ needed_plugin ].cfg is defined 13 | -------------------------------------------------------------------------------- /roles/cmk_host_plugins/tasks/Windows-main.yml: -------------------------------------------------------------------------------- 1 | --- 2 | 3 | - name: Get installed plugins 4 | win_shell: "(Get-Item '{{ plugins_path }}\\*' | Select-Object Name | Format-Table -HideTableHeaders | Out-String).trim()" 5 | register: plugin_list 6 | changed_when: false 7 | 8 | - name: Get installed software 9 | win_shell: "(Get-ItemProperty HKLM:\\Software\\Wow6432Node\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\* | Select-Object DisplayName | Format-Table -HideTableHeaders | Out-String).trim()" 10 | register: software_list 11 | when: by_package == true 12 | 13 | - include_tasks: "Windows-search.yml" 14 | with_dict: "{{ cmk_plugin_base }}" 15 | loop_control: 16 | loop_var: plugin_name 17 | 18 | - include_tasks: "Windows-install.yml" 19 | with_items: "{{ CMK_PLUGINS }}" 20 | loop_control: 21 | loop_var: needed_plugin 22 | when: CMK_PLUGINS > 0 23 | 24 | - name: Get obsolete installed Plugins 25 | set_fact: 26 | plugin_list: "{{ plugin_list.stdout_lines | difference(CMK_PLUGINS) }}" 27 | 28 | - include_tasks: "Windows-remove.yml" 29 | with_items: "{{ plugin_list }}" 30 | loop_control: 31 | loop_var: obsolete_plugin 32 | when: obsolete_plugin > 0 and obsolete_plugin != "" 33 | -------------------------------------------------------------------------------- /roles/cmk_host_plugins/tasks/Windows-remove.yml: -------------------------------------------------------------------------------- 1 | --- 2 | 3 | - name: Remove obsolete {{ obsolete_plugin }} 4 | win_file: 5 | path: "{{ plugins_path }}/{{ obsolete_plugin }}" 6 | state: absent 7 | 8 | - name: Remove obsolete config of {{ obsolete_plugin }} 9 | win_file: 10 | path: "{{ config_path }}/{{ cmk_plugin_base[ obsolete_plugin ].cfg }}" 11 | state: absent 12 | when: cmk_plugin_base[ obsolete_plugin ].cfg is defined 13 | -------------------------------------------------------------------------------- /roles/cmk_host_plugins/tasks/Windows-search.yml: -------------------------------------------------------------------------------- 1 | --- 2 | 3 | - name: Get process needed for {{ plugin_name.key }} 4 | win_shell: "(Get-Process | Where-Object {$_.ProcessName -like '*{{ plugin_name.value.cmd }}*'} | Get-Unique | Select-Object ProcessName | Format-Table -HideTableHeaders | Out-String).trim()" 5 | register: get_process 6 | failed_when: get_process.rc == 1 7 | changed_when: false 8 | when: by_process == true and plugin_name.value.cmd is defined 9 | 10 | - name: Get file needed for {{ plugin_name.key }} 11 | win_stat: 12 | path: "{{ plugin_name.value.path }}" 13 | register: get_file 14 | changed_when: false 15 | when: by_files == true and plugin_name.value.path is defined 16 | 17 | - name: Add {{ plugin_name.key }} to needed plugins 18 | set_fact: 19 | CMK_PLUGINS: "{{ CMK_PLUGINS + [ plugin_name.key ] }}" 20 | when: (get_process.stdout is defined and get_process.stdout_lines[0] != "" ) or 21 | (get_file.stat is defined and get_file.stat.exists == true) or 22 | (by_package == true and plugin_name.value.pkg is defined and plugin_name.value.pkg in packages) or 23 | (plugin_name.value.force is defined and plugin_name.value.force == true) 24 | -------------------------------------------------------------------------------- /roles/cmk_host_plugins/tasks/main.yml: -------------------------------------------------------------------------------- 1 | --- 2 | 3 | # Initialize list of plugins/configs to install 4 | 5 | - set_fact: 6 | OS: "Linux" 7 | when: ansible_system == "Linux" 8 | 9 | - set_fact: 10 | OS: "Windows" 11 | when: ansible_os_family == "Windows" 12 | 13 | - set_fact: 14 | CMK_PLUGINS: [ ] 15 | cmk_plugin_base: "{{ cmk_host_plugins[ OS ] }}" 16 | 17 | # Install plugins based on OS system 18 | - include_vars: "{{ OS }}-vars.yml" 19 | - include_tasks: "{{ OS }}-main.yml" 20 | -------------------------------------------------------------------------------- /roles/cmk_host_plugins/vars/Linux-vars.yml: -------------------------------------------------------------------------------- 1 | --- 2 | 3 | plugins_path: "{{ cmk_agent_lnx_path }}/plugins" 4 | local_path: "{{ cmk_agent_lnx_path }}/local" 5 | config_path: "/etc/check_mk/" 6 | -------------------------------------------------------------------------------- /roles/cmk_host_plugins/vars/Windows-vars.yml: -------------------------------------------------------------------------------- 1 | --- 2 | 3 | plugins_path: "{{ cmk_agent_win_path }}\\plugins" 4 | local_path: "{{ cmk_agent_win_path }}\\local" 5 | config_path: "{{ cmk_agent_win_path }}\\config" 6 | -------------------------------------------------------------------------------- /roles/cmk_host_registration/defaults/main.yml: -------------------------------------------------------------------------------- 1 | --- 2 | 3 | cmk_site_url: "http://192.168.56.1/mysite" 4 | cmk_site_user: automation 5 | cmk_site_password: myautomationpassword 6 | cmk_site_default_folder: "ansible" 7 | cmk_validate_certs: true 8 | -------------------------------------------------------------------------------- /roles/cmk_host_registration/handlers/main.yml: -------------------------------------------------------------------------------- 1 | --- 2 | 3 | - name: activate changes 4 | checkmk_changes: 5 | url: "{{ cmk_site_url }}" 6 | user: "{{ cmk_site_user }}" 7 | password: "{{ cmk_site_password }}" 8 | allow_foreign_changes: yes 9 | comments: 'Changes made by Ansible' 10 | validate_certs: "{{ cmk_validate_certs }}" 11 | delegate_to: localhost 12 | -------------------------------------------------------------------------------- /roles/cmk_host_registration/library/checkmk_changes.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python 2 | # -*- encoding: utf-8; py-indent-offset: 4 -*- 3 | 4 | ANSIBLE_METADATA = {'status': ['preview'], 5 | 'supported_by': 'community', 6 | 'version': '0.1'} 7 | 8 | DOCUMENTATION = ''' 9 | module: checkmk_changes 10 | 11 | short_description: Activate configuration changes in checkMK 12 | 13 | version_added: "0.1" 14 | 15 | description: 16 | - "With the C(checkmk_changes) module it is possible to activate configuration changes of one or more checkMK sites." 17 | - "This module provides some more options of the API of checkMK than the C(checkmk_host) module" 18 | 19 | author: "Marcel Arentz (@ma@mathias-kettner.de)" 20 | 21 | options: 22 | url: 23 | description: 24 | - URL to the Check_MK instance as HTTP or HTTPS 25 | required: true 26 | user: 27 | description: 28 | - The user to authenticate against the site 29 | required: true 30 | password: 31 | description: 32 | - The password to authenticate against the site 33 | required: true 34 | sites: 35 | description: Specifies a list of sites to activate changes on. This list may or may not contain the site on which the API call is made on. 36 | required: false 37 | default: none 38 | allow_foreign_changes: 39 | description: Sometimes other users made changes meanwhile. This option specifies if the changes should be activated if there are configuration changes from other users. 40 | required: false 41 | default: False 42 | type: bool 43 | comment: 44 | description: You can optionally add a comment to this activation. 45 | required: false 46 | default: none 47 | validate_certs: 48 | description: Check SSL certificate 49 | required: false 50 | default: True 51 | type: bool 52 | ''' 53 | 54 | EXAMPLES = ''' 55 | - name: Activate changes in a single site of checkMK 56 | checkmk_changes: 57 | url: https://monitoring.example.org/mysite 58 | user: myuser 59 | password: mypassword 60 | validate_certs: yes 61 | 62 | - name: Activate changes to a set of sites except the call one 63 | checkmk_changes: 64 | url: https://monitoring.example.org/mysite 65 | user: myuser 66 | password: mypassword 67 | sites: 68 | - first_slave_site 69 | - second_slave_site 70 | allow_foreign_changes: yes 71 | comment: Changes made by ansible 72 | ''' 73 | 74 | RETURN = ''' 75 | request: 76 | - description: The paramters that was passed in 77 | type: dict 78 | result: 79 | - description: The result from the Check_MK site 80 | type: dict 81 | ''' 82 | 83 | 84 | from ansible.module_utils.basic import AnsibleModule 85 | from ansible.module_utils.checkmk_api import Changes 86 | 87 | class CallChanges: 88 | def __init__(self, session): 89 | self.session = session 90 | 91 | def activate(self, payload, ansible): 92 | result = self.session.activate(payload=payload) 93 | result_output = result['result'] 94 | 95 | if 'no changes to activate' in result_output: 96 | return False, result_output 97 | elif isinstance(result_output, dict): 98 | return True, result_output 99 | 100 | ansible.fail_json(msg='Failed to activate changes: %s' % result_output, 101 | payload=payload) 102 | 103 | 104 | def main(): 105 | args = dict( 106 | # Required 107 | url=dict(type='str', required=True), 108 | user=dict(type='str', required=True), 109 | password=dict(type='str', required=True, no_log=True), 110 | # Optional 111 | sites=dict(type='list', default=None), 112 | allow_foreign_changes=dict(type='bool', default=True), 113 | comments=dict(type='str', default=None), 114 | validate_certs=dict(type='bool', default=True), 115 | ) 116 | 117 | ansible = AnsibleModule( 118 | argument_spec=args, 119 | supports_check_mode=False 120 | ) 121 | 122 | sites = ansible.params['sites'] 123 | 124 | changes = CallChanges(Changes( 125 | ansible.params['url'], 126 | ansible.params['user'], 127 | ansible.params['password'], 128 | verify=ansible.params['validate_certs'],)) 129 | 130 | payload = { 131 | 'allow_foreign_changes': '1' if ansible.params['allow_foreign_changes'] == 'yes' else '0' 132 | } 133 | 134 | if ansible.params['comments']: 135 | payload['comment'] = ansible.params['comments'] 136 | if sites: 137 | payload['sites'] = sites 138 | payload['mode'] = 'specific' 139 | else: 140 | payload['mode'] = 'dirty' 141 | 142 | changed, result = changes.activate(payload, ansible) 143 | 144 | ansible_result = dict( 145 | sites=sites, 146 | changed=changed, 147 | result=result, 148 | ) 149 | 150 | ansible.exit_json(**ansible_result) 151 | 152 | if __name__ == '__main__': 153 | main() 154 | -------------------------------------------------------------------------------- /roles/cmk_host_registration/library/checkmk_host.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python 2 | # -*- encoding: utf-8; py-indent-offset: 4 -*- 3 | 4 | ANSIBLE_METADATA = {'status': ['preview'], 5 | 'supported_by': 'community', 6 | 'version': '0.1'} 7 | 8 | DOCUMENTATION = ''' 9 | module: checkmk_host 10 | 11 | short_description: Managing hosts in checkMK 12 | 13 | version_added: "0.1" 14 | 15 | description: 16 | - "With the C(checkmk_host) module it is possible to add/edit/delete hosts via the checkmk API" 17 | 18 | author: "Marcel Arentz (@ma@mathias-kettner.de)" 19 | 20 | options: 21 | site: 22 | description: URL to the Check_MK instance as HTTP or HTTPS. The URL just needs to have a format like C(https://myserver.com/mysite) 23 | required: true 24 | user: 25 | description: The user to authenticate against the site 26 | required: true 27 | password: 28 | description: The password to authenticate against the site 29 | required: true 30 | name: 31 | description: Name of the host 32 | required: true 33 | folder: 34 | description: Folder to put the host in. A folder is always defined as a relative path. 35 | required: false 36 | default: '' 37 | attributes: 38 | description: A host can have several attributes except it's name and the folder. These attributes are summarized in a dictionary. 39 | required: false 40 | state: 41 | description: If present, the host will be created if it does not exists yet. If absent, the host will remove, if present. 42 | required: false 43 | default: present 44 | choices: 45 | - present 46 | - absent 47 | validate_certs: 48 | description: Check SSL certificate 49 | required: false 50 | default: True 51 | type: bool 52 | service_discovery: 53 | description: Start the service discovery after adding/changing the host 54 | required: false 55 | default: True 56 | type: bool 57 | activate_changes: 58 | description: Activate the changes 59 | required: false 60 | default: True 61 | type: bool 62 | ''' 63 | 64 | EXAMPLES = ''' 65 | - name: Add host to Check_MK site 66 | checkmk_host: 67 | url: https://monitoring.example.org/mysite 68 | user: myuser 69 | password: mypassword 70 | name: myhost1 71 | 72 | - name: Add host with specific folder and with explcit ip address 73 | checkmk_host: 74 | url: https://monitoring.example.org/mysite 75 | user: myuser 76 | password: mypassword 77 | name: {{ inventory_hostname }} 78 | folder: automation/linux 79 | attributes: 80 | addressv4: 192.168.56.42 81 | alias: My Alias 82 | ''' 83 | 84 | RETURN = ''' 85 | request: 86 | - description: The paramters that was passed in 87 | type: dict 88 | result: 89 | - description: The result from the Check_MK site 90 | type: dict 91 | service_discovery: 92 | - description: If the services are discvored directly, the result and the result code will be available here 93 | activate_changes: 94 | - description: If changes are activates directly, the result and the result code will be available here 95 | type: dict 96 | ''' 97 | 98 | 99 | from ansible.module_utils.basic import AnsibleModule 100 | from ansible.module_utils.checkmk_api import Hosts, Services, Changes 101 | 102 | class CallHost: 103 | def __init__(self, session): 104 | self.session = session 105 | self.hostname = session.hostname 106 | 107 | self.is_present, self.data = self._get(1) 108 | 109 | 110 | def _get(self, effective): 111 | host = self.session.get(effective_attributes=effective) 112 | if isinstance(host['result'], dict): 113 | return True, host['result'] 114 | else: 115 | return False, host['result'] 116 | 117 | 118 | def add(self, payload): 119 | result = self.session.add(payload=payload) 120 | return True, result['result'] 121 | 122 | 123 | def edit(self, request): 124 | diff = False 125 | payload = request.copy() 126 | if payload['folder'] != self.data['path']: 127 | self.delete() 128 | changed, result = self.add(payload=payload) 129 | return changed, result 130 | payload.pop('folder') 131 | 132 | needed_attr = payload['attributes'] 133 | _is_present, existing_attr = self._get(0) 134 | existing_attr = existing_attr.get('attributes', {}) 135 | unset_attr = [] 136 | if not needed_attr: 137 | if not existing_attr: 138 | return False, None 139 | 140 | for key in existing_attr: 141 | unset_attr.append(key) 142 | 143 | payload['unset_attributes'] = unset_attr 144 | return True, self.session.edit(payload=payload)['result'] 145 | else: 146 | if not existing_attr: 147 | return True, self.session.edit(payload=payload)['result'] 148 | 149 | # We need to figure what to do with every custom key 150 | for key, value in existing_attr.items(): 151 | if key not in needed_attr: 152 | unset_attr.append(key) 153 | elif value != needed_attr[key]: 154 | diff = True 155 | 156 | if len(unset_attr) > 0: 157 | payload['unset_attributes'] = unset_attr 158 | return True, self.session.edit(payload=payload)['result'] 159 | if diff: 160 | return True, self.session.edit(payload=payload)['result'] 161 | return False, None 162 | 163 | 164 | def delete(self): 165 | result = self.session.delete(payload={'hostname': self.hostname}) 166 | return True, result['result'] 167 | 168 | 169 | def main(): 170 | args = dict( 171 | # Required 172 | url=dict(type='str', required=True), 173 | user=dict(type='str', required=True), 174 | password=dict(type='str', required=True, no_log=True), 175 | name=dict(type='str', required=True), 176 | # Optional 177 | attributes=dict(type='dict', default={}), 178 | folder=dict(type='str', default=''), 179 | validate_certs=dict(type='bool', default=True), 180 | discover_services=dict(type='bool', default=True), 181 | activate_changes=dict(type='bool', default=True), 182 | # Meta 183 | state=dict(type='str', default='present', choices=['present', 'absent']), 184 | ) 185 | 186 | ansible = AnsibleModule( 187 | argument_spec=args, 188 | supports_check_mode=False 189 | ) 190 | 191 | hostname = ansible.params['name'] 192 | state = ansible.params['state'] 193 | discover = ansible.params['discover_services'] 194 | activate = ansible.params['activate_changes'] 195 | 196 | host = CallHost(Hosts( 197 | ansible.params['url'], 198 | ansible.params['user'], 199 | ansible.params['password'], 200 | verify=ansible.params['validate_certs'], 201 | hostname=hostname,)) 202 | 203 | payload = dict( 204 | hostname=hostname, 205 | folder=ansible.params['folder'], 206 | attributes=ansible.params['attributes'] 207 | ) 208 | 209 | if state == 'present' and not host.is_present: 210 | changed, result = host.add(payload) 211 | elif state == 'present': 212 | changed, result = host.edit(payload) 213 | elif state == 'absent' and host.is_present: 214 | changed, result = host.delete() 215 | elif state == 'absent': 216 | changed = False 217 | result = None 218 | 219 | if isinstance(result, str): 220 | if 'exception' in result: 221 | ansible.fail_json(msg='Failed to work on %s: %s' % (hostname, result), 222 | request=payload, 223 | orig_data=host.data) 224 | 225 | ansible_result = dict( 226 | changed=changed, 227 | request=payload, 228 | result=result, 229 | ) 230 | 231 | if discover and changed == True: 232 | service = Services( 233 | ansible.params['url'], 234 | ansible.params['user'], 235 | ansible.params['password'], 236 | verify=ansible.params['validate_certs'], 237 | hostname=hostname) 238 | discovery = service.discover(mode='refresh') 239 | ansible_result['service_discovery'] = dict( 240 | result=discovery['result'], 241 | status=discovery['result_code'], 242 | ) 243 | 244 | if activate and changed == True: 245 | changes = Changes( 246 | ansible.params['url'], 247 | ansible.params['user'], 248 | ansible.params['password'], 249 | verify=ansible.params['validate_certs']) 250 | activation = changes.activate(allow_foreign_changes=1) 251 | ansible_result['activate_changes'] = dict( 252 | result=activation['result'], 253 | status=activation['result_code'], 254 | ) 255 | 256 | ansible_result['hostname'] = hostname 257 | ansible.exit_json(**ansible_result) 258 | 259 | if __name__ == '__main__': 260 | main() 261 | -------------------------------------------------------------------------------- /roles/cmk_host_registration/library/checkmk_services.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python 2 | # -*- encoding: utf-8; py-indent-offset: 4 -*- 3 | 4 | ANSIBLE_METADATA = {'status': ['preview'], 5 | 'supported_by': 'community', 6 | 'version': '0.1'} 7 | 8 | DOCUMENTATION = ''' 9 | module: checkmk_services 10 | 11 | short_description: Managing services in checkMK 12 | 13 | version_added: "0.1" 14 | 15 | description: 16 | - "With the C(checkmk_services) module it is possible to discover or rediscover services of a host in checkMK." 17 | - "This module provides some more options of the API of checkMK than the C(checkmk_host) module" 18 | 19 | author: "Marcel Arentz (@ma@mathias-kettner.de)" 20 | 21 | options: 22 | site: 23 | description: 24 | - URL to the Check_MK instance as HTTP or HTTPS 25 | required: true 26 | user: 27 | description: 28 | - The user to authenticate against the site 29 | required: true 30 | password: 31 | description: 32 | - The password to authenticate against the site 33 | required: true 34 | name: 35 | description: Name of the host 36 | required: true 37 | mode: 38 | description: Controls the behaviour of the service discovery. With C(new) all new services are added to the host while C(remove) just removes vanished services. You can combine these two mode with C(fixall). C(refresh) removes all services and rediscvors them again afterwards. 39 | required: false 40 | default: new 41 | choices: 42 | - fixall 43 | - new 44 | - refresh 45 | - remove 46 | validate_certs: 47 | description: Check SSL certificate 48 | required: false 49 | default: True 50 | type: bool 51 | ''' 52 | 53 | EXAMPLES = ''' 54 | - name: Add new services to a host in checkMK 55 | checkmk_services: 56 | url: https://monitoring.example.org/mysite 57 | user: myuser 58 | password: mypassword 59 | name: myhost1 60 | 61 | - name: Adds new and removes vanished services 62 | checkmk_services: 63 | url: https://monitoring.example.org/mysite 64 | user: myuser 65 | password: mypassword 66 | name: {{ inventory_hostname }} 67 | mode: fixall 68 | ''' 69 | 70 | RETURN = ''' 71 | request: 72 | - description: The paramters that was passed in 73 | type: dict 74 | result: 75 | - description: The result from the Check_MK site 76 | type: dict 77 | ''' 78 | 79 | 80 | from ansible.module_utils.basic import AnsibleModule 81 | from ansible.module_utils.checkmk_api import Services 82 | 83 | class CallServices: 84 | def __init__(self, session): 85 | self.session = session 86 | self.hostname = session.hostname 87 | 88 | 89 | def discover(self, mode): 90 | result = self.session.discover(mode=mode) 91 | result_text = result['result'] 92 | 93 | if result_text.startswith('Service discovery successful.'): 94 | list_as_string = result.text.strip('Service discovery successful.') 95 | added, removed, kept, new_count = list_as_string.split(',') 96 | added_count = int(added.split(' ')[1]) 97 | removed_count = int(removed.split(' ')[1]) 98 | 99 | if added_count > 0 or removed_count > 0: 100 | return True, result_text 101 | return False, result_text 102 | 103 | ansible.fail_json(msg='Failed to discover as %s: %s' % (mode, result_text)) 104 | 105 | def main(): 106 | args = dict( 107 | # Required 108 | url=dict(type='str', required=True), 109 | user=dict(type='str', required=True), 110 | password=dict(type='str', required=True, no_log=True), 111 | name=dict(type='str', required=True), 112 | # Optional 113 | mode=dict(type='str', default='new', choices=['']), 114 | validate_certs=dict(type='bool', default=True), 115 | ) 116 | 117 | ansible = AnsibleModule( 118 | argument_spec=args, 119 | supports_check_mode=False 120 | ) 121 | 122 | hostname = ansible.params['name'] 123 | mode = ansible.params['mode'] 124 | 125 | host = CallServices(Services( 126 | ansible.params['url'], 127 | ansible.params['user'], 128 | ansible.params['password'], 129 | verify=ansible.params['validate_certs'], 130 | hostname=hostname,)) 131 | 132 | changed, result = host.discover(mode=mode) 133 | 134 | ansible_result = dict( 135 | hostname=hostname, 136 | changed=changed, 137 | mode=mode, 138 | result=result, 139 | ) 140 | 141 | ansible.exit_json(**ansible_result) 142 | 143 | if __name__ == '__main__': 144 | main() 145 | -------------------------------------------------------------------------------- /roles/cmk_host_registration/meta/main.yml: -------------------------------------------------------------------------------- 1 | galaxy_info: 2 | role_name: cmk_host_registration 3 | author: MArcel Arentz 4 | description: Register Host at checkMK site, discover services and activate these changes 5 | company: tribe29 GmbH 6 | 7 | license: GPLv2 8 | 9 | min_ansible_version: 2.4 10 | -------------------------------------------------------------------------------- /roles/cmk_host_registration/module_utils/checkmk_api.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python 2 | # -*- encoding: utf-8; py-indent-offset: 4 -*- 3 | 4 | from collections import namedtuple 5 | import ast 6 | import requests 7 | 8 | 9 | class WebAPI(object): 10 | def __init__(self, session): 11 | self.url = session.url 12 | self.username = session.username 13 | self.secret = session.secret 14 | self.verify = session.verify 15 | 16 | self.header = { 17 | 'request_format': 'python', 18 | 'output_format': 'python', 19 | '_username': self.username, 20 | '_secret': self.secret, 21 | } 22 | 23 | def query(self, action, request=None): 24 | payload = self.header.copy() 25 | payload['action'] = action 26 | if request: 27 | payload['request'] = repr(request) 28 | 29 | try: 30 | response = requests.get(self.url, params=payload, verify=self.verify, timeout=30) 31 | return ast.literal_eval(response.text) 32 | except: 33 | raise 34 | 35 | @property 36 | def result(self): 37 | return self.result 38 | 39 | @property 40 | def result_code(self): 41 | return self.result_code 42 | 43 | 44 | class DataTuple(object): 45 | def __init__(self, url, username, secret, verify=True): 46 | name = namedtuple('name', ['url', 'username', 'secret', 'verify']) 47 | self.data = name(url, username, secret, verify) 48 | 49 | 50 | class Hosts(object): 51 | def __init__(self, url, username, secret, verify=True, hostname=None): 52 | url = "%s/check_mk/webapi.py" % url.rstrip('/') 53 | session = DataTuple(url, username, secret, verify) 54 | self.session = WebAPI(session.data) 55 | self.hostname = hostname 56 | 57 | def _prepare_hostname(self, hostname=None): 58 | if hostname: 59 | self.hostname = hostname 60 | 61 | def pre_call(name): 62 | def _build_payload(fn): 63 | def _decorator(self, **kwargs): 64 | self._prepare_hostname(kwargs.get('hostname', None)) 65 | if not self.hostname: 66 | return fn(self, payload=None) 67 | 68 | if kwargs.get('payload', None): 69 | payload = kwargs['payload'] 70 | else: # we need to build the payload manually 71 | payload = {'hostname': self.hostname} 72 | if name == 'get': 73 | payload['effective_attributes'] = kwargs.get('effective_attributes', 0) 74 | if name in ['add', 'edit'] and kwargs.get('attributes', None): 75 | payload['attributes'] = kwargs['attributes'] 76 | if name == 'add': 77 | payload['folder'] = kwargs.get('folder', '') 78 | 79 | return fn(self, payload=payload) 80 | return _decorator 81 | return _build_payload 82 | 83 | @pre_call('get') 84 | def get(self, hostname=None, effective_attributes=None, payload=None): 85 | return self.session.query('get_host', payload) 86 | 87 | @pre_call('add') 88 | def add(self, hostname=None, folder=None, attributes=None, payload=None): 89 | return self.session.query('add_host', payload) 90 | 91 | @pre_call('delete') 92 | def delete(self, hostname=None, payload=None): 93 | return self.session.query('delete_host', payload) 94 | 95 | @pre_call('edit') 96 | def edit(self, hostname=None, attributes=None, payload=None): 97 | return self.session.query('edit_host', payload) 98 | 99 | 100 | class Services(object): 101 | def __init__(self, url, username, secret, verify=True, hostname=None): 102 | url = "%s/check_mk/webapi.py" % url.rstrip('/') 103 | session = DataTuple(url, username, secret, verify) 104 | self.session = WebAPI(session.data) 105 | self.hostname = hostname 106 | 107 | 108 | def _prepare_hostname(self, hostname=None): 109 | if hostname: 110 | self.hostname = hostname 111 | 112 | def pre_call(fn): 113 | def _decorator(self, *args, **kwargs): 114 | self._prepare_hostname(kwargs.get('hostname', None)) 115 | if not self.hostname: 116 | return fn(self, payload=None) 117 | 118 | if kwargs.get('payload', None): 119 | payload = kwargs['payload'] 120 | else: 121 | payload = {'hostname': self.hostname} 122 | if kwargs.get('mode', None): 123 | payload['mode'] = kwargs['mode'] 124 | 125 | return fn(self, payload=payload) 126 | return _decorator 127 | 128 | @pre_call 129 | def discover(self, hostname=None, mode=None, payload=None): 130 | return self.session.query('discover_services', payload) 131 | 132 | 133 | class Changes(object): 134 | def __init__(self, url, username, secret, verify=True): 135 | url = "%s/check_mk/webapi.py" % url.rstrip('/') 136 | session = DataTuple(url, username, secret, verify) 137 | self.session = WebAPI(session.data) 138 | 139 | def pre_call(fn): 140 | def _decorator(self, **kwargs): 141 | if kwargs.get('payload', None): 142 | payload = kwargs['payload'] 143 | else: 144 | payload = {} 145 | if kwargs.get('sites', None): 146 | payload['mode'] = 'specific' 147 | payload['sites'] = list(kwargs['sites']) 148 | if kwargs.get('allow_foreign_changes', None): 149 | payload['allow_foreign_changes'] = str(kwargs['allow_foreign_changes']) 150 | if kwargs.get('comment', None): 151 | payload['comment'] = str(kwargs['comment']) 152 | return fn(self, payload=payload) 153 | return _decorator 154 | 155 | @pre_call 156 | def activate(self, sites=None, allow_foreign_changes=None, comment=None, payload=None): 157 | return self.session.query('activate_changes', payload) 158 | -------------------------------------------------------------------------------- /roles/cmk_host_registration/tasks/main.yml: -------------------------------------------------------------------------------- 1 | --- 2 | 3 | - set_fact: 4 | OS: "linux" 5 | when: ansible_system == "Linux" 6 | 7 | - set_fact: 8 | OS: "windows" 9 | when: ansible_os_family == "Windows" 10 | 11 | - name: Add host 12 | checkmk_host: 13 | url: "{{ cmk_site_url }}" 14 | user: "{{ cmk_site_user }}" 15 | password: "{{ cmk_site_password }}" 16 | name: "{{ ansible_fqdn }}" 17 | folder: "{{ cmk_site_default_folder }}/{{ OS }}" 18 | state: present 19 | discover_services: yes 20 | validate_certs: "{{ cmk_validate_certs }}" 21 | delegate_to: localhost 22 | notify: 23 | - activate changes 24 | --------------------------------------------------------------------------------