예제 #1
0
    def test_automonitor_strings_basic(self):
        # Clean things out so we only see what we want to see...
        ocf_string = '''{
#       comment
        "class":        "ocf",
        "type":         "neo4j",
        "provider":     "assimilation",
        "classconfig": [
            [null,      "@basename()",              "java$"],
            [null,      "$argv[-1]",                 "org\\.neo4j\\.server\\.Bootstrapper$"],
            ["PORT",    "serviceport",              "[0-9]+$"],
            ["NEOHOME", "@argequals(-Dneo4j.home)", "/.*"]
        ]
}'''
        ocf = MonitoringRule.ConstructFromString(ocf_string)
        self.assertTrue(isinstance(ocf, OCFMonitoringRule))
        lsb_string = '''{
#       comment
        "class":        "lsb",
        "type":         "neo4j",
        "classconfig": [
            ["@basename()",    "java$"],
            ["$argv[-1]",       "org\\.neo4j\\.server\\.Bootstrapper$"],
        ]
}'''
        lsb = MonitoringRule.ConstructFromString(lsb_string)
        self.assertTrue(isinstance(lsb, LSBMonitoringRule))
    def processpkt(self, drone, _unused_srcaddr, _unused_jsonobj, _discoverychanged):
        '''Send commands to monitor host aspects for the given System.
        We ignore discoverychanged because we always want to monitor even if a system
        has just come up with the same discovery as before it went down.
        '''

        drone.monitors_activated = True
        #self.log.debug('In DiscoveryGenerateHostMonitoring::processpkt for %s with %s (%s)'
        #               %    (drone, _discoverychanged, str(_unused_jsonobj)))
        montuples = MonitoringRule.findallmatches((drone,), objclass='host')
        for montuple in montuples:
            if montuple[0] == MonitoringRule.NOMATCH:
                continue
            elif montuple[0] == MonitoringRule.PARTMATCH:
                print >> sys.stderr, (
                'Automatic host monitoring of %s not possible with %s: missing %s'
                %   (drone.designation, str(montuple[1]), str(montuple[2])))
                self.log.warning('Insufficient information to monitor host %s'
                ' using %s: %s is missing.'
                %   (drone.designation, str(montuple[1]), str(montuple[2])))
            else:
                agent = montuple[1]
                self._add_service_monitoring(drone, drone, agent)
                print >> sys.stderr, ('START monitoring host %s using %s:%s agent'
                %   (drone.designation, agent['monitorclass'], agent['monitortype']))
    def processpkt(self, drone, unused_srcaddr, unused_jsonobj):
        "Send commands to monitor host aspects for the given Drone"
        unused_srcaddr = unused_srcaddr
        unused_jsonobj = unused_jsonobj

        drone.monitors_activated = True
        montuples = MonitoringRule.findallmatches((drone, ), objclass='host')
        for montuple in montuples:
            if montuple[0] == MonitoringRule.NOMATCH:
                continue
            elif montuple[0] == MonitoringRule.PARTMATCH:
                print >> sys.stderr, (
                    'Automatic host monitoring of %s not possible with %s: missing %s'
                    % (drone.designation, str(montuple[1]), str(montuple[2])))
                self.log.warning(
                    'Insufficient information to monitor host %s'
                    ' using %s: %s is missing.' %
                    (drone.designation, str(montuple[1]), str(montuple[2])))
            else:
                agent = montuple[1]
                self._add_service_monitoring(drone, drone, agent)
                print >> sys.stderr, (
                    'START monitoring host %s using %s:%s agent' %
                    (drone.designation, agent['monitorclass'],
                     agent['monitortype']))
    def processpkt(self, drone, _unused_srcaddr, _unused_jsonobj,
                   _discoverychanged):
        '''Send commands to monitor host aspects for the given System.
        We ignore discoverychanged because we always want to monitor even if a system
        has just come up with the same discovery as before it went down.
        '''

        drone.monitors_activated = True
        #self.log.debug('In DiscoveryGenerateHostMonitoring::processpkt for %s with %s (%s)'
        #               %    (drone, _discoverychanged, str(_unused_jsonobj)))
        montuples = MonitoringRule.findallmatches((drone, ), objclass='host')
        for montuple in montuples:
            if montuple[0] == MonitoringRule.NOMATCH:
                continue
            elif montuple[0] == MonitoringRule.PARTMATCH:
                print >> sys.stderr, (
                    'Automatic host monitoring of %s not possible with %s: missing %s'
                    % (drone.designation, str(montuple[1]), str(montuple[2])))
                self.log.warning(
                    'Insufficient information to monitor host %s'
                    ' using %s: %s is missing.' %
                    (drone.designation, str(montuple[1]), str(montuple[2])))
            else:
                agent = montuple[1]
                self._add_service_monitoring(drone, drone, agent)
                print >> sys.stderr, (
                    'START monitoring host %s using %s:%s agent' %
                    (drone.designation, agent['monitorclass'],
                     agent['monitortype']))
    def processpkt(self, drone, _unused_srcaddr, jsonobj, _discoverychanged):
        '''Send commands to monitor services for this Systems's listening processes
        We ignore discoverychanged because we always want to monitor even if a system
        has just come up with the same discovery as before it went down.'''

        drone.monitors_activated = True
        #self.log.debug('In TCPDiscoveryGenerateMonitoring::processpkt for %s with %s (%s)'
        #               %    (drone, _discoverychanged, str(jsonobj)))
        data = jsonobj['data']  # The data portion of the JSON message
        for procname in data.keys(
        ):  # List of nanoprobe-assigned names of processes...
            procinfo = data[procname]
            processproc = self.store.load_or_create(
                ProcessNode,
                domain=drone.domain,
                processname=procname,
                host=drone.designation,
                pathname=procinfo.get('exe', 'unknown'),
                argv=procinfo.get('cmdline', 'unknown'),
                uid=procinfo.get('uid', 'unknown'),
                gid=procinfo.get('gid', 'unknown'),
                cwd=procinfo.get('cwd', '/'))
            if 'listenaddrs' not in procinfo:
                # We only monitor services, not clients...
                continue
            montuple = MonitoringRule.findbestmatch((processproc, drone))
            if montuple[0] == MonitoringRule.NOMATCH:
                processproc.is_monitored = False
                print >> sys.stderr, "**don't know how to monitor %s" % str(
                    processproc.argv)
                self.log.warning('No rules to monitor %s service %s' %
                                 (drone.designation, str(processproc.argv)))
            elif montuple[0] == MonitoringRule.PARTMATCH:
                processproc.is_monitored = False
                print >> sys.stderr, (
                    'Automatic monitoring not possible for %s -- %s is missing %s'
                    % (str(processproc.argv), str(montuple[1]), str(
                        montuple[2])))
                self.log.warning(
                    'Insufficient information to monitor %s service %s'
                    '. %s is missing %s' %
                    (drone.designation, str(processproc.argv), str(
                        montuple[1]), str(montuple[2])))
            else:
                processproc.is_monitored = True
                agent = montuple[1]
                self._add_service_monitoring(drone, processproc, agent)
                if agent['monitorclass'] == 'NEVERMON':
                    print >> sys.stderr, ('NEVER monitor %s' %
                                          (str(agent['monitortype'])))
                else:
                    print >> sys.stderr, (
                        'START monitoring %s using %s agent' %
                        (agent['monitortype'], agent['monitorclass']))
    def processpkt(self, drone, unused_srcaddr, jsonobj):
        "Send commands to monitor services for this Drone's listening processes"
        unused_srcaddr = unused_srcaddr

        drone.monitors_activated = True
        data = jsonobj['data']  # The data portion of the JSON message
        for procname in data.keys(
        ):  # List of nanoprobe-assigned names of processes...
            procinfo = data[procname]
            processproc = self.store.load_or_create(
                ProcessNode,
                domain=drone.domain,
                processname=procname,
                host=drone.designation,
                pathname=procinfo.get('exe', 'unknown'),
                argv=procinfo.get('cmdline', 'unknown'),
                uid=procinfo.get('uid', 'unknown'),
                gid=procinfo.get('gid', 'unknown'),
                cwd=procinfo.get('cwd', '/'))
            if 'listenaddrs' not in procinfo:
                # We only monitor services, not clients...
                continue
            montuple = MonitoringRule.findbestmatch((processproc, drone))
            if montuple[0] == MonitoringRule.NOMATCH:
                print >> sys.stderr, "**don't know how to monitor %s" % str(
                    processproc.argv)
                self.log.warning('No rules to monitor %s service %s' %
                                 (drone.designation, str(processproc.argv)))
            elif montuple[0] == MonitoringRule.PARTMATCH:
                print >> sys.stderr, (
                    'Automatic monitoring not possible for %s -- %s is missing %s'
                    % (str(processproc.argv), str(montuple[1]), str(
                        montuple[2])))
                self.log.warning(
                    'Insufficient information to monitor %s service %s'
                    '. %s is missing %s' %
                    (drone.designation, str(processproc.argv), str(
                        montuple[1]), str(montuple[2])))
            else:
                agent = montuple[1]
                self._add_service_monitoring(drone, processproc, agent)
                if agent['monitorclass'] == 'NEVERMON':
                    print >> sys.stderr, ('NEVER monitor %s' %
                                          (str(agent['monitortype'])))
                else:
                    print >> sys.stderr, (
                        'START monitoring %s using %s agent' %
                        (agent['monitortype'], agent['monitorclass']))
