def get_subscriber_table(self): chan = ServiceRegistry.get_rpc_channel('mobilityd', ServiceRegistry.LOCAL) client = MobilityServiceStub(chan) table = client.GetSubscriberIPTable(Void()) return table.entries
def setUp(self): # Bind the rpc server to a free port thread_pool = futures.ThreadPoolExecutor(max_workers=10) self._rpc_server = grpc.server(thread_pool) port = self._rpc_server.add_insecure_port('0.0.0.0:0') # Create a mock "mconfig" for the servicer to use mconfig = unittest.mock.Mock() mconfig.ip_block = None # Add the servicer config = {'persist_to_redis': False, 'redis_port': None} self._servicer = MobilityServiceRpcServicer(mconfig, config) self._servicer.add_to_server(self._rpc_server) self._rpc_server.start() # Create a rpc stub channel = grpc.insecure_channel('0.0.0.0:{}'.format(port)) self._stub = MobilityServiceStub(channel) # variables shared across tests self._netaddr = '192.168.0.0' self._prefix_len = 28 ip_bytes = bytes(map(int, self._netaddr.split('.'))) self._block_msg = IPBlock(version=IPBlock.IPV4, net_address=ip_bytes, prefix_len=self._prefix_len) self._block = ipaddress.ip_network("%s/%s" % (self._netaddr, self._prefix_len)) self._sid0 = SIDUtils.to_pb('IMSI0') self._sid1 = SIDUtils.to_pb('IMSI1') self._sid2 = SIDUtils.to_pb('IMSI2') self._apn0 = 'Internet' self._apn1 = 'IMS'
def setUp(self): # Bind the rpc server to a free port thread_pool = futures.ThreadPoolExecutor(max_workers=10) self._rpc_server = grpc.server(thread_pool) port = self._rpc_server.add_insecure_port('0.0.0.0:0') store = MobilityStore(get_default_client(), False, 3980) store.dhcp_gw_info.read_default_gw() ip_allocator = IpAllocatorPool(store) ipv6_allocator = IPv6AllocatorPool( store, session_prefix_alloc_mode='RANDOM', ) self._allocator = IPAddressManager( ip_allocator, ipv6_allocator, store, ) # Add the servicer self._servicer = MobilityServiceRpcServicer(self._allocator, False) self._servicer.add_to_server(self._rpc_server) self._rpc_server.start() # Create a rpc stub channel = grpc.insecure_channel('0.0.0.0:{}'.format(port)) self._stub = MobilityServiceStub(channel) # variables shared across tests self._netaddr = '192.168.0.0' self._prefix_len = 28 ip_bytes = bytes(map(int, self._netaddr.split('.'))) self._block_msg = IPBlock( version=IPBlock.IPV4, net_address=ip_bytes, prefix_len=self._prefix_len, ) self._ipv6_block = ipaddress.ip_network('fdee:5:6c::/48') self._ipv6_netaddr = self._ipv6_block.network_address.packed self._ipv6_block_msg = IPBlock( version=IPBlock.IPV6, net_address=self._ipv6_netaddr, prefix_len=self._ipv6_block.prefixlen, ) self._block = ipaddress.ip_network( "%s/%s" % (self._netaddr, self._prefix_len), ) self._sid0 = SIDUtils.to_pb('IMSI0') self._sid1 = SIDUtils.to_pb('IMSI1') self._sid2 = SIDUtils.to_pb('IMSI2') self._apn0 = 'Internet' self._apn1 = 'IMS'
async def get_ping_targets(self, service_loop) -> PingedTargets: """ Sends gRPC call to mobilityd to get all subscribers table. Returns: List of [Subscriber ID => IP address, APN] entries """ ping_addresses = self.ping_addresses.copy() ping_targets = self.ping_targets.copy() try: mobilityd_chan = ServiceRegistry.get_rpc_channel( 'mobilityd', ServiceRegistry.LOCAL, ) mobilityd_stub = MobilityServiceStub(mobilityd_chan) response = await grpc_async_wrapper( mobilityd_stub.GetSubscriberIPTable.future( Void(), 10, ), service_loop, ) for sub in response.entries: ip = _get_addr_from_subscribers(sub.ip) ping_addresses.append(ip) ping_targets[sub.sid.id] = ip except grpc.RpcError as err: logging.error( "GetSubscribers Error for %s! %s", err.code(), err.details(), ) return PingedTargets(ping_targets, ping_addresses)
def main(): parser = create_parser() # Parse the args args = parser.parse_args() if not args.cmd: parser.print_usage() exit(1) print('Preparing %s load test...' % args.cmd) client = MobilityServiceStub( ServiceRegistry.get_rpc_channel( 'mobilityd', ServiceRegistry.LOCAL, ), ) if args.cmd == 'allocate': _setup_ip_block(client) _build_allocate_ip_data(args.num) _benchmark_grpc_request(args, 'AllocateIPAddress') _cleanup_subs() elif args.cmd == 'release': _build_release_ip_data(client) _benchmark_grpc_request(args, 'ReleaseIPAddress') print('Done')
def load(self): """ Instantiates and schedules the Ryu app eventlets in the service eventloop. """ # Some setups might not use REDIS if (self._magma_service.config['redis_enabled']): # Wait for redis as multiple controllers rely on it while not redisAvailable(self.rule_id_mapper.redis_cli): logging.warning("Pipelined waiting for redis...") time.sleep(1) else: self.rule_id_mapper._rule_nums_by_rule = {} self.rule_id_mapper._rules_by_rule_num = {} self.session_rule_version_mapper._version_by_imsi_and_rule = {} self.interface_to_prefix_mapper._prefix_by_interface = {} self.tunnel_id_mapper._tunnel_map = {} manager = AppManager.get_instance() manager.load_apps([app.module for app in self._apps]) contexts = manager.create_contexts() contexts['rule_id_mapper'] = self.rule_id_mapper contexts[ 'session_rule_version_mapper'] = self.session_rule_version_mapper contexts['interface_to_prefix_mapper'] = self.interface_to_prefix_mapper contexts['tunnel_id_mapper'] = self.tunnel_id_mapper contexts['app_futures'] = {app.name: Future() for app in self._apps} contexts['internal_ip_allocator'] = \ InternalIPAllocator(self._magma_service.config) contexts['config'] = self._magma_service.config contexts['mconfig'] = self._magma_service.mconfig contexts['loop'] = self._magma_service.loop contexts['service_manager'] = self sessiond_chan = ServiceRegistry.get_rpc_channel( 'sessiond', ServiceRegistry.LOCAL) mobilityd_chan = ServiceRegistry.get_rpc_channel( 'mobilityd', ServiceRegistry.LOCAL) contexts['rpc_stubs'] = { 'mobilityd': MobilityServiceStub(mobilityd_chan), 'sessiond': LocalSessionManagerStub(sessiond_chan), } # Instantiate and schedule apps for app in manager.instantiate_apps(**contexts): # Wrap the eventlet in asyncio so it will stop when the loop is # stopped future = aioeventlet.wrap_greenthread(app, self._magma_service.loop) # Schedule the eventlet for evaluation in service loop asyncio.ensure_future(future) # In development mode, run server so that if environment.is_dev_mode(): server_thread = of_rest_server.start(manager) future = aioeventlet.wrap_greenthread(server_thread, self._magma_service.loop) asyncio.ensure_future(future)
def set_mobilityd_gw_info(ip: IPAddress, mac: str, vlan: str): """ Make RPC call to 'SetGatewayInfo' method of local mobilityD service """ try: chan = ServiceRegistry.get_rpc_channel(SERVICE_NAME, ServiceRegistry.LOCAL) except ValueError: logging.error('Cant get RPC channel to %s', SERVICE_NAME) return client = MobilityServiceStub(chan) try: gwinfo = GWInfo(ip=ip, mac=mac, vlan=vlan) client.SetGatewayInfo(gwinfo) except grpc.RpcError as err: logging.error("SetGatewayInfo error[%s] %s", err.code(), err.details())
def mobilityd_list_ip_blocks(): """ Make RPC call to query all ip-blocks. """ try: chan = ServiceRegistry.get_rpc_channel(SERVICE_NAME, ServiceRegistry.LOCAL) except ValueError: logging.error('Cant get RPC channel to %s', SERVICE_NAME) return client = MobilityServiceStub(chan) try: resp = client.ListAddedIPv4Blocks(Void()) return resp except grpc.RpcError as err: logging.error("List IpBlock error[%s] %s", err.code(), err.details())
def set_mobilityd_gw_info(gwinfo: GWInfo): """ Make RPC call to 'SetGatewayInfo' method of local mobilityD service """ try: chan = ServiceRegistry.get_rpc_channel(SERVICE_NAME, ServiceRegistry.LOCAL) except ValueError: logging.error('Cant get RPC channel to %s', SERVICE_NAME) return client = MobilityServiceStub(chan) try: client.SetGatewayInfo(gwinfo) except grpc.RpcError as err: logging.error("GetGatewayInfoRequest error[%s] %s", err.code(), err.details())
def get_mobilityd_gw_info() -> List[GWInfo]: """ Make RPC call to 'GetGatewayInfo' method of local mobilityD service """ try: chan = ServiceRegistry.get_rpc_channel(SERVICE_NAME, ServiceRegistry.LOCAL) except ValueError: logging.error('Cant get RPC channel to %s', SERVICE_NAME) return GWInfo() client = MobilityServiceStub(chan) try: return client.ListGatewayInfo(Void()).gw_list except grpc.RpcError as err: logging.error("ListGatewayInfo error[%s] %s", err.code(), err.details()) return []
def get_allocated_ips(): chan = ServiceRegistry.get_rpc_channel('mobilityd', ServiceRegistry.LOCAL) client = MobilityServiceStub(chan) res = [] list_blocks_resp = client.ListAddedIPv4Blocks(Void()) for block_msg in list_blocks_resp.ip_block_list: list_ips_resp = client.ListAllocatedIPs(block_msg) for ip_msg in list_ips_resp.ip_list: if ip_msg.version == IPAddress.IPV4: ip = ipaddress.IPv4Address(ip_msg.address) elif ip_msg.address == IPAddress.IPV6: ip = ipaddress.IPv6Address(ip_msg.address) else: continue res.append(ip) return res
def main(): parser = create_parser() # Parse the args args = parser.parse_args() if not args.cmd: parser.print_usage() exit(1) print('Preparing %s load test...' % args.cmd) client = MobilityServiceStub( ServiceRegistry.get_rpc_channel( MOBILITYD_SERVICE_NAME, ServiceRegistry.LOCAL, ), ) if args.cmd == 'allocate': _cleanup_subs() _setup_ip_block(client) input_file = 'allocate_data.json' request_type = 'AllocateIPAddress' _build_allocate_ip_data(args.num, input_file) benchmark_grpc_request( proto_path=PROTO_PATH, full_request_type=make_full_request_type( MOBILITYD_SERVICE_RPC_PATH, request_type, ), input_file=input_file, output_file=make_output_file_path(request_type), num_reqs=args.num, address=MOBILITYD_PORT, import_path=args.import_path, ) _cleanup_subs() elif args.cmd == 'release': input_file = 'release_data.json' request_type = 'ReleaseIPAddress' _build_release_ip_data(client, input_file) benchmark_grpc_request( proto_path=PROTO_PATH, full_request_type=make_full_request_type( MOBILITYD_SERVICE_RPC_PATH, request_type, ), input_file=input_file, output_file=make_output_file_path(request_type), num_reqs=args.num, address=MOBILITYD_PORT, import_path=args.import_path, ) print('Done')
def get_mobilityd_gw_info() -> List[GWInfo]: """ Make RPC call to 'GetGatewayInfo' method of local mobilityD service """ try: chan = ServiceRegistry.get_rpc_channel( SERVICE_NAME, ServiceRegistry.LOCAL, ) except ValueError: logging.error('Cant get RPC channel to %s', SERVICE_NAME) return GWInfo() client = MobilityServiceStub(chan) try: return client.ListGatewayInfo(Void()).gw_list except grpc.RpcError as err: logging.error( "ListGatewayInfo error[%s] %s", err.code(), err.details(), extra=EXCLUDE_FROM_ERROR_MONITORING if indicates_connection_error(err) else None, ) return []
def _build_release_ip_data(client: MobilityServiceStub, input_file: str): release_ip_reqs = [] table = client.GetSubscriberIPTable(Void()) if not table.entries: print('No IPs allocated to be freed, please run allocate test first') exit(1) for entry in table.entries: release_ip_req = ReleaseIPRequest( sid=entry.sid, ip=entry.ip, apn=entry.apn, ) release_ip_dict = json_format.MessageToDict(release_ip_req) # Dumping ReleaseIP request into json release_ip_reqs.append(release_ip_dict) with open(input_file, 'w') as file: json.dump(release_ip_reqs, file)
def load(self): """ Instantiates and schedules the Ryu app eventlets in the service eventloop. """ manager = AppManager.get_instance() manager.load_apps([app.module for app in self._apps]) contexts = manager.create_contexts() contexts['rule_id_mapper'] = RuleIDToNumMapper() contexts[ 'session_rule_version_mapper'] = self.session_rule_version_mapper contexts['app_futures'] = {app.name: Future() for app in self._apps} contexts['config'] = self._magma_service.config contexts['mconfig'] = self._magma_service.mconfig contexts['loop'] = self._magma_service.loop contexts['service_manager'] = self records_chan = ServiceRegistry.get_rpc_channel('meteringd_records', ServiceRegistry.CLOUD) sessiond_chan = ServiceRegistry.get_rpc_channel( 'sessiond', ServiceRegistry.LOCAL) mobilityd_chan = ServiceRegistry.get_rpc_channel( 'mobilityd', ServiceRegistry.LOCAL) contexts['rpc_stubs'] = { 'metering_cloud': MeteringdRecordsControllerStub(records_chan), 'mobilityd': MobilityServiceStub(mobilityd_chan), 'sessiond': LocalSessionManagerStub(sessiond_chan), } # Instantiate and schedule apps for app in manager.instantiate_apps(**contexts): # Wrap the eventlet in asyncio so it will stop when the loop is # stopped future = aioeventlet.wrap_greenthread(app, self._magma_service.loop) # Schedule the eventlet for evaluation in service loop asyncio.ensure_future(future) # In development mode, run server so that if environment.is_dev_mode(): server_thread = of_rest_server.start(manager) future = aioeventlet.wrap_greenthread(server_thread, self._magma_service.loop) asyncio.ensure_future(future)
async def _get_subscribers(self) -> List[IPAddress]: """ Sends gRPC call to mobilityd to get all subscribers table. Returns: List of [Subscriber ID => IP address, APN] entries """ try: mobilityd_chan = ServiceRegistry.get_rpc_channel( 'mobilityd', ServiceRegistry.LOCAL) mobilityd_stub = MobilityServiceStub(mobilityd_chan) response = await grpc_async_wrapper( mobilityd_stub.GetSubscriberIPTable.future( Void(), TIMEOUT_SECS), self._loop) return response.entries except grpc.RpcError as err: logging.error("GetSubscribers Error for %s! %s", err.code(), err.details()) return []
class RpcTests(unittest.TestCase): """ Tests for the IPAllocator rpc servicer and stub """ def setUp(self): # Bind the rpc server to a free port thread_pool = futures.ThreadPoolExecutor(max_workers=10) self._rpc_server = grpc.server(thread_pool) port = self._rpc_server.add_insecure_port('0.0.0.0:0') store = MobilityStore(get_default_client(), False, 3980) store.dhcp_gw_info.read_default_gw() ip_allocator = IpAllocatorPool(store) ipv6_allocator = IPv6AllocatorPool(store, session_prefix_alloc_mode='RANDOM') self._allocator = IPAddressManager(ip_allocator, ipv6_allocator, store) # Add the servicer self._servicer = MobilityServiceRpcServicer(self._allocator, '', 'fdee:5:6c::/48') self._servicer.add_to_server(self._rpc_server) self._rpc_server.start() # Create a rpc stub channel = grpc.insecure_channel('0.0.0.0:{}'.format(port)) self._stub = MobilityServiceStub(channel) # variables shared across tests self._netaddr = '192.168.0.0' self._prefix_len = 28 ip_bytes = bytes(map(int, self._netaddr.split('.'))) self._block_msg = IPBlock(version=IPBlock.IPV4, net_address=ip_bytes, prefix_len=self._prefix_len) self._block = ipaddress.ip_network("%s/%s" % (self._netaddr, self._prefix_len)) self._ipv6_block = ipaddress.ip_network('fdee:5:6c::/48') self._sid0 = SIDUtils.to_pb('IMSI0') self._sid1 = SIDUtils.to_pb('IMSI1') self._sid2 = SIDUtils.to_pb('IMSI2') self._apn0 = 'Internet' self._apn1 = 'IMS' def tearDown(self): self._rpc_server.stop(0) def test_add_invalid_ip_block(self): """ adding invalid ipblock should raise INVALID_ARGUMENT """ block_msg = IPBlock() with self.assertRaises(grpc.RpcError) as err: self._stub.AddIPBlock(block_msg) self.assertEqual(err.exception.code(), grpc.StatusCode.INVALID_ARGUMENT) def test_list_invalid_ip_block(self): """ listing invalid ipblock should raise INVALID_ARGUMENT """ block_msg = IPBlock() with self.assertRaises(grpc.RpcError) as err: self._stub.ListAllocatedIPs(block_msg) self.assertEqual(err.exception.code(), grpc.StatusCode.INVALID_ARGUMENT) def test_add_overlapped_ip_block(self): """ overlaping IPBlocks should raise FAILED_PRECONDITION """ self._stub.AddIPBlock(self._block_msg) # overlaped block ip_bytes = bytes(map(int, self._netaddr.split('.'))) block_msg = IPBlock(version=IPBlock.IPV4, net_address=ip_bytes, prefix_len=30) with self.assertRaises(grpc.RpcError) as err: self._stub.AddIPBlock(block_msg) self.assertEqual(err.exception.code(), grpc.StatusCode.FAILED_PRECONDITION) def test_list_added_ip_blocks(self): """ List IP blocks added to the allocator """ # return empty list before adding an IP block resp = self._stub.ListAddedIPv4Blocks(Void()) self.assertEqual(len(resp.ip_block_list), 0) # list one assigned IP blocks self._stub.AddIPBlock(self._block_msg) resp = self._stub.ListAddedIPv4Blocks(Void()) self.assertEqual(len(resp.ip_block_list), 1) self.assertEqual(resp.ip_block_list[0], self._block_msg) def test_list_allocated_ips(self): """ test list allocated IPs from a IP block """ self._stub.AddIPBlock(self._block_msg) # list empty allocated IPs resp = self._stub.ListAllocatedIPs(self._block_msg) self.assertEqual(len(resp.ip_list), 0) # list after allocating one IP request = AllocateIPRequest(sid=self._sid0, version=AllocateIPRequest.IPV4, apn=self._apn0) ip_msg0 = self._stub.AllocateIPAddress(request) resp = self._stub.ListAllocatedIPs(self._block_msg) self.assertNotEqual(resp, None) tmp = ListAllocatedIPsResponse() tmp.ip_list.extend([ip_msg0.ip_list[0]]) self.assertEqual(resp, tmp) def test_list_allocated_ips_from_unknown_ipblock(self): """ test list allocated IPs from an unknown IP block """ self._stub.AddIPBlock(self._block_msg) ip_bytes = bytes(map(int, '10.0.0.0'.split('.'))) block_msg = IPBlock(version=IPBlock.IPV4, net_address=ip_bytes, prefix_len=30) with self.assertRaises(grpc.RpcError) as err: self._stub.ListAllocatedIPs(block_msg) self.assertEqual(err.exception.code(), grpc.StatusCode.FAILED_PRECONDITION) def test_allocate_ip_address(self): """ test AllocateIPAddress and ListAllocatedIPs """ self._stub.AddIPBlock(self._block_msg) # allocate 1st IP request = AllocateIPRequest(sid=self._sid0, version=AllocateIPRequest.IPV4, apn=self._apn0) ip_msg0 = self._stub.AllocateIPAddress(request) self.assertEqual(ip_msg0.ip_list[0].version, AllocateIPRequest.IPV4) ip0 = ipaddress.ip_address(ip_msg0.ip_list[0].address) self.assertTrue(ip0 in self._block) # TODO: uncomment the code below when ip_allocator # actually rejects with DuplicatedIPAllocationError # with self.assertRaises(grpc.RpcError) as err: # self._stub.AllocateIPAddress(request) # self.assertEqual(err.exception.code(), # grpc.StatusCode.ALREADY_EXISTS) # allocate 2nd IP request.sid.CopyFrom(self._sid1) ip_msg2 = self._stub.AllocateIPAddress(request) self.assertEqual(ip_msg2.ip_list[0].version, AllocateIPRequest.IPV4) ip2 = ipaddress.ip_address(ip_msg2.ip_list[0].address) self.assertTrue(ip2 in self._block) def test_multiple_apn_ipallocation(self): """ test AllocateIPAddress for multiple APNs """ self._stub.AddIPBlock(self._block_msg) # allocate 1st IP request = AllocateIPRequest(sid=self._sid0, version=AllocateIPRequest.IPV4, apn=self._apn0) ip_msg0 = self._stub.AllocateIPAddress(request) self.assertEqual(ip_msg0.ip_list[0].version, AllocateIPRequest.IPV4) ip0 = ipaddress.ip_address(ip_msg0.ip_list[0].address) self.assertTrue(ip0 in self._block) # allocate 2nd IP from another APN to the same user request.apn = self._apn1 ip_msg1 = self._stub.AllocateIPAddress(request) self.assertEqual(ip_msg1.ip_list[0].version, AllocateIPRequest.IPV4) ip1 = ipaddress.ip_address(ip_msg1.ip_list[0].address) self.assertTrue(ip1 in self._block) def test_run_out_of_ip(self): """ should raise RESOURCE_EXHAUSTED when running out of IP """ # The subnet is provisioned with 16 addresses # Inside ip_address_man.py 11 addresses are reserved, # 2 addresses are not usable (all zeros and all ones) # Thus, we have a usable pool of 3 IP addresses; # first three allocations should succeed, while the fourth # request should raise RESOURCE_EXHAUSTED error self._stub.AddIPBlock(self._block_msg) request = AllocateIPRequest(sid=self._sid0, version=AllocateIPRequest.IPV4, apn=self._apn0) self._stub.AllocateIPAddress(request) request.apn = self._apn1 self._stub.AllocateIPAddress(request) request.sid.CopyFrom(self._sid1) self._stub.AllocateIPAddress(request) request.sid.CopyFrom(self._sid2) with self.assertRaises(grpc.RpcError) as err: self._stub.AllocateIPAddress(request) self.assertEqual(err.exception.code(), grpc.StatusCode.RESOURCE_EXHAUSTED) def test_release_ip_address(self): """ test ReleaseIPAddress """ self._stub.AddIPBlock(self._block_msg) alloc_request0 = AllocateIPRequest(sid=self._sid0, version=AllocateIPRequest.IPV4, apn=self._apn0) ip_msg0 = self._stub.AllocateIPAddress(alloc_request0) alloc_request1 = AllocateIPRequest(sid=self._sid1, version=AllocateIPRequest.IPV4, apn=self._apn0) ip_msg1 = self._stub.AllocateIPAddress(alloc_request1) # release ip_msg0 release_request0 = ReleaseIPRequest(sid=self._sid0, ip=ip_msg0.ip_list[0], apn=self._apn0) resp = self._stub.ReleaseIPAddress(release_request0) self.assertEqual(resp, Void()) resp = self._stub.ListAllocatedIPs(self._block_msg) tmp = ListAllocatedIPsResponse() tmp.ip_list.extend([ip_msg1.ip_list[0]]) self.assertEqual(resp, tmp) # release ip_msg1 release_request1 = ReleaseIPRequest(sid=self._sid1, ip=ip_msg1.ip_list[0], apn=self._apn0) resp = self._stub.ReleaseIPAddress(release_request1) resp = self._stub.ListAllocatedIPs(self._block_msg) self.assertEqual(len(resp.ip_list), 0) def test_release_unknown_sid_apn_ip_tuple(self): """ releasing unknown sid-apn-ip tuple should raise NOT_FOUND """ self._stub.AddIPBlock(self._block_msg) alloc_request0 = AllocateIPRequest(sid=self._sid0, version=AllocateIPRequest.IPV4, apn=self._apn0) ip_msg0 = self._stub.AllocateIPAddress(alloc_request0) request = ReleaseIPRequest(sid=SIDUtils.to_pb("IMSI12345"), ip=ip_msg0.ip_list[0], apn=self._apn0) with self.assertRaises(grpc.RpcError) as err: self._stub.ReleaseIPAddress(request) self.assertEqual(err.exception.code(), grpc.StatusCode.NOT_FOUND) ip_bytes = bytes(map(int, '10.0.0.0'.split('.'))) request.ip.CopyFrom(IPAddress(version=IPAddress.IPV4, address=ip_bytes)) with self.assertRaises(grpc.RpcError) as err: self._stub.ReleaseIPAddress(request) self.assertEqual(err.exception.code(), grpc.StatusCode.NOT_FOUND) request = ReleaseIPRequest(sid=self._sid0, ip=ip_msg0.ip_list[0], apn=self._apn1) with self.assertRaises(grpc.RpcError) as err: self._stub.ReleaseIPAddress(request) self.assertEqual(err.exception.code(), grpc.StatusCode.NOT_FOUND) def test_get_ip_for_subscriber(self): """ test GetIPForSubscriber """ self._stub.AddIPBlock(self._block_msg) alloc_request0 = AllocateIPRequest(sid=self._sid0, version=AllocateIPRequest.IPV4, apn=self._apn0) ip_msg0 = self._stub.AllocateIPAddress(alloc_request0) ip0 = ipaddress.ip_address(ip_msg0.ip_list[0].address) lookup_request0 = IPLookupRequest(sid=self._sid0, apn=self._apn0, version=IPAddress.IPV4) ip_msg0_returned = self._stub.GetIPForSubscriber(lookup_request0) ip0_returned = ipaddress.ip_address(ip_msg0_returned.address) self.assertEqual(ip0, ip0_returned) def test_get_ip_for_unknown_subscriber(self): """ Getting ip for non existent subscriber should return NOT_FOUND status code """ lookup_request0 = IPLookupRequest(sid=self._sid0, apn=self._apn0, version=IPAddress.IPV4) with self.assertRaises(grpc.RpcError) as err: self._stub.GetIPForSubscriber(lookup_request0) self.assertEqual(err.exception.code(), grpc.StatusCode.NOT_FOUND) def test_get_gw_info(self): def_gw_cmd = shlex.split("ip route show") p = subprocess.Popen(def_gw_cmd, stdout=subprocess.PIPE) output = p.stdout.read().decode("utf-8") def_ip = None for line in output.splitlines(): if 'default ' in line: tokens = line.split() def_ip = tokens[2] break gw_info_list = self._stub.ListGatewayInfo(Void()) for gw_info in gw_info_list.gw_list: gw_ip_get = str(ipaddress.ip_address(gw_info.ip.address)) if gw_ip_get == def_ip: return assert 0 def test_set_gw_info(self): mac1 = "22:22:c6:d0:02:3c" ipaddr1 = ipaddress.ip_address("10.1.1.11") gwinfo_msg = GWInfo() gwinfo_msg.ip.version = IPBlock.IPV4 gwinfo_msg.ip.address = ipaddr1.packed gwinfo_msg.mac = mac1 gwinfo_msg.vlan = "" self._stub.SetGatewayInfo(gwinfo_msg) gw_info_list = self._stub.ListGatewayInfo(Void()) for gw_info in gw_info_list.gw_list: gw_ip_get = ipaddress.ip_address(gw_info.ip.address) self.assertEqual(ipaddr1, gw_ip_get) self.assertEqual(mac1, gw_info.mac) def test_set_gw_info_vlan(self): mac1 = "22:22:c6:d0:02:3c" ipaddr1 = ipaddress.ip_address("10.1.1.11") gwinfo_msg = GWInfo(ip=IPAddress(version=IPAddress.IPV4, address=ipaddr1.packed), mac=mac1, vlan="1") self._stub.SetGatewayInfo(gwinfo_msg) gw_info_list = self._stub.ListGatewayInfo(Void()) for gw_info in gw_info_list.gw_list: if gw_info.vlan == "1": gw_ip_get = ipaddress.ip_address(gw_info.ip.address) self.assertEqual(ipaddr1, gw_ip_get) self.assertEqual(mac1, gw_info.mac) return assert 0 def test_set_gw_info_vlan2(self): mac1 = "22:22:c6:d0:02:3c" ipaddr1 = ipaddress.ip_address("10.1.1.11") gwinfo_msg1 = GWInfo(ip=IPAddress(version=IPAddress.IPV4, address=ipaddr1.packed), mac=mac1, vlan="1") self._stub.SetGatewayInfo(gwinfo_msg1) mac2 = "33:22:c6:d0:02:3c" ipaddr2 = ipaddress.ip_address("20.1.1.11") gwinfo_msg2 = GWInfo(ip=IPAddress(version=IPAddress.IPV4, address=ipaddr2.packed), mac=mac2, vlan="2") self._stub.SetGatewayInfo(gwinfo_msg2) gw_info_list = self._stub.ListGatewayInfo(Void()) count1 = 0 count2 = 0 for gw_info in gw_info_list.gw_list: if gw_info == gwinfo_msg1: count1 = count1 + 1 if gw_info == gwinfo_msg2: count2 = count2 + 1 self.assertEqual(count1, 1) self.assertEqual(count2, 1) def test_get_subscriber_id_from_ip(self): """ test GetSubscriberIDFromIP """ self._stub.AddIPBlock(self._block_msg) alloc_request0 = AllocateIPRequest(sid=self._sid0, version=AllocateIPRequest.IPV4, apn=self._apn0) ip_msg0 = self._stub.AllocateIPAddress(alloc_request0) sid_pb_returned = self._stub.GetSubscriberIDFromIP(ip_msg0.ip_list[0]) self.assertEqual(SIDUtils.to_str(self._sid0), SIDUtils.to_str(sid_pb_returned)) def test_get_subscriber_id_from_unknown_ip(self): """ Getting subscriber id for non-allocated ip address should return NOT_FOUND error code """ ip_pb = IPAddress(version=IPAddress.IPV4, address=ipaddress.ip_address('1.1.1.1').packed) with self.assertRaises(grpc.RpcError) as err: self._stub.GetSubscriberIDFromIP(ip_pb) self.assertEqual(err.exception.code(), grpc.StatusCode.NOT_FOUND) def test_get_subscriber_ip_table(self): """ test GetSubscriberIPTable """ self._stub.AddIPBlock(self._block_msg) resp = self._stub.GetSubscriberIPTable(Void()) self.assertEqual(len(resp.entries), 0) alloc_request0 = AllocateIPRequest(sid=self._sid0, version=AllocateIPRequest.IPV4, apn=self._apn0) ip_msg0 = self._stub.AllocateIPAddress(alloc_request0) entry0 = SubscriberIPTableEntry(sid=self._sid0, ip=ip_msg0.ip_list[0], apn=self._apn0) resp = self._stub.GetSubscriberIPTable(Void()) self.assertTrue(entry0 in resp.entries) alloc_request1 = AllocateIPRequest(sid=self._sid1, version=AllocateIPRequest.IPV4, apn=self._apn1) ip_msg1 = self._stub.AllocateIPAddress(alloc_request1) entry1 = SubscriberIPTableEntry(sid=self._sid1, ip=ip_msg1.ip_list[0], apn=self._apn1) resp = self._stub.GetSubscriberIPTable(Void()) self.assertTrue(entry0 in resp.entries) self.assertTrue(entry1 in resp.entries) # keep in table after in release release_request0 = ReleaseIPRequest(sid=self._sid0, ip=ip_msg0.ip_list[0], apn=self._apn0) resp = self._stub.ReleaseIPAddress(release_request0) resp = self._stub.GetSubscriberIPTable(Void()) self.assertTrue(entry0 in resp.entries) self.assertTrue(entry1 in resp.entries) def test_remove_no_assigned_blocks(self): """ remove should return nothing """ remove_request0 = RemoveIPBlockRequest(ip_blocks=[self._block_msg], force=False) resp = self._stub.RemoveIPBlock(remove_request0) expect = RemoveIPBlockResponse() self.assertEqual(expect, resp) resp = self._stub.ListAddedIPv4Blocks(Void()) expect = ListAddedIPBlocksResponse() self.assertEqual(expect, resp) def test_remove_unallocated_assigned_block(self): """ remove should return nothing """ self._stub.AddIPBlock(self._block_msg) remove_request0 = RemoveIPBlockRequest(ip_blocks=[self._block_msg], force=False) resp = self._stub.RemoveIPBlock(remove_request0) expect = RemoveIPBlockResponse() expect.ip_blocks.extend([self._block_msg]) self.assertEqual(expect, resp) resp = self._stub.ListAddedIPv4Blocks(Void()) expect = ListAddedIPBlocksResponse() self.assertEqual(expect, resp) def test_remove_allocated_assigned_block_without_force(self): """ remove should return nothing """ self._stub.AddIPBlock(self._block_msg) alloc_request0 = AllocateIPRequest(sid=self._sid0, version=AllocateIPRequest.IPV4, apn=self._apn0) self._stub.AllocateIPAddress(alloc_request0) remove_request0 = RemoveIPBlockRequest(ip_blocks=[self._block_msg], force=False) resp = self._stub.RemoveIPBlock(remove_request0) expect = RemoveIPBlockResponse() self.assertEqual(expect, resp) resp = self._stub.ListAddedIPv4Blocks(Void()) expect = ListAddedIPBlocksResponse() expect.ip_block_list.extend([self._block_msg]) self.assertEqual(expect, resp) def test_remove_allocated_assigned_block_with_force(self): """ remove should return nothing """ self._stub.AddIPBlock(self._block_msg) alloc_request0 = AllocateIPRequest(sid=self._sid0, version=AllocateIPRequest.IPV4, apn=self._apn0) self._stub.AllocateIPAddress(alloc_request0) remove_request0 = RemoveIPBlockRequest(ip_blocks=[self._block_msg], force=True) resp = self._stub.RemoveIPBlock(remove_request0) expect = RemoveIPBlockResponse() expect.ip_blocks.extend([self._block_msg]) self.assertEqual(expect, resp) resp = self._stub.ListAddedIPv4Blocks(Void()) expect = ListAddedIPBlocksResponse() self.assertEqual(expect, resp) def test_remove_after_releasing_all_addresses(self): """ remove after releasing all addresses should remove block """ # Assign IP block self._stub.AddIPBlock(self._block_msg) # Allocate 2 IPs alloc_request0 = AllocateIPRequest(sid=self._sid0, version=AllocateIPRequest.IPV4, apn=self._apn0) ip_msg0 = self._stub.AllocateIPAddress(alloc_request0) alloc_request1 = AllocateIPRequest(sid=self._sid1, version=AllocateIPRequest.IPV4, apn=self._apn0) ip_msg1 = self._stub.AllocateIPAddress(alloc_request1) # Test remove without force -- should not remove block remove_request0 = RemoveIPBlockRequest(ip_blocks=[self._block_msg], force=False) resp = self._stub.RemoveIPBlock(remove_request0) expect = RemoveIPBlockResponse() self.assertEqual(expect, resp) # Ensure that block has not been removed resp = self._stub.ListAddedIPv4Blocks(Void()) expect = ListAddedIPBlocksResponse() expect.ip_block_list.extend([self._block_msg]) self.assertEqual(expect, resp) # Release the allocated IPs release_request0 = ReleaseIPRequest(sid=self._sid0, ip=ip_msg0.ip_list[0], apn=self._apn0) resp = self._stub.ReleaseIPAddress(release_request0) self.assertEqual(resp, Void()) release_request1 = ReleaseIPRequest(sid=self._sid1, ip=ip_msg1.ip_list[0], apn=self._apn0) resp = self._stub.ReleaseIPAddress(release_request1) self.assertEqual(resp, Void()) # Test remove without force -- should remove block remove_request1 = RemoveIPBlockRequest(ip_blocks=[self._block_msg], force=False) resp = self._stub.RemoveIPBlock(remove_request1) expect = RemoveIPBlockResponse() expect.ip_blocks.extend([self._block_msg]) self.assertEqual(expect, resp) # Ensure that block has been removed resp = self._stub.ListAddedIPv4Blocks(Void()) expect = ListAddedIPBlocksResponse() self.assertEqual(expect, resp) def test_remove_after_releasing_some_addresses(self): """ remove after releasing some addresses shouldn't remove block """ # Assign IP block self._stub.AddIPBlock(self._block_msg) # Allocate 2 IPs alloc_request0 = AllocateIPRequest(sid=self._sid0, version=AllocateIPRequest.IPV4, apn=self._apn0) ip_msg0 = self._stub.AllocateIPAddress(alloc_request0) alloc_request1 = AllocateIPRequest(sid=self._sid1, version=AllocateIPRequest.IPV4, apn=self._apn0) self._stub.AllocateIPAddress(alloc_request1) # Test remove without force -- should not remove block remove_request0 = RemoveIPBlockRequest(ip_blocks=[self._block_msg], force=False) resp = self._stub.RemoveIPBlock(remove_request0) expect = RemoveIPBlockResponse() self.assertEqual(expect, resp) # Ensure that block has not been removed resp = self._stub.ListAddedIPv4Blocks(Void()) expect = ListAddedIPBlocksResponse() expect.ip_block_list.extend([self._block_msg]) self.assertEqual(expect, resp) # Release the allocated IPs release_request0 = ReleaseIPRequest(sid=self._sid0, ip=ip_msg0.ip_list[0], apn=self._apn0) resp = self._stub.ReleaseIPAddress(release_request0) self.assertEqual(resp, Void()) # Test remove without force -- should not remove block remove_request1 = RemoveIPBlockRequest(ip_blocks=[self._block_msg], force=False) resp = self._stub.RemoveIPBlock(remove_request1) expect = RemoveIPBlockResponse() self.assertEqual(expect, resp) # Ensure that block has not been removed resp = self._stub.ListAddedIPv4Blocks(Void()) expect = ListAddedIPBlocksResponse() expect.ip_block_list.extend([self._block_msg]) self.assertEqual(expect, resp) def test_ipv6(self): """ ipv6 requests should work for allocate / release IP requests """ # AllocateIPAddress request = AllocateIPRequest(sid=self._sid1, version=AllocateIPRequest.IPV6, apn=self._apn0) ip_msg = self._stub.AllocateIPAddress(request) self.assertTrue( ipaddress.ip_address(ip_msg.ip_list[0].address) in self._ipv6_block) # ReleaseIPAddress release_request = ReleaseIPRequest(sid=self._sid1, ip=ip_msg.ip_list[0], apn=self._apn0) self._stub.ReleaseIPAddress(release_request)
class RpcTests(unittest.TestCase): """ Tests for the IPAllocator rpc servicer and stub """ def setUp(self): # Bind the rpc server to a free port thread_pool = futures.ThreadPoolExecutor(max_workers=10) self._rpc_server = grpc.server(thread_pool) port = self._rpc_server.add_insecure_port('0.0.0.0:0') # Create a mock "mconfig" for the servicer to use mconfig = unittest.mock.Mock() mconfig.ip_block = None mconfig.ip_allocator_type = MobilityD.IP_POOL # Add the servicer config = { 'persist_to_redis': False, 'redis_port': None, 'allocator_type': "ip_pool" } self._servicer = MobilityServiceRpcServicer(mconfig, config) self._servicer.add_to_server(self._rpc_server) self._rpc_server.start() # Create a rpc stub channel = grpc.insecure_channel('0.0.0.0:{}'.format(port)) self._stub = MobilityServiceStub(channel) # variables shared across tests self._netaddr = '192.168.0.0' self._prefix_len = 28 ip_bytes = bytes(map(int, self._netaddr.split('.'))) self._block_msg = IPBlock(version=IPBlock.IPV4, net_address=ip_bytes, prefix_len=self._prefix_len) self._block = ipaddress.ip_network("%s/%s" % (self._netaddr, self._prefix_len)) self._sid0 = SIDUtils.to_pb('IMSI0') self._sid1 = SIDUtils.to_pb('IMSI1') self._sid2 = SIDUtils.to_pb('IMSI2') self._apn0 = 'Internet' self._apn1 = 'IMS' def tearDown(self): self._rpc_server.stop(0) def test_add_ipv6_block_to_servicer(self): """ add IPv6 block (ipaddress.ipblock) directly to servicer should raise IPVersionNotSupportedError """ ip = ipaddress.ip_address("fc::") with self.assertRaises(IPVersionNotSupportedError): self._servicer.add_ip_block(ip) def test_add_invalid_ip_block(self): """ adding invalid ipblock should raise INVALID_ARGUMENT """ block_msg = IPBlock() with self.assertRaises(grpc.RpcError) as err: self._stub.AddIPBlock(block_msg) self.assertEqual(err.exception.code(), grpc.StatusCode.INVALID_ARGUMENT) def test_list_invalid_ip_block(self): """ listing invalid ipblock should raise INVALID_ARGUMENT """ block_msg = IPBlock() with self.assertRaises(grpc.RpcError) as err: self._stub.ListAllocatedIPs(block_msg) self.assertEqual(err.exception.code(), grpc.StatusCode.INVALID_ARGUMENT) def test_add_overlapped_ip_block(self): """ overlaping IPBlocks should raise FAILED_PRECONDITION """ self._stub.AddIPBlock(self._block_msg) # overlaped block ip_bytes = bytes(map(int, self._netaddr.split('.'))) block_msg = IPBlock(version=IPBlock.IPV4, net_address=ip_bytes, prefix_len=30) with self.assertRaises(grpc.RpcError) as err: self._stub.AddIPBlock(block_msg) self.assertEqual(err.exception.code(), grpc.StatusCode.FAILED_PRECONDITION) def test_list_added_ip_blocks(self): """ List IP blocks added to the allocator """ # return empty list before adding an IP block resp = self._stub.ListAddedIPv4Blocks(Void()) self.assertEqual(len(resp.ip_block_list), 0) # list one assigned IP blocks self._stub.AddIPBlock(self._block_msg) resp = self._stub.ListAddedIPv4Blocks(Void()) self.assertEqual(len(resp.ip_block_list), 1) self.assertEqual(resp.ip_block_list[0], self._block_msg) def test_list_allocated_ips(self): """ test list allocated IPs from a IP block """ self._stub.AddIPBlock(self._block_msg) # list empty allocated IPs resp = self._stub.ListAllocatedIPs(self._block_msg) self.assertEqual(len(resp.ip_list), 0) # list after allocating one IP request = AllocateIPRequest(sid=self._sid0, version=AllocateIPRequest.IPV4, apn=self._apn0) ip_msg0 = self._stub.AllocateIPAddress(request) resp = self._stub.ListAllocatedIPs(self._block_msg) self.assertNotEqual(resp, None) tmp = ListAllocatedIPsResponse() tmp.ip_list.extend([ip_msg0]) self.assertEqual(resp, tmp) def test_list_allocated_ips_from_unknown_ipblock(self): """ test list allocated IPs from an unknown IP block """ self._stub.AddIPBlock(self._block_msg) ip_bytes = bytes(map(int, '10.0.0.0'.split('.'))) block_msg = IPBlock(version=IPBlock.IPV4, net_address=ip_bytes, prefix_len=30) with self.assertRaises(grpc.RpcError) as err: self._stub.ListAllocatedIPs(block_msg) self.assertEqual(err.exception.code(), grpc.StatusCode.FAILED_PRECONDITION) def test_allocate_ip_address(self): """ test AllocateIPAddress and ListAllocatedIPs """ self._stub.AddIPBlock(self._block_msg) # allocate 1st IP request = AllocateIPRequest(sid=self._sid0, version=AllocateIPRequest.IPV4, apn=self._apn0) ip_msg0 = self._stub.AllocateIPAddress(request) self.assertEqual(ip_msg0.version, AllocateIPRequest.IPV4) ip0 = ipaddress.ip_address(ip_msg0.address) self.assertTrue(ip0 in self._block) # TODO: uncomment the code below when ip_allocator # actually rejects with DuplicatedIPAllocationError # with self.assertRaises(grpc.RpcError) as err: # self._stub.AllocateIPAddress(request) # self.assertEqual(err.exception.code(), # grpc.StatusCode.ALREADY_EXISTS) # allocate 2nd IP request.sid.CopyFrom(self._sid1) ip_msg2 = self._stub.AllocateIPAddress(request) self.assertEqual(ip_msg2.version, AllocateIPRequest.IPV4) ip2 = ipaddress.ip_address(ip_msg2.address) self.assertTrue(ip2 in self._block) def test_multiple_apn_ipallocation(self): """ test AllocateIPAddress for multiple APNs """ self._stub.AddIPBlock(self._block_msg) # allocate 1st IP request = AllocateIPRequest(sid=self._sid0, version=AllocateIPRequest.IPV4, apn=self._apn0) ip_msg0 = self._stub.AllocateIPAddress(request) self.assertEqual(ip_msg0.version, AllocateIPRequest.IPV4) ip0 = ipaddress.ip_address(ip_msg0.address) self.assertTrue(ip0 in self._block) # allocate 2nd IP from another APN to the same user request.apn = self._apn1 ip_msg1 = self._stub.AllocateIPAddress(request) self.assertEqual(ip_msg1.version, AllocateIPRequest.IPV4) ip1 = ipaddress.ip_address(ip_msg1.address) self.assertTrue(ip1 in self._block) def test_run_out_of_ip(self): """ should raise RESOURCE_EXHAUSTED when running out of IP """ # The subnet is provisioned with 16 addresses # Inside ip_address_man.py 11 addresses are reserved, # 2 addresses are not usable (all zeros and all ones) # Thus, we have a usable pool of 3 IP addresses; # first three allocations should succeed, while the fourth # request should raise RESOURCE_EXHAUSTED error self._stub.AddIPBlock(self._block_msg) request = AllocateIPRequest(sid=self._sid0, version=AllocateIPRequest.IPV4, apn=self._apn0) self._stub.AllocateIPAddress(request) request.apn = self._apn1 self._stub.AllocateIPAddress(request) request.sid.CopyFrom(self._sid1) self._stub.AllocateIPAddress(request) request.sid.CopyFrom(self._sid2) with self.assertRaises(grpc.RpcError) as err: self._stub.AllocateIPAddress(request) self.assertEqual(err.exception.code(), grpc.StatusCode.RESOURCE_EXHAUSTED) def test_release_ip_address(self): """ test ReleaseIPAddress """ self._stub.AddIPBlock(self._block_msg) alloc_request0 = AllocateIPRequest(sid=self._sid0, version=AllocateIPRequest.IPV4, apn=self._apn0) ip_msg0 = self._stub.AllocateIPAddress(alloc_request0) alloc_request1 = AllocateIPRequest(sid=self._sid1, version=AllocateIPRequest.IPV4, apn=self._apn0) ip_msg1 = self._stub.AllocateIPAddress(alloc_request1) # release ip_msg0 release_request0 = ReleaseIPRequest(sid=self._sid0, ip=ip_msg0, apn=self._apn0) resp = self._stub.ReleaseIPAddress(release_request0) self.assertEqual(resp, Void()) resp = self._stub.ListAllocatedIPs(self._block_msg) tmp = ListAllocatedIPsResponse() tmp.ip_list.extend([ip_msg1]) self.assertEqual(resp, tmp) # release ip_msg1 release_request1 = ReleaseIPRequest(sid=self._sid1, ip=ip_msg1, apn=self._apn0) resp = self._stub.ReleaseIPAddress(release_request1) resp = self._stub.ListAllocatedIPs(self._block_msg) self.assertEqual(len(resp.ip_list), 0) def test_release_unknown_sid_apn_ip_tuple(self): """ releasing unknown sid-apn-ip tuple should raise NOT_FOUND """ self._stub.AddIPBlock(self._block_msg) alloc_request0 = AllocateIPRequest(sid=self._sid0, version=AllocateIPRequest.IPV4, apn=self._apn0) ip_msg0 = self._stub.AllocateIPAddress(alloc_request0) request = ReleaseIPRequest(sid=SIDUtils.to_pb("IMSI12345"), ip=ip_msg0, apn=self._apn0) with self.assertRaises(grpc.RpcError) as err: self._stub.ReleaseIPAddress(request) self.assertEqual(err.exception.code(), grpc.StatusCode.NOT_FOUND) ip_bytes = bytes(map(int, '10.0.0.0'.split('.'))) request.ip.CopyFrom(IPAddress(version=IPAddress.IPV4, address=ip_bytes)) with self.assertRaises(grpc.RpcError) as err: self._stub.ReleaseIPAddress(request) self.assertEqual(err.exception.code(), grpc.StatusCode.NOT_FOUND) request = ReleaseIPRequest(sid=self._sid0, ip=ip_msg0, apn=self._apn1) with self.assertRaises(grpc.RpcError) as err: self._stub.ReleaseIPAddress(request) self.assertEqual(err.exception.code(), grpc.StatusCode.NOT_FOUND) def test_get_ip_for_subscriber(self): """ test GetIPForSubscriber """ self._stub.AddIPBlock(self._block_msg) alloc_request0 = AllocateIPRequest(sid=self._sid0, version=AllocateIPRequest.IPV4, apn=self._apn0) ip_msg0 = self._stub.AllocateIPAddress(alloc_request0) ip0 = ipaddress.ip_address(ip_msg0.address) lookup_request0 = IPLookupRequest(sid=self._sid0, apn=self._apn0) ip_msg0_returned = self._stub.GetIPForSubscriber(lookup_request0) ip0_returned = ipaddress.ip_address(ip_msg0_returned.address) self.assertEqual(ip0, ip0_returned) def test_get_ip_for_unknown_subscriber(self): """ Getting ip for non existent subscriber should return NOT_FOUND status code """ lookup_request0 = IPLookupRequest(sid=self._sid0, apn=self._apn0) with self.assertRaises(grpc.RpcError) as err: self._stub.GetIPForSubscriber(lookup_request0) self.assertEqual(err.exception.code(), grpc.StatusCode.NOT_FOUND) def test_get_subscriber_id_from_ip(self): """ test GetSubscriberIDFromIP """ self._stub.AddIPBlock(self._block_msg) alloc_request0 = AllocateIPRequest(sid=self._sid0, version=AllocateIPRequest.IPV4, apn=self._apn0) ip_msg0 = self._stub.AllocateIPAddress(alloc_request0) sid_pb_returned = self._stub.GetSubscriberIDFromIP(ip_msg0) self.assertEqual(SIDUtils.to_str(self._sid0), SIDUtils.to_str(sid_pb_returned)) def test_get_subscriber_id_from_unknown_ip(self): """ Getting subscriber id for non-allocated ip address should return NOT_FOUND error code """ ip_pb = IPAddress(version=IPAddress.IPV4, address=ipaddress.ip_address('1.1.1.1').packed) with self.assertRaises(grpc.RpcError) as err: self._stub.GetSubscriberIDFromIP(ip_pb) self.assertEqual(err.exception.code(), grpc.StatusCode.NOT_FOUND) def test_get_subscriber_ip_table(self): """ test GetSubscriberIPTable """ self._stub.AddIPBlock(self._block_msg) resp = self._stub.GetSubscriberIPTable(Void()) self.assertEqual(len(resp.entries), 0) alloc_request0 = AllocateIPRequest(sid=self._sid0, version=AllocateIPRequest.IPV4, apn=self._apn0) ip_msg0 = self._stub.AllocateIPAddress(alloc_request0) entry0 = SubscriberIPTableEntry(sid=self._sid0, ip=ip_msg0, apn=self._apn0) resp = self._stub.GetSubscriberIPTable(Void()) self.assertTrue(entry0 in resp.entries) alloc_request1 = AllocateIPRequest(sid=self._sid1, version=AllocateIPRequest.IPV4, apn=self._apn1) ip_msg1 = self._stub.AllocateIPAddress(alloc_request1) entry1 = SubscriberIPTableEntry(sid=self._sid1, ip=ip_msg1, apn=self._apn1) resp = self._stub.GetSubscriberIPTable(Void()) self.assertTrue(entry0 in resp.entries) self.assertTrue(entry1 in resp.entries) # keep in table after in release release_request0 = ReleaseIPRequest(sid=self._sid0, ip=ip_msg0, apn=self._apn0) resp = self._stub.ReleaseIPAddress(release_request0) resp = self._stub.GetSubscriberIPTable(Void()) self.assertTrue(entry0 in resp.entries) self.assertTrue(entry1 in resp.entries) def test_remove_no_assigned_blocks(self): """ remove should return nothing """ remove_request0 = RemoveIPBlockRequest(ip_blocks=[self._block_msg], force=False) resp = self._stub.RemoveIPBlock(remove_request0) expect = RemoveIPBlockResponse() self.assertEqual(expect, resp) resp = self._stub.ListAddedIPv4Blocks(Void()) expect = ListAddedIPBlocksResponse() self.assertEqual(expect, resp) def test_remove_unallocated_assigned_block(self): """ remove should return nothing """ self._stub.AddIPBlock(self._block_msg) remove_request0 = RemoveIPBlockRequest(ip_blocks=[self._block_msg], force=False) resp = self._stub.RemoveIPBlock(remove_request0) expect = RemoveIPBlockResponse() expect.ip_blocks.extend([self._block_msg]) self.assertEqual(expect, resp) resp = self._stub.ListAddedIPv4Blocks(Void()) expect = ListAddedIPBlocksResponse() self.assertEqual(expect, resp) def test_remove_allocated_assigned_block_without_force(self): """ remove should return nothing """ self._stub.AddIPBlock(self._block_msg) alloc_request0 = AllocateIPRequest(sid=self._sid0, version=AllocateIPRequest.IPV4, apn=self._apn0) self._stub.AllocateIPAddress(alloc_request0) remove_request0 = RemoveIPBlockRequest(ip_blocks=[self._block_msg], force=False) resp = self._stub.RemoveIPBlock(remove_request0) expect = RemoveIPBlockResponse() self.assertEqual(expect, resp) resp = self._stub.ListAddedIPv4Blocks(Void()) expect = ListAddedIPBlocksResponse() expect.ip_block_list.extend([self._block_msg]) self.assertEqual(expect, resp) def test_remove_allocated_assigned_block_with_force(self): """ remove should return nothing """ self._stub.AddIPBlock(self._block_msg) alloc_request0 = AllocateIPRequest(sid=self._sid0, version=AllocateIPRequest.IPV4, apn=self._apn0) self._stub.AllocateIPAddress(alloc_request0) remove_request0 = RemoveIPBlockRequest(ip_blocks=[self._block_msg], force=True) resp = self._stub.RemoveIPBlock(remove_request0) expect = RemoveIPBlockResponse() expect.ip_blocks.extend([self._block_msg]) self.assertEqual(expect, resp) resp = self._stub.ListAddedIPv4Blocks(Void()) expect = ListAddedIPBlocksResponse() self.assertEqual(expect, resp) def test_remove_after_releasing_all_addresses(self): """ remove after releasing all addresses should remove block """ # Assign IP block self._stub.AddIPBlock(self._block_msg) # Allocate 2 IPs alloc_request0 = AllocateIPRequest(sid=self._sid0, version=AllocateIPRequest.IPV4, apn=self._apn0) ip_msg0 = self._stub.AllocateIPAddress(alloc_request0) alloc_request1 = AllocateIPRequest(sid=self._sid1, version=AllocateIPRequest.IPV4, apn=self._apn0) ip_msg1 = self._stub.AllocateIPAddress(alloc_request1) # Test remove without force -- should not remove block remove_request0 = RemoveIPBlockRequest(ip_blocks=[self._block_msg], force=False) resp = self._stub.RemoveIPBlock(remove_request0) expect = RemoveIPBlockResponse() self.assertEqual(expect, resp) # Ensure that block has not been removed resp = self._stub.ListAddedIPv4Blocks(Void()) expect = ListAddedIPBlocksResponse() expect.ip_block_list.extend([self._block_msg]) self.assertEqual(expect, resp) # Release the allocated IPs release_request0 = ReleaseIPRequest(sid=self._sid0, ip=ip_msg0, apn=self._apn0) resp = self._stub.ReleaseIPAddress(release_request0) self.assertEqual(resp, Void()) release_request1 = ReleaseIPRequest(sid=self._sid1, ip=ip_msg1, apn=self._apn0) resp = self._stub.ReleaseIPAddress(release_request1) self.assertEqual(resp, Void()) # Test remove without force -- should remove block remove_request1 = RemoveIPBlockRequest(ip_blocks=[self._block_msg], force=False) resp = self._stub.RemoveIPBlock(remove_request1) expect = RemoveIPBlockResponse() expect.ip_blocks.extend([self._block_msg]) self.assertEqual(expect, resp) # Ensure that block has been removed resp = self._stub.ListAddedIPv4Blocks(Void()) expect = ListAddedIPBlocksResponse() self.assertEqual(expect, resp) def test_remove_after_releasing_some_addresses(self): """ remove after releasing some addresses shouldn't remove block """ # Assign IP block self._stub.AddIPBlock(self._block_msg) # Allocate 2 IPs alloc_request0 = AllocateIPRequest(sid=self._sid0, version=AllocateIPRequest.IPV4, apn=self._apn0) ip_msg0 = self._stub.AllocateIPAddress(alloc_request0) alloc_request1 = AllocateIPRequest(sid=self._sid1, version=AllocateIPRequest.IPV4, apn=self._apn0) self._stub.AllocateIPAddress(alloc_request1) # Test remove without force -- should not remove block remove_request0 = RemoveIPBlockRequest(ip_blocks=[self._block_msg], force=False) resp = self._stub.RemoveIPBlock(remove_request0) expect = RemoveIPBlockResponse() self.assertEqual(expect, resp) # Ensure that block has not been removed resp = self._stub.ListAddedIPv4Blocks(Void()) expect = ListAddedIPBlocksResponse() expect.ip_block_list.extend([self._block_msg]) self.assertEqual(expect, resp) # Release the allocated IPs release_request0 = ReleaseIPRequest(sid=self._sid0, ip=ip_msg0, apn=self._apn0) resp = self._stub.ReleaseIPAddress(release_request0) self.assertEqual(resp, Void()) # Test remove without force -- should not remove block remove_request1 = RemoveIPBlockRequest(ip_blocks=[self._block_msg], force=False) resp = self._stub.RemoveIPBlock(remove_request1) expect = RemoveIPBlockResponse() self.assertEqual(expect, resp) # Ensure that block has not been removed resp = self._stub.ListAddedIPv4Blocks(Void()) expect = ListAddedIPBlocksResponse() expect.ip_block_list.extend([self._block_msg]) self.assertEqual(expect, resp) def test_ipv6_unimplemented(self): """ ipv6 requests should raise UNIMPLEMENTED """ ip = ipaddress.ip_address("fc::") block = IPBlock(version=IPBlock.IPV6, net_address=ip.packed, prefix_len=120) # AddIPBlock with self.assertRaises(grpc.RpcError) as err: self._stub.AddIPBlock(block) self.assertEqual(err.exception.code(), grpc.StatusCode.UNIMPLEMENTED) # ListAllocatedIPs with self.assertRaises(grpc.RpcError) as err: self._stub.ListAllocatedIPs(block) self.assertEqual(err.exception.code(), grpc.StatusCode.UNIMPLEMENTED) # AllocateIPAddress request = AllocateIPRequest(sid=self._sid1, version=AllocateIPRequest.IPV6, apn=self._apn0) with self.assertRaises(grpc.RpcError) as err: self._stub.AllocateIPAddress(request) self.assertEqual(err.exception.code(), grpc.StatusCode.UNIMPLEMENTED) # ReleaseIPAddress release_request = ReleaseIPRequest( sid=self._sid0, ip=IPAddress(version=IPAddress.IPV6), apn=self._apn0) with self.assertRaises(grpc.RpcError) as err: self._stub.ReleaseIPAddress(release_request) self.assertEqual(err.exception.code(), grpc.StatusCode.UNIMPLEMENTED)
def __init__(self): """ Init the gRPC stub. """ self._mobility_stub = MobilityServiceStub(get_rpc_channel("mobilityd"))
class MobilityServiceGrpc(MobilityServiceClient): """ Handle mobility actions by making calls over gRPC directly to the gateway. """ def __init__(self): """ Init the gRPC stub. """ self._mobility_stub = MobilityServiceStub(get_rpc_channel("mobilityd")) @staticmethod def _get_ip_data(block): """ Construct an IPBlock message from a given IP block. Args: block (ipaddress.ip_network): the IP block to embed """ ipblock_msg = IPBlock() ipblock_msg.version = IPBlock.IPV4 ipblock_msg.net_address = block.network_address.packed ipblock_msg.prefix_len = block.prefixlen return ipblock_msg def add_ip_block(self, block): mobility_data = self._get_ip_data(block) try: self._mobility_stub.AddIPBlock(mobility_data) except grpc.RpcError as error: err_code = error.exception().code() if err_code == grpc.StatusCode.FAILED_PRECONDITION: logging.info("Ignoring FAILED_PRECONDITION exception") else: raise def list_added_blocks(self): try: response = self._mobility_stub.ListAddedIPv4Blocks(Void()) ip_block_list = [] for block in response.ip_block_list: address_bytes = block.net_address address_int = int.from_bytes(address_bytes, byteorder='big') address = ipaddress.ip_address(address_int) ip_block_list.append( ipaddress.ip_network("%s/%d" % (address, block.prefix_len))) return ip_block_list except grpc.RpcError as error: err_code = error.exception().code() if (err_code == grpc.StatusCode.FAILED_PRECONDITION): logging.info("Ignoring FAILED_PRECONDITION exception") else: raise def remove_ip_blocks(self, blocks): try: ip_blocks = [ IPBlock(version={ 4: IPAddress.IPV4, 6: IPAddress.IPV6 }[block.version], net_address=block.network_address.packed, prefix_len=block.prefixlen) for block in blocks ] response = self._mobility_stub.RemoveIPBlock( RemoveIPBlockRequest(ip_blocks=ip_blocks, force=False)) removed_ip_block_list = () for block in response.ip_blocks: address_bytes = block.net_address address_int = int.from_bytes(address_bytes, byteorder='big') address = ipaddress.ip_address(address_int) removed_ip_block_list += (ipaddress.ip_network( "%s/%d" % (address, block.prefix_len)), ) return removed_ip_block_list except grpc.RpcError as error: err_code = error.exception().code() if (err_code == grpc.StatusCode.FAILED_PRECONDITION): logging.info("Ignoring FAILED_PRECONDITION exception") else: raise def get_subscriber_ip_table(self): response = self._mobility_stub.GetSubscriberIPTable(Void()) table = {} for entry in response.entries: sid = entry.sid.id ip = ipaddress.ip_address(entry.ip.address) table[sid] = ip return table def remove_all_ip_blocks(self): blocks = self.list_added_blocks() self.remove_ip_blocks(blocks) def wait_for_changes(self): """ All changes propagate immediately, no need to wait """ return