mirror of
https://github.com/linuxkit/linuxkit.git
synced 2025-10-05 21:44:01 +00:00
infrakit: Update vendored packages
Signed-off-by: Rolf Neugebauer <rolf.neugebauer@docker.com>
This commit is contained in:
115
tools/infrakit.hyperkit/vendor/github.com/docker/hyperkit/README.md
generated
vendored
Normal file
115
tools/infrakit.hyperkit/vendor/github.com/docker/hyperkit/README.md
generated
vendored
Normal file
@@ -0,0 +1,115 @@
|
||||
## [HyperKit](http://github.com/docker/hyperkit)
|
||||
|
||||

|
||||
|
||||
*HyperKit* is a toolkit for embedding hypervisor capabilities in your application. It includes a complete hypervisor, based on [xhyve](https://github.com/mist64/xhyve)/[bhyve](http://bhyve.org), which is optimized for lightweight virtual machines and container deployment. It is designed to be interfaced with higher-level components such as the [VPNKit](https://github.com/docker/vpnkit) and [DataKit](https://github.com/docker/datakit).
|
||||
|
||||
HyperKit currently only supports Mac OS X using the [Hypervisor.framework](https://developer.apple.com/library/mac/documentation/DriversKernelHardware/Reference/Hypervisor/index.html). It is a core component of Docker For Mac.
|
||||
|
||||
|
||||
## Requirements
|
||||
|
||||
* OS X 10.10.3 Yosemite or later
|
||||
* a 2010 or later Mac (i.e. a CPU that supports EPT)
|
||||
|
||||
## Reporting Bugs
|
||||
|
||||
If you are using a version of Hyperkit which is embedded into a higher level application (e.g. [Docker for Mac](https://github.com/docker/for-mac)) then please report any issues against that higher level application in the first instance. That way the relevant team can triage and determine if the issue lies in Hyperkit and assign as necessary.
|
||||
|
||||
If you are using Hyperkit directly then please report issues against this repository.
|
||||
|
||||
## Usage
|
||||
|
||||
$ hyperkit -h
|
||||
|
||||
## Building
|
||||
|
||||
$ git clone https://github.com/docker/hyperkit
|
||||
$ cd hyperkit
|
||||
$ make
|
||||
|
||||
The resulting binary will be in `build/hyperkit`
|
||||
|
||||
To enable qcow support in the block backend an OCaml [OPAM](https://opam.ocaml.org) development
|
||||
environment is required with the qcow module available. A
|
||||
suitable environment can be setup by installing `opam` and `libev`
|
||||
via `brew` and using `opam` to install the appropriate libraries:
|
||||
|
||||
$ brew install opam libev
|
||||
$ opam init
|
||||
$ eval `opam config env`
|
||||
$ opam install uri qcow.0.8.1 mirage-block-unix.2.6.0 conf-libev logs fmt mirage-unix
|
||||
|
||||
Notes:
|
||||
|
||||
- `opam config env` must be evaluated each time prior to building
|
||||
hyperkit so the build will find the ocaml environment.
|
||||
- Any previous pin of `mirage-block-unix` or `qcow`
|
||||
should be removed with the commands:
|
||||
|
||||
```sh
|
||||
$ opam update
|
||||
$ opam pin remove mirage-block-unix
|
||||
$ opam pin remove qcow
|
||||
```
|
||||
|
||||
## Tracing
|
||||
|
||||
HyperKit defines a number of static DTrace probes to simplify investigation of
|
||||
performance problems. To list the probes supported by your version of HyperKit,
|
||||
type the following command while HyperKit VM is running:
|
||||
|
||||
$ sudo dtrace -l -P 'hyperkit$target' -p $(pgrep hyperkit)
|
||||
|
||||
Refer to scripts in dtrace/ directory for examples of possible usage and
|
||||
available probes.
|
||||
|
||||
### Relationship to xhyve and bhyve
|
||||
|
||||
HyperKit includes a hypervisor derived from [xhyve](http://www.xhyve.org), which in turn
|
||||
was derived from [bhyve](http://www.bhyve.org). See the [original xhyve
|
||||
README](README.xhyve.md) which incorporates the bhyve README.
|
||||
|
||||
We try to avoid deviating from these upstreams unnecessarily in order
|
||||
to more easily share code, for example the various device
|
||||
models/emulations should be easily shareable.
|
||||
|
||||
### Reporting security issues
|
||||
|
||||
The maintainers take security seriously. If you discover a security issue,
|
||||
please bring it to their attention right away!
|
||||
|
||||
Please **DO NOT** file a public issue, instead send your report privately to
|
||||
[security@docker.com](mailto:security@docker.com).
|
||||
|
||||
Security reports are greatly appreciated and we will publicly thank you for it.
|
||||
We also like to send gifts—if you're into Docker schwag, make sure to let
|
||||
us know. We currently do not offer a paid security bounty program, but are not
|
||||
ruling it out in the future.
|
||||
|
||||
|
||||
## Copyright and license
|
||||
|
||||
Copyright the authors and contributors. See individual source files
|
||||
for details.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions
|
||||
are met:
|
||||
1. Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
2. Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
|
||||
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
|
||||
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
SUCH DAMAGE.
|
224
tools/infrakit.hyperkit/vendor/github.com/docker/hyperkit/README.xhyve.md
generated
vendored
Normal file
224
tools/infrakit.hyperkit/vendor/github.com/docker/hyperkit/README.xhyve.md
generated
vendored
Normal file
@@ -0,0 +1,224 @@
|
||||
# [xhyve.org](http://www.xhyve.org)
|
||||
|
||||

|
||||
<!-- https://thenounproject.com/term/squirrel/57718/ -->
|
||||
|
||||
About
|
||||
-----
|
||||
|
||||
The *xhyve hypervisor* is a port of [bhyve](http://www.bhyve.org) to OS X. It is built on top of [Hypervisor.framework](https://developer.apple.com/library/mac/documentation/DriversKernelHardware/Reference/Hypervisor/index.html) in OS X 10.10 Yosemite and higher, runs entirely in userspace, and has no other dependencies. It can run FreeBSD and vanilla Linux distributions and may gain support for other guest operating systems in the future.
|
||||
|
||||
License: BSD
|
||||
|
||||
Introduction: [http://www.pagetable.com/?p=831](http://www.pagetable.com/?p=831)
|
||||
|
||||
Requirements
|
||||
------------
|
||||
|
||||
* OS X 10.10.3 Yosemite or later
|
||||
* a 2010 or later Mac (i.e. a CPU that supports EPT)
|
||||
|
||||
Installation
|
||||
------------
|
||||
|
||||
If you have homebrew, then simply:
|
||||
|
||||
$ brew update
|
||||
$ brew install --HEAD xhyve
|
||||
|
||||
The `--HEAD` in the brew command ensures that you always get the latest changes, even if the homebrew database is not yet updated. If for any reason you don't want that simply do `brew install xhyve` .
|
||||
|
||||
if not then:
|
||||
|
||||
Building
|
||||
--------
|
||||
$ git clone https://github.com/mist64/xhyve
|
||||
$ cd xhyve
|
||||
$ make
|
||||
|
||||
The resulting binary will be in build/xhyve
|
||||
|
||||
Usage
|
||||
-----
|
||||
|
||||
$ xhyve -h
|
||||
|
||||
|
||||
What is bhyve?
|
||||
--------------
|
||||
|
||||
bhyve is the FreeBSD hypervisor, roughly analogous to KVM + QEMU on Linux. It has a focus on simplicity and being legacy free.
|
||||
|
||||
It exposes the following peripherals to virtual machines:
|
||||
|
||||
- Local x(2)APIC
|
||||
- IO-APIC
|
||||
- 8259A PIC
|
||||
- 8253/8254 PIT
|
||||
- HPET
|
||||
- PM Timer
|
||||
- RTC
|
||||
- PCI
|
||||
- host bridge
|
||||
- passthrough
|
||||
- UART
|
||||
- AHCI (i.e. HDD and CD)
|
||||
- VirtIO block device
|
||||
- VirtIO networking
|
||||
- VirtIO RNG
|
||||
|
||||
Notably absent are sound, USB, HID and any kind of graphics support. With a focus on server virtualization this is not strictly a requirement. bhyve may gain desktop virtualization capabilities in the future but this doesn't seem to be a priority.
|
||||
|
||||
Unlike QEMU, bhyve also currently lacks any kind of guest-side firmware (QEMU uses the GPL3 [SeaBIOS](http://www.seabios.org)), but aims to provide a compatible [OVMF EFI](http://www.linux-kvm.org/page/OVMF) in the near future. It does however provide ACPI, SMBIOS and MP Tables.
|
||||
|
||||
bhyve architecture
|
||||
------------------
|
||||
Linux
|
||||
I/O VM control FreeBSD NetBSD
|
||||
OpenBSD
|
||||
| A | A | |
|
||||
V | V | V V
|
||||
+-------------++-------------++-------------++-------------+
|
||||
| || || || |
|
||||
| bhyve || bhyvectl || bhyveload || grub2-bhyve |
|
||||
| || || || |
|
||||
| || || || |
|
||||
+-------------++-------------++-------------++-------------+
|
||||
+----------------------------------------------------------+
|
||||
| libvmmapi |
|
||||
+----------------------------------------------------------+
|
||||
A
|
||||
| user
|
||||
------------------------------┼------------------------------
|
||||
| ioctl FreeBSD kernel
|
||||
V
|
||||
+----------------------------+
|
||||
| VMX/SVM host |
|
||||
| VMX/SVM guest |
|
||||
| VMX/SVM nested paging |
|
||||
| Timers |
|
||||
| Interrupts |
|
||||
+----------------------------+
|
||||
vmm.ko
|
||||
|
||||
|
||||
**vmm.ko**
|
||||
|
||||
The bhyve FreeBSD kernel module. Manages VM and vCPU objects, the guest physical address space and handles guest interaction with PIC, PIT, HPET, PM Timer, x(2)APIC and I/O-APIC. Contains a minimal x86 emulator to decode guest MMIO. Executes the two innermost vCPU runloops (VMX/SVM and interrupts/timers/paging). Has backends for Intel VMX and AMD SVM. Provides an ioctl and mmap API to userspace.
|
||||
|
||||
**libvmmapi**
|
||||
|
||||
Thin abstraction layer between the vmm.ko ioctl interface and the userspace C API.
|
||||
|
||||
**bhyve**
|
||||
|
||||
The userspace bhyve component (kind of a very light-weight QEMU) that executes virtual machines. Runs the guest I/O vCPU runloops. Manages ACPI, PCI and all non in-kernel devices. Interacts with vmm.ko through libvmmapi.
|
||||
|
||||
**bhyvectl**
|
||||
|
||||
Somewhat superfluous utility to introspect and manage the life cycle of virtual machines. Virtual machines and vCPUs can exist as kernel objects independently of a bhyve host process. Typically used to delete VM objects after use. Odd architectural choice.
|
||||
|
||||
**bhyveload**
|
||||
|
||||
Userspace port of the FreeBSD bootloader. Since bhyve still lacks a firmware this is a cumbersome workaround to bootstrap a guest operating system. It creates a VM object, loads the FreeBSD kernel into guest memory, sets up the initial vCPU state and then exits. Only then a VM can be executed by bhyve.
|
||||
|
||||
**grub2-bhyve**
|
||||
|
||||
Performs the same function as bhyveload but is a userspace port of [GRUB2](http://github.com/grehan-freebsd/grub2-bhyve). It is used to bootstrap guest operating systems other than FreeBSD, i.e. Linux, OpenBSD and NetBSD.
|
||||
|
||||
Support for Windows guests is work in progress and dependent on the EFI port.
|
||||
|
||||
|
||||
xhyve architecture
|
||||
------------------
|
||||
+----------------------------------------------------------+
|
||||
| xhyve |
|
||||
| |
|
||||
| I/O |
|
||||
| |
|
||||
| |
|
||||
| |
|
||||
|+--------------------------------------------------------+|
|
||||
|| vmm VMX guest ||
|
||||
|| Timers ||
|
||||
|| Interrupts ||
|
||||
|+--------------------------------------------------------+|
|
||||
+----------------------------------------------------------+
|
||||
+----------------------------------------------------------+
|
||||
| Hypervisor.framework |
|
||||
+----------------------------------------------------------+
|
||||
A
|
||||
| user
|
||||
------------------------------┼------------------------------
|
||||
|syscall xnu kernel
|
||||
V
|
||||
|
||||
VMX host
|
||||
VMX nested paging
|
||||
|
||||
|
||||
xhyve shares most of the code with bhyve but is architecturally very different. Hypervisor.framework provides an interface to the VMX VMCS guest state and a safe subset of the VMCS control fields, thus making userspace hypervisors without any additional kernel extensions possible. The VMX host state and all aspects of nested paging are handled by the OS X kernel, you can manage the guest physical address space simply through mapping of regions of your own address space.
|
||||
|
||||
*xhyve* is equivalent to the *bhyve* process but gains a subset of a userspace port of the vmm kernel module. SVM, PCI passthrough and the VMX host and EPT aspects are dropped. The vmm component provides a libvmmapi compatible interface to xhyve. Hypervisor.framework seems to enforce a strict 1:1 relationship between a host process/VM and host thread/vCPU, that means VMs and vCPUs can only be interacted with by the processes and threads that created them. Therefore, unlike bhyve, xhyve needs to adhere to a single process model. Multiple virtual machines can be created by launching multiple instances of xhyve. xhyve retains most of the bhyve command line interface.
|
||||
|
||||
*bhyvectl*, *bhyveload* and *grub2-bhyve* are incompatible with a single process model and are dropped. As a stop-gap solution until we have a proper firmware xhyve supports the Linux [kexec protocol](http://www.kernel.org/doc/Documentation/x86/boot.txt), a very simple and straightforward way to bootstrap a Linux kernel. It takes a bzImage and optionally initrd image and kernel parameter string as input.
|
||||
|
||||
Networking
|
||||
------
|
||||
If you want the same IP address across VM reboots, assign a UUID to a particular VM:
|
||||
|
||||
$ xhyve [-U uuid]
|
||||
|
||||
**Optional:**
|
||||
|
||||
If you need more advanced networking and already have a configured [TAP](http://tuntaposx.sourceforge.net) device you can use it with:
|
||||
|
||||
virtio-tap,tapX
|
||||
|
||||
instead of:
|
||||
|
||||
virtio-net
|
||||
|
||||
Where *X* is your tap device, i.e. */dev/tapX*.
|
||||
|
||||
Issues
|
||||
------
|
||||
If you are, or were, running any version of VirtualBox, prior to 4.3.30 or 5.0,
|
||||
and attempt to run xhyve your system will immediately crash as a kernel panic is
|
||||
triggered. This is due to a VirtualBox bug (that got fixed in newest VirtualBox
|
||||
versions) as VirtualBox wasn't playing nice with OSX's Hypervisor.framework used
|
||||
by xhyve.
|
||||
|
||||
To get around this you either have to update to newest VirtualBox 4.3 or 5.0 or,
|
||||
if you for some reason are unable to update, to reboot
|
||||
your Mac after using VirtualBox and before attempting to use xhyve.
|
||||
(see issues [#5](https://github.com/mist64/xhyve/issues/5) and
|
||||
[#9](https://github.com/mist64/xhyve/issues/9) for the full context)
|
||||
|
||||
TODO
|
||||
----
|
||||
|
||||
- vmm:
|
||||
- enable APIC access page to speed up APIC emulation (**performance**)
|
||||
- enable x2APIC MSRs (even faster) (**performance**)
|
||||
- vmm_callout:
|
||||
- is a quick'n'dirty implementation of the FreeBSD kernel callout mechanism
|
||||
- seems to be racy
|
||||
- fix races or perhaps replace with something better
|
||||
- use per vCPU timer event thread (**performance**)?
|
||||
- use hardware VMX preemption timer instead of `pthread_cond_wait` (**performance**)
|
||||
- some 32-bit guests are broken (support PAE paging in VMCS)
|
||||
- PCID guest support (**performance**)
|
||||
- block_if:
|
||||
- OS X does not support `preadv`/`pwritev`, we need to serialize reads and writes for the time being until we find a better solution. (**performance**)
|
||||
- support block devices other than plain files
|
||||
- virtio_net:
|
||||
- unify TAP and vmnet backends
|
||||
- vmnet: make it not require root
|
||||
- vmnet: send/receive more than a single packet at a time (**performance**)
|
||||
- virtio_rnd:
|
||||
- is untested
|
||||
- remove explicit state transitions:
|
||||
- since only the owning task/thread can modify the VM/vCPUs a lot of the synchronization might be unnecessary (**performance**)
|
||||
- performance, performance and performance
|
||||
- remove vestigial code, cleanup
|
533
tools/infrakit.hyperkit/vendor/github.com/docker/hyperkit/go/hyperkit.go
generated
vendored
Normal file
533
tools/infrakit.hyperkit/vendor/github.com/docker/hyperkit/go/hyperkit.go
generated
vendored
Normal file
@@ -0,0 +1,533 @@
|
||||
// +build darwin
|
||||
|
||||
// Package hyperkit provides a Go wrapper around the hyperkit
|
||||
// command. It currently shells out to start hyperkit with the
|
||||
// provided configuration.
|
||||
//
|
||||
// Most of the arguments should be self explanatory, but console
|
||||
// handling deserves a mention. If the Console is configured with
|
||||
// ConsoleStdio, the hyperkit is started with stdin, stdout, and
|
||||
// stderr plumbed through to the VM console. If Console is set to
|
||||
// ConsoleFile hyperkit the console output is redirected to a file and
|
||||
// console input is disabled. For this mode StateDir has to be set and
|
||||
// the interactive console is accessible via a 'tty' file created
|
||||
// there.
|
||||
//
|
||||
// Currently this module has some limitations:
|
||||
// - Only supports zero or one disk image
|
||||
// - Only support zero or one network interface connected to VPNKit
|
||||
// - Only kexec boot
|
||||
//
|
||||
// This package is currently implemented by shelling out a hyperkit
|
||||
// process. In the future we may change this to become a wrapper
|
||||
// around the hyperkit library.
|
||||
package hyperkit
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"log"
|
||||
"os"
|
||||
"os/exec"
|
||||
"os/user"
|
||||
"path/filepath"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"github.com/mitchellh/go-ps"
|
||||
"github.com/rneugeba/iso9660wrap"
|
||||
)
|
||||
|
||||
const (
|
||||
// ConsoleStdio configures console to use Stdio
|
||||
ConsoleStdio = iota
|
||||
// ConsoleFile configures console to a tty and output to a file
|
||||
ConsoleFile
|
||||
|
||||
defaultVPNKitSock = "Library/Containers/com.docker.docker/Data/s50"
|
||||
defaultDiskImage = "disk.img"
|
||||
|
||||
defaultCPUs = 1
|
||||
defaultMemory = 1024 // 1G
|
||||
|
||||
jsonFile = "hyperkit.json"
|
||||
pidFile = "hyperkit.pid"
|
||||
)
|
||||
|
||||
var defaultHyperKits = []string{"hyperkit",
|
||||
"com.docker.hyperkit",
|
||||
"/usr/local/bin/hyperkit",
|
||||
"/Applications/Docker.app/Contents/MacOS/com.docker.hyperkit"}
|
||||
|
||||
// HyperKit contains the configuration of the hyperkit VM
|
||||
type HyperKit struct {
|
||||
// HyperKit is the path to the hyperkit binary
|
||||
HyperKit string `json:"hyperkit"`
|
||||
// StateDir is the directory where runtime state is kept. If left empty, no state will be kept.
|
||||
StateDir string `json:"state_dir"`
|
||||
// VPNKitSock is the location of the VPNKit socket used for networking.
|
||||
VPNKitSock string `json:"vpnkit_sock"`
|
||||
// DiskImage is the path to the disk image to use
|
||||
DiskImage string `json:"disk"`
|
||||
// ISOImage is the (optional) path to a ISO image to attach
|
||||
ISOImage string `json:"iso"`
|
||||
|
||||
// Kernel is the path to the kernel image to boot
|
||||
Kernel string `json:"kernel"`
|
||||
// Initrd is the path to the initial ramdisk to boot off
|
||||
Initrd string `json:"initrd"`
|
||||
|
||||
// CPUs is the number CPUs to configure
|
||||
CPUs int `json:"cpus"`
|
||||
// Memory is the amount of megabytes of memory for the VM
|
||||
Memory int `json:"memory"`
|
||||
// DiskSize is the size of the disk image in megabytes. If zero and DiskImage does not exist, no disk will be attached.
|
||||
DiskSize int `json:"disk_size"`
|
||||
|
||||
// Console defines where the console of the VM should be
|
||||
// connected to. ConsoleStdio and ConsoleFile are supported.
|
||||
Console int `json:"console"`
|
||||
|
||||
// UserData, if non empty, will be added to a ISO under the
|
||||
// filename `config` and passed to the VM.
|
||||
UserData string `json:"user_data"`
|
||||
|
||||
// Below here are internal members, but they are exported so
|
||||
// that they are written to the state json file, if configured.
|
||||
|
||||
// Pid of the hyperkit process
|
||||
Pid int `json:"pid"`
|
||||
// Arguments used to execute the hyperkit process
|
||||
Arguments []string `json:"arguments"`
|
||||
// CmdLine is a single string of the command line
|
||||
CmdLine string `json:"cmdline"`
|
||||
|
||||
process *os.Process
|
||||
background bool
|
||||
log *log.Logger
|
||||
}
|
||||
|
||||
// New creates a template config structure.
|
||||
// - If hyperkit can't be found an error is returned.
|
||||
// - If vpnkitsock is empty no networking is configured. If it is set
|
||||
// to "auto" it tries to re-use the Docker for Mac VPNKit connection.
|
||||
// - If statedir is "" no state is written to disk.
|
||||
func New(hyperkit, statedir, vpnkitsock, diskimage string) (*HyperKit, error) {
|
||||
h := HyperKit{}
|
||||
var err error
|
||||
|
||||
h.HyperKit, err = checkHyperKit(hyperkit)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
h.StateDir = statedir
|
||||
h.VPNKitSock, err = checkVPNKitSock(vpnkitsock)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
h.DiskImage = diskimage
|
||||
|
||||
h.CPUs = defaultCPUs
|
||||
h.Memory = defaultMemory
|
||||
|
||||
h.Console = ConsoleStdio
|
||||
h.UserData = ""
|
||||
|
||||
return &h, nil
|
||||
}
|
||||
|
||||
// FromState reads a json file from statedir and populates a HyperKit structure.
|
||||
func FromState(statedir string) (*HyperKit, error) {
|
||||
b, err := ioutil.ReadFile(filepath.Join(statedir, jsonFile))
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("Can't read json file: ", err)
|
||||
}
|
||||
h := &HyperKit{}
|
||||
err = json.Unmarshal(b, h)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("Can't parse json file: ", err)
|
||||
}
|
||||
|
||||
// Make sure the pid written by hyperkit is the same as in the json
|
||||
d, err := ioutil.ReadFile(filepath.Join(statedir, pidFile))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
pid, err := strconv.Atoi(string(d[:]))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if h.Pid != pid {
|
||||
return nil, fmt.Errorf("pids do not match %d != %d", h.Pid, pid)
|
||||
}
|
||||
|
||||
h.process, err = os.FindProcess(h.Pid)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return h, nil
|
||||
}
|
||||
|
||||
// SetLogger sets the log instance to use for the output of the hyperkit process itself (not the console of the VM).
|
||||
// This is only relevant when Console is set to ConsoleFile
|
||||
func (h *HyperKit) SetLogger(logger *log.Logger) {
|
||||
h.log = logger
|
||||
}
|
||||
|
||||
// Run the VM with a given command line until it exits
|
||||
func (h *HyperKit) Run(cmdline string) error {
|
||||
h.background = false
|
||||
return h.execute(cmdline)
|
||||
}
|
||||
|
||||
// Start the VM with a given command line in the background
|
||||
func (h *HyperKit) Start(cmdline string) error {
|
||||
h.background = true
|
||||
return h.execute(cmdline)
|
||||
}
|
||||
|
||||
func (h *HyperKit) execute(cmdline string) error {
|
||||
var err error
|
||||
// Sanity checks on configuration
|
||||
if h.Console == ConsoleFile && h.StateDir == "" {
|
||||
return fmt.Errorf("If ConsoleFile is set, StateDir was be specified")
|
||||
}
|
||||
if h.UserData != "" && h.ISOImage != "" {
|
||||
return fmt.Errorf("If UserData is supplied, ISOImage must not be set")
|
||||
}
|
||||
if h.ISOImage != "" {
|
||||
if _, err = os.Stat(h.ISOImage); os.IsNotExist(err) {
|
||||
return fmt.Errorf("ISO %s does not exist", h.ISOImage)
|
||||
}
|
||||
}
|
||||
if h.UserData != "" && h.StateDir == "" {
|
||||
return fmt.Errorf("If UserData is supplied, StateDir was be specified")
|
||||
}
|
||||
if _, err = os.Stat(h.Kernel); os.IsNotExist(err) {
|
||||
return fmt.Errorf("Kernel %s does not exist", h.Kernel)
|
||||
}
|
||||
if _, err = os.Stat(h.Initrd); os.IsNotExist(err) {
|
||||
return fmt.Errorf("initrd %s does not exist", h.Initrd)
|
||||
}
|
||||
if h.DiskImage == "" && h.StateDir == "" && h.DiskSize != 0 {
|
||||
return fmt.Errorf("Can't create disk, because neither DiskImage nor StateDir is set")
|
||||
}
|
||||
|
||||
// Create files
|
||||
if h.StateDir != "" {
|
||||
err = os.MkdirAll(h.StateDir, 0755)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
if h.DiskImage == "" && h.DiskSize != 0 {
|
||||
h.DiskImage = filepath.Join(h.StateDir, "disk.img")
|
||||
}
|
||||
if _, err = os.Stat(h.DiskImage); os.IsNotExist(err) {
|
||||
if h.DiskSize != 0 {
|
||||
err = CreateDiskImage(h.DiskImage, h.DiskSize)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
}
|
||||
if h.UserData != "" {
|
||||
h.ISOImage, err = createUserDataISO(h.StateDir, h.UserData)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
// Run
|
||||
h.buildArgs(cmdline)
|
||||
err = h.execHyperKit()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// Stop the running VM
|
||||
func (h *HyperKit) Stop() error {
|
||||
if h.process == nil {
|
||||
return fmt.Errorf("hyperkit process not known")
|
||||
}
|
||||
if !h.IsRunning() {
|
||||
return nil
|
||||
}
|
||||
err := h.process.Kill()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// IsRunning returns true if the hyperkit process is running.
|
||||
func (h *HyperKit) IsRunning() bool {
|
||||
// os.FindProcess on Unix always returns a process object even
|
||||
// if the process does not exists. There does not seem to be
|
||||
// a call to find out if the process is running either, so we
|
||||
// use another package to find out.
|
||||
proc, err := ps.FindProcess(h.Pid)
|
||||
if err != nil {
|
||||
return false
|
||||
}
|
||||
if proc == nil {
|
||||
return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
// Remove deletes all statefiles if present.
|
||||
// This also removes the StateDir if empty.
|
||||
// If keepDisk is set, the diskimage will not get removed.
|
||||
func (h *HyperKit) Remove(keepDisk bool) error {
|
||||
if h.IsRunning() {
|
||||
return fmt.Errorf("Can't remove state as process is running")
|
||||
}
|
||||
if h.StateDir == "" {
|
||||
// If there is not state directory we don't mess with the disk
|
||||
return nil
|
||||
}
|
||||
|
||||
if !keepDisk {
|
||||
return os.RemoveAll(h.StateDir)
|
||||
}
|
||||
|
||||
files, _ := ioutil.ReadDir(h.StateDir)
|
||||
for _, f := range files {
|
||||
fn := filepath.Clean(filepath.Join(h.StateDir, f.Name()))
|
||||
if fn == h.DiskImage {
|
||||
continue
|
||||
}
|
||||
err := os.Remove(fn)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// Convert to json string
|
||||
func (h *HyperKit) String() string {
|
||||
s, err := json.Marshal(h)
|
||||
if err != nil {
|
||||
return err.Error()
|
||||
}
|
||||
return string(s)
|
||||
}
|
||||
|
||||
// CreateDiskImage creates a empty file suitable for use as a disk image for a hyperkit VM.
|
||||
func CreateDiskImage(location string, sizeMB int) error {
|
||||
f, err := os.Create(location)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer f.Close()
|
||||
|
||||
buf := make([]byte, 1048676)
|
||||
for i := 0; i < sizeMB; i++ {
|
||||
f.Write(buf)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (h *HyperKit) buildArgs(cmdline string) {
|
||||
a := []string{"-A", "-u"}
|
||||
if h.StateDir != "" {
|
||||
a = append(a, "-F", filepath.Join(h.StateDir, pidFile))
|
||||
}
|
||||
|
||||
a = append(a, "-c", fmt.Sprintf("%d", h.CPUs))
|
||||
a = append(a, "-m", fmt.Sprintf("%dM", h.Memory))
|
||||
|
||||
a = append(a, "-s", "0:0,hostbridge")
|
||||
if h.VPNKitSock != "" {
|
||||
a = append(a, "-s", fmt.Sprintf("1:0,virtio-vpnkit,path=%s", h.VPNKitSock))
|
||||
}
|
||||
if h.DiskImage != "" {
|
||||
a = append(a, "-s", fmt.Sprintf("2:0,virtio-blk,%s", h.DiskImage))
|
||||
}
|
||||
if h.ISOImage != "" {
|
||||
a = append(a, "-s", fmt.Sprintf("4,ahci-cd,%s", h.ISOImage))
|
||||
}
|
||||
|
||||
a = append(a, "-s", "10,virtio-rnd")
|
||||
a = append(a, "-s", "31,lpc")
|
||||
|
||||
if h.Console == ConsoleFile {
|
||||
a = append(a, "-l", fmt.Sprintf("com1,autopty=%s/tty,log=%s/console-ring", h.StateDir, h.StateDir))
|
||||
} else {
|
||||
a = append(a, "-l", "com1,stdio")
|
||||
}
|
||||
|
||||
kernArgs := fmt.Sprintf("kexec,%s,%s,earlyprintk=serial %s", h.Kernel, h.Initrd, cmdline)
|
||||
a = append(a, "-f", kernArgs)
|
||||
|
||||
h.Arguments = a
|
||||
h.CmdLine = h.HyperKit + " " + strings.Join(a, " ")
|
||||
}
|
||||
|
||||
// Execute hyperkit and plumb stdin/stdout/stderr.
|
||||
func (h *HyperKit) execHyperKit() error {
|
||||
|
||||
cmd := exec.Command(h.HyperKit, h.Arguments...)
|
||||
cmd.Env = os.Environ()
|
||||
|
||||
// Plumb in stdin/stdout/stderr. If ConsoleStdio is configured
|
||||
// plumb them to the system streams. If a logger is specified,
|
||||
// use it for stdout/stderr logging. Otherwise use the default
|
||||
// /dev/null.
|
||||
if h.Console == ConsoleStdio {
|
||||
cmd.Stdin = os.Stdin
|
||||
cmd.Stdout = os.Stdout
|
||||
cmd.Stderr = os.Stderr
|
||||
} else if h.log != nil {
|
||||
stdoutChan := make(chan string)
|
||||
stderrChan := make(chan string)
|
||||
stdout, err := cmd.StdoutPipe()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
stderr, err := cmd.StderrPipe()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
stream(stdout, stdoutChan)
|
||||
stream(stderr, stderrChan)
|
||||
|
||||
done := make(chan struct{})
|
||||
go func() {
|
||||
for {
|
||||
select {
|
||||
case stderrl := <-stderrChan:
|
||||
log.Printf("%s", stderrl)
|
||||
case stdoutl := <-stdoutChan:
|
||||
log.Printf("%s", stdoutl)
|
||||
case <-done:
|
||||
return
|
||||
}
|
||||
}
|
||||
}()
|
||||
}
|
||||
|
||||
err := cmd.Start()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
h.Pid = cmd.Process.Pid
|
||||
h.process = cmd.Process
|
||||
err = h.writeState()
|
||||
if err != nil {
|
||||
h.process.Kill()
|
||||
return err
|
||||
}
|
||||
if !h.background {
|
||||
err = cmd.Wait()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// writeState write the state to a JSON file
|
||||
func (h *HyperKit) writeState() error {
|
||||
if h.StateDir == "" {
|
||||
// This is not an error
|
||||
return nil
|
||||
}
|
||||
|
||||
s, err := json.Marshal(h)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return ioutil.WriteFile(filepath.Join(h.StateDir, jsonFile), []byte(s), 0644)
|
||||
}
|
||||
|
||||
func stream(r io.ReadCloser, dest chan<- string) {
|
||||
go func() {
|
||||
defer r.Close()
|
||||
reader := bufio.NewReader(r)
|
||||
for {
|
||||
line, err := reader.ReadString('\n')
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
dest <- line
|
||||
}
|
||||
}()
|
||||
}
|
||||
|
||||
// Create a ISO with Userdata in the specified directory
|
||||
func createUserDataISO(dir string, init string) (string, error) {
|
||||
cfgName := filepath.Join(dir, "config")
|
||||
isoName := cfgName + ".iso"
|
||||
|
||||
if err := ioutil.WriteFile(cfgName, []byte(init), 0644); err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
outfh, err := os.OpenFile(isoName, os.O_CREATE|os.O_EXCL|os.O_WRONLY, 0644)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
infh, err := os.Open(cfgName)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
err = iso9660wrap.WriteFile(outfh, infh)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
return isoName, nil
|
||||
}
|
||||
|
||||
// checkHyperKit tries to find and/or validate the path of hyperkit
|
||||
func checkHyperKit(hyperkit string) (string, error) {
|
||||
if hyperkit != "" {
|
||||
p, err := exec.LookPath(hyperkit)
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("Could not find hyperkit executable: ", hyperkit)
|
||||
}
|
||||
return p, nil
|
||||
}
|
||||
|
||||
// Look in a number of default locations
|
||||
for _, hyperkit := range defaultHyperKits {
|
||||
p, err := exec.LookPath(hyperkit)
|
||||
if err == nil {
|
||||
return p, nil
|
||||
}
|
||||
}
|
||||
|
||||
return "", fmt.Errorf("Could not find hyperkit executable")
|
||||
}
|
||||
|
||||
// checkVPNKitSock tries to find and/or validate the path of the VPNKit socket
|
||||
func checkVPNKitSock(vpnkitsock string) (string, error) {
|
||||
if vpnkitsock == "auto" {
|
||||
vpnkitsock = filepath.Join(getHome(), defaultVPNKitSock)
|
||||
}
|
||||
|
||||
vpnkitsock = filepath.Clean(vpnkitsock)
|
||||
_, err := os.Stat(vpnkitsock)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
return vpnkitsock, nil
|
||||
}
|
||||
|
||||
func getHome() string {
|
||||
if usr, err := user.Current(); err == nil {
|
||||
return usr.HomeDir
|
||||
}
|
||||
return os.Getenv("HOME")
|
||||
}
|
Reference in New Issue
Block a user