def setUp(self):
        basic = Discrete(("VAL1", "VAL2"))
        default = Discrete(("VAL1", "VAL2"), default="VAL1")
        optional = Discrete(("VAL1", "VAL2"), optional=True)
        default_optional = Discrete(("VAL1", "VAL2"),
                                    default="VAL1",
                                    optional=True)
        case_insensitive = Discrete(("val1", "VAL2"), case_insensitive=True)

        self._pack = [
            (basic, "VAL1", "VAL1"),
            (basic, "VAL2", "VAL2"),
            (basic, "a", ValueError),
            (basic, "val1", ValueError),
            (basic, None, ValueError),
            (default, None, "VAL1"),
            (default_optional, None, "VAL1"),
            (optional, None, ValueError),
            (case_insensitive, "VAL1", "VAL1"),
            (case_insensitive, "vAl2", "vAl2"),
            (case_insensitive, "a", ValueError),
        ]

        self._unpack = [
            (basic, "VAL1", "VAL1"),
            (basic, "VAL2", "VAL2"),
            (basic, "a", ValueError),
            (basic, None, ValueError),
            (default, None, "VAL1"),
            (default_optional, None, "VAL1"),
            (optional, None, None),
            (case_insensitive, "val1", "val1"),
            (case_insensitive, "vAl2", "vAl2"),
            (case_insensitive, "a", ValueError),
        ]
Exemple #2
0
class NodeServer(AsyncDeviceServer):
    """Basic katcp server providing common sensors
       for monitoring a node.
    """
    VERSION_INFO = ("reynard-nodeserver-api", 0, 1)
    BUILD_INFO = ("reynard-nodeserver-implementation", 0, 1, "rc1")
    DEVICE_STATUSES = ["ok", "degraded", "fail"]

    def __init__(self, server_host, server_port, config):
        self._config = config
        self._monitors = {}
        super(NodeServer, self).__init__(server_host, server_port)

    @request()
    @return_reply(Discrete(DEVICE_STATUSES))
    def request_device_status(self, req):
        """Return the status of the instrument"""
        def status_query():
            # go and find out the status of all
            # subordinates.
            req.reply("ok", "degraded")

        self.ioloop.add_callback(status_query)
        raise AsyncReply

    def setup_sensors(self):
        """Set up basic monitoring sensors.

        Note: These are primarily for testing and
              will be replaced in the final build.
        """
        self._device_status = Sensor.discrete(
            "device-status",
            description="health status of node",
            params=self.DEVICE_STATUSES,
            default="ok")
        self.add_sensor(self._device_status)
        self._monitors["disk"] = DiskMonitor(self._config.VOLUMES)
        self._monitors["cpu"] = CpuMonitor()
        self._monitors["memory"] = MemoryMonitor()
        for monitor in self._monitors.values():
            for sensor in monitor.sensors():
                self.add_sensor(sensor)
            monitor.start()
Exemple #3
0
    def setUp(self):
        basic = Discrete(("VAL1", "VAL2"))
        default = Discrete(("VAL1", "VAL2"), default="VAL1")
        optional = Discrete(("VAL1", "VAL2"), optional=True)
        default_optional = Discrete(("VAL1", "VAL2"),
                                    default="VAL1",
                                    optional=True)
        case_insensitive = Discrete(("val1", "VAL2"), case_insensitive=True)
        values = ('VAL{}'.format(i + 1) for i in range(2))
        basic_generator = Discrete(values)

        self._pack = [
            (basic, "VAL1", b"VAL1"),
            (basic, "VAL2", b"VAL2"),
            (basic, "a", ValueError),
            (basic, "val1", ValueError),
            (basic, None, ValueError),
            (basic_generator, "VAL1", b"VAL1"),
            (basic_generator, "VAL2", b"VAL2"),
            (basic_generator, "a", ValueError),
            (basic_generator, "val1", ValueError),
            (basic_generator, None, ValueError),
            (default, None, b"VAL1"),
            (default_optional, None, b"VAL1"),
            (optional, None, ValueError),
            (case_insensitive, "VAL1", b"VAL1"),
            (case_insensitive, "vAl2", b"vAl2"),
            (case_insensitive, "a", ValueError),
        ]

        self._unpack = [
            (basic, b"VAL1", "VAL1"),
            (basic, b"VAL2", "VAL2"),
            (basic, b"a", ValueError),
            (basic, None, ValueError),
            (default, None, "VAL1"),
            (default_optional, None, "VAL1"),
            (optional, None, None),
            (case_insensitive, b"val1", "val1"),
            (case_insensitive, b"vAl2", "vAl2"),
            (case_insensitive, b"a", ValueError),
        ]