예제 #7
0
def is_upstartjob(args, context):
    '''
    Returns "true" if any of its arguments names an upstart job, "false" otherwise
    If no arguments are given, it returns whether this system has upstart enabled.
    '''

    from monitoring import MonitoringRule
    agentcache = MonitoringRule.compute_available_agents(context)

    if 'upstart' not in agentcache or len(agentcache['upstart']) == 0:
        return 'false'

    for arg in args:
        value = GraphNodeExpression.evaluate(arg, context)
        if value in agentcache['upstart']:
            return 'true'
    return len(args) == 0
def is_upstartjob(args, context):
    '''
    Returns "true" if any of its arguments names an upstart job, "false" otherwise
    If no arguments are given, it returns whether this system has upstart enabled.
    '''


    from monitoring import MonitoringRule
    agentcache = MonitoringRule.compute_available_agents(context)

    if 'upstart' not in agentcache or len(agentcache['upstart']) == 0:
        return 'false'

    for arg in args:
        value = GraphNodeExpression.evaluate(arg, context)
        if value in agentcache['upstart']:
            return 'true'
    return len(args) == 0
    def processpkt(self, drone, _unused_srcaddr, jsonobj, _discoverychanged):
        '''Send commands to monitor services for this Systems's listening processes
        We ignore discoverychanged because we always want to monitor even if a system
        has just come up with the same discovery as before it went down.'''

        drone.monitors_activated = True
        #self.log.debug('In TCPDiscoveryGenerateMonitoring::processpkt for %s with %s (%s)'
        #               %    (drone, _discoverychanged, str(jsonobj)))
        data = jsonobj['data'] # The data portion of the JSON message
        for procname in data.keys():    # List of nanoprobe-assigned names of processes...
            procinfo = data[procname]
            processproc = self.store.load_or_create(ProcessNode, domain=drone.domain
            ,   processname=procname, host=drone.designation
            ,   pathname=procinfo.get('exe', 'unknown'), argv=procinfo.get('cmdline', 'unknown')
            ,   uid=procinfo.get('uid','unknown'), gid=procinfo.get('gid', 'unknown')
            ,   cwd=procinfo.get('cwd', '/'))
            if 'listenaddrs' not in procinfo:
                # We only monitor services, not clients...
                continue
            montuple = MonitoringRule.findbestmatch((processproc, drone))
            if montuple[0] == MonitoringRule.NOMATCH:
                processproc.is_monitored = False
                print >> sys.stderr, "**don't know how to monitor %s" % str(processproc.argv)
                self.log.warning('No rules to monitor %s service %s'
                %   (drone.designation, str(processproc.argv)))
            elif montuple[0] == MonitoringRule.PARTMATCH:
                processproc.is_monitored = False
                print >> sys.stderr, (
                'Automatic monitoring not possible for %s -- %s is missing %s'
                %   (str(processproc.argv), str(montuple[1]), str(montuple[2])))
                self.log.warning('Insufficient information to monitor %s service %s'
                '. %s is missing %s'
                %   (drone.designation, str(processproc.argv)
                ,    str(montuple[1]), str(montuple[2])))
            else:
                processproc.is_monitored = True
                agent = montuple[1]
                self._add_service_monitoring(drone, processproc, agent)
                if agent['monitorclass'] == 'NEVERMON':
                    print >> sys.stderr, ('NEVER monitor %s' %  (str(agent['monitortype'])))
                else:
                    print >> sys.stderr, ('START monitoring %s using %s agent'
                    %   (agent['monitortype'], agent['monitorclass']))
    def processpkt(self, drone, unused_srcaddr, jsonobj):
        "Send commands to monitor services for this Drone's listening processes"
        unused_srcaddr = unused_srcaddr

        drone.monitors_activated = True
        data = jsonobj['data'] # The data portion of the JSON message
        for procname in data.keys():    # List of nanoprobe-assigned names of processes...
            procinfo = data[procname]
            processproc = self.store.load_or_create(ProcessNode, domain=drone.domain
            ,   processname=procname, host=drone.designation
            ,   pathname=procinfo.get('exe', 'unknown'), argv=procinfo.get('cmdline', 'unknown')
            ,   uid=procinfo.get('uid','unknown'), gid=procinfo.get('gid', 'unknown')
            ,   cwd=procinfo.get('cwd', '/'))
            if 'listenaddrs' not in procinfo:
                # We only monitor services, not clients...
                continue
            montuple = MonitoringRule.findbestmatch((processproc, drone))
            if montuple[0] == MonitoringRule.NOMATCH:
                processproc.is_monitored = False
                print >> sys.stderr, "**don't know how to monitor %s" % str(processproc.argv)
                self.log.warning('No rules to monitor %s service %s'
                %   (drone.designation, str(processproc.argv)))
            elif montuple[0] == MonitoringRule.PARTMATCH:
                processproc.is_monitored = False
                print >> sys.stderr, (
                'Automatic monitoring not possible for %s -- %s is missing %s'
                %   (str(processproc.argv), str(montuple[1]), str(montuple[2])))
                self.log.warning('Insufficient information to monitor %s service %s'
                '. %s is missing %s'
                %   (drone.designation, str(processproc.argv)
                ,    str(montuple[1]), str(montuple[2])))
            else:
                processproc.is_monitored = True
                agent = montuple[1]
                self._add_service_monitoring(drone, processproc, agent)
                if agent['monitorclass'] == 'NEVERMON':
                    print >> sys.stderr, ('NEVER monitor %s' %  (str(agent['monitortype'])))
                else:
                    print >> sys.stderr, ('START monitoring %s using %s agent'
                    %   (agent['monitortype'], agent['monitorclass']))
    def processpkt(self, drone, unused_srcaddr, unused_jsonobj):
        "Send commands to monitor host aspects for the given Drone"
        unused_srcaddr = unused_srcaddr
        unused_jsonobj = unused_jsonobj

        drone.monitors_activated = True
        montuples = MonitoringRule.findallmatches((drone,), objclass='host')
        for montuple in montuples:
            if montuple[0] == MonitoringRule.NOMATCH:
                continue
            elif montuple[0] == MonitoringRule.PARTMATCH:
                print >> sys.stderr, (
                'Automatic host monitoring of %s not possible with %s: missing %s'
                %   (drone.designation, str(montuple[1]), str(montuple[2])))
                self.log.warning('Insufficient information to monitor host %s'
                ' using %s: %s is missing.'
                %   (drone.designation, str(montuple[1]), str(montuple[2])))
            else:
                agent = montuple[1]
                self._add_service_monitoring(drone, drone, agent)
                print >> sys.stderr, ('START monitoring host %s using %s:%s agent'
                %   (drone.designation, agent['monitorclass'], agent['monitortype']))
