Skip to content

Commit

Permalink
Merge pull request #145 from guidograzioli/activemq_jolokia_facts_module
Browse files Browse the repository at this point in the history
Add fact gathering module for amq
  • Loading branch information
guidograzioli authored Aug 12, 2024
2 parents bf04a93 + 1c7807a commit e4b8ae4
Show file tree
Hide file tree
Showing 6 changed files with 242 additions and 0 deletions.
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ This collection has been tested against following Ansible versions: **>=2.15.0**

### Plugins:

* `activemq_facts`: return activemq configuration as ansible fact data
* `pbkdf2_hmac`: filter plugin used internally to generate unidirectional account password hashes
<!--end roles_paths -->

Expand Down
23 changes: 23 additions & 0 deletions molecule/default/verify.yml
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,16 @@
- name: Populate service facts
ansible.builtin.service_facts:

- name: Populate activemq facts
middleware_automation.amq.activemq_facts:
base_url: http://0.0.0.0:8161
auth_username: amq
auth_password: amqbrokerpass

- name: Print activemq gathered facts
ansible.builtin.debug:
var: ansible_facts.activemq

- name: Check if amq-broker service is started
ansible.builtin.assert:
that:
Expand Down Expand Up @@ -91,3 +101,16 @@
- diverts.count == 1
quiet: true
fail_msg: "Failed to retrieve generated divert"

- name: Check divert configuration via jolokia
ansible.builtin.assert:
that:
- ansible_facts.activemq.DivertNames | length > 0
- ansible_facts.activemq.DivertNames | first == "TESTDIVERT"

- name: Check queue configuration via jolokia
ansible.builtin.assert:
that:
- ansible_facts.activemq.AddressNames | length > 0
- "'client123.pubsub' in ansible_facts.activemq.AddressNames"
- "'importantTopic' in ansible_facts.activemq.AddressNames"
6 changes: 6 additions & 0 deletions molecule/mask_passwords/verify.yml
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,12 @@
- name: Populate service facts
ansible.builtin.service_facts:

- name: Populate activemq facts
middleware_automation.amq.activemq_facts:
auth_username: tesla
auth_password: password
validate_certs: false

- name: Check if amq-broker service is started
ansible.builtin.assert:
that:
Expand Down
4 changes: 4 additions & 0 deletions molecule/static_cluster/converge.yml
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,10 @@
activemq_tls_keystore_password: securepass
activemq_tls_truststore_path: nfs/trust.ks
activemq_tls_truststore_password: securepass
activemq_users:
- user: amq
password: amqbrokerpass
roles: [ amq ]
activemq_acceptors:
- name: artemis
bind_address: 0.0.0.0
Expand Down
24 changes: 24 additions & 0 deletions molecule/static_cluster/verify.yml
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,13 @@
- name: Populate service facts
ansible.builtin.service_facts:

- name: Populate activemq facts
middleware_automation.amq.activemq_facts:
base_url: https://localhost:8161
auth_username: amq
auth_password: amqbrokerpass
validate_certs: false

- name: Check if amq-broker service is started
ansible.builtin.assert:
that:
Expand Down Expand Up @@ -43,3 +50,20 @@
- "'got backup lock' in slurped_log_instance2.content|b64decode"
- "'waiting live to fail before it gets active' in slurped_log_instance2.content|b64decode or 'waiting for primary to fail before activating' in slurped_log_instance2.content|b64decode"
quiet: true

- name: Check cluster status via jolokia facts (master)
ansible.builtin.assert:
that:
- ansible_facts.activemq.Active == true
- ansible_facts.activemq.Backup == false
- ansible_facts.activemq.SharedStore == true
- ansible_facts.activemq.HAPolicy == "Shared Store Primary"
when: inventory_hostname == 'instance1'

- name: Check cluster status via jolokia facts (backup)
ansible.builtin.assert:
that:
- ansible_facts.activemq.Active == false
- ansible_facts.activemq.Backup == true
- ansible_facts.activemq.SharedStore == true
when: inventory_hostname == 'instance2'
184 changes: 184 additions & 0 deletions plugins/modules/activemq_facts.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,184 @@
#!/usr/bin/python
# -*- coding: utf-8 -*-
# Copyright (c) 2024, Red Hat Inc.
# Copyright (c) 2024, Guido Grazioli <ggraziol@redhat.com>
# Apache License, Version 2.0 (see LICENSE or https://www.apache.org/licenses/LICENSE-2.0)
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)

from __future__ import absolute_import, division, print_function
__metaclass__ = type

