예제 #1
0
파일: admin_gui.py 프로젝트: wiz21b/koi
    def load_configuration(self):
        cfg_path = os.path.join(get_data_dir(), "server.cfg")

        # try:
        f = open(cfg_path, "r")
        t = f.read()
        f.close()
        self.text_edit_widget.setText(t)
예제 #2
0
def find_highest_installed_version():

    codename = configuration.get("Globals", "codename")

    mainlog.debug("Looking for new version of '{}' in {}".format(
        codename, get_data_dir()))

    select = re.compile(codename + r'-([0-9]+\.[0-9]+\.[0-9]+)$')

    highest_version = None

    for dirname in os.listdir(get_data_dir()):
        res = select.match(dirname)
        if res:
            d = os.path.join(get_data_dir(), dirname)
            if os.path.isdir(d):
                version = StrictVersion(res.group(1))
                if not highest_version or version > highest_version:
                    highest_version = version

    return highest_version
예제 #3
0
파일: admin_gui.py 프로젝트: wiz21b/koi
    def _save(self):

        try:
            old_server_ip = configuration.get("DEFAULT", "public_ip")

            cfg_path = os.path.join(get_data_dir(), "server.cfg")
            f = open(cfg_path, "w")
            f.write(self.text_edit_widget.toPlainText())
            f.close()
            self._log._log_success(
                "Server configuration saved in {}".format(cfg_path))

            load_configuration(cfg_path, "server_config_check.cfg")
            self._log._log_success("Server configuration reloaded")

            server_ip = configuration.get("DEFAULT", "public_ip")
            if old_server_ip != server_ip:
                self._log._log_success(
                    "Updating IP address in the downloadable delivery_slips")
                inject_public_ip_in_client(server_ip)

        except Exception as ex:
            self._log._log_error(
                "Something went wrong while saving the configuration : {}".
                format(ex))

        self._log._log("Reloading server configuration")
        import threading

        def open_server(url):
            try:
                urlopen(url)
            except ConnectionResetError as ex:
                pass

        threading.Thread(target=open_server,
                         args=['http://127.0.0.1:8079/reload']).start()
예제 #4
0
def upgrade_process(args):
    if platform.system() != 'Windows':
        mainlog.info(
            "The upgrade process won't work on something else than Windows... I skip that."
        )
        return

    this_version = configuration.this_version  # the one of this very code
    mainlog.debug("Client version is {}".format(this_version))

    if args.no_update:
        mainlog.info("Skipping update process because --no-update is set")

        # This is rather strange. If we are started by regular Windows ways
        # (double click, cmd,...) PySide finds its DLL fine.
        # But, if it is started through the upgrade process (via Popen), then
        # it doesn't because Windows can't expand junction points correctly
        # (according to what I saw, this is not a bug in windows, but rather a
        # feature to prevent old code to misuse junction points)
        # So, for this code to work, one has to make sure that _setupQtDir
        # is not called during the import but right after (else it crashes).

        # This is how to patch the __init__py of PySide :

        # def _setupQtDirectories(zedir=None):
        #     import sys
        #     import os
        #     from . import _utils
        #
        #     if zedir:
        #         pysideDir = zedir
        #     else:
        #         pysideDir = _utils.get_pyside_dir()
        #

        try:
            from PySide import _setupQtDirectories
        except Exception as ex:
            mainlog.error(
                "Unable to import _setupQtDirectories. Remember this was a bug fix, make sure "
                +
                "_setupQtDirectories is not called at the end of the __init__.py of pyside. "
                + "Check the comments in the code for more info.")
            mainlog.exception(ex)
            return

        if getattr(sys, 'frozen', False):
            # Frozen
            mainlog.debug("Fixing Qt import on frozen exe {}".format(
                os.path.normpath(os.getcwd())))
            _setupQtDirectories(os.path.normpath(os.getcwd()))
        else:
            mainlog.debug("Fixed Qt import on NON frozen exe")
            _setupQtDirectories()

        return

    next_version = get_server_version(
        configuration.update_url_version
    )  # available on the server (abd maybe already downloaded)
    current_version = find_highest_installed_version(
    )  # one we have downloaded in the past

    mainlog.info(
        "This version is {}, last downloaded version = {}, version available on server = {}"
        .format(this_version, current_version, next_version))

    if (not current_version or (current_version and this_version >= current_version)) and \
            (not next_version or (next_version and this_version >= next_version)):
        mainlog.info(
            "The available versions are not more recent than the current one. No update necessary."
        )
        return

    codename = configuration.get("Globals", "codename")

    # Update only if we have no current version or if the
    # next version is higher than ours

    if next_version and (not current_version
                         or next_version > current_version):

        try:
            tmpfile = make_temp_file(prefix='NewVersion_' +
                                     version_to_str(next_version),
                                     extension='.zip')
            download_file(configuration.update_url_file, tmpfile)

            newdir = os.path.join(
                get_data_dir(), "{}-{}".format(codename,
                                               version_to_str(next_version)))
            extractAll(tmpfile, newdir)

            # show that we actually downloaded something
            current_version = next_version
        except Exception as ex:
            mainlog.error(
                "The download of version {} failed. Therefore, I'll go on with the current one."
                .format(next_version))
            mainlog.exception(ex)

    # If we were able to download a version now or in the
    # past, then use this one. If not, then we run the
    # program (that is, the version that was installed
    # by the user)

    if current_version:
        current_dir = os.path.join(
            get_data_dir(), "{}-{}".format(codename,
                                           version_to_str(current_version)))

        # --no-update "signals" the control transfer (without it we'd
        # try to update with the latest version again creating an
        # endless loop)

        # os.chdir(os.path.join(current_dir,codename)) # FIXME Not sure this is useful; too tired to test
        cmd = [
            os.path.join(os.path.join(current_dir, codename),
                         codename + '.exe'), '--no-update'
        ]
        mainlog.info("Transferring control to {}".format(' '.join(cmd)))

        # DETACHED_PROCESS = 0x00000008
        # CREATE_NEW_PROCESS_GROUP = 0x00000200
        # subprocess.Popen( cmd,cwd=os.path.join(current_dir,'xxx'),creationflags=DETACHED_PROCESS|CREATE_NEW_PROCESS_GROUP)

        # From what I can see WinExec don't run in os.getcwd(), so I give it an absolute path.

        try:
            # win32api.WinExec will *NOT* block. The new version is run
            # in parallel. This allow us to quit so we don't have two
            # instances of Koi running simulatenaously

            # Unfortunaately, because of that it's hard to build a watch
            # dog that will protect us against a broken upgrade.
            # For example, we'd have to release our log files...

            res = win32api.WinExec(" ".join(cmd), win32con.SW_SHOWMAXIMIZED)
            sys.exit(RETURN_CODE_SUCCESS)

        except Exception as ex:
            mainlog.error(
                "Control transfer failed. There was an error while starting the newer version {}"
                .format(current_version))
            mainlog.exception(ex)
            return False
