diff --git a/zhypervisor/api/api.py b/zhypervisor/api/api.py index 9e3d9da..53bb5fe 100644 --- a/zhypervisor/api/api.py +++ b/zhypervisor/api/api.py @@ -149,6 +149,60 @@ class ZApiMachineRestart(object): return machine_id +@cherrypy.popargs("prop") +class ZApiMachineProperty(object): + """ + Endpoint to modify machine properties + """ + exposed = True + + def __init__(self, root): + self.root = root + + @cherrypy.tools.json_out() + def GET(self, machine_id, prop): + """ + Fetch a property from a machine + """ + try: + machine = self.root.master.machines[machine_id] + return machine.properties[prop] + except KeyError: + raise cherrypy.HTTPError(status=404) + + @cherrypy.tools.json_out() + def PUT(self, machine_id, prop, value): + """ + Set a property on a machine. + """ + value = json.loads(value) + try: + machine = self.root.master.machines[machine_id] + assert machine.machine.get_status() == "stopped", "Machine must be stopped to modify" + + except KeyError: + raise cherrypy.HTTPError(status=404) + + machine.properties[prop] = value + machine.save() + return [machine_id, prop, value] + + @cherrypy.tools.json_out() + def DELETE(self, machine_id, prop): + """ + Remove a property on a machine. + """ + try: + machine = self.root.master.machines[machine_id] + assert machine.machine.get_status() == "stopped", "Machine must be stopped to modify" + except KeyError: + raise cherrypy.HTTPError(status=404) + + del machine.properties[prop] + machine.save() + return [machine_id, prop] + + @cherrypy.popargs("machine_id") class ZApiMachines(): """ @@ -166,6 +220,7 @@ class ZApiMachines(): self.stop = ZApiMachineStop(self.root) self.start = ZApiMachineStart(self.root) self.restart = ZApiMachineRestart(self.root) + self.property = ZApiMachineProperty(self.root) @cherrypy.tools.json_out() def GET(self, machine_id=None, summary=False): diff --git a/zhypervisor/clients/qmachine.py b/zhypervisor/clients/qmachine.py index 14590c6..553e783 100644 --- a/zhypervisor/clients/qmachine.py +++ b/zhypervisor/clients/qmachine.py @@ -107,15 +107,18 @@ class QMachine(Machine): args = [] for iface in self.spec.properties.get("netifaces"): iface_type = iface.get("type") + iface_args = {"type": iface_type} if iface_type == "tap": - if "ifname" not in iface: - iface["ifname"] = tap_name - iface["script"] = "/root/zhypervisor/testenv/bin/zd_ifup" # TODO don't hard code - iface["downscript"] = "no" + if "ifname" in iface: + iface_args["ifname"] = iface.get("ifname") + iface_args["script"] = "/root/zhypervisor/testenv/bin/zd_ifup" # TODO don't hard code + iface_args["downscript"] = "no" + else: + iface_args.update(iface) args.append("-net") - args.append(QMachine.format_args(iface)) + args.append(QMachine.format_args(iface_args)) return args # return ['-net', 'nic,vlan=0,model=e1000,macaddr=82:25:60:41:D5:97', diff --git a/zhypervisor/daemon.py b/zhypervisor/daemon.py index 2b463c3..af6d321 100644 --- a/zhypervisor/daemon.py +++ b/zhypervisor/daemon.py @@ -67,6 +67,11 @@ class ZHypervisorDaemon(object): machine_id = machine_info["machine_id"] self.add_machine(machine_id, machine_info["spec"]) + # Launch if machine is an autostarted machine + machine = self.machines[machine_id] + if machine.options.get("autostart", False) and machine.machine.get_status() == "stopped": + machine.start() + def signal_handler(self, signum, frame): """ Handle signals sent to the daemon. On any, exit. @@ -148,11 +153,7 @@ class ZHypervisorDaemon(object): if write: self.state.write_machine(machine_id, machine_spec) - # Launch if machine is an autostarted machine - if machine.options.get("autostart", False) and machine.machine.get_status() == "stopped": - machine.start() - - def forceful_stop(self, machine_id, timeout=10): # make this timeout longer? + def forceful_stop(self, machine_id, timeout=30): # make this timeout longer? """ Gracefully stop a machine by asking it nicely, waiting some time, then forcefully killing it. """ diff --git a/zhypervisor/machine.py b/zhypervisor/machine.py index 36f1966..2fd41d2 100644 --- a/zhypervisor/machine.py +++ b/zhypervisor/machine.py @@ -39,6 +39,13 @@ class MachineSpec(object): self.machine.block_respawns = True self.machine.stop_machine() + def save(self): + """ + Write the machine's config to disk + """ + self.master.add_machine(self.machine_id, {"options": self.options, "properties": self.properties}, + write=True) + def serialize(self): """ Return a serializable form of this machine's specs