예제 #12
0
def main():
    'Main program for the CMA (Collective Management Authority)'
    py2neo_major_version = int(PY2NEO_VERSION.partition('.')[0])
    if py2neo_major_version not in SUPPORTED_PY2NEO_VERSIONS:
        raise EnvironmentError('py2neo version %s not supported' %
                               PY2NEO_VERSION)
    DefaultPort = 1984
    # VERY Linux-specific - but useful and apparently correct ;-)
    PrimaryIPcmd =   \
    "ip address show primary scope global | grep '^ *inet' | sed -e 's%^ *inet *%%' -e 's%/.*%%'"
    ipfd = os.popen(PrimaryIPcmd, 'r')
    OurAddrStr = ('%s:%d' % (ipfd.readline().rstrip(), DefaultPort))
    ipfd.close()

    parser = optparse.OptionParser(
        prog='CMA',
        version=AssimCtypes.VERSION_STRING,
        description=
        'Collective Management Authority for the Assimilation System',
        usage='cma.py [--bind address:port]')

    parser.add_option(
        '-b',
        '--bind',
        action='store',
        default=None,
        dest='bind',
        metavar='address:port-to-bind-to',
        help='Address:port to listen to - for nanoprobes to connect to')

    parser.add_option(
        '-d',
        '--debug',
        action='store',
        default=0,
        dest='debug',
        help=
        'enable debug for CMA and libraries - value is debug level for C libraries.'
    )

    parser.add_option('-s',
                      '--status',
                      action='store_true',
                      default=False,
                      dest='status',
                      help='Return status of running CMA')

    parser.add_option('-k',
                      '--kill',
                      action='store_true',
                      default=False,
                      dest='kill',
                      help='Shut down running CMA.')

    parser.add_option('-e',
                      '--erasedb',
                      action='store_true',
                      default=False,
                      dest='erasedb',
                      help='Erase Neo4J before starting')

    parser.add_option('-f',
                      '--foreground',
                      action='store_true',
                      default=False,
                      dest='foreground',
                      help='keep the CMA from going into the background')

    parser.add_option('-p',
                      '--pidfile',
                      action='store',
                      default='/var/run/assimilation/cma',
                      dest='pidfile',
                      metavar='pidfile-pathname',
                      help='full pathname of where to locate our pid file')

    parser.add_option('-T',
                      '--trace',
                      action='store_true',
                      default=False,
                      dest='doTrace',
                      help='Trace CMA execution')

    parser.add_option('-u',
                      '--user',
                      action='store',
                      default=CMAUSERID,
                      dest='userid',
                      metavar='userid',
                      help='userid to run the CMA as')

    opt = parser.parse_args()[0]

    from AssimCtypes import daemonize_me, assimilation_openlog, are_we_already_running, \
        kill_pid_service, pidrunningstat_to_status, remove_pid_file, rmpid_and_exit_on_signal

    if opt.status:
        rc = pidrunningstat_to_status(are_we_already_running(
            opt.pidfile, None))
        return rc

    if opt.kill:
        if kill_pid_service(opt.pidfile, 15) < 0:
            print >> sys.stderr, "Unable to stop CMA."
            return 1
        return 0

    opt.debug = int(opt.debug)

    # This doesn't seem to work no matter where I invoke it...
    # But if we don't fork in daemonize_me() ('C' code), it works great...
    #    def cleanup():
    #        remove_pid_file(opt.pidfile)
    #    atexit.register(cleanup)
    #    signal.signal(signal.SIGTERM, lambda sig, stack: sys.exit(0))
    #    signal.signal(signal.SIGINT, lambda sig, stack: sys.exit(0))

    from cmadb import CMAdb
    CMAdb.running_under_docker()
    make_pid_dir(opt.pidfile, opt.userid)
    make_key_dir(CRYPTKEYDIR, opt.userid)
    cryptwarnings = pyCryptCurve25519.initkeys()
    for warn in cryptwarnings:
        print >> sys.stderr, ("WARNING: %s" % warn)
    #print >> sys.stderr, 'All known key ids:'
    keyids = pyCryptFrame.get_key_ids()
    keyids.sort()
    for keyid in keyids:
        if not keyid.startswith(CMA_KEY_PREFIX):
            try:
                # @FIXME This is not an ideal way to associate identities with hosts
                # in a multi-tenant environment
                # @FIXME - don't think I need to do the associate_identity at all any more...
                hostname, notused_post = keyid.split('@@', 1)
                notused_post = notused_post
                pyCryptFrame.associate_identity(hostname, keyid)
            except ValueError:
                pass
        #print >> sys.stderr, '>    %s/%s' % (keyid, pyCryptFrame.get_identity(keyid))

    daemonize_me(opt.foreground, '/', opt.pidfile, 20)

    rmpid_and_exit_on_signal(opt.pidfile, signal.SIGTERM)

    # Next statement can't appear before daemonize_me() or bind() fails -- not quite sure why...
    assimilation_openlog("cma")
    from packetlistener import PacketListener
    from messagedispatcher import MessageDispatcher
    from dispatchtarget import DispatchTarget
    from monitoring import MonitoringRule
    from AssimCclasses import pyNetAddr, pySignFrame, pyReliableUDP, \
         pyPacketDecoder
    from AssimCtypes import CONFIGNAME_CMAINIT, CONFIGNAME_CMAADDR, CONFIGNAME_CMADISCOVER, \
        CONFIGNAME_CMAFAIL, CONFIGNAME_CMAPORT, CONFIGNAME_OUTSIG, CONFIGNAME_COMPRESSTYPE, \
        CONFIGNAME_COMPRESS, proj_class_incr_debug, LONG_LICENSE_STRING, MONRULEINSTALL_DIR

    if opt.debug:
        print >> sys.stderr, ('Setting debug to %s' % opt.debug)

    for debug in range(opt.debug):
        debug = debug
        print >> sys.stderr, ('Incrementing C-level debug by one.')
        proj_class_incr_debug(None)

    #   Input our monitoring rule templates
    #   They only exist in flat files and in memory - they aren't in the database
    MonitoringRule.load_tree(MONRULEINSTALL_DIR)
    print >> sys.stderr, ('Monitoring rules loaded from %s' %
                          MONRULEINSTALL_DIR)

    execobserver_constraints = {
        'nodetype': [
            'Drone',
            'IPaddrNode',
            'MonitorAction',
            'NICNode',
            'ProcessNode',
            'SystemNode',
        ]
    }
    ForkExecObserver(constraints=execobserver_constraints,
                     scriptdir=NOTIFICATION_SCRIPT_DIR)
    print >> sys.stderr, ('Fork/Event observer dispatching from %s' %
                          NOTIFICATION_SCRIPT_DIR)

    if opt.bind is not None:
        OurAddrStr = opt.bind

    OurAddr = pyNetAddr(OurAddrStr)
    if OurAddr.port() == 0:
        OurAddr.setport(DefaultPort)

    try:
        configinfo = ConfigFile(filename=CMAINITFILE)
    except IOError:
        configinfo = ConfigFile()
    if opt.bind is not None:
        bindaddr = pyNetAddr(opt.bind)
        if bindaddr.port() == 0:
            bindaddr.setport(ConfigFile[CONFIGNAME_CMAPORT])
        configinfo[CONFIGNAME_CMAINIT] = bindaddr
    configinfo[CONFIGNAME_CMADISCOVER] = OurAddr
    configinfo[CONFIGNAME_CMAFAIL] = OurAddr
    configinfo[CONFIGNAME_CMAADDR] = OurAddr
    if (CONFIGNAME_COMPRESSTYPE in configinfo):
        configinfo[CONFIGNAME_COMPRESS]     \
        =   pyCompressFrame(compression_method=configinfo[CONFIGNAME_COMPRESSTYPE])
    configinfo[CONFIGNAME_OUTSIG] = pySignFrame(1)
    config = configinfo.complete_config()

    addr = config[CONFIGNAME_CMAINIT]
    # pylint is confused: addr is a pyNetAddr, not a pyConfigContext
    # pylint: disable=E1101
    if addr.port() == 0:
        addr.setport(DefaultPort)
    ourport = addr.port()
    for elem in (CONFIGNAME_CMAINIT, CONFIGNAME_CMAADDR,
                 CONFIGNAME_CMADISCOVER, CONFIGNAME_CMAFAIL):
        if elem in config:
            config[elem] = pyNetAddr(str(config[elem]), port=ourport)
    io = pyReliableUDP(config, pyPacketDecoder())
    io.setrcvbufsize(
        10 * 1024 *
        1024)  # No harm in asking - it will get us the best we can get...
    io.setsendbufsize(
        1024 * 1024)  # Most of the traffic volume is inbound from discovery
    drop_privileges_permanently(opt.userid)
    try:
        cmainit.CMAinit(io, cleanoutdb=opt.erasedb, debug=(opt.debug > 0))
    except RuntimeError:
        remove_pid_file(opt.pidfile)
        raise
    for warn in cryptwarnings:
        CMAdb.log.warning(warn)
    if CMAdb.cdb.db.neo4j_version[0] not in SUPPORTED_NEO4J_VERSIONS:
        raise EnvironmentError('Neo4j version %s.%s.%s not supported' %
                               CMAdb.cdb.db.neo4j_version)
    CMAdb.log.info('Listening on: %s' % str(config[CONFIGNAME_CMAINIT]))
    CMAdb.log.info('Requesting return packets sent to: %s' % str(OurAddr))
    CMAdb.log.info('Socket input buffer size:  %d' % io.getrcvbufsize())
    CMAdb.log.info('Socket output buffer size: %d' % io.getsendbufsize())
    keyids = pyCryptFrame.get_key_ids()
    keyids.sort()
    for keyid in keyids:
        CMAdb.log.info('KeyId %s Identity %s' %
                       (keyid, pyCryptFrame.get_identity(keyid)))
    if CMAdb.debug:
        CMAdb.log.debug('C-library Debug was set to %s' % opt.debug)
        CMAdb.log.debug('TheOneRing created - id = %s' % CMAdb.TheOneRing)
        CMAdb.log.debug('Config Object sent to nanoprobes: %s' % config)

    jvmfd = os.popen('java -version 2>&1')
    jvers = jvmfd.readline()
    jvmfd.close()
    disp = MessageDispatcher(DispatchTarget.dispatchtable)
    neovers = CMAdb.cdb.db.neo4j_version
    neoversstring = (('%s.%s.%s' if len(neovers) == 3 else '%s.%s.%s%s') %
                     neovers[0:3])

    CMAdb.log.info('Starting CMA version %s - licensed under %s' %
                   (AssimCtypes.VERSION_STRING, LONG_LICENSE_STRING))
    CMAdb.log.info(
        'Neo4j version %s // py2neo version %s // Python version %s // %s' %
        (('%s.%s.%s' % CMAdb.cdb.db.neo4j_version), str(py2neo.__version__),
         ('%s.%s.%s' % sys.version_info[0:3]), jvers))
    if opt.foreground:
        print >> sys.stderr, (
            'Starting CMA version %s - licensed under %s' %
            (AssimCtypes.VERSION_STRING, LONG_LICENSE_STRING))
        print >> sys.stderr, (
            'Neo4j version %s // py2neo version %s // Python version %s // %s'
            % (neoversstring, PY2NEO_VERSION,
               ('%s.%s.%s' % sys.version_info[0:3]), jvers))
    if len(neovers) > 3:
        CMAdb.log.warning(
            'Neo4j version %s is beta code - results not guaranteed.' %
            str(neovers))

    # Important to note that we don't want PacketListener to create its own 'io' object
    # or it will screw up the ReliableUDP protocol...
    listener = PacketListener(config, disp, io=io)
    mandatory_modules = ['discoverylistener']
    for mandatory in mandatory_modules:
        importlib.import_module(mandatory)
    #pylint is confused here...
    # pylint: disable=E1133
    for optional in config['optional_modules']:
        importlib.import_module(optional)
    if opt.doTrace:
        import trace
        tracer = trace.Trace(count=False, trace=True)
        if CMAdb.debug:
            CMAdb.log.debug('Starting up traced listener.listen(); debug=%d' %
                            opt.debug)
        if opt.foreground:
            print >> sys.stderr, (
                'cma: Starting up traced listener.listen() in foreground; debug=%d'
                % opt.debug)
        tracer.run('listener.listen()')
    else:
        if CMAdb.debug:
            CMAdb.log.debug(
                'Starting up untraced listener.listen(); debug=%d' % opt.debug)
        if opt.foreground:
            print >> sys.stderr, (
                'cma: Starting up untraced listener.listen() in foreground; debug=%d'
                % opt.debug)

        # This is kind of a kludge, we should really look again at
        # at initializition and so on.
        # This module *ought* to be optional.
        # that would involve adding some Drone callbacks for creation of new Drones
        BestPractices(config, io, CMAdb.store, CMAdb.log, opt.debug)
        listener.listen()
    return 0