예제 #5
0
파일: admin_gui.py 프로젝트: wiz21b/koi
    def __init__(self):
        super(MainWindow, self).__init__()

        self.edit_config = EditConfigurationDialog(self)
        self.edit_config.load_configuration()

        w = QWidget(self)

        big_hlayout = QHBoxLayout()

        layout = QVBoxLayout()
        big_hlayout.addLayout(layout)
        big_hlayout.addWidget(self.edit_config)

        layout.addWidget(
            QLabel("<h1>{} administration</h1>".format(
                configuration.get("Globals", "name"))))

        glayout = QGridLayout()

        row = 0

        HOST = "{} or {}".format(guess_server_public_ip(),
                                 socket.gethostname())
        glayout.addWidget(QLabel("<b>Server's IP address"), row, 0)
        ip_address = configuration.get("DEFAULT", "public_ip")
        if not ip_address:
            ip_address = "<font color='red'><b>NOT DEFINED</b></font>"
        glayout.addWidget(QLabel("{} (guessed: {})".format(ip_address, HOST)),
                          row, 1)

        row += 1
        glayout.addWidget(QLabel("<b>Client database URL"), row, 0)
        db_url = configuration.get("Database", "url")
        self.public_url_edit = QLabel(db_url)
        glayout.addWidget(self.public_url_edit, row, 1)

        row += 1
        glayout.addWidget(QLabel("<b>Client server URL"), row, 0)
        url = configuration.get("DownloadSite", "public_url")
        self.public_web_url_edit = QLabel(url)
        glayout.addWidget(self.public_web_url_edit, row, 1)

        row += 1
        glayout.addWidget(QLabel("Server local DB URL"), row, 0)
        db_url = configuration.get("Database", "admin_url")
        self.url_edit = QLabel(db_url)
        glayout.addWidget(self.url_edit, row, 1)

        row += 1
        glayout.addWidget(QLabel("Backup directory"), row, 0)
        db_url = configuration.get("Backup", "backup_directory")
        self.backup_directory_edit = QLabel(db_url)
        glayout.addWidget(self.backup_directory_edit, row, 1)

        row += 1
        glayout.addWidget(QLabel("Data/logs directory"), row, 0)
        self.data_directory_edit = QLabel(get_data_dir())
        glayout.addWidget(self.data_directory_edit, row, 1)

        qgb = QGroupBox("Life data")
        qgb.setLayout(glayout)
        layout.addWidget(qgb)

        hlayout = QHBoxLayout()
        b = QPushButton("Check database")
        b.clicked.connect(self.check_database)
        hlayout.addWidget(b)

        b = QPushButton("Check web server")
        b.clicked.connect(self.check_server)
        hlayout.addWidget(b)

        b = QPushButton("Show delivery_slips download page")
        b.clicked.connect(self.show_client_dowload_page)
        hlayout.addWidget(b)

        qgb = QGroupBox("Checks")
        qgb.setLayout(hlayout)
        layout.addWidget(qgb)

        hlayout = QHBoxLayout()
        # b = QPushButton("Set backup directory")
        # b.clicked.connect(self.set_backup_directory)
        # hlayout.addWidget( b)

        b = QPushButton("Restore backup")
        b.clicked.connect(self.restore_backup)
        hlayout.addWidget(b)

        b = QPushButton("Reset admin account")
        b.clicked.connect(self.create_root_account)
        hlayout.addWidget(b)

        # b = QPushButton("Set public IP")
        # b.clicked.connect(self.set_public_ip)
        # hlayout.addWidget( b)

        # Please use the command line, this is not for the faint hearted.

        # b = QPushButton("Clear database")
        # b.clicked.connect(self.create_database)
        # hlayout.addWidget( b)

        qgb = QGroupBox("Actions")
        qgb.setLayout(hlayout)
        layout.addWidget(qgb)

        vlayout = QVBoxLayout()

        # if platform.system() == 'Windows':
        #     # when running on Linux, it's expected that the
        #     # whole server configuration is set up by us
        #
        #     hlayout = QHBoxLayout()
        #     b = QPushButton("Start server manually")
        #     b.clicked.connect(self.start_server_manually)
        #     hlayout.addWidget( b)
        #
        #     b = QPushButton("Stop server manually")
        #     b.clicked.connect(self.stop_server_manually)
        #     hlayout.addWidget( b)
        #     vlayout.addLayout(hlayout)
        #
        #     hlayout = QHBoxLayout()
        #     b = QPushButton("Install services")
        #     b.clicked.connect(self.install_service)
        #     hlayout.addWidget( b)
        #
        #     b = QPushButton("Uninstall services")
        #     b.clicked.connect(self.uninstall_service)
        #     hlayout.addWidget( b)
        #     vlayout.addLayout(hlayout)
        #
        #     b = QPushButton("Install scheduled services")
        #     b.clicked.connect(self.install_on_start_tasks)
        #     vlayout.addWidget( b)
        #
        #     # b = QPushButton("Upgrade delivery_slips")
        #     # b.clicked.connect(self.upgrade_client)
        #     # layout.addWidget( b)
        #
        #     qgb = QGroupBox("Service & installation")
        #     qgb.setLayout(vlayout)
        #     layout.addWidget(qgb)

        self.log_view = QTextEdit()
        layout.addWidget(self.log_view)

        self.url_edit.setTextInteractionFlags(Qt.TextSelectableByMouse)
        self.public_url_edit.setTextInteractionFlags(Qt.TextSelectableByMouse)
        self.public_web_url_edit.setTextInteractionFlags(
            Qt.TextSelectableByMouse)
        self.backup_directory_edit.setTextInteractionFlags(
            Qt.TextSelectableByMouse)

        self.log_view.setReadOnly(True)

        w.setLayout(big_hlayout)

        self.setCentralWidget(w)
