# Copyright 2014-2015 Canonical Limited.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#  http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

"""Compatibility with the nrpe-external-master charm"""
# Copyright 2012 Canonical Ltd.
#
# Authors:
#  Matthew Wedgwood <matthew.wedgwood@canonical.com>

import subprocess
import pwd
import grp
import os
import glob
import shutil
import re
import shlex
import yaml

from charmhelpers.core.hookenv import (
    config,
    hook_name,
    local_unit,
    log,
    relation_get,
    relation_ids,
    relation_set,
    relations_of_type,
)

from charmhelpers.core.host import service
from charmhelpers.core import host

# This module adds compatibility with the nrpe-external-master and plain nrpe
# subordinate charms. To use it in your charm:
#
# 1. Update metadata.yaml
#
#   provides:
#     (...)
#     nrpe-external-master:
#       interface: nrpe-external-master
#       scope: container
#
#   and/or
#
#   provides:
#     (...)
#     local-monitors:
#       interface: local-monitors
#       scope: container

#
# 2. Add the following to config.yaml
#
#    nagios_context:
#      default: "juju"
#      type: string
#      description: |
#        Used by the nrpe subordinate charms.
#        A string that will be prepended to instance name to set the host name
#        in nagios. So for instance the hostname would be something like:
#            juju-myservice-0
#        If you're running multiple environments with the same services in them
#        this allows you to differentiate between them.
#    nagios_servicegroups:
#      default: ""
#      type: string
#      description: |
#        A comma-separated list of nagios servicegroups.
#        If left empty, the nagios_context will be used as the servicegroup
#
# 3. Add custom checks (Nagios plugins) to files/nrpe-external-master
#
# 4. Update your hooks.py with something like this:
#
#    from charmsupport.nrpe import NRPE
#    (...)
#    def update_nrpe_config():
#        nrpe_compat = NRPE()
#        nrpe_compat.add_check(
#            shortname = "myservice",
#            description = "Check MyService",
#            check_cmd = "check_http -w 2 -c 10 http://localhost"
#            )
#        nrpe_compat.add_check(
#            "myservice_other",
#            "Check for widget failures",
#            check_cmd = "/srv/myapp/scripts/widget_check"
#            )
#        nrpe_compat.write()
#
#    def config_changed():
#        (...)
#        update_nrpe_config()
#
#    def nrpe_external_master_relation_changed():
#        update_nrpe_config()
#
#    def local_monitors_relation_changed():
#        update_nrpe_config()
#
# 4.a If your charm is a subordinate charm set primary=False
#
#    from charmsupport.nrpe import NRPE
#    (...)
#    def update_nrpe_config():
#        nrpe_compat = NRPE(primary=False)
#
# 5. ln -s hooks.py nrpe-external-master-relation-changed
#    ln -s hooks.py local-monitors-relation-changed


class CheckException(Exception):
    pass