예제 #13
0
def main():
    'Main program for the CMA (Collective Management Authority)'
    py2neo_major_version = int(PY2NEO_VERSION.partition('.')[0])
    if py2neo_major_version not in SUPPORTED_PY2NEO_VERSIONS:
        raise EnvironmentError('py2neo version %s not supported' % PY2NEO_VERSION)
    DefaultPort = 1984
    # VERY Linux-specific - but useful and apparently correct ;-)
    PrimaryIPcmd =   \
    "ip address show primary scope global | grep '^ *inet' | sed -e 's%^ *inet *%%' -e 's%/.*%%'"
    ipfd = os.popen(PrimaryIPcmd, 'r')
    OurAddrStr = ('%s:%d' % (ipfd.readline().rstrip(), DefaultPort))
    ipfd.close()

    parser = optparse.OptionParser(prog='CMA', version=AssimCtypes.VERSION_STRING,
        description='Collective Management Authority for the Assimilation System',
        usage='cma.py [--bind address:port]')

    parser.add_option('-b', '--bind', action='store', default=None, dest='bind'
    ,   metavar='address:port-to-bind-to'
    ,   help='Address:port to listen to - for nanoprobes to connect to')

    parser.add_option('-d', '--debug', action='store', default=0, dest='debug'
    ,   help='enable debug for CMA and libraries - value is debug level for C libraries.')

    parser.add_option('-s', '--status', action='store_true', default=False, dest='status'
    ,   help='Return status of running CMA')

    parser.add_option('-k', '--kill', action='store_true', default=False, dest='kill'
    ,   help='Shut down running CMA.')

    parser.add_option('-e', '--erasedb', action='store_true', default=False, dest='erasedb'
    ,   help='Erase Neo4J before starting')

    parser.add_option('-f', '--foreground', action='store_true', default=False, dest='foreground'
    ,   help='keep the CMA from going into the background')

    parser.add_option('-p', '--pidfile', action='store', default='/var/run/assimilation/cma'
    ,   dest='pidfile',   metavar='pidfile-pathname'
    ,   help='full pathname of where to locate our pid file')

    parser.add_option('-T', '--trace', action='store_true', default=False, dest='doTrace'
    ,   help='Trace CMA execution')

    parser.add_option('-u', '--user', action='store', default=CMAUSERID, dest='userid'
    ,   metavar='userid'
    ,   help='userid to run the CMA as')


    opt = parser.parse_args()[0]

    from AssimCtypes import daemonize_me, assimilation_openlog, are_we_already_running, \
        kill_pid_service, pidrunningstat_to_status, remove_pid_file, rmpid_and_exit_on_signal


    if opt.status:
        rc = pidrunningstat_to_status(are_we_already_running(opt.pidfile, None))
        return rc

    if opt.kill:
        if kill_pid_service(opt.pidfile, 15) < 0:
            print >> sys.stderr, "Unable to stop CMA."
            return 1
        return 0

    opt.debug = int(opt.debug)

    # This doesn't seem to work no matter where I invoke it...
    # But if we don't fork in daemonize_me() ('C' code), it works great...
