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)
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)
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)
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')
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
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
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
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
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
def __init__(self, client, opts): self.__opts = opts self.__client = client self.__auto_update_timer = None self.__logger = ClientLogger.setup(opts)
def __init__(self, phase=None): #TODO: going to need to pass in opts for clientLogger self.__logger = ClientLogger.setup(phase=phase)