source: lliurex-statistics/trunk/fuentes/lliurex-statistics.install/usr/sbin/analytics @ 6929

Last change on this file since 6929 was 6929, checked in by mabarracus, 3 years ago

Fix bugs

  • Property svn:executable set to *
File size: 26.9 KB
Line 
1#!/usr/bin/env python3
2import sys
3import os
4import re
5import signal
6import time
7import subprocess
8import requests
9import json
10import configparser
11import daemon
12from xmlrpc import client
13import lockfile
14import logging.handlers
15from logging import config as cfg
16import ssl
17import psutil
18
19
20oldsignals = {}
21for sig in signal.Signals:
22    try:
23        oldsignals.setdefault(sig.name, signal.getsignal(sig))
24        signal.signal(sig.value, signal.SIG_IGN)
25    except:
26        continue
27
28#
29# START EDITABLE VARS (OVERRIDES VALUES IN CONFIGFILE)
30#
31
32# DEBUG = 1
33
34MODE = 'PROCEDURAL'
35# MODE = 'THREADED'
36
37CONFIGFILE = '/etc/lliurex-analytics/agent.cfg'
38# CONFIGFILE = 'config.txt'
39
40# OVERRIDE_SEND_PERMISSION   = 1
41
42# MIN_LOG_LEVEL = 'info'
43
44# DAEMON_MODE = 1
45
46# FILELOCK = '/tmp/analytics'
47
48# PIDFILE = '/var/run/analitics.pid'
49# PIDFILE = '/tmp/analitics.pid'
50
51# STATUSFILE = '/etc/lliurex-analytics/status'
52
53# TIMEOUT = 1
54
55#
56# END EDITABLE VARS #
57#
58
59
60if MODE == 'PROCEDURAL':
61    from multiprocessing import Process, Manager
62    str_formatter = '(%(processName)s)'
63if MODE == 'THREADED':
64    from multiprocessing.dummy import Process, Manager
65    str_formatter = '(%(threadName)s)'
66
67def get_var_value(varname, config=None, mode='string', section='Agent'):
68    value = None
69
70    if config:
71        varname = varname.lower()
72        try:
73            if mode == 'string':
74                value = config.get(section, varname)
75            elif mode == 'bool':
76                value = config.getboolean(section, varname)
77            elif mode == 'int':
78                value = config.getint(section, varname)
79            elif mode == 'float':
80                value = config.getfloat(section, varname)
81        except:
82            pass
83
84    def f(item):
85        if isinstance(item, str) or isinstance(item, bool) or isinstance(item, int) or isinstance(item, float):
86            return True
87        else:
88            return False
89
90    for x in (v for v in globals() if varname.lower() == v.lower() and f(globals()[v])):
91        value = globals()[x]
92
93    if mode == 'string':
94        return str(value)
95    elif mode == 'bool':
96        return bool(value)
97    elif mode == 'int':
98        return int(value)
99    elif mode == 'float':
100        return float(value)
101    else:
102        return value
103
104
105if get_var_value('DEBUG', mode='bool'):
106    loglevel = get_var_value('MIN_LOG_LEVEL')
107    if loglevel:
108        if loglevel == 'debug' or loglevel == logging.DEBUG:
109            loglevel = logging.DEBUG
110        elif loglevel == 'critical' or loglevel == logging.CRITICAL:
111            loglevel = logging.CRITICAL
112        elif loglevel == 'error' or loglevel == logging.ERROR:
113            loglevel = logging.ERROR
114        elif loglevel == 'warning' or loglevel == logging.WARNING:
115            loglevel = logging.WARNING
116        elif loglevel == 'info' or loglevel == logging.INFO:
117            loglevel = logging.INFO
118        else:
119            loglevel = logging.DEBUG
120    else:
121        loglevel = logging.DEBUG
122else:
123    loglevel = logging.INFO
124
125
126LOGGING = {
127    'version': 1,
128    'disable_existing_loggers': False,
129    'formatters': {
130        'verbose': {
131#            'format': '%(levelname)s %(module)s (%(pathname)s:%(lineno)d) ' + str_formatter  + ' %(message)s'
132            'format': '%(levelname)s %(module)s ' + str_formatter + ' %(message)s'
133        },
134    },
135    'handlers': {
136        'stdout': {
137            'class': 'logging.StreamHandler',
138            'stream': sys.stdout,
139            'formatter': 'verbose',
140        },
141        'sys-logger6': {
142            'class': 'logging.handlers.SysLogHandler',
143            'address': '/dev/log',
144            'facility': "local6",
145            'formatter': 'verbose',
146        },
147    },
148    'loggers': {
149        'analytics-logger': {
150            'handlers': ['sys-logger6', 'stdout'],
151            'level': loglevel,
152            'propagate': True,
153        },
154    }
155}
156
157
158cfg.dictConfig(LOGGING)
159log = logging.getLogger('analytics-logger')
160
161
162def print_config(config):
163    global log
164
165    for sect in config:
166        for key in config[sect]:
167            log.debug("Config Loaded: '{}' '{}' '{}'".format(sect, key, config[sect][key]))
168
169
170def init_config():
171
172    config = configparser.ConfigParser()
173    config.read(CONFIGFILE)
174
175    return config
176
177
178def init_logging(config):
179    global DEBUG, log
180
181    if get_var_value('DEBUG', config):
182        DEBUG = True
183        log.setLevel(loglevel)
184        print_config(config)
185
186
187def bin_to_ascii(value):
188    global log
189
190    try:
191        if isinstance(value, bytes):
192            return value.decode('utf-8')
193        else:
194            return value
195    except Exception as e:
196        log.error('Error bin_to_ascii {}'.format(e))
197        return value
198
199
200def get_llx_version():
201    global log
202
203    output = bin_to_ascii(subprocess.check_output(['bash','lliurex-version','-n']))
204    release = output[0:2].strip()
205    if release == '15':
206        use = ['lliurex-detect','-f']
207        output = bin_to_ascii(subprocess.check_output(use))
208    else:
209        use = ['bash','lliurex-version','-f']
210        output = bin_to_ascii(subprocess.check_output(use))
211    flavour = output.strip()
212    #log.info("Detected release:'{}' flavour:'{}'".format(release, flavour))
213    return release, flavour
214
215
216def detect_proxy():
217    global log
218
219    px = subprocess.Popen(["bash", "-c", "source /etc/profile && echo $http_proxy"], stdout=subprocess.PIPE)
220    proxy = bin_to_ascii(px.stdout.readline()).strip()
221    #log.info("Detected proxy: '{}'".format(proxy))
222    return proxy
223
224
225def daemonize(*args, **kwargs):
226    global glob, log, CONFIG
227
228    log.info('Running daemon mode...')
229    filelock = get_var_value('filelock', CONFIG)
230    if not filelock:
231        filelock = '/var/run/analytics'
232
233    try:
234        with daemon.DaemonContext(detach_process=True,
235                                  working_directory='/tmp',
236                                  umask=0o002,
237                                  pidfile=lockfile.FileLock(filelock),
238                                  files_preserve=[log.handlers[0].socket.fileno()]):
239            start(**kwargs)
240    except Exception as e:
241        log.critical("Error daemonizing {}".format(e))
242        sys.exit(1)
243
244
245def add_item(item,regexp):
246    global glob, log
247
248    log.debug('Request to add {}'.format(item))
249
250    parts_item = item.split(' ')
251
252    executable = None
253    for i in range(len(parts_item)):
254        executable = parts_item[i].strip()
255        if not re.match(regexp,executable):
256            log.debug('Skipping malformed executable {}'.format(executable))
257            executable = None
258            continue
259        if '/' in executable:
260            executable = executable.split('/')[-1]
261            log.debug('Trimming executable to {}'.format(executable))
262        if executable in glob['INTERPRETERS']:
263            log.debug('Trimming interpreter part {}'.format(executable))
264            executable = None
265            continue
266        else:
267            if executable in glob['BLACKLIST']:
268                log.debug('Skipping add due to blacklisted command {}'.format(executable))
269                return None
270            log.debug('Valid executable {}'.format(executable))
271            break
272
273    the_list = glob['LIST']
274    if executable:
275        if executable in the_list:
276            the_list[executable] = the_list[executable] + 1
277            log.debug('+++ Incrementing {} = {}'.format(executable, the_list[executable]))
278        else:
279            log.debug('*** Adding {} = 1'.format(executable, 1))
280            the_list[executable] = 1
281    glob['LIST'] = the_list
282
283def monitor():
284    global glob, log
285
286    log.info('Start monitor')
287    logfilename = get_var_value('file', glob['config'], section='Audit')
288
289    glob['BLACKLIST'] = get_var_value('blacklist', glob['config'], section='Audit')
290    glob['INTERPRETERS'] = get_var_value('interpreters', glob['config'], section='Audit')
291
292    try:
293        glob['INTERPRETERS'] = [x.strip() for x in glob['INTERPRETERS'].split(',')]
294    except Exception as e:
295        log.error('Malformed interpreters list ,{}'.format(e))
296        glob['INTERPRETERS'] = []
297        return None
298
299    try:
300        with open(glob['BLACKLIST'], 'r') as fp:
301            glob['BLACKLIST'] = [line.strip() for line in fp]
302    except Exception as e:
303        log.error('Unable to read blacklist from {} , {}'.format(glob['BLACKLIST'], e))
304        glob['BLACKLIST'] = []
305        return None
306
307    try:
308        if not (os.path.isfile(logfilename) and os.access(logfilename, os.R_OK)):
309            log.critical('File {} not readable'.format(logfilename))
310            glob['TERMINATE'] = True
311
312        fp = subprocess.Popen(['tail', '-F', logfilename], stdout=subprocess.PIPE, stderr=open(os.devnull, 'w'))
313    except Exception as e:
314        log.critical('Error initializing {} read, {}'.format(logfilename, e))
315        glob['TERMINATE'] = True
316        return None
317
318    try:
319        log.info('Starting monitoring {}'.format(logfilename))
320        regexp = re.compile('^[a-zA-Z][a-zA-Z0-9_.+\-]+$')
321        while not glob['TERMINATE']:
322            if fp.poll() is not None:
323                log.error('Dead subprocess monitoring {}'.format(logfilename))
324                fp = subprocess.Popen(['tail', '-F', logfilename], stdout=subprocess.PIPE, stderr=open(os.devnull, 'w'))
325            else:
326                line = bin_to_ascii(fp.stdout.readline()).strip()
327                if re.search('type=EXECVE', line):
328                    m = re.findall('a[0-9]+="([^"]+)"', line)
329                    if m:
330                        captured = ' '.join(m)
331                        add_item(captured,regexp)
332
333    except Exception as e:
334        if isinstance(e, ConnectionResetError):
335            log.info('Connection reset exitting monitor thread')
336            glob['TERMINATE'] = True
337            return
338        else:
339            log.error('Error reading file {}, {}'.format(logfilename, e))
340            glob['TERMINATE'] = True
341            return
342
343    log.info('Exitting monitor thread')
344    return
345
346def update_list():
347    global glob, log
348
349    log.info('Start update list')
350    try:
351        list_path = get_var_value('list_path', glob['config'], mode='string', section='Server')
352        server = get_var_value('server', glob['config'], mode='string', section='Server')
353        url = 'http://' + server + '/' + list_path
354        agent = glob['user_agent']
355        headers = {'user-agent': agent}
356    except Exception as e:
357        log.warning('Error gettting update list settings {}'.format(e))
358
359    log.debug('List path {}'.format(url))
360
361    tick = 1
362    timeout = 60 * 60 * 12
363    c = 10
364
365    while not glob['TERMINATE']:
366        time.sleep(tick)
367        if c > 0:
368            c = c - tick
369        else:
370            c = timeout
371
372            sent = False
373            rq = None
374
375            try:
376                if glob['use_proxy']:
377                    proxy_obj = dict()
378                    proxy_obj.setdefault('http', glob['proxy'])
379
380                    rq = requests.get(url, headers=headers, proxies=proxy_obj, timeout=5)
381                    sent = True
382                else:
383                    rq = requests.get(url, headers=headers, timeout=5)
384                    sent = True
385            except Exception as e:
386                log.warning('Error getting list from {}, {}'.format(url,e))
387
388            try:
389                blist = glob['BLACKLIST']
390            except Exception as e:
391                log.error('Error loading current blacklist on update_list, {}'.format(e))
392
393            try:
394                the_list = glob['LIST']
395            except Exception as e:
396                log.error('Error loading current applist on update_list, {}'.format(e))
397
398            if sent and rq:
399                result = rq.text
400                try:
401                    json_list = json.loads(result)
402                except Exception as e:
403                    log.warning('Wrong list received {}, {}'.format(result,e))
404                    continue
405
406                try:
407                    for item in json_list:
408                        if item not in blist:
409                            blist.append(item)
410                            log.info("Received item list '{}'".format(item))
411                        if item in the_list:
412                            del the_list[item]
413                            log.info("Removed item from list '{}'".format(item))
414                    glob['BLACKLIST'] = blist
415                    glob['LIST'] = the_list
416                except Exception as e:
417                    log.error('Error updating blacklist, {}'.format(e))
418            else:
419                log.warning('Unable to get list data')
420
421    log.info('Exitting update list thread')
422
423
424def timed_send():
425    global glob, log
426
427    log.debug('Start timed_send ')
428    try:
429        count = get_var_value('timeout', glob['config'], mode='int')
430        if count < 0:
431            log.warning('Not valid timeout value setting default 300')
432    except Exception as e:
433        log.warning('Unable to read timeout value defaulting to 300, {}'.format(e))
434        count = 300
435
436    log.info('Initialized timed send with value {} seconds'.format(count))
437    c = count
438    tick = 0.2
439    try:
440        while not glob['TERMINATE']:
441            while glob['PRINTING'] == True:
442                time.sleep(1)
443            time.sleep(tick)
444            if c > 0:
445                c = c - tick
446            else:
447                c = count
448                log.debug('Triggering timed send')
449                clean_and_send()
450
451    except Exception as e:
452        if isinstance(e, ConnectionResetError):
453            log.info('Connection reset exitting timer thread')
454        else:
455            log.error('Error with timed send, {}'.format(e))
456
457    log.info('Exitting timer thread')
458    return
459
460
461def start(*args, daemon_mode=False,release='Unknown',flavour='Unknown',proxy=False, **kwargs):
462    global THREADS, oldsignals, log, CONFIG, glob
463
464    log.info("Starting analytics")
465    log.info('Initialization with release={} flavour={} proxy={}'.format(release,flavour,proxy))
466   
467    mgr = Manager()
468    glob = mgr.dict()
469
470    glob['DAEMON_MODE'] = daemon_mode
471    glob['config'] = CONFIG
472
473    glob['release'] = release
474    glob['flavour'] = flavour
475    if proxy:
476        glob['proxy'] = proxy
477        glob['use_proxy'] = True
478    else:
479        glob['proxy'] = False
480        glob['use_proxy'] = False
481
482    pidfile = get_var_value('pidfile', glob['config'])
483
484    try:
485        server = get_var_value('server', glob['config'], section='Server')
486        server_path = get_var_value('server-path', glob['config'], section='Server')
487        if server.strip() == '' or server_path.strip() == '':
488            raise Exception('Empty server or server-path')
489        glob['server'] = server
490        glob['server_path'] = server_path
491    except Exception as e:
492        log.critical('Error getting server url, {}'.format(e))
493
494    try:
495        agent = get_var_value('user-agent', glob['config'])
496        if agent.strip() == '' or agent == 'None':
497            agent = 'lliurex-analytics-agent'
498        glob['user_agent'] = agent
499    except Exception as e:
500        log.warning('Error getting user-agent, {}'.format(e))
501
502    # write pid
503    try:
504        with open(pidfile, 'w') as fp:
505            fp.write(str(os.getpid()))
506    except Exception as e:
507        log.error('Error writting pidfile {}'.format(e))
508
509    glob['TERMINATE'] = False
510    glob['PRINTING'] = False
511    glob['LIST'] = {}
512
513    glob['platform_data'] = get_platform_data()
514
515    THREADS = dict()
516    THREADS['monitor'] = Process(target=monitor, name='monitor')
517    THREADS['monitor'].daemon = glob['DAEMON_MODE']
518
519    THREADS['timed_send'] = Process(target=timed_send, name='timed_send')
520    THREADS['timed_send'].daemon = glob['DAEMON_MODE']
521
522    THREADS['update_list'] = Process(target=update_list, name='update_list')
523    THREADS['update_list'].daemon = glob['DAEMON_MODE']
524
525    THREADS['monitor'].start()
526    THREADS['timed_send'].start()
527    THREADS['update_list'].start()
528
529    signals = {'SIGTERM': interrupt, 'SIGINT': interrupt, 'SIGUSR1': clean_and_send, 'SIGUSR2': show_captured}
530    for sig in oldsignals:
531        if sig in signals:
532            signal.signal(signal.__dict__[sig], signals[sig])
533        else:
534            try:
535                signal.signal(signal.__dict__[sig], oldsignals[sig])
536            except:
537                continue
538
539
540def clean_and_send(*args, **kwargs):
541    global glob, log
542
543    override_send_permission = get_var_value('override_send_permission', glob['config'], mode='bool')
544
545    if allow_send() or override_send_permission:
546        send_data(glob['LIST'])
547    else:
548        log.info('Sending not allowed when try to send results')
549    glob['LIST'] = {}
550
551
552def get_mac():
553    global log
554
555    dirmac = '/sys/class/net'
556    eth = 'eth0'
557    filemac = 'address'
558    file = '{}/{}/{}'.format(dirmac, eth, filemac)
559    uid = None
560    try:
561        with open(file, 'r') as fp:
562            uid = bin_to_ascii(fp.read()).strip()
563    except:
564        log.warning('Unable to read {}'.format(file))
565        eth = sorted(os.listdir(dirmac))
566        if len(eth) > 0:
567            eth = eth[0]
568        file = '{}/{}/{}'.format(dirmac, eth, filemac)
569        try:
570            with open(file, 'r') as fp:
571                uid = bin_to_ascii(fp.read()).strip()
572        except Exception as e:
573            log.error('Unable to read mac address, {}'.format(e))
574
575    return str(uid)
576
577
578def get_cpu():
579    global log
580
581    file = '/proc/cpuinfo'
582    cpu = {}
583    try:
584        with open(file, 'r') as fp:
585            for line in fp:
586                if re.search('^processor\s+:\s+([0-9]+)$', line):
587                    m = re.findall('^processor\s+:\s+([0-9]+)', line)
588                    if m and len(m) > 0:
589                        cpu['ncpus'] = int(m[0]) + 1
590                if re.search('^model name\s+:\s+(.+)$', line):
591                    m = re.findall('^model name\s+:\s+(.+)$', line)
592                    if m and len(m) > 0:
593                        cpu['model'] = str(m[0])
594    except Exception as e:
595        log.warning('Unable to read cpuinfo, {}'.format(e))
596        cpu = None
597    return cpu
598
599
600def get_mem():
601    global log
602
603    file = '/proc/meminfo'
604    mem = None
605
606    try:
607        with open(file, 'r') as fp:
608            for line in fp:
609                if re.search('^MemTotal:\s+([0-9]+)\s+\S+$', line):
610                    m = re.findall('^MemTotal:\s+([0-9]+)\s+\S+$', line)
611                    if m and len(m) > 0:
612                        mem = int(m[0])
613                        break
614    except Exception as e:
615        log.warning('Unable to read meminfo, {}'.format(e))
616        mem = None
617    return str(mem)
618
619
620def get_vga():
621    global log
622
623    vga = None
624    try:
625        out = bin_to_ascii(subprocess.check_output(['lspci'])).split('\n')
626        for line in out:
627            line_strip = line.strip()
628            if re.search('VGA', line_strip, re.IGNORECASE):
629                m = re.findall('^\S+\s(.+)$', line_strip)
630                if m and len(m) > 0:
631                    vga = m[0]
632                    break
633    except Exception as e:
634        log.warning('Unable to read pciinfo, {}'.format(e))
635        vga = None
636    return str(vga)
637
638
639def get_arch():
640    global log
641
642    arch = None
643    try:
644        arch = bin_to_ascii(subprocess.check_output(['uname', '-m'])).strip()
645    except Exception as e:
646        log.warning('Unable to read architecture, {}'.format(e))
647        arch = None
648    return str(arch)
649
650
651def get_platform_data():
652    global log
653
654    data = {}
655    data.setdefault('mac', get_mac())
656    data.setdefault('cpu', get_cpu())
657    data.setdefault('mem', get_mem())
658    data.setdefault('vga', get_vga())
659    data.setdefault('arch', get_arch())
660
661    log.debug("Detected mac='{}' arch='{}' cpu='{}' mem='{}' vga='{}'".format(data['mac'], data['arch'], data['cpu'], data['mem'], data['vga']))
662    return data
663
664
665def send_data(data):
666    global log, glob
667
668    log.debug('sending specs {}'.format(glob['platform_data']))
669    log.debug('sending data {}'.format(glob['LIST']))
670
671    agent = glob['user_agent']
672    url = 'http://' + glob['server'] + '/' + glob['server_path']
673    headers = {'user-agent': agent}
674
675    version = glob['release']
676    flavour = glob['flavour']
677
678    list_data = data
679    try:
680        json_list_data = json.dumps(list_data)
681    except Exception as e:
682        log.error('Json error on internal data list')
683        return None
684
685    platform_data = glob['platform_data']
686    uid = platform_data['mac']
687
688    data_to_send = dict()
689    data_to_send.setdefault('uid', uid)
690    data_to_send.setdefault('vers', version)
691    data_to_send.setdefault('sab', flavour)
692    data_to_send.setdefault('specs', platform_data)
693    data_to_send.setdefault('stats', json_list_data)
694
695    try:
696        json_data_to_send = json.dumps(data_to_send)
697    except Exception as e:
698        log.error('Json error on data to send')
699        return None
700
701    payload = {'stats': json_data_to_send}
702    log.debug('Payload to send: {}'.format(payload))
703
704    sent = False
705    rq = None
706    if glob['use_proxy']:
707        proxy_obj = dict()
708        proxy_obj.setdefault('http', glob['proxy'])
709        try:
710            rq = requests.post(url, data=payload, headers=headers, proxies=proxy_obj, timeout=5)
711            sent = True
712        except Exception as e:
713            log.error('Error sending data through proxy, {}'.format(e))
714
715    if not glob['use_proxy'] or sent == False:
716        try:
717            rq = requests.post(url, data=payload, headers=headers, timeout=5)
718            sent = True
719        except Exception as e:
720            log.error('Error sending data, {}'.format(e))
721
722    if sent and rq:
723        result = rq.text
724        result = result.strip().lower()
725        if result == 'ok':
726            log.debug('Sending was success with reply OK ')
727        elif result == 'nok':
728            log.info('Sending was success but reply is NOK ')
729        else:
730            log.warning("Sending was success but reply is unknown '{}'".format(result))
731    else:
732        log.warning('Unable to send data')
733
734
735def interrupt(*args, **kwargs):
736    global glob, log, THREADS
737
738    log.info('Interrupting analytics')
739    try:
740        clean_and_send()
741        try:
742            glob['TERMINATE'] = True
743        except:
744            log.error('Requested kill the program')
745            sys.exit(1)
746        for x in THREADS:
747            THREADS[x].join()
748
749    except Exception as e:
750        log.error('Error while interrupting, {}'.format(e))
751
752
753def show_captured(*args, **kwargs):
754    global glob, log
755
756    glob['PRINTING'] = True
757    log.info('Requested to show list')
758
759    list_items = glob['LIST']
760    if not isinstance(list_items, dict):
761        log.warning('Error showing captured items, LIST is not a dictionary')
762
763    listkeys_sorted = sorted(list_items, key=list_items.get, reverse=True)
764
765    if len(listkeys_sorted) > 0:
766        log.info('analytics is showing currently capture list in memory')
767        for i in listkeys_sorted:
768            log.info('{} = {}'.format(i, list_items.get(i)))
769    else:
770        log.info('analytics detect an empty capture list in memory')
771
772    glob['PRINTING'] = False
773
774
775def check_server_acknowledge():
776    global log
777
778    try:
779        c = client.ServerProxy("https://server:9779/",
780                               verbose=False,
781                               use_datetime=True,
782                               context=ssl._create_unverified_context())
783        return c.get_variable("", "VariablesManager", "STATS_ENABLED")
784    except Exception as e:
785        log.error('Error getting variables, {}'.format(e))
786        return None
787
788
789def check_local_acknowledge():
790    global glob, log
791
792    if glob['TERMINATE']:
793        return None
794
795    try:
796        statusfile = get_var_value('statusfile', glob['config'])
797        if str(statusfile) == 'None':
798            statusfile = '/etc/lliurex-analytics/status'
799            log.warning('Warning statusfile not set, defaulting to {}'.format(statusfile))
800    except Exception as e:
801        log.error('Error getting value for statusfile, {}'.format(e))
802
803    answer = None
804    try:
805
806        if os.path.isfile(statusfile):
807            fp = open(statusfile, 'r')
808            answer = fp.readline()
809            fp.close()
810        else:
811            log.error('wrong statusfile {}'.format(statusfile))
812            return None
813
814        return answer.strip()
815    except Exception as e:
816        log.warning('Error reading status file, {}'.format(e))
817        return None
818
819
820def allow_send():
821    global glob, log
822
823    if glob['TERMINATE']:
824        return False
825
826    if glob['flavour'].lower() == 'server':
827        answer = str(check_server_acknowledge())
828        answer = answer.strip()
829        if answer == '1':
830            log.info('Allowed to send stats checking server acknowledge')
831            return True
832        elif answer == '0':
833            log.info('Denied to send stats checking server acknowledge')
834            return False
835        elif answer == 'None':
836            pass
837        else:
838            log.info('Unknown value checking server acknowledge, {}'.format(answer))
839    answer = str(check_local_acknowledge()).lower()
840    answer = answer.strip()
841    if answer == 'yes':
842        log.info('Allowed to send stats checking local acknowledge')
843        return True
844    elif answer == 'no':
845        log.info('Denied to send stats checking local acknowledge')
846        return False
847    elif answer == '':
848        pass
849    else:
850        log.info('Unknown value checking local acknowledge, {}'.format(answer))
851
852    log.info('Denied to send stats by default')
853    return False
854
855
856if __name__ == '__main__':
857    exit = 0
858    keyword='analytics'
859    interpreter='python3'
860    for proc in psutil.process_iter():
861        a=False
862        b=False
863        for argument in proc.cmdline:
864            #print('{} {} {}'.format(proc.cmdline,keyword,argument[-len(keyword):]))
865            if interpreter in argument[-len(interpreter):]:
866                a = True
867            if keyword in argument[-len(keyword):]:
868                b = True
869            if a and b:
870                exit = exit +1
871    if exit > 1:
872        log.error('Another daemon is running')
873        sys.exit(1)
874
875    try:
876        CONFIG = init_config()
877    except Exception as e:
878        print('Error initializing config analytics {}'.format(e), file=sys.stderr)
879        sys.exit(1)
880    try:
881        init_logging(CONFIG)
882    except Exception as e:
883        print('Error initializing logging analytics {}'.format(e), file=sys.stderr)
884        sys.exit(1)
885
886    THREADS = {}
887
888    try:
889        release, flavour = get_llx_version()
890    except Exception as e:
891        log.error('Error getting llx version {}'.format(e))
892        release = 'Unknown'
893        flavour = 'Unknown'
894
895    proxy = ''
896    try:
897        proxy = detect_proxy()
898        if proxy == '':
899            #log.info('Not using proxy')
900            proxy = False
901    except Exception as e:
902        log.warning('Error detecting proxy {}'.format(e))
903        proxy = False
904
905    DAEMON_MODE = get_var_value('DAEMON_MODE', CONFIG, 'bool')
906
907    if DAEMON_MODE:
908        daemonize(daemon_mode=True,flavour=flavour,release=release,proxy=proxy)
909    else:
910        start(daemon_mode=False,flavour=flavour,release=release,proxy=proxy)
911
912    log.debug('End main')
913    ended = False
914    while not ended:
915        for t in THREADS:
916            THREADS[t].join()
917            if THREADS[t].is_alive():
918                ended = False
919                break
920            else:
921                ended = True
922                continue
923
924    log.info('Exitting analytics')
925    sys.exit(0)
Note: See TracBrowser for help on using the repository browser.