OpenSecurity/bin/ui/configure_dialog.py
author BarthaM@N3SIM1218.D03.arc.local
Fri, 05 Sep 2014 12:28:30 +0100
changeset 221 853af9cfab6a
parent 220 f5805ee62d80
child 240 d7ef04254e9c
permissions -rwxr-xr-x
Integrated import script (rewritten in python) into opensecurity/vmmanager.py
Improoved user feedback upon import and update as well as logging.
Reduced system shutdown times and ui response times
Improoved the decoupling between UI and OSec subsystem.
Various other fixes
     1 #!/bin/env python
     2 # -*- coding: utf-8 -*-
     3 
     4 # ------------------------------------------------------------
     5 # configure_dialog.pyw
     6 # 
     7 # let the user configure the opensecurity system
     8 #
     9 # Autor: Oliver Maurhart, <oliver.maurhart@ait.ac.at>
    10 #
    11 # Copyright (C) 2014 AIT Austrian Institute of Technology
    12 # AIT Austrian Institute of Technology GmbH
    13 # Donau-City-Strasse 1 | 1220 Vienna | Austria
    14 # http://www.ait.ac.at
    15 #
    16 # This program is free software; you can redistribute it and/or
    17 # modify it under the terms of the GNU General Public License
    18 # as published by the Free Software Foundation version 2.
    19 # 
    20 # This program is distributed in the hope that it will be useful,
    21 # but WITHOUT ANY WARRANTY; without even the implied warranty of
    22 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    23 # GNU General Public License for more details.
    24 # 
    25 # You should have received a copy of the GNU General Public License
    26 # along with this program; if not, write to the Free Software
    27 # Foundation, Inc., 51 Franklin Street, Fifth Floor, 
    28 # Boston, MA  02110-1301, USA.
    29 # ------------------------------------------------------------
    30 
    31 
    32 # ------------------------------------------------------------
    33 # for the record:
    34 #
    35 #   This script uses a QTimer (in a busy loop) for checking
    36 #   changes to the log file watched.
    37 #
    38 #   Yes, this is sure f--g ugly.
    39 #
    40 #   Thing is: there is no real good cross-platform in
    41 #   doing this nicely. And here we solve this problem
    42 #   neither. See doc in update_progress method.
    43 #
    44 #   There is no python native but external packages
    45 #   using pip with different qualities (and struggling).
    46 #
    47 #   Qt and as such PyQt offer the QFileSystemWatcher class
    48 #   which *could* solve this isse but
    49 #
    50 #       a) this class is somehow buggy and unstable
    51 #       b) deprecated as of Qt 5.1
    52 #
    53 #   ... and this ain't a beauty contest either, is it?
    54 # ------------------------------------------------------------
    55 
    56 
    57 # ------------------------------------------------------------
    58 # imports
    59 
    60 import json
    61 import os
    62 import subprocess
    63 import sys
    64 import urllib2
    65 
    66 from PyQt4 import QtCore
    67 from PyQt4 import QtGui
    68 
    69 from ui_ConfigureDialog import Ui_ConfigureDialog 
    70 from about_dialog import AboutDialog
    71 
    72 
    73 # ------------------------------------------------------------
    74 # code
    75 
    76 
    77 class ConfigureDialog(QtGui.QDialog):
    78 
    79     """A dialog which lets the user configure the OpenSecurity Subsystem"""
    80 
    81     def __init__(self):
    82 
    83         QtGui.QDialog.__init__(self)
    84 
    85         # setup the user interface
    86         self.ui = Ui_ConfigureDialog()
    87         self.ui.setupUi(self)
    88 
    89         # monospace font fix for windows systems
    90         font = QtGui.QFont("Monospace [Courier]")
    91         font.setPointSize(8);
    92         font.setStyleHint(QtGui.QFont.TypeWriter)
    93         font.setStyleStrategy(QtGui.QFont.PreferAntialias)
    94         self.ui.edtProgress.setFont(font)
    95         self.ui.edtLog.setFont(font)
    96     
    97         self.ui.edtStatus.setText('<not evaluated yet>')
    98         self.ui.edtVersion.setText('<not evaluated yet>')
    99         self.ui.edtStatus.setEnabled(False);
   100         self.ui.edtVersion.setEnabled(False);
   101 
   102         # local members
   103         self._about_dialog = AboutDialog()
   104         self._file_watched_name = ''
   105         self._file_watched_size = 0
   106         self._file_watcher = QtCore.QTimer(self)
   107         self._service_log_file = ''
   108         self._service_log_size = 0
   109 
   110         # connectors
   111         self.ui.btnAbout.clicked.connect(self.clicked_about)
   112         self.ui.btnClose.clicked.connect(self.accept)
   113         self.ui.btnDownload.clicked.connect(self.clicked_download)
   114         self.ui.btnExplorer.clicked.connect(self.clicked_explorer)
   115         self.ui.btnImport.clicked.connect(self.clicked_import)
   116         self.ui.btnUpdate.clicked.connect(self.clicked_update)
   117         self.ui.btnRefresh.clicked.connect(self.clicked_refresh)
   118         self._file_watcher.timeout.connect(self.update_progress)
   119 
   120         # call first refresh immediately
   121         QtCore.QTimer.singleShot(0, self.clicked_refresh)
   122         self._file_watcher.start(100)
   123 
   124 
   125     def clicked_about(self):
   126 
   127         """About button has been clicked."""
   128         self._about_dialog.exec_()
   129 
   130 
   131     def clicked_download(self):
   132 
   133         """Download button has been clicked."""
   134 
   135         # remove old stuff
   136         self._file_watched_name = ''
   137         self._file_watched_size = 0
   138         self.ui.edtProgress.clear()
   139 
   140         try:
   141 
   142             # get general server info
   143             j = json.load(urllib2.urlopen('http://127.0.0.1:8080/fetch_initial_image'))
   144             self._file_watched_name = str(j['fetch_log'])
   145 
   146         except:
   147             pass
   148 
   149 
   150     def clicked_explorer(self):
   151 
   152         """Explorer button has been clicked."""
   153         if sys.platform == 'win32' or sys.platform == 'cygwin':
   154             subprocess.Popen([os.path.join(os.environ['WINDIR'], 'explorer.exe'), self._service_log_path])
   155 
   156 
   157     def clicked_import(self):
   158 
   159         """Import button has been clicked."""
   160 
   161         # remove old stuff
   162         self._file_watched_name = ''
   163         self._file_watched_size = 0
   164         self.ui.edtProgress.clear()
   165 
   166         try:
   167             j = json.load(urllib2.urlopen('http://127.0.0.1:8080/init'))
   168             self._file_watched_name = str(j['init_log'])
   169         except:
   170             pass
   171     
   172     
   173     def clicked_update(self):
   174 
   175         """Update button has been clicked."""
   176 
   177         # remove old stuff
   178         self._file_watched_name = ''
   179         self._file_watched_size = 0
   180         self.ui.edtProgress.clear()
   181 
   182         try:
   183             j = json.load(urllib2.urlopen('http://127.0.0.1:8080/update_template'))
   184             self._file_watched_name = str(j['init_log'])
   185         except:
   186             pass
   187 
   188 
   189     def clicked_refresh(self):
   190 
   191         """Refresh button has been clicked."""
   192         self.ui.edtStatus.setText('<not evaluated yet>')
   193         self.ui.edtVersion.setText('<not evaluated yet>')
   194         self.ui.edtStatus.setEnabled(False);
   195         self.ui.edtVersion.setEnabled(False);
   196         self.ui.tvTemplate.clear()
   197 
   198         try:
   199 
   200             # get general server info
   201             j = json.load(urllib2.urlopen('http://127.0.0.1:8080'))
   202             self.ui.edtStatus.setText(j['os_server']['status message'])
   203             self.ui.edtStatus.setEnabled(True)
   204             self.ui.edtVersion.setText(j['os_server']['version'])
   205             self.ui.edtVersion.setEnabled(True)
   206             self._service_log_path = j['os_server']['current log folder']
   207             self._service_log_file = os.path.join(self._service_log_path, 'OpenSecurity.log')
   208             self._service_log_size = 0
   209 
   210             # get initial template info
   211             j = json.load(urllib2.urlopen('http://127.0.0.1:8080/initial_image'))
   212             i = QtGui.QTreeWidgetItem(self.ui.tvTemplate)
   213             i.setText(0, j['initial_template']['name'])
   214             i.setText(1, QtCore.QDateTime.fromTime_t(int(j['initial_template']['date'])).toString(QtCore.Qt.SystemLocaleShortDate))
   215             i.setText(2, str(j['initial_template']['size']))
   216             i.setText(3, j['initial_template']['path'])
   217             
   218         except:
   219             pass
   220 
   221         # trigger machine update
   222         self.update_machines()
   223 
   224 
   225     def update_machines(self):
   226 
   227         """Update the machines view"""
   228         self.ui.tvMachines.clear()
   229         self._icon_machine = QtGui.QIcon()
   230         self._icon_machine.addPixmap(QtGui.QPixmap(":/opensecurity/gfx/cpu.png"), QtGui.QIcon.Normal, QtGui.QIcon.Off)
   231         self._icon_property = QtGui.QIcon()
   232         self._icon_property.addPixmap(QtGui.QPixmap(":/opensecurity/gfx/configure.png"), QtGui.QIcon.Normal, QtGui.QIcon.Off)
   233         self._icon_network = QtGui.QIcon()
   234         self._icon_network.addPixmap(QtGui.QPixmap(":/opensecurity/gfx/network-workgroup.png"), QtGui.QIcon.Normal, QtGui.QIcon.Off)
   235 
   236         try:
   237 
   238             # get machines
   239             machines = json.load(urllib2.urlopen('http://127.0.0.1:8080/sdvms'))
   240             for m in machines:
   241                 i = QtGui.QTreeWidgetItem(self.ui.tvMachines)
   242                 i.setIcon(0, self._icon_machine)
   243                 i.setText(0, m)
   244                 i.setIcon(1, self._icon_network)
   245                 i.setText(1, machines[m])
   246 
   247 
   248                 properties = json.load(urllib2.urlopen('http://127.0.0.1:8080/sdvms/' + m))
   249                 for p in properties:
   250                     j = QtGui.QTreeWidgetItem(i)
   251                     j.setIcon(0, self._icon_property)
   252                     j.setText(0, p)
   253                     j.setText(1, properties[p])
   254 
   255                 j.setIcon(0, self._icon_network)
   256                 j.setText(0, 'ip')
   257                 j.setText(1, machines[m])
   258 
   259 
   260         except:
   261             pass
   262 
   263 
   264 
   265     def update_progress(self):
   266         
   267         """Our log file has changed, update ui"""
   268 
   269         # we could use os.stat(PATH).st_mtime ...
   270         # 
   271         # ... but Windows does not update it frequently. -.- 
   272         #
   273         # Running a Cygwin Bash Shell script in the background
   274         # does not update mtime of the redirected stderr file.
   275         #
   276         # This is terrible. 
   277 
   278         # first the service log
   279         if self._service_log_file != '':
   280             file_size = os.stat(self._service_log_file).st_size
   281             if file_size > self._service_log_size:
   282                 f = open(self._service_log_file, 'r')
   283                 f.seek(self._service_log_size)
   284                 self.ui.edtLog.appendPlainText(f.read())
   285                 self._service_log_size = file_size
   286         
   287         # now any processing log (download or import)
   288         if self._file_watched_name == '':
   289             return
   290 
   291         file_size = os.stat(self._file_watched_name).st_size
   292         if self._file_watched_size >= file_size:
   293             return
   294 
   295         f = open(self._file_watched_name, 'r')
   296         self.ui.edtProgress.setPlainText(f.read())
   297         self.ui.edtProgress.verticalScrollBar().setValue(self.ui.edtProgress.verticalScrollBar().maximum())
   298         self._file_watched_size = file_size
   299 
   300 
   301 if __name__ == "__main__":
   302     a = QtGui.QApplication(sys.argv)
   303     d = ConfigureDialog()
   304     d.show()
   305     sys.exit(a.exec_())     
   306