def setUpTestData(cls):
        # VLANs
        cls.vlan = {
            'VLAN1': VLAN.objects.create(name="vlan1", long_name="VLAN 1",
                ip_network=ipaddress.IPv4Network("10.0.0.0/16")),
            'VLAN2': VLAN.objects.create(name="vlan2", long_name="VLAN 2",
                ip_network=ipaddress.IPv4Network("10.1.0.0/16")),
        }

        # Owners
        cls.owner = [
            Owner.objects.create(name="owner1", long_name="Owner 1", contact=""),
            Owner.objects.create(name="owner2", long_name="Owner 2", contact=""),
        ]

        # ISDs
        cls.isd = [
            ISD.objects.create(isd_id=1, name="Region 1"),
        ]

        # ASes
        cls.asys = {
            'A': AS.objects.create(asn=ASN("ff00:0:0"), isd=cls.isd[0], name="AS A",
                owner=cls.owner[0], is_core=False),
            'B': AS.objects.create(asn=ASN("ff00:0:1"), isd=cls.isd[0], name="AS B",
                owner=cls.owner[1], is_core=False),
        }

        # Peering Clients
        cls.client = {
            'A-1': PeeringClient.objects.create(asys=cls.asys['A'], name="1"),
            'A-2': PeeringClient.objects.create(asys=cls.asys['A'], name="2"),
            'B-1': PeeringClient.objects.create(asys=cls.asys['B'], name="1"),
            'B-2': PeeringClient.objects.create(asys=cls.asys['B'], name="2"),
            'B-3': PeeringClient.objects.create(asys=cls.asys['B'], name="3")
        }

        # Interfaces
        hosts1 = cls.vlan['VLAN1'].ip_network.hosts()
        hosts2 = cls.vlan['VLAN2'].ip_network.hosts()
        cls.interface = {
            'A-1-VLAN1': Interface.objects.create(peering_client=cls.client['A-1'], vlan=cls.vlan['VLAN1'],
                public_ip=next(hosts1), first_port=50000, last_port=51000),
            'A-2-VLAN1': Interface.objects.create(peering_client=cls.client['A-2'], vlan=cls.vlan['VLAN1'],
                public_ip=next(hosts1), first_port=50000, last_port=51000),
            'A-2-VLAN2': Interface.objects.create(peering_client=cls.client['A-2'], vlan=cls.vlan['VLAN2'],
                public_ip=next(hosts2), first_port=51000, last_port=52000),
            'B-1-VLAN1': Interface.objects.create(peering_client=cls.client['B-1'], vlan=cls.vlan['VLAN1'],
                public_ip=next(hosts1), first_port=50000, last_port=51000),
            'B-2-VLAN1': Interface.objects.create(peering_client=cls.client['B-1'], vlan=cls.vlan['VLAN1'],
                public_ip=next(hosts1), first_port=51000, last_port=52000),
            'B-2-VLAN2': Interface.objects.create(peering_client=cls.client['B-2'], vlan=cls.vlan['VLAN2'],
                public_ip=next(hosts2), first_port=50000, last_port=51000),
            'B-3-VLAN2': Interface.objects.create(peering_client=cls.client['B-2'], vlan=cls.vlan['VLAN2'],
                public_ip=next(hosts2), first_port=51000, last_port=52000),
        }
