run_cli.py 3.0 KB

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