示例#1
0
文件: db.py 项目: olatarkowska/omego
    def __call__(self, args):
        super(DbCommand, self).__call__(args)
        self.configure_logging(args)

        # Since EnvDefault.__action__ is only called if a user actively passes
        # a variable, there's no way to do the string replacing in the action
        # itself. Instead, we're post-processing them here, but this could be
        # improved.

        names = sorted(x.dest for x in self.parser._actions)
        for dest in names:
            if dest in ("help", "verbose", "quiet"):
                continue
            value = getattr(args, dest)
            if value and isinstance(value, basestring):
                replacement = value % dict(args._get_kwargs())
                log.debug("% 20s => %s" % (dest, replacement))
                setattr(args, dest, replacement)

        if args.serverdir:
            d = args.serverdir
        else:
            raise Stop(1, 'OMERO server directory required')
        ext = External(d)
        ext.setup_omero_cli()
        DbAdmin(d, args.dbcommand, args, ext)
示例#2
0
class Install(object):
    def __init__(self, cmd, args):

        self.args = args
        log.info("%s: %s", self.__class__.__name__, cmd)
        log.debug("Current directory: %s", os.getcwd())

        if cmd == "upgrade":
            newinstall = False
            if not os.path.exists(args.sym):
                raise Stop(30, "Symlink is missing: %s" % args.sym)
        elif cmd == "install":
            newinstall = True
            if os.path.exists(args.sym):
                raise Stop(30, "Symlink already exists: %s" % args.sym)
        else:
            raise Exception("Unexpected command: %s" % cmd)

        server_dir = self.get_server_dir()

        if newinstall:
            # Create a symlink to simplify the rest of the logic-
            # just need to check if OLD == NEW
            self.symlink(server_dir, args.sym)
            log.info("Installing %s (%s)...", server_dir, args.sym)
        else:
            log.info("Upgrading %s (%s)...", server_dir, args.sym)

        self.external = External(server_dir)
        self.external.setup_omero_cli()

        if not newinstall:
            self.external.setup_previous_omero_env(args.sym, args.savevarsfile)

        # Need lib/python set above
        import path

        self.dir = path.path(server_dir)

        if not newinstall:
            self.stop()
            self.archive_logs()

        copyold = not newinstall and not args.ignoreconfig
        self.configure(copyold, args.prestartfile)
        self.directories()

        if newinstall:
            self.init_db()

        self.upgrade_db()

        self.external.save_env_vars(args.savevarsfile, args.savevars.split())
        self.start()

    def get_server_dir(self):
        """
        Either downloads and/or unzips the server if necessary
        return: the directory of the unzipped server
        """
        if not self.args.server:
            if self.args.skipunzip:
                raise Stop(0, "Unzip disabled, exiting")

            log.info("Downloading server")
            artifacts = Artifacts(self.args)
            server = artifacts.download("server")
        else:
            progress = 0
            if self.args.verbose:
                progress = 20
            ptype, server = fileutils.get_as_local_path(
                self.args.server,
                self.args.overwrite,
                progress=progress,
                httpuser=self.args.httpuser,
                httppassword=self.args.httppassword,
            )
            if ptype == "file":
                if self.args.skipunzip:
                    raise Stop(0, "Unzip disabled, exiting")
                log.info("Unzipping %s", server)
                server = fileutils.unzip(server, match_dir=True, destdir=self.args.unzipdir)

        log.debug("Server directory: %s", server)
        return server

    def stop(self):
        try:
            log.info("Stopping server")
            self.bin("admin status --nodeonly")
            self.bin("admin stop")
        except Exception as e:
            log.error("Error whilst stopping server: %s", e)

        if not self.args.no_web:
            try:
                log.info("Stopping web")
                self.stopweb()
            except Exception as e:
                log.error("Error whilst stopping web: %s", e)

    def configure(self, copyold, prestartfile):
        def samecontents(a, b):
            # os.path.samefile is not available on Windows
            try:
                return os.path.samefile(a, b)
            except AttributeError:
                with open(a) as fa:
                    with open(b) as fb:
                        return fa.read() == fb.read()

        target = self.dir / "etc" / "grid" / "config.xml"

        if copyold:
            from path import path

            old_grid = path(self.args.sym) / "etc" / "grid"
            old_cfg = old_grid / "config.xml"
            log.info("Copying old configuration from %s", old_cfg)
            if not old_cfg.exists():
                raise Stop(40, "config.xml not found")
            if target.exists() and samecontents(old_cfg, target):
                # This likely is caused by the symlink being
                # created early on an initial install.
                pass
            else:
                old_cfg.copy(target)
        else:
            if target.exists():
                log.info("Deleting configuration file %s", target)
                target.remove()

        if prestartfile:
            for f in prestartfile:
                log.info("Loading prestart file %s", f)
                ftype, fpath = fileutils.get_as_local_path(f, "backup")
                if ftype != "file":
                    raise Stop(50, "Expected file, found: %s %s" % (ftype, f))
                self.run(["load", fpath])

    def archive_logs(self):
        if self.args.archivelogs:
            logdir = os.path.join(self.args.sym, "var", "log")
            archive = self.args.archivelogs
            log.info("Archiving logs to %s", archive)
            fileutils.zip(archive, logdir, os.path.join(self.args.sym, "var"))
            return archive

    def directories(self):
        if self.samedir(self.dir, self.args.sym):
            log.warn("Upgraded server was the same, not deleting")
            return

        try:
            target = self.readlink(self.args.sym)
            targetzip = target + ".zip"
        except IOError:
            log.error("Unable to get symlink target: %s", self.args.sym)
            target = None
            targetzip = None

        if self.args.delete_old and target:
            try:
                log.info("Deleting %s", target)
                shutil.rmtree(target)
            except OSError as e:
                log.error("Failed to delete %s: %s", target, e)

        if not self.args.keep_old_zip and targetzip:
            try:
                log.info("Deleting %s", targetzip)
                os.unlink(targetzip)
            except OSError as e:
                log.error("Failed to delete %s: %s", targetzip, e)

        self.rmlink(self.args.sym)
        self.symlink(self.dir, self.args.sym)

    def init_db(self):
        if self.args.initdb:
            log.debug("Initialising database")
            DbAdmin(self.dir, "init", self.args, self.external)

    def upgrade_db(self):
        if self.args.upgradedb:
            log.debug("Upgrading database")
            DbAdmin(self.dir, "upgrade", self.args, self.external)

    def start(self):
        if self.args.no_start:
            log.debug("Not starting OMERO")
            return

        self.run("admin start")
        if not self.args.no_web:
            log.info("Starting web")
            self.startweb()

    def run(self, command):
        """
        Runs a command as if from the command-line
        without the need for using popen or subprocess
        """
        if isinstance(command, basestring):
            command = command.split()
        else:
            command = list(command)
        self.external.omero_cli(command)

    def bin(self, command):
        """
        Runs the omero command-line client with an array of arguments using the
        old environment
        """
        if isinstance(command, basestring):
            command = command.split()
        self.external.omero_bin(command)