Beispiel #2
0
    def ListPolicies(self, request, context):
        """List policies of the AS making the request."""
        asn_str, client = get_client_from_metadata(
            context.invocation_metadata())
        asn = ASN(asn_str)

        # Prepare common selection criteria
        common_selection = {'asys__asn': asn}
        if request.vlan:
            common_selection['vlan__name'] = request.vlan
        if request.asn and request.asn != asn_str:
            context.abort(grpc.StatusCode.PERMISSION_DENIED,
                          "Cannot list policies of other ASes")
        if request.WhichOneof("accept_") is not None:
            common_selection['accept'] = request.accept

        # Return matching default policies
        if request.WhichOneof('peer') is None or request.peer_everyone:
            for policy in DefaultPolicy.objects.filter(**common_selection):
                yield PolicyProtoSerializer(policy).message

        # Return matching AS policies
        if request.WhichOneof('peer') is None or request.peer_asn:
            policies = AsPeerPolicy.objects.filter(**common_selection)
            if request.peer_asn:
                try:
                    policies = policies.filter(
                        peer_as__asn=ASN(request.peer_asn))
                except ValueError:
                    context.abort(grpc.StatusCode.INVALID_ARGUMENT,
                                  "Invalid ASN")
            for policy in policies.filter(**common_selection):
                yield PolicyProtoSerializer(policy).message

        # Return matching owner policies
        if request.WhichOneof('peer') is None or request.peer_owner:
            policies = OwnerPeerPolicy.objects.filter(**common_selection)
            if request.peer_owner:
                policies = policies.filter(peer_owner__name=request.peer_owner)
            for policy in policies.filter(**common_selection):
                yield PolicyProtoSerializer(policy).message

        # Return matching ISD policies
        if request.WhichOneof('peer') is None or request.peer_isd:
            policies = IsdPeerPolicy.objects.filter(**common_selection)
            if request.peer_isd:
                try:
                    policies = policies.filter(
                        peer_isd__isd_id=int(request.peer_isd))
                except ValueError:
                    context.abort(grpc.StatusCode.INVALID_ARGUMENT,
                                  "Invalid ISD")
            for policy in policies.filter(**common_selection):
                yield PolicyProtoSerializer(policy).message
Beispiel #3
0
    def CreatePolicy(self, request, context):
        """Create a new policy."""
        asn_str, client = get_client_from_metadata(
            context.invocation_metadata())
        asn = ASN(asn_str)

        if request.asn != asn_str:
            context.abort(grpc.StatusCode.PERMISSION_DENIED,
                          "Cannot create policies for other ASes")

        serializer = PolicyProtoSerializer(message=request)
        if not serializer.is_valid():
            context.abort(grpc.StatusCode.INVALID_ARGUMENT,
                          _fmt_validation_errors(serializer.errors))

        _assert_policy_write_permission(context, asn, client, request.vlan)

        try:
            policy = serializer.save()
        except ValidationError as e:
            msg, code = _translate_validation_errors(e)
            context.abort(code, msg)

        # Update links and notify clients
        policy_resolver.update_accepted_peers(policy.vlan, policy.asys)
        policy_resolver.update_links(policy.vlan, policy.asys)

        return serializer.message
Beispiel #4
0
    def _set_policies(
            self, request, context
    ) -> Tuple[typing.List[peering_pb2.Policy], typing.List[str]]:
        # Delete old policies. Parse the new ones, and try saving them to the DB.
        # Returns the unsuccessful policies and matching error descriptions.
        # context.abort() is called on fatal errors to abort the RPC and trigger a transaction
        # rollback.
        asn_str, client = get_client_from_metadata(
            context.invocation_metadata())
        asn = ASN(asn_str)

        # Delete previous policies
        if request.vlan:
            try:
                vlan_id = VLAN.objects.get(name=request.vlan).id
            except VLAN.DoesNotExist:
                context.abort(grpc.StatusCode.NOT_FOUND, "VLAN does not exist")
                _assert_policy_write_permission(context, asn, client,
                                                request.vlan)
            _delete_policies(asn, vlan_id)
        else:
            _assert_policy_write_permission(context, asn, client)
            _delete_policies(asn)

        # Create new policies
        rejected_policies = []
        errors = []
        for policy in request.policies:
            serializer = PolicyProtoSerializer(message=policy)

            if policy.asn != asn_str:
                rejected_policies.append(policy)
                errors.append("Policy ASN belongs to foreign AS")
                continue

            if request.vlan and policy.vlan != request.vlan:
                rejected_policies.append(policy)
                errors.append("VLAN excluded by filter")
                continue

            if not serializer.is_valid():
                rejected_policies.append(policy)
                errors.append(_fmt_validation_errors(serializer.errors))
                continue

            try:
                serializer.save()
            except ValidationError as e:
                msg, _ = _translate_validation_errors(e)
                rejected_policies.append(policy)
                errors.append(msg)
                continue

        # Update links and notify clients
        asys = AS.objects.get(asn=asn)
        for vlan in asys.get_connected_vlans():
            policy_resolver.update_accepted_peers(vlan, asys)
            policy_resolver.update_links(vlan, asys)

        return rejected_policies, errors