예제 #6
0
파일: admin_gui.py 프로젝트: wiz21b/koi
    def restore_backup(self):

        self._clear_log()
        self._log("Restore procedure started")

        url = self.url_edit.text()
        psql_path = configuration.get("Commands", "psql")

        if not psql_path:
            self._log_error(
                "The Commands/psql path is not set in the server.cfg")
            self._log("Please fix the configuration file (on the right)")
            return

        if not configuration.get("Commands", "pg_restore"):
            self._log_error(
                "The Commands/pg_restore path is not set in the server.cfg")
            self._log("Please fix the configuration file (on the right)")
            return

        if not configuration.get("Backup", "backup_directory"):

            self._log(
                "The Backup/backup_directory path is not set in the server.cfg"
            )
            self._log("I'm setting it myself.")

            configuration.set("Backup", "backup_directory", get_data_dir())
            configuration.set("DocumentsDatabase", "documents_root",
                              os.path.join(get_data_dir(), "documents"))
            configuration.save()
            self.edit_config.load_configuration()

        login_clt, password_clt, dummy, dummy, dummy = self._extract_db_params_from_url(
            configuration.get("Database", "url"))
        login_adm, password_adm, dbname, host, port = self._extract_db_params_from_url(
            configuration.get("Database", "admin_url"))

        self._log("{} / {}".format(login_adm, password_adm))

        full_path_backup = None
        d = ""
        if configuration.get("Backup", "backup_directory"):
            d = configuration.get("Backup", "backup_directory")

        if platform.system() == "Windows":

            if configuration.get("Backup", "backup_directory"):
                d = configuration.get("Backup", "backup_directory")

            # Using the static method gives a more native FileDialog.
            # with support for network
            backup_file = QFileDialog.getOpenFileName(
                self, _("Please select a backup file"), d,
                "{} database backup (*.pgbackup)".format(
                    configuration.get("Globals", "name")))[0]

            if not backup_file:
                self._log("Restore aborted")
                return

            full_path_backup = backup_file
            if not os.path.isdir(full_path_backup):
                self._log(
                    "{} is not a directory, so I'll go up a level".format(
                        full_path_backup))
                full_path_backup = os.path.dirname(full_path_backup)

                if not os.path.isdir(full_path_backup):
                    self._log_error(
                        "{} is not a directory either. Aborting restore.".
                        format(full_path_backup))
                    return

        elif platform.system() == "Linux":

            d = AskWindowsShare(None)
            d.exec_()
            if d.result() == QDialog.Accepted:

                # //192.168.0.6/postgresqlbackup

                script_path = "/tmp/horse_mount.sh"
                script = open(script_path, "w")
                script.write("""#!/bin/bash
echo "Creating transfer directory"
mkdir /tmp/backup_win
echo "Unmounting previous transfer directory (can fail)"
umount /tmp/backup_win
echo "Mouting the backup directory"
mount -t cifs -ousername={},password={} {} /tmp/backup_win
                """.format(d.user.text().strip(),
                           d.password.text().strip(),
                           d.address.text().strip()))
                script.close()

                import stat
                os.chmod(script_path,
                         stat.S_IEXEC | stat.S_IWRITE | stat.S_IREAD)

                cmd = [
                    'gksudo', '--sudo-mode', '--message',
                    'Allow Koi to connect to the backup server.', script_path
                ]

                # gksudo seems to like to have the DISPLAY set. So I basically copy
                # it from the calling environment.

                ret, dummy, dummy = self._run_shell(
                    cmd, {'DISPLAY': os.environ.get('DISPLAY')})

                if ret > 0:
                    self._log_error(
                        "The mount operation failed. Please review the parameters you've given."
                    )
                    self._log_error(
                        "Network address : {}, windows user name : {}".format(
                            d.address.text() or "?",
                            d.user.text() or "?"))
                    return

                full_path_backup = "/tmp/backup_win"
            else:
                dialog = QFileDialog(self)
                dialog.setFileMode(QFileDialog.Directory)
                dialog.setNameFilters(['Koi database backup (*.pgbackup)'])
                dialog.setWindowTitle("Please select a backup file")
                if configuration.get("Backup", "backup_directory"):
                    dialog.setDirectory(
                        configuration.get("Backup", "backup_directory"))
                if dialog.exec_():
                    full_path_backup = dialog.selectedFiles()[0]
                else:
                    self._log_error(
                        "Without proper source directory, I can't continue !")
                    return
        else:
            self._log_error("Unsupported operating system")

        # At this poitn full_path_backup is the path to the backup
        # directory of Horse that we want to restore.
        # It is different than the current backup directory.

        if full_path_backup:
            full_restore(configuration, full_path_backup, backup_file, True,
                         mainlog)
            self._log_success("Backup successfully restored !")
예제 #7
0
파일: admin_gui.py 프로젝트: wiz21b/koi
    mainlog.addHandler(LoggerHandler(window))

    # d = AskWindowsShare(None)
    # d.exec_()

    if args.reset_database:
        window.create_database()
        sys.exit(0)
    if args.create_root_account:
        window.create_root_account()
        sys.exit(0)

    window.setMinimumSize(1000, 700)
    # window._upgrade_client_to_version("1.0.42","postgresql://jsdfksdhf","192.168.16.16","666")

    cfg_path = os.path.join(get_data_dir(), "server.cfg")

    if not os.path.exists(cfg_path):
        f = open(cfg_path, "w")

        c = configuration.base_configuration.copy()
        for section in sorted(c.keys()):
            f.write("[{}]\n".format(section))

            for entry, value in c[section].items():
                f.write("{} = {}\n".format(entry, value))

            f.write("\n")

        f.close()