示例#3
0
class Install(object):
    def __init__(self, cmd, args):

        self.args = args
        log.info("%s: %s", self.__class__.__name__, cmd)
        log.debug("Current directory: %s", os.getcwd())

        if cmd == 'upgrade':
            newinstall = False
            if not os.path.exists(args.sym):
                raise Stop(30, 'Symlink is missing: %s' % args.sym)
        elif cmd == 'install':
            newinstall = True
            if os.path.exists(args.sym):
                raise Stop(30, 'Symlink already exists: %s' % args.sym)
        else:
            raise Exception('Unexpected command: %s' % cmd)

        server_dir = self.get_server_dir()

        if newinstall:
            # Create a symlink to simplify the rest of the logic-
            # just need to check if OLD == NEW
            self.symlink(server_dir, args.sym)
            log.info("Installing %s (%s)...", server_dir, args.sym)
        else:
            log.info("Upgrading %s (%s)...", server_dir, args.sym)

        self.external = External(server_dir)
        self.external.setup_omero_cli()

        if not newinstall:
            self.external.setup_previous_omero_env(args.sym, args.savevarsfile)

        # Need lib/python set above
        import path
        self.dir = path.path(server_dir)

        if not newinstall:
            self.stop()
            self.archive_logs()

        copyold = not newinstall and not args.ignoreconfig
        self.configure(copyold, args.prestartfile)
        self.directories()

        if newinstall:
            self.init_db()

        self.upgrade_db()

        self.external.save_env_vars(args.savevarsfile, args.savevars.split())
        self.start()

    def get_server_dir(self):
        """
        Either downloads and/or unzips the server if necessary
        return: the directory of the unzipped server
        """
        if not self.args.server:
            if self.args.skipunzip:
                raise Stop(0, 'Unzip disabled, exiting')

            log.info('Downloading server')
            artifacts = Artifacts(self.args)
            server = artifacts.download('server')
        else:
            progress = 0
            if self.args.verbose:
                progress = 20
            ptype, server = fileutils.get_as_local_path(
                self.args.server,
                self.args.overwrite,
                progress=progress,
                httpuser=self.args.httpuser,
                httppassword=self.args.httppassword)
            if ptype == 'file':
                if self.args.skipunzip:
                    raise Stop(0, 'Unzip disabled, exiting')
                log.info('Unzipping %s', server)
                server = fileutils.unzip(server,
                                         match_dir=True,
                                         destdir=self.args.unzipdir)

        log.debug('Server directory: %s', server)
        return server

    def stop(self):
        try:
            log.info("Stopping server")
            self.bin("admin status --nodeonly")
            self.bin("admin stop")
        except Exception as e:
            log.error('Error whilst stopping server: %s', e)

        if not self.args.no_web:
            try:
                log.info("Stopping web")
                self.stopweb()
            except Exception as e:
                log.error('Error whilst stopping web: %s', e)

    def configure(self, copyold, prestartfile):
        def samecontents(a, b):
            # os.path.samefile is not available on Windows
            try:
                return os.path.samefile(a, b)
            except AttributeError:
                with open(a) as fa:
                    with open(b) as fb:
                        return fa.read() == fb.read()

        target = self.dir / "etc" / "grid" / "config.xml"

        if copyold:
            from path import path
            old_grid = path(self.args.sym) / "etc" / "grid"
            old_cfg = old_grid / "config.xml"
            log.info("Copying old configuration from %s", old_cfg)
            if not old_cfg.exists():
                raise Stop(40, 'config.xml not found')
            if target.exists() and samecontents(old_cfg, target):
                # This likely is caused by the symlink being
                # created early on an initial install.
                pass
            else:
                old_cfg.copy(target)
        else:
            if target.exists():
                log.info('Deleting configuration file %s', target)
                target.remove()

        if prestartfile:
            for f in prestartfile:
                log.info('Loading prestart file %s', f)
                ftype, fpath = fileutils.get_as_local_path(f, 'backup')
                if ftype != 'file':
                    raise Stop(50, 'Expected file, found: %s %s' % (ftype, f))
                self.run(['load', fpath])

    def archive_logs(self):
        if self.args.archivelogs:
            logdir = os.path.join(self.args.sym, 'var', 'log')
            archive = self.args.archivelogs
            log.info('Archiving logs to %s', archive)
            fileutils.zip(archive, logdir, os.path.join(self.args.sym, 'var'))
            return archive

    def directories(self):
        if self.samedir(self.dir, self.args.sym):
            log.warn("Upgraded server was the same, not deleting")
            return

        try:
            target = self.readlink(self.args.sym)
            targetzip = target + '.zip'
        except IOError:
            log.error('Unable to get symlink target: %s', self.args.sym)
            target = None
            targetzip = None

        if self.args.delete_old and target:
            try:
                log.info("Deleting %s", target)
                shutil.rmtree(target)
            except OSError as e:
                log.error("Failed to delete %s: %s", target, e)

        if not self.args.keep_old_zip and targetzip:
            try:
                log.info("Deleting %s", targetzip)
                os.unlink(targetzip)
            except OSError as e:
                log.error("Failed to delete %s: %s", targetzip, e)

        self.rmlink(self.args.sym)
        self.symlink(self.dir, self.args.sym)

    def init_db(self):
        if self.args.initdb:
            log.debug('Initialising database')
            DbAdmin(self.dir, 'init', self.args, self.external)

    def upgrade_db(self):
        if self.args.upgradedb:
            log.debug('Upgrading database')
            DbAdmin(self.dir, 'upgrade', self.args, self.external)

    def start(self):
        if self.args.no_start:
            log.debug('Not starting OMERO')
            return

        self.run("admin start")
        if not self.args.no_web:
            log.info("Starting web")
            self.startweb()

    def run(self, command):
        """
        Runs a command as if from the command-line
        without the need for using popen or subprocess
        """
        if isinstance(command, basestring):
            command = command.split()
        else:
            command = list(command)
        self.external.omero_cli(command)

    def bin(self, command):
        """
        Runs the omero command-line client with an array of arguments using the
        old environment
        """
        if isinstance(command, basestring):
            command = command.split()
        self.external.omero_bin(command)
