source: hwdetector/trunk/fuentes/valentin.install/usr/bin/valentin @ 6431

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

Loading information

  • Property svn:executable set to *
File size: 15.8 KB
Line 
1#!/usr/bin/env python
2import sys,os
3sys.path.insert(0,'/usr/lib/valentin/')
4import logging
5import hwdetector.utils.log as log
6import tarfile
7import datetime
8import time
9import tempfile
10import json
11import argparse
12import zlib
13import base64
14from ruleset import ruleset
15
16try:
17    import threading
18    import gi
19    gi.require_version('Gtk','3.0')
20    from gi.repository import Gtk,GObject
21    GObject.threads_init()
22except Exception as e:
23    log.error('Unable to import Gtk libraries')
24
25
26def run_in_debug():
27    gettrace=getattr(sys,'gettrace',None)
28    if gettrace is None:
29        return False
30    elif gettrace():
31        return True
32    else:
33        return None
34
35def indent_var(st=u'',var={},indent=0):
36    creturn=u'\n'
37    if indent==0:
38        creturn=creturn*2
39    indentation=u'\t'*indent
40    try:
41        if isinstance(var,dict):
42            for x in sorted(var.keys()):
43                if not (x.lower().startswith('helper') and indent==0):
44                    st += u'{}{}\n{}{}'.format(indentation,x,indent_var(var=var[x],indent=indent+1),creturn)
45        elif isinstance(var,list) or isinstance(var,tuple):
46            if len(var) == 2 and var[0] == '__gz__':
47                content=zlib.decompress(base64.b64decode(var[1])).decode('utf-8')
48                replaced = content.replace(u'\n',indentation+u'\n'+indentation)
49                st += u'{}{}'.format(indentation,replaced)
50            else:
51                if isinstance(var,tuple):
52                    st += u'{}{}'.format(indentation,var)
53                else:
54                    for x in sorted(var):
55                        st += u'{}\n'.format(indent_var(var=x,indent=indent+1))
56        elif isinstance(var,str):
57            try:
58                var = var.encode('utf-8')
59            except:
60                var = var.decode('utf-8')
61            replaced = var.replace(u'\n',indentation+u'\n'+indentation)
62            st += u'{}{}'.format(indentation,replaced)
63        elif isinstance(var,unicode):
64            replaced = var.replace(u'\n',indentation+u'\n'+indentation)
65            st += u'{}{}'.format(indentation,replaced)
66        elif isinstance(var,bool) or isinstance(var,int) or isinstance(var,float) or var == None:
67            st += u'{}{}'.format(indentation,var)
68        else:
69            raise Exception('Unknown type var')
70        return st
71    except Exception as e:
72        return u''
73
74def make_file(capabilities,*args,**kwargs):
75    try:
76        txt = json.dumps(capabilities,indent=4,separators=(',',':'),sort_keys=True)
77        name = tempfile.mkstemp()[1]
78        with open(name,'w') as f:
79            f.write(txt.encode('utf-8'))
80        return name
81    except Exception as e:
82        return False
83
84def make_tar(file,*args,**kwargs):
85    try:
86        datestr='{:%Y%m%d%H%M}'.format(datetime.datetime.now())
87        if kwargs['fname']:
88            filename = kwargs['fname']
89        else:
90            filename = 'valentin-info-{}.tar.gz'.format(datestr)
91
92        if os.path.exists(file):
93            with tarfile.open(filename,'w:gz') as f:
94                f.add(file,arcname='debug-info-{}.txt'.format(datestr),recursive=False)
95                logger_message_file='/tmp/valentin-debug-log-messages.txt'
96                if os.path.exists(logger_message_file):
97                    f.add(logger_message_file,arcname=os.path.basename(logger_message_file))
98            return filename
99    except Exception as e:
100        return False
101
102def run_detection(*args,**kwargs):
103    log.debug("Importing hwdetector")
104    import hwdetector
105
106    log.debug("Instantiate HwDetector")
107    hwd=hwdetector.HwDetector()
108
109    #hwd.all_plugins_are_needed=True
110    if not run_in_debug():
111        log.info('USING MAX_RUNNING_TIME !!!')
112        hwd.MAX_RUNNING_TIME = 30
113
114    #hwd.fake_capabilities={'IAMGOD':'yes'}
115
116    log.debug("Calling run plugins")
117    #ret = hwd.run(needs=['ALL_TESTS'])
118    #ret = hwd.run(needs=['LLXSYSTEM_TEST','LLXNETWORK_TEST'])
119    ret = hwd.run()
120
121    log.info("Total running time: {}".format(hwd.RUNNING_TIME))
122
123    return (ret,hwd.capabilities)
124
125def load_file(*args,**kwargs):
126    if kwargs.get('fname',None):
127        filename = kwargs['fname']
128    else:
129        return False
130    if os.path.exists(filename):
131        ftxt=None
132        if tarfile.is_tarfile(filename):
133            with tarfile.open(filename,'r:gz') as tar:
134                target_file=None
135
136                for tarinfo in tar.getmembers():
137                    if 'debug-info' in tarinfo.name.lower():
138                        target_file=tarinfo.name
139                        break
140                if target_file:
141                    ftxt = tar.extractfile(target_file).read()
142        else:
143            ftxt = None
144            with open(filename,'r') as f:
145                ftxt = f.read()
146        return ftxt
147    else:
148        return False
149
150def run_analysis(*args,**kwargs):
151
152    if kwargs.get('capabilities',None):
153        fileinfo = kwargs.get('capabilities')
154    if not kwargs.get('ruleset',None):
155        fileruleset='/usr/share/valentin/valentin.rules'
156        if not os.path.exists(fileruleset):
157            return False
158    else:
159        fileruleset=kwargs.get('ruleset')[0]
160
161    rs = ruleset()
162    try:
163        rs.load_ruleset(fileruleset=fileruleset,data=fileinfo)
164        rs.make_tree()
165        rs.make_suggestion()
166    except Exception as e:
167        log.error(e)
168
169    return True
170
171
172class Handler:
173    def __init__(self,gui):
174        self.gui = gui
175
176    def destroy(self,*args,**kwargs):
177        log.debug('Exitting gui')
178        sys.exit(0)
179
180    def key_clicked(self,tselection,tpath,tviewcolumn,*args,**kwargs):
181        model,lpaths=tselection.get_selected_rows()
182        id_selected=model[lpaths][0]
183        if self.gui.coldict[id_selected]['child']:
184            tview=tselection.get_tree_view()
185            for sel in lpaths:
186                if tview.row_expanded(sel):
187                    tview.collapse_row(sel)
188                else:
189                    tview.expand_row(sel,False)
190        else:
191            self.gui.showText(id_selected)
192
193class Gui:
194    def __init__(self,*args,**kwargs):
195        self.builder=None
196        self.handler = Handler(self)
197        self._load_glade(**kwargs)
198        self.buffer=Gtk.TextBuffer()
199        self.text='Loading...'
200        self.buffer.set_text(self.text)
201        self.textview=self.builder.get_object('textview1')
202        self.textview.set_buffer(self.buffer)
203        self.id=0
204        self.done=False
205        threading.Thread(target=self.updateText).start()
206        pass
207
208    def updateText(self,*args,**kwargs):
209        while not self.done:
210            time.sleep(0.3)
211            self.buffer.set_text('{} {}'.format(self.text,self.id))
212            self.textview.set_buffer(self.buffer)
213        self.buffer.set_text('')
214        self.textview.set_buffer(self.buffer)
215
216    def _store_data(self,data,id=[0]):
217        if not self.store:
218            return None
219        me=id[0]
220        self.id=me
221        if isinstance(data,dict):
222            for key in sorted(data.keys()):
223                if key.startswith('HELPER'):
224                    continue
225                id[0]+=1
226                id_child=id[0]
227                col=self.store.append(self.coldict[me]['col'],[id_child,key])
228                self.coldict[me]['child'].append(id_child)
229                self.coldict[id_child]={'parent':me,'col':col,'data':data[key],'me':id_child,'child':[]}
230                self._store_data(data=data[key],id=id)
231        elif isinstance(data,list):
232            if len(data) > 1:
233                if len(data)==2 and data[0] == '__gz__':
234                    self.coldict[me]['data']=zlib.decompress(base64.b64decode(data[1]))
235                    self._store_data(data=self.coldict[me]['data'],id=id)
236                else:
237                    for x in data:
238                        id[0]+=1
239                        id_child=id[0]
240                        col=self.store.append(self.coldict[me]['col'],[id_child,'[{}]'.format(str(data.index(x))).encode('utf-8').decode('utf-8')])
241                        self.coldict[me]['child'].append(id_child)
242                        self.coldict[id_child]={'parent':me,'col':col,'data':x,'me':id_child,'child':[]}
243                        self._store_data(data=x,id=id)
244            elif len(data) == 1:
245                self.coldict[me]['data']=data[0]
246                self._store_data(data=data[0],id=id)
247        elif isinstance(data,tuple):
248            self._store_data(data=list(data),id=id)
249            pass
250        elif isinstance(data,str):
251            try:
252                data=data.encode('utf-8').decode('utf-8')
253                self.coldict[me]['data']=data
254            except:
255                pass
256        elif isinstance(data,unicode):
257            try:
258                data.decode('utf-8')
259            except:
260                data=data.encode('utf-8').decode('utf-8')
261                self.coldict[me]['data']=data
262        else:
263            self._store_data(data=str(data).encode('utf-8').decode('utf-8'),id=id)
264
265        return True
266
267    def showData(self,data,*args,**kwargs):
268        self.treeview=self.builder.get_object('treeview1')
269        self.store=self.builder.get_object('treestore1')
270        self.storesort=self.builder.get_object('treemodelsort1')
271        self.storesort.set_sort_column_id(1,Gtk.SortType.ASCENDING)
272        self.coldict={0:{'parent':0,'col':None,'data':data,'me':0,'child':[]}}
273        self._store_data(data=data)
274        self.treeview.set_model(self.storesort)
275        self.done=True
276
277    def showText(self,id=0,*args,**kwargs):
278        if id == 0 or not isinstance(id,int):
279            self.buffer=''
280        else:
281            coldata=self.coldict[id]
282            self.buffer.set_text(str(coldata['data']))
283
284        self.textview.set_buffer(self.buffer)
285        return True
286
287    def _show_window(self,*args,**kwargs):
288        if not (self.builder):
289            return
290        self.mainwindow=self.builder.get_object('mainwindow')
291        self.builder.connect_signals(self.handler)
292        self.treeview=self.builder.get_object('treeview1')
293        self.treeview.set_model(Gtk.TreeStore(int,str))
294        self.mainwindow.show_all()
295        pass
296
297
298    def _load_glade(self,*args,**kwargs):
299        self.gladefile=kwargs.get('gladefile',None)
300        log.info('Loading glade file {}'.format(self.gladefile))
301        if self.gladefile and os.path.exists(self.gladefile):
302            try:
303                self.builder=Gtk.Builder()
304                self.builder.add_from_file(self.gladefile)
305                log.info('Loaded gladefile')
306                self._show_window()
307            except Exception as e:
308                log.error('Can\'t load gladefile')
309                self.builder=None
310        else:
311            log.error('can\'t find gladefile')
312            sys.exit(1)
313
314
315
316
317        pass
318if __name__ == '__main__':
319    try:
320        parser = argparse.ArgumentParser(description='Simple system diagnostic tool')
321        dlevels = ['debug','info','warning','error']
322        parser.add_argument('-d','--debug-level',metavar='debug|info|warning|error',nargs='?',choices=dlevels,help='Set the debug level (default: warning)')
323        parser.add_argument('-c','--coloured',action='store_const',help='Colorize logger messages',const=True)
324
325        parser.add_argument('-f','--with-file',metavar='filename',nargs='?',help='Filename for results file (default valentin-info-(date).tar.gz')
326        parser.add_argument('-o','--to-stdout',action='store_const',help='Output results to stdout',const=True)
327        parser.add_argument('-w','--to-stdout-raw',action='store_const',help='Output results to stdout in json format',const=True)
328        parser.add_argument('-g','--graphical-mode',action='store_const',help='Show results in graphical mode',const=True)
329
330        parser.add_argument('-a','--analyze-file',metavar='filename',nargs=1,help='Filename to analyze')
331        parser.add_argument('-x','--run-detection',action='store_const',help='Run detection',const=True)
332
333        parser.add_argument('-s','--suggest',action='store_const',help='Suggest actions to repair system',const=True)
334        parser.add_argument('-r','--ruleset',metavar='filename',nargs=1,help='Load ruleset when suggest user actions')
335        args = parser.parse_args()
336
337        if not args.debug_level:
338            #log.set_level(logging.WARNING)
339            log.disable()
340        else:
341            levels={'debug':logging.DEBUG,'info':logging.INFO,'warning':logging.WARNING,'error':logging.ERROR}
342            log.set_level(levels[args.debug_level.lower()])
343
344        if args.coloured:
345            log.set_color(True)
346
347        kw=vars(args)
348
349        fname=None
350        if args.with_file:
351            fname=args.with_file
352            if '.' not in fname:
353                fname = fname + '.tar.gz'
354            kw.update({'fname':fname})
355
356        if args.analyze_file:
357            fname=args.analyze_file[0]
358            kw.update({'fname':fname})
359            capabilities=load_file(**kw)
360            if capabilities:
361                capabilities = json.loads(capabilities)
362                ret = True
363                log.info("File {} loaded".format(fname))
364                kw.update({'capabilities':capabilities})
365            else:
366                log.error("File {} can't be loaded".format(fname))
367                ret = False
368        else:
369            if args.run_detection:
370                ret,capabilities=run_detection(**kw)
371                log.info('Detection done!')
372                if args.with_file:
373                    try:
374                        file = make_file(capabilities,**kw)
375                        fname = make_tar(file,**kw)
376                        log.info("File {} created".format(fname))
377                    except Exception as e:
378                        log.error("File creation unsuccessful "+str(e))
379
380                kw.update({'capabilities':capabilities})
381            else:
382                sys.stderr.write('Missing detection option\n')
383                ret = False
384
385        if ret:
386            if args.to_stdout or args.to_stdout_raw:
387                if args.to_stdout:
388                    pr=indent_var(var=capabilities)
389                elif args.to_stdout_raw:
390                    for x in (x for x in capabilities.keys() if x.lower().startswith('helper')):
391                        del capabilities[x]
392
393                    def clear_compressed(var):
394                        try:
395                            if isinstance(var,tuple) or isinstance(var,list):
396                                if len(var) == 2 and var[0]=='__gz__':
397                                    try:
398                                        var=zlib.decompress(base64.b64decode(var[1])).decode('utf-8')
399                                    except:
400                                        pass
401                                    return var
402                                var=list(var)
403                                for i in range(len(var)):
404                                    var[i]=clear_compressed(var[i])
405                            elif isinstance(var,dict):
406                                for x in var:
407                                    var[x]=clear_compressed(var[x])
408
409                            return var
410                        except Exception as e:
411                            log.error(e)
412
413                    capabilities=clear_compressed(capabilities)
414                    pr=json.dumps(capabilities,indent=4,separators=(',',':'),sort_keys=True)
415
416                sys.stdout.write(pr.encode('utf-8'))
417                sys.stderr.write('\n')
418            elif args.graphical_mode:
419                GObject.threads_init()
420                gui = Gui(gladefile=os.path.dirname(__file__)+'/../lib/valentin/varviewer.glade')
421                threading.Thread(target=gui.showData,args=(capabilities,)).start()
422                sys.exit(Gtk.main())
423
424            if args.suggest:
425                ret=run_analysis(**kw)
426
427
428        if ret:
429            log.info("Exit code = 0")
430            sys.exit(0)
431        else:
432            log.info("Exit code = 1")
433            sys.exit(1)
434
435    except Exception as e:
436        log.error("Exception occurred: {}".format(e))
437        log.error("Exit code = 1")
438        sys.exit(1)
439
Note: See TracBrowser for help on using the repository browser.