mirror of
https://github.com/GNS3/gns3-server
synced 2024-11-24 17:28:08 +00:00
Qemu integration stage 2, support for ASA and IDS.
This commit is contained in:
parent
d1715baae1
commit
aca9e0de56
@ -67,26 +67,6 @@ class Qemu(IModule):
|
||||
|
||||
def __init__(self, name, *args, **kwargs):
|
||||
|
||||
# get the qemu-img location
|
||||
config = Config.instance()
|
||||
qemu_config = config.get_section_config(name.upper())
|
||||
self._qemu_img_path = qemu_config.get("qemu_img_path")
|
||||
if not self._qemu_img_path or not os.path.isfile(self._qemu_img_path):
|
||||
paths = [os.getcwd()] + os.environ["PATH"].split(":")
|
||||
# look for qemu-img in the current working directory and $PATH
|
||||
for path in paths:
|
||||
try:
|
||||
if "qemu-img" in os.listdir(path) and os.access(os.path.join(path, "qemu-img"), os.X_OK):
|
||||
self._qemu_img_path = os.path.join(path, "qemu-img")
|
||||
break
|
||||
except OSError:
|
||||
continue
|
||||
|
||||
if not self._qemu_img_path:
|
||||
log.warning("qemu-img couldn't be found!")
|
||||
elif not os.access(self._qemu_img_path, os.X_OK):
|
||||
log.warning("qemu-img is not executable")
|
||||
|
||||
# a new process start when calling IModule
|
||||
IModule.__init__(self, name, *args, **kwargs)
|
||||
self._qemu_instances = {}
|
||||
@ -173,13 +153,6 @@ class Qemu(IModule):
|
||||
self.send_param_error()
|
||||
return
|
||||
|
||||
if "qemu_img_path" in request and request["qemu_img_path"]:
|
||||
self._qemu_img_path = request["qemu_img_path"]
|
||||
log.info("QEMU image utility path set to {}".format(self._qemu_img_path))
|
||||
for qemu_id in self._qemu_instances:
|
||||
qemu_instance = self._qemu_instances[qemu_id]
|
||||
qemu_instance.qemu_img_path = self._qemu_img_path
|
||||
|
||||
if "working_dir" in request:
|
||||
new_working_dir = request["working_dir"]
|
||||
log.info("this server is local with working directory path to {}".format(new_working_dir))
|
||||
@ -245,7 +218,6 @@ class Qemu(IModule):
|
||||
try:
|
||||
qemu_instance = QemuVM(name,
|
||||
qemu_path,
|
||||
self._qemu_img_path,
|
||||
self._working_dir,
|
||||
self._host,
|
||||
qemu_id,
|
||||
|
@ -23,6 +23,7 @@ import os
|
||||
import shutil
|
||||
import random
|
||||
import subprocess
|
||||
import shlex
|
||||
|
||||
from .qemu_error import QemuError
|
||||
from .adapters.ethernet_adapter import EthernetAdapter
|
||||
@ -39,7 +40,6 @@ class QemuVM(object):
|
||||
|
||||
:param name: name of this QEMU VM
|
||||
:param qemu_path: path to the QEMU binary
|
||||
:param qemu_img_path: path to the QEMU IMG binary
|
||||
:param working_dir: path to a working directory
|
||||
:param host: host/address to bind for console and UDP connections
|
||||
:param qemu_id: QEMU VM instance ID
|
||||
@ -54,7 +54,6 @@ class QemuVM(object):
|
||||
def __init__(self,
|
||||
name,
|
||||
qemu_path,
|
||||
qemu_img_path,
|
||||
working_dir,
|
||||
host="127.0.0.1",
|
||||
qemu_id=None,
|
||||
@ -85,18 +84,21 @@ class QemuVM(object):
|
||||
self._started = False
|
||||
self._process = None
|
||||
self._stdout_file = ""
|
||||
self._qemu_img_path = qemu_img_path
|
||||
self._console_start_port_range = console_start_port_range
|
||||
self._console_end_port_range = console_end_port_range
|
||||
|
||||
# QEMU settings
|
||||
self._qemu_path = qemu_path
|
||||
self._disk_image = ""
|
||||
self._hda_disk_image = ""
|
||||
self._hdb_disk_image = ""
|
||||
self._options = ""
|
||||
self._ram = 256
|
||||
self._console = console
|
||||
self._ethernet_adapters = []
|
||||
self._adapter_type = "e1000"
|
||||
self._initrd = ""
|
||||
self._kernel_image = ""
|
||||
self._kernel_command_line = ""
|
||||
|
||||
working_dir_path = os.path.join(working_dir, "qemu", "vm-{}".format(self._id))
|
||||
|
||||
@ -134,11 +136,15 @@ class QemuVM(object):
|
||||
qemu_defaults = {"name": self._name,
|
||||
"qemu_path": self._qemu_path,
|
||||
"ram": self._ram,
|
||||
"disk_image": self._disk_image,
|
||||
"hda_disk_image": self._hda_disk_image,
|
||||
"hdb_disk_image": self._hdb_disk_image,
|
||||
"options": self._options,
|
||||
"adapters": self.adapters,
|
||||
"adapter_type": self._adapter_type,
|
||||
"console": self._console}
|
||||
"console": self._console,
|
||||
"initrd": self._initrd,
|
||||
"kernel_image": self._kernel_image,
|
||||
"kernel_command_line": self._kernel_command_line}
|
||||
|
||||
return qemu_defaults
|
||||
|
||||
@ -306,50 +312,51 @@ class QemuVM(object):
|
||||
self._qemu_path = qemu_path
|
||||
|
||||
@property
|
||||
def qemu_img_path(self):
|
||||
def hda_disk_image(self):
|
||||
"""
|
||||
Returns the QEMU IMG binary path for this QEMU VM.
|
||||
Returns the hda disk image path for this QEMU VM.
|
||||
|
||||
:returns: QEMU IMG path
|
||||
:returns: QEMU hda disk image path
|
||||
"""
|
||||
|
||||
return self._qemu_img_path
|
||||
return self._hda_disk_image
|
||||
|
||||
@qemu_img_path.setter
|
||||
def qemu_img_path(self, qemu_img_path):
|
||||
@hda_disk_image.setter
|
||||
def hda_disk_image(self, hda_disk_image):
|
||||
"""
|
||||
Sets the QEMU IMG binary path this QEMU VM.
|
||||
Sets the hda disk image for this QEMU VM.
|
||||
|
||||
:param qemu_img_path: QEMU IMG path
|
||||
:param hda_disk_image: QEMU hda disk image path
|
||||
"""
|
||||
|
||||
log.info("QEMU VM {name} [id={id}] has set the QEMU IMG path to {qemu_img_path}".format(name=self._name,
|
||||
log.info("QEMU VM {name} [id={id}] has set the QEMU hda disk image path to {disk_image}".format(name=self._name,
|
||||
id=self._id,
|
||||
qemu_img_path=qemu_img_path))
|
||||
self._qemu_img_path = qemu_img_path
|
||||
disk_image=hda_disk_image))
|
||||
self._hda_disk_image = hda_disk_image
|
||||
|
||||
@property
|
||||
def disk_image(self):
|
||||
def hdb_disk_image(self):
|
||||
"""
|
||||
Returns the disk image path for this QEMU VM.
|
||||
Returns the hdb disk image path for this QEMU VM.
|
||||
|
||||
:returns: QEMU disk image path
|
||||
:returns: QEMU hdb disk image path
|
||||
"""
|
||||
|
||||
return self._disk_image
|
||||
return self._hdb_disk_image
|
||||
|
||||
@disk_image.setter
|
||||
def disk_image(self, disk_image):
|
||||
@hdb_disk_image.setter
|
||||
def hdb_disk_image(self, hdb_disk_image):
|
||||
"""
|
||||
Sets the disk image for this QEMU VM.
|
||||
Sets the hdb disk image for this QEMU VM.
|
||||
|
||||
:param disk_image: QEMU disk image path
|
||||
:param hdb_disk_image: QEMU hdb disk image path
|
||||
"""
|
||||
|
||||
log.info("QEMU VM {name} [id={id}] has set the QEMU disk image path to {disk_image}".format(name=self._name,
|
||||
log.info("QEMU VM {name} [id={id}] has set the QEMU hdb disk image path to {disk_image}".format(name=self._name,
|
||||
id=self._id,
|
||||
disk_image=disk_image))
|
||||
self._disk_image = disk_image
|
||||
disk_image=hdb_disk_image))
|
||||
self._hdb_disk_image = hdb_disk_image
|
||||
|
||||
|
||||
@property
|
||||
def adapters(self):
|
||||
@ -401,6 +408,121 @@ class QemuVM(object):
|
||||
id=self._id,
|
||||
adapter_type=adapter_type))
|
||||
|
||||
@property
|
||||
def ram(self):
|
||||
"""
|
||||
Returns the RAM amount for this QEMU VM.
|
||||
|
||||
:returns: RAM amount in MB
|
||||
"""
|
||||
|
||||
return self._ram
|
||||
|
||||
@ram.setter
|
||||
def ram(self, ram):
|
||||
"""
|
||||
Sets the amount of RAM for this QEMU VM.
|
||||
|
||||
:param ram: RAM amount in MB
|
||||
"""
|
||||
|
||||
log.info("QEMU VM {name} [id={id}] has set the RAM to {ram}".format(name=self._name,
|
||||
id=self._id,
|
||||
ram=ram))
|
||||
self._ram = ram
|
||||
|
||||
@property
|
||||
def options(self):
|
||||
"""
|
||||
Returns the options for this QEMU VM.
|
||||
|
||||
:returns: QEMU options
|
||||
"""
|
||||
|
||||
return self._options
|
||||
|
||||
@options.setter
|
||||
def options(self, options):
|
||||
"""
|
||||
Sets the options for this QEMU VM.
|
||||
|
||||
:param options: QEMU options
|
||||
"""
|
||||
|
||||
log.info("QEMU VM {name} [id={id}] has set the QEMU options to {options}".format(name=self._name,
|
||||
id=self._id,
|
||||
options=options))
|
||||
self._options = options
|
||||
|
||||
@property
|
||||
def initrd(self):
|
||||
"""
|
||||
Returns the initrd path for this QEMU VM.
|
||||
|
||||
:returns: QEMU initrd path
|
||||
"""
|
||||
|
||||
return self._initrd
|
||||
|
||||
@initrd.setter
|
||||
def initrd(self, initrd):
|
||||
"""
|
||||
Sets the initrd path for this QEMU VM.
|
||||
|
||||
:param initrd: QEMU initrd path
|
||||
"""
|
||||
|
||||
log.info("QEMU VM {name} [id={id}] has set the QEMU initrd path to {initrd}".format(name=self._name,
|
||||
id=self._id,
|
||||
initrd=initrd))
|
||||
self._initrd = initrd
|
||||
|
||||
@property
|
||||
def kernel_image(self):
|
||||
"""
|
||||
Returns the kernel image path for this QEMU VM.
|
||||
|
||||
:returns: QEMU kernel image path
|
||||
"""
|
||||
|
||||
return self._kernel_image
|
||||
|
||||
@kernel_image.setter
|
||||
def kernel_image(self, kernel_image):
|
||||
"""
|
||||
Sets the kernel image path for this QEMU VM.
|
||||
|
||||
:param kernel_image: QEMU kernel image path
|
||||
"""
|
||||
|
||||
log.info("QEMU VM {name} [id={id}] has set the QEMU kernel image path to {kernel_image}".format(name=self._name,
|
||||
id=self._id,
|
||||
kernel_image=kernel_image))
|
||||
self._kernel_image = kernel_image
|
||||
|
||||
@property
|
||||
def kernel_command_line(self):
|
||||
"""
|
||||
Returns the kernel command line for this QEMU VM.
|
||||
|
||||
:returns: QEMU kernel command line
|
||||
"""
|
||||
|
||||
return self._kernel_command_line
|
||||
|
||||
@kernel_command_line.setter
|
||||
def kernel_command_line(self, kernel_command_line):
|
||||
"""
|
||||
Sets the kernel command line for this QEMU VM.
|
||||
|
||||
:param kernel_command_line: QEMU kernel command line
|
||||
"""
|
||||
|
||||
log.info("QEMU VM {name} [id={id}] has set the QEMU kernel command line to {kernel_command_line}".format(name=self._name,
|
||||
id=self._id,
|
||||
kernel_command_line=kernel_command_line))
|
||||
self._kernel_command_line = kernel_command_line
|
||||
|
||||
def start(self):
|
||||
"""
|
||||
Starts this QEMU VM.
|
||||
@ -411,9 +533,7 @@ class QemuVM(object):
|
||||
if not os.path.isfile(self._qemu_path) or not os.path.exists(self._qemu_path):
|
||||
raise QemuError("QEMU binary '{}' is not accessible".format(self._qemu_path))
|
||||
|
||||
#TODO: check binary image is valid?
|
||||
self._command = self._build_command()
|
||||
|
||||
try:
|
||||
log.info("starting QEMU: {}".format(self._command))
|
||||
self._stdout_file = os.path.join(self._working_dir, "qemu.log")
|
||||
@ -567,36 +687,81 @@ class QemuVM(object):
|
||||
|
||||
def _disk_options(self):
|
||||
|
||||
hda_disk = os.path.join(self._working_dir, "hda.disk")
|
||||
if not os.path.exists(hda_disk):
|
||||
options = []
|
||||
qemu_img_path = ""
|
||||
qemu_path_dir = os.path.dirname(self._qemu_path)
|
||||
try:
|
||||
retcode = subprocess.call([self._qemu_img_path, "create", "-o",
|
||||
"backing_file={}".format(self._disk_image),
|
||||
for f in os.listdir(qemu_path_dir):
|
||||
if f.startswith("qemu-img"):
|
||||
qemu_img_path = os.path.join(qemu_path_dir, f)
|
||||
except OSError as e:
|
||||
raise QemuError("Error while looking for qemu-img in {}: {}".format(qemu_path_dir, e))
|
||||
|
||||
if not qemu_img_path:
|
||||
raise QemuError("Could not find qemu-img in {}".format(qemu_path_dir))
|
||||
|
||||
try:
|
||||
if self._hda_disk_image:
|
||||
hda_disk = os.path.join(self._working_dir, "hda_disk.qcow2")
|
||||
if not os.path.exists(hda_disk):
|
||||
retcode = subprocess.call([qemu_img_path, "create", "-o",
|
||||
"backing_file={}".format(self._hda_disk_image),
|
||||
"-f", "qcow2", hda_disk])
|
||||
log.info("{} returned with {}".format(self._qemu_img_path, retcode))
|
||||
log.info("{} returned with {}".format(qemu_img_path, retcode))
|
||||
else:
|
||||
# create a "FLASH" with 256MB if no disk image has been specified
|
||||
hda_disk = os.path.join(self._working_dir, "flash.qcow2")
|
||||
if not os.path.exists(hda_disk):
|
||||
retcode = subprocess.call([qemu_img_path, "create", "-f", "qcow2", hda_disk, "256M"])
|
||||
log.info("{} returned with {}".format(qemu_img_path, retcode))
|
||||
|
||||
except OSError as e:
|
||||
raise QemuError("Could not create disk image {}".format(e))
|
||||
|
||||
return ["-hda", hda_disk]
|
||||
options.extend(["-hda", hda_disk])
|
||||
if self._hdb_disk_image:
|
||||
hdb_disk = os.path.join(self._working_dir, "hdb_disk.qcow2")
|
||||
if not os.path.exists(hdb_disk):
|
||||
try:
|
||||
retcode = subprocess.call([qemu_img_path, "create", "-o",
|
||||
"backing_file={}".format(self._hdb_disk_image),
|
||||
"-f", "qcow2", hdb_disk])
|
||||
log.info("{} returned with {}".format(qemu_img_path, retcode))
|
||||
except OSError as e:
|
||||
raise QemuError("Could not create disk image {}".format(e))
|
||||
options.extend(["-hdb", hdb_disk])
|
||||
|
||||
return options
|
||||
|
||||
def _linux_boot_options(self):
|
||||
|
||||
options = []
|
||||
if self._initrd:
|
||||
options.extend(["-initrd", self._initrd])
|
||||
if self._kernel_image:
|
||||
options.extend(["-kernel", self._kernel_image])
|
||||
if self._kernel_command_line:
|
||||
options.extend(["-append", self._kernel_command_line])
|
||||
|
||||
return options
|
||||
|
||||
def _network_options(self):
|
||||
|
||||
network_options = []
|
||||
adapter_id = 0
|
||||
for adapter in self._ethernet_adapters:
|
||||
nio = adapter.get_nio(0)
|
||||
if nio:
|
||||
#TODO: let users specific the base mac address
|
||||
#TODO: let users specify a base mac address
|
||||
mac = "00:00:ab:%02x:%02x:%02d" % (random.randint(0x00, 0xff), random.randint(0x00, 0xff), adapter_id)
|
||||
network_options.extend(["-device", "{},mac={},netdev=gns3-{}".format(self._adapter_type, mac, adapter_id)])
|
||||
if isinstance(nio, NIO_UDP):
|
||||
nio = adapter.get_nio(0)
|
||||
if nio and isinstance(nio, NIO_UDP):
|
||||
network_options.extend(["-netdev", "socket,id=gns3-{},udp={}:{},localaddr={}:{}".format(adapter_id,
|
||||
nio.rhost,
|
||||
nio.rport,
|
||||
self._host,
|
||||
nio.lport)])
|
||||
else:
|
||||
network_options.extend(["-device", "{}".format(self._adapter_type)])
|
||||
network_options.extend(["-netdev", "user,id=gns3-{}".format(adapter_id)])
|
||||
adapter_id += 1
|
||||
|
||||
return network_options
|
||||
@ -611,6 +776,10 @@ class QemuVM(object):
|
||||
command.extend(["-name", self._name])
|
||||
command.extend(["-m", str(self._ram)])
|
||||
command.extend(self._disk_options())
|
||||
command.extend(self._linux_boot_options())
|
||||
command.extend(self._serial_options())
|
||||
additional_options = self._options.strip()
|
||||
if additional_options:
|
||||
command.extend(shlex.split(additional_options))
|
||||
command.extend(self._network_options())
|
||||
return command
|
||||
|
@ -79,8 +79,13 @@ QEMU_UPDATE_SCHEMA = {
|
||||
"type": "string",
|
||||
"minLength": 1,
|
||||
},
|
||||
"disk_image": {
|
||||
"description": "QEMU disk image path",
|
||||
"hda_disk_image": {
|
||||
"description": "QEMU hda disk image path",
|
||||
"type": "string",
|
||||
"minLength": 1,
|
||||
},
|
||||
"hdb_disk_image": {
|
||||
"description": "QEMU hdb disk image path",
|
||||
"type": "string",
|
||||
"minLength": 1,
|
||||
},
|
||||
@ -105,6 +110,21 @@ QEMU_UPDATE_SCHEMA = {
|
||||
"maximum": 65535,
|
||||
"type": "integer"
|
||||
},
|
||||
"initrd": {
|
||||
"description": "QEMU initrd path",
|
||||
"type": "string",
|
||||
"minLength": 1,
|
||||
},
|
||||
"kernel_image": {
|
||||
"description": "QEMU kernel image path",
|
||||
"type": "string",
|
||||
"minLength": 1,
|
||||
},
|
||||
"kernel_command_line": {
|
||||
"description": "QEMU kernel command line",
|
||||
"type": "string",
|
||||
"minLength": 1,
|
||||
},
|
||||
"options": {
|
||||
"description": "additional QEMU options",
|
||||
"type": "string",
|
||||
|
@ -23,5 +23,5 @@
|
||||
# or negative for a release candidate or beta (after the base version
|
||||
# number has been incremented)
|
||||
|
||||
__version__ = "1.0beta3.dev1"
|
||||
__version__ = "1.0beta3.dev2"
|
||||
__version_info__ = (1, 0, 0, -99)
|
||||
|
Loading…
Reference in New Issue
Block a user