Beispiel #5
0
    def DestroyPolicy(self, request, context):
        """Delete a policy."""
        asn_str, client = get_client_from_metadata(
            context.invocation_metadata())
        asn = ASN(asn_str)

        if request.asn != asn_str:
            context.abort(grpc.StatusCode.PERMISSION_DENIED,
                          "Cannot delete policies of other ASes")

        serializer = PolicyProtoSerializer(message=request)
        if not serializer.is_valid():
            context.abort(grpc.StatusCode.INVALID_ARGUMENT,
                          _fmt_validation_errors(serializer.errors))
        try:
            policy = serializer.get()
        except ObjectDoesNotExist:
            context.abort(grpc.StatusCode.NOT_FOUND, "Policy does not exist")

        _assert_policy_write_permission(context, asn, client, request.vlan)
        policy.delete()

        # Update links and notify clients
        policy_resolver.update_accepted_peers(policy.vlan, policy.asys)
        policy_resolver.update_links(policy.vlan, policy.asys)

        return Empty()
Beispiel #6
0
 def to_internal_value(self, data):
     try:
         return self.get_queryset().get(asn=ASN(data))
     except ValueError:
         raise serializers.ValidationError("Invalid ASN.")
     except AS.DoesNotExist:
         raise serializers.ValidationError("AS does not exist.")
Beispiel #7
0
 def to_python(self, value: Union[None, int, str, ASN]) -> Optional[ASN]:
     if isinstance(value, ASN):
         return value
     if value is None:
         return value
     try:
         return ASN(value)
     except ValueError as e:
         raise ValidationError(
             "Invalid AS number: '%(value)s'. Error: %(msg)s",
             code='invalid_asn',
             params={
                 'value': value,
                 'msg': str(e)
             })
    def setUpTestData(cls):
        # VLANs
        cls.vlan = [
            VLAN.objects.create(name="prod", long_name="Production",
                ip_network=ipaddress.IPv4Network("10.0.0.0/16")),
        ]

        # Owners
        cls.owner = [
            Owner.objects.create(name="owner1", long_name="Owner 1", contact=""),
            Owner.objects.create(name="owner2", long_name="Owner 2", contact=""),
        ]

        # ISDs
        cls.isd = [
            ISD.objects.create(isd_id=1, name="Region 1"),
            ISD.objects.create(isd_id=2, name="Region 2"),
        ]

        # ASes
        cls.asys = {
            'A': AS.objects.create(asn=ASN("ff00:0:0"), isd=cls.isd[0], name="AS 0", owner=cls.owner[0], is_core=True),
            'B': AS.objects.create(asn=ASN("ff00:0:1"), isd=cls.isd[1], name="AS 1", owner=cls.owner[0], is_core=True),
            'C': AS.objects.create(asn=ASN("ff00:0:2"), isd=cls.isd[0], name="AS 2", owner=cls.owner[0], is_core=True),
            'D': AS.objects.create(asn=ASN("ff00:0:3"), isd=cls.isd[1], name="AS 3", owner=cls.owner[0], is_core=False),
            'E': AS.objects.create(asn=ASN("ff00:0:4"), isd=cls.isd[1], name="AS 4", owner=cls.owner[0], is_core=False),
            'F': AS.objects.create(asn=ASN("ff00:0:5"), isd=cls.isd[0], name="AS 5", owner=cls.owner[1], is_core=False),
            'G': AS.objects.create(asn=ASN("ff00:0:6"), isd=cls.isd[1], name="AS 6", owner=cls.owner[1], is_core=False),
            'H': AS.objects.create(asn=ASN("ff00:0:7"), isd=cls.isd[1], name="AS 7", owner=cls.owner[0], is_core=False),
        }

        # Peering Clients
        clients = []
        for asys in cls.asys.values():
            clients.append(PeeringClient.objects.create(asys=asys, name="default"))

        # Interfaces
        for vlan in cls.vlan:
            for daemon, ip in zip(clients, cls.vlan[0].ip_network.hosts()):
                Interface.objects.create(peering_client=daemon, vlan=vlan, public_ip=ip,
                    first_port=50000, last_port=51000)
