basic docker machine support

This commit is contained in:
dave 2017-02-24 18:11:36 -08:00
parent 1798cf7fd6
commit 2b6b7db0c7
6 changed files with 135 additions and 6 deletions

7
example/docker-disk.json Normal file
View File

@ -0,0 +1,7 @@
{
"disk_id": "dockerdata",
"properties": {
"type": "dockerdisk",
"datastore": "default"
}
}

9
example/docker.json Normal file
View File

@ -0,0 +1,9 @@
{
"machine_id": "dockertest",
"properties": {
"ports": [
[1234, 80]
],
"image": "dpedu/nginx"
}
}

View 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?

View File

@ -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)

View File

@ -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):
"""

View File

@ -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)
"""