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