cli.py 3.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114
  1. #!/usr/bin/env python3
  2. # SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause
  3. import argparse
  4. import json
  5. import pprint
  6. import time
  7. from lib import YnlFamily, Netlink, NlError
  8. class YnlEncoder(json.JSONEncoder):
  9. def default(self, obj):
  10. if isinstance(obj, bytes):
  11. return bytes.hex(obj)
  12. if isinstance(obj, set):
  13. return list(obj)
  14. return json.JSONEncoder.default(self, obj)
  15. def main():
  16. description = """
  17. YNL CLI utility - a general purpose netlink utility that uses YAML
  18. specs to drive protocol encoding and decoding.
  19. """
  20. epilog = """
  21. The --multi option can be repeated to include several do operations
  22. in the same netlink payload.
  23. """
  24. parser = argparse.ArgumentParser(description=description,
  25. epilog=epilog)
  26. parser.add_argument('--spec', dest='spec', type=str, required=True)
  27. parser.add_argument('--schema', dest='schema', type=str)
  28. parser.add_argument('--no-schema', action='store_true')
  29. parser.add_argument('--json', dest='json_text', type=str)
  30. group = parser.add_mutually_exclusive_group()
  31. group.add_argument('--do', dest='do', metavar='DO-OPERATION', type=str)
  32. group.add_argument('--multi', dest='multi', nargs=2, action='append',
  33. metavar=('DO-OPERATION', 'JSON_TEXT'), type=str)
  34. group.add_argument('--dump', dest='dump', metavar='DUMP-OPERATION', type=str)
  35. group.add_argument('--list-ops', action='store_true')
  36. group.add_argument('--list-msgs', action='store_true')
  37. parser.add_argument('--sleep', dest='sleep', type=int)
  38. parser.add_argument('--subscribe', dest='ntf', type=str)
  39. parser.add_argument('--replace', dest='flags', action='append_const',
  40. const=Netlink.NLM_F_REPLACE)
  41. parser.add_argument('--excl', dest='flags', action='append_const',
  42. const=Netlink.NLM_F_EXCL)
  43. parser.add_argument('--create', dest='flags', action='append_const',
  44. const=Netlink.NLM_F_CREATE)
  45. parser.add_argument('--append', dest='flags', action='append_const',
  46. const=Netlink.NLM_F_APPEND)
  47. parser.add_argument('--process-unknown', action=argparse.BooleanOptionalAction)
  48. parser.add_argument('--output-json', action='store_true')
  49. parser.add_argument('--dbg-small-recv', default=0, const=4000,
  50. action='store', nargs='?', type=int)
  51. args = parser.parse_args()
  52. def output(msg):
  53. if args.output_json:
  54. print(json.dumps(msg, cls=YnlEncoder))
  55. else:
  56. pprint.PrettyPrinter().pprint(msg)
  57. if args.no_schema:
  58. args.schema = ''
  59. attrs = {}
  60. if args.json_text:
  61. attrs = json.loads(args.json_text)
  62. ynl = YnlFamily(args.spec, args.schema, args.process_unknown,
  63. recv_size=args.dbg_small_recv)
  64. if args.dbg_small_recv:
  65. ynl.set_recv_dbg(True)
  66. if args.ntf:
  67. ynl.ntf_subscribe(args.ntf)
  68. if args.sleep:
  69. time.sleep(args.sleep)
  70. if args.list_ops:
  71. for op_name, op in ynl.ops.items():
  72. print(op_name, " [", ", ".join(op.modes), "]")
  73. if args.list_msgs:
  74. for op_name, op in ynl.msgs.items():
  75. print(op_name, " [", ", ".join(op.modes), "]")
  76. try:
  77. if args.do:
  78. reply = ynl.do(args.do, attrs, args.flags)
  79. output(reply)
  80. if args.dump:
  81. reply = ynl.dump(args.dump, attrs)
  82. output(reply)
  83. if args.multi:
  84. ops = [ (item[0], json.loads(item[1]), args.flags or []) for item in args.multi ]
  85. reply = ynl.do_multi(ops)
  86. output(reply)
  87. except NlError as e:
  88. print(e)
  89. exit(1)
  90. if args.ntf:
  91. ynl.check_ntf()
  92. output(ynl.async_msg_queue)
  93. if __name__ == "__main__":
  94. main()