DOCUMENTATION = r'''
---
module: activemq_facts
short_description: Return activemq configuration as fact data
description:
- Return artemis activemq configuration and runtime information from the jolokia endpoint as fact data.
version_added: "2.1.0"
requirements: ["A running instance of activemq with the jolokia port open"]
extends_documentation_fragment:
- action_common_attributes
- action_common_attributes.facts
attributes:
check_mode:
support: full
diff_mode:
support: none
facts:
support: full
platform:
platforms: all
options:
base_url:
description:
- URL to the activemq instance.
type: str
required: false
default: http://localhost:8161
aliases:
- url
broker_name:
description:
- Name of the broker instance
type: str
required: false
default: 'amq-broker'
aliases:
- broker
auth_username:
description:
- Username to authenticate for API access with.
type: str
required: true
aliases:
- username
auth_password:
description:
- Password to authenticate for API access with.
type: str
required: true
aliases:
- password
validate_certs:
description:
- Verify TLS certificates when using https.
type: bool
default: true
connection_timeout:
description:
- Controls the HTTP connections timeout period in seconds to jolokia API.
type: int
default: 10
author:
- Guido Grazioli (@guidograzioli)
'''

EXAMPLES = r'''
- name: Populate activemq facts
middleware_automation.amq.activemq_facts:
- name: Print activemq service facts
ansible.builtin.debug:
var: ansible_facts.activemq
'''

RETURN = r'''
ansible_facts:
description: Facts to add to ansible_facts about the activemq service
returned: always
type: complex
contains:
activemq:
description: The factual representation of an activemq instance configuration.
returned: always
type: dict
'''

import json
import traceback

from ansible.module_utils.basic import AnsibleModule
from ansible.module_utils.urls import open_url, basic_auth_header
from ansible.module_utils.six.moves.urllib.error import HTTPError
from ansible.module_utils.common.text.converters import to_native


URL_JOLOKIA_INFO = "{url}/console/jolokia/read/org.apache.activemq.artemis:broker=!%22{broker}!%22"


class JolokiaService(object):

def __init__(self, module):
self.module = module
self.baseurl = self.module.params.get('base_url')
self.broker = self.module.params.get('broker_name')
self.validate_certs = self.module.params.get('validate_certs')
self.connection_timeout = self.module.params.get('connection_timeout')
self.auth_username = self.module.params.get('auth_username')
self.auth_password = self.module.params.get('auth_password')

def gather_facts(self):
""" Obtain configuration from jolokia API
:return: dict of real, representation or None if none matching exist
"""

jolokia_url = URL_JOLOKIA_INFO.format(url=self.baseurl, broker=self.broker)

if not self.baseurl.lower().startswith(('http', 'https')):
raise ValueError("base url '%s' should either start with 'http' or 'https'." % self.baseurl)

restheaders = {}
restheaders["Authorization"] = basic_auth_header(self.auth_username, self.auth_password)
restheaders['Origin'] = self.baseurl if 'localhost' not in self.baseurl else 'https://0.0.0.0'

try:
return json.loads(to_native(open_url(jolokia_url, method='GET',
headers=restheaders,
timeout=self.connection_timeout,
validate_certs=self.validate_certs).read()))

except HTTPError as e:
if e.code == 404:
return None
else:
self.module.fail_json(msg='HTTP error calling jolokia api: %s' % (str(e)),
exception=traceback.format_exc())
except ValueError as e:
self.module.fail_json(msg='API returned incorrect JSON: %s' % (str(e)),
exception=traceback.format_exc())
except Exception as e:
self.module.fail_json(msg='General error calling jolokia api %s' % (str(e)),
exception=traceback.format_exc())


def amq_argument_spec():
"""
Returns argument_spec of options
:return: argument_spec dict
"""
return dict(
base_url=dict(type='str', aliases=['url'], required=False, default="http://localhost:8161", no_log=False),
broker_name=dict(type='str', aliases=['broker'], required=False, default="amq-broker"),
auth_username=dict(type='str', aliases=['username'], required=True),
auth_password=dict(type='str', aliases=['password'], required=True, no_log=True),
validate_certs=dict(type='bool', default=True),
connection_timeout=dict(type='int', default=10)
)


def main():
module = AnsibleModule(argument_spec=amq_argument_spec(), supports_check_mode=True,
required_together=([['auth_username', 'auth_password']]))
mod = JolokiaService(module)
svc = mod.gather_facts()
if not svc or "value" not in svc:
results = dict(skipped=True, msg="Failed to find info. This can be due to privileges or some other configuration issue.")
else:
results = dict(ansible_facts=dict(activemq=svc["value"]))
module.exit_json(**results)


if __name__ == '__main__':
main()

0 comments on commit e4b8ae4

Please sign in to comment.