class Check(object):
    shortname_re = '[A-Za-z0-9-_.@]+$'
    service_template = ("""
#---------------------------------------------------
# This file is Juju managed
#---------------------------------------------------
define service {{
    use                             active-service
    host_name                       {nagios_hostname}
    service_description             {nagios_hostname}[{shortname}] """
                        """{description}
    check_command                   check_nrpe!{command}
    servicegroups                   {nagios_servicegroup}
}}
""")

    def __init__(self, shortname, description, check_cmd):
        super(Check, self).__init__()
        # XXX: could be better to calculate this from the service name
        if not re.match(self.shortname_re, shortname):
            raise CheckException("shortname must match {}".format(
                Check.shortname_re))
        self.shortname = shortname
        self.command = "check_{}".format(shortname)
        # Note: a set of invalid characters is defined by the
        # Nagios server config
        # The default is: illegal_object_name_chars=`~!$%^&*"|'<>?,()=
        self.description = description
        self.check_cmd = self._locate_cmd(check_cmd)

    def _get_check_filename(self):
        return os.path.join(NRPE.nrpe_confdir, '{}.cfg'.format(self.command))

    def _get_service_filename(self, hostname):
        return os.path.join(NRPE.nagios_exportdir,
                            'service__{}_{}.cfg'.format(hostname, self.command))

    def _locate_cmd(self, check_cmd):
        search_path = (
            '/usr/lib/nagios/plugins',
            '/usr/local/lib/nagios/plugins',
        )
        parts = shlex.split(check_cmd)
        for path in search_path:
            if os.path.exists(os.path.join(path, parts[0])):
                command = os.path.join(path, parts[0])
                if len(parts) > 1:
                    command += " " + " ".join(parts[1:])
                return command
        log('Check command not found: {}'.format(parts[0]))
        return ''

    def _remove_service_files(self):
        if not os.path.exists(NRPE.nagios_exportdir):
            return
        for f in os.listdir(NRPE.nagios_exportdir):
            if f.endswith('_{}.cfg'.format(self.command)):
                os.remove(os.path.join(NRPE.nagios_exportdir, f))

    def remove(self, hostname):
        nrpe_check_file = self._get_check_filename()
        if os.path.exists(nrpe_check_file):
            os.remove(nrpe_check_file)
        self._remove_service_files()

    def write(self, nagios_context, hostname, nagios_servicegroups):
        nrpe_check_file = self._get_check_filename()
        with open(nrpe_check_file, 'w') as nrpe_check_config:
            nrpe_check_config.write("# check {}\n".format(self.shortname))
            if nagios_servicegroups:
                nrpe_check_config.write(
                    "# The following header was added automatically by juju\n")
                nrpe_check_config.write(
                    "# Modifying it will affect nagios monitoring and alerting\n")
                nrpe_check_config.write(
                    "# servicegroups: {}\n".format(nagios_servicegroups))
            nrpe_check_config.write("command[{}]={}\n".format(
                self.command, self.check_cmd))

        if not os.path.exists(NRPE.nagios_exportdir):
            log('Not writing service config as {} is not accessible'.format(
                NRPE.nagios_exportdir))
        else:
            self.write_service_config(nagios_context, hostname,
                                      nagios_servicegroups)

    def write_service_config(self, nagios_context, hostname,
                             nagios_servicegroups):
        self._remove_service_files()

        templ_vars = {
            'nagios_hostname': hostname,
            'nagios_servicegroup': nagios_servicegroups,
            'description': self.description,
            'shortname': self.shortname,
            'command': self.command,
        }
        nrpe_service_text = Check.service_template.format(**templ_vars)
        nrpe_service_file = self._get_service_filename(hostname)
        with open(nrpe_service_file, 'w') as nrpe_service_config:
            nrpe_service_config.write(str(nrpe_service_text))

    def run(self):
        subprocess.call(self.check_cmd)


