run_cli.py 2.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101
  1. #!/usr/bin/env python3
  2. import argparse
  3. import sys
  4. import re
  5. import subprocess
  6. import os
  7. import json
  8. def main():
  9. parser = argparse.ArgumentParser(prog=sys.argv[0], description="Configure a switch port")
  10. parser.add_argument(
  11. "--switch",
  12. "-s",
  13. metavar="<SWITCH NAME(s)>",
  14. help="Switch name or names (comma-separated) on which to run commands (defaults to all) ",
  15. )
  16. parser.add_argument(
  17. "--commands", "-c", metavar="<COMMAND(s)>", help="Pipe-separated list of commands to run",
  18. )
  19. parser.add_argument(
  20. "--parents", "-p", metavar="<PARENT(s)>", help="Pipe-separated list of parents for all commands",
  21. )
  22. parser.add_argument(
  23. "--input", "-i", metavar="<INPUT_FILE>", help="Path to an input file with commands formated like config",
  24. )
  25. parser.add_argument(
  26. "--username", "-u", metavar="<USERNAME>", help="Username to use to connect to the N9Ks", required=True,
  27. )
  28. args = parser.parse_args()
  29. if not args.commands and not args.input:
  30. print("ERROR: Either --commands or --input is required.")
  31. sys.exit(1)
  32. if args.commands and args.input:
  33. print("ERROR: Only one of --commands or --input can be specified.")
  34. sys.exit(1)
  35. plist = []
  36. clist = []
  37. if args.input:
  38. contents = None
  39. try:
  40. with open(args.input, "r") as fd:
  41. contents = fd.read()
  42. lines = contents.split("\n")
  43. m = re.findall(r"^(\s+)", contents, re.M)
  44. if len(m) > 0:
  45. for line in lines:
  46. if re.search(r"^\s", line):
  47. clist.append(line)
  48. else:
  49. plist.append(line)
  50. else:
  51. clist = lines
  52. except Exception as e:
  53. print("ERROR: Failed to process input file: %s" % e)
  54. sys.exit(1)
  55. else:
  56. clist = args.commands.split("|")
  57. if args.parents:
  58. plist = args.parents.split("|")
  59. os.environ["ANSIBLE_FORCE_COLOR"] = "True"
  60. os.environ["ANSIBLE_HOST_KEY_CHECKING"] = "False"
  61. os.environ["ANSIBLE_PERSISTENT_COMMAND_TIMEOUT"] = "300"
  62. command = [
  63. "ansible-playbook",
  64. "-i",
  65. "inventory/hosts",
  66. "-u",
  67. args.username,
  68. "-k",
  69. "-e",
  70. '{{"cli_commands": {}}}'.format(json.dumps(clist)),
  71. "-e",
  72. '{{"cli_parents": {}}}'.format(json.dumps(plist)),
  73. "-e",
  74. "ansible_python_interpreter={}".format(sys.executable),
  75. "run-cli-playbook.yml",
  76. ]
  77. if args.switch:
  78. command += ["--limit", "{}".format(args.switch)]
  79. p = subprocess.Popen(command, stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
  80. for c in iter(lambda: p.stdout.read(1), b""):
  81. sys.stdout.write(c.decode("utf-8"))
  82. sys.stdout.flush()
  83. p.poll()
  84. if __name__ == "__main__":
  85. main()