← Back to team overview

nagios-charmers team mailing list archive

[Merge] ~wallyworld/nagios-charm:cmr-aware into nagios-charm:master

 

You have been requested to review the proposed merge of ~wallyworld/nagios-charm:cmr-aware into nagios-charm:master.

For more details, see:
https://code.launchpad.net/~wallyworld/nagios-charm/+git/nagios-charm/+merge/332829

Add support for using the new charm networking primitives so that the charm becomes cross model relations aware.

The main change is to use the new charm helpers network_get() API to ask for an ingress-address instead of a private-address via unit_get(). Some existing bash hooks were re-written in Python to make use of the functionality.

The charm deploys and functions just fine in the only previously supported scenario which was everything on one model. In the cross model case, the new network primitives ensure the correct IP address is used ti communicate with nrpe (not just the private IP address as was the case).

Requires https://git.launchpad.net/~wallyworld/nrpe-charm/commit/?id=ce33aa27a612ca2c4ade6f78e0a8f0492cb7880a

To test live:

juju bootstrap
juju deploy ~/charms/nagios-charm
juju expose nagios
juju offer nagios:monitors
juju switch controller
juju deploy ubuntu
juju deploy ~/charms/nrpe-charm
juju add-relation ubuntu nrpe
juju add-relation nrpe:monitors default.nagios



-- 
Your team Nagios Charm developers is requested to review the proposed merge of ~wallyworld/nagios-charm:cmr-aware into nagios-charm:master.
diff --git a/hooks/charmhelpers/core/hookenv.py b/hooks/charmhelpers/core/hookenv.py
index 899722f..67ad691 100644
--- a/hooks/charmhelpers/core/hookenv.py
+++ b/hooks/charmhelpers/core/hookenv.py
@@ -1082,6 +1082,35 @@ def network_get_primary_address(binding):
     return subprocess.check_output(cmd).decode('UTF-8').strip()
 
 
