def __init__(self, ip, port, api_token, need_human_ob=False, max_containable_step=10, logfile_path='./', debug=False): self.grpc_client = GrpcClient(ip, port, api_token, logfile_path, debug) self.need_human_ob = need_human_ob self.max_containable_step = max_containable_step self._frame_period = self.grpc_client.get_system_info().frame_period self._last_action_frame = 0 self._refresh_obs = RefreshObservation(self.grpc_client, need_human_ob) self._action_space = None self._reincarnation_flag = True
def get_vcore_subscription(self): log.debug('start-get-vcore-subscription') while self.running and self.subscription is None: try: # If a subscription is not yet assigned then establish new GRPC connection # ... otherwise keep using existing connection details if self.subscription is None: self._assign_grpc_attributes() # Send subscription request to register the current ofagent instance container_name = self.instance_id if self.grpc_client is None: self.grpc_client = GrpcClient(self, self.channel, self.grpc_timeout, self.core_binding_key, self.core_transaction_key) subscription = yield self.grpc_client.subscribe( OfAgentSubscriber(ofagent_id=container_name)) # If the subscriber id matches the current instance # ... then the subscription has succeeded if subscription is not None and subscription.ofagent_id == container_name: if self.subscription is None: # Keep details on the current GRPC session and subscription log.debug('subscription-with-vcore-successful', subscription=subscription) self.subscription = subscription self.grpc_client.start() # Sleep a bit in between each subscribe yield asleep(self.subscription_refresh_interval) # Move on to next subscribe request continue # The subscription did not succeed, reset and move on else: log.info('subscription-with-vcore-unavailable', subscription=subscription) except _Rendezvous, e: log.error('subscription-with-vcore-terminated', exception=e, status=e.code()) except Exception as e: log.exception('unexpected-subscription-termination-with-vcore', e=e)
def __init__(self, ip, port, api_token, need_human_ob=False, max_containable_step=10, logfile_path='./', debug=False): self.grpc_client = GrpcClient(ip, port, api_token, logfile_path, debug) self._check_frame = CheckFrame(self.grpc_client, need_human_ob) self.need_human_ob = need_human_ob self.last_action_frame = 0 self.max_containable_step = max_containable_step self._action_space = None self._reincarnation_flag = True
def start(self): if self.running: return log.debug('starting') self.running = True # Get voltha grpc endpoint self.channel = self.get_grpc_channel_with_voltha() # Create shared gRPC API object self.grpc_client = GrpcClient(self, self.channel).start() # Start monitoring logical devices and manage agents accordingly reactor.callLater(0, self.monitor_logical_devices) log.info('started') return self
class ConnectionManager(object): def __init__(self, consul_endpoint, vcore_endpoint, vcore_grpc_timeout, vcore_binding_key, vcore_transaction_key, controller_endpoints, instance_id, enable_tls=False, key_file=None, cert_file=None, vcore_retry_interval=0.5, devices_refresh_interval=5, subscription_refresh_interval=5): log.info('init-connection-manager') log.info('list-of-controllers', controller_endpoints=controller_endpoints) self.controller_endpoints = controller_endpoints self.consul_endpoint = consul_endpoint self.vcore_endpoint = vcore_endpoint self.grpc_timeout = vcore_grpc_timeout self.core_binding_key = vcore_binding_key self.core_transaction_key = vcore_transaction_key self.instance_id = instance_id self.enable_tls = enable_tls self.key_file = key_file self.cert_file = cert_file self.channel = None self.grpc_client = None # single, shared gRPC client to vcore self.agent_map = {} # (datapath_id, controller_endpoint) -> Agent() self.device_id_to_datapath_id_map = {} self.vcore_retry_interval = vcore_retry_interval self.devices_refresh_interval = devices_refresh_interval self.subscription_refresh_interval = subscription_refresh_interval self.subscription = None self.running = False def start(self): if self.running: return log.debug('starting') self.running = True # Get a subscription to vcore reactor.callInThread(self.get_vcore_subscription) # Start monitoring logical devices and manage agents accordingly reactor.callLater(0, self.monitor_logical_devices) log.info('started') return self def stop(self): log.debug('stopping') # clean up all controller connections for agent in self.agent_map.itervalues(): agent.stop() self.running = False self._reset_grpc_attributes() log.info('stopped') def resolve_endpoint(self, endpoint): ip_port_endpoint = endpoint if endpoint.startswith('@'): try: ip_port_endpoint = get_endpoint_from_consul( self.consul_endpoint, endpoint[1:]) log.info('{}-service-endpoint-found'.format(endpoint), address=ip_port_endpoint) except Exception as e: log.error('{}-service-endpoint-not-found'.format(endpoint), exception=repr(e)) log.error('committing-suicide') # Committing suicide in order to let docker restart ofagent os.system("kill -15 {}".format(os.getpid())) if ip_port_endpoint: host, port = ip_port_endpoint.split(':', 2) return host, int(port) def _reset_grpc_attributes(self): log.debug('start-reset-grpc-attributes') if self.grpc_client is not None: self.grpc_client.stop() if self.channel is not None: del self.channel self.is_alive = False self.channel = None self.subscription = None self.grpc_client = None log.debug('stop-reset-grpc-attributes') def _assign_grpc_attributes(self): log.debug('start-assign-grpc-attributes') host, port = self.resolve_endpoint(self.vcore_endpoint) log.info('revolved-vcore-endpoint', endpoint=self.vcore_endpoint, host=host, port=port) assert host is not None assert port is not None # Establish a connection to the vcore GRPC server self.channel = grpc.insecure_channel('{}:{}'.format(host, port)) self.is_alive = True log.debug('stop-assign-grpc-attributes') @inlineCallbacks def get_vcore_subscription(self): log.debug('start-get-vcore-subscription') while self.running and self.subscription is None: try: # If a subscription is not yet assigned then establish new GRPC connection # ... otherwise keep using existing connection details if self.subscription is None: self._assign_grpc_attributes() # Send subscription request to register the current ofagent instance container_name = self.instance_id if self.grpc_client is None: self.grpc_client = GrpcClient(self, self.channel, self.grpc_timeout, self.core_binding_key, self.core_transaction_key) subscription = yield self.grpc_client.subscribe( OfAgentSubscriber(ofagent_id=container_name)) # If the subscriber id matches the current instance # ... then the subscription has succeeded if subscription is not None and subscription.ofagent_id == container_name: if self.subscription is None: # Keep details on the current GRPC session and subscription log.debug('subscription-with-vcore-successful', subscription=subscription) self.subscription = subscription self.grpc_client.start() # Sleep a bit in between each subscribe yield asleep(self.subscription_refresh_interval) # Move on to next subscribe request continue # The subscription did not succeed, reset and move on else: log.info('subscription-with-vcore-unavailable', subscription=subscription) except _Rendezvous, e: log.error('subscription-with-vcore-terminated', exception=e, status=e.code()) except Exception as e: log.exception('unexpected-subscription-termination-with-vcore', e=e) # Reset grpc details # The vcore instance is either not available for subscription # or a failure occurred with the existing communication. self._reset_grpc_attributes() # Sleep for a short period and retry yield asleep(self.vcore_retry_interval)
class GameEnvironment: def __init__(self, ip, port, api_token, need_human_ob=False, max_containable_step=10, logfile_path='./', debug=False): self.grpc_client = GrpcClient(ip, port, api_token, logfile_path, debug) self.need_human_ob = need_human_ob self.max_containable_step = max_containable_step self._frame_period = self.grpc_client.get_system_info().frame_period self._last_action_frame = 0 self._refresh_obs = RefreshObservation(self.grpc_client, need_human_ob) self._action_space = None self._reincarnation_flag = True def create_room(self, password): rsp = self.grpc_client.create_room(password) if rsp.err_code == 0: self._refresh_obs.start() return rsp.room_id, rsp.state else: return None def join_room(self, room_id, password): rsp = self.grpc_client.join_room(room_id, password) if rsp.err_code == 0: self._refresh_obs.start() return rsp.state else: return None def get_action_space(self): if self._action_space is None: self._action_space = self.grpc_client.get_action_space() return self._action_space.move, self._action_space.swing, self._action_space.fire, self._action_space.apply def get_inform(self): inform = self.grpc_client.get_inform() return inform.score, inform.kills, inform.health, inform.state, inform.frame_index def get_frame_period(self): return self._frame_period def submit_reincarnation(self): rsp = self.grpc_client.submit_reincarnation() if rsp.err_code == 0: return rsp.state else: return None def submit_action(self, frame, move, swing, fire, apply): """read""" frame_lock.acquire_read() current_frame = frame_index frame_lock.release() if self._last_action_frame < frame and frame > current_frame - self.max_containable_step: rsp = self.grpc_client.submit_action(move, swing, fire, apply) if rsp.err_code == 0: self._last_action_frame = frame return rsp.state else: return None else: return None def get_observation_with_info(self): """read""" observation_lock.acquire_read() state = observation_state location = location_observation immutable_element = immutable_element_observation mutable_element = mutable_element_observation bodies = bodies_observation asset_ownership = asset_ownership_observation self_asset = self_asset_observation self_status = self_status_observation pointer = pointer_observation human = human_observation observation_lock.release() frame_lock.acquire_read() frame = frame_index frame_lock.release() inform_lock.acquire_read() score = score_inform kill = kill_inform heath = heath_inform inform_lock.release() if self.need_human_ob: return frame, \ state, \ location, \ immutable_element, \ mutable_element, \ bodies, \ asset_ownership, \ self_asset, \ self_status, \ pointer, \ human, \ score, \ kill, \ heath else: return frame, \ state, \ location, \ immutable_element, \ mutable_element, \ bodies, \ asset_ownership, \ self_asset, \ self_status, \ pointer, \ score, \ kill, \ heath def get_move_meanings(self): return [MOVE_MEANING[i] for i in self._action_space.move] def show_image(self, image, height=100, width=200): plt.close('all') image_array = np.array(image).reshape(height, width) plt.imshow(image_array, cmap='gray') plt.show() @staticmethod def get_state_meanings(): return STATE_MEANING
class ConnectionManager(object): def __init__(self, consul_endpoint, voltha_endpoint, controller_endpoints, voltha_retry_interval=0.5, devices_refresh_interval=5): log.info('init-connection-manager') log.info('list-of-controllers', controller_endpoints=controller_endpoints) self.controller_endpoints = controller_endpoints self.consul_endpoint = consul_endpoint self.voltha_endpoint = voltha_endpoint self.channel = None self.grpc_client = None # single, shared gRPC client to Voltha self.agent_map = {} # (datapath_id, controller_endpoint) -> Agent() self.device_id_to_datapath_id_map = {} self.voltha_retry_interval = voltha_retry_interval self.devices_refresh_interval = devices_refresh_interval self.running = False def start(self): if self.running: return log.debug('starting') self.running = True # Get voltha grpc endpoint self.channel = self.get_grpc_channel_with_voltha() # Create shared gRPC API object self.grpc_client = GrpcClient(self, self.channel).start() # Start monitoring logical devices and manage agents accordingly reactor.callLater(0, self.monitor_logical_devices) log.info('started') return self def stop(self): log.debug('stopping') # clean up all controller connections for agent in self.agent_map.itervalues(): agent.stop() self.running = False self.grpc_client.stop() del self.channel log.info('stopped') def resolve_endpoint(self, endpoint): ip_port_endpoint = endpoint if endpoint.startswith('@'): try: ip_port_endpoint = get_endpoint_from_consul( self.consul_endpoint, endpoint[1:]) log.info('Found endpoint {} service at {}'.format( endpoint, ip_port_endpoint)) except Exception as e: log.error('Failure to locate {} service from ' 'consul {}:'.format(endpoint, repr(e))) log.error('Committing suicide...') # Committing suicide in order to let docker restart ofagent os.system("kill -15 {}".format(os.getpid())) if ip_port_endpoint: host, port = ip_port_endpoint.split(':', 2) return host, int(port) def get_grpc_channel_with_voltha(self): log.info('Resolving voltha endpoint {} from consul'.format( self.voltha_endpoint)) host, port = self.resolve_endpoint(self.voltha_endpoint) assert host is not None assert port is not None # Create grpc channel to Voltha channel = grpc.insecure_channel('{}:{}'.format(host, port)) log.info('Acquired a grpc channel to voltha') return channel @inlineCallbacks def get_list_of_logical_devices_from_voltha(self): while True: log.info('Retrieve devices from voltha') try: stub = voltha_pb2.VolthaLocalServiceStub(self.channel) devices = stub.ListLogicalDevices(Empty()).items for device in devices: log.info("Devices {} -> {}".format(device.id, device.datapath_id)) returnValue(devices) except _Rendezvous, e: if e.code() == StatusCode.UNAVAILABLE: os.system("kill -15 {}".format(os.getpid())) except Exception as e: log.error('Failure to retrieve devices from ' 'voltha: {}'.format(repr(e))) log.info('reconnect', after_delay=self.voltha_retry_interval) yield asleep(self.voltha_retry_interval)
class ConnectionManager(object): def __init__(self, consul_endpoint, voltha_endpoint, controller_endpoint, voltha_retry_interval=0.5, devices_refresh_interval=5): log.info('init-connection-manager') self.controller_endpoint = controller_endpoint self.consul_endpoint = consul_endpoint self.voltha_endpoint = voltha_endpoint self.channel = None self.grpc_client = None # single, shared gRPC client to Voltha self.agent_map = {} # datapath_id -> Agent() self.device_id_to_datapath_id_map = {} self.voltha_retry_interval = voltha_retry_interval self.devices_refresh_interval = devices_refresh_interval self.running = False def start(self): if self.running: return log.debug('starting') self.running = True # Get voltha grpc endpoint self.channel = self.get_grpc_channel_with_voltha() # Create shared gRPC API object self.grpc_client = GrpcClient(self, self.channel).start() # Start monitoring logical devices and manage agents accordingly reactor.callLater(0, self.monitor_logical_devices) log.info('started') return self def stop(self): log.debug('stopping') # clean up all controller connections for agent in self.agent_map.itervalues(): agent.stop() self.running = False self.grpc_client.stop() del self.channel log.info('stopped') def resolve_endpoint(self, endpoint): ip_port_endpoint = endpoint if endpoint.startswith('@'): try: ip_port_endpoint = get_endpoint_from_consul( self.consul_endpoint, endpoint[1:]) log.info('Found endpoint {} service at {}'.format( endpoint, ip_port_endpoint)) except Exception as e: log.error('Failure to locate {} service from ' 'consul {}:'.format(endpoint, repr(e))) log.error('Committing suicide...') # Committing suicide in order to let docker restart ofagent os.system("kill -15 {}".format(os.getpid())) if ip_port_endpoint: host, port = ip_port_endpoint.split(':', 2) return host, int(port) def get_grpc_channel_with_voltha(self): log.info('Resolving voltha endpoint {} from consul'.format( self.voltha_endpoint)) host, port = self.resolve_endpoint(self.voltha_endpoint) assert host is not None assert port is not None # Create grpc channel to Voltha channel = grpc.insecure_channel('{}:{}'.format(host, port)) log.info('Acquired a grpc channel to voltha') return channel @inlineCallbacks def get_list_of_logical_devices_from_voltha(self): while True: log.info('Retrieve devices from voltha') try: stub = voltha_pb2.VolthaLocalServiceStub(self.channel) devices = stub.ListLogicalDevices(Empty()).items for device in devices: log.info("Devices {} -> {}".format(device.id, device.datapath_id)) returnValue(devices) except Exception as e: log.error('Failure to retrieve devices from ' 'voltha: {}'.format(repr(e))) log.info('reconnect', after_delay=self.voltha_retry_interval) yield asleep(self.voltha_retry_interval) def refresh_agent_connections(self, devices): """ Based on the new device list, update the following state in the class: * agent_map * datapath_map * device_id_map :param devices: full device list freshly received from Voltha :return: None """ # Use datapath ids for deciding what's new and what's obsolete desired_datapath_ids = set(d.datapath_id for d in devices) current_datapath_ids = set(self.agent_map.iterkeys()) # if identical, nothing to do if desired_datapath_ids == current_datapath_ids: return # ... otherwise calculate differences to_add = desired_datapath_ids.difference(current_datapath_ids) to_del = current_datapath_ids.difference(desired_datapath_ids) # remove what we don't need for datapath_id in to_del: self.delete_agent(datapath_id) # start new agents as needed for device in devices: if device.datapath_id in to_add: self.create_agent(device) log.debug('updated-agent-list', count=len(self.agent_map)) log.debug('updated-device-id-to-datapath-id-map', map=str(self.device_id_to_datapath_id_map)) def create_agent(self, device): datapath_id = device.datapath_id device_id = device.id agent = Agent(self.controller_endpoint, datapath_id, device_id, self.grpc_client) agent.start() self.agent_map[datapath_id] = agent self.device_id_to_datapath_id_map[device_id] = datapath_id def delete_agent(self, datapath_id): agent = self.agent_map[datapath_id] device_id = agent.get_device_id() agent.stop() del self.agent_map[datapath_id] del self.device_id_to_datapath_id_map[device_id] @inlineCallbacks def monitor_logical_devices(self): while True: # should change to a gRPC streaming call # see https://jira.opencord.org/browse/CORD-821 # get current list from Voltha devices = yield self.get_list_of_logical_devices_from_voltha() # update agent list and mapping tables as needed self.refresh_agent_connections(devices) # wait before next poll yield asleep(self.devices_refresh_interval) log.info('Monitor connections') def forward_packet_in(self, device_id, ofp_packet_in): datapath_id = self.device_id_to_datapath_id_map.get(device_id, None) if datapath_id: agent = self.agent_map[datapath_id] agent.forward_packet_in(ofp_packet_in) def forward_change_event(self, device_id, event): datapath_id = self.device_id_to_datapath_id_map.get(device_id, None) if datapath_id: agent = self.agent_map[datapath_id] agent.forward_change_event(event)
class GameEnvironment: def __init__(self, ip, port, api_token, need_human_ob=False, max_containable_step=10, logfile_path='./', debug=False): self.grpc_client = GrpcClient(ip, port, api_token, logfile_path, debug) self._check_frame = CheckFrame(self.grpc_client, need_human_ob) self.need_human_ob = need_human_ob self.last_action_frame = 0 self.max_containable_step = max_containable_step self._action_space = None self._reincarnation_flag = True def create_room(self, password): rsp = self.grpc_client.create_room(password) if rsp.err_code == 0: self._check_frame.start() return rsp.room_id, rsp.state else: return None def join_room(self, room_id, password): rsp = self.grpc_client.join_room(room_id, password) if rsp.err_code == 0: self._check_frame.start() return rsp.state else: return None def get_action_space(self): if self._action_space is None: self._action_space = self.grpc_client.get_action_space() return self._action_space.move, self._action_space.swing, self._action_space.fire, self._action_space.apply def get_inform(self): inform = self.grpc_client.get_inform() return inform.score, inform.kills, inform.health, inform.state, inform.frame_index def submit_reincarnation(self): if self._reincarnation_flag: rsp = self.grpc_client.submit_reincarnation() if rsp.err_code == 0: self._reincarnation_flag = False return rsp.state else: return None else: return None def submit_action(self, frame, move, swing, fire, apply): """read""" frame_lock.acquire_read() current_frame = frame frame_lock.release() if self.last_action_frame < frame and frame > current_frame - self.max_containable_step: rsp = self.grpc_client.submit_action(move, swing, fire, apply) if rsp.err_code == 0: self.last_action_frame = frame return rsp.state else: return None else: return None def get_observation_with_info(self): """read""" observation_lock.acquire_read() state = observation_state location = location_observation immutable_element = immutable_element_observation mutable_element = mutable_element_observation bodies = bodies_observation asset_ownership = asset_ownership_observation self_asset = self_asset_observation asset_status = asset_status_observation pointer = pointer_observation human = human_observation observation_lock.release() frame_lock.acquire_read() frame = frame_index frame_lock.release() inform_lock.acquire_read() score = score_inform kill = kill_inform heath = heath_inform inform_lock.release() if state == api.in_game and self._reincarnation_flag is False: self._reincarnation_flag = True if self.need_human_ob: return frame, \ state, \ location, \ immutable_element, \ mutable_element, \ bodies, \ asset_ownership, \ self_asset, \ asset_status, \ pointer, \ human, \ score, \ kill, \ heath else: return frame, \ state, \ location, \ immutable_element, \ mutable_element, \ bodies, \ asset_ownership, \ self_asset, \ asset_status, \ pointer, \ score, \ kill, \ heath def get_move_meanings(self): return [MOVE_MEANING[i] for i in self._action_space.move] @staticmethod def get_state_meanings(): return STATE_MEANING