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.

230 lines
8.2KB

  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. if template.get(hd_intf) and template[hd_intf] != "ide":
  132. qemu[hd_intf] = template[hd_intf]
  133. if qemu[hd_intf] == "sata":
  134. gns3a["registry_version"] = max(gns3a["registry_version"], 4)
  135. if template.get("cdrom_image"):
  136. vm_images["cdrom_image"] = template["cdrom_image"]
  137. match = re.search(r'qemu-system-([^/\\]*)$', template["qemu_path"])
  138. if match:
  139. qemu["arch"] = match.group(1)
  140. else:
  141. qemu["arch"] = "i386"
  142. qemu["console_type"] = template.get("console_type", "telnet")
  143. if qemu["console_type"] == "spice":
  144. gns3a["registry_version"] = max(gns3a["registry_version"], 5)
  145. if template.get("boot_priority") and template["boot_priority"] != "c":
  146. qemu["boot_priority"] = template["boot_priority"]
  147. if template.get("kernel_command_line"):
  148. qemu["kernel_command_line"] = template["kernel_command_line"]
  149. qemu["kvm"] = "allow"
  150. options = template.get("options")
  151. if options:
  152. options, changes = re.subn(r'\s*-no-kvm\b', "", options)
  153. if changes:
  154. qemu["kvm"] = "disable"
  155. options = re.sub(r'\s*-nographic\b', "", options)
  156. options = options.strip()
  157. if options:
  158. qemu["options"] = options
  159. if template.get("cpu_throttling"):
  160. qemu["cpu_throttling"] = template["cpu_throttling"]
  161. if template.get("process_priority") and \
  162. template["process_priority"] != "normal":
  163. qemu["process_priority"] = template["process_priority"]
  164. # Images
  165. image_version = "0.0"
  166. if vm_images:
  167. try:
  168. image_list = api.request("GET", ("/v2/computes",
  169. template["compute_id"],
  170. template["template_type"],
  171. "images"))
  172. except gns3api.GNS3ApiException as err:
  173. die("Can't get image list: {}".format(err))
  174. images = []
  175. version_images = OrderedDict()
  176. for image_type, path in vm_images.items():
  177. filename = re.split(r'[/\\]', path)[-1]
  178. filesize = 0
  179. md5sum = "00000000000000000000000000000000"
  180. for image_info in image_list:
  181. if image_info["filename"] == filename:
  182. filesize = image_info["filesize"]
  183. md5sum = image_info["md5sum"]
  184. break
  185. image = OrderedDict()
  186. image["filename"] = filename
  187. image["version"] = image_version
  188. image["md5sum"] = md5sum
  189. image["filesize"] = filesize
  190. images.append(image)
  191. version_images[image_type] = filename
  192. gns3a["images"] = images
  193. version_ver = OrderedDict()
  194. version_ver["name"] = image_version
  195. if template.get("idlepc"):
  196. version_ver["idlepc"] = template["idlepc"]
  197. version_ver["images"] = version_images
  198. gns3a["versions"] = [version_ver]
  199. # save appliance
  200. ofile = widget.get_save_filename("Save appliance", "~",
  201. (("GNS3 Appliance", "*.gns3a *.gns3appliance"),
  202. ("all files", "*")))
  203. if not ofile:
  204. sys.exit(0)
  205. try:
  206. with open(ofile, "w") as f_out:
  207. json.dump(gns3a, f_out, indent=4, separators=(",", ": "))
  208. f_out.write("\n")
  209. except OSError as err:
  210. die("Can't save appliance: {}".format(err))