#    def cleanup():
#        remove_pid_file(opt.pidfile)
#    atexit.register(cleanup)
#    signal.signal(signal.SIGTERM, lambda sig, stack: sys.exit(0))
#    signal.signal(signal.SIGINT, lambda sig, stack: sys.exit(0))

    from cmadb import CMAdb
    CMAdb.running_under_docker()
    make_pid_dir(opt.pidfile, opt.userid)
    make_key_dir(CRYPTKEYDIR, opt.userid)
    cryptwarnings = pyCryptCurve25519.initkeys()
    for warn in cryptwarnings:
        print >> sys.stderr, ("WARNING: %s" % warn)
    #print >> sys.stderr, 'All known key ids:'
    keyids = pyCryptFrame.get_key_ids()
    keyids.sort()
    for keyid in keyids:
        if not keyid.startswith(CMA_KEY_PREFIX):
            try:
                # @FIXME This is not an ideal way to associate identities with hosts
                # in a multi-tenant environment
                # @FIXME - don't think I need to do the associate_identity at all any more...
                hostname, notused_post = keyid.split('@@', 1)
                notused_post = notused_post
                pyCryptFrame.associate_identity(hostname, keyid)
            except ValueError:
                pass
        #print >> sys.stderr, '>    %s/%s' % (keyid, pyCryptFrame.get_identity(keyid))

    daemonize_me(opt.foreground, '/', opt.pidfile, 20)

    rmpid_and_exit_on_signal(opt.pidfile, signal.SIGTERM)


    # Next statement can't appear before daemonize_me() or bind() fails -- not quite sure why...
    assimilation_openlog("cma")
    from packetlistener import PacketListener
    from messagedispatcher import MessageDispatcher
    from dispatchtarget import DispatchTarget
    from monitoring import MonitoringRule
    from AssimCclasses import pyNetAddr, pySignFrame, pyReliableUDP, \
         pyPacketDecoder
    from AssimCtypes import CONFIGNAME_CMAINIT, CONFIGNAME_CMAADDR, CONFIGNAME_CMADISCOVER, \
        CONFIGNAME_CMAFAIL, CONFIGNAME_CMAPORT, CONFIGNAME_OUTSIG, CONFIGNAME_COMPRESSTYPE, \
        CONFIGNAME_COMPRESS, proj_class_incr_debug, LONG_LICENSE_STRING, MONRULEINSTALL_DIR


    if opt.debug:
        print >> sys.stderr, ('Setting debug to %s' % opt.debug)

    for debug in range(opt.debug):
        debug = debug
        print >> sys.stderr, ('Incrementing C-level debug by one.')
        proj_class_incr_debug(None)

    #   Input our monitoring rule templates
    #   They only exist in flat files and in memory - they aren't in the database
    MonitoringRule.load_tree(MONRULEINSTALL_DIR)
    print >> sys.stderr, ('Monitoring rules loaded from %s' % MONRULEINSTALL_DIR)

    execobserver_constraints = {
        'nodetype': ['Drone',
                     'IPaddrNode',
                     'MonitorAction',
                     'NICNode',
                     'ProcessNode',
                     'SystemNode',
                    ]
    }
    ForkExecObserver(constraints=execobserver_constraints, scriptdir=NOTIFICATION_SCRIPT_DIR)
    print >> sys.stderr, ('Fork/Event observer dispatching from %s' % NOTIFICATION_SCRIPT_DIR)


    if opt.bind is not None:
        OurAddrStr = opt.bind

    OurAddr = pyNetAddr(OurAddrStr)
    if OurAddr.port() == 0:
        OurAddr.setport(DefaultPort)

    try:
        configinfo = ConfigFile(filename=CMAINITFILE)
    except IOError:
        configinfo = ConfigFile()
    if opt.bind is not None:
        bindaddr = pyNetAddr(opt.bind)
        if bindaddr.port() == 0:
            bindaddr.setport(ConfigFile[CONFIGNAME_CMAPORT])
        configinfo[CONFIGNAME_CMAINIT] = bindaddr
    configinfo[CONFIGNAME_CMADISCOVER] = OurAddr
    configinfo[CONFIGNAME_CMAFAIL] = OurAddr
    configinfo[CONFIGNAME_CMAADDR] = OurAddr
    if (CONFIGNAME_COMPRESSTYPE in configinfo):
        configinfo[CONFIGNAME_COMPRESS]     \
        =   pyCompressFrame(compression_method=configinfo[CONFIGNAME_COMPRESSTYPE])
    configinfo[CONFIGNAME_OUTSIG] = pySignFrame(1)
    config = configinfo.complete_config()

    addr = config[CONFIGNAME_CMAINIT]
    # pylint is confused: addr is a pyNetAddr, not a pyConfigContext
    # pylint: disable=E1101
    if addr.port() == 0:
        addr.setport(DefaultPort)
    ourport = addr.port()
    for elem in (CONFIGNAME_CMAINIT, CONFIGNAME_CMAADDR
    ,           CONFIGNAME_CMADISCOVER, CONFIGNAME_CMAFAIL):
        if elem in config:
            config[elem] = pyNetAddr(str(config[elem]), port=ourport)
    io = pyReliableUDP(config, pyPacketDecoder())
    io.setrcvbufsize(10*1024*1024) # No harm in asking - it will get us the best we can get...
    io.setsendbufsize(1024*1024)   # Most of the traffic volume is inbound from discovery
    drop_privileges_permanently(opt.userid)
    try:
        cmainit.CMAinit(io, cleanoutdb=opt.erasedb, debug=(opt.debug > 0))
    except RuntimeError:
        remove_pid_file(opt.pidfile)
        raise
    for warn in cryptwarnings:
        CMAdb.log.warning(warn)
    if CMAdb.cdb.db.neo4j_version[0] not in SUPPORTED_NEO4J_VERSIONS:
        raise EnvironmentError('Neo4j version %s.%s.%s not supported'
                               % CMAdb.cdb.db.neo4j_version)
    CMAdb.log.info('Listening on: %s' % str(config[CONFIGNAME_CMAINIT]))
    CMAdb.log.info('Requesting return packets sent to: %s' % str(OurAddr))
    CMAdb.log.info('Socket input buffer size:  %d' % io.getrcvbufsize())
    CMAdb.log.info('Socket output buffer size: %d' % io.getsendbufsize())
    keyids = pyCryptFrame.get_key_ids()
    keyids.sort()
    for keyid in keyids:
        CMAdb.log.info('KeyId %s Identity %s' % (keyid, pyCryptFrame.get_identity(keyid)))
    if CMAdb.debug:
        CMAdb.log.debug('C-library Debug was set to %s' % opt.debug)
        CMAdb.log.debug('TheOneRing created - id = %s' % CMAdb.TheOneRing)
        CMAdb.log.debug('Config Object sent to nanoprobes: %s' % config)

    jvmfd = os.popen('java -version 2>&1')
    jvers = jvmfd.readline()
    jvmfd.close()
    disp = MessageDispatcher(DispatchTarget.dispatchtable)
    neovers = CMAdb.cdb.db.neo4j_version
    neoversstring = (('%s.%s.%s'if len(neovers) == 3 else '%s.%s.%s%s')
                     %   neovers[0:3])

    CMAdb.log.info('Starting CMA version %s - licensed under %s'
    %   (AssimCtypes.VERSION_STRING, LONG_LICENSE_STRING))
    CMAdb.log.info('Neo4j version %s // py2neo version %s // Python version %s // %s'
        % (('%s.%s.%s' % CMAdb.cdb.db.neo4j_version)
        ,   str(py2neo.__version__)
        ,   ('%s.%s.%s' % sys.version_info[0:3])
        ,   jvers))
    if opt.foreground:
        print >> sys.stderr, ('Starting CMA version %s - licensed under %s'
        %   (AssimCtypes.VERSION_STRING, LONG_LICENSE_STRING))
        print >> sys.stderr, ('Neo4j version %s // py2neo version %s // Python version %s // %s'
            % ( neoversstring
            ,   PY2NEO_VERSION
            ,   ('%s.%s.%s' % sys.version_info[0:3])
            ,   jvers))
    if len(neovers) > 3:
        CMAdb.log.warning('Neo4j version %s is beta code - results not guaranteed.'
                          % str(neovers))

    # Important to note that we don't want PacketListener to create its own 'io' object
    # or it will screw up the ReliableUDP protocol...
    listener = PacketListener(config, disp, io=io)
    mandatory_modules = [ 'discoverylistener' ]
    for mandatory in mandatory_modules:
        importlib.import_module(mandatory)
    #pylint is confused here...
    # pylint: disable=E1133
    for optional in config['optional_modules']:
        importlib.import_module(optional)
    if opt.doTrace:
        import trace
        tracer = trace.Trace(count=False, trace=True)
        if CMAdb.debug:
            CMAdb.log.debug(
            'Starting up traced listener.listen(); debug=%d' % opt.debug)
        if opt.foreground:
            print >> sys.stderr, (
            'cma: Starting up traced listener.listen() in foreground; debug=%d' % opt.debug)
        tracer.run('listener.listen()')
    else:
        if CMAdb.debug:
            CMAdb.log.debug(
            'Starting up untraced listener.listen(); debug=%d' % opt.debug)
        if opt.foreground:
            print >> sys.stderr, (
            'cma: Starting up untraced listener.listen() in foreground; debug=%d' % opt.debug)

        # This is kind of a kludge, we should really look again at
        # at initializition and so on.
        # This module *ought* to be optional.
        # that would involve adding some Drone callbacks for creation of new Drones
        BestPractices(config, io, CMAdb.store, CMAdb.log, opt.debug)
        listener.listen()
    return 0