Beispiel #9
0
    def test_asn_parsing(self):
        for string, integer in self.TEST_CASES:
            with self.subTest(string=string, integer=integer):
                self.assertEqual(int(ASN(string)), integer)

        with self.assertRaisesRegex(ValueError, r"Out of range"):
            ASN(-1)
        with self.assertRaisesRegex(ValueError, r"Out of range"):
            ASN(2**48)
        with self.assertRaisesRegex(ValueError, r"^Invalid decimal ASN"):
            ASN(str(2**32))
        with self.assertRaisesRegex(ValueError, r"^Invalid hexadecimal ASN"):
            ASN("ffff:fffff:ffff")
        with self.assertRaisesRegex(ValueError,
                                    r"Wrong number of colon-separated groups"):
            ASN("ff:ff:ff:ff:ff:ff")
Beispiel #10
0
    def SetPortRange(self, request, context):
        """Set the UDP port range used for SCION underlay connections."""
        asn_str, _ = get_client_from_metadata(context.invocation_metadata())
        asn = ASN(asn_str)

        # Validate arguments and retrieve the interface
        try:
            vlan = VLAN.objects.get(name=request.interface_vlan)
        except VLAN.DoesNotExist:
            context.abort(grpc.StatusCode.NOT_FOUND, "VLAN does not exist")
        try:
            ip = ipaddress.ip_address(request.interface_ip)
        except ValueError:
            context.abort(grpc.StatusCode.INVALID_ARGUMENT,
                          "Invalid IP address")
        try:
            interface = Interface.objects.get(vlan=vlan, public_ip=ip)
        except (Interface.DoesNotExist, Interface.MultipleObjectsReturned):
            context.abort(grpc.StatusCode.NOT_FOUND, "Interface not found")

        recreate_links = not (request.first_port <= interface.first_port
                              and request.last_port >= interface.last_port)

        try:
            interface.first_port = request.first_port
            interface.last_port = request.last_port
            interface.save()
        except ValidationError:
            context.abort(grpc.StatusCode.INVALID_ARGUMENT,
                          "Invalid port range")

        if recreate_links:
            # Recreate the interface's links with the new ports
            for link in interface.query_links().all():
                link.delete()
            policy_resolver.update_links(vlan, AS.objects.get(asn=asn))

        return peering_pb2.google_dot_protobuf_dot_empty__pb2.Empty()
    def GetOwner(self, request, context):
        """Retrieve information on an AS owner by owner name or by an AS."""
        # Build query
        query = Owner.objects
        if request.name:
            query = query.filter(name=request.name)
        if request.asn:
            try:
                query = query.filter(ases__asn=ASN(request.asn))
            except ValueError:
                context.abort(grpc.StatusCode.INVALID_ARGUMENT, "Invalid ASN")

        # Query database
        owner = None
        try:
            owner = query.get()
        except Owner.DoesNotExist:
            context.abort(grpc.StatusCode.NOT_FOUND, "No matching owner found")

        # Build response
        buffer = info_pb2.Owner()
        _fill_owner_protobuf(owner, buffer)
        return buffer
Beispiel #12
0
    def intercept_service(self, continuation, handler_call_details):
        asn, client = get_client_from_metadata(
            handler_call_details.invocation_metadata)
        if not asn or not client:
            return self._abortion

        # Retrieve the expected token
        try:
            query = PeeringClient.objects.values_list('secret_token',
                                                      flat=True)
            token = query.get(asys__asn=ASN(asn), name=client)
            if len(token) < 2 * API_TOKEN_BYTES:
                return self._abortion
        except ValueError:
            return self._abortion
        except PeeringClient.DoesNotExist:
            return self._abortion

        expected_metadata = (TOKEN_HEADER_KEY, token)
        if expected_metadata in handler_call_details.invocation_metadata:
            return continuation(handler_call_details)
        else:
            return self._abortion
