mirror of https://github.com/ansible/ansible.git
You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
2171 lines
74 KiB
Python
2171 lines
74 KiB
Python
8 years ago
|
#!/usr/bin/python
|
||
|
|
||
|
"""LogicMonitor Ansible module for managing Collectors, Hosts and Hostgroups
|
||
|
Copyright (C) 2015 LogicMonitor
|
||
|
|
||
|
This program is free software; you can redistribute it and/or modify
|
||
|
it under the terms of the GNU General Public License as published by
|
||
|
the Free Software Foundation; either version 3 of the License, or
|
||
|
(at your option) any later version.
|
||
|
|
||
|
This program is distributed in the hope that it will be useful,
|
||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||
|
GNU General Public License for more details.
|
||
|
|
||
|
You should have received a copy of the GNU General Public License
|
||
|
along with this program; if not, write to the Free Software Foundation,
|
||
|
Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA"""
|
||
|
|
||
|
import datetime
|
||
|
import os
|
||
|
import platform
|
||
|
import socket
|
||
|
import sys
|
||
|
import types
|
||
|
import urllib
|
||
|
|
||
|
HAS_LIB_JSON = True
|
||
|
try:
|
||
|
import json
|
||
|
# Detect the python-json library which is incompatible
|
||
|
# Look for simplejson if that's the case
|
||
|
try:
|
||
|
if (
|
||
|
not isinstance(json.loads, types.FunctionType) or
|
||
|
not isinstance(json.dumps, types.FunctionType)
|
||
|
):
|
||
|
raise ImportError
|
||
|
except AttributeError:
|
||
|
raise ImportError
|
||
|
except ImportError:
|
||
|
try:
|
||
|
import simplejson as json
|
||
|
except ImportError:
|
||
|
print(
|
||
|
'\n{"msg": "Error: ansible requires the stdlib json or ' +
|
||
|
'simplejson module, neither was found!", "failed": true}'
|
||
|
)
|
||
|
HAS_LIB_JSON = False
|
||
|
except SyntaxError:
|
||
|
print(
|
||
|
'\n{"msg": "SyntaxError: probably due to installed simplejson ' +
|
||
|
'being for a different python version", "failed": true}'
|
||
|
)
|
||
|
HAS_LIB_JSON = False
|
||
|
|
||
|
RETURN = '''
|
||
|
---
|
||
|
success:
|
||
|
description: flag indicating that execution was successful
|
||
|
returned: success
|
||
|
type: boolean
|
||
|
sample: True
|
||
|
...
|
||
|
'''
|
||
|
|
||
|
|
||
|
DOCUMENTATION = '''
|
||
|
---
|
||
|
module: logicmonitor
|
||
|
short_description: Manage your LogicMonitor account through Ansible Playbooks
|
||
|
description:
|
||
|
- LogicMonitor is a hosted, full-stack, infrastructure monitoring platform.
|
||
|
- This module manages hosts, host groups, and collectors within your LogicMonitor account.
|
||
|
version_added: "2.2"
|
||
|
author: Ethan Culler-Mayeno, Jeff Wozniak
|
||
|
notes:
|
||
|
- You must have an existing LogicMonitor account for this module to function.
|
||
|
requirements: ["An existing LogicMonitor account", "Linux"]
|
||
|
options:
|
||
|
target:
|
||
|
description:
|
||
|
- The type of LogicMonitor object you wish to manage.
|
||
|
- "Collector: Perform actions on a LogicMonitor collector"
|
||
|
- NOTE You should use Ansible service modules such as 'service' or 'supervisorctl' for managing the Collector 'logicmonitor-agent' and 'logicmonitor-watchdog' services. Specifically, you'll probably want to start these services after a Collector add and stop these services before a Collector remove.
|
||
|
- "Host: Perform actions on a host device"
|
||
|
- "Hostgroup: Perform actions on a LogicMonitor host group"
|
||
|
- NOTE Host and Hostgroup tasks should always be performed via local_action. There are no benefits to running these tasks on the remote host and doing so will typically cause problems.
|
||
|
required: true
|
||
|
default: null
|
||
|
choices: ['collector', 'host', 'datsource', 'hostgroup']
|
||
|
action:
|
||
|
description:
|
||
|
- The action you wish to perform on target
|
||
|
- "Add: Add an object to your LogicMonitor account"
|
||
|
- "Remove: Remove an object from your LogicMonitor account"
|
||
|
- "Update: Update properties, description, or groups (target=host) for an object in your LogicMonitor account"
|
||
|
- "SDT: Schedule downtime for an object in your LogicMonitor account"
|
||
|
required: true
|
||
|
default: null
|
||
|
choices: ['add', 'remove', 'update', 'sdt']
|
||
|
company:
|
||
|
description:
|
||
|
- The LogicMonitor account company name. If you would log in to your account at "superheroes.logicmonitor.com" you would use "superheroes"
|
||
|
required: true
|
||
|
default: null
|
||
|
user:
|
||
|
description:
|
||
|
- A LogicMonitor user name. The module will authenticate and perform actions on behalf of this user
|
||
|
required: true
|
||
|
default: null
|
||
|
password:
|
||
|
description:
|
||
|
- The password of the specified LogicMonitor user
|
||
|
required: true
|
||
|
default: null
|
||
|
collector:
|
||
|
description:
|
||
|
- The fully qualified domain name of a collector in your LogicMonitor account.
|
||
|
- This is required for the creation of a LogicMonitor host (target=host action=add)
|
||
|
- This is required for updating, removing or scheduling downtime for hosts if 'displayname' isn't specified (target=host action=update action=remove action=sdt)
|
||
|
required: false
|
||
|
default: null
|
||
|
hostname:
|
||
|
description:
|
||
|
- The hostname of a host in your LogicMonitor account, or the desired hostname of a device to manage.
|
||
|
- Optional for managing hosts (target=host)
|
||
|
required: false
|
||
|
default: 'hostname -f'
|
||
|
displayname:
|
||
|
description:
|
||
|
- The display name of a host in your LogicMonitor account or the desired display name of a device to manage.
|
||
|
- Optional for managing hosts (target=host)
|
||
|
required: false
|
||
|
default: 'hostname -f'
|
||
|
description:
|
||
|
description:
|
||
|
- The long text description of the object in your LogicMonitor account
|
||
|
- Optional for managing hosts and host groups (target=host or target=hostgroup; action=add or action=update)
|
||
|
required: false
|
||
|
default: ""
|
||
|
properties:
|
||
|
description:
|
||
|
- A dictionary of properties to set on the LogicMonitor host or host group.
|
||
|
- Optional for managing hosts and host groups (target=host or target=hostgroup; action=add or action=update)
|
||
|
- This parameter will add or update existing properties in your LogicMonitor account or
|
||
|
required: false
|
||
|
default: {}
|
||
|
groups:
|
||
|
description:
|
||
|
- A list of groups that the host should be a member of.
|
||
|
- Optional for managing hosts (target=host; action=add or action=update)
|
||
|
required: false
|
||
|
default: []
|
||
|
id:
|
||
|
description:
|
||
|
- ID of the datasource to target
|
||
|
- Required for management of LogicMonitor datasources (target=datasource)
|
||
|
required: false
|
||
|
default: null
|
||
|
fullpath:
|
||
|
description:
|
||
|
- The fullpath of the host group object you would like to manage
|
||
|
- Recommend running on a single Ansible host
|
||
|
- Required for management of LogicMonitor host groups (target=hostgroup)
|
||
|
required: false
|
||
|
default: null
|
||
|
alertenable:
|
||
|
description:
|
||
|
- A boolean flag to turn alerting on or off for an object
|
||
|
- Optional for managing all hosts (action=add or action=update)
|
||
|
required: false
|
||
|
default: true
|
||
|
choices: [true, false]
|
||
|
starttime:
|
||
|
description:
|
||
|
- The time that the Scheduled Down Time (SDT) should begin
|
||
|
- Optional for managing SDT (action=sdt)
|
||
|
- Y-m-d H:M
|
||
|
required: false
|
||
|
default: Now
|
||
|
duration:
|
||
|
description:
|
||
|
- The duration (minutes) of the Scheduled Down Time (SDT)
|
||
|
- Optional for putting an object into SDT (action=sdt)
|
||
|
required: false
|
||
|
default: 30
|
||
|
...
|
||
|
'''
|
||
|
EXAMPLES = '''
|
||
|
# example of adding a new LogicMonitor collector to these devices
|
||
|
---
|
||
|
- hosts: collectors
|
||
|
remote_user: '{{ username }}'
|
||
|
vars:
|
||
|
company: 'mycompany'
|
||
|
user: 'myusername'
|
||
|
password: 'mypassword'
|
||
|
tasks:
|
||
|
- name: Deploy/verify LogicMonitor collectors
|
||
|
become: yes
|
||
|
logicmonitor:
|
||
|
target=collector
|
||
|
action=add
|
||
|
company={{ company }}
|
||
|
user={{ user }}
|
||
|
password={{ password }}
|
||
|
|
||
|
#example of adding a list of hosts into monitoring
|
||
|
---
|
||
|
- hosts: hosts
|
||
|
remote_user: '{{ username }}'
|
||
|
vars:
|
||
|
company: 'mycompany'
|
||
|
user: 'myusername'
|
||
|
password: 'mypassword'
|
||
|
tasks:
|
||
|
- name: Deploy LogicMonitor Host
|
||
|
# All tasks except for target=collector should use local_action
|
||
|
local_action: >
|
||
|
logicmonitor
|
||
|
target=host
|
||
|
action=add
|
||
|
collector='mycompany-Collector'
|
||
|
company='{{ company }}'
|
||
|
user='{{ user }}'
|
||
|
password='{{ password }}'
|
||
|
groups="/servers/production,/datacenter1"
|
||
|
properties="{'snmp.community':'secret','dc':'1', 'type':'prod'}"
|
||
|
|
||
|
#example of putting a datasource in SDT
|
||
|
---
|
||
|
- hosts: localhost
|
||
|
remote_user: '{{ username }}'
|
||
|
vars:
|
||
|
company: 'mycompany'
|
||
|
user: 'myusername'
|
||
|
password: 'mypassword'
|
||
|
tasks:
|
||
|
- name: SDT a datasource
|
||
|
# All tasks except for target=collector should use local_action
|
||
|
local_action: >
|
||
|
logicmonitor
|
||
|
target=datasource
|
||
|
action=sdt
|
||
|
id='123'
|
||
|
duration=3000
|
||
|
starttime='2017-03-04 05:06'
|
||
|
company='{{ company }}'
|
||
|
user='{{ user }}'
|
||
|
password='{{ password }}'
|
||
|
|
||
|
#example of creating a hostgroup
|
||
|
---
|
||
|
- hosts: localhost
|
||
|
remote_user: '{{ username }}'
|
||
|
vars:
|
||
|
company: 'mycompany'
|
||
|
user: 'myusername'
|
||
|
password: 'mypassword'
|
||
|
tasks:
|
||
|
- name: Create a host group
|
||
|
# All tasks except for target=collector should use local_action
|
||
|
local_action: >
|
||
|
logicmonitor
|
||
|
target=hostgroup
|
||
|
action=add
|
||
|
fullpath='/servers/development'
|
||
|
company='{{ company }}'
|
||
|
user='{{ user }}'
|
||
|
password='{{ password }}'
|
||
|
properties="{'snmp.community':'commstring', 'type':'dev'}"
|
||
|
|
||
|
#example of putting a list of hosts into SDT
|
||
|
---
|
||
|
- hosts: hosts
|
||
|
remote_user: '{{ username }}'
|
||
|
vars:
|
||
|
company: 'mycompany'
|
||
|
user: 'myusername'
|
||
|
password: 'mypassword'
|
||
|
tasks:
|
||
|
- name: SDT hosts
|
||
|
# All tasks except for target=collector should use local_action
|
||
|
local_action: >
|
||
|
logicmonitor
|
||
|
target=host
|
||
|
action=sdt
|
||
|
duration=3000
|
||
|
starttime='2016-11-10 09:08'
|
||
|
company='{{ company }}'
|
||
|
user='{{ user }}'
|
||
|
password='{{ password }}'
|
||
|
collector='mycompany-Collector'
|
||
|
|
||
|
#example of putting a host group in SDT
|
||
|
---
|
||
|
- hosts: localhost
|
||
|
remote_user: '{{ username }}'
|
||
|
vars:
|
||
|
company: 'mycompany'
|
||
|
user: 'myusername'
|
||
|
password: 'mypassword'
|
||
|
tasks:
|
||
|
- name: SDT a host group
|
||
|
# All tasks except for target=collector should use local_action
|
||
|
local_action: >
|
||
|
logicmonitor
|
||
|
target=hostgroup
|
||
|
action=sdt
|
||
|
fullpath='/servers/development'
|
||
|
duration=3000
|
||
|
starttime='2017-03-04 05:06'
|
||
|
company='{{ company }}'
|
||
|
user='{{ user }}'
|
||
|
password='{{ password }}'
|
||
|
|
||
|
#example of updating a list of hosts
|
||
|
---
|
||
|
- hosts: hosts
|
||
|
remote_user: '{{ username }}'
|
||
|
vars:
|
||
|
company: 'mycompany'
|
||
|
user: 'myusername'
|
||
|
password: 'mypassword'
|
||
|
tasks:
|
||
|
- name: Update a list of hosts
|
||
|
# All tasks except for target=collector should use local_action
|
||
|
local_action: >
|
||
|
logicmonitor
|
||
|
target=host
|
||
|
action=update
|
||
|
company='{{ company }}'
|
||
|
user='{{ user }}'
|
||
|
password='{{ password }}'
|
||
|
collector='mycompany-Collector'
|
||
|
groups="/servers/production,/datacenter5"
|
||
|
properties="{'snmp.community':'commstring','dc':'5'}"
|
||
|
|
||
|
#example of updating a hostgroup
|
||
|
---
|
||
|
- hosts: hosts
|
||
|
remote_user: '{{ username }}'
|
||
|
vars:
|
||
|
company: 'mycompany'
|
||
|
user: 'myusername'
|
||
|
password: 'mypassword'
|
||
|
tasks:
|
||
|
- name: Update a host group
|
||
|
# All tasks except for target=collector should use local_action
|
||
|
local_action: >
|
||
|
logicmonitor
|
||
|
target=hostgroup
|
||
|
action=update
|
||
|
fullpath='/servers/development'
|
||
|
company='{{ company }}'
|
||
|
user='{{ user }}'
|
||
|
password='{{ password }}'
|
||
|
properties="{'snmp.community':'hg', 'type':'dev', 'status':'test'}"
|
||
|
|
||
|
#example of removing a list of hosts from monitoring
|
||
|
---
|
||
|
- hosts: hosts
|
||
|
remote_user: '{{ username }}'
|
||
|
vars:
|
||
|
company: 'mycompany'
|
||
|
user: 'myusername'
|
||
|
password: 'mypassword'
|
||
|
tasks:
|
||
|
- name: Remove LogicMonitor hosts
|
||
|
# All tasks except for target=collector should use local_action
|
||
|
local_action: >
|
||
|
logicmonitor
|
||
|
target=host
|
||
|
action=remove
|
||
|
company='{{ company }}'
|
||
|
user='{{ user }}'
|
||
|
password='{{ password }}'
|
||
|
collector='mycompany-Collector'
|
||
|
|
||
|
#example of removing a host group
|
||
|
---
|
||
|
- hosts: hosts
|
||
|
remote_user: '{{ username }}'
|
||
|
vars:
|
||
|
company: 'mycompany'
|
||
|
user: 'myusername'
|
||
|
password: 'mypassword'
|
||
|
tasks:
|
||
|
- name: Remove LogicMonitor development servers hostgroup
|
||
|
# All tasks except for target=collector should use local_action
|
||
|
local_action: >
|
||
|
logicmonitor
|
||
|
target=hostgroup
|
||
|
action=remove
|
||
|
company='{{ company }}'
|
||
|
user='{{ user }}'
|
||
|
password='{{ password }}'
|
||
|
fullpath='/servers/development'
|
||
|
- name: Remove LogicMonitor servers hostgroup
|
||
|
# All tasks except for target=collector should use local_action
|
||
|
local_action: >
|
||
|
logicmonitor
|
||
|
target=hostgroup
|
||
|
action=remove
|
||
|
company='{{ company }}'
|
||
|
user='{{ user }}'
|
||
|
password='{{ password }}'
|
||
|
fullpath='/servers'
|
||
|
- name: Remove LogicMonitor datacenter1 hostgroup
|
||
|
# All tasks except for target=collector should use local_action
|
||
|
local_action: >
|
||
|
logicmonitor
|
||
|
target=hostgroup
|
||
|
action=remove
|
||
|
company='{{ company }}'
|
||
|
user='{{ user }}'
|
||
|
password='{{ password }}'
|
||
|
fullpath='/datacenter1'
|
||
|
- name: Remove LogicMonitor datacenter5 hostgroup
|
||
|
# All tasks except for target=collector should use local_action
|
||
|
local_action: >
|
||
|
logicmonitor
|
||
|
target=hostgroup
|
||
|
action=remove
|
||
|
company='{{ company }}'
|
||
|
user='{{ user }}'
|
||
|
password='{{ password }}'
|
||
|
fullpath='/datacenter5'
|
||
|
|
||
|
### example of removing a new LogicMonitor collector to these devices
|
||
|
---
|
||
|
- hosts: collectors
|
||
|
remote_user: '{{ username }}'
|
||
|
vars:
|
||
|
company: 'mycompany'
|
||
|
user: 'myusername'
|
||
|
password: 'mypassword'
|
||
|
tasks:
|
||
|
- name: Remove LogicMonitor collectors
|
||
|
become: yes
|
||
|
logicmonitor:
|
||
|
target=collector
|
||
|
action=remove
|
||
|
company={{ company }}
|
||
|
user={{ user }}
|
||
|
password={{ password }}
|
||
|
|
||
|
#complete example
|
||
|
---
|
||
|
- hosts: localhost
|
||
|
remote_user: '{{ username }}'
|
||
|
vars:
|
||
|
company: 'mycompany'
|
||
|
user: 'myusername'
|
||
|
password: 'mypassword'
|
||
|
tasks:
|
||
|
- name: Create a host group
|
||
|
local_action: >
|
||
|
logicmonitor
|
||
|
target=hostgroup
|
||
|
action=add
|
||
|
fullpath='/servers/production/database'
|
||
|
company='{{ company }}'
|
||
|
user='{{ user }}'
|
||
|
password='{{ password }}'
|
||
|
properties="{'snmp.community':'commstring'}"
|
||
|
- name: SDT a host group
|
||
|
local_action: >
|
||
|
logicmonitor
|
||
|
target=hostgroup
|
||
|
action=sdt
|
||
|
fullpath='/servers/production/web'
|
||
|
duration=3000
|
||
|
starttime='2012-03-04 05:06'
|
||
|
company='{{ company }}'
|
||
|
user='{{ user }}'
|
||
|
password='{{ password }}'
|
||
|
|
||
|
- hosts: collectors
|
||
|
remote_user: '{{ username }}'
|
||
|
vars:
|
||
|
company: 'mycompany'
|
||
|
user: 'myusername'
|
||
|
password: 'mypassword'
|
||
|
tasks:
|
||
|
- name: Deploy/verify LogicMonitor collectors
|
||
|
logicmonitor:
|
||
|
target: collector
|
||
|
action: add
|
||
|
company: {{ company }}
|
||
|
user: {{ user }}
|
||
|
password: {{ password }}
|
||
|
- name: Place LogicMonitor collectors into 30 minute Scheduled downtime
|
||
|
logicmonitor: target=collector action=sdt company={{ company }}
|
||
|
user={{ user }} password={{ password }}
|
||
|
- name: Deploy LogicMonitor Host
|
||
|
local_action: >
|
||
|
logicmonitor
|
||
|
target=host
|
||
|
action=add
|
||
|
collector=agent1.ethandev.com
|
||
|
company='{{ company }}'
|
||
|
user='{{ user }}'
|
||
|
password='{{ password }}'
|
||
|
properties="{'snmp.community':'commstring', 'dc':'1'}"
|
||
|
groups="/servers/production/collectors, /datacenter1"
|
||
|
|
||
|
- hosts: database-servers
|
||
|
remote_user: '{{ username }}'
|
||
|
vars:
|
||
|
company: 'mycompany'
|
||
|
user: 'myusername'
|
||
|
password: 'mypassword'
|
||
|
tasks:
|
||
|
- name: deploy logicmonitor hosts
|
||
|
local_action: >
|
||
|
logicmonitor
|
||
|
target=host
|
||
|
action=add
|
||
|
collector=monitoring.dev.com
|
||
|
company='{{ company }}'
|
||
|
user='{{ user }}'
|
||
|
password='{{ password }}'
|
||
|
properties="{'snmp.community':'commstring', 'type':'db', 'dc':'1'}"
|
||
|
groups="/servers/production/database, /datacenter1"
|
||
|
- name: schedule 5 hour downtime for 2012-11-10 09:08
|
||
|
local_action: >
|
||
|
logicmonitor
|
||
|
target=host
|
||
|
action=sdt
|
||
|
duration=3000
|
||
|
starttime='2012-11-10 09:08'
|
||
|
company='{{ company }}'
|
||
|
user='{{ user }}'
|
||
|
password='{{ password }}'
|
||
|
'''
|
||
|
|
||
|
|
||
|
class LogicMonitor(object):
|
||
|
|
||
|
def __init__(self, module, **params):
|
||
|
self.__version__ = "1.0-python"
|
||
|
self.module = module
|
||
|
self.module.debug("Instantiating LogicMonitor object")
|
||
|
|
||
|
self.check_mode = False
|
||
|
self.company = params["company"]
|
||
|
self.user = params["user"]
|
||
|
self.password = params["password"]
|
||
|
self.fqdn = socket.getfqdn()
|
||
|
self.lm_url = "logicmonitor.com/santaba"
|
||
|
self.urlopen = open_url # use the ansible provided open_url
|
||
|
self.__version__ = self.__version__ + "-ansible-module"
|
||
|
|
||
|
def rpc(self, action, params):
|
||
|
"""Make a call to the LogicMonitor RPC library
|
||
|
and return the response"""
|
||
|
self.module.debug("Running LogicMonitor.rpc")
|
||
|
|
||
|
param_str = urllib.urlencode(params)
|
||
|
creds = urllib.urlencode(
|
||
|
{"c": self.company,
|
||
|
"u": self.user,
|
||
|
"p": self.password})
|
||
|
|
||
|
if param_str:
|
||
|
param_str = param_str + "&"
|
||
|
|
||
|
param_str = param_str + creds
|
||
|
|
||
|
try:
|
||
|
url = ("https://" + self.company + "." + self.lm_url +
|
||
|
"/rpc/" + action + "?" + param_str)
|
||
|
|
||
|
# Set custom LogicMonitor header with version
|
||
|
headers = {"X-LM-User-Agent": self.__version__}
|
||
|
|
||
|
# Set headers
|
||
|
f = self.urlopen(url, headers=headers)
|
||
|
|
||
|
raw = f.read()
|
||
|
resp = json.loads(raw)
|
||
|
if resp["status"] == 403:
|
||
|
self.module.debug("Authentication failed.")
|
||
|
self.fail(msg="Error: " + resp["errmsg"])
|
||
|
else:
|
||
|
return raw
|
||
|
except IOError:
|
||
|
self.fail(msg="Error: Unknown exception making RPC call")
|
||
|
|
||
|
def do(self, action, params):
|
||
|
"""Make a call to the LogicMonitor
|
||
|
server \"do\" function"""
|
||
|
self.module.debug("Running LogicMonitor.do...")
|
||
|
|
||
|
param_str = urllib.urlencode(params)
|
||
|
creds = (urllib.urlencode(
|
||
|
{"c": self.company,
|
||
|
"u": self.user,
|
||
|
"p": self.password}))
|
||
|
|
||
|
if param_str:
|
||
|
param_str = param_str + "&"
|
||
|
param_str = param_str + creds
|
||
|
|
||
|
try:
|
||
|
self.module.debug("Attempting to open URL: " +
|
||
|
"https://" + self.company + "." + self.lm_url +
|
||
|
"/do/" + action + "?" + param_str)
|
||
|
f = self.urlopen(
|
||
|
"https://" + self.company + "." + self.lm_url +
|
||
|
"/do/" + action + "?" + param_str)
|
||
|
return f.read()
|
||
|
except IOError:
|
||
|
# self.module.debug("Error opening URL. " + ioe)
|
||
|
self.fail("Unknown exception opening URL")
|
||
|
|
||
|
def get_collectors(self):
|
||
|
"""Returns a JSON object containing a list of
|
||
|
LogicMonitor collectors"""
|
||
|
self.module.debug("Running LogicMonitor.get_collectors...")
|
||
|
|
||
|
self.module.debug("Making RPC call to 'getAgents'")
|
||
|
resp = self.rpc("getAgents", {})
|
||
|
resp_json = json.loads(resp)
|
||
|
|
||
|
if resp_json["status"] is 200:
|
||
|
self.module.debug("RPC call succeeded")
|
||
|
return resp_json["data"]
|
||
|
else:
|
||
|
self.fail(msg=resp)
|
||
|
|
||
|
def get_host_by_hostname(self, hostname, collector):
|
||
|
"""Returns a host object for the host matching the
|
||
|
specified hostname"""
|
||
|
self.module.debug("Running LogicMonitor.get_host_by_hostname...")
|
||
|
|
||
|
self.module.debug("Looking for hostname " + hostname)
|
||
|
self.module.debug("Making RPC call to 'getHosts'")
|
||
|
hostlist_json = json.loads(self.rpc("getHosts", {"hostGroupId": 1}))
|
||
|
|
||
|
if collector:
|
||
|
if hostlist_json["status"] == 200:
|
||
|
self.module.debug("RPC call succeeded")
|
||
|
|
||
|
hosts = hostlist_json["data"]["hosts"]
|
||
|
|
||
|
self.module.debug(
|
||
|
"Looking for host matching: hostname " + hostname +
|
||
|
" and collector " + str(collector["id"]))
|
||
|
|
||
|
for host in hosts:
|
||
|
if (host["hostName"] == hostname and
|
||
|
host["agentId"] == collector["id"]):
|
||
|
|
||
|
self.module.debug("Host match found")
|
||
|
return host
|
||
|
self.module.debug("No host match found")
|
||
|
return None
|
||
|
else:
|
||
|
self.module.debug("RPC call failed")
|
||
|
self.module.debug(hostlist_json)
|
||
|
else:
|
||
|
self.module.debug("No collector specified")
|
||
|
return None
|
||
|
|
||
|
def get_host_by_displayname(self, displayname):
|
||
|
"""Returns a host object for the host matching the
|
||
|
specified display name"""
|
||
|
self.module.debug("Running LogicMonitor.get_host_by_displayname...")
|
||
|
|
||
|
self.module.debug("Looking for displayname " + displayname)
|
||
|
self.module.debug("Making RPC call to 'getHost'")
|
||
|
host_json = (json.loads(self.rpc("getHost",
|
||
|
{"displayName": displayname})))
|
||
|
|
||
|
if host_json["status"] == 200:
|
||
|
self.module.debug("RPC call succeeded")
|
||
|
return host_json["data"]
|
||
|
else:
|
||
|
self.module.debug("RPC call failed")
|
||
|
self.module.debug(host_json)
|
||
|
return None
|
||
|
|
||
|
def get_collector_by_description(self, description):
|
||
|
"""Returns a JSON collector object for the collector
|
||
|
matching the specified FQDN (description)"""
|
||
|
self.module.debug(
|
||
|
"Running LogicMonitor.get_collector_by_description..."
|
||
|
)
|
||
|
|
||
|
collector_list = self.get_collectors()
|
||
|
if collector_list is not None:
|
||
|
self.module.debug("Looking for collector with description {0}" +
|
||
|
description)
|
||
|
for collector in collector_list:
|
||
|
if collector["description"] == description:
|
||
|
self.module.debug("Collector match found")
|
||
|
return collector
|
||
|
self.module.debug("No collector match found")
|
||
|
return None
|
||
|
|
||
|
def get_group(self, fullpath):
|
||
|
"""Returns a JSON group object for the group matching the
|
||
|
specified path"""
|
||
|
self.module.debug("Running LogicMonitor.get_group...")
|
||
|
|
||
|
self.module.debug("Making RPC call to getHostGroups")
|
||
|
resp = json.loads(self.rpc("getHostGroups", {}))
|
||
|
|
||
|
if resp["status"] == 200:
|
||
|
self.module.debug("RPC called succeeded")
|
||
|
groups = resp["data"]
|
||
|
|
||
|
self.module.debug("Looking for group matching " + fullpath)
|
||
|
for group in groups:
|
||
|
if group["fullPath"] == fullpath.lstrip('/'):
|
||
|
self.module.debug("Group match found")
|
||
|
return group
|
||
|
|
||
|
self.module.debug("No group match found")
|
||
|
return None
|
||
|
else:
|
||
|
self.module.debug("RPC call failed")
|
||
|
self.module.debug(resp)
|
||
|
|
||
|
return None
|
||
|
|
||
|
def create_group(self, fullpath):
|
||
|
"""Recursively create a path of host groups.
|
||
|
Returns the id of the newly created hostgroup"""
|
||
|
self.module.debug("Running LogicMonitor.create_group...")
|
||
|
|
||
|
res = self.get_group(fullpath)
|
||
|
if res:
|
||
|
self.module.debug("Group {0} exists." + fullpath)
|
||
|
return res["id"]
|
||
|
|
||
|
if fullpath == "/":
|
||
|
self.module.debug("Specified group is root. Doing nothing.")
|
||
|
return 1
|
||
|
else:
|
||
|
self.module.debug("Creating group named " + fullpath)
|
||
|
self.module.debug("System changed")
|
||
|
self.change = True
|
||
|
|
||
|
if self.check_mode:
|
||
|
self.exit(changed=True)
|
||
|
|
||
|
parentpath, name = fullpath.rsplit('/', 1)
|
||
|
parentgroup = self.get_group(parentpath)
|
||
|
|
||
|
parentid = 1
|
||
|
|
||
|
if parentpath == "":
|
||
|
parentid = 1
|
||
|
elif parentgroup:
|
||
|
parentid = parentgroup["id"]
|
||
|
else:
|
||
|
parentid = self.create_group(parentpath)
|
||
|
|
||
|
h = None
|
||
|
|
||
|
# Determine if we're creating a group from host or hostgroup class
|
||
|
if hasattr(self, '_build_host_group_hash'):
|
||
|
h = self._build_host_group_hash(
|
||
|
fullpath,
|
||
|
self.description,
|
||
|
self.properties,
|
||
|
self.alertenable)
|
||
|
h["name"] = name
|
||
|
h["parentId"] = parentid
|
||
|
else:
|
||
|
h = {"name": name,
|
||
|
"parentId": parentid,
|
||
|
"alertEnable": True,
|
||
|
"description": ""}
|
||
|
|
||
|
self.module.debug("Making RPC call to 'addHostGroup'")
|
||
|
resp = json.loads(
|
||
|
self.rpc("addHostGroup", h))
|
||
|
|
||
|
if resp["status"] == 200:
|
||
|
self.module.debug("RPC call succeeded")
|
||
|
return resp["data"]["id"]
|
||
|
elif resp["errmsg"] == "The record already exists":
|
||
|
self.module.debug("The hostgroup already exists")
|
||
|
group = self.get_group(fullpath)
|
||
|
return group["id"]
|
||
|
else:
|
||
|
self.module.debug("RPC call failed")
|
||
|
self.fail(
|
||
|
msg="Error: unable to create new hostgroup \"" +
|
||
|
name + "\".\n" + resp["errmsg"])
|
||
|
|
||
|
def fail(self, msg):
|
||
|
self.module.fail_json(msg=msg, changed=self.change, failed=True)
|
||
|
|
||
|
def exit(self, changed):
|
||
|
self.module.debug("Changed: " + changed)
|
||
|
self.module.exit_json(changed=changed, success=True)
|
||
|
|
||
|
def output_info(self, info):
|
||
|
self.module.debug("Registering properties as Ansible facts")
|
||
|
self.module.exit_json(changed=False, ansible_facts=info)
|
||
|
|
||
|
|
||
|
class Collector(LogicMonitor):
|
||
|
|
||
|
def __init__(self, params, module=None):
|
||
|
"""Initializor for the LogicMonitor Collector object"""
|
||
|
self.change = False
|
||
|
self.params = params
|
||
|
|
||
|
LogicMonitor.__init__(self, module, **params)
|
||
|
self.module.debug("Instantiating Collector object")
|
||
|
|
||
|
if self.params['description']:
|
||
|
self.description = self.params['description']
|
||
|
else:
|
||
|
self.description = self.fqdn
|
||
|
|
||
|
self.info = self._get()
|
||
|
self.installdir = "/usr/local/logicmonitor"
|
||
|
self.platform = platform.system()
|
||
|
self.is_64bits = sys.maxsize > 2**32
|
||
|
self.duration = self.params['duration']
|
||
|
self.starttime = self.params['starttime']
|
||
|
|
||
|
if self.info is None:
|
||
|
self.id = None
|
||
|
else:
|
||
|
self.id = self.info["id"]
|
||
|
|
||
|
def create(self):
|
||
|
"""Idempotent function to make sure that there is
|
||
|
a running collector installed and registered"""
|
||
|
self.module.debug("Running Collector.create...")
|
||
|
|
||
|
self._create()
|
||
|
self.get_installer_binary()
|
||
|
self.install()
|
||
|
|
||
|
def remove(self):
|
||
|
"""Idempotent function to make sure that there is
|
||
|
not a running collector installed and registered"""
|
||
|
self.module.debug("Running Collector.destroy...")
|
||
|
|
||
|
self._unreigster()
|
||
|
self.uninstall()
|
||
|
|
||
|
def get_installer_binary(self):
|
||
|
"""Download the LogicMonitor collector installer binary"""
|
||
|
self.module.debug("Running Collector.get_installer_binary...")
|
||
|
|
||
|
arch = 32
|
||
|
|
||
|
if self.is_64bits:
|
||
|
self.module.debug("64 bit system")
|
||
|
arch = 64
|
||
|
else:
|
||
|
self.module.debug("32 bit system")
|
||
|
|
||
|
if self.platform == "Linux" and self.id is not None:
|
||
|
self.module.debug("Platform is Linux")
|
||
|
self.module.debug("Agent ID is " + str(self.id))
|
||
|
|
||
|
installfilepath = (self.installdir +
|
||
|
"/logicmonitorsetup" +
|
||
|
str(self.id) + "_" + str(arch) +
|
||
|
".bin")
|
||
|
|
||
|
self.module.debug("Looking for existing installer at " +
|
||
|
installfilepath)
|
||
|
if not os.path.isfile(installfilepath):
|
||
|
self.module.debug("No previous installer found")
|
||
|
self.module.debug("System changed")
|
||
|
self.change = True
|
||
|
|
||
|
if self.check_mode:
|
||
|
self.exit(changed=True)
|
||
|
|
||
|
self.module.debug("Downloading installer file")
|
||
|
# attempt to create the install dir before download
|
||
|
self.module.run_command("mkdir " + self.installdir)
|
||
|
|
||
|
try:
|
||
|
f = open(installfilepath, "w")
|
||
|
installer = (self.do("logicmonitorsetup",
|
||
|
{"id": self.id,
|
||
|
"arch": arch}))
|
||
|
f.write(installer)
|
||
|
f.closed
|
||
|
except:
|
||
|
self.fail(msg="Unable to open installer file for writing")
|
||
|
f.closed
|
||
|
else:
|
||
|
self.module.debug("Collector installer already exists")
|
||
|
return installfilepath
|
||
|
|
||
|
elif self.id is None:
|
||
|
self.fail(
|
||
|
msg="Error: There is currently no collector " +
|
||
|
"associated with this device. To download " +
|
||
|
" the installer, first create a collector " +
|
||
|
"for this device.")
|
||
|
elif self.platform != "Linux":
|
||
|
self.fail(
|
||
|
msg="Error: LogicMonitor Collector must be " +
|
||
|
"installed on a Linux device.")
|
||
|
else:
|
||
|
self.fail(
|
||
|
msg="Error: Unable to retrieve the installer from the server")
|
||
|
|
||
|
def install(self):
|
||
|
"""Execute the LogicMonitor installer if not
|
||
|
already installed"""
|
||
|
self.module.debug("Running Collector.install...")
|
||
|
|
||
|
if self.platform == "Linux":
|
||
|
self.module.debug("Platform is Linux")
|
||
|
|
||
|
installer = self.get_installer_binary()
|
||
|
|
||
|
if self.info is None:
|
||
|
self.module.debug("Retriving collector information")
|
||
|
self.info = self._get()
|
||
|
|
||
|
if not os.path.exists(self.installdir + "/agent"):
|
||
|
self.module.debug("System changed")
|
||
|
self.change = True
|
||
|
|
||
|
if self.check_mode:
|
||
|
self.exit(changed=True)
|
||
|
|
||
|
self.module.debug("Setting installer file permissions")
|
||
|
os.chmod(installer, 484) # decimal for 0o744
|
||
|
|
||
|
self.module.debug("Executing installer")
|
||
|
ret_code, out, err = self.module.run_command(installer + " -y")
|
||
|
|
||
|
if ret_code != 0:
|
||
|
self.fail(msg="Error: Unable to install collector: " + err)
|
||
|
else:
|
||
|
self.module.debug("Collector installed successfully")
|
||
|
else:
|
||
|
self.module.debug("Collector already installed")
|
||
|
else:
|
||
|
self.fail(
|
||
|
msg="Error: LogicMonitor Collector must be " +
|
||
|
"installed on a Linux device")
|
||
|
|
||
|
def uninstall(self):
|
||
|
"""Uninstall LogicMontitor collector from the system"""
|
||
|
self.module.debug("Running Collector.uninstall...")
|
||
|
|
||
|
uninstallfile = self.installdir + "/agent/bin/uninstall.pl"
|
||
|
|
||
|
if os.path.isfile(uninstallfile):
|
||
|
self.module.debug("Collector uninstall file exists")
|
||
|
self.module.debug("System changed")
|
||
|
self.change = True
|
||
|
|
||
|
if self.check_mode:
|
||
|
self.exit(changed=True)
|
||
|
|
||
|
self.module.debug("Running collector uninstaller")
|
||
|
ret_code, out, err = self.module.run_command(uninstallfile)
|
||
|
|
||
|
if ret_code != 0:
|
||
|
self.fail(
|
||
|
msg="Error: Unable to uninstall collector: " + err)
|
||
|
else:
|
||
|
self.module.debug("Collector successfully uninstalled")
|
||
|
else:
|
||
|
if os.path.exists(self.installdir + "/agent"):
|
||
|
(self.fail(
|
||
|
msg="Unable to uninstall LogicMonitor " +
|
||
|
"Collector. Can not find LogicMonitor " +
|
||
|
"uninstaller."))
|
||
|
|
||
|
def sdt(self):
|
||
|
"""Create a scheduled down time
|
||
|
(maintenance window) for this host"""
|
||
|
self.module.debug("Running Collector.sdt...")
|
||
|
|
||
|
self.module.debug("System changed")
|
||
|
self.change = True
|
||
|
|
||
|
if self.check_mode:
|
||
|
self.exit(changed=True)
|
||
|
|
||
|
duration = self.duration
|
||
|
starttime = self.starttime
|
||
|
offsetstart = starttime
|
||
|
|
||
|
if starttime:
|
||
|
self.module.debug("Start time specified")
|
||
|
start = datetime.datetime.strptime(starttime, '%Y-%m-%d %H:%M')
|
||
|
offsetstart = start
|
||
|
else:
|
||
|
self.module.debug("No start time specified. Using default.")
|
||
|
start = datetime.datetime.utcnow()
|
||
|
|
||
|
# Use user UTC offset
|
||
|
self.module.debug("Making RPC call to 'getTimeZoneSetting'")
|
||
|
accountresp = json.loads(self.rpc("getTimeZoneSetting", {}))
|
||
|
|
||
|
if accountresp["status"] == 200:
|
||
|
self.module.debug("RPC call succeeded")
|
||
|
|
||
|
offset = accountresp["data"]["offset"]
|
||
|
offsetstart = start + datetime.timedelta(0, offset)
|
||
|
else:
|
||
|
self.fail(msg="Error: Unable to retrieve timezone offset")
|
||
|
|
||
|
offsetend = offsetstart + datetime.timedelta(0, int(duration)*60)
|
||
|
|
||
|
h = {"agentId": self.id,
|
||
|
"type": 1,
|
||
|
"notifyCC": True,
|
||
|
"year": offsetstart.year,
|
||
|
"month": offsetstart.month-1,
|
||
|
"day": offsetstart.day,
|
||
|
"hour": offsetstart.hour,
|
||
|
"minute": offsetstart.minute,
|
||
|
"endYear": offsetend.year,
|
||
|
"endMonth": offsetend.month-1,
|
||
|
"endDay": offsetend.day,
|
||
|
"endHour": offsetend.hour,
|
||
|
"endMinute": offsetend.minute}
|
||
|
|
||
|
self.module.debug("Making RPC call to 'setAgentSDT'")
|
||
|
resp = json.loads(self.rpc("setAgentSDT", h))
|
||
|
|
||
|
if resp["status"] == 200:
|
||
|
self.module.debug("RPC call succeeded")
|
||
|
return resp["data"]
|
||
|
else:
|
||
|
self.module.debug("RPC call failed")
|
||
|
self.fail(msg=resp["errmsg"])
|
||
|
|
||
|
def site_facts(self):
|
||
|
"""Output current properties information for the Collector"""
|
||
|
self.module.debug("Running Collector.site_facts...")
|
||
|
|
||
|
if self.info:
|
||
|
self.module.debug("Collector exists")
|
||
|
props = self.get_properties(True)
|
||
|
|
||
|
self.output_info(props)
|
||
|
else:
|
||
|
self.fail(msg="Error: Collector doesn't exit.")
|
||
|
|
||
|
def _get(self):
|
||
|
"""Returns a JSON object representing this collector"""
|
||
|
self.module.debug("Running Collector._get...")
|
||
|
collector_list = self.get_collectors()
|
||
|
|
||
|
if collector_list is not None:
|
||
|
self.module.debug("Collectors returned")
|
||
|
for collector in collector_list:
|
||
|
if collector["description"] == self.description:
|
||
|
return collector
|
||
|
else:
|
||
|
self.module.debug("No collectors returned")
|
||
|
return None
|
||
|
|
||
|
def _create(self):
|
||
|
"""Create a new collector in the associated
|
||
|
LogicMonitor account"""
|
||
|
self.module.debug("Running Collector._create...")
|
||
|
|
||
|
if self.platform == "Linux":
|
||
|
self.module.debug("Platform is Linux")
|
||
|
ret = self.info or self._get()
|
||
|
|
||
|
if ret is None:
|
||
|
self.change = True
|
||
|
self.module.debug("System changed")
|
||
|
|
||
|
if self.check_mode:
|
||
|
self.exit(changed=True)
|
||
|
|
||
|
h = {"autogen": True,
|
||
|
"description": self.description}
|
||
|
|
||
|
self.module.debug("Making RPC call to 'addAgent'")
|
||
|
create = (json.loads(self.rpc("addAgent", h)))
|
||
|
|
||
|
if create["status"] is 200:
|
||
|
self.module.debug("RPC call succeeded")
|
||
|
self.info = create["data"]
|
||
|
self.id = create["data"]["id"]
|
||
|
return create["data"]
|
||
|
else:
|
||
|
self.fail(msg=create["errmsg"])
|
||
|
else:
|
||
|
self.info = ret
|
||
|
self.id = ret["id"]
|
||
|
return ret
|
||
|
else:
|
||
|
self.fail(
|
||
|
msg="Error: LogicMonitor Collector must be " +
|
||
|
"installed on a Linux device.")
|
||
|
|
||
|
def _unreigster(self):
|
||
|
"""Delete this collector from the associated
|
||
|
LogicMonitor account"""
|
||
|
self.module.debug("Running Collector._unreigster...")
|
||
|
|
||
|
if self.info is None:
|
||
|
self.module.debug("Retrieving collector information")
|
||
|
self.info = self._get()
|
||
|
|
||
|
if self.info is not None:
|
||
|
self.module.debug("Collector found")
|
||
|
self.module.debug("System changed")
|
||
|
self.change = True
|
||
|
|
||
|
if self.check_mode:
|
||
|
self.exit(changed=True)
|
||
|
|
||
|
self.module.debug("Making RPC call to 'deleteAgent'")
|
||
|
delete = json.loads(self.rpc("deleteAgent",
|
||
|
{"id": self.id}))
|
||
|
|
||
|
if delete["status"] is 200:
|
||
|
self.module.debug("RPC call succeeded")
|
||
|
return delete
|
||
|
else:
|
||
|
# The collector couldn't unregister. Start the service again
|
||
|
self.module.debug("Error unregistering collecting. " +
|
||
|
delete["errmsg"])
|
||
|
self.fail(msg=delete["errmsg"])
|
||
|
else:
|
||
|
self.module.debug("Collector not found")
|
||
|
return None
|
||
|
|
||
|
|
||
|
class Host(LogicMonitor):
|
||
|
|
||
|
def __init__(self, params, module=None):
|
||
|
"""Initializor for the LogicMonitor host object"""
|
||
|
self.change = False
|
||
|
self.params = params
|
||
|
self.collector = None
|
||
|
|
||
|
LogicMonitor.__init__(self, module, **self.params)
|
||
|
self.module.debug("Instantiating Host object")
|
||
|
|
||
|
if self.params["hostname"]:
|
||
|
self.module.debug("Hostname is " + self.params["hostname"])
|
||
|
self.hostname = self.params['hostname']
|
||
|
else:
|
||
|
self.module.debug("No hostname specified. Using " + self.fqdn)
|
||
|
self.hostname = self.fqdn
|
||
|
|
||
|
if self.params["displayname"]:
|
||
|
self.module.debug("Display name is " + self.params["displayname"])
|
||
|
self.displayname = self.params['displayname']
|
||
|
else:
|
||
|
self.module.debug("No display name specified. Using " + self.fqdn)
|
||
|
self.displayname = self.fqdn
|
||
|
|
||
|
# Attempt to host information via display name of host name
|
||
|
self.module.debug("Attempting to find host by displayname " +
|
||
|
self.displayname)
|
||
|
info = self.get_host_by_displayname(self.displayname)
|
||
|
|
||
|
if info is not None:
|
||
|
self.module.debug("Host found by displayname")
|
||
|
# Used the host information to grab the collector description
|
||
|
# if not provided
|
||
|
if (not hasattr(self.params, "collector") and
|
||
|
"agentDescription" in info):
|
||
|
self.module.debug("Setting collector from host response. " +
|
||
|
"Collector " + info["agentDescription"])
|
||
|
self.params["collector"] = info["agentDescription"]
|
||
|
else:
|
||
|
self.module.debug("Host not found by displayname")
|
||
|
|
||
|
# At this point, a valid collector description is required for success
|
||
|
# Check that the description exists or fail
|
||
|
if self.params["collector"]:
|
||
|
self.module.debug(
|
||
|
"Collector specified is " +
|
||
|
self.params["collector"]
|
||
|
)
|
||
|
self.collector = (self.get_collector_by_description(
|
||
|
self.params["collector"]))
|
||
|
else:
|
||
|
self.fail(msg="No collector specified.")
|
||
|
|
||
|
# If the host wasn't found via displayname, attempt by hostname
|
||
|
if info is None:
|
||
|
self.module.debug("Attempting to find host by hostname " +
|
||
|
self.hostname)
|
||
|
info = self.get_host_by_hostname(self.hostname, self.collector)
|
||
|
|
||
|
self.info = info
|
||
|
self.properties = self.params["properties"]
|
||
|
self.description = self.params["description"]
|
||
|
self.starttime = self.params["starttime"]
|
||
|
self.duration = self.params["duration"]
|
||
|
self.alertenable = self.params["alertenable"]
|
||
|
if self.params["groups"] is not None:
|
||
|
self.groups = self._strip_groups(self.params["groups"])
|
||
|
else:
|
||
|
self.groups = None
|
||
|
|
||
|
def create(self):
|
||
|
"""Idemopotent function to create if missing,
|
||
|
update if changed, or skip"""
|
||
|
self.module.debug("Running Host.create...")
|
||
|
|
||
|
self.update()
|
||
|
|
||
|
def get_properties(self):
|
||
|
"""Returns a hash of the properties
|
||
|
associated with this LogicMonitor host"""
|
||
|
self.module.debug("Running Host.get_properties...")
|
||
|
|
||
|
if self.info:
|
||
|
self.module.debug("Making RPC call to 'getHostProperties'")
|
||
|
properties_json = (json.loads(self.rpc("getHostProperties",
|
||
|
{'hostId': self.info["id"],
|
||
|
"filterSystemProperties": True})))
|
||
|
|
||
|
if properties_json["status"] == 200:
|
||
|
self.module.debug("RPC call succeeded")
|
||
|
return properties_json["data"]
|
||
|
else:
|
||
|
self.module.debug("Error: there was an issue retrieving the " +
|
||
|
"host properties")
|
||
|
self.module.debug(properties_json["errmsg"])
|
||
|
|
||
|
self.fail(msg=properties_json["status"])
|
||
|
else:
|
||
|
self.module.debug(
|
||
|
"Unable to find LogicMonitor host which matches " +
|
||
|
self.displayname + " (" + self.hostname + ")"
|
||
|
)
|
||
|
return None
|
||
|
|
||
|
def set_properties(self, propertyhash):
|
||
|
"""update the host to have the properties
|
||
|
contained in the property hash"""
|
||
|
self.module.debug("Running Host.set_properties...")
|
||
|
self.module.debug("System changed")
|
||
|
self.change = True
|
||
|
|
||
|
if self.check_mode:
|
||
|
self.exit(changed=True)
|
||
|
|
||
|
self.module.debug("Assigning property hash to host object")
|
||
|
self.properties = propertyhash
|
||
|
|
||
|
def add(self):
|
||
|
"""Add this device to monitoring
|
||
|
in your LogicMonitor account"""
|
||
|
self.module.debug("Running Host.add...")
|
||
|
|
||
|
if self.collector and not self.info:
|
||
|
self.module.debug("Host not registered. Registering.")
|
||
|
self.module.debug("System changed")
|
||
|
self.change = True
|
||
|
|
||
|
if self.check_mode:
|
||
|
self.exit(changed=True)
|
||
|
|
||
|
h = self._build_host_hash(
|
||
|
self.hostname,
|
||
|
self.displayname,
|
||
|
self.collector,
|
||
|
self.description,
|
||
|
self.groups,
|
||
|
self.properties,
|
||
|
self.alertenable)
|
||
|
|
||
|
self.module.debug("Making RPC call to 'addHost'")
|
||
|
resp = json.loads(self.rpc("addHost", h))
|
||
|
|
||
|
if resp["status"] == 200:
|
||
|
self.module.debug("RPC call succeeded")
|
||
|
return resp["data"]
|
||
|
else:
|
||
|
self.module.debug("RPC call failed")
|
||
|
self.module.debug(resp)
|
||
|
return resp["errmsg"]
|
||
|
elif self.collector is None:
|
||
|
self.fail(msg="Specified collector doesn't exist")
|
||
|
else:
|
||
|
self.module.debug("Host already registered")
|
||
|
|
||
|
def update(self):
|
||
|
"""This method takes changes made to this host
|
||
|
and applies them to the corresponding host
|
||
|
in your LogicMonitor account."""
|
||
|
self.module.debug("Running Host.update...")
|
||
|
|
||
|
if self.info:
|
||
|
self.module.debug("Host already registed")
|
||
|
if self.is_changed():
|
||
|
self.module.debug("System changed")
|
||
|
self.change = True
|
||
|
|
||
|
if self.check_mode:
|
||
|
self.exit(changed=True)
|
||
|
|
||
|
h = (self._build_host_hash(
|
||
|
self.hostname,
|
||
|
self.displayname,
|
||
|
self.collector,
|
||
|
self.description,
|
||
|
self.groups,
|
||
|
self.properties,
|
||
|
self.alertenable))
|
||
|
h["id"] = self.info["id"]
|
||
|
h["opType"] = "replace"
|
||
|
|
||
|
self.module.debug("Making RPC call to 'updateHost'")
|
||
|
resp = json.loads(self.rpc("updateHost", h))
|
||
|
|
||
|
if resp["status"] == 200:
|
||
|
self.module.debug("RPC call succeeded")
|
||
|
else:
|
||
|
self.module.debug("RPC call failed")
|
||
|
self.fail(msg="Error: unable to update the host.")
|
||
|
else:
|
||
|
self.module.debug(
|
||
|
"Host properties match supplied properties. " +
|
||
|
"No changes to make."
|
||
|
)
|
||
|
return self.info
|
||
|
else:
|
||
|
self.module.debug("Host not registed. Registering")
|
||
|
self.module.debug("System changed")
|
||
|
self.change = True
|
||
|
|
||
|
if self.check_mode:
|
||
|
self.exit(changed=True)
|
||
|
|
||
|
return self.add()
|
||
|
|
||
|
def remove(self):
|
||
|
"""Remove this host from your LogicMonitor account"""
|
||
|
self.module.debug("Running Host.remove...")
|
||
|
|
||
|
if self.info:
|
||
|
self.module.debug("Host registered")
|
||
|
self.module.debug("System changed")
|
||
|
self.change = True
|
||
|
|
||
|
if self.check_mode:
|
||
|
self.exit(changed=True)
|
||
|
|
||
|
self.module.debug("Making RPC call to 'deleteHost'")
|
||
|
resp = json.loads(self.rpc("deleteHost",
|
||
|
{"hostId": self.info["id"],
|
||
|
"deleteFromSystem": True,
|
||
|
"hostGroupId": 1}))
|
||
|
|
||
|
if resp["status"] == 200:
|
||
|
self.module.debug(resp)
|
||
|
self.module.debug("RPC call succeeded")
|
||
|
return resp
|
||
|
else:
|
||
|
self.module.debug("RPC call failed")
|
||
|
self.module.debug(resp)
|
||
|
self.fail(msg=resp["errmsg"])
|
||
|
|
||
|
else:
|
||
|
self.module.debug("Host not registered")
|
||
|
|
||
|
def is_changed(self):
|
||
|
"""Return true if the host doesn't
|
||
|
match the LogicMonitor account"""
|
||
|
self.module.debug("Running Host.is_changed")
|
||
|
|
||
|
ignore = ['system.categories', 'snmp.version']
|
||
|
|
||
|
hostresp = self.get_host_by_displayname(self.displayname)
|
||
|
|
||
|
if hostresp is None:
|
||
|
hostresp = self.get_host_by_hostname(self.hostname, self.collector)
|
||
|
|
||
|
if hostresp:
|
||
|
self.module.debug("Comparing simple host properties")
|
||
|
if hostresp["alertEnable"] != self.alertenable:
|
||
|
return True
|
||
|
|
||
|
if hostresp["description"] != self.description:
|
||
|
return True
|
||
|
|
||
|
if hostresp["displayedAs"] != self.displayname:
|
||
|
return True
|
||
|
|
||
|
if (self.collector and
|
||
|
hasattr(self.collector, "id") and
|
||
|
hostresp["agentId"] != self.collector["id"]):
|
||
|
return True
|
||
|
|
||
|
self.module.debug("Comparing groups.")
|
||
|
if self._compare_groups(hostresp) is True:
|
||
|
return True
|
||
|
|
||
|
propresp = self.get_properties()
|
||
|
|
||
|
if propresp:
|
||
|
self.module.debug("Comparing properties.")
|
||
|
if self._compare_props(propresp, ignore) is True:
|
||
|
return True
|
||
|
else:
|
||
|
self.fail(
|
||
|
msg="Error: Unknown error retrieving host properties")
|
||
|
|
||
|
return False
|
||
|
else:
|
||
|
self.fail(msg="Error: Unknown error retrieving host information")
|
||
|
|
||
|
def sdt(self):
|
||
|
"""Create a scheduled down time
|
||
|
(maintenance window) for this host"""
|
||
|
self.module.debug("Running Host.sdt...")
|
||
|
if self.info:
|
||
|
self.module.debug("System changed")
|
||
|
self.change = True
|
||
|
|
||
|
if self.check_mode:
|
||
|
self.exit(changed=True)
|
||
|
|
||
|
duration = self.duration
|
||
|
starttime = self.starttime
|
||
|
offset = starttime
|
||
|
|
||
|
if starttime:
|
||
|
self.module.debug("Start time specified")
|
||
|
start = datetime.datetime.strptime(starttime, '%Y-%m-%d %H:%M')
|
||
|
offsetstart = start
|
||
|
else:
|
||
|
self.module.debug("No start time specified. Using default.")
|
||
|
start = datetime.datetime.utcnow()
|
||
|
|
||
|
# Use user UTC offset
|
||
|
self.module.debug("Making RPC call to 'getTimeZoneSetting'")
|
||
|
accountresp = (json.loads(self.rpc("getTimeZoneSetting", {})))
|
||
|
|
||
|
if accountresp["status"] == 200:
|
||
|
self.module.debug("RPC call succeeded")
|
||
|
|
||
|
offset = accountresp["data"]["offset"]
|
||
|
offsetstart = start + datetime.timedelta(0, offset)
|
||
|
else:
|
||
|
self.fail(
|
||
|
msg="Error: Unable to retrieve timezone offset")
|
||
|
|
||
|
offsetend = offsetstart + datetime.timedelta(0, int(duration)*60)
|
||
|
|
||
|
h = {"hostId": self.info["id"],
|
||
|
"type": 1,
|
||
|
"year": offsetstart.year,
|
||
|
"month": offsetstart.month - 1,
|
||
|
"day": offsetstart.day,
|
||
|
"hour": offsetstart.hour,
|
||
|
"minute": offsetstart.minute,
|
||
|
"endYear": offsetend.year,
|
||
|
"endMonth": offsetend.month - 1,
|
||
|
"endDay": offsetend.day,
|
||
|
"endHour": offsetend.hour,
|
||
|
"endMinute": offsetend.minute}
|
||
|
|
||
|
self.module.debug("Making RPC call to 'setHostSDT'")
|
||
|
resp = (json.loads(self.rpc("setHostSDT", h)))
|
||
|
|
||
|
if resp["status"] == 200:
|
||
|
self.module.debug("RPC call succeeded")
|
||
|
return resp["data"]
|
||
|
else:
|
||
|
self.module.debug("RPC call failed")
|
||
|
self.fail(msg=resp["errmsg"])
|
||
|
else:
|
||
|
self.fail(msg="Error: Host doesn't exit.")
|
||
|
|
||
|
def site_facts(self):
|
||
|
"""Output current properties information for the Host"""
|
||
|
self.module.debug("Running Host.site_facts...")
|
||
|
|
||
|
if self.info:
|
||
|
self.module.debug("Host exists")
|
||
|
props = self.get_properties()
|
||
|
|
||
|
self.output_info(props)
|
||
|
else:
|
||
|
self.fail(msg="Error: Host doesn't exit.")
|
||
|
|
||
|
def _build_host_hash(self,
|
||
|
hostname,
|
||
|
displayname,
|
||
|
collector,
|
||
|
description,
|
||
|
groups,
|
||
|
properties,
|
||
|
alertenable):
|
||
|
"""Return a property formated hash for the
|
||
|
creation of a host using the rpc function"""
|
||
|
self.module.debug("Running Host._build_host_hash...")
|
||
|
|
||
|
h = {}
|
||
|
h["hostName"] = hostname
|
||
|
h["displayedAs"] = displayname
|
||
|
h["alertEnable"] = alertenable
|
||
|
|
||
|
if collector:
|
||
|
self.module.debug("Collector property exists")
|
||
|
h["agentId"] = collector["id"]
|
||
|
else:
|
||
|
self.fail(
|
||
|
msg="Error: No collector found. Unable to build host hash.")
|
||
|
|
||
|
if description:
|
||
|
h["description"] = description
|
||
|
|
||
|
if groups is not None and groups is not []:
|
||
|
self.module.debug("Group property exists")
|
||
|
groupids = ""
|
||
|
|
||
|
for group in groups:
|
||
|
groupids = groupids + str(self.create_group(group)) + ","
|
||
|
|
||
|
h["hostGroupIds"] = groupids.rstrip(',')
|
||
|
|
||
|
if properties is not None and properties is not {}:
|
||
|
self.module.debug("Properties hash exists")
|
||
|
propnum = 0
|
||
|
for key, value in properties.iteritems():
|
||
|
h["propName" + str(propnum)] = key
|
||
|
h["propValue" + str(propnum)] = value
|
||
|
propnum = propnum + 1
|
||
|
|
||
|
return h
|
||
|
|
||
|
def _verify_property(self, propname):
|
||
|
"""Check with LogicMonitor server to
|
||
|
verify property is unchanged"""
|
||
|
self.module.debug("Running Host._verify_property...")
|
||
|
|
||
|
if self.info:
|
||
|
self.module.debug("Host is registered")
|
||
|
if propname not in self.properties:
|
||
|
self.module.debug("Property " + propname + " does not exist")
|
||
|
return False
|
||
|
else:
|
||
|
self.module.debug("Property " + propname + " exists")
|
||
|
h = {"hostId": self.info["id"],
|
||
|
"propName0": propname,
|
||
|
"propValue0": self.properties[propname]}
|
||
|
|
||
|
self.module.debug("Making RCP call to 'verifyProperties'")
|
||
|
resp = json.loads(self.rpc('verifyProperties', h))
|
||
|
|
||
|
if resp["status"] == 200:
|
||
|
self.module.debug("RPC call succeeded")
|
||
|
return resp["data"]["match"]
|
||
|
else:
|
||
|
self.fail(
|
||
|
msg="Error: unable to get verification " +
|
||
|
"from server.\n%s" % resp["errmsg"])
|
||
|
else:
|
||
|
self.fail(
|
||
|
msg="Error: Host doesn't exist. Unable to verify properties")
|
||
|
|
||
|
def _compare_groups(self, hostresp):
|
||
|
"""Function to compare the host's current
|
||
|
groups against provided groups"""
|
||
|
self.module.debug("Running Host._compare_groups")
|
||
|
|
||
|
g = []
|
||
|
fullpathinids = hostresp["fullPathInIds"]
|
||
|
self.module.debug("Building list of groups")
|
||
|
for path in fullpathinids:
|
||
|
if path != []:
|
||
|
h = {'hostGroupId': path[-1]}
|
||
|
|
||
|
hgresp = json.loads(self.rpc("getHostGroup", h))
|
||
|
|
||
|
if (hgresp["status"] == 200 and
|
||
|
hgresp["data"]["appliesTo"] == ""):
|
||
|
|
||
|
g.append(path[-1])
|
||
|
|
||
|
if self.groups is not None:
|
||
|
self.module.debug("Comparing group lists")
|
||
|
for group in self.groups:
|
||
|
groupjson = self.get_group(group)
|
||
|
|
||
|
if groupjson is None:
|
||
|
self.module.debug("Group mismatch. No result.")
|
||
|
return True
|
||
|
elif groupjson['id'] not in g:
|
||
|
self.module.debug("Group mismatch. ID doesn't exist.")
|
||
|
return True
|
||
|
else:
|
||
|
g.remove(groupjson['id'])
|
||
|
|
||
|
if g != []:
|
||
|
self.module.debug("Group mismatch. New ID exists.")
|
||
|
return True
|
||
|
self.module.debug("Groups match")
|
||
|
|
||
|
def _compare_props(self, propresp, ignore):
|
||
|
"""Function to compare the host's current
|
||
|
properties against provided properties"""
|
||
|
self.module.debug("Running Host._compare_props...")
|
||
|
p = {}
|
||
|
|
||
|
self.module.debug("Creating list of properties")
|
||
|
for prop in propresp:
|
||
|
if prop["name"] not in ignore:
|
||
|
if ("*******" in prop["value"] and
|
||
|
self._verify_property(prop["name"])):
|
||
|
p[prop["name"]] = self.properties[prop["name"]]
|
||
|
else:
|
||
|
p[prop["name"]] = prop["value"]
|
||
|
|
||
|
self.module.debug("Comparing properties")
|
||
|
# Iterate provided properties and compare to received properties
|
||
|
for prop in self.properties:
|
||
|
if (prop not in p or
|
||
|
p[prop] != self.properties[prop]):
|
||
|
self.module.debug("Properties mismatch")
|
||
|
return True
|
||
|
self.module.debug("Properties match")
|
||
|
|
||
|
def _strip_groups(self, groups):
|
||
|
"""Function to strip whitespace from group list.
|
||
|
This function provides the user some flexibility when
|
||
|
formatting group arguments """
|
||
|
self.module.debug("Running Host._strip_groups...")
|
||
|
return map(lambda x: x.strip(), groups)
|
||
|
|
||
|
|
||
|
class Datasource(LogicMonitor):
|
||
|
|
||
|
def __init__(self, params, module=None):
|
||
|
"""Initializor for the LogicMonitor Datasource object"""
|
||
|
self.change = False
|
||
|
self.params = params
|
||
|
|
||
|
LogicMonitor.__init__(self, module, **params)
|
||
|
self.module.debug("Instantiating Datasource object")
|
||
|
|
||
|
self.id = self.params["id"]
|
||
|
self.starttime = self.params["starttime"]
|
||
|
self.duration = self.params["duration"]
|
||
|
|
||
|
def sdt(self):
|
||
|
"""Create a scheduled down time
|
||
|
(maintenance window) for this host"""
|
||
|
self.module.debug("Running Datasource.sdt...")
|
||
|
|
||
|
self.module.debug("System changed")
|
||
|
self.change = True
|
||
|
|
||
|
if self.check_mode:
|
||
|
self.exit(changed=True)
|
||
|
|
||
|
duration = self.duration
|
||
|
starttime = self.starttime
|
||
|
offsetstart = starttime
|
||
|
|
||
|
if starttime:
|
||
|
self.module.debug("Start time specified")
|
||
|
start = datetime.datetime.strptime(starttime, '%Y-%m-%d %H:%M')
|
||
|
offsetstart = start
|
||
|
else:
|
||
|
self.module.debug("No start time specified. Using default.")
|
||
|
start = datetime.datetime.utcnow()
|
||
|
|
||
|
# Use user UTC offset
|
||
|
self.module.debug("Making RPC call to 'getTimeZoneSetting'")
|
||
|
accountresp = json.loads(self.rpc("getTimeZoneSetting", {}))
|
||
|
|
||
|
if accountresp["status"] == 200:
|
||
|
self.module.debug("RPC call succeeded")
|
||
|
|
||
|
offset = accountresp["data"]["offset"]
|
||
|
offsetstart = start + datetime.timedelta(0, offset)
|
||
|
else:
|
||
|
self.fail(msg="Error: Unable to retrieve timezone offset")
|
||
|
|
||
|
offsetend = offsetstart + datetime.timedelta(0, int(duration)*60)
|
||
|
|
||
|
h = {"hostDataSourceId": self.id,
|
||
|
"type": 1,
|
||
|
"notifyCC": True,
|
||
|
"year": offsetstart.year,
|
||
|
"month": offsetstart.month-1,
|
||
|
"day": offsetstart.day,
|
||
|
"hour": offsetstart.hour,
|
||
|
"minute": offsetstart.minute,
|
||
|
"endYear": offsetend.year,
|
||
|
"endMonth": offsetend.month-1,
|
||
|
"endDay": offsetend.day,
|
||
|
"endHour": offsetend.hour,
|
||
|
"endMinute": offsetend.minute}
|
||
|
|
||
|
self.module.debug("Making RPC call to 'setHostDataSourceSDT'")
|
||
|
resp = json.loads(self.rpc("setHostDataSourceSDT", h))
|
||
|
|
||
|
if resp["status"] == 200:
|
||
|
self.module.debug("RPC call succeeded")
|
||
|
return resp["data"]
|
||
|
else:
|
||
|
self.module.debug("RPC call failed")
|
||
|
self.fail(msg=resp["errmsg"])
|
||
|
|
||
|
|
||
|
class Hostgroup(LogicMonitor):
|
||
|
|
||
|
def __init__(self, params, module=None):
|
||
|
"""Initializor for the LogicMonitor host object"""
|
||
|
self.change = False
|
||
|
self.params = params
|
||
|
|
||
|
LogicMonitor.__init__(self, module, **self.params)
|
||
|
self.module.debug("Instantiating Hostgroup object")
|
||
|
|
||
|
self.fullpath = self.params["fullpath"]
|
||
|
self.info = self.get_group(self.fullpath)
|
||
|
self.properties = self.params["properties"]
|
||
|
self.description = self.params["description"]
|
||
|
self.starttime = self.params["starttime"]
|
||
|
self.duration = self.params["duration"]
|
||
|
self.alertenable = self.params["alertenable"]
|
||
|
|
||
|
def create(self):
|
||
|
"""Wrapper for self.update()"""
|
||
|
self.module.debug("Running Hostgroup.create...")
|
||
|
self.update()
|
||
|
|
||
|
def get_properties(self, final=False):
|
||
|
"""Returns a hash of the properties
|
||
|
associated with this LogicMonitor host"""
|
||
|
self.module.debug("Running Hostgroup.get_properties...")
|
||
|
|
||
|
if self.info:
|
||
|
self.module.debug("Group found")
|
||
|
|
||
|
self.module.debug("Making RPC call to 'getHostGroupProperties'")
|
||
|
properties_json = json.loads(self.rpc(
|
||
|
"getHostGroupProperties",
|
||
|
{'hostGroupId': self.info["id"],
|
||
|
"finalResult": final}))
|
||
|
|
||
|
if properties_json["status"] == 200:
|
||
|
self.module.debug("RPC call succeeded")
|
||
|
return properties_json["data"]
|
||
|
else:
|
||
|
self.module.debug("RPC call failed")
|
||
|
self.fail(msg=properties_json["status"])
|
||
|
else:
|
||
|
self.module.debug("Group not found")
|
||
|
return None
|
||
|
|
||
|
def set_properties(self, propertyhash):
|
||
|
"""Update the host to have the properties
|
||
|
contained in the property hash"""
|
||
|
self.module.debug("Running Hostgroup.set_properties")
|
||
|
|
||
|
self.module.debug("System changed")
|
||
|
self.change = True
|
||
|
|
||
|
if self.check_mode:
|
||
|
self.exit(changed=True)
|
||
|
|
||
|
self.module.debug("Assigning property has to host object")
|
||
|
self.properties = propertyhash
|
||
|
|
||
|
def add(self):
|
||
|
"""Idempotent function to ensure that the host
|
||
|
group exists in your LogicMonitor account"""
|
||
|
self.module.debug("Running Hostgroup.add")
|
||
|
|
||
|
if self.info is None:
|
||
|
self.module.debug("Group doesn't exist. Creating.")
|
||
|
self.module.debug("System changed")
|
||
|
self.change = True
|
||
|
|
||
|
if self.check_mode:
|
||
|
self.exit(changed=True)
|
||
|
|
||
|
self.create_group(self.fullpath)
|
||
|
self.info = self.get_group(self.fullpath)
|
||
|
|
||
|
self.module.debug("Group created")
|
||
|
return self.info
|
||
|
else:
|
||
|
self.module.debug("Group already exists")
|
||
|
|
||
|
def update(self):
|
||
|
"""Idempotent function to ensure the host group settings
|
||
|
(alertenable, properties, etc) in the
|
||
|
LogicMonitor account match the current object."""
|
||
|
self.module.debug("Running Hostgroup.update")
|
||
|
|
||
|
if self.info:
|
||
|
if self.is_changed():
|
||
|
self.module.debug("System changed")
|
||
|
self.change = True
|
||
|
|
||
|
if self.check_mode:
|
||
|
self.exit(changed=True)
|
||
|
|
||
|
h = self._build_host_group_hash(
|
||
|
self.fullpath,
|
||
|
self.description,
|
||
|
self.properties,
|
||
|
self.alertenable)
|
||
|
h["opType"] = "replace"
|
||
|
|
||
|
if self.fullpath != "/":
|
||
|
h["id"] = self.info["id"]
|
||
|
|
||
|
self.module.debug("Making RPC call to 'updateHostGroup'")
|
||
|
resp = json.loads(self.rpc("updateHostGroup", h))
|
||
|
|
||
|
if resp["status"] == 200:
|
||
|
self.module.debug("RPC call succeeded")
|
||
|
return resp["data"]
|
||
|
else:
|
||
|
self.module.debug("RPC call failed")
|
||
|
self.fail(msg="Error: Unable to update the " +
|
||
|
"host.\n" + resp["errmsg"])
|
||
|
else:
|
||
|
self.module.debug(
|
||
|
"Group properties match supplied properties. " +
|
||
|
"No changes to make"
|
||
|
)
|
||
|
return self.info
|
||
|
else:
|
||
|
self.module.debug("Group doesn't exist. Creating.")
|
||
|
|
||
|
self.module.debug("System changed")
|
||
|
self.change = True
|
||
|
|
||
|
if self.check_mode:
|
||
|
self.exit(changed=True)
|
||
|
|
||
|
return self.add()
|
||
|
|
||
|
def remove(self):
|
||
|
"""Idempotent function to ensure the host group
|
||
|
does not exist in your LogicMonitor account"""
|
||
|
self.module.debug("Running Hostgroup.remove...")
|
||
|
|
||
|
if self.info:
|
||
|
self.module.debug("Group exists")
|
||
|
self.module.debug("System changed")
|
||
|
self.change = True
|
||
|
|
||
|
if self.check_mode:
|
||
|
self.exit(changed=True)
|
||
|
|
||
|
self.module.debug("Making RPC call to 'deleteHostGroup'")
|
||
|
resp = json.loads(self.rpc("deleteHostGroup",
|
||
|
{"hgId": self.info["id"]}))
|
||
|
|
||
|
if resp["status"] == 200:
|
||
|
self.module.debug(resp)
|
||
|
self.module.debug("RPC call succeeded")
|
||
|
return resp
|
||
|
elif resp["errmsg"] == "No such group":
|
||
|
self.module.debug("Group doesn't exist")
|
||
|
else:
|
||
|
self.module.debug("RPC call failed")
|
||
|
self.module.debug(resp)
|
||
|
self.fail(msg=resp["errmsg"])
|
||
|
else:
|
||
|
self.module.debug("Group doesn't exist")
|
||
|
|
||
|
def is_changed(self):
|
||
|
"""Return true if the host doesn't match
|
||
|
the LogicMonitor account"""
|
||
|
self.module.debug("Running Hostgroup.is_changed...")
|
||
|
|
||
|
ignore = []
|
||
|
group = self.get_group(self.fullpath)
|
||
|
properties = self.get_properties()
|
||
|
|
||
|
if properties is not None and group is not None:
|
||
|
self.module.debug("Comparing simple group properties")
|
||
|
if (group["alertEnable"] != self.alertenable or
|
||
|
group["description"] != self.description):
|
||
|
|
||
|
return True
|
||
|
|
||
|
p = {}
|
||
|
|
||
|
self.module.debug("Creating list of properties")
|
||
|
for prop in properties:
|
||
|
if prop["name"] not in ignore:
|
||
|
if ("*******" in prop["value"] and
|
||
|
self._verify_property(prop["name"])):
|
||
|
|
||
|
p[prop["name"]] = (
|
||
|
self.properties[prop["name"]])
|
||
|
else:
|
||
|
p[prop["name"]] = prop["value"]
|
||
|
|
||
|
self.module.debug("Comparing properties")
|
||
|
if set(p) != set(self.properties):
|
||
|
return True
|
||
|
else:
|
||
|
self.module.debug("No property information received")
|
||
|
return False
|
||
|
|
||
|
def sdt(self, duration=30, starttime=None):
|
||
|
"""Create a scheduled down time
|
||
|
(maintenance window) for this host"""
|
||
|
self.module.debug("Running Hostgroup.sdt")
|
||
|
|
||
|
self.module.debug("System changed")
|
||
|
self.change = True
|
||
|
|
||
|
if self.check_mode:
|
||
|
self.exit(changed=True)
|
||
|
|
||
|
duration = self.duration
|
||
|
starttime = self.starttime
|
||
|
offset = starttime
|
||
|
|
||
|
if starttime:
|
||
|
self.module.debug("Start time specified")
|
||
|
start = datetime.datetime.strptime(starttime, '%Y-%m-%d %H:%M')
|
||
|
offsetstart = start
|
||
|
else:
|
||
|
self.module.debug("No start time specified. Using default.")
|
||
|
start = datetime.datetime.utcnow()
|
||
|
|
||
|
# Use user UTC offset
|
||
|
self.module.debug("Making RPC call to 'getTimeZoneSetting'")
|
||
|
accountresp = json.loads(self.rpc("getTimeZoneSetting", {}))
|
||
|
|
||
|
if accountresp["status"] == 200:
|
||
|
self.module.debug("RPC call succeeded")
|
||
|
|
||
|
offset = accountresp["data"]["offset"]
|
||
|
offsetstart = start + datetime.timedelta(0, offset)
|
||
|
else:
|
||
|
self.fail(
|
||
|
msg="Error: Unable to retrieve timezone offset")
|
||
|
|
||
|
offsetend = offsetstart + datetime.timedelta(0, int(duration)*60)
|
||
|
|
||
|
h = {"hostGroupId": self.info["id"],
|
||
|
"type": 1,
|
||
|
"year": offsetstart.year,
|
||
|
"month": offsetstart.month-1,
|
||
|
"day": offsetstart.day,
|
||
|
"hour": offsetstart.hour,
|
||
|
"minute": offsetstart.minute,
|
||
|
"endYear": offsetend.year,
|
||
|
"endMonth": offsetend.month-1,
|
||
|
"endDay": offsetend.day,
|
||
|
"endHour": offsetend.hour,
|
||
|
"endMinute": offsetend.minute}
|
||
|
|
||
|
self.module.debug("Making RPC call to setHostGroupSDT")
|
||
|
resp = json.loads(self.rpc("setHostGroupSDT", h))
|
||
|
|
||
|
if resp["status"] == 200:
|
||
|
self.module.debug("RPC call succeeded")
|
||
|
return resp["data"]
|
||
|
else:
|
||
|
self.module.debug("RPC call failed")
|
||
|
self.fail(msg=resp["errmsg"])
|
||
|
|
||
|
def site_facts(self):
|
||
|
"""Output current properties information for the Hostgroup"""
|
||
|
self.module.debug("Running Hostgroup.site_facts...")
|
||
|
|
||
|
if self.info:
|
||
|
self.module.debug("Group exists")
|
||
|
props = self.get_properties(True)
|
||
|
|
||
|
self.output_info(props)
|
||
|
else:
|
||
|
self.fail(msg="Error: Group doesn't exit.")
|
||
|
|
||
|
def _build_host_group_hash(self,
|
||
|
fullpath,
|
||
|
description,
|
||
|
properties,
|
||
|
alertenable):
|
||
|
"""Return a property formated hash for the
|
||
|
creation of a hostgroup using the rpc function"""
|
||
|
self.module.debug("Running Hostgroup._build_host_hash")
|
||
|
|
||
|
h = {}
|
||
|
h["alertEnable"] = alertenable
|
||
|
|
||
|
if fullpath == "/":
|
||
|
self.module.debug("Group is root")
|
||
|
h["id"] = 1
|
||
|
else:
|
||
|
self.module.debug("Determining group path")
|
||
|
parentpath, name = fullpath.rsplit('/', 1)
|
||
|
parent = self.get_group(parentpath)
|
||
|
|
||
|
h["name"] = name
|
||
|
|
||
|
if parent:
|
||
|
self.module.debug("Parent group " +
|
||
|
str(parent["id"]) + " found.")
|
||
|
h["parentID"] = parent["id"]
|
||
|
else:
|
||
|
self.module.debug("No parent group found. Using root.")
|
||
|
h["parentID"] = 1
|
||
|
|
||
|
if description:
|
||
|
self.module.debug("Description property exists")
|
||
|
h["description"] = description
|
||
|
|
||
|
if properties != {}:
|
||
|
self.module.debug("Properties hash exists")
|
||
|
propnum = 0
|
||
|
for key, value in properties.iteritems():
|
||
|
h["propName" + str(propnum)] = key
|
||
|
h["propValue" + str(propnum)] = value
|
||
|
propnum = propnum + 1
|
||
|
|
||
|
return h
|
||
|
|
||
|
def _verify_property(self, propname):
|
||
|
"""Check with LogicMonitor server
|
||
|
to verify property is unchanged"""
|
||
|
self.module.debug("Running Hostgroup._verify_property")
|
||
|
|
||
|
if self.info:
|
||
|
self.module.debug("Group exists")
|
||
|
if propname not in self.properties:
|
||
|
self.module.debug("Property " + propname + " does not exist")
|
||
|
return False
|
||
|
else:
|
||
|
self.module.debug("Property " + propname + " exists")
|
||
|
h = {"hostGroupId": self.info["id"],
|
||
|
"propName0": propname,
|
||
|
"propValue0": self.properties[propname]}
|
||
|
|
||
|
self.module.debug("Making RCP call to 'verifyProperties'")
|
||
|
resp = json.loads(self.rpc('verifyProperties', h))
|
||
|
|
||
|
if resp["status"] == 200:
|
||
|
self.module.debug("RPC call succeeded")
|
||
|
return resp["data"]["match"]
|
||
|
else:
|
||
|
self.fail(
|
||
|
msg="Error: unable to get verification " +
|
||
|
"from server.\n%s" % resp["errmsg"])
|
||
|
else:
|
||
|
self.fail(
|
||
|
msg="Error: Group doesn't exist. Unable to verify properties")
|
||
|
|
||
|
|
||
|
def selector(module):
|
||
|
"""Figure out which object and which actions
|
||
|
to take given the right parameters"""
|
||
|
|
||
|
if module.params["target"] == "collector":
|
||
|
target = Collector(module.params, module)
|
||
|
elif module.params["target"] == "host":
|
||
|
# Make sure required parameter collector is specified
|
||
|
if ((module.params["action"] == "add" or
|
||
|
module.params["displayname"] is None) and
|
||
|
module.params["collector"] is None):
|
||
|
module.fail_json(
|
||
|
msg="Parameter 'collector' required.")
|
||
|
|
||
|
target = Host(module.params, module)
|
||
|
elif module.params["target"] == "datasource":
|
||
|
# Validate target specific required parameters
|
||
|
if module.params["id"] is not None:
|
||
|
# make sure a supported action was specified
|
||
|
if module.params["action"] == "sdt":
|
||
|
target = Datasource(module.params, module)
|
||
|
else:
|
||
|
errmsg = ("Error: Unexpected action \"" +
|
||
|
module.params["action"] + "\" was specified.")
|
||
|
module.fail_json(msg=errmsg)
|
||
|
|
||
|
elif module.params["target"] == "hostgroup":
|
||
|
# Validate target specific required parameters
|
||
|
if module.params["fullpath"] is not None:
|
||
|
target = Hostgroup(module.params, module)
|
||
|
else:
|
||
|
module.fail_json(
|
||
|
msg="Parameter 'fullpath' required for target 'hostgroup'")
|
||
|
else:
|
||
|
module.fail_json(
|
||
|
msg="Error: Unexpected target \"" + module.params["target"] +
|
||
|
"\" was specified.")
|
||
|
|
||
|
if module.params["action"].lower() == "add":
|
||
|
action = target.create
|
||
|
elif module.params["action"].lower() == "remove":
|
||
|
action = target.remove
|
||
|
elif module.params["action"].lower() == "sdt":
|
||
|
action = target.sdt
|
||
|
elif module.params["action"].lower() == "update":
|
||
|
action = target.update
|
||
|
else:
|
||
|
errmsg = ("Error: Unexpected action \"" + module.params["action"] +
|
||
|
"\" was specified.")
|
||
|
module.fail_json(msg=errmsg)
|
||
|
|
||
|
action()
|
||
|
module.exit_json(changed=target.change)
|
||
|
|
||
|
|
||
|
def main():
|
||
|
TARGETS = [
|
||
|
"collector",
|
||
|
"host",
|
||
|
"datasource",
|
||
|
"hostgroup"]
|
||
|
|
||
|
ACTIONS = [
|
||
|
"add",
|
||
|
"remove",
|
||
|
"sdt",
|
||
|
"update"]
|
||
|
|
||
|
module = AnsibleModule(
|
||
|
argument_spec=dict(
|
||
|
target=dict(required=True, default=None, choices=TARGETS),
|
||
|
action=dict(required=True, default=None, choices=ACTIONS),
|
||
|
company=dict(required=True, default=None),
|
||
|
user=dict(required=True, default=None),
|
||
|
password=dict(required=True, default=None, no_log=True),
|
||
|
|
||
|
collector=dict(required=False, default=None),
|
||
|
hostname=dict(required=False, default=None),
|
||
|
displayname=dict(required=False, default=None),
|
||
|
id=dict(required=False, default=None),
|
||
|
description=dict(required=False, default=""),
|
||
|
fullpath=dict(required=False, default=None),
|
||
|
starttime=dict(required=False, default=None),
|
||
|
duration=dict(required=False, default=30),
|
||
|
properties=dict(required=False, default={}, type="dict"),
|
||
|
groups=dict(required=False, default=[], type="list"),
|
||
|
alertenable=dict(required=False, default="true", choices=BOOLEANS)
|
||
|
),
|
||
|
supports_check_mode=True
|
||
|
)
|
||
|
|
||
|
if HAS_LIB_JSON is not True:
|
||
|
module.fail_json(msg="Unable to load JSON library")
|
||
|
|
||
|
selector(module)
|
||
|
|
||
|
|
||
|
from ansible.module_utils.basic import *
|
||
|
from ansible.module_utils.urls import *
|
||
|
from ansible.module_utils.urls import open_url
|
||
|
|
||
|
|
||
|
if __name__ == "__main__":
|
||
|
main()
|