예제 #14
0
    def test_automonitor_search_basic(self):
        AssimEvent.disable_all_observers()
        drone = FakeDrone({
                'data': {
                        'ocf': {
                            'assimilation/neo4j',
                        },
                        'lsb': {
                            'neo4j-service',
                        }
                    }
                })
        MonitoringRule.monitor_objects = {'service': {}, 'host':{}}
        ocf_string = '''{
        "class":        "ocf", "type":         "neo4j", "provider":     "assimilation",
        "classconfig": [
            [null,      "@basename()",          "java$"],
            [null,      "$argv[-1]",             "org\\.neo4j\\.server\\.Bootstrapper$"],
            ["PORT",    "$serviceport"],
            ["NEOHOME", "@argequals(-Dneo4j.home)", "/.*"]
        ]
        }'''
        MonitoringRule.ConstructFromString(ocf_string)
        lsb_string = '''{
        "class":        "lsb", "type":         "neo4j-service",
        "classconfig": [
            ["@basename()",    "java$"],
            ["$argv[-1]", "org\\.neo4j\\.server\\.Bootstrapper$"],
        ]
        }'''
        MonitoringRule.ConstructFromString(lsb_string)
        neoprocargs = ("/usr/bin/java", "-cp"
        , "/var/lib/neo4j/lib/concurrentlinkedhashmap-lru-1.3.1.jar:"
        "AND SO ON:"
        "/var/lib/neo4j/system/lib/slf4j-api-1.6.2.jar:"
        "/var/lib/neo4j/conf/", "-server", "-XX:"
        "+DisableExplicitGC"
        ,   "-Dneo4j.home=/var/lib/neo4j"
        ,   "-Dneo4j.instance=/var/lib/neo4j"
        ,   "-Dfile.encoding=UTF-8"
        ,   "org.neo4j.server.Bootstrapper")

        neonode = ProcessNode('global', 'foofred', 'fred', '/usr/bin/java', neoprocargs
        ,   'root', 'root', '/', roles=(CMAconsts.ROLE_server,))
        #neonode.serviceport=7474
        context = ExpressionContext((neonode, drone))
        first = MonitoringRule.findbestmatch(context)
        second = MonitoringRule.findbestmatch(context, False)
        list1 = MonitoringRule.findallmatches(context)
        neonode.serviceport=7474
        third = MonitoringRule.findbestmatch(context)
        list2 = MonitoringRule.findallmatches(context)

        # first should be the LSB instance
        self.assertEqual(first[1]['monitorclass'], 'lsb')
        self.assertEqual(first[0], MonitoringRule.LOWPRIOMATCH)
        # second should be the incomplete OCF instance
        self.assertEqual(second[1]['monitorclass'], 'ocf')
        self.assertEqual(second[0], MonitoringRule.PARTMATCH)
        # third should be the high priority OCF instance
        self.assertEqual(third[1]['monitorclass'], 'ocf')
        self.assertEqual(third[0], MonitoringRule.HIGHPRIOMATCH)
        # list1 should be the incomplete OCF and the complete LSB - in that order
        self.assertEqual(len(list1), 2)
        # They should come out sorted by monitorclass
        self.assertEqual(list1[0][0], MonitoringRule.LOWPRIOMATCH)
        self.assertEqual(list1[0][1]['monitorclass'], 'lsb')
        self.assertEqual(list1[1][0], MonitoringRule.PARTMATCH)
        self.assertEqual(list1[1][1]['monitorclass'], 'ocf')
        # third should be a complete OCF match
        # list2 should be the complete OCF and the complete OCF - in that order
        self.assertEqual(len(list2), 2)
        self.assertEqual(list2[0][0], MonitoringRule.LOWPRIOMATCH)
        self.assertEqual(list2[0][1]['monitorclass'], 'lsb')
        self.assertEqual(list2[1][0], MonitoringRule.HIGHPRIOMATCH)
        self.assertEqual(list2[1][1]['monitorclass'], 'ocf')