class NRPE(object):
    nagios_logdir = '/var/log/nagios'
    nagios_exportdir = '/var/lib/nagios/export'
    nrpe_confdir = '/etc/nagios/nrpe.d'
    homedir = '/var/lib/nagios'  # home dir provided by nagios-nrpe-server

    def __init__(self, hostname=None, primary=True):
        super(NRPE, self).__init__()
        self.config = config()
        self.primary = primary
        self.nagios_context = self.config['nagios_context']
        if 'nagios_servicegroups' in self.config and self.config['nagios_servicegroups']:
            self.nagios_servicegroups = self.config['nagios_servicegroups']
        else:
            self.nagios_servicegroups = self.nagios_context
        self.unit_name = local_unit().replace('/', '-')
        if hostname:
            self.hostname = hostname
        else:
            nagios_hostname = get_nagios_hostname()
            if nagios_hostname:
                self.hostname = nagios_hostname
            else:
                self.hostname = "{}-{}".format(self.nagios_context, self.unit_name)
        self.checks = []
        # Iff in an nrpe-external-master relation hook, set primary status
        relation = relation_ids('nrpe-external-master')
        if relation:
            log("Setting charm primary status {}".format(primary))
            for rid in relation:
                relation_set(relation_id=rid, relation_settings={'primary': self.primary})
        self.remove_check_queue = set()

    def add_check(self, *args, **kwargs):
        shortname = None
        if kwargs.get('shortname') is None:
            if len(args) > 0:
                shortname = args[0]
        else:
            shortname = kwargs['shortname']

        self.checks.append(Check(*args, **kwargs))
        try:
            self.remove_check_queue.remove(shortname)
        except KeyError:
            pass

    def remove_check(self, *args, **kwargs):
        if kwargs.get('shortname') is None:
            raise ValueError('shortname of check must be specified')

        # Use sensible defaults if they're not specified - these are not
        # actually used during removal, but they're required for constructing
        # the Check object; check_disk is chosen because it's part of the
        # nagios-plugins-basic package.
        if kwargs.get('check_cmd') is None:
            kwargs['check_cmd'] = 'check_disk'
        if kwargs.get('description') is None:
            kwargs['description'] = ''

        check = Check(*args, **kwargs)
        check.remove(self.hostname)
        self.remove_check_queue.add(kwargs['shortname'])

    def write(self):
        try:
            nagios_uid = pwd.getpwnam('nagios').pw_uid
            nagios_gid = grp.getgrnam('nagios').gr_gid
        except Exception:
            log("Nagios user not set up, nrpe checks not updated")
            return

        if not os.path.exists(NRPE.nagios_logdir):
            os.mkdir(NRPE.nagios_logdir)
            os.chown(NRPE.nagios_logdir, nagios_uid, nagios_gid)

        nrpe_monitors = {}
        monitors = {"monitors": {"remote": {"nrpe": nrpe_monitors}}}
        for nrpecheck in self.checks:
            nrpecheck.write(self.nagios_context, self.hostname,
                            self.nagios_servicegroups)
            nrpe_monitors[nrpecheck.shortname] = {
                "command": nrpecheck.command,
            }

        # update-status hooks are configured to firing every 5 minutes by
        # default. When nagios-nrpe-server is restarted, the nagios server
        # reports checks failing causing unnecessary alerts. Let's not restart
        # on update-status hooks.
        if not hook_name() == 'update-status':
            service('restart', 'nagios-nrpe-server')

        monitor_ids = relation_ids("local-monitors") + \
            relation_ids("nrpe-external-master")
        for rid in monitor_ids:
            reldata = relation_get(unit=local_unit(), rid=rid)
            if 'monitors' in reldata:
                # update the existing set of monitors with the new data
                old_monitors = yaml.safe_load(reldata['monitors'])
                old_nrpe_monitors = old_monitors['monitors']['remote']['nrpe']
                # remove keys that are in the remove_check_queue
                old_nrpe_monitors = {k: v for k, v in old_nrpe_monitors.items()
                                     if k not in self.remove_check_queue}
                # update/add nrpe_monitors
                old_nrpe_monitors.update(nrpe_monitors)
                old_monitors['monitors']['remote']['nrpe'] = old_nrpe_monitors
                # write back to the relation
                relation_set(relation_id=rid, monitors=yaml.dump(old_monitors))
            else:
                # write a brand new set of monitors, as no existing ones.
                relation_set(relation_id=rid, monitors=yaml.dump(monitors))

        self.remove_check_queue.clear()


def get_nagios_hostcontext(relation_name='nrpe-external-master'):
    """
    Query relation with nrpe subordinate, return the nagios_host_context

    :param str relation_name: Name of relation nrpe sub joined to
    """
    for rel in relations_of_type(relation_name):
        if 'nagios_host_context' in rel:
            return rel['nagios_host_context']


