basic docker machine support
This commit is contained in:
parent
1798cf7fd6
commit
2b6b7db0c7
7
example/docker-disk.json
Normal file
7
example/docker-disk.json
Normal file
@ -0,0 +1,7 @@
|
||||
{
|
||||
"disk_id": "dockerdata",
|
||||
"properties": {
|
||||
"type": "dockerdisk",
|
||||
"datastore": "default"
|
||||
}
|
||||
}
|
9
example/docker.json
Normal file
9
example/docker.json
Normal file
@ -0,0 +1,9 @@
|
||||
{
|
||||
"machine_id": "dockertest",
|
||||
"properties": {
|
||||
"ports": [
|
||||
[1234, 80]
|
||||
],
|
||||
"image": "dpedu/nginx"
|
||||
}
|
||||
}
|
106
zhypervisor/clients/dockermachine.py
Normal file
106
zhypervisor/clients/dockermachine.py
Normal file
@ -0,0 +1,106 @@
|
||||
import os
|
||||
import logging
|
||||
import subprocess
|
||||
from time import sleep
|
||||
from threading import Thread
|
||||
from zhypervisor.util import ZDisk
|
||||
from zhypervisor.util import Machine
|
||||
|
||||
|
||||
class DockerMachine(Machine):
|
||||
machine_type = "docker"
|
||||
|
||||
def __init__(self, spec):
|
||||
Machine.__init__(self, spec)
|
||||
self.proc = None
|
||||
self.block_respawns = False
|
||||
|
||||
def get_status(self):
|
||||
"""
|
||||
Return string "stopped" or "running" depending on machine status
|
||||
"""
|
||||
return "stopped" if self.proc is None else "running"
|
||||
|
||||
def start_machine(self):
|
||||
"""
|
||||
If needed, launch the machine.
|
||||
"""
|
||||
if self.proc:
|
||||
raise Exception("Machine already running!")
|
||||
else:
|
||||
docker_args = self.get_args()
|
||||
logging.info("spawning docker with: {}".format(' '.join(docker_args)))
|
||||
sleep(1) # anti-spin
|
||||
self.proc = subprocess.Popen(docker_args, preexec_fn=lambda: os.setpgrp())
|
||||
# TODO handle stdout/err - stream to logs?
|
||||
Thread(target=self.wait_on_exit, args=[self.proc]).start()
|
||||
|
||||
def wait_on_exit(self, proc):
|
||||
"""
|
||||
Listener used by above start_machine to restart the machine if the machine exits
|
||||
"""
|
||||
proc.wait()
|
||||
logging.info("docker process has exited")
|
||||
self.proc = None
|
||||
if not self.block_respawns and self.spec.properties.get("respawn", False):
|
||||
self.start_machine()
|
||||
|
||||
def stop_machine(self):
|
||||
"""
|
||||
Send the powerdown signal to the running machine
|
||||
"""
|
||||
if self.proc:
|
||||
logging.info("stopping machine %s", self.spec.machine_id)
|
||||
subprocess.check_call(["docker", "stop", self.spec.machine_id])
|
||||
self.proc.wait()
|
||||
self.proc = None
|
||||
|
||||
def kill_machine(self):
|
||||
"""
|
||||
Forcefully kill the running machine
|
||||
"""
|
||||
print("Terminating {}".format(self.proc))
|
||||
if self.proc:
|
||||
subprocess.check_call(["docker", "kill", self.spec.machine_id])
|
||||
try:
|
||||
self.proc.wait(5)
|
||||
except subprocess.TimeoutError:
|
||||
self.proc.kill()
|
||||
self.proc.wait()
|
||||
self.proc = None
|
||||
|
||||
def get_args(self):
|
||||
"""
|
||||
Assemble the full argv array that will be executed for this machine
|
||||
"""
|
||||
argv = ['docker', 'run', '--rm', '--name', self.spec.machine_id,
|
||||
'--hostname', self.spec.properties.get("hostname", self.spec.machine_id)]
|
||||
|
||||
for hostport, containerport in self.spec.properties.get("ports", []):
|
||||
argv.append("-p")
|
||||
argv.append("{}:{}".format(int(hostport), int(containerport)))
|
||||
|
||||
for volume in self.spec.properties.get("volumes", []):
|
||||
disk_ob = self.spec.master.disks[volume["disk"]]
|
||||
|
||||
volpath = disk_ob.get_path()
|
||||
argv.append("-v")
|
||||
argv.append("{}:{}".format(volpath, volume.get("mountpoint")))
|
||||
|
||||
if self.spec.properties.get("stopsignal", False):
|
||||
argv += ['--stop-signal', int(self.spec.properties.get("stopsignal"))]
|
||||
|
||||
argv += ['--stop-timeout', int(self.spec.properties.get("timeout", 25))]
|
||||
|
||||
argv.append("{}".format(self.spec.properties.get("image")))
|
||||
if self.spec.properties.get("cmd", False):
|
||||
argv.append("{}".format(self.spec.properties.get("cmd")))
|
||||
|
||||
return [str(arg) for arg in argv]
|
||||
|
||||
|
||||
class DockerDisk(ZDisk):
|
||||
|
||||
def validate(self):
|
||||
pass
|
||||
# alphanumeric only? underscores?
|
@ -12,6 +12,7 @@ from concurrent.futures import ThreadPoolExecutor
|
||||
from zhypervisor.logging import setup_logging
|
||||
from zhypervisor.machine import MachineSpec
|
||||
from zhypervisor.clients.qmachine import QDisk, IsoDisk
|
||||
from zhypervisor.clients.dockermachine import DockerDisk
|
||||
from zhypervisor.util import ZDisk
|
||||
from zhypervisor.api.api import ZApi
|
||||
|
||||
@ -113,6 +114,8 @@ class ZHypervisorDaemon(object):
|
||||
disk = QDisk(datastore, disk_id, disk_spec)
|
||||
elif disk_type == "iso":
|
||||
disk = IsoDisk(datastore, disk_id, disk_spec)
|
||||
elif disk_type == "dockerdisk":
|
||||
disk = DockerDisk(datastore, disk_id, disk_spec)
|
||||
else:
|
||||
raise Exception("Unknown disk type: {}".format(disk_type))
|
||||
disk = ZDisk(datastore, disk_id, disk_spec)
|
||||
|
@ -1,6 +1,9 @@
|
||||
import logging
|
||||
|
||||
from zhypervisor.clients.qmachine import QMachine
|
||||
from zhypervisor.clients.dockermachine import DockerMachine
|
||||
|
||||
MACHINETYPES = {"q": QMachine, "docker": DockerMachine}
|
||||
|
||||
|
||||
class MachineSpec(object):
|
||||
@ -18,11 +21,12 @@ class MachineSpec(object):
|
||||
|
||||
self.properties = spec
|
||||
|
||||
# TODO replace if/else with better system
|
||||
if self.properties["type"] == "q":
|
||||
self.machine = QMachine(self)
|
||||
else:
|
||||
raise Exception("Unknown machine type: {}".format(self.properties["type"]))
|
||||
try:
|
||||
machine_type = MACHINETYPES[self.properties.get("type", None)]
|
||||
except KeyError:
|
||||
raise Exception("Unknown or missing machine type: {}".format(self.properties.get("type", None)))
|
||||
|
||||
self.machine = machine_type(self)
|
||||
|
||||
def start(self):
|
||||
"""
|
||||
|
@ -35,7 +35,7 @@ class Machine(object):
|
||||
def __init__(self, machine_spec):
|
||||
self.spec = machine_spec
|
||||
|
||||
def run_machine(self):
|
||||
def start_machine(self):
|
||||
"""
|
||||
Run the machine and block until it exits (or was killed)
|
||||
"""
|
||||
|
Loading…
Reference in New Issue
Block a user