OpenSecurity/bin/ui/configure_dialog.py
author Oliver Maurhart <oliver.maurhart@ait.ac.at>
Wed, 25 Jun 2014 20:56:40 +0200
changeset 204 0c3136908f4f
parent 203 0cc33b647a4e
child 207 ae931a692b54
permissions -rwxr-xr-x
yet even more sex to the configuration dialog
     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.btnRefresh.clicked.connect(self.clicked_refresh)
   117         self._file_watcher.timeout.connect(self.update_progress)
   118 
   119         # call first refresh immediately
   120         QtCore.QTimer.singleShot(0, self.clicked_refresh)
   121         self._file_watcher.start(100)
   122 
   123 
   124     def clicked_about(self):
   125 
   126         """About button has been clicked."""
   127         self._about_dialog.exec_()
   128 
   129 
   130     def clicked_download(self):
   131 
   132         """Download button has been clicked."""
   133 
   134         # remove old stuff
   135         self._file_watched_name = ''
   136         self._file_watched_size = 0
   137         self.ui.edtProgress.clear()
   138 
   139         try:
   140 
   141             # get general server info
   142             j = json.load(urllib2.urlopen('http://127.0.0.1:8080/fetch_initial_image'))
   143             self._file_watched_name = str(j['fetch_log'])
   144 
   145         except:
   146             pass
   147 
   148 
   149     def clicked_explorer(self):
   150 
   151         """Explorer button has been clicked."""
   152         if sys.platform == 'win32' or sys.platform == 'cygwin':
   153             subprocess.Popen([os.path.join(os.environ['WINDIR'], 'explorer.exe'), self._service_log_path])
   154 
   155 
   156     def clicked_import(self):
   157 
   158         """Import button has been clicked."""
   159 
   160         # remove old stuff
   161         self._file_watched_name = ''
   162         self._file_watched_size = 0
   163         self.ui.edtProgress.clear()
   164 
   165         try:
   166 
   167             # get general server info
   168             j = json.load(urllib2.urlopen('http://127.0.0.1:8080/init'))
   169             self._file_watched_name = str(j['init_log'])
   170 
   171         except:
   172             pass
   173 
   174 
   175     def clicked_refresh(self):
   176 
   177         """Refresh button has been clicked."""
   178         self.ui.edtStatus.setText('<not evaluated yet>')
   179         self.ui.edtVersion.setText('<not evaluated yet>')
   180         self.ui.edtStatus.setEnabled(False);
   181         self.ui.edtVersion.setEnabled(False);
   182         self.ui.tvTemplate.clear()
   183 
   184         try:
   185 
   186             # get general server info
   187             j = json.load(urllib2.urlopen('http://127.0.0.1:8080'))
   188             self.ui.edtStatus.setText(j['os_server']['status message'])
   189             self.ui.edtStatus.setEnabled(True)
   190             self.ui.edtVersion.setText(j['os_server']['version'])
   191             self.ui.edtVersion.setEnabled(True)
   192             self._service_log_path = j['os_server']['current log folder']
   193             self._service_log_file = os.path.join(self._service_log_path, 'OpenSecurity.log')
   194             self._service_log_size = 0
   195 
   196             # get initial template info
   197             j = json.load(urllib2.urlopen('http://127.0.0.1:8080/initial_image'))
   198             i = QtGui.QTreeWidgetItem(self.ui.tvTemplate)
   199             i.setText(0, j['initial_template']['name'])
   200             i.setText(1, QtCore.QDateTime.fromTime_t(int(j['initial_template']['date'])).toString(QtCore.Qt.SystemLocaleShortDate))
   201             i.setText(2, str(j['initial_template']['size']))
   202             i.setText(3, j['initial_template']['path'])
   203             
   204         except:
   205             pass
   206 
   207         # trigger machine update
   208         self.update_machines()
   209 
   210 
   211     def update_machines(self):
   212 
   213         """Update the machines view"""
   214         self.ui.tvMachines.clear()
   215         self._icon_machine = QtGui.QIcon()
   216         self._icon_machine.addPixmap(QtGui.QPixmap(":/opensecurity/gfx/cpu.png"), QtGui.QIcon.Normal, QtGui.QIcon.Off)
   217         self._icon_property = QtGui.QIcon()
   218         self._icon_property.addPixmap(QtGui.QPixmap(":/opensecurity/gfx/configure.png"), QtGui.QIcon.Normal, QtGui.QIcon.Off)
   219         self._icon_network = QtGui.QIcon()
   220         self._icon_network.addPixmap(QtGui.QPixmap(":/opensecurity/gfx/network-workgroup.png"), QtGui.QIcon.Normal, QtGui.QIcon.Off)
   221 
   222 
   223         #try:
   224 
   225         # get machines
   226         machines = json.load(urllib2.urlopen('http://127.0.0.1:8080/sdvms'))
   227         for m in machines:
   228             i = QtGui.QTreeWidgetItem(self.ui.tvMachines)
   229             i.setIcon(0, self._icon_machine)
   230             i.setText(0, m)
   231             i.setIcon(1, self._icon_network)
   232             i.setText(1, machines[m])
   233 
   234 
   235             properties = json.load(urllib2.urlopen('http://127.0.0.1:8080/sdvms/' + m))
   236             for p in properties:
   237                 j = QtGui.QTreeWidgetItem(i)
   238                 j.setIcon(0, self._icon_property)
   239                 j.setText(0, p)
   240                 j.setText(1, properties[p])
   241 
   242             j.setIcon(0, self._icon_network)
   243             j.setText(0, 'ip')
   244             j.setText(1, machines[m])
   245 
   246 
   247         #except:
   248         #    pass
   249 
   250 
   251 
   252     def update_progress(self):
   253         
   254         """Our log file has changed, update ui"""
   255 
   256         # we could use os.stat(PATH).st_mtime ...
   257         # 
   258         # ... but Windows does not update it frequently. -.- 
   259         #
   260         # Running a Cygwin Bash Shell script in the background
   261         # does not update mtime of the redirected stderr file.
   262         #
   263         # This is terrible. 
   264 
   265         # first the service log
   266         if self._service_log_file != '':
   267             file_size = os.stat(self._service_log_file).st_size
   268             if file_size > self._service_log_size:
   269                 f = open(self._service_log_file, 'r')
   270                 f.seek(self._service_log_size)
   271                 self.ui.edtLog.appendPlainText(f.read())
   272                 self._service_log_size = file_size
   273         
   274         # now any processing log (download or import)
   275         if self._file_watched_name == '':
   276             return
   277 
   278         file_size = os.stat(self._file_watched_name).st_size
   279         if self._file_watched_size >= file_size:
   280             return
   281 
   282         f = open(self._file_watched_name, 'r')
   283         self.ui.edtProgress.setPlainText(f.read())
   284         self.ui.edtProgress.verticalScrollBar().setValue(self.ui.edtProgress.verticalScrollBar().maximum())
   285         self._file_watched_size = file_size
   286 
   287 
   288 if __name__ == "__main__":
   289     a = QtGui.QApplication(sys.argv)
   290     d = ConfigureDialog()
   291     d.show()
   292     sys.exit(a.exec_())     
   293