mirror of
https://github.com/linuxkit/linuxkit.git
synced 2025-07-19 09:16:29 +00:00
infrakit: Update vendored packages
Signed-off-by: Rolf Neugebauer <rolf.neugebauer@docker.com>
This commit is contained in:
parent
f4bf27e044
commit
a6dab6e6ca
@ -1,8 +1,10 @@
|
||||
github.com/Masterminds/sprig 427e90187e0902bc04b64167610f2da7ba26e0e1
|
||||
github.com/Sirupsen/logrus 1deb2db2a6fff8a35532079061b903c3a25eed52
|
||||
github.com/Masterminds/semver 312afcd0e81e5cf81fdc3cfd0e8504ae031521c8
|
||||
github.com/Masterminds/sprig 01a849f546a584d7b29bfee253e7db0aed44f7ba
|
||||
github.com/Sirupsen/logrus 10f801ebc38b33738c9d17d50860f484a0988ff5
|
||||
github.com/aokoli/goutils 9c37978a95bd5c709a15883b6242714ea6709e64
|
||||
github.com/armon/go-radix 4239b77079c7b5d1243b7b4736304ce8ddb6f0f2
|
||||
github.com/docker/infrakit 9b2321847c2eb4af9e63b5ff13f71b72fc1aad53
|
||||
github.com/docker/hyperkit 9f093be2e131133a7ec63f859d75242f1db9116e
|
||||
github.com/docker/infrakit 208d114478ed94ee9015083e13946ca1caaad790
|
||||
github.com/gorilla/context 08b5f424b9271eedf6f9f0ce86cb9396ed337a42
|
||||
github.com/gorilla/mux 599cba5e7b6137d46ddf58fb1765f5d928e69604
|
||||
github.com/gorilla/rpc 22c016f3df3febe0c1f6727598b6389507e03a18
|
||||
@ -11,8 +13,8 @@ github.com/jmespath/go-jmespath bd40a432e4c76585ef6b72d3fd96fb9b6dc7b68d
|
||||
github.com/mitchellh/go-ps 4fdf99ab29366514c69ccccddab5dc58b8d84062
|
||||
github.com/rneugeba/iso9660wrap 9c7eaf5ac74b2416be8b7b8d1f35b9af44a6e4fa
|
||||
github.com/satori/go.uuid b061729afc07e77a8aa4fad0a2fd840958f1942a
|
||||
github.com/spf13/cobra 16c014f1a19d865b765b420e74508f80eb831ada
|
||||
github.com/spf13/cobra 7be4beda01ec05d0b93d80b3facd2b6f44080d94
|
||||
github.com/spf13/pflag 9ff6c6923cfffbcd502984b8e0c80539a94968b7
|
||||
golang.org/x/crypto 728b753d0135da6801d45a38e6f43ff55779c5c2
|
||||
golang.org/x/crypto 459e26527287adbc2adcc5d0d49abff9a5f315a7
|
||||
golang.org/x/sys 99f16d856c9836c42d24e7ab64ea72916925fa97
|
||||
gopkg.in/tylerb/graceful.v1 4654dfbb6ad53cb5e27f37d99b02e16c1872fbbb
|
||||
|
20
tools/infrakit.hyperkit/vendor/github.com/Masterminds/semver/LICENSE.txt
generated
vendored
Normal file
20
tools/infrakit.hyperkit/vendor/github.com/Masterminds/semver/LICENSE.txt
generated
vendored
Normal file
@ -0,0 +1,20 @@
|
||||
The Masterminds
|
||||
Copyright (C) 2014-2015, Matt Butcher and Matt Farina
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
163
tools/infrakit.hyperkit/vendor/github.com/Masterminds/semver/README.md
generated
vendored
Normal file
163
tools/infrakit.hyperkit/vendor/github.com/Masterminds/semver/README.md
generated
vendored
Normal file
@ -0,0 +1,163 @@
|
||||
# SemVer
|
||||
|
||||
The `semver` package provides the ability to work with [Semantic Versions](http://semver.org) in Go. Specifically it provides the ability to:
|
||||
|
||||
* Parse semantic versions
|
||||
* Sort semantic versions
|
||||
* Check if a semantic version fits within a set of constraints
|
||||
* Optionally work with a `v` prefix
|
||||
|
||||
[](https://travis-ci.org/Masterminds/semver) [](https://ci.appveyor.com/project/mattfarina/semver/branch/master) [](https://godoc.org/github.com/Masterminds/semver) [](https://goreportcard.com/report/github.com/Masterminds/semver)
|
||||
|
||||
## Parsing Semantic Versions
|
||||
|
||||
To parse a semantic version use the `NewVersion` function. For example,
|
||||
|
||||
```go
|
||||
v, err := semver.NewVersion("1.2.3-beta.1+build345")
|
||||
```
|
||||
|
||||
If there is an error the version wasn't parseable. The version object has methods
|
||||
to get the parts of the version, compare it to other versions, convert the
|
||||
version back into a string, and get the original string. For more details
|
||||
please see the [documentation](https://godoc.org/github.com/Masterminds/semver).
|
||||
|
||||
## Sorting Semantic Versions
|
||||
|
||||
A set of versions can be sorted using the [`sort`](https://golang.org/pkg/sort/)
|
||||
package from the standard library. For example,
|
||||
|
||||
```go
|
||||
raw := []string{"1.2.3", "1.0", "1.3", "2", "0.4.2",}
|
||||
vs := make([]*semver.Version, len(raw))
|
||||
for i, r := range raw {
|
||||
v, err := semver.NewVersion(r)
|
||||
if err != nil {
|
||||
t.Errorf("Error parsing version: %s", err)
|
||||
}
|
||||
|
||||
vs[i] = v
|
||||
}
|
||||
|
||||
sort.Sort(semver.Collection(vs))
|
||||
```
|
||||
|
||||
## Checking Version Constraints
|
||||
|
||||
Checking a version against version constraints is one of the most featureful
|
||||
parts of the package.
|
||||
|
||||
```go
|
||||
c, err := semver.NewConstraint(">= 1.2.3")
|
||||
if err != nil {
|
||||
// Handle constraint not being parseable.
|
||||
}
|
||||
|
||||
v, _ := semver.NewVersion("1.3")
|
||||
if err != nil {
|
||||
// Handle version not being parseable.
|
||||
}
|
||||
// Check if the version meets the constraints. The a variable will be true.
|
||||
a := c.Check(v)
|
||||
```
|
||||
|
||||
## Basic Comparisons
|
||||
|
||||
There are two elements to the comparisons. First, a comparison string is a list
|
||||
of comma separated and comparisons. These are then separated by || separated or
|
||||
comparisons. For example, `">= 1.2, < 3.0.0 || >= 4.2.3"` is looking for a
|
||||
comparison that's greater than or equal to 1.2 and less than 3.0.0 or is
|
||||
greater than or equal to 4.2.3.
|
||||
|
||||
The basic comparisons are:
|
||||
|
||||
* `=`: equal (aliased to no operator)
|
||||
* `!=`: not equal
|
||||
* `>`: greater than
|
||||
* `<`: less than
|
||||
* `>=`: greater than or equal to
|
||||
* `<=`: less than or equal to
|
||||
|
||||
_Note, according to the Semantic Version specification pre-releases may not be
|
||||
API compliant with their release counterpart. It says,_
|
||||
|
||||
> _A pre-release version indicates that the version is unstable and might not satisfy the intended compatibility requirements as denoted by its associated normal version._
|
||||
|
||||
_SemVer comparisons without a pre-release value will skip pre-release versions.
|
||||
For example, `>1.2.3` will skip pre-releases when looking at a list of values
|
||||
while `>1.2.3-alpha.1` will evaluate pre-releases._
|
||||
|
||||
## Hyphen Range Comparisons
|
||||
|
||||
There are multiple methods to handle ranges and the first is hyphens ranges.
|
||||
These look like:
|
||||
|
||||
* `1.2 - 1.4.5` which is equivalent to `>= 1.2, <= 1.4.5`
|
||||
* `2.3.4 - 4.5` which is equivalent to `>= 2.3.4, <= 4.5`
|
||||
|
||||
## Wildcards In Comparisons
|
||||
|
||||
The `x`, `X`, and `*` characters can be used as a wildcard character. This works
|
||||
for all comparison operators. When used on the `=` operator it falls
|
||||
back to the pack level comparison (see tilde below). For example,
|
||||
|
||||
* `1.2.x` is equivalent to `>= 1.2.0, < 1.3.0`
|
||||
* `>= 1.2.x` is equivalent to `>= 1.2.0`
|
||||
* `<= 2.x` is equivalent to `<= 3`
|
||||
* `*` is equivalent to `>= 0.0.0`
|
||||
|
||||
## Tilde Range Comparisons (Patch)
|
||||
|
||||
The tilde (`~`) comparison operator is for patch level ranges when a minor
|
||||
version is specified and major level changes when the minor number is missing.
|
||||
For example,
|
||||
|
||||
* `~1.2.3` is equivalent to `>= 1.2.3, < 1.3.0`
|
||||
* `~1` is equivalent to `>= 1, < 2`
|
||||
* `~2.3` is equivalent to `>= 2.3, < 2.4`
|
||||
* `~1.2.x` is equivalent to `>= 1.2.0, < 1.3.0`
|
||||
* `~1.x` is equivalent to `>= 1, < 2`
|
||||
|
||||
## Caret Range Comparisons (Major)
|
||||
|
||||
The caret (`^`) comparison operator is for major level changes. This is useful
|
||||
when comparisons of API versions as a major change is API breaking. For example,
|
||||
|
||||
* `^1.2.3` is equivalent to `>= 1.2.3, < 2.0.0`
|
||||
* `^1.2.x` is equivalent to `>= 1.2.0, < 2.0.0`
|
||||
* `^2.3` is equivalent to `>= 2.3, < 3`
|
||||
* `^2.x` is equivalent to `>= 2.0.0, < 3`
|
||||
|
||||
# Validation
|
||||
|
||||
In addition to testing a version against a constraint, a version can be validated
|
||||
against a constraint. When validation fails a slice of errors containing why a
|
||||
version didn't meet the constraint is returned. For example,
|
||||
|
||||
```go
|
||||
c, err := semver.NewConstraint("<= 1.2.3, >= 1.4")
|
||||
if err != nil {
|
||||
// Handle constraint not being parseable.
|
||||
}
|
||||
|
||||
v, _ := semver.NewVersion("1.3")
|
||||
if err != nil {
|
||||
// Handle version not being parseable.
|
||||
}
|
||||
|
||||
// Validate a version against a constraint.
|
||||
a, msgs := c.Validate(v)
|
||||
// a is false
|
||||
for _, m := range msgs {
|
||||
fmt.Println(m)
|
||||
|
||||
// Loops over the errors which would read
|
||||
// "1.3 is greater than 1.2.3"
|
||||
// "1.3 is less than 1.4"
|
||||
}
|
||||
```
|
||||
|
||||
# Contribute
|
||||
|
||||
If you find an issue or want to contribute please file an [issue](https://github.com/Masterminds/semver/issues)
|
||||
or [create a pull request](https://github.com/Masterminds/semver/pulls).
|
24
tools/infrakit.hyperkit/vendor/github.com/Masterminds/semver/collection.go
generated
vendored
Normal file
24
tools/infrakit.hyperkit/vendor/github.com/Masterminds/semver/collection.go
generated
vendored
Normal file
@ -0,0 +1,24 @@
|
||||
package semver
|
||||
|
||||
// Collection is a collection of Version instances and implements the sort
|
||||
// interface. See the sort package for more details.
|
||||
// https://golang.org/pkg/sort/
|
||||
type Collection []*Version
|
||||
|
||||
// Len returns the length of a collection. The number of Version instances
|
||||
// on the slice.
|
||||
func (c Collection) Len() int {
|
||||
return len(c)
|
||||
}
|
||||
|
||||
// Less is needed for the sort interface to compare two Version objects on the
|
||||
// slice. If checks if one is less than the other.
|
||||
func (c Collection) Less(i, j int) bool {
|
||||
return c[i].LessThan(c[j])
|
||||
}
|
||||
|
||||
// Swap is needed for the sort interface to replace the Version objects
|
||||
// at two different positions in the slice.
|
||||
func (c Collection) Swap(i, j int) {
|
||||
c[i], c[j] = c[j], c[i]
|
||||
}
|
421
tools/infrakit.hyperkit/vendor/github.com/Masterminds/semver/constraints.go
generated
vendored
Normal file
421
tools/infrakit.hyperkit/vendor/github.com/Masterminds/semver/constraints.go
generated
vendored
Normal file
@ -0,0 +1,421 @@
|
||||
package semver
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"regexp"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// Constraints is one or more constraint that a semantic version can be
|
||||
// checked against.
|
||||
type Constraints struct {
|
||||
constraints [][]*constraint
|
||||
}
|
||||
|
||||
// NewConstraint returns a Constraints instance that a Version instance can
|
||||
// be checked against. If there is a parse error it will be returned.
|
||||
func NewConstraint(c string) (*Constraints, error) {
|
||||
|
||||
// Rewrite - ranges into a comparison operation.
|
||||
c = rewriteRange(c)
|
||||
|
||||
ors := strings.Split(c, "||")
|
||||
or := make([][]*constraint, len(ors))
|
||||
for k, v := range ors {
|
||||
cs := strings.Split(v, ",")
|
||||
result := make([]*constraint, len(cs))
|
||||
for i, s := range cs {
|
||||
pc, err := parseConstraint(s)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
result[i] = pc
|
||||
}
|
||||
or[k] = result
|
||||
}
|
||||
|
||||
o := &Constraints{constraints: or}
|
||||
return o, nil
|
||||
}
|
||||
|
||||
// Check tests if a version satisfies the constraints.
|
||||
func (cs Constraints) Check(v *Version) bool {
|
||||
// loop over the ORs and check the inner ANDs
|
||||
for _, o := range cs.constraints {
|
||||
joy := true
|
||||
for _, c := range o {
|
||||
if !c.check(v) {
|
||||
joy = false
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
if joy {
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
// Validate checks if a version satisfies a constraint. If not a slice of
|
||||
// reasons for the failure are returned in addition to a bool.
|
||||
func (cs Constraints) Validate(v *Version) (bool, []error) {
|
||||
// loop over the ORs and check the inner ANDs
|
||||
var e []error
|
||||
for _, o := range cs.constraints {
|
||||
joy := true
|
||||
for _, c := range o {
|
||||
if !c.check(v) {
|
||||
em := fmt.Errorf(c.msg, v, c.orig)
|
||||
e = append(e, em)
|
||||
joy = false
|
||||
}
|
||||
}
|
||||
|
||||
if joy {
|
||||
return true, []error{}
|
||||
}
|
||||
}
|
||||
|
||||
return false, e
|
||||
}
|
||||
|
||||
var constraintOps map[string]cfunc
|
||||
var constraintMsg map[string]string
|
||||
var constraintRegex *regexp.Regexp
|
||||
|
||||
func init() {
|
||||
constraintOps = map[string]cfunc{
|
||||
"": constraintTildeOrEqual,
|
||||
"=": constraintTildeOrEqual,
|
||||
"!=": constraintNotEqual,
|
||||
">": constraintGreaterThan,
|
||||
"<": constraintLessThan,
|
||||
">=": constraintGreaterThanEqual,
|
||||
"=>": constraintGreaterThanEqual,
|
||||
"<=": constraintLessThanEqual,
|
||||
"=<": constraintLessThanEqual,
|
||||
"~": constraintTilde,
|
||||
"~>": constraintTilde,
|
||||
"^": constraintCaret,
|
||||
}
|
||||
|
||||
constraintMsg = map[string]string{
|
||||
"": "%s is not equal to %s",
|
||||
"=": "%s is not equal to %s",
|
||||
"!=": "%s is equal to %s",
|
||||
">": "%s is less than or equal to %s",
|
||||
"<": "%s is greater than or equal to %s",
|
||||
">=": "%s is less than %s",
|
||||
"=>": "%s is less than %s",
|
||||
"<=": "%s is greater than %s",
|
||||
"=<": "%s is greater than %s",
|
||||
"~": "%s does not have same major and minor version as %s",
|
||||
"~>": "%s does not have same major and minor version as %s",
|
||||
"^": "%s does not have same major version as %s",
|
||||
}
|
||||
|
||||
ops := make([]string, 0, len(constraintOps))
|
||||
for k := range constraintOps {
|
||||
ops = append(ops, regexp.QuoteMeta(k))
|
||||
}
|
||||
|
||||
constraintRegex = regexp.MustCompile(fmt.Sprintf(
|
||||
`^\s*(%s)\s*(%s)\s*$`,
|
||||
strings.Join(ops, "|"),
|
||||
cvRegex))
|
||||
|
||||
constraintRangeRegex = regexp.MustCompile(fmt.Sprintf(
|
||||
`\s*(%s)\s+-\s+(%s)\s*`,
|
||||
cvRegex, cvRegex))
|
||||
}
|
||||
|
||||
// An individual constraint
|
||||
type constraint struct {
|
||||
// The callback function for the restraint. It performs the logic for
|
||||
// the constraint.
|
||||
function cfunc
|
||||
|
||||
msg string
|
||||
|
||||
// The version used in the constraint check. For example, if a constraint
|
||||
// is '<= 2.0.0' the con a version instance representing 2.0.0.
|
||||
con *Version
|
||||
|
||||
// The original parsed version (e.g., 4.x from != 4.x)
|
||||
orig string
|
||||
|
||||
// When an x is used as part of the version (e.g., 1.x)
|
||||
minorDirty bool
|
||||
dirty bool
|
||||
}
|
||||
|
||||
// Check if a version meets the constraint
|
||||
func (c *constraint) check(v *Version) bool {
|
||||
return c.function(v, c)
|
||||
}
|
||||
|
||||
type cfunc func(v *Version, c *constraint) bool
|
||||
|
||||
func parseConstraint(c string) (*constraint, error) {
|
||||
m := constraintRegex.FindStringSubmatch(c)
|
||||
if m == nil {
|
||||
return nil, fmt.Errorf("improper constraint: %s", c)
|
||||
}
|
||||
|
||||
ver := m[2]
|
||||
orig := ver
|
||||
minorDirty := false
|
||||
dirty := false
|
||||
if isX(m[3]) {
|
||||
ver = "0.0.0"
|
||||
dirty = true
|
||||
} else if isX(strings.TrimPrefix(m[4], ".")) {
|
||||
minorDirty = true
|
||||
dirty = true
|
||||
ver = fmt.Sprintf("%s.0.0%s", m[3], m[6])
|
||||
} else if isX(strings.TrimPrefix(m[5], ".")) {
|
||||
dirty = true
|
||||
ver = fmt.Sprintf("%s%s.0%s", m[3], m[4], m[6])
|
||||
}
|
||||
|
||||
con, err := NewVersion(ver)
|
||||
if err != nil {
|
||||
|
||||
// The constraintRegex should catch any regex parsing errors. So,
|
||||
// we should never get here.
|
||||
return nil, errors.New("constraint Parser Error")
|
||||
}
|
||||
|
||||
cs := &constraint{
|
||||
function: constraintOps[m[1]],
|
||||
msg: constraintMsg[m[1]],
|
||||
con: con,
|
||||
orig: orig,
|
||||
minorDirty: minorDirty,
|
||||
dirty: dirty,
|
||||
}
|
||||
return cs, nil
|
||||
}
|
||||
|
||||
// Constraint functions
|
||||
func constraintNotEqual(v *Version, c *constraint) bool {
|
||||
if c.dirty {
|
||||
|
||||
// If there is a pre-release on the version but the constraint isn't looking
|
||||
// for them assume that pre-releases are not compatible. See issue 21 for
|
||||
// more details.
|
||||
if v.Prerelease() != "" && c.con.Prerelease() == "" {
|
||||
return false
|
||||
}
|
||||
|
||||
if c.con.Major() != v.Major() {
|
||||
return true
|
||||
}
|
||||
if c.con.Minor() != v.Minor() && !c.minorDirty {
|
||||
return true
|
||||
} else if c.minorDirty {
|
||||
return false
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
return !v.Equal(c.con)
|
||||
}
|
||||
|
||||
func constraintGreaterThan(v *Version, c *constraint) bool {
|
||||
|
||||
// An edge case the constraint is 0.0.0 and the version is 0.0.0-someprerelease
|
||||
// exists. This that case.
|
||||
if !isNonZero(c.con) && isNonZero(v) {
|
||||
return true
|
||||
}
|
||||
|
||||
// If there is a pre-release on the version but the constraint isn't looking
|
||||
// for them assume that pre-releases are not compatible. See issue 21 for
|
||||
// more details.
|
||||
if v.Prerelease() != "" && c.con.Prerelease() == "" {
|
||||
return false
|
||||
}
|
||||
|
||||
return v.Compare(c.con) == 1
|
||||
}
|
||||
|
||||
func constraintLessThan(v *Version, c *constraint) bool {
|
||||
// If there is a pre-release on the version but the constraint isn't looking
|
||||
// for them assume that pre-releases are not compatible. See issue 21 for
|
||||
// more details.
|
||||
if v.Prerelease() != "" && c.con.Prerelease() == "" {
|
||||
return false
|
||||
}
|
||||
|
||||
if !c.dirty {
|
||||
return v.Compare(c.con) < 0
|
||||
}
|
||||
|
||||
if v.Major() > c.con.Major() {
|
||||
return false
|
||||
} else if v.Minor() > c.con.Minor() && !c.minorDirty {
|
||||
return false
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
func constraintGreaterThanEqual(v *Version, c *constraint) bool {
|
||||
// An edge case the constraint is 0.0.0 and the version is 0.0.0-someprerelease
|
||||
// exists. This that case.
|
||||
if !isNonZero(c.con) && isNonZero(v) {
|
||||
return true
|
||||
}
|
||||
|
||||
// If there is a pre-release on the version but the constraint isn't looking
|
||||
// for them assume that pre-releases are not compatible. See issue 21 for
|
||||
// more details.
|
||||
if v.Prerelease() != "" && c.con.Prerelease() == "" {
|
||||
return false
|
||||
}
|
||||
|
||||
return v.Compare(c.con) >= 0
|
||||
}
|
||||
|
||||
func constraintLessThanEqual(v *Version, c *constraint) bool {
|
||||
// If there is a pre-release on the version but the constraint isn't looking
|
||||
// for them assume that pre-releases are not compatible. See issue 21 for
|
||||
// more details.
|
||||
if v.Prerelease() != "" && c.con.Prerelease() == "" {
|
||||
return false
|
||||
}
|
||||
|
||||
if !c.dirty {
|
||||
return v.Compare(c.con) <= 0
|
||||
}
|
||||
|
||||
if v.Major() > c.con.Major() {
|
||||
return false
|
||||
} else if v.Minor() > c.con.Minor() && !c.minorDirty {
|
||||
return false
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
// ~*, ~>* --> >= 0.0.0 (any)
|
||||
// ~2, ~2.x, ~2.x.x, ~>2, ~>2.x ~>2.x.x --> >=2.0.0, <3.0.0
|
||||
// ~2.0, ~2.0.x, ~>2.0, ~>2.0.x --> >=2.0.0, <2.1.0
|
||||
// ~1.2, ~1.2.x, ~>1.2, ~>1.2.x --> >=1.2.0, <1.3.0
|
||||
// ~1.2.3, ~>1.2.3 --> >=1.2.3, <1.3.0
|
||||
// ~1.2.0, ~>1.2.0 --> >=1.2.0, <1.3.0
|
||||
func constraintTilde(v *Version, c *constraint) bool {
|
||||
// If there is a pre-release on the version but the constraint isn't looking
|
||||
// for them assume that pre-releases are not compatible. See issue 21 for
|
||||
// more details.
|
||||
if v.Prerelease() != "" && c.con.Prerelease() == "" {
|
||||
return false
|
||||
}
|
||||
|
||||
if v.LessThan(c.con) {
|
||||
return false
|
||||
}
|
||||
|
||||
// ~0.0.0 is a special case where all constraints are accepted. It's
|
||||
// equivalent to >= 0.0.0.
|
||||
if c.con.Major() == 0 && c.con.Minor() == 0 && c.con.Patch() == 0 {
|
||||
return true
|
||||
}
|
||||
|
||||
if v.Major() != c.con.Major() {
|
||||
return false
|
||||
}
|
||||
|
||||
if v.Minor() != c.con.Minor() && !c.minorDirty {
|
||||
return false
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
// When there is a .x (dirty) status it automatically opts in to ~. Otherwise
|
||||
// it's a straight =
|
||||
func constraintTildeOrEqual(v *Version, c *constraint) bool {
|
||||
// If there is a pre-release on the version but the constraint isn't looking
|
||||
// for them assume that pre-releases are not compatible. See issue 21 for
|
||||
// more details.
|
||||
if v.Prerelease() != "" && c.con.Prerelease() == "" {
|
||||
return false
|
||||
}
|
||||
|
||||
if c.dirty {
|
||||
c.msg = constraintMsg["~"]
|
||||
return constraintTilde(v, c)
|
||||
}
|
||||
|
||||
return v.Equal(c.con)
|
||||
}
|
||||
|
||||
// ^* --> (any)
|
||||
// ^2, ^2.x, ^2.x.x --> >=2.0.0, <3.0.0
|
||||
// ^2.0, ^2.0.x --> >=2.0.0, <3.0.0
|
||||
// ^1.2, ^1.2.x --> >=1.2.0, <2.0.0
|
||||
// ^1.2.3 --> >=1.2.3, <2.0.0
|
||||
// ^1.2.0 --> >=1.2.0, <2.0.0
|
||||
func constraintCaret(v *Version, c *constraint) bool {
|
||||
// If there is a pre-release on the version but the constraint isn't looking
|
||||
// for them assume that pre-releases are not compatible. See issue 21 for
|
||||
// more details.
|
||||
if v.Prerelease() != "" && c.con.Prerelease() == "" {
|
||||
return false
|
||||
}
|
||||
|
||||
if v.LessThan(c.con) {
|
||||
return false
|
||||
}
|
||||
|
||||
if v.Major() != c.con.Major() {
|
||||
return false
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
var constraintRangeRegex *regexp.Regexp
|
||||
|
||||
const cvRegex string = `v?([0-9|x|X|\*]+)(\.[0-9|x|X|\*]+)?(\.[0-9|x|X|\*]+)?` +
|
||||
`(-([0-9A-Za-z\-]+(\.[0-9A-Za-z\-]+)*))?` +
|
||||
`(\+([0-9A-Za-z\-]+(\.[0-9A-Za-z\-]+)*))?`
|
||||
|
||||
func isX(x string) bool {
|
||||
switch x {
|
||||
case "x", "*", "X":
|
||||
return true
|
||||
default:
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
func rewriteRange(i string) string {
|
||||
m := constraintRangeRegex.FindAllStringSubmatch(i, -1)
|
||||
if m == nil {
|
||||
return i
|
||||
}
|
||||
o := i
|
||||
for _, v := range m {
|
||||
t := fmt.Sprintf(">= %s, <= %s", v[1], v[11])
|
||||
o = strings.Replace(o, v[0], t, 1)
|
||||
}
|
||||
|
||||
return o
|
||||
}
|
||||
|
||||
// Detect if a version is not zero (0.0.0)
|
||||
func isNonZero(v *Version) bool {
|
||||
if v.Major() != 0 || v.Minor() != 0 || v.Patch() != 0 || v.Prerelease() != "" {
|
||||
return true
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
115
tools/infrakit.hyperkit/vendor/github.com/Masterminds/semver/doc.go
generated
vendored
Normal file
115
tools/infrakit.hyperkit/vendor/github.com/Masterminds/semver/doc.go
generated
vendored
Normal file
@ -0,0 +1,115 @@
|
||||
/*
|
||||
Package semver provides the ability to work with Semantic Versions (http://semver.org) in Go.
|
||||
|
||||
Specifically it provides the ability to:
|
||||
|
||||
* Parse semantic versions
|
||||
* Sort semantic versions
|
||||
* Check if a semantic version fits within a set of constraints
|
||||
* Optionally work with a `v` prefix
|
||||
|
||||
Parsing Semantic Versions
|
||||
|
||||
To parse a semantic version use the `NewVersion` function. For example,
|
||||
|
||||
v, err := semver.NewVersion("1.2.3-beta.1+build345")
|
||||
|
||||
If there is an error the version wasn't parseable. The version object has methods
|
||||
to get the parts of the version, compare it to other versions, convert the
|
||||
version back into a string, and get the original string. For more details
|
||||
please see the documentation at https://godoc.org/github.com/Masterminds/semver.
|
||||
|
||||
Sorting Semantic Versions
|
||||
|
||||
A set of versions can be sorted using the `sort` package from the standard library.
|
||||
For example,
|
||||
|
||||
raw := []string{"1.2.3", "1.0", "1.3", "2", "0.4.2",}
|
||||
vs := make([]*semver.Version, len(raw))
|
||||
for i, r := range raw {
|
||||
v, err := semver.NewVersion(r)
|
||||
if err != nil {
|
||||
t.Errorf("Error parsing version: %s", err)
|
||||
}
|
||||
|
||||
vs[i] = v
|
||||
}
|
||||
|
||||
sort.Sort(semver.Collection(vs))
|
||||
|
||||
Checking Version Constraints
|
||||
|
||||
Checking a version against version constraints is one of the most featureful
|
||||
parts of the package.
|
||||
|
||||
c, err := semver.NewConstraint(">= 1.2.3")
|
||||
if err != nil {
|
||||
// Handle constraint not being parseable.
|
||||
}
|
||||
|
||||
v, _ := semver.NewVersion("1.3")
|
||||
if err != nil {
|
||||
// Handle version not being parseable.
|
||||
}
|
||||
// Check if the version meets the constraints. The a variable will be true.
|
||||
a := c.Check(v)
|
||||
|
||||
Basic Comparisons
|
||||
|
||||
There are two elements to the comparisons. First, a comparison string is a list
|
||||
of comma separated and comparisons. These are then separated by || separated or
|
||||
comparisons. For example, `">= 1.2, < 3.0.0 || >= 4.2.3"` is looking for a
|
||||
comparison that's greater than or equal to 1.2 and less than 3.0.0 or is
|
||||
greater than or equal to 4.2.3.
|
||||
|
||||
The basic comparisons are:
|
||||
|
||||
* `=`: equal (aliased to no operator)
|
||||
* `!=`: not equal
|
||||
* `>`: greater than
|
||||
* `<`: less than
|
||||
* `>=`: greater than or equal to
|
||||
* `<=`: less than or equal to
|
||||
|
||||
Hyphen Range Comparisons
|
||||
|
||||
There are multiple methods to handle ranges and the first is hyphens ranges.
|
||||
These look like:
|
||||
|
||||
* `1.2 - 1.4.5` which is equivalent to `>= 1.2, <= 1.4.5`
|
||||
* `2.3.4 - 4.5` which is equivalent to `>= 2.3.4, <= 4.5`
|
||||
|
||||
Wildcards In Comparisons
|
||||
|
||||
The `x`, `X`, and `*` characters can be used as a wildcard character. This works
|
||||
for all comparison operators. When used on the `=` operator it falls
|
||||
back to the pack level comparison (see tilde below). For example,
|
||||
|
||||
* `1.2.x` is equivalent to `>= 1.2.0, < 1.3.0`
|
||||
* `>= 1.2.x` is equivalent to `>= 1.2.0`
|
||||
* `<= 2.x` is equivalent to `<= 3`
|
||||
* `*` is equivalent to `>= 0.0.0`
|
||||
|
||||
Tilde Range Comparisons (Patch)
|
||||
|
||||
The tilde (`~`) comparison operator is for patch level ranges when a minor
|
||||
version is specified and major level changes when the minor number is missing.
|
||||
For example,
|
||||
|
||||
* `~1.2.3` is equivalent to `>= 1.2.3, < 1.3.0`
|
||||
* `~1` is equivalent to `>= 1, < 2`
|
||||
* `~2.3` is equivalent to `>= 2.3, < 2.4`
|
||||
* `~1.2.x` is equivalent to `>= 1.2.0, < 1.3.0`
|
||||
* `~1.x` is equivalent to `>= 1, < 2`
|
||||
|
||||
Caret Range Comparisons (Major)
|
||||
|
||||
The caret (`^`) comparison operator is for major level changes. This is useful
|
||||
when comparisons of API versions as a major change is API breaking. For example,
|
||||
|
||||
* `^1.2.3` is equivalent to `>= 1.2.3, < 2.0.0`
|
||||
* `^1.2.x` is equivalent to `>= 1.2.0, < 2.0.0`
|
||||
* `^2.3` is equivalent to `>= 2.3, < 3`
|
||||
* `^2.x` is equivalent to `>= 2.0.0, < 3`
|
||||
*/
|
||||
package semver
|
375
tools/infrakit.hyperkit/vendor/github.com/Masterminds/semver/version.go
generated
vendored
Normal file
375
tools/infrakit.hyperkit/vendor/github.com/Masterminds/semver/version.go
generated
vendored
Normal file
@ -0,0 +1,375 @@
|
||||
package semver
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"errors"
|
||||
"fmt"
|
||||
"regexp"
|
||||
"strconv"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// The compiled version of the regex created at init() is cached here so it
|
||||
// only needs to be created once.
|
||||
var versionRegex *regexp.Regexp
|
||||
var validPrereleaseRegex *regexp.Regexp
|
||||
|
||||
var (
|
||||
// ErrInvalidSemVer is returned a version is found to be invalid when
|
||||
// being parsed.
|
||||
ErrInvalidSemVer = errors.New("Invalid Semantic Version")
|
||||
|
||||
// ErrInvalidMetadata is returned when the metadata is an invalid format
|
||||
ErrInvalidMetadata = errors.New("Invalid Metadata string")
|
||||
|
||||
// ErrInvalidPrerelease is returned when the pre-release is an invalid format
|
||||
ErrInvalidPrerelease = errors.New("Invalid Prerelease string")
|
||||
)
|
||||
|
||||
// SemVerRegex is the regular expression used to parse a semantic version.
|
||||
const SemVerRegex string = `v?([0-9]+)(\.[0-9]+)?(\.[0-9]+)?` +
|
||||
`(-([0-9A-Za-z\-]+(\.[0-9A-Za-z\-]+)*))?` +
|
||||
`(\+([0-9A-Za-z\-]+(\.[0-9A-Za-z\-]+)*))?`
|
||||
|
||||
// ValidPrerelease is the regular expression which validates
|
||||
// both prerelease and metadata values.
|
||||
const ValidPrerelease string = `^([0-9A-Za-z\-]+(\.[0-9A-Za-z\-]+)*)`
|
||||
|
||||
// Version represents a single semantic version.
|
||||
type Version struct {
|
||||
major, minor, patch int64
|
||||
pre string
|
||||
metadata string
|
||||
original string
|
||||
}
|
||||
|
||||
func init() {
|
||||
versionRegex = regexp.MustCompile("^" + SemVerRegex + "$")
|
||||
validPrereleaseRegex = regexp.MustCompile(ValidPrerelease)
|
||||
}
|
||||
|
||||
// NewVersion parses a given version and returns an instance of Version or
|
||||
// an error if unable to parse the version.
|
||||
func NewVersion(v string) (*Version, error) {
|
||||
m := versionRegex.FindStringSubmatch(v)
|
||||
if m == nil {
|
||||
return nil, ErrInvalidSemVer
|
||||
}
|
||||
|
||||
sv := &Version{
|
||||
metadata: m[8],
|
||||
pre: m[5],
|
||||
original: v,
|
||||
}
|
||||
|
||||
var temp int64
|
||||
temp, err := strconv.ParseInt(m[1], 10, 32)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("Error parsing version segment: %s", err)
|
||||
}
|
||||
sv.major = temp
|
||||
|
||||
if m[2] != "" {
|
||||
temp, err = strconv.ParseInt(strings.TrimPrefix(m[2], "."), 10, 32)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("Error parsing version segment: %s", err)
|
||||
}
|
||||
sv.minor = temp
|
||||
} else {
|
||||
sv.minor = 0
|
||||
}
|
||||
|
||||
if m[3] != "" {
|
||||
temp, err = strconv.ParseInt(strings.TrimPrefix(m[3], "."), 10, 32)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("Error parsing version segment: %s", err)
|
||||
}
|
||||
sv.patch = temp
|
||||
} else {
|
||||
sv.patch = 0
|
||||
}
|
||||
|
||||
return sv, nil
|
||||
}
|
||||
|
||||
// MustParse parses a given version and panics on error.
|
||||
func MustParse(v string) *Version {
|
||||
sv, err := NewVersion(v)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
return sv
|
||||
}
|
||||
|
||||
// String converts a Version object to a string.
|
||||
// Note, if the original version contained a leading v this version will not.
|
||||
// See the Original() method to retrieve the original value. Semantic Versions
|
||||
// don't contain a leading v per the spec. Instead it's optional on
|
||||
// impelementation.
|
||||
func (v *Version) String() string {
|
||||
var buf bytes.Buffer
|
||||
|
||||
fmt.Fprintf(&buf, "%d.%d.%d", v.major, v.minor, v.patch)
|
||||
if v.pre != "" {
|
||||
fmt.Fprintf(&buf, "-%s", v.pre)
|
||||
}
|
||||
if v.metadata != "" {
|
||||
fmt.Fprintf(&buf, "+%s", v.metadata)
|
||||
}
|
||||
|
||||
return buf.String()
|
||||
}
|
||||
|
||||
// Original returns the original value passed in to be parsed.
|
||||
func (v *Version) Original() string {
|
||||
return v.original
|
||||
}
|
||||
|
||||
// Major returns the major version.
|
||||
func (v *Version) Major() int64 {
|
||||
return v.major
|
||||
}
|
||||
|
||||
// Minor returns the minor version.
|
||||
func (v *Version) Minor() int64 {
|
||||
return v.minor
|
||||
}
|
||||
|
||||
// Patch returns the patch version.
|
||||
func (v *Version) Patch() int64 {
|
||||
return v.patch
|
||||
}
|
||||
|
||||
// Prerelease returns the pre-release version.
|
||||
func (v *Version) Prerelease() string {
|
||||
return v.pre
|
||||
}
|
||||
|
||||
// Metadata returns the metadata on the version.
|
||||
func (v *Version) Metadata() string {
|
||||
return v.metadata
|
||||
}
|
||||
|
||||
// originalVPrefix returns the original 'v' prefix if any.
|
||||
func (v *Version) originalVPrefix() string {
|
||||
|
||||
// Note, only lowercase v is supported as a prefix by the parser.
|
||||
if v.original != "" && v.original[:1] == "v" {
|
||||
return v.original[:1]
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
// IncPatch produces the next patch version.
|
||||
// If the current version does not have prerelease/metadata information,
|
||||
// it unsets metadata and prerelease values, increments patch number.
|
||||
// If the current version has any of prerelease or metadata information,
|
||||
// it unsets both values and keeps curent patch value
|
||||
func (v Version) IncPatch() Version {
|
||||
vNext := v
|
||||
// according to http://semver.org/#spec-item-9
|
||||
// Pre-release versions have a lower precedence than the associated normal version.
|
||||
// according to http://semver.org/#spec-item-10
|
||||
// Build metadata SHOULD be ignored when determining version precedence.
|
||||
if v.pre != "" {
|
||||
vNext.metadata = ""
|
||||
vNext.pre = ""
|
||||
} else {
|
||||
vNext.metadata = ""
|
||||
vNext.pre = ""
|
||||
vNext.patch = v.patch + 1
|
||||
}
|
||||
vNext.original = v.originalVPrefix() + "" + vNext.String()
|
||||
return vNext
|
||||
}
|
||||
|
||||
// IncMinor produces the next minor version.
|
||||
// Sets patch to 0.
|
||||
// Increments minor number.
|
||||
// Unsets metadata.
|
||||
// Unsets prerelease status.
|
||||
func (v Version) IncMinor() Version {
|
||||
vNext := v
|
||||
vNext.metadata = ""
|
||||
vNext.pre = ""
|
||||
vNext.patch = 0
|
||||
vNext.minor = v.minor + 1
|
||||
vNext.original = v.originalVPrefix() + "" + vNext.String()
|
||||
return vNext
|
||||
}
|
||||
|
||||
// IncMajor produces the next major version.
|
||||
// Sets patch to 0.
|
||||
// Sets minor to 0.
|
||||
// Increments major number.
|
||||
// Unsets metadata.
|
||||
// Unsets prerelease status.
|
||||
func (v Version) IncMajor() Version {
|
||||
vNext := v
|
||||
vNext.metadata = ""
|
||||
vNext.pre = ""
|
||||
vNext.patch = 0
|
||||
vNext.minor = 0
|
||||
vNext.major = v.major + 1
|
||||
vNext.original = v.originalVPrefix() + "" + vNext.String()
|
||||
return vNext
|
||||
}
|
||||
|
||||
// SetPrerelease defines the prerelease value.
|
||||
// Value must not include the required 'hypen' prefix.
|
||||
func (v Version) SetPrerelease(prerelease string) (Version, error) {
|
||||
vNext := v
|
||||
if len(prerelease) > 0 && !validPrereleaseRegex.MatchString(prerelease) {
|
||||
return vNext, ErrInvalidPrerelease
|
||||
}
|
||||
vNext.pre = prerelease
|
||||
vNext.original = v.originalVPrefix() + "" + vNext.String()
|
||||
return vNext, nil
|
||||
}
|
||||
|
||||
// SetMetadata defines metadata value.
|
||||
// Value must not include the required 'plus' prefix.
|
||||
func (v Version) SetMetadata(metadata string) (Version, error) {
|
||||
vNext := v
|
||||
if len(metadata) > 0 && !validPrereleaseRegex.MatchString(metadata) {
|
||||
return vNext, ErrInvalidMetadata
|
||||
}
|
||||
vNext.metadata = metadata
|
||||
vNext.original = v.originalVPrefix() + "" + vNext.String()
|
||||
return vNext, nil
|
||||
}
|
||||
|
||||
// LessThan tests if one version is less than another one.
|
||||
func (v *Version) LessThan(o *Version) bool {
|
||||
return v.Compare(o) < 0
|
||||
}
|
||||
|
||||
// GreaterThan tests if one version is greater than another one.
|
||||
func (v *Version) GreaterThan(o *Version) bool {
|
||||
return v.Compare(o) > 0
|
||||
}
|
||||
|
||||
// Equal tests if two versions are equal to each other.
|
||||
// Note, versions can be equal with different metadata since metadata
|
||||
// is not considered part of the comparable version.
|
||||
func (v *Version) Equal(o *Version) bool {
|
||||
return v.Compare(o) == 0
|
||||
}
|
||||
|
||||
// Compare compares this version to another one. It returns -1, 0, or 1 if
|
||||
// the version smaller, equal, or larger than the other version.
|
||||
//
|
||||
// Versions are compared by X.Y.Z. Build metadata is ignored. Prerelease is
|
||||
// lower than the version without a prerelease.
|
||||
func (v *Version) Compare(o *Version) int {
|
||||
// Compare the major, minor, and patch version for differences. If a
|
||||
// difference is found return the comparison.
|
||||
if d := compareSegment(v.Major(), o.Major()); d != 0 {
|
||||
return d
|
||||
}
|
||||
if d := compareSegment(v.Minor(), o.Minor()); d != 0 {
|
||||
return d
|
||||
}
|
||||
if d := compareSegment(v.Patch(), o.Patch()); d != 0 {
|
||||
return d
|
||||
}
|
||||
|
||||
// At this point the major, minor, and patch versions are the same.
|
||||
ps := v.pre
|
||||
po := o.Prerelease()
|
||||
|
||||
if ps == "" && po == "" {
|
||||
return 0
|
||||
}
|
||||
if ps == "" {
|
||||
return 1
|
||||
}
|
||||
if po == "" {
|
||||
return -1
|
||||
}
|
||||
|
||||
return comparePrerelease(ps, po)
|
||||
}
|
||||
|
||||
func compareSegment(v, o int64) int {
|
||||
if v < o {
|
||||
return -1
|
||||
}
|
||||
if v > o {
|
||||
return 1
|
||||
}
|
||||
|
||||
return 0
|
||||
}
|
||||
|
||||
func comparePrerelease(v, o string) int {
|
||||
|
||||
// split the prelease versions by their part. The separator, per the spec,
|
||||
// is a .
|
||||
sparts := strings.Split(v, ".")
|
||||
oparts := strings.Split(o, ".")
|
||||
|
||||
// Find the longer length of the parts to know how many loop iterations to
|
||||
// go through.
|
||||
slen := len(sparts)
|
||||
olen := len(oparts)
|
||||
|
||||
l := slen
|
||||
if olen > slen {
|
||||
l = olen
|
||||
}
|
||||
|
||||
// Iterate over each part of the prereleases to compare the differences.
|
||||
for i := 0; i < l; i++ {
|
||||
// Since the lentgh of the parts can be different we need to create
|
||||
// a placeholder. This is to avoid out of bounds issues.
|
||||
stemp := ""
|
||||
if i < slen {
|
||||
stemp = sparts[i]
|
||||
}
|
||||
|
||||
otemp := ""
|
||||
if i < olen {
|
||||
otemp = oparts[i]
|
||||
}
|
||||
|
||||
d := comparePrePart(stemp, otemp)
|
||||
if d != 0 {
|
||||
return d
|
||||
}
|
||||
}
|
||||
|
||||
// Reaching here means two versions are of equal value but have different
|
||||
// metadata (the part following a +). They are not identical in string form
|
||||
// but the version comparison finds them to be equal.
|
||||
return 0
|
||||
}
|
||||
|
||||
func comparePrePart(s, o string) int {
|
||||
// Fastpath if they are equal
|
||||
if s == o {
|
||||
return 0
|
||||
}
|
||||
|
||||
// When s or o are empty we can use the other in an attempt to determine
|
||||
// the response.
|
||||
if o == "" {
|
||||
_, n := strconv.ParseInt(s, 10, 64)
|
||||
if n != nil {
|
||||
return -1
|
||||
}
|
||||
return 1
|
||||
}
|
||||
if s == "" {
|
||||
_, n := strconv.ParseInt(o, 10, 64)
|
||||
if n != nil {
|
||||
return 1
|
||||
}
|
||||
return -1
|
||||
}
|
||||
|
||||
if s > o {
|
||||
return 1
|
||||
}
|
||||
return -1
|
||||
}
|
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")
|
||||
}
|
Loading…
Reference in New Issue
Block a user