예제 #1
0
    def stop(opts, args):
        logger = ClientLogger.setup(opts)
        pid_file = opts.get(ClientOption.PID_FILE)
        logout_coast_time = opts.get(ClientOption.LOGOUT_COAST_TIME)

        try:
            for process_id in ClientDaemon.__get_process_ids():
                try:
                    os.kill(process_id, signal.SIGTERM)
                except Exception as e:
                    logger.exception(e)
        except CalledProcessError:
            pass

        # Wait for what we assume will be a graceful exit,
        # this will exit early if the pid file is removed as expected.
        current = time.time()
        max_wait_time = logout_coast_time + 5
        while time.time() - current < max_wait_time and os.path.isfile(pid_file):
            time.sleep(0.1)

        # This should never happen, but... if the pid file still exist at this point, we will nuke it from orbit!
        # Otherwise it will prevent the client daemon from starting again...
        if os.path.isfile(pid_file):
            try:
                os.remove(pid_file)
            except Exception as e:
                logger.exception(e)
예제 #2
0
def run():
    if os.geteuid() != 0:
        sys.stdout.write(
            'You need to have root privileges to run {0} commands.\n'
            'Please try again, this time using \'sudo\'.\n'.format(
                PackageInfo.pip_package_name))
        sys.stdout.flush()
        sys.exit(1)

    (opts, args) = ClientOptionParser().parse_args()
    logger = ClientLogger.setup(opts)

    try:
        with CommandHandler(opts, args) as handler:
            handler.on(Command.STOP, ClientDaemon.stop)
            handler.on(Command.START, __handle_start_command)
            handler.on(Command.STATUS, __handle_status_command)
            handler.on(Command.UPDATE, __handle_update_command)
            handler.on(Command.REMOVE, ClientDaemon.remove)
            handler.on(Command.RESTART, ClientDaemon.restart)
            return handler.handle_command()

    except Exception as e:
        logger.exception(e)
        sys.stdout.write(str(e))
        sys.stdout.flush()
        sys.exit(1)
예제 #3
0
    def __init__(self, install_lib):
        self.__logger = ClientLogger.setup(phase='install')
        self.__command_executor = CommandExecutor(phase='install')

        self.__install_lib = install_lib
        self.__service_link = "/etc/init.d/{0}".format(
            PackageInfo.pip_package_name)
        self.__service_script = '{0}{1}/Service.py'.format(
            install_lib, PackageInfo.python_package_name)
예제 #4
0
    def __init__(self, device=None, opts=None):
        self.__opts = opts
        self.__device = device
        self.__user_info = None
        self.__logout_timer = None
        self.__logger = ClientLogger.setup(opts)
        self.__tinkerAccessServerApi = TinkerAccessServerApi(opts)

        states = []
        for key, value in vars(State).items():
            if not key.startswith('__'):
                states.append(value)

        transitions = [
            {
                'source': [State.INITIALIZED],
                'trigger': Trigger.IDLE,
                'dest': State.IDLE
            },

            {
                'source': [State.IDLE],
                'trigger': Trigger.LOGIN,
                'dest': State.IN_USE,
                'conditions': ['is_authorized']
            },

            {
                'source': [State.IN_USE],
                'trigger': Trigger.LOGIN,
                'dest': State.IN_USE,
                'conditions': ['should_extend_current_session']
            },

            {
                'source': [State.IN_USE, State.IN_TRAINING],
                'trigger': Trigger.LOGOUT,
                'dest': State.IDLE
            },

            {
                'source': [State.IDLE],
                'trigger': Trigger.LOGOUT,
                'dest': State.IN_TRAINING,
                'conditions': ['is_waiting_for_training']
            },

            {
                'source': '*',
                'trigger': Trigger.TERMINATE,
                'dest': State.TERMINATED
            }
        ]

        Machine.__init__(self, queued=True, states=states,
                         transitions=transitions, initial=State.INITIALIZED, after_state_change='update_status')
