Ejemplo n.º 1
0
    def get_subscriber_table(self):
        chan = ServiceRegistry.get_rpc_channel('mobilityd',
                                               ServiceRegistry.LOCAL)
        client = MobilityServiceStub(chan)

        table = client.GetSubscriberIPTable(Void())
        return table.entries
Ejemplo n.º 2
0
    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'
Ejemplo n.º 3
0
    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'
Ejemplo n.º 4
0
    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)
Ejemplo n.º 5
0
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')
Ejemplo n.º 6
0
    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)
Ejemplo n.º 7
0
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())
Ejemplo n.º 8
0
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())
Ejemplo n.º 9
0
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())
Ejemplo n.º 10
0
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 []
Ejemplo n.º 11
0
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
Ejemplo n.º 12
0
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')
Ejemplo n.º 13
0
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 []
Ejemplo n.º 14
0
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)
Ejemplo n.º 15
0
    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)
Ejemplo n.º 16
0
    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 []
Ejemplo n.º 17
0
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)
Ejemplo n.º 18
0
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)
Ejemplo n.º 19
0
 def __init__(self):
     """ Init the gRPC stub. """
     self._mobility_stub = MobilityServiceStub(get_rpc_channel("mobilityd"))
Ejemplo n.º 20
0
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