def self_register_service(config): """An example of using the Boston Dynamics API to self register a service using payload auth. This function represents code that would run directly on a payload to set itself up. It registers a single leaf service without access to a pre-existing credentials. """ # Create an sdk and robot instance. sdk = bosdyn.client.create_standard_sdk('SelfRegisterServiceExampleClient') robot = sdk.create_robot(config.hostname) # Authenticate by using the credentials of a registered & authorized payload. robot.authenticate_from_payload_credentials(config.guid, config.secret) # Create the directory registration client after getting the user token. directory_registration_client = robot.ensure_client( DirectoryRegistrationClient.default_service_name) # Create a keep_alive to reset and maintain registration of service. keep_alive = DirectoryRegistrationKeepAlive(directory_registration_client) keep_alive.start(DIRECTORY_NAME, SERVICE_TYPE, AUTHORITY, config.host_ip, config.port) # List all services. Success if above test service is shown. directory_client = robot.ensure_client( DirectoryClient.default_service_name) try: registered_service = directory_client.get_entry(DIRECTORY_NAME) except NonexistentServiceError: print('\nSelf-registered service not found. Failure.') return False print('\nService registration confirmed. Self-registration was a success.') return True
def liveness_faulting(robot): """Force ServiceFaults to be raised indirectly via the directory registration liveness.""" # Set up robot state client robot_state_client = robot.ensure_client( RobotStateClient.default_service_name) # Set up directory client directory_client = robot.ensure_client( DirectoryClient.default_service_name) # Set up a directory registration client. directory_registration_client = robot.ensure_client( DirectoryRegistrationClient.default_service_name) # Unregister the service if it already exists try: directory_registration_client.unregister(kServiceName) # Wait for a few seconds to give old liveness faults a chance to clear themselves. time.sleep(2) except: pass # Use keep alive helper class to maintain liveness with repeated registration/update requests. directory_keep_alive = DirectoryRegistrationKeepAlive( directory_registration_client, rpc_interval_seconds=kKeepAliveIntervalSecs) directory_keep_alive.start(kServiceName, kServiceType, kServiceAuthority, kServiceIp, kServicePort, kTimeoutSecs) # Verify the service is listed services = directory_client.list() for service in services: if service.name == kServiceName: print('Service registration confirmed with liveness timeout == ' + str(service.liveness_timeout_secs)) # Continually display ServiceFaults. Should not see liveness fault from service_name print( '\n\n\nHeartbeat thread is active. Should not see liveness fault from ' + kServiceName + ':') watch_service_fault_state(robot_state_client, 8) # Stop the service and display ServiceFaults. New liveness fault from service_name should appear. print( '\n\n\nHeartbeat thread is shutting down. Expect liveness faults from ' + kServiceName + ':') directory_keep_alive.shutdown() watch_service_fault_state(robot_state_client, 8) # Start a keep alive again, which should re-establish liveness and automatically clear the liveness fault. # Unregistering the service will also automatically clear liveness faults. print('\n\n\nHeartbeat thread is starting again. Expect ' + kServiceName + ' liveness faults to clear') directory_keep_alive_2 = DirectoryRegistrationKeepAlive( directory_registration_client, rpc_interval_seconds=kKeepAliveIntervalSecs) directory_keep_alive_2.start(kServiceName, kServiceType, kServiceAuthority, kServiceIp, kServicePort, kTimeoutSecs) watch_service_fault_state(robot_state_client, 4)
def test_keep_alive(default_service_entry, default_service_endpoint): client, service, server = _setup() keepalive = DirectoryRegistrationKeepAlive(client) name = default_service_entry.name assert name not in service.service_entries keepalive.start(name, default_service_entry.type, default_service_entry.authority, default_service_endpoint.host_ip, default_service_endpoint.port) assert name in service.service_entries with keepalive: # Just have some statement inside the "with" context. assert service.service_entries[name] == default_service_entry # Now that we've exited the "with" block, the internal thread should have ended and the service # should be unregistered. assert not keepalive.is_alive() assert name not in service.service_entries
def test_keep_alive_update(default_service_entry, default_service_endpoint): client, service, server = _setup() interval_seconds = 0.1 keepalive = DirectoryRegistrationKeepAlive(client, rpc_interval_seconds=interval_seconds) name = default_service_entry.name assert name not in service.service_entries client.register(default_service_entry.name, default_service_entry.type, default_service_entry.authority, default_service_endpoint.host_ip, default_service_endpoint.port) new_authority = default_service_entry.authority + 'woo-hoo' keepalive.start(name, default_service_entry.type, new_authority, default_service_endpoint.host_ip, default_service_endpoint.port) assert service.service_entries[name].authority == new_authority # Make sure the thread is still alive after a few loops. time.sleep(interval_seconds * 3) assert keepalive.is_alive()
def register_with_robot(options): """ Registers this worker with the robot's Directory.""" ip = bosdyn.client.common.get_self_ip(options.hostname) print('Detected IP address as: ' + ip) kServiceName = "fire-extinguisher-server" kServiceTypeName = "bosdyn.api.NetworkComputeBridgeWorker" kServiceAuthority = "fire-extinguisher-worker.spot.robot" sdk = bosdyn.client.create_standard_sdk("retinanet-server") robot = sdk.create_robot(options.hostname) # Authenticate robot before being able to use it if options.on_spot_core: guid, secret = get_guid_and_secret() robot.authenticate_from_payload_credentials(guid, secret) else: robot.authenticate(options.username, options.password) directory_client = robot.ensure_client( bosdyn.client.directory.DirectoryClient.default_service_name) directory_registration_client = robot.ensure_client( bosdyn.client.directory_registration.DirectoryRegistrationClient.default_service_name) # Create a keep_alive to reset and maintain registration of service. keep_alive = DirectoryRegistrationKeepAlive(directory_registration_client) keep_alive.start(kServiceName, kServiceTypeName, kServiceAuthority, ip, int(options.port)) # List all services. Success if above test service is shown. try: registered_service = directory_client.get_entry(kServiceName) except NonexistentServiceError: print('\nSelf-registered service not found. Failure.') return False print('\nService registration confirmed. Self-registration was a success.') return True
service_runner = run_service(options.port, logger=_LOGGER) print('{} service running.\nCtrl + C to shutdown.'.format( DIRECTORY_NAME)) service_runner.run_until_interrupt() sys.exit('Shutting down {} service'.format(DIRECTORY_NAME)) # Else if a robot is available, register the service with the robot so that all clients can # access it through the robot directory without knowledge of the service IP or port. # Setup logging to use either INFO level or DEBUG level. setup_logging(options.verbose) # Create and authenticate a bosdyn robot object. sdk = bosdyn.client.create_standard_sdk("HelloWorldMissionServiceSDK") robot = sdk.create_robot(options.hostname) robot.authenticate(options.username, options.password) # Create a service runner to start and maintain the service on background thread. service_runner = run_service(options.port, logger=_LOGGER) # Use a keep alive to register the service with the robot directory. dir_reg_client = robot.ensure_client( DirectoryRegistrationClient.default_service_name) keep_alive = DirectoryRegistrationKeepAlive(dir_reg_client, logger=_LOGGER) keep_alive.start(DIRECTORY_NAME, SERVICE_TYPE, AUTHORITY, options.host_ip, service_runner.port) # Attach the keep alive to the service runner and run until a SIGINT is received. with keep_alive: service_runner.run_until_interrupt()
if __name__ == '__main__': # Define all arguments used by this service. import argparse parser = argparse.ArgumentParser() bosdyn.client.util.add_base_arguments(parser) bosdyn.client.util.add_payload_credentials_arguments(parser) bosdyn.client.util.add_service_endpoint_arguments(parser) options = parser.parse_args() # Setup logging to use either INFO level or DEBUG level. setup_logging(options.verbose) # Create and authenticate a bosdyn robot object. sdk = bosdyn.client.create_standard_sdk("PiksiMetadataPluginServiceSDK") robot = sdk.create_robot(options.hostname) robot.authenticate_from_payload_credentials(options.guid, options.secret) # Create a service runner to start and maintain the service on background thread. service_runner = run_service(robot, options.port, logger=_LOGGER) # Use a keep alive to register the service with the robot directory. dir_reg_client = robot.ensure_client( DirectoryRegistrationClient.default_service_name) keep_alive = DirectoryRegistrationKeepAlive(dir_reg_client, logger=_LOGGER) keep_alive.start(DIRECTORY_NAME, DataAcquisitionPluginService.service_type, AUTHORITY, options.host_ip, service_runner.port) # Attach the keep alive to the service runner and run until a SIGINT is received. with keep_alive: service_runner.run_until_interrupt()
def main(server): parser = argparse.ArgumentParser() bosdyn.client.util.add_common_arguments(parser) parser.add_argument('--my-host', help='Address to register into the directory with') parser.add_argument( '--directory-host', help= 'Host running the directory service. Omit to skip directory registration' ) parser.add_argument( '--port', default=0, type=int, help='Listening port for server. Omit to choose a port at random') parser.add_argument('--servicer', default='HelloWorld', help='Type of servicer to launch.') options = parser.parse_args() sdk = bosdyn.client.create_standard_sdk('run-mission-service') sdk.load_app_token(options.app_token) level = logging.DEBUG if options.verbose else logging.INFO logging.basicConfig(level=level, format='%(message)s (%(filename)s:%(lineno)d)') logger = logging.getLogger() # Map options.servicer to a function that will build the appropriate instance. string_to_servicer = { 'HelloWorld': lambda: HelloWorldServicer(logger), 'PowerOff': lambda: PowerOffServicer(logger, sdk, options.hostname, options. username, options.password) } # Build whatever service the user specified. servicer = string_to_servicer[options.servicer]() # Start the server, talking over an insecure channel. remote_service_pb2_grpc.add_RemoteMissionServiceServicer_to_server( servicer, server) port = server.add_insecure_port('[::]:{}'.format(options.port)) server.start() logger.info('Starting server on port %i', port) dir_keepalive = None # If a directory host was specified, register with the directory there. # This will often be the robot. For example, if this program is running on a payload computer # like the Spot CORE, directory_host would be 192.168.50.3. # Registering with the directory will be important when running with a robot, but it's useful # to skip directory registration when you're just testing your service locally. if options.directory_host: # Register with the directory. robot = sdk.create_robot(options.directory_host) robot.authenticate(options.username, options.password) dir_reg_client = robot.ensure_client( DirectoryRegistrationClient.default_service_name) dir_keepalive = DirectoryRegistrationKeepAlive(dir_reg_client, logger=logger) dir_keepalive.start(SERVICE_NAME_IN_DIRECTORY, SERVICE_TYPE, AUTHORITY, options.my_host, port) try: # Nothing for this thread to do. The server / servicer pair handles all incoming # requests. while not _STOP_RUNNING.wait(1): pass except KeyboardInterrupt: logger.info('Cancelled by keyboard interrupt') if dir_keepalive: dir_keepalive.shutdown() dir_keepalive.unregister() logger.info('Stopping server.') return 0
def main(): """Main remote mission service function""" parser = argparse.ArgumentParser( description=__doc__, formatter_class=argparse.ArgumentDefaultsHelpFormatter) bosdyn.client.util.add_common_arguments(parser) parser.add_argument('--my-host', help='Address to register into the directory with') parser.add_argument( '--directory-host', help= 'Host running the directory service. Omit to skip directory registration' ) parser.add_argument( '--port', default=0, type=int, help='Listening port for server. Omit to choose a port at random') parser.add_argument('--theta-client', dest='theta_client', action='store_true', help='Use theta client or direct mode ip settings') parser.add_argument('--payload-token', dest='payload_token', action='store_true', help='Use limited-access user token') options = parser.parse_args() level = logging.DEBUG if options.verbose else logging.INFO logging.basicConfig(level=level, format='%(message)s (%(filename)s:%(lineno)d)') logger = logging.getLogger() sdk = bosdyn.client.create_standard_sdk('run-ricoh-service') guid = None secret = None if options.payload_token: guid, secret = get_guid_and_secret() server = grpc.server(futures.ThreadPoolExecutor()) service = RicohThetaServicer(logger, options.theta_client) remote_service_pb2_grpc.add_RemoteMissionServiceServicer_to_server( service, server) port = server.add_insecure_port('[::]:{}'.format(options.port)) server.start() logger.info('Starting server on port %i', port) dir_keepalive = None if options.directory_host: robot = sdk.create_robot(options.directory_host) # Check authentication method if guid: payload_registration_client = robot.ensure_client( PayloadRegistrationClient.default_service_name) limited_token = payload_registration_client.get_payload_auth_token( guid, secret) robot.update_user_token(limited_token) else: robot.authenticate(options.username, options.password) # Register with the directory dir_reg_client = robot.ensure_client( DirectoryRegistrationClient.default_service_name) dir_keepalive = DirectoryRegistrationKeepAlive(dir_reg_client, logger=logger) dir_keepalive.start(DIRECTORY_NAME, SERVICE_TYPE, AUTHORITY, options.my_host, port) try: while True: # Nothing for this thread to do. time.sleep(100) except KeyboardInterrupt: logger.info('Cancelled by keyboard interrupt') if dir_keepalive: dir_keepalive.shutdown() dir_keepalive.unregister() logger.info('Stopping server.') # Stop with no grace period. shutdown_complete = server.stop(None) # Wait up to 1 second for a clean shutdown. shutdown_complete.wait(1) return 0
if options.on_spot_core: guid, secret = get_guid_and_secret() robot.authenticate_from_payload_credentials(guid, secret) else: if not options.guid or not options.secret: _LOGGER.error('GUID and secret need to both be specified.') exit(1) else: robot.authenticate_from_payload_credentials( options.guid, options.secret) robot.sync_with_directory() # Create a service runner to start and maintain the service on background thread. service_runner = run_service(robot, options.port, options.worker_name, logger=_LOGGER) # Set up the directory name. The name must have the pattern data-acquisition-XXX-plugin. directory_name = get_directory_name(options.worker_name) # Use a keep alive to register the service with the robot directory. dir_reg_client = robot.ensure_client( DirectoryRegistrationClient.default_service_name) keep_alive = DirectoryRegistrationKeepAlive(dir_reg_client, logger=_LOGGER) keep_alive.start(directory_name, DataAcquisitionPluginService.service_type, AUTHORITY, self_ip, service_runner.port) # Attach the keep alive to the service runner and run until a SIGINT is received. with keep_alive: service_runner.run_until_interrupt()