def get_nagios_hostname(relation_name='nrpe-external-master'):
    """
    Query relation with nrpe subordinate, return the nagios_hostname

    :param str relation_name: Name of relation nrpe sub joined to
    """
    for rel in relations_of_type(relation_name):
        if 'nagios_hostname' in rel:
            return rel['nagios_hostname']


def get_nagios_unit_name(relation_name='nrpe-external-master'):
    """
    Return the nagios unit name prepended with host_context if needed

    :param str relation_name: Name of relation nrpe sub joined to
    """
    host_context = get_nagios_hostcontext(relation_name)
    if host_context:
        unit = "%s:%s" % (host_context, local_unit())
    else:
        unit = local_unit()
    return unit


def add_init_service_checks(nrpe, services, unit_name, immediate_check=True):
    """
    Add checks for each service in list

    :param NRPE nrpe: NRPE object to add check to
    :param list services: List of services to check
    :param str unit_name: Unit name to use in check description
    :param bool immediate_check: For sysv init, run the service check immediately
    """
    for svc in services:
        # Don't add a check for these services from neutron-gateway
        if svc in ['ext-port', 'os-charm-phy-nic-mtu']:
            next

        upstart_init = '/etc/init/%s.conf' % svc
        sysv_init = '/etc/init.d/%s' % svc

        if host.init_is_systemd():
            nrpe.add_check(
                shortname=svc,
                description='process check {%s}' % unit_name,
                check_cmd='check_systemd.py %s' % svc
            )
        elif os.path.exists(upstart_init):
            nrpe.add_check(
                shortname=svc,
                description='process check {%s}' % unit_name,
                check_cmd='check_upstart_job %s' % svc
            )
        elif os.path.exists(sysv_init):
            cronpath = '/etc/cron.d/nagios-service-check-%s' % svc
            checkpath = '%s/service-check-%s.txt' % (nrpe.homedir, svc)
            croncmd = (
                '/usr/local/lib/nagios/plugins/check_exit_status.pl '
                '-e -s /etc/init.d/%s status' % svc
            )
            cron_file = '*/5 * * * * root %s > %s\n' % (croncmd, checkpath)
            f = open(cronpath, 'w')
            f.write(cron_file)
            f.close()
            nrpe.add_check(
                shortname=svc,
                description='service check {%s}' % unit_name,
                check_cmd='check_status_file.py -f %s' % checkpath,
            )
            # if /var/lib/nagios doesn't exist open(checkpath, 'w') will fail
            # (LP: #1670223).
            if immediate_check and os.path.isdir(nrpe.homedir):
                f = open(checkpath, 'w')
                subprocess.call(
                    croncmd.split(),
                    stdout=f,
                    stderr=subprocess.STDOUT
                )
                f.close()
                os.chmod(checkpath, 0o644)


def copy_nrpe_checks(nrpe_files_dir=None):
    """
    Copy the nrpe checks into place

    """
    NAGIOS_PLUGINS = '/usr/local/lib/nagios/plugins'
    if nrpe_files_dir is None:
        # determine if "charmhelpers" is in CHARMDIR or CHARMDIR/hooks
        for segment in ['.', 'hooks']:
            nrpe_files_dir = os.path.abspath(os.path.join(
                os.getenv('CHARM_DIR'),
                segment,
                'charmhelpers',
                'contrib',
                'openstack',
                'files'))
            if os.path.isdir(nrpe_files_dir):
                break
        else:
            raise RuntimeError("Couldn't find charmhelpers directory")
    if not os.path.exists(NAGIOS_PLUGINS):
        os.makedirs(NAGIOS_PLUGINS)
    for fname in glob.glob(os.path.join(nrpe_files_dir, "check_*")):
        if os.path.isfile(fname):
            shutil.copy2(fname,
                         os.path.join(NAGIOS_PLUGINS, os.path.basename(fname)))