Beispiel #13
0
    def get_queryset(self):
        # Filter for VLAN
        self.vlan = get_object_or_404(VLAN, name=self.kwargs['name'])
        ases = self.vlan.members.values_list('asys', flat=True).all()
        queryset = AS.objects.filter(id__in=ases)

        # Filter according to query string
        self.query = self.request.GET.get("query")
        if self.query:
            if self.query.startswith("AS"):
                try:
                    queryset = queryset.filter(asn=ASN(self.query[2:]))
                except ValueError:
                    queryset = AS.objects.none()
            else:
                queryset = queryset.filter(
                    Q(name__icontains=self.query)
                    | Q(owner__long_name__icontains=self.query))

        # Ordering
        self.sort_order = self.request.GET.get(ORDER_KEY, ORDER_ASC)
        validate_sort_order(self.sort_order)

        self.order_by = self.request.GET.get(SORT_BY_KEY)
        if self.order_by in ["name", "asn", "owner"]:
            queryset = queryset.order_by(self.order_by)
        elif self.order_by == "isd":
            queryset = queryset.order_by("isd__isd_id")
        elif self.order_by == "links":
            queryset = queryset.annotate(link_count=Count('links'))
        elif self.order_by:
            raise Http404()

        if self.sort_order == ORDER_DESC:
            queryset = queryset.reverse()

        return queryset
Beispiel #14
0
    def StreamChannel(self, request_iterator, context):
        """Server side of the persistent bidirectional gRPC stream peering clients maintain with the
        coordinator.

        Since bidirectional gRPC streams in Python use blocking generators for sending and
        receiving, an additional thread just for reading request from the stream is created for
        every connection. The request listener threads forwards received requests to the main thread
        handling the connection via the associated ClientConnection object.
        """
        asn, client_name = get_client_from_metadata(
            context.invocation_metadata())
        asn = ASN(asn)

        # Register the connection
        try:
            conn = ClientRegistry.createConnection(asn, client_name)
        except KeyError as e:
            context.abort(grpc.StatusCode.NOT_FOUND, str(e))
        except ClientConnections.AlreadyConnected as e:
            context.abort(grpc.StatusCode.ALREADY_EXISTS, str(e))
        except:
            context.abort(grpc.StatusCode.INTERNAL, "Internal error")

        # Enqueue link create messages for all existing links.
        try:
            client = PeeringClient.objects.get(asys__asn=asn, name=client_name)
            for interface in Interface.objects.filter(
                    peering_client=client).all():
                for link in interface.query_links().all():
                    if link.interface_a == interface:
                        update = create_link_update(
                            peering_pb2.LinkUpdate.Type.CREATE,
                            link_type=link.link_type,
                            local_interface=link.interface_a,
                            local_port=link.port_a,
                            remote_interface=link.interface_b,
                            remote_port=link.port_b)
                    else:
                        update = create_link_update(
                            peering_pb2.LinkUpdate.Type.CREATE,
                            link_type=link.link_type,
                            local_interface=link.interface_b,
                            local_port=link.port_b,
                            remote_interface=link.interface_a,
                            remote_port=link.port_a)
                    conn.send_link_update(update)
        except:
            ClientRegistry.destroyConnection(conn)
            raise

        # Launch a new thread to listen for requests from the client.
        def stream_listener():
            try:
                for request in request_iterator:
                    conn.stream_request_received(request)
            except grpc.RpcError:
                pass
            finally:
                conn.request_stream_closed()

        listener = threading.Thread(
            target=stream_listener,
            name="gRPC stream listener for {}-{}".format(asn, client_name))
        listener.start()

        # Run the event loop to process requests and generate responses.
        try:
            for response in conn.run():
                yield response
        finally:
            ClientRegistry.destroyConnection(conn)
            listener.join()