예제 #15
0
    def test_automonitor_functions(self):
        AssimEvent.disable_all_observers()
        MonitoringRule.monitor_objects = {'service': {}, 'host':{}}
        drone = FakeDrone({
                'data': {
                        'ocf': {
                            'assimilation/neo4j',
                        },
                        'lsb': {
                            'bacula',
                        },
                    }
                })
        ocf_string = '''{
        "class":        "ocf", "type":         "neo4j", "provider":     "assimilation",
        "classconfig": [
            ["classpath",   "@flagvalue(-cp)"],
            ["ipaddr",      "@serviceip($procinfo.listenaddrs)"],
            ["port",        "@serviceport()",   "[0-9]+$"]
        ]
        }'''
        ssh_json = '''{
          "exe": "/usr/sbin/sshd",
          "argv": [ "/usr/sbin/sshd", "-D" ],
          "uid": "root",
          "gid": "root",
          "cwd": "/",
          "listenaddrs": {
            "0.0.0.0:22": {
              "proto": "tcp",
              "addr": "0.0.0.0",
              "port": 22
            },
            ":::22": {
              "proto": "tcp6",
              "addr": "::",
              "port": 22
            }
          }
        }'''
        neo4j_json = '''{
          "exe": "/usr/lib/jvm/java-7-openjdk-amd64/jre/bin/java",
          "argv": [ "/usr/bin/java", "-cp", "/var/lib/neo4j/lib/concurrentlinkedhashmap-lru-1.3.1.jar: ...", "-server", "-XX:+DisableExplicitGC", "-Dorg.neo4j.server.properties=conf/neo4
    j-server.properties", "-Djava.util.logging.config.file=conf/logging.properties", "-Dlog4j.configuration=file:conf/log4j.properties", "-XX:
    +UseConcMarkSweepGC", "-XX:+CMSClassUnloadingEnabled", "-Dneo4j.home=/var/lib/neo4j", "-Dneo4j.instance=/var/lib/neo4j", "-Dfile.encoding=
    UTF-8", "org.neo4j.server.Bootstrapper" ],
          "uid": "neo4j",
          "gid": "neo4j",
          "cwd": "/var/lib/neo4j",
          "listenaddrs": {
            ":::1337": {
              "proto": "tcp6",
              "addr": "::",
              "port": 1337
            },
            ":::39185": {
              "proto": "tcp6",
              "addr": "::",
              "port": 39185
            }
          }
        }'''
        bacula_json = '''{
      "exe": "/usr/sbin/bacula-dir",
      "argv": [ "/usr/sbin/bacula-dir", "-c", "/etc/bacula/bacula-dir.conf", "-u", "bacula", "-g", "bacula" ],
      "uid": "bacula",
      "gid": "bacula",
      "cwd": "/",
      "listenaddrs": {
        "10.10.10.5:9101": {
          "proto": "tcp",
          "addr": "10.10.10.5",
          "port": 9101
        }
      }
    }'''
        MonitoringRule.ConstructFromString(ocf_string)
        neoargs = pyConfigContext(neo4j_json)['argv']
        testnode = ProcessNode('global', 'foofred', 'fred', '/usr/bin/java', neoargs
        ,   'root', 'root', '/', roles=(CMAconsts.ROLE_server,))

        testnode.procinfo = neo4j_json
        context = ExpressionContext((testnode, drone))
        (prio, match) = MonitoringRule.findbestmatch(context)
        self.assertEqual(prio, MonitoringRule.HIGHPRIOMATCH)
        self.assertEqual(match['arglist']['ipaddr'], '::1')
        self.assertEqual(match['arglist']['port'], '1337')

        testnode.procinfo = ssh_json
        context = ExpressionContext((testnode, drone))
        (prio, match) = MonitoringRule.findbestmatch(context)
        self.assertEqual(prio, MonitoringRule.HIGHPRIOMATCH)
        self.assertEqual(match['arglist']['port'], '22')
        self.assertEqual(match['arglist']['ipaddr'], '127.0.0.1')

        testnode.procinfo = bacula_json
        context = ExpressionContext((testnode, drone))
        (prio, match) = MonitoringRule.findbestmatch(context)
        self.assertEqual(prio, MonitoringRule.HIGHPRIOMATCH)
        self.assertEqual(match['arglist']['port'], '9101')
        self.assertEqual(match['arglist']['ipaddr'], '10.10.10.5')
예제 #16
0
 def processpkt(self, drone, unused_srcaddr, unused_jsonobj):
     '''Update the _agentcache when we get a new set of available agents'''
     unused_jsonobj = unused_jsonobj
     unused_srcaddr = unused_srcaddr
     MonitoringRule.compute_available_agents((self,))
