Collection of GNS3 GUI Tools
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

229 lines
8.1 KiB

  1. #!/usr/local/bin/python3
  2. """
  3. export_template.py - Export Template as an Appliance
  4. """
  5. import os
  6. import sys
  7. import json
  8. import re
  9. from collections import OrderedDict
  10. import gns3api
  11. from qt_widgets import SimpleWidgets
  12. widget = SimpleWidgets()
  13. def die(text):
  14. """ terminate program with error message """
  15. widget.alert(None, text)
  16. sys.exit(text)
  17. # get command line parameter
  18. if len(sys.argv) < 3:
  19. die("usage: export_template version parameter-file [project-id [sel-item ...]]")
  20. try:
  21. with open(sys.argv[2], "r") as file:
  22. cntl_url, cntl_user, cntl_passwd, *_ = file.read(512).splitlines()
  23. if sys.argv[2].endswith(".tmp"):
  24. os.remove(sys.argv[2])
  25. except (OSError, ValueError) as err:
  26. die("Can't get controller connection params: {}".format(err))
  27. version = sys.argv[1]
  28. # check version
  29. ver_match = re.match(r'[vV]?(\d+)\.(\d+)', version)
  30. if ver_match:
  31. ver_tuple = tuple(map(int, ver_match.groups()))
  32. if not ver_match or ver_tuple < (2, 2):
  33. die("Unsupported version {}, need at least 2.2".format(version))
  34. # connect to GNS3 controller
  35. try:
  36. api = gns3api.GNS3Api(cntl_url, cntl_user, cntl_passwd)
  37. except gns3api.GNS3ApiException as err:
  38. die("Can't connect to GNS3 controller: {}".format(err))
  39. template_name = widget.get_text(None, "Template name:")
  40. if not template_name:
  41. sys.exit(0)
  42. template = None
  43. try:
  44. for template in api.request("GET", "/v2/templates"):
  45. if template["name"] == template_name:
  46. break
  47. else:
  48. die("Template '{}' not found".format(template_name))
  49. except gns3api.GNS3ApiException as err:
  50. die("Can't get templates: {}".format(err))
  51. if template["template_type"] not in ("docker", "dynamips", "iou", "qemu"):
  52. die("Unsupported VM type '{}', must be docker, dynamips, iou or qemu."
  53. .format(template["template_type"]))
  54. # basic information
  55. gns3a = OrderedDict()
  56. gns3a["name"] = template["name"]
  57. if template["category"] == "switch":
  58. gns3a["category"] = "multilayer_switch"
  59. else:
  60. gns3a["category"] = template["category"]
  61. gns3a["description"] = "Export of template '{}'".format(template["name"])
  62. gns3a["vendor_name"] = "unknown"
  63. gns3a["vendor_url"] = "http://www.example.com"
  64. gns3a["product_name"] = template["name"]
  65. gns3a["registry_version"] = 3
  66. gns3a["status"] = "experimental"
  67. gns3a["maintainer"] = "Unknown"
  68. gns3a["maintainer_email"] = "unknown@example.org"
  69. for key in ("usage", "symbol", "first_port_name", "port_name_format"):
  70. if template.get(key):
  71. gns3a[key] = template[key]
  72. if not template.get("linked_clone", True):
  73. gns3a["linked_clone"] = False
  74. gns3a["registry_version"] = 4
  75. vm_images = OrderedDict()
  76. # Docker
  77. if template["template_type"] == "docker":
  78. docker = OrderedDict()
  79. gns3a["docker"] = docker
  80. docker["adapters"] = template.get("adapters", 1)
  81. for key in ("image", "start_command", "environment",
  82. "console_type", "console_http_port", "console_http_path"):
  83. if template.get(key):
  84. docker[key] = template[key]
  85. if docker["image"].endswith(":latest"):
  86. docker["image"] = docker["image"][:-7]
  87. if docker.get("console_type") not in ("http", "https"):
  88. docker.pop("console_http_port", None)
  89. docker.pop("console_http_path", None)
  90. # Dynamips
  91. elif template["template_type"] == "dynamips":
  92. dynamips = OrderedDict()
  93. gns3a["dynamips"] = dynamips
  94. for key in ("chassis", "platform", "ram", "nvram", "startup_config",
  95. "wic0", "wic1", "wic2", "slot0", "slot1", "slot2", "slot3",
  96. "slot4", "slot5", "slot6", "midplane", "npe"):
  97. if template.get(key):
  98. dynamips[key] = template[key]
  99. vm_images["image"] = template["image"]
  100. # IOU VM
  101. elif template["template_type"] == "iou":
  102. iou = OrderedDict()
  103. gns3a["iou"] = iou
  104. for key in ("ethernet_adapters", "serial_adapters",
  105. "nvram", "ram", "startup_config"):
  106. iou[key] = template[key]
  107. vm_images["image"] = template["path"]
  108. # QEMU
  109. elif template["template_type"] == "qemu":
  110. qemu = OrderedDict()
  111. gns3a["qemu"] = qemu
  112. qemu["adapter_type"] = template.get("adapter_type", "e1000")
  113. qemu["adapters"] = template.get("adapters", 1)
  114. if template.get("custom_adapters"):
  115. qemu["custom_adapters"] = template["custom_adapters"]
  116. gns3a["registry_version"] = max(gns3a["registry_version"], 6)
  117. qemu["ram"] = template.get("ram", 256)
  118. if template.get("cpus", 1) >= 2:
  119. qemu["cpus"] = template["cpus"]
  120. gns3a["registry_version"] = max(gns3a["registry_version"], 4)
  121. for key in ("kernel_image", "initrd", "bios_image"):
  122. if template.get(key):
  123. vm_images[key] = template[key]
  124. if "bios_image" in vm_images:
  125. gns3a["registry_version"] = max(gns3a["registry_version"], 4)
  126. for key in ("hda", "hdb", "hdc", "hdd"):
  127. hd_image = key + "_disk_image"
  128. hd_intf = key + "_disk_interface"
  129. if template.get(hd_image):
  130. vm_images[hd_image] = template[hd_image]
  131. qemu[hd_intf] = template.get(hd_intf, "ide")
  132. if qemu[hd_intf] == "sata":
  133. gns3a["registry_version"] = max(gns3a["registry_version"], 4)
  134. if template.get("cdrom_image"):
  135. vm_images["cdrom_image"] = template["cdrom_image"]
  136. match = re.search(r'qemu-system-([^/\\]*)$', template["qemu_path"])
  137. if match:
  138. qemu["arch"] = match.group(1)
  139. else:
  140. qemu["arch"] = "i386"
  141. qemu["console_type"] = template.get("console_type", "telnet")
  142. if qemu["console_type"] == "spice":
  143. gns3a["registry_version"] = max(gns3a["registry_version"], 5)
  144. if template.get("boot_priority") and template["boot_priority"] != "c":
  145. qemu["boot_priority"] = template["boot_priority"]
  146. if template.get("kernel_command_line"):
  147. qemu["kernel_command_line"] = template["kernel_command_line"]
  148. qemu["kvm"] = "allow"
  149. options = template.get("options")
  150. if options:
  151. options, changes = re.subn(r'\s*-no-kvm\b', "", options)
  152. if changes:
  153. qemu["kvm"] = "disable"
  154. options = re.sub(r'\s*-nographic\b', "", options)
  155. options = options.strip()
  156. if options:
  157. qemu["options"] = options
  158. if template.get("cpu_throttling"):
  159. qemu["cpu_throttling"] = template["cpu_throttling"]
  160. if template.get("process_priority") and \
  161. template["process_priority"] != "normal":
  162. qemu["process_priority"] = template["process_priority"]
  163. # Images
  164. image_version = "0.0"
  165. if vm_images:
  166. try:
  167. image_list = api.request("GET", ("/v2/computes",
  168. template["compute_id"],
  169. template["template_type"],
  170. "images"))
  171. except gns3api.GNS3ApiException as err:
  172. die("Can't get image list: {}".format(err))
  173. images = []
  174. version_images = OrderedDict()
  175. for image_type, path in vm_images.items():
  176. filename = re.split(r'[/\\]', path)[-1]
  177. filesize = 0
  178. md5sum = "00000000000000000000000000000000"
  179. for image_info in image_list:
  180. if image_info["filename"] == filename:
  181. filesize = image_info["filesize"]
  182. md5sum = image_info["md5sum"]
  183. break
  184. image = OrderedDict()
  185. image["filename"] = filename
  186. image["version"] = image_version
  187. image["md5sum"] = md5sum
  188. image["filesize"] = filesize
  189. images.append(image)
  190. version_images[image_type] = filename
  191. gns3a["images"] = images
  192. version_ver = OrderedDict()
  193. version_ver["name"] = image_version
  194. if template.get("idlepc"):
  195. version_ver["idlepc"] = template["idlepc"]
  196. version_ver["images"] = version_images
  197. gns3a["versions"] = [version_ver]
  198. # save appliance
  199. ofile = widget.get_save_filename("Save appliance", "~",
  200. (("GNS3 Appliance", "*.gns3a *.gns3appliance"),
  201. ("all files", "*")))
  202. if not ofile:
  203. sys.exit(0)
  204. try:
  205. with open(ofile, "w") as f_out:
  206. json.dump(gns3a, f_out, indent=4, separators=(",", ": "))
  207. f_out.write("\n")
  208. except OSError as err:
  209. die("Can't save appliance: {}".format(err))