Beispiel #15
0
 def from_db_value(self, value: Optional[int], expression,
                   connection) -> Optional[ASN]:
     if value is None:
         return value
     return ASN(value)
    def setUpTestData(cls):
        # Owners
        cls.owner = [
            Owner.objects.create(name="owner1",
                                 long_name="Owner 1",
                                 contact="Contact Info A"),
        ]

        # ISDs
        cls.isd = [
            ISD.objects.create(isd_id=1, name="Region 1"),
            ISD.objects.create(isd_id=2, name="Region 2"),
        ]

        # ASes
        cls.asys = [
            AS.objects.create(asn=ASN("ff00:0:0"),
                              isd=cls.isd[0],
                              name="AS 0",
                              owner=cls.owner[0],
                              is_core=True),
            AS.objects.create(asn=ASN("ff00:0:1"),
                              isd=cls.isd[0],
                              name="AS 1",
                              owner=cls.owner[0],
                              is_core=False),
            AS.objects.create(asn=ASN("ff00:0:2"),
                              isd=cls.isd[0],
                              name="AS 2",
                              owner=cls.owner[0],
                              is_core=False),
            AS.objects.create(asn=ASN("ff00:0:3"),
                              isd=cls.isd[1],
                              name="AS 3",
                              owner=cls.owner[0],
                              is_core=True),
            AS.objects.create(asn=ASN("ff00:0:4"),
                              isd=cls.isd[1],
                              name="AS 4",
                              owner=cls.owner[0],
                              is_core=False),
        ]

        # VLANs
        cls.vlan = [
            VLAN.objects.create(
                name="prod",
                long_name="Production",
                ip_network=ipaddress.IPv4Network("10.0.0.0/16")),
            VLAN.objects.create(
                name="test",
                long_name="Testing",
                ip_network=ipaddress.IPv4Network("10.1.0.0/16")),
        ]

        # Peering Clients
        clients = []
        for asys in cls.asys:
            clients.append(
                PeeringClient.objects.create(asys=asys, name="default"))

        # Interfaces
        for vlan in cls.vlan:
            for client, ip in zip(clients, vlan.ip_network.hosts()):
                Interface.objects.create(peering_client=client,
                                         vlan=vlan,
                                         public_ip=ip)

        # AS 0 has an additional client
        client = PeeringClient.objects.create(asys=cls.asys[0], name="backup")
        Interface.objects.create(peering_client=client,
                                 vlan=cls.vlan[0],
                                 public_ip="10.0.0.200")