예제 #17
0
    def test_automonitor_search_basic(self):
        drone = FakeDrone({
            'data': {
                'ocf': {
                    'assimilation/neo4j',
                },
                'lsb': {
                    'neo4j-service',
                }
            }
        })
        MonitoringRule.monitor_objects = {'service': {}, 'host': {}}
        ocf_string = '''{
        "class":        "ocf", "type":         "neo4j", "provider":     "assimilation",
        "classconfig": [
            [null,      "@basename()",          "java$"],
            [null,      "$argv[-1]",             "org\\.neo4j\\.server\\.Bootstrapper$"],
            ["PORT",    "$serviceport"],
            ["NEOHOME", "@argequals(-Dneo4j.home)", "/.*"]
        ]
        }'''
        MonitoringRule.ConstructFromString(ocf_string)
        lsb_string = '''{
        "class":        "lsb", "type":         "neo4j-service",
        "classconfig": [
            ["@basename()",    "java$"],
            ["$argv[-1]", "org\\.neo4j\\.server\\.Bootstrapper$"],
        ]
        }'''
        MonitoringRule.ConstructFromString(lsb_string)
        neoprocargs = (
            "/usr/bin/java", "-cp",
            "/var/lib/neo4j/lib/concurrentlinkedhashmap-lru-1.3.1.jar:"
            "AND SO ON:"
            "/var/lib/neo4j/system/lib/slf4j-api-1.6.2.jar:"
            "/var/lib/neo4j/conf/", "-server", "-XX:"
            "+DisableExplicitGC", "-Dneo4j.home=/var/lib/neo4j",
            "-Dneo4j.instance=/var/lib/neo4j", "-Dfile.encoding=UTF-8",
            "org.neo4j.server.Bootstrapper")

        neonode = ProcessNode('global',
                              'foofred',
                              'fred',
                              '/usr/bin/java',
                              neoprocargs,
                              'root',
                              'root',
                              '/',
                              roles=(CMAconsts.ROLE_server, ))
        #neonode.serviceport=7474
        context = ExpressionContext((neonode, drone))
        first = MonitoringRule.findbestmatch(context)
        second = MonitoringRule.findbestmatch(context, False)
        list1 = MonitoringRule.findallmatches(context)
        neonode.serviceport = 7474
        third = MonitoringRule.findbestmatch(context)
        list2 = MonitoringRule.findallmatches(context)

        # first should be the LSB instance
        self.assertEqual(first[1]['monitorclass'], 'lsb')
        self.assertEqual(first[0], MonitoringRule.LOWPRIOMATCH)
        # second should be the incomplete OCF instance
        self.assertEqual(second[1]['monitorclass'], 'ocf')
        self.assertEqual(second[0], MonitoringRule.PARTMATCH)
        # third should be the high priority OCF instance
        self.assertEqual(third[1]['monitorclass'], 'ocf')
        self.assertEqual(third[0], MonitoringRule.HIGHPRIOMATCH)
        # list1 should be the incomplete OCF and the complete LSB - in that order
        self.assertEqual(len(list1), 2)
        # They should come out sorted by monitorclass
        self.assertEqual(list1[0][0], MonitoringRule.LOWPRIOMATCH)
        self.assertEqual(list1[0][1]['monitorclass'], 'lsb')
        self.assertEqual(list1[1][0], MonitoringRule.PARTMATCH)
        self.assertEqual(list1[1][1]['monitorclass'], 'ocf')
        # third should be a complete OCF match
        # list2 should be the complete OCF and the complete OCF - in that order
        self.assertEqual(len(list2), 2)
        self.assertEqual(list2[0][0], MonitoringRule.LOWPRIOMATCH)
        self.assertEqual(list2[0][1]['monitorclass'], 'lsb')
        self.assertEqual(list2[1][0], MonitoringRule.HIGHPRIOMATCH)
        self.assertEqual(list2[1][1]['monitorclass'], 'ocf')
예제 #18
0
    def test_automonitor_functions(self):
        MonitoringRule.monitor_objects = {'service': {}, 'host': {}}
        drone = FakeDrone(
            {'data': {
                'ocf': {
                    'assimilation/neo4j',
                },
                'lsb': {
                    'bacula',
                },
            }})
        ocf_string = '''{
        "class":        "ocf", "type":         "neo4j", "provider":     "assimilation",
        "classconfig": [
            ["classpath",   "@flagvalue(-cp)"],
            ["ipaddr",      "@serviceip($JSON_procinfo.listenaddrs)"],
            ["port",        "@serviceport()",   "[0-9]+$"]
        ]
        }'''
        ssh_json = '''{
          "exe": "/usr/sbin/sshd",
          "argv": [ "/usr/sbin/sshd", "-D" ],
          "uid": "root",
          "gid": "root",
          "cwd": "/",
          "listenaddrs": {
            "0.0.0.0:22": {
              "proto": "tcp",
              "addr": "0.0.0.0",
              "port": 22
            },
            ":::22": {
              "proto": "tcp6",
              "addr": "::",
              "port": 22
            }
          }
        }'''
        neo4j_json = '''{
          "exe": "/usr/lib/jvm/java-7-openjdk-amd64/jre/bin/java",
          "argv": [ "/usr/bin/java", "-cp", "/var/lib/neo4j/lib/concurrentlinkedhashmap-lru-1.3.1.jar: ...", "-server", "-XX:+DisableExplicitGC", "-Dorg.neo4j.server.properties=conf/neo4
    j-server.properties", "-Djava.util.logging.config.file=conf/logging.properties", "-Dlog4j.configuration=file:conf/log4j.properties", "-XX:
    +UseConcMarkSweepGC", "-XX:+CMSClassUnloadingEnabled", "-Dneo4j.home=/var/lib/neo4j", "-Dneo4j.instance=/var/lib/neo4j", "-Dfile.encoding=
    UTF-8", "org.neo4j.server.Bootstrapper" ],
          "uid": "neo4j",
          "gid": "neo4j",
          "cwd": "/var/lib/neo4j",
          "listenaddrs": {
            ":::1337": {
              "proto": "tcp6",
              "addr": "::",
              "port": 1337
            },
            ":::39185": {
              "proto": "tcp6",
              "addr": "::",
              "port": 39185
            }
          }
        }'''
        bacula_json = '''{
      "exe": "/usr/sbin/bacula-dir",
      "argv": [ "/usr/sbin/bacula-dir", "-c", "/etc/bacula/bacula-dir.conf", "-u", "bacula", "-g", "bacula" ],
      "uid": "bacula",
      "gid": "bacula",
      "cwd": "/",
      "listenaddrs": {
        "10.10.10.5:9101": {
          "proto": "tcp",
          "addr": "10.10.10.5",
          "port": 9101
        }
      }
    }'''
        MonitoringRule.ConstructFromString(ocf_string)
        neoargs = pyConfigContext(neo4j_json)['argv']
        testnode = ProcessNode('global',
                               'foofred',
                               'fred',
                               '/usr/bin/java',
                               neoargs,
                               'root',
                               'root',
                               '/',
                               roles=(CMAconsts.ROLE_server, ))

        testnode.JSON_procinfo = neo4j_json
        context = ExpressionContext((testnode, drone))
        (prio, match) = MonitoringRule.findbestmatch(context)
        self.assertEqual(prio, MonitoringRule.HIGHPRIOMATCH)
        self.assertEqual(match['arglist']['ipaddr'], '::1')
        self.assertEqual(match['arglist']['port'], '1337')

        testnode.JSON_procinfo = ssh_json
        context = ExpressionContext((testnode, drone))
        (prio, match) = MonitoringRule.findbestmatch(context)
        self.assertEqual(prio, MonitoringRule.HIGHPRIOMATCH)
        self.assertEqual(match['arglist']['port'], '22')
        self.assertEqual(match['arglist']['ipaddr'], '127.0.0.1')

        testnode.JSON_procinfo = bacula_json
        context = ExpressionContext((testnode, drone))
        (prio, match) = MonitoringRule.findbestmatch(context)
        self.assertEqual(prio, MonitoringRule.HIGHPRIOMATCH)
        self.assertEqual(match['arglist']['port'], '9101')
        self.assertEqual(match['arglist']['ipaddr'], '10.10.10.5')