+@translate_exc(from_exc=OSError, to_exc=NotImplementedError)
+def network_get(endpoint, relation_id=None):
+    """
+    Retrieve the network details for a relation endpoint
+
+    :param endpoint: string. The name of a relation endpoint
+    :param relation_id: int. The ID of the relation for the current context.
+    :return: dict. The loaded YAML output of the network-get query.
+    :raise: NotImplementedError if run on Juju < 2.1
+    """
+    cmd = ['network-get', endpoint, '--format', 'yaml']
+    if relation_id:
+        cmd.append('-r')
+        cmd.append(relation_id)
+    try:
+        response = subprocess.check_output(
+            cmd,
+            stderr=subprocess.STDOUT).decode('UTF-8').strip()
+    except CalledProcessError as e:
+        # Early versions of Juju 2.0.x required the --primary-address argument.
+        # We catch that condition here and raise NotImplementedError since
+        # the requested semantics are not available - the caller can then
+        # use the network_get_primary_address() method instead.
+        if '--primary-address is currently required' in e.output.decode('UTF-8'):
+            raise NotImplementedError
+        raise
+    return yaml.safe_load(response)
+
+
 def add_metric(*args, **kwargs):
     """Add metric values. Values may be expressed with keyword arguments. For
     metric names containing dashes, these may be expressed as one or more
diff --git a/hooks/common.py b/hooks/common.py
index ed16a96..e195488 100644
--- a/hooks/common.py
+++ b/hooks/common.py
@@ -7,6 +7,13 @@ import sqlite3
 import shutil
 import tempfile
 
+from charmhelpers.core.hookenv import (
+    log,
+    network_get,
+    network_get_primary_address,
+    unit_get,
+)
+
 from pynag import Model
 
 INPROGRESS_DIR = '/etc/nagios3-inprogress'
@@ -35,12 +42,49 @@ def check_ip(n):
         except socket.error:
             return False
 
+def ingress_address(relation_data):
+    if 'ingress-address' in relation_data:
+        return relation_data['ingress-address']
+    return relation_data['private-address']
 
-def get_ip_and_hostname(remote_unit, relation_id=None):
-    args = ["relation-get", "private-address", remote_unit]
+
+def get_local_ingress_address(binding='website'):
+    # using network-get to retrieve the address details if available.
+    log('Getting hostname for binding %s' % binding)
+    try:
+        network_info = network_get(binding)
+        if network_info is not None and 'ingress-addresses' in network_info:
+            log('Using ingress-addresses')
+            hostname = network_info['ingress-addresses'][0]
+            log(hostname)
+            return hostname
+    except NotImplementedError:
+        # We'll fallthrough to the Pre 2.3 code below.
+        pass
+
+    # Pre 2.3 output
+    try:
+        hostname = network_get_primary_address(binding)
+        log('Using primary-addresses')
+    except NotImplementedError:
+        # pre Juju 2.0
+        hostname = unit_get('private_address')
+        log('Using unit_get private address')
+    log(hostname)
+    return hostname
+
+
+def get_remote_relation_attr(remote_unit, attr_name, relation_id=None):
+    args = ["relation-get", attr_name, remote_unit]
     if relation_id is not None:
         args.extend(['-r', relation_id])
-    hostname = subprocess.check_output(args).strip()
+    return subprocess.check_output(args).strip()
+
+
+def get_ip_and_hostname(remote_unit, relation_id=None):
+    hostname = get_remote_relation_attr(remote_unit, 'ingress-address', relation_id)
+    if hostname is None or not len(hostname):
+        hostname = get_remote_relation_attr(remote_unit, 'private-address',relation_id)
 
     if hostname is None or not len(hostname):
         print "relation-get failed"
diff --git a/hooks/monitors-relation-changed b/hooks/monitors-relation-changed
index be91feb..c48cdbb 100755
--- a/hooks/monitors-relation-changed
+++ b/hooks/monitors-relation-changed
@@ -22,13 +22,13 @@ import subprocess
 import yaml
 import json
 import re
-import string
 
 
 from common import (customize_service, get_pynag_host,
         get_pynag_service, refresh_hostgroups,
         get_valid_relations, get_valid_units,
-        initialize_inprogress_config, flush_inprogress_config)
+        initialize_inprogress_config, flush_inprogress_config,
+        ingress_address)
 
 
 def main(argv):
@@ -60,12 +60,12 @@ def main(argv):
                             or 'target-id' not in relation_settings):
                         continue
                     if ('target-id' in relation_settings and 'target-address' not in relation_settings):
-                            relation_settings['target-address'] = relation_settings['private-address']
+                            relation_settings['target-address'] = ingress_address(relation_settings)
 
                 else:
                     # Fake it for the more generic 'nagios' relation'
                     relation_settings['target-id'] = unit.replace('/','-')
-                    relation_settings['target-address'] = relation_settings['private-address']
+                    relation_settings['target-address'] = ingress_address(relation_settings)
                     relation_settings['monitors'] = {'monitors': {'remote': {} } }
 
                 if relid not in all_relations:
diff --git a/hooks/mymonitors-relation-joined b/hooks/mymonitors-relation-joined
index 4db4dee..ac4fd4e 100755
--- a/hooks/mymonitors-relation-joined
+++ b/hooks/mymonitors-relation-joined
@@ -1,17 +1,53 @@
-#!/bin/bash
-if [ -n "$JUJU_RELATION_ID" ] ; then
-    # single relation joined
-    rels=$JUJU_RELATION_ID
-else
-    # Refresh from upgrade or some other place
-    rels=`relation-ids mymonitors`
-fi
-
-target_id=${JUJU_UNIT_NAME//\//-}
-
-for rel in $rels ; do
-    relation-set -r $rel \
-        monitors="`cat monitors.yaml`" \
-        target-address=`unit-get private-address` \
-        target-id=$target_id
-done
+#!/usr/bin/python
+# mymonitors-relation-joined - adds monitors.yaml content to relation data
+# Copyright Canonical 2017 Canonical Ltd. All Rights Reserved
+#
+# 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, see <http://www.gnu.org/licenses/>.
+
+import common
+
+from charmhelpers.core.hookenv import (
+    local_unit,
+    log,
+    relation_id,
+    relation_ids,
+    relation_set,
+)
+
+def main():
+    rel_id = relation_id()
+    if rel_id is None:
+        rels = relation_ids("mymonitors")
+    else:
+        rels = [rel_id]
+
+    with open('monitors.yaml', 'r') as monitors:
+        monitors_yaml=monitors.read()
+    target_id = local_unit().replace('/', '-')
+    target_address = common.get_local_ingress_address('monitors')
+
+    relation_data={
+        'monitors': monitors_yaml,
+        'target-address': target_address,
+        'target-id': target_id
+    }
+    log('mymonitors data:\n%s' % relation_data)
+
+    for rel_id in rels:
+        log('setting monitors data for %s' % rel_id)
+        relation_set(rel_id, **relation_data)
+
+
+if __name__ == '__main__':
+    main()
diff --git a/hooks/website-relation-joined b/hooks/website-relation-joined
index 6d11044..dc3fec0 100755
--- a/hooks/website-relation-joined
+++ b/hooks/website-relation-joined
@@ -1,8 +1,38 @@
-#!/bin/bash
-sslcfg=`config-get ssl`
-
-if [ "$sslcfg" == "only" ]; then
-    relation-set hostname=`unit-get private-address` port=443
-else
-    relation-set hostname=`unit-get private-address` port=80
-fi
+#!/usr/bin/python
+# website-relation-joined - Set the hostname into remote nagios http consumers
+# Copyright Canonical 2017 Canonical Ltd. All Rights Reserved
+#
+# 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, see <http://www.gnu.org/licenses/>.
+
+import common
+
+from charmhelpers.core.hookenv import (
+    config,
+    log,
+    relation_set,
+)
+
+def main():
+    relation_data = {'hostname': common.get_local_ingress_address()}
+    sslcfg = config()['ssl']
+    if sslcfg == 'only':
+        relation_data['port'] = 443
+    else:
+        relation_data['port'] = 80
+    log('website-relation-joined data %s' % relation_data)
+    relation_set(None, **relation_data)
+
+
+if __name__ == '__main__':
+    main()

References