def _set_up_test_data(cls):
    # Owners
    cls.owner = [
        Owner.objects.create(name="owner1",
                             long_name="Owner Name 1",
                             contact="Contact Info A"),
        Owner.objects.create(name="owner2",
                             long_name="Owner 2",
                             contact="Contact Info B"),
        Owner.objects.create(name="owner3",
                             long_name="Owner 3",
                             contact="Contact Info C"),
    ]

    # ISDs
    cls.isd = [
        ISD.objects.create(isd_id=1, name="Region 1"),
        ISD.objects.create(isd_id=2, name="Region 2"),
    ]

    # ASes
    cls.asys = [
        AS.objects.create(asn=ASN("ff00:0:0"),
                          isd=cls.isd[0],
                          name="AS 0",
                          owner=cls.owner[0],
                          is_core=True),
        AS.objects.create(asn=ASN("ff00:0:1"),
                          isd=cls.isd[0],
                          name="AS 1",
                          owner=cls.owner[0],
                          is_core=False),
        AS.objects.create(asn=ASN("ff00:0:2"),
                          isd=cls.isd[0],
                          name="AS 2",
                          owner=cls.owner[0],
                          is_core=True),
        AS.objects.create(asn=ASN("ff00:0:3"),
                          isd=cls.isd[0],
                          name="AS 3",
                          owner=cls.owner[1],
                          is_core=False),
        AS.objects.create(asn=ASN("ff00:0:4"),
                          isd=cls.isd[1],
                          name="AS 4",
                          owner=cls.owner[1],
                          is_core=False),
        AS.objects.create(asn=ASN("ff00:0:5"),
                          isd=cls.isd[1],
                          name="AS 5",
                          owner=cls.owner[1],
                          is_core=False),
    ]

    # VLANs
    cls.vlan = [
        VLAN.objects.create(name="prod",
                            long_name="Production",
                            ip_network=ipaddress.IPv4Network("10.0.0.0/16")),
        VLAN.objects.create(name="test",
                            long_name="Testing",
                            ip_network=ipaddress.IPv4Network("10.1.0.0/16")),
    ]

    # Peering Clients
    clients = []
    for asys in cls.asys:
        clients.append(PeeringClient.objects.create(asys=asys, name="default"))

    # Interfaces
    for vlan in cls.vlan:
        for client, ip in zip(clients, vlan.ip_network.hosts()):
            Interface.objects.create(peering_client=client,
                                     vlan=vlan,
                                     public_ip=ip,
                                     first_port=50000,
                                     last_port=51000)
    def testArbitration(self):
        stub = peering_pb2_grpc.PeeringStub(self.channel)
        default_call_cred = [(ASN_HEADER_KEY, "ff00:0:0"),
                             (CLIENT_NAME_HEADER_KEY, "default")]
        backup_call_cred = [(ASN_HEADER_KEY, "ff00:0:0"),
                            (CLIENT_NAME_HEADER_KEY, "backup")]

        default_request_queue = queue.Queue()
        backup_request_queue = queue.Queue()
        self.assertIsNone(ClientRegistry.get_clients(ASN("ff00:0:0")))

        # Connect the backup client
        backup_channel = stub.StreamChannel(iter(backup_request_queue.get,
                                                 None),
                                            metadata=backup_call_cred)

        request = peering_pb2.StreamMessageRequest()
        request.arbitration.election_id = 0
        backup_request_queue.put(request)

        response = next(backup_channel)
        self.assertEqual(response.arbitration.vlan, "prod")
        self.assertEqual(response.arbitration.status,
                         peering_pb2.ArbitrationUpdate.Status.PRIMARY)
        clients = ClientRegistry.get_clients(ASN("ff00:0:0"))
        self.assertEqual(len(clients.connections), 1)
        self.assertTrue(clients.is_primary_client("backup", "prod"))
        self.assertFalse(clients.is_primary_client("default", "test"))

        # Connect the default client
        default_channel = stub.StreamChannel(iter(default_request_queue.get,
                                                  None),
                                             metadata=default_call_cred)

        request = peering_pb2.StreamMessageRequest()
        request.arbitration.election_id = 100
        default_request_queue.put(request)

        response = next(default_channel)
        self.assertEqual(response.arbitration.vlan, "prod")
        self.assertEqual(response.arbitration.status,
                         peering_pb2.ArbitrationUpdate.Status.PRIMARY)
        response = next(default_channel)
        self.assertEqual(response.arbitration.vlan, "test")
        self.assertEqual(response.arbitration.status,
                         peering_pb2.ArbitrationUpdate.Status.PRIMARY)

        response = next(backup_channel)
        self.assertEqual(response.arbitration.vlan, "prod")
        self.assertEqual(response.arbitration.status,
                         peering_pb2.ArbitrationUpdate.Status.NOT_PRIMARY)
        self.assertEqual(len(clients.connections), 2)
        self.assertFalse(clients.is_primary_client("backup", "prod"))
        self.assertTrue(clients.is_primary_client("default", "prod"))
        self.assertTrue(clients.is_primary_client("default", "test"))

        # Disconnect the default client
        default_request_queue.put(None)
        for response in default_channel:
            self.assertTrue(False, "Unexpected additional messages on stream")

        response = next(backup_channel)
        self.assertEqual(response.arbitration.status,
                         peering_pb2.ArbitrationUpdate.Status.PRIMARY)
        self.assertEqual(len(clients.connections), 1)
        self.assertTrue(clients.is_primary_client("backup", "prod"))
        self.assertFalse(clients.is_primary_client("default", "test"))

        # Disconnect the backup client
        backup_request_queue.put(None)
        for response in backup_channel:
            self.assertTrue(False, "Unexpected additional messages on stream")

        self.assertIsNone(ClientRegistry.get_clients(ASN("ff00:0:0")))
Beispiel #19
0
 def test_asn_deparsing(self):
     for string, integer in self.TEST_CASES:
         with self.subTest(string=string, integer=integer):
             self.assertEqual(str(ASN(integer)), string)
 def to_python(self, value: str) -> ASN:
     # ValueError is thrown to indicate no match.
     return ASN(value.replace("-", ":"))