Exemple #4
0
        except KeyError, e:
            return ("fail", str(e))
        return ("ok", "added client")

    @request()
    @return_reply(Str())
    def request_client_list(self, req):
        """List all available clients"""
        msg = [""]
        for ii, (name, client) in enumerate(self._clients.items()):
            msg.append("{client.name} {client.address}".format(client=client))
        req.inform("\n\_\_\_\_".join(msg))
        return ("ok", "{count} clients found".format(count=len(self._clients)))

    @request()
    @return_reply(Discrete(NodeServer.DEVICE_STATUSES))
    def request_device_status(self, req):
        """Return status of the instrument.

        Notes: Status is based on aggregate information
               from all subordinate client.

        Currently this is a dummy function to test chaining
        async calls.
        """
        @coroutine
        def status_handler():
            futures = {}
            for name, client in self._clients.items():
                future = client.req.device_status()
                futures[name] = future
class TestDevice(object):
    def __init__(self):
        self.sent_messages = []

    @request(Int(min=1, max=10), Discrete(("on", "off")), Bool())
    @return_reply(Int(min=1, max=10), Discrete(("on", "off")), Bool())
    def request_one(self, sock, i, d, b):
        if i == 3:
            return ("fail", "I failed!")
        if i == 5:
            return ("bananas", "This should never be sent")
        if i == 6:
            return ("ok", i, d, b, "extra parameter")
        if i == 9:
            # This actually gets put in the callback params automatically
            orig_msg = Message.request("one", "foo", "bar")
            self.finish_request_one(orig_msg, sock, i, d, b)
            raise AsyncReply()
        return ("ok", i, d, b)

    @send_reply(Int(min=1, max=10), Discrete(("on", "off")), Bool())
    def finish_request_one(self, msg, sock, i, d, b):
        return (sock, msg, "ok", i, d, b)

    def reply(self, sock, msg, orig_msg):
        self.sent_messages.append([sock, msg])

    @request(Int(min=1, max=3, default=2),
             Discrete(("on", "off"), default="off"), Bool(default=True))
    @return_reply(Int(min=1, max=3), Discrete(("on", "off")), Bool())
    def request_two(self, sock, i, d, b):
        return ("ok", i, d, b)

    @return_reply(Int(min=1, max=3), Discrete(("on", "off")), Bool())
    @request(Int(min=1, max=3), Discrete(("on", "off")), Bool())
    def request_three(self, sock, i, d, b):
        return ("ok", i, d, b)

    @return_reply()
    @request()
    def request_four(self, sock):
        return ["ok"]

    @inform(Int(min=1, max=3), Discrete(("on", "off")), Bool())
    def inform_one(self, sock, i, d, b):
        pass

    @request(Int(min=1, max=3), Discrete(("on", "off")), Bool())
    @return_reply(Int(min=1, max=3), Discrete(("on", "off")), Bool())
    def request_five(self, i, d, b):
        return ("ok", i, d, b)

    @return_reply(Int(min=1, max=3), Discrete(("on", "off")), Bool())
    @request(Int(min=1, max=3), Discrete(("on", "off")), Bool())
    def request_six(self, i, d, b):
        return ("ok", i, d, b)

    @return_reply(Int(), Str())
    @request(Int(), include_msg=True)
    def request_seven(self, msg, i):
        return ("ok", i, msg.name)

    @return_reply(Int(), Str())
    @request(Int(), include_msg=True)
    def request_eight(self, sock, msg, i):
        return ("ok", i, msg.name)
class MyServer(DeviceServer):

    VERSION_INFO = ("example-api", 1, 0)
    BUILD_INFO = ("example-implementation", 0, 1, "")

    # Optionally set the KATCP protocol version and features. Defaults to
    # the latest implemented version of KATCP, with all supported optional
    # features
    PROTOCOL_INFO = ProtocolFlags(5, 0, set([
        ProtocolFlags.MULTI_CLIENT,
        ProtocolFlags.MESSAGE_IDS,
    ]))

    FRUIT = [
        "apple", "banana", "pear", "kiwi",
    ]

    def setup_sensors(self):
        """Setup some server sensors."""
        self._add_result = Sensor.float("add.result",
            "Last ?add result.", "", [-10000, 10000])
        self._add_result.set_value(0, Sensor.UNREACHABLE)

        self._time_result = Sensor.timestamp("time.result",
            "Last ?time result.", "")
        self._time_result.set_value(0, Sensor.INACTIVE)

        self._eval_result = Sensor.string("eval.result",
            "Last ?eval result.", "")
        self._eval_result.set_value('', Sensor.UNKNOWN)

        self._fruit_result = Sensor.discrete("fruit.result",
            "Last ?pick-fruit result.", "", self.FRUIT)
        self._fruit_result.set_value('apple', Sensor.ERROR)

        self.add_sensor(self._add_result)
        self.add_sensor(self._time_result)
        self.add_sensor(self._eval_result)
        self.add_sensor(self._fruit_result)

    @request(Float(), Float())
    @return_reply(Float())
    def request_add(self, req, x, y):
        """Add two numbers"""
        r = x + y
        self._add_result.set_value(r)
        return ("ok", r)

    @request()
    @return_reply(Timestamp())
    def request_time(self, req):
        """Return the current time in ms since the Unix Epoch."""
        r = time.time()
        self._time_result.set_value(r)
        return ("ok", r)

    @request(Str())
    @return_reply(Str())
    def request_eval(self, req, expression):
        """Evaluate a Python expression."""
        r = str(eval(expression))
        self._eval_result.set_value(r)
        return ("ok", r)

    @request()
    @return_reply(Discrete(FRUIT))
    def request_pick_fruit(self, req):
        """Pick a random fruit."""
        r = random.choice(self.FRUIT + [None])
        if r is None:
            return ("fail", "No fruit.")
        delay = random.randrange(1,5)
        req.inform("Picking will take %d seconds" % delay)

        def pick_handler():
            self._fruit_result.set_value(r)
            req.reply("ok", r)

        handle_timer = threading.Timer(delay, pick_handler)
        handle_timer.start()

        raise AsyncReply

    @request(Str())
    @return_reply()
    def request_set_sensor_inactive(self, req, sensor_name):
        """Set sensor status to inactive"""
        sensor = self.get_sensor(sensor_name)
        ts, status, value = sensor.read()
        sensor.set_value(value, sensor.INACTIVE, ts)
        return('ok',)

    @request(Str())
    @return_reply()
    def request_set_sensor_unreachable(self, req, sensor_name):
        """Set sensor status to unreachable"""
        sensor = self.get_sensor(sensor_name)
        ts, status, value = sensor.read()
        sensor.set_value(value, sensor.UNREACHABLE, ts)
        return('ok',)

    def request_raw_reverse(self, req, msg):
        """
        A raw request handler to demonstrate the calling convention if
        @request decoraters are not used. Reverses the message arguments.
        """
        # msg is a katcp.Message.request object
        reversed_args = msg.arguments[::-1]
        # req.make_reply() makes a katcp.Message.reply using the correct request
        # name and message ID
        return req.make_reply(*reversed_args)
class TestDevice(object):
    def __init__(self):
        self.sent_messages = []

    @request(Int(min=1, max=10), Discrete(("on", "off")), Bool())
    @return_reply(Int(min=1, max=10), Discrete(("on", "off")), Bool())
    def request_one(self, req, i, d, b):
        if i == 3:
            return ("fail", "I failed!")
        if i == 5:
            return ("bananas", "This should never be sent")
        if i == 6:
            return ("ok", i, d, b, "extra parameter")
        if i == 9:
            self.finish_request_one(req, i, d, b)
            raise AsyncReply()
        return ("ok", i, d, b)

    @send_reply(Int(min=1, max=10), Discrete(("on", "off")), Bool())
    def finish_request_one(self, req, i, d, b):
        return (req, "ok", i, d, b)

    def reply(self, req, msg, orig_msg):
        self.sent_messages.append([req, msg])

    @request(Int(min=1, max=3, default=2),
             Discrete(("on", "off"), default="off"), Bool(default=True))
    @return_reply(Int(min=1, max=3), Discrete(("on", "off")), Bool())
    def request_two(self, req, i, d, b):
        return ("ok", i, d, b)

    @return_reply(Int(min=1, max=3), Discrete(("on", "off")), Bool())
    @request(Int(min=1, max=3), Discrete(("on", "off")), Bool())
    def request_three(self, req, i, d, b):
        return ("ok", i, d, b)

    @return_reply()
    @request()
    def request_four(self, req):
        return ["ok"]

    @inform(Int(min=1, max=3), Discrete(("on", "off")), Bool())
    def inform_one(self, i, d, b):
        pass

    @request(Timestamp(), Timestamp(optional=True), major=4)
    @return_reply(Timestamp(), Timestamp(default=321), major=4)
    def request_katcpv4_time(self, req, timestamp1, timestamp2):
        self.katcpv4_time1 = timestamp1
        self.katcpv4_time2 = timestamp2
        if timestamp2:
            return ('ok', timestamp1, timestamp2)
        else:
            return ('ok', timestamp1)

    @request(Timestamp(multiple=True), major=4)
    @return_reply(Timestamp(multiple=True), major=4)
    def request_katcpv4_time_multi(self, req, *timestamps):
        self.katcpv4_time_multi = timestamps
        return ('ok', ) + timestamps

    @return_reply(Int(), Str())
    @request(Int(), include_msg=True)
    def request_eight(self, req, msg, i):
        return ("ok", i, msg.name)

    @request(Int(), Float(multiple=True))
    @return_reply(Int(), Float(multiple=True))
    def request_int_multifloat(self, req, i, *floats):
        return ('ok', i) + floats
Exemple #8
0
 def test_discrete_values(self):
     values = ('VAL{}'.format(i + 1) for i in range(2))
     basic = Discrete(values)
     self.assertEqual(sorted(basic._values), sorted(basic._valid_values))