示例#4
0
文件: upgrade.py 项目: manics/omego
class Install(object):

    def __init__(self, cmd, args):
        self.args, newinstall = self._handle_args(cmd, args)
        log.info("%s: %s", self.__class__.__name__, cmd)
        log.debug("Current directory: %s", os.getcwd())
        self.symlink_check_and_set()

        if newinstall is None:
            # Automatically install or upgrade
            newinstall = not os.path.exists(args.sym)
        elif newinstall is False:
            if not os.path.exists(args.sym):
                raise Stop(30, 'Symlink is missing: %s' % args.sym)
        elif newinstall is True:
            if os.path.exists(args.sym):
                raise Stop(30, 'Symlink already exists: %s' % args.sym)
        else:
            assert False

        server_dir = self.get_server_dir()

        if newinstall:
            # Create a symlink to simplify the rest of the logic-
            # just need to check if OLD == NEW
            self.symlink(server_dir, args.sym)
            log.info("Installing %s (%s)...", server_dir, args.sym)
        else:
            log.info("Upgrading %s (%s)...", server_dir, args.sym)

        self.external = External(server_dir)
        self.external.setup_omero_cli()

        if not newinstall:
            self.external.setup_previous_omero_env(args.sym, args.savevarsfile)

        # Need lib/python set above
        import path
        self.dir = path.path(server_dir)

        if not newinstall:
            self.stop()
            self.archive_logs()

        copyold = not newinstall and not args.ignoreconfig
        self.configure(copyold, args.prestartfile)
        self.directories()

        self.handle_database()

        self.external.save_env_vars(args.savevarsfile, args.savevars.split())
        self.start()

    def _handle_args(self, cmd, args):
        """
        We need to support deprecated behaviour for now which makes this
        quite complicated

        Current behaviour:
        - install: Installs a new server, existing server causes an error
        - install --upgrade: Installs or upgrades a server
        - install --managedb: Automatically initialise or upgrade the db

        Deprecated:
        - install --upgradedb --initdb: Replaced by install --managedb
        - install --upgradedb: upgrade the db, must exist
        - install --initdb: initialise the db
        - upgrade: Upgrades a server, must already exist
        - upgrade --upgradedb: Automatically upgrade the db

        returns:
        - Modified args object, flag to indicate new/existing/auto install
        """
        if cmd == 'install':
            if args.upgrade:
                # Current behaviour: install or upgrade
                if args.initdb or args.upgradedb:
                    raise Stop(10, (
                        'Deprecated --initdb --upgradedb flags '
                        'are incompatible with --upgrade'))
                newinstall = None
            else:
                # Current behaviour: Server must not exist
                newinstall = True

            if args.managedb:
                # Current behaviour
                if args.initdb or args.upgradedb:
                    raise Stop(10, (
                        'Deprecated --initdb --upgradedb flags '
                        'are incompatible with --managedb'))
                args.initdb = True
                args.upgradedb = True
            else:
                if args.initdb or args.upgradedb:
                    log.warn('--initdb and --upgradedb are deprecated, '
                             'use --managedb')

        elif cmd == 'upgrade':
            # Deprecated behaviour
            log.warn(
                '"omero upgrade" is deprecated, use "omego install --upgrade"')
            cmd = 'install'
            args.upgrade = True
            # Deprecated behaviour: Server must exist
            newinstall = False

        else:
            raise Exception('Unexpected command: %s' % cmd)

        return args, newinstall

    def get_server_dir(self):
        """
        Either downloads and/or unzips the server if necessary
        return: the directory of the unzipped server
        """
        if not self.args.server:
            if self.args.skipunzip:
                raise Stop(0, 'Unzip disabled, exiting')

            log.info('Downloading server')

            # The downloader automatically symlinks the server, however if
            # we are upgrading we want to delay the symlink swap, so this
            # overrides args.sym
            # TODO: Find a nicer way to do this?
            artifact_args = copy.copy(self.args)
            artifact_args.sym = ''
            artifacts = Artifacts(artifact_args)
            server = artifacts.download('server')
        else:
            progress = 0
            if self.args.verbose:
                progress = 20
            ptype, server = fileutils.get_as_local_path(
                self.args.server, self.args.overwrite, progress=progress,
                httpuser=self.args.httpuser,
                httppassword=self.args.httppassword)
            if ptype == 'file':
                if self.args.skipunzip:
                    raise Stop(0, 'Unzip disabled, exiting')
                log.info('Unzipping %s', server)
                server = fileutils.unzip(
                    server, match_dir=True, destdir=self.args.unzipdir)

        log.debug('Server directory: %s', server)
        return server

    def stop(self):
        try:
            log.info("Stopping server")
            self.bin("admin status --nodeonly")
            self.bin("admin stop")
        except Exception as e:
            log.error('Error whilst stopping server: %s', e)

        if not self.args.no_web:
            try:
                log.info("Stopping web")
                self.stopweb()
            except Exception as e:
                log.error('Error whilst stopping web: %s', e)

    def configure(self, copyold, prestartfile):
        def samecontents(a, b):
            # os.path.samefile is not available on Windows
            try:
                return os.path.samefile(a, b)
            except AttributeError:
                with open(a) as fa:
                    with open(b) as fb:
                        return fa.read() == fb.read()

        target = self.dir / "etc" / "grid" / "config.xml"

        if copyold:
            from path import path
            old_grid = path(self.args.sym) / "etc" / "grid"
            old_cfg = old_grid / "config.xml"
            log.info("Copying old configuration from %s", old_cfg)
            if not old_cfg.exists():
                raise Stop(40, 'config.xml not found')
            if target.exists() and samecontents(old_cfg, target):
                # This likely is caused by the symlink being
                # created early on an initial install.
                pass
            else:
                old_cfg.copy(target)
        else:
            if target.exists():
                log.info('Deleting configuration file %s', target)
                target.remove()

        if prestartfile:
            for f in prestartfile:
                log.info('Loading prestart file %s', f)
                ftype, fpath = fileutils.get_as_local_path(f, 'backup')
                if ftype != 'file':
                    raise Stop(50, 'Expected file, found: %s %s' % (
                        ftype, f))
                self.run(['load', fpath])

    def archive_logs(self):
        if self.args.archivelogs:
            logdir = os.path.join(self.args.sym, 'var', 'log')
            archive = self.args.archivelogs
            log.info('Archiving logs to %s', archive)
            fileutils.zip(archive, logdir, os.path.join(self.args.sym, 'var'))
            return archive

    def directories(self):
        if self.samedir(self.dir, self.args.sym):
            log.warn("Upgraded server was the same, not deleting")
            return

        try:
            target = self.readlink(self.args.sym)
            targetzip = target + '.zip'
        except IOError:
            log.error('Unable to get symlink target: %s', self.args.sym)
            target = None
            targetzip = None

        if self.args.delete_old and target:
            try:
                log.info("Deleting %s", target)
                shutil.rmtree(target)
            except OSError as e:
                log.error("Failed to delete %s: %s", target, e)

        if not self.args.keep_old_zip and targetzip:
            try:
                log.info("Deleting %s", targetzip)
                os.unlink(targetzip)
            except OSError as e:
                log.error("Failed to delete %s: %s", targetzip, e)

        self.rmlink(self.args.sym)
        self.symlink(self.dir, self.args.sym)

    def handle_database(self):
        """
        Handle database initialisation and upgrade, taking into account
        command line arguments
        """
        # TODO: When initdb and upgradedb are dropped we can just test
        # managedb, but for backwards compatibility we need to support
        # initdb without upgradedb and vice-versa

        if self.args.initdb or self.args.upgradedb:
            db = DbAdmin(self.dir, None, self.args, self.external)
            status = db.check()
            log.debug('OMERO database upgrade status: %s', status)
        else:
            log.warn('OMERO database check disabled')
            return DB_INIT_NEEDED

        if status == DB_INIT_NEEDED:
            if self.args.initdb:
                log.debug('Initialising OMERO database')
                db.init()
            else:
                log.error('OMERO database not found')
                raise Stop(DB_INIT_NEEDED,
                           'Install/Upgrade failed: OMERO database not found')

        elif status == DB_UPGRADE_NEEDED:
            log.warn('OMERO database exists but is out of date')
            if self.args.upgradedb:
                log.debug('Upgrading OMERO database')
                db.upgrade()
            else:
                raise Stop(
                    DB_UPGRADE_NEEDED,
                    'Pass --managedb or upgrade your OMERO database manually')

        else:
            assert status == DB_UPTODATE

        return status

    def start(self):
        if self.args.no_start:
            log.debug('Not starting OMERO')
            return

        self.run("admin start")
        if not self.args.no_web:
            log.info("Starting web")
            self.startweb()

    def run(self, command):
        """
        Runs a command as if from the command-line
        without the need for using popen or subprocess
        """
        if isinstance(command, basestring):
            command = command.split()
        else:
            command = list(command)
        self.external.omero_cli(command)

    def bin(self, command):
        """
        Runs the omero command-line client with an array of arguments using the
        old environment
        """
        if isinstance(command, basestring):
            command = command.split()
        self.external.omero_bin(command)

    def symlink_check_and_set(self):
        """
        The default symlink was changed from OMERO-CURRENT to OMERO.server.
        If `--sym` was not specified and OMERO-CURRENT exists in the current
        directory stop and warn.
        """
        if self.args.sym == '':
            if os.path.exists('OMERO-CURRENT'):
                log.error('Deprecated OMERO-CURRENT found but --sym not set')
                raise Stop(
                    30, 'The default for --sym has changed to OMERO.server '
                    'but the current directory contains OMERO-CURRENT. '
                    'Either remove OMERO-CURRENT or explicity pass --sym.')
        if self.args.sym in ('', 'auto'):
            self.args.sym = 'OMERO.server'