def add_haproxy_checks(nrpe, unit_name):
    """
    Add checks for each service in list

    :param NRPE nrpe: NRPE object to add check to
    :param str unit_name: Unit name to use in check description
    """
    nrpe.add_check(
        shortname='haproxy_servers',
        description='Check HAProxy {%s}' % unit_name,
        check_cmd='check_haproxy.sh')
    nrpe.add_check(
        shortname='haproxy_queue',
        description='Check HAProxy queue depth {%s}' % unit_name,
        check_cmd='check_haproxy_queue_depth.sh')

[((356, 15, 356, 47), 'charmhelpers.core.hookenv.relations_of_type', 'relations_of_type', ({(356, 33, 356, 46): 'relation_name'}, {}), '(relation_name)', False, 'from charmhelpers.core.hookenv import config, hook_name, local_unit, log, relation_get, relation_ids, relation_set, relations_of_type\n'), ((367, 15, 367, 47), 'charmhelpers.core.hookenv.relations_of_type', 'relations_of_type', ({(367, 33, 367, 46): 'relation_name'}, {}), '(relation_name)', False, 'from charmhelpers.core.hookenv import config, hook_name, local_unit, log, relation_get, relation_ids, relation_set, relations_of_type\n'), ((171, 16, 171, 38), 'shlex.split', 'shlex.split', ({(171, 28, 171, 37): 'check_cmd'}, {}), '(check_cmd)', False, 'import shlex\n'), ((184, 17, 184, 50), 'os.listdir', 'os.listdir', ({(184, 28, 184, 49): 'NRPE.nagios_exportdir'}, {}), '(NRPE.nagios_exportdir)', False, 'import os\n'), ((190, 11, 190, 42), 'os.path.exists', 'os.path.exists', ({(190, 26, 190, 41): 'nrpe_check_file'}, {}), '(nrpe_check_file)', False, 'import os\n'), ((232, 8, 232, 39), 'subprocess.call', 'subprocess.call', ({(232, 24, 232, 38): 'self.check_cmd'}, {}), '(self.check_cmd)', False, 'import subprocess\n'), ((243, 22, 243, 30), 'charmhelpers.core.hookenv.config', 'config', ({}, {}), '()', False, 'from charmhelpers.core.hookenv import config, hook_name, local_unit, log, relation_get, relation_ids, relation_set, relations_of_type\n'), ((261, 19, 261, 55), 'charmhelpers.core.hookenv.relation_ids', 'relation_ids', ({(261, 32, 261, 54): '"""nrpe-external-master"""'}, {}), "('nrpe-external-master')", False, 'from charmhelpers.core.hookenv import config, hook_name, local_unit, log, relation_get, relation_ids, relation_set, relations_of_type\n'), ((382, 15, 382, 27), 'charmhelpers.core.hookenv.local_unit', 'local_unit', ({}, {}), '()', False, 'from charmhelpers.core.hookenv import config, hook_name, local_unit, log, relation_get, relation_ids, relation_set, relations_of_type\n'), ((403, 11, 403, 33), 'charmhelpers.core.host.init_is_systemd', 'host.init_is_systemd', ({}, {}), '()', False, 'from charmhelpers.core import host\n'), ((464, 11, 464, 41), 'os.path.exists', 'os.path.exists', ({(464, 26, 464, 40): 'NAGIOS_PLUGINS'}, {}), '(NAGIOS_PLUGINS)', False, 'import os\n'), ((465, 8, 465, 35), 'os.makedirs', 'os.makedirs', ({(465, 20, 465, 34): 'NAGIOS_PLUGINS'}, {}), '(NAGIOS_PLUGINS)', False, 'import os\n'), ((466, 27, 466, 66), 'os.path.join', 'os.path.join', ({(466, 40, 466, 54): 'nrpe_files_dir', (466, 56, 466, 65): '"""check_*"""'}, {}), "(nrpe_files_dir, 'check_*')", False, 'import os\n'), ((467, 11, 467, 32), 'os.path.isfile', 'os.path.isfile', ({(467, 26, 467, 31): 'fname'}, {}), '(fname)', False, 'import os\n'), ((148, 15, 148, 53), 're.match', 're.match', ({(148, 24, 148, 41): 'self.shortname_re', (148, 43, 148, 52): 'shortname'}, {}), '(self.shortname_re, shortname)', False, 'import re\n'), ((182, 15, 182, 52), 'os.path.exists', 'os.path.exists', ({(182, 30, 182, 51): 'NRPE.nagios_exportdir'}, {}), '(NRPE.nagios_exportdir)', False, 'import os\n'), ((191, 12, 191, 38), 'os.remove', 'os.remove', ({(191, 22, 191, 37): 'nrpe_check_file'}, {}), '(nrpe_check_file)', False, 'import os\n'), ((208, 15, 208, 52), 'os.path.exists', 'os.path.exists', ({(208, 30, 208, 51): 'NRPE.nagios_exportdir'}, {}), '(NRPE.nagios_exportdir)', False, 'import os\n'), ((307, 15, 307, 49), 'os.path.exists', 'os.path.exists', ({(307, 30, 307, 48): 'NRPE.nagios_logdir'}, {}), '(NRPE.nagios_logdir)', False, 'import os\n'), ((308, 12, 308, 40), 'os.mkdir', 'os.mkdir', ({(308, 21, 308, 39): 'NRPE.nagios_logdir'}, {}), '(NRPE.nagios_logdir)', False, 'import os\n'), ((309, 12, 309, 64), 'os.chown', 'os.chown', ({(309, 21, 309, 39): 'NRPE.nagios_logdir', (309, 41, 309, 51): 'nagios_uid', (309, 53, 309, 63): 'nagios_gid'}, {}), '(NRPE.nagios_logdir, nagios_uid, nagios_gid)', False, 'import os\n'), ((325, 12, 325, 52), 'charmhelpers.core.host.service', 'service', ({(325, 20, 325, 29): '"""restart"""', (325, 31, 325, 51): '"""nagios-nrpe-server"""'}, {}), "('restart', 'nagios-nrpe-server')", False, 'from charmhelpers.core.host import service\n'), ((327, 22, 327, 52), 'charmhelpers.core.hookenv.relation_ids', 'relation_ids', ({(327, 35, 327, 51): '"""local-monitors"""'}, {}), "('local-monitors')", False, 'from charmhelpers.core.hookenv import config, hook_name, local_unit, log, relation_get, relation_ids, relation_set, relations_of_type\n'), ((328, 12, 328, 48), 'charmhelpers.core.hookenv.relation_ids', 'relation_ids', ({(328, 25, 328, 47): '"""nrpe-external-master"""'}, {}), "('nrpe-external-master')", False, 'from charmhelpers.core.hookenv import config, hook_name, local_unit, log, relation_get, relation_ids, relation_set, relations_of_type\n'), ((409, 13, 409, 41), 'os.path.exists', 'os.path.exists', ({(409, 28, 409, 40): 'upstart_init'}, {}), '(upstart_init)', False, 'import os\n'), ((460, 15, 460, 44), 'os.path.isdir', 'os.path.isdir', ({(460, 29, 460, 43): 'nrpe_files_dir'}, {}), '(nrpe_files_dir)', False, 'import os\n'), ((173, 30, 173, 58), 'os.path.join', 'os.path.join', ({(173, 43, 173, 47): 'path', (173, 49, 173, 57): 'parts[0]'}, {}), '(path, parts[0])', False, 'import os\n'), ((174, 26, 174, 54), 'os.path.join', 'os.path.join', ({(174, 39, 174, 43): 'path', (174, 45, 174, 53): 'parts[0]'}, {}), '(path, parts[0])', False, 'import os\n'), ((250, 25, 250, 37), 'charmhelpers.core.hookenv.local_unit', 'local_unit', ({}, {}), '()', False, 'from charmhelpers.core.hookenv import config, hook_name, local_unit, log, relation_get, relation_ids, relation_set, relations_of_type\n'), ((265, 16, 265, 90), 'charmhelpers.core.hookenv.relation_set', 'relation_set', (), '', False, 'from charmhelpers.core.hookenv import config, hook_name, local_unit, log, relation_get, relation_ids, relation_set, relations_of_type\n'), ((301, 25, 301, 47), 'pwd.getpwnam', 'pwd.getpwnam', ({(301, 38, 301, 46): '"""nagios"""'}, {}), "('nagios')", False, 'import pwd\n'), ((302, 25, 302, 47), 'grp.getgrnam', 'grp.getgrnam', ({(302, 38, 302, 46): '"""nagios"""'}, {}), "('nagios')", False, 'import grp\n'), ((304, 12, 304, 66), 'charmhelpers.core.hookenv.log', 'log', ({(304, 16, 304, 65): '"""Nagios user not set up, nrpe checks not updated"""'}, {}), "('Nagios user not set up, nrpe checks not updated')", False, 'from charmhelpers.core.hookenv import config, hook_name, local_unit, log, relation_get, relation_ids, relation_set, relations_of_type\n'), ((324, 15, 324, 26), 'charmhelpers.core.hookenv.hook_name', 'hook_name', ({}, {}), '()', False, 'from charmhelpers.core.hookenv import config, hook_name, local_unit, log, relation_get, relation_ids, relation_set, relations_of_type\n'), ((333, 31, 333, 66), 'yaml.safe_load', 'yaml.safe_load', ({(333, 46, 333, 65): "reldata['monitors']"}, {}), "(reldata['monitors'])", False, 'import yaml\n'), ((380, 40, 380, 52), 'charmhelpers.core.hookenv.local_unit', 'local_unit', ({}, {}), '()', False, 'from charmhelpers.core.hookenv import config, hook_name, local_unit, log, relation_get, relation_ids, relation_set, relations_of_type\n'), ((415, 13, 415, 38), 'os.path.exists', 'os.path.exists', ({(415, 28, 415, 37): 'sysv_init'}, {}), '(sysv_init)', False, 'import os\n'), ((186, 26, 186, 64), 'os.path.join', 'os.path.join', ({(186, 39, 186, 60): 'NRPE.nagios_exportdir', (186, 62, 186, 63): 'f'}, {}), '(NRPE.nagios_exportdir, f)', False, 'import os\n'), ((330, 40, 330, 52), 'charmhelpers.core.hookenv.local_unit', 'local_unit', ({}, {}), '()', False, 'from charmhelpers.core.hookenv import config, hook_name, local_unit, log, relation_get, relation_ids, relation_set, relations_of_type\n'), ((454, 16, 454, 38), 'os.getenv', 'os.getenv', ({(454, 26, 454, 37): '"""CHARM_DIR"""'}, {}), "('CHARM_DIR')", False, 'import os\n'), ((469, 54, 469, 77), 'os.path.basename', 'os.path.basename', ({(469, 71, 469, 76): 'fname'}, {}), '(fname)', False, 'import os\n'), ((342, 55, 342, 78), 'yaml.dump', 'yaml.dump', ({(342, 65, 342, 77): 'old_monitors'}, {}), '(old_monitors)', False, 'import yaml\n'), ((345, 55, 345, 74), 'yaml.dump', 'yaml.dump', ({(345, 65, 345, 73): 'monitors'}, {}), '(monitors)', False, 'import yaml\n'), ((433, 35, 433, 62), 'os.path.isdir', 'os.path.isdir', ({(433, 49, 433, 61): 'nrpe.homedir'}, {}), '(nrpe.homedir)', False, 'import os\n'), ((441, 16, 441, 42), 'os.chmod', 'os.chmod', ({(441, 25, 441, 34): 'checkpath', (441, 36, 441, 41): '(420)'}, {}), '(checkpath, 420)', False, 'import os\n')]