예제 #5
0
    def update(opts, args):
        if not ClientDaemon.__is_in_use(opts, args):
            logger = ClientLogger.setup(opts)
            requested_version = args[1] if len(args) >= 2 else None
            if ClientDaemon.__should_update(opts, requested_version):
                try:
                    requested_package = PackageInfo.pip_package_name

                    # BUG: There is a big fat bug with pip that is causing it to redirect to
                    # install the latest version, even when a specific version is installed.
                    # I'll look into this when I get time.

                    if requested_version:
                        requested_package = '{0}=={1}'.format(requested_package, requested_version)

                    ClientDaemon.stop(opts, args)
                    CommandExecutor().execute_commands([
                        'pip install --upgrade --force-reinstall --ignore-installed --no-cache-dir {0}'
                        .format(requested_package)
                    ])
                except Exception as e:
                    msg = '{0} update failed, remediation maybe required!'.format(PackageInfo.pip_package_name)
                    logger.error(msg)
                    logger.exception(e)
                    raise e
                finally:
                    if not ClientDaemon.status(opts, args):
                        ClientDaemon.restart(opts, args)
            else:

                force_update_hint = 'Use the --force-update option to bypass ' \
                                    'the version check and re-install from PyPi.\n'\
                                    .format(
                                        PackageInfo.pip_package_name,
                                        PackageInfo.version
                                    )

                if not PackageInfo.version:
                    return [
                        'You are currently using a non-versioned build...\n',
                        force_update_hint
                    ], 1

                version = 'latest' if not requested_version else 'requested'
                return [
                    '{0} v{1} already matches the {2} version. \n'
                    'Use the --force-update option to bypass the version check and re-install.\n'.format(
                        PackageInfo.pip_package_name,
                        PackageInfo.version,
                        version
                    )], 1
        else:
            return ['{0} is currently in use, try again later...\n'.format(PackageInfo.pip_package_name)], 1
예제 #6
0
    def run(opts, args):
        logger = ClientLogger.setup(opts)
        reboot_delay = opts.get(ClientOption.REBOOT_DELAY) * 60
        reboot_on_error = opts.get(ClientOption.REBOOT_ON_ERROR)

        try:
            with DeviceApi(opts) as device, \
                    Client(device, opts) as client, \
                    AutoUpdateTimer(client, opts) as auto_update_timer:

                device.on(
                    Channel.SERIAL,
                    direction=device.GPIO.IN,
                    call_back=client.handle_badge_code
                )

                device.on(
                    Channel.PIN,
                    pin=opts.get(ClientOption.PIN_LOGOUT),
                    direction=device.GPIO.RISING,
                    call_back=client.logout
                )

                client.idle()
                auto_update_timer.start()
                while not client.is_terminated():
                    logger.debug('%s is waiting...', PackageInfo.pip_package_name)
                    client.wait()

        except (KeyboardInterrupt, SystemExit) as e:
            pass

        except Exception as e:
            logger.exception(e)

            if reboot_on_error:

                # reboot is only supported on Raspberry PI devices
                # noinspection PyBroadException
                try:
                    # noinspection PyUnresolvedReferences
                    import RPi.GPIO
                    logger.error('Rebooting in %s minutes...', reboot_delay / 60)
                    CommandExecutor().execute_commands([
                        'sleep {0}s'.format(reboot_delay),
                        'reboot now'
                    ])
                except Exception:
                    pass
예제 #7
0
    def __should_update(opts, requested_version=None):
        logger = ClientLogger.setup(opts)
        try:
            if opts.get(ClientOption.FORCE_UPDATE):
                return True

            current_version = PackageInfo.version
            if current_version:
                if not requested_version:
                    return current_version != ClientDaemon.__get_latest_version_from_pypi()

                requested_version = '.'.join([s.zfill(2) for s in requested_version.split('.')])
            return current_version != requested_version
        except Exception as e:
            logger.exception(e)
        return False
예제 #8
0
 def restart(opts, args):
     logger = ClientLogger.setup(opts)
     reboot_delay = opts.get(ClientOption.REBOOT_DELAY)
     logout_coast_time = opts.get(ClientOption.LOGOUT_COAST_TIME)
     try:
         args[0] = Command.STOP.get('command')
         ClientDaemon.stop(opts, args)
         time.sleep(logout_coast_time)
         logger.debug('Restarting in %s seconds...', reboot_delay)
         time.sleep(reboot_delay)
         args[0] = Command.START.get('command')
         ClientDaemon.start(opts, args)
     except Exception as e:
         msg = '{0} restart failed.'.format(PackageInfo.pip_package_name)
         logger.error(msg)
         logger.exception(e)
         raise e
예제 #9
0
    def start(opts, args):
        logger = ClientLogger.setup(opts)
        if not ClientDaemon.status(opts, args):
            pid_file = opts.get(ClientOption.PID_FILE)
            foreground = opts.get(ClientOption.DEBUG)

            def start():
                Client.run(opts, args)

            daemon = Daemonize(
                app=PackageInfo.pip_package_name,
                pid=pid_file,
                action=start,
                foreground=foreground,
                verbose=True,
                logger=logger,
                auto_close_fds=False
            )
            daemon.start()
            return [], 0
        else:
            return ['{0} is already running...\n'.format(PackageInfo.pip_package_name)], 1
예제 #10
0
 def __init__(self, client, opts):
     self.__opts = opts
     self.__client = client
     self.__auto_update_timer = None
     self.__logger = ClientLogger.setup(opts)
예제 #11
0
 def __init__(self, phase=None):
     #TODO: going to need to pass in opts for clientLogger
     self.__logger = ClientLogger.setup(phase=phase)