示例#5
0
class Install(object):
    def __init__(self, cmd, args):
        self.args, newinstall = self._handle_args(cmd, args)
        log.info("%s: %s", self.__class__.__name__, cmd)
        log.debug("Current directory: %s", os.getcwd())
        self.symlink_check_and_set()

        if newinstall is None:
            # Automatically install or upgrade
            newinstall = not os.path.exists(args.sym)
        elif newinstall is False:
            if not os.path.exists(args.sym):
                raise Stop(30, 'Symlink is missing: %s' % args.sym)
        elif newinstall is True:
            if os.path.exists(args.sym):
                raise Stop(30, 'Symlink already exists: %s' % args.sym)
        else:
            assert False

        server_dir = self.get_server_dir()

        if newinstall:
            # Create a symlink to simplify the rest of the logic-
            # just need to check if OLD == NEW
            self.symlink(server_dir, args.sym)
            log.info("Installing %s (%s)...", server_dir, args.sym)
        else:
            log.info("Upgrading %s (%s)...", server_dir, args.sym)

        self.external = External(server_dir)
        self.external.setup_omero_cli()

        if not newinstall:
            self.external.setup_previous_omero_env(args.sym, args.savevarsfile)

        # Need lib/python set above
        import path
        self.dir = path.path(server_dir)

        if not newinstall:
            self.stop()
            self.archive_logs()

        copyold = not newinstall and not args.ignoreconfig
        self.configure(copyold, args.prestartfile)
        self.directories()

        self.handle_database()

        self.external.save_env_vars(args.savevarsfile, args.savevars.split())
        self.start()

    def _handle_args(self, cmd, args):
        """
        We need to support deprecated behaviour for now which makes this
        quite complicated

        Current behaviour:
        - install: Installs a new server, existing server causes an error
        - install --upgrade: Installs or upgrades a server
        - install --managedb: Automatically initialise or upgrade the db

        Deprecated:
        - install --upgradedb --initdb: Replaced by install --managedb
        - install --upgradedb: upgrade the db, must exist
        - install --initdb: initialise the db
        - upgrade: Upgrades a server, must already exist
        - upgrade --upgradedb: Automatically upgrade the db

        returns:
        - Modified args object, flag to indicate new/existing/auto install
        """
        if cmd == 'install':
            if args.upgrade:
                # Current behaviour: install or upgrade
                if args.initdb or args.upgradedb:
                    raise Stop(10, ('Deprecated --initdb --upgradedb flags '
                                    'are incompatible with --upgrade'))
                newinstall = None
            else:
                # Current behaviour: Server must not exist
                newinstall = True

            if args.managedb:
                # Current behaviour
                if args.initdb or args.upgradedb:
                    raise Stop(10, ('Deprecated --initdb --upgradedb flags '
                                    'are incompatible with --managedb'))
                args.initdb = True
                args.upgradedb = True
            else:
                if args.initdb or args.upgradedb:
                    log.warn('--initdb and --upgradedb are deprecated, '
                             'use --managedb')

        elif cmd == 'upgrade':
            # Deprecated behaviour
            log.warn(
                '"omero upgrade" is deprecated, use "omego install --upgrade"')
            cmd = 'install'
            args.upgrade = True
            # Deprecated behaviour: Server must exist
            newinstall = False

        else:
            raise Exception('Unexpected command: %s' % cmd)

        return args, newinstall

    def get_server_dir(self):
        """
        Either downloads and/or unzips the server if necessary
        return: the directory of the unzipped server
        """
        if not self.args.server:
            if self.args.skipunzip:
                raise Stop(0, 'Unzip disabled, exiting')

            log.info('Downloading server')

            # The downloader automatically symlinks the server, however if
            # we are upgrading we want to delay the symlink swap, so this
            # overrides args.sym
            # TODO: Find a nicer way to do this?
            artifact_args = copy.copy(self.args)
            artifact_args.sym = ''
            artifacts = Artifacts(artifact_args)
            server = artifacts.download('server')
        else:
            progress = 0
            if self.args.verbose:
                progress = 20
            ptype, server = fileutils.get_as_local_path(
                self.args.server,
                self.args.overwrite,
                progress=progress,
                httpuser=self.args.httpuser,
                httppassword=self.args.httppassword)
            if ptype == 'file':
                if self.args.skipunzip:
                    raise Stop(0, 'Unzip disabled, exiting')
                log.info('Unzipping %s', server)
                server = fileutils.unzip(server,
                                         match_dir=True,
                                         destdir=self.args.unzipdir)

        log.debug('Server directory: %s', server)
        return server

    def stop(self):
        try:
            log.info("Stopping server")
            self.bin("admin status --nodeonly")
            self.bin("admin stop")
        except Exception as e:
            log.error('Error whilst stopping server: %s', e)

        if not self.args.no_web:
            try:
                log.info("Stopping web")
                self.stopweb()
            except Exception as e:
                log.error('Error whilst stopping web: %s', e)

    def configure(self, copyold, prestartfile):
        def samecontents(a, b):
            # os.path.samefile is not available on Windows
            try:
                return os.path.samefile(a, b)
            except AttributeError:
                with open(a) as fa:
                    with open(b) as fb:
                        return fa.read() == fb.read()

        target = self.dir / "etc" / "grid" / "config.xml"

        if copyold:
            from path import path
            old_grid = path(self.args.sym) / "etc" / "grid"
            old_cfg = old_grid / "config.xml"
            log.info("Copying old configuration from %s", old_cfg)
            if not old_cfg.exists():
                raise Stop(40, 'config.xml not found')
            if target.exists() and samecontents(old_cfg, target):
                # This likely is caused by the symlink being
                # created early on an initial install.
                pass
            else:
                old_cfg.copy(target)
        else:
            if target.exists():
                log.info('Deleting configuration file %s', target)
                target.remove()

        if prestartfile:
            for f in prestartfile:
                log.info('Loading prestart file %s', f)
                ftype, fpath = fileutils.get_as_local_path(f, 'backup')
                if ftype != 'file':
                    raise Stop(50, 'Expected file, found: %s %s' % (ftype, f))
                self.run(['load', fpath])

    def archive_logs(self):
        if self.args.archivelogs:
            logdir = os.path.join(self.args.sym, 'var', 'log')
            archive = self.args.archivelogs
            log.info('Archiving logs to %s', archive)
            fileutils.zip(archive, logdir, os.path.join(self.args.sym, 'var'))
            return archive

    def directories(self):
        if self.samedir(self.dir, self.args.sym):
            log.warn("Upgraded server was the same, not deleting")
            return

        try:
            target = self.readlink(self.args.sym)
            targetzip = target + '.zip'
        except IOError:
            log.error('Unable to get symlink target: %s', self.args.sym)
            target = None
            targetzip = None

        if self.args.delete_old and target:
            try:
                log.info("Deleting %s", target)
                shutil.rmtree(target)
            except OSError as e:
                log.error("Failed to delete %s: %s", target, e)

        if not self.args.keep_old_zip and targetzip:
            try:
                log.info("Deleting %s", targetzip)
                os.unlink(targetzip)
            except OSError as e:
                log.error("Failed to delete %s: %s", targetzip, e)

        self.rmlink(self.args.sym)
        self.symlink(self.dir, self.args.sym)

    def handle_database(self):
        """
        Handle database initialisation and upgrade, taking into account
        command line arguments
        """
        # TODO: When initdb and upgradedb are dropped we can just test
        # managedb, but for backwards compatibility we need to support
        # initdb without upgradedb and vice-versa

        if self.args.initdb or self.args.upgradedb:
            db = DbAdmin(self.dir, None, self.args, self.external)
            status = db.check()
            log.debug('OMERO database upgrade status: %s', status)
        else:
            log.warn('OMERO database check disabled')
            return DB_INIT_NEEDED

        if status == DB_INIT_NEEDED:
            if self.args.initdb:
                log.debug('Initialising OMERO database')
                db.init()
            else:
                log.error('OMERO database not found')
                raise Stop(DB_INIT_NEEDED,
                           'Install/Upgrade failed: OMERO database not found')

        elif status == DB_UPGRADE_NEEDED:
            log.warn('OMERO database exists but is out of date')
            if self.args.upgradedb:
                log.debug('Upgrading OMERO database')
                db.upgrade()
            else:
                raise Stop(
                    DB_UPGRADE_NEEDED,
                    'Pass --managedb or upgrade your OMERO database manually')

        else:
            assert status == DB_UPTODATE

        return status

    def start(self):
        if self.args.no_start:
            log.debug('Not starting OMERO')
            return

        self.run("admin start")
        if not self.args.no_web:
            log.info("Starting web")
            self.startweb()

    def run(self, command):
        """
        Runs a command as if from the command-line
        without the need for using popen or subprocess
        """
        if isinstance(command, basestring):
            command = command.split()
        else:
            command = list(command)
        self.external.omero_cli(command)

    def bin(self, command):
        """
        Runs the omero command-line client with an array of arguments using the
        old environment
        """
        if isinstance(command, basestring):
            command = command.split()
        self.external.omero_bin(command)

    def symlink_check_and_set(self):
        """
        The default symlink was changed from OMERO-CURRENT to OMERO.server.
        If `--sym` was not specified and OMERO-CURRENT exists in the current
        directory stop and warn.
        """
        if self.args.sym == '':
            if os.path.exists('OMERO-CURRENT'):
                log.error('Deprecated OMERO-CURRENT found but --sym not set')
                raise Stop(
                    30, 'The default for --sym has changed to OMERO.server '
                    'but the current directory contains OMERO-CURRENT. '
                    'Either remove OMERO-CURRENT or explicity pass --sym.')
        if self.args.sym in ('', 'auto'):
            self.args.sym = 'OMERO.server'