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), ]
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()
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), ]
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
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))