restructure docker runtime pkg

pull/227/head
iwilltry42 5 years ago
parent 9323179a3c
commit 03eaba037f
  1. 86
      pkg/runtimes/docker/container.go
  2. 104
      pkg/runtimes/docker/node.go
  3. 2
      vendor/github.com/go-test/deep/.gitignore
  4. 13
      vendor/github.com/go-test/deep/.travis.yml
  5. 30
      vendor/github.com/go-test/deep/CHANGES.md
  6. 21
      vendor/github.com/go-test/deep/LICENSE
  7. 51
      vendor/github.com/go-test/deep/README.md
  8. 376
      vendor/github.com/go-test/deep/deep.go
  9. 1
      vendor/github.com/go-test/deep/go.mod
  10. 2
      vendor/modules.txt

@ -26,47 +26,35 @@ import (
"context"
"fmt"
"github.com/docker/docker/api/types/filters"
"github.com/docker/docker/api/types"
"github.com/docker/docker/api/types/container"
"github.com/docker/docker/api/types/network"
"github.com/docker/docker/client"
k3d "github.com/rancher/k3d/pkg/types"
log "github.com/sirupsen/logrus"
)
// CreateNode creates a new container
func (d Docker) CreateNode(node *k3d.Node) error {
log.Debugln("docker.CreateNode...")
ctx := context.Background() // TODO: check how kind handles contexts
// createContainer creates a new docker container from translated specs
func createContainer(dockerNode *NodeInDocker, name string) error {
log.Debugf("Creating docker container with translated config\n%+v\n", dockerNode) // TODO: remove?
// initialize docker client
ctx := context.Background()
docker, err := client.NewClientWithOpts(client.FromEnv, client.WithAPIVersionNegotiation())
if err != nil {
return fmt.Errorf("Failed to create docker client. %+v", err)
}
containerConfig := container.Config{
Cmd: node.Args,
Image: node.Image,
Labels: node.Labels,
log.Errorln("Failed to create docker client")
return err
}
resp, err := docker.ContainerCreate(ctx, &containerConfig, &container.HostConfig{}, &network.NetworkingConfig{}, node.Name)
// start container // TODO: check first if image exists locally and pull if it doesn't
resp, err := docker.ContainerCreate(ctx, &dockerNode.ContainerConfig, &dockerNode.HostConfig, &dockerNode.NetworkingConfig, name)
if err != nil {
log.Error("Couldn't create container")
log.Errorln("Failed to create container")
return err
}
log.Infoln("Created", resp.ID)
log.Infoln("Created container", resp.ID)
return nil
}
// createContainer creates a new docker container
// @return containerID, error
func createContainer(types.Container) (string, error) {
return "", nil
}
// removeContainer deletes a running container (like docker rm -f)
func removeContainer(ID string) error {
@ -92,51 +80,3 @@ func removeContainer(ID string) error {
return nil
}
// DeleteNode deletes a node
func (d Docker) DeleteNode(nodeSpec *k3d.Node) error {
log.Debugln("docker.DeleteNode...")
return removeContainer(nodeSpec.Name)
}
func (d Docker) GetNodesByLabel(labels map[string]string) ([]*k3d.Node, error) {
// (0) create docker client
ctx := context.Background()
docker, err := client.NewClientWithOpts(client.FromEnv, client.WithAPIVersionNegotiation())
if err != nil {
return nil, fmt.Errorf("Failed to create docker client. %+v", err)
}
// (1) list containers which have the default k3d labels attached
filters := filters.NewArgs()
for k, v := range k3d.DefaultObjectLabels {
filters.Add("label", fmt.Sprintf("%s=%s", k, v))
}
for k, v := range labels {
filters.Add("label", fmt.Sprintf("%s=%s", k, v))
}
containers, err := docker.ContainerList(ctx, types.ContainerListOptions{
Filters: filters,
All: true,
})
if err != nil {
log.Errorln("Failed to list containers")
return nil, err
}
// (2) convert them to node structs
nodes := []*k3d.Node{}
for _, container := range containers {
node := &k3d.Node{
Name: container.Names[0],
Role: container.Labels["role"], // TODO: catch keyerror
Labels: container.Labels,
}
nodes = append(nodes, node)
}
return nodes, nil
}

@ -0,0 +1,104 @@
/*
Copyright © 2019 Thorsten Klein <iwilltry42@gmail.com>
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.
*/
package docker
import (
"context"
"fmt"
"github.com/docker/docker/api/types/filters"
"github.com/docker/docker/api/types"
"github.com/docker/docker/client"
k3d "github.com/rancher/k3d/pkg/types"
log "github.com/sirupsen/logrus"
)
// CreateNode creates a new container
func (d Docker) CreateNode(node *k3d.Node) error {
log.Debugln("docker.CreateNode...")
// translate node spec to docker container specs
dockerNode, err := TranslateNodeToContainer(node)
if err != nil {
log.Errorln("Failed to translate k3d node specification to docker container specifications")
return err
}
// create node
if err := createContainer(dockerNode, node.Name); err != nil {
log.Errorln("Failed to create k3d node")
return err
}
return nil
}
// DeleteNode deletes a node
func (d Docker) DeleteNode(nodeSpec *k3d.Node) error {
log.Debugln("docker.DeleteNode...")
return removeContainer(nodeSpec.Name)
}
// GetNodesByLabel returns a list of existing nodes
func (d Docker) GetNodesByLabel(labels map[string]string) ([]*k3d.Node, error) {
// (0) create docker client
ctx := context.Background()
docker, err := client.NewClientWithOpts(client.FromEnv, client.WithAPIVersionNegotiation())
if err != nil {
return nil, fmt.Errorf("Failed to create docker client. %+v", err)
}
// (1) list containers which have the default k3d labels attached
filters := filters.NewArgs()
for k, v := range k3d.DefaultObjectLabels {
filters.Add("label", fmt.Sprintf("%s=%s", k, v))
}
for k, v := range labels {
filters.Add("label", fmt.Sprintf("%s=%s", k, v))
}
containers, err := docker.ContainerList(ctx, types.ContainerListOptions{
Filters: filters,
All: true,
})
if err != nil {
log.Errorln("Failed to list containers")
return nil, err
}
// (2) convert them to node structs
nodes := []*k3d.Node{}
for _, container := range containers {
node := &k3d.Node{
Name: container.Names[0],
Role: container.Labels["role"], // TODO: catch keyerror
Labels: container.Labels,
}
nodes = append(nodes, node)
}
return nodes, nil
}

@ -0,0 +1,2 @@
*.swp
*.out

@ -0,0 +1,13 @@
language: go
go:
- "1.10"
- "1.11"
- "1.12"
before_install:
- go get github.com/mattn/goveralls
- go get golang.org/x/tools/cover
script:
- $HOME/gopath/bin/goveralls -service=travis-ci

@ -0,0 +1,30 @@
# go-test/deep Changelog
## v1.0.4 released 2019-09-15
* Added \`deep:"-"\` structure field tag to ignore field (PR #38) (@flga)
## v1.0.3 released 2019-08-18
* Fixed issue #31: panic on typed primitives that implement error interface
## v1.0.2 released 2019-07-14
* Enabled Go module (@radeksimko)
* Changed supported and tested Go versions: 1.10, 1.11, and 1.12 (dropped 1.9)
* Changed Error equality: additional struct fields are compared too (PR #29) (@andrewmostello)
* Fixed typos and ineffassign issues (PR #25) (@tariq1890)
* Fixed diff order for nil comparison (PR #16) (@gmarik)
* Fixed slice equality when slices are extracted from the same array (PR #11) (@risteli)
* Fixed test spelling and messages (PR #19) (@sofuture)
* Fixed issue #15: panic on comparing struct with anonymous time.Time
* Fixed issue #18: Panic when comparing structs with time.Time value and CompareUnexportedFields is true
* Fixed issue #21: Set default MaxDepth = 0 (disabled) (PR #23)
## v1.0.1 released 2018-01-28
* Fixed issue #12: Arrays are not properly compared (@samlitowitz)
## v1.0.0 releaesd 2017-10-27
* First release

@ -0,0 +1,21 @@
MIT License
Copyright 2015-2017 Daniel Nichter
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.

@ -0,0 +1,51 @@
# Deep Variable Equality for Humans
[![Go Report Card](https://goreportcard.com/badge/github.com/go-test/deep)](https://goreportcard.com/report/github.com/go-test/deep) [![Build Status](https://travis-ci.org/go-test/deep.svg?branch=master)](https://travis-ci.org/go-test/deep) [![Coverage Status](https://coveralls.io/repos/github/go-test/deep/badge.svg?branch=master)](https://coveralls.io/github/go-test/deep?branch=master) [![GoDoc](https://godoc.org/github.com/go-test/deep?status.svg)](https://godoc.org/github.com/go-test/deep)
This package provides a single function: `deep.Equal`. It's like [reflect.DeepEqual](http://golang.org/pkg/reflect/#DeepEqual) but much friendlier to humans (or any sentient being) for two reason:
* `deep.Equal` returns a list of differences
* `deep.Equal` does not compare unexported fields (by default)
`reflect.DeepEqual` is good (like all things Golang!), but it's a game of [Hunt the Wumpus](https://en.wikipedia.org/wiki/Hunt_the_Wumpus). For large maps, slices, and structs, finding the difference is difficult.
`deep.Equal` doesn't play games with you, it lists the differences:
```go
package main_test
import (
"testing"
"github.com/go-test/deep"
)
type T struct {
Name string
Numbers []float64
}
func TestDeepEqual(t *testing.T) {
// Can you spot the difference?
t1 := T{
Name: "Isabella",
Numbers: []float64{1.13459, 2.29343, 3.010100010},
}
t2 := T{
Name: "Isabella",
Numbers: []float64{1.13459, 2.29843, 3.010100010},
}
if diff := deep.Equal(t1, t2); diff != nil {
t.Error(diff)
}
}
```
```
$ go test
--- FAIL: TestDeepEqual (0.00s)
main_test.go:25: [Numbers.slice[1]: 2.29343 != 2.29843]
```
The difference is in `Numbers.slice[1]`: the two values aren't equal using Go `==`.

@ -0,0 +1,376 @@
// Package deep provides function deep.Equal which is like reflect.DeepEqual but
// returns a list of differences. This is helpful when comparing complex types
// like structures and maps.
package deep
import (
"errors"
"fmt"
"log"
"reflect"
"strings"
)
var (
// FloatPrecision is the number of decimal places to round float values
// to when comparing.
FloatPrecision = 10
// MaxDiff specifies the maximum number of differences to return.
MaxDiff = 10
// MaxDepth specifies the maximum levels of a struct to recurse into,
// if greater than zero. If zero, there is no limit.
MaxDepth = 0
// LogErrors causes errors to be logged to STDERR when true.
LogErrors = false
// CompareUnexportedFields causes unexported struct fields, like s in
// T{s int}, to be compared when true.
CompareUnexportedFields = false
)
var (
// ErrMaxRecursion is logged when MaxDepth is reached.
ErrMaxRecursion = errors.New("recursed to MaxDepth")
// ErrTypeMismatch is logged when Equal passed two different types of values.
ErrTypeMismatch = errors.New("variables are different reflect.Type")
// ErrNotHandled is logged when a primitive Go kind is not handled.
ErrNotHandled = errors.New("cannot compare the reflect.Kind")
)
type cmp struct {
diff []string
buff []string
floatFormat string
}
var errorType = reflect.TypeOf((*error)(nil)).Elem()
// Equal compares variables a and b, recursing into their structure up to
// MaxDepth levels deep (if greater than zero), and returns a list of differences,
// or nil if there are none. Some differences may not be found if an error is
// also returned.
//
// If a type has an Equal method, like time.Equal, it is called to check for
// equality.
//
// When comparing a struct, if a field has the tag `deep:"-"` then it will be
// ignored.
func Equal(a, b interface{}) []string {
aVal := reflect.ValueOf(a)
bVal := reflect.ValueOf(b)
c := &cmp{
diff: []string{},
buff: []string{},
floatFormat: fmt.Sprintf("%%.%df", FloatPrecision),
}
if a == nil && b == nil {
return nil
} else if a == nil && b != nil {
c.saveDiff("<nil pointer>", b)
} else if a != nil && b == nil {
c.saveDiff(a, "<nil pointer>")
}
if len(c.diff) > 0 {
return c.diff
}
c.equals(aVal, bVal, 0)
if len(c.diff) > 0 {
return c.diff // diffs
}
return nil // no diffs
}
func (c *cmp) equals(a, b reflect.Value, level int) {
if MaxDepth > 0 && level > MaxDepth {
logError(ErrMaxRecursion)
return
}
// Check if one value is nil, e.g. T{x: *X} and T.x is nil
if !a.IsValid() || !b.IsValid() {
if a.IsValid() && !b.IsValid() {
c.saveDiff(a.Type(), "<nil pointer>")
} else if !a.IsValid() && b.IsValid() {
c.saveDiff("<nil pointer>", b.Type())
}
return
}
// If different types, they can't be equal
aType := a.Type()
bType := b.Type()
if aType != bType {
c.saveDiff(aType, bType)
logError(ErrTypeMismatch)
return
}
// Primitive https://golang.org/pkg/reflect/#Kind
aKind := a.Kind()
bKind := b.Kind()
// Do a and b have underlying elements? Yes if they're ptr or interface.
aElem := aKind == reflect.Ptr || aKind == reflect.Interface
bElem := bKind == reflect.Ptr || bKind == reflect.Interface
// If both types implement the error interface, compare the error strings.
// This must be done before dereferencing because the interface is on a
// pointer receiver. Re https://github.com/go-test/deep/issues/31, a/b might
// be primitive kinds; see TestErrorPrimitiveKind.
if aType.Implements(errorType) && bType.Implements(errorType) {
if (!aElem || !a.IsNil()) && (!bElem || !b.IsNil()) {
aString := a.MethodByName("Error").Call(nil)[0].String()
bString := b.MethodByName("Error").Call(nil)[0].String()
if aString != bString {
c.saveDiff(aString, bString)
return
}
}
}
// Dereference pointers and interface{}
if aElem || bElem {
if aElem {
a = a.Elem()
}
if bElem {
b = b.Elem()
}
c.equals(a, b, level+1)
return
}
switch aKind {
/////////////////////////////////////////////////////////////////////
// Iterable kinds
/////////////////////////////////////////////////////////////////////
case reflect.Struct:
/*
The variables are structs like:
type T struct {
FirstName string
LastName string
}
Type = <pkg>.T, Kind = reflect.Struct
Iterate through the fields (FirstName, LastName), recurse into their values.
*/
// Types with an Equal() method, like time.Time, only if struct field
// is exported (CanInterface)
if eqFunc := a.MethodByName("Equal"); eqFunc.IsValid() && eqFunc.CanInterface() {
// Handle https://github.com/go-test/deep/issues/15:
// Don't call T.Equal if the method is from an embedded struct, like:
// type Foo struct { time.Time }
// First, we'll encounter Equal(Ttime, time.Time) but if we pass b
// as the 2nd arg we'll panic: "Call using pkg.Foo as type time.Time"
// As far as I can tell, there's no way to see that the method is from
// time.Time not Foo. So we check the type of the 1st (0) arg and skip
// unless it's b type. Later, we'll encounter the time.Time anonymous/
// embedded field and then we'll have Equal(time.Time, time.Time).
funcType := eqFunc.Type()
if funcType.NumIn() == 1 && funcType.In(0) == bType {
retVals := eqFunc.Call([]reflect.Value{b})
if !retVals[0].Bool() {
c.saveDiff(a, b)
}
return
}
}
for i := 0; i < a.NumField(); i++ {
if aType.Field(i).PkgPath != "" && !CompareUnexportedFields {
continue // skip unexported field, e.g. s in type T struct {s string}
}
if aType.Field(i).Tag.Get("deep") == "-" {
continue // field wants to be ignored
}
c.push(aType.Field(i).Name) // push field name to buff
// Get the Value for each field, e.g. FirstName has Type = string,
// Kind = reflect.String.
af := a.Field(i)
bf := b.Field(i)
// Recurse to compare the field values
c.equals(af, bf, level+1)
c.pop() // pop field name from buff
if len(c.diff) >= MaxDiff {
break
}
}
case reflect.Map:
/*
The variables are maps like:
map[string]int{
"foo": 1,
"bar": 2,
}
Type = map[string]int, Kind = reflect.Map
Or:
type T map[string]int{}
Type = <pkg>.T, Kind = reflect.Map
Iterate through the map keys (foo, bar), recurse into their values.
*/
if a.IsNil() || b.IsNil() {
if a.IsNil() && !b.IsNil() {
c.saveDiff("<nil map>", b)
} else if !a.IsNil() && b.IsNil() {
c.saveDiff(a, "<nil map>")
}
return
}
if a.Pointer() == b.Pointer() {
return
}
for _, key := range a.MapKeys() {
c.push(fmt.Sprintf("map[%s]", key))
aVal := a.MapIndex(key)
bVal := b.MapIndex(key)
if bVal.IsValid() {
c.equals(aVal, bVal, level+1)
} else {
c.saveDiff(aVal, "<does not have key>")
}
c.pop()
if len(c.diff) >= MaxDiff {
return
}
}
for _, key := range b.MapKeys() {
if aVal := a.MapIndex(key); aVal.IsValid() {
continue
}
c.push(fmt.Sprintf("map[%s]", key))
c.saveDiff("<does not have key>", b.MapIndex(key))
c.pop()
if len(c.diff) >= MaxDiff {
return
}
}
case reflect.Array:
n := a.Len()
for i := 0; i < n; i++ {
c.push(fmt.Sprintf("array[%d]", i))
c.equals(a.Index(i), b.Index(i), level+1)
c.pop()
if len(c.diff) >= MaxDiff {
break
}
}
case reflect.Slice:
if a.IsNil() || b.IsNil() {
if a.IsNil() && !b.IsNil() {
c.saveDiff("<nil slice>", b)
} else if !a.IsNil() && b.IsNil() {
c.saveDiff(a, "<nil slice>")
}
return
}
aLen := a.Len()
bLen := b.Len()
if a.Pointer() == b.Pointer() && aLen == bLen {
return
}
n := aLen
if bLen > aLen {
n = bLen
}
for i := 0; i < n; i++ {
c.push(fmt.Sprintf("slice[%d]", i))
if i < aLen && i < bLen {
c.equals(a.Index(i), b.Index(i), level+1)
} else if i < aLen {
c.saveDiff(a.Index(i), "<no value>")
} else {
c.saveDiff("<no value>", b.Index(i))
}
c.pop()
if len(c.diff) >= MaxDiff {
break
}
}
/////////////////////////////////////////////////////////////////////
// Primitive kinds
/////////////////////////////////////////////////////////////////////
case reflect.Float32, reflect.Float64:
// Avoid 0.04147685731961082 != 0.041476857319611
// 6 decimal places is close enough
aval := fmt.Sprintf(c.floatFormat, a.Float())
bval := fmt.Sprintf(c.floatFormat, b.Float())
if aval != bval {
c.saveDiff(a.Float(), b.Float())
}
case reflect.Bool:
if a.Bool() != b.Bool() {
c.saveDiff(a.Bool(), b.Bool())
}
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
if a.Int() != b.Int() {
c.saveDiff(a.Int(), b.Int())
}
case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
if a.Uint() != b.Uint() {
c.saveDiff(a.Uint(), b.Uint())
}
case reflect.String:
if a.String() != b.String() {
c.saveDiff(a.String(), b.String())
}
default:
logError(ErrNotHandled)
}
}
func (c *cmp) push(name string) {
c.buff = append(c.buff, name)
}
func (c *cmp) pop() {
if len(c.buff) > 0 {
c.buff = c.buff[0 : len(c.buff)-1]
}
}
func (c *cmp) saveDiff(aval, bval interface{}) {
if len(c.buff) > 0 {
varName := strings.Join(c.buff, ".")
c.diff = append(c.diff, fmt.Sprintf("%s: %v != %v", varName, aval, bval))
} else {
c.diff = append(c.diff, fmt.Sprintf("%v != %v", aval, bval))
}
}
func logError(err error) {
if LogErrors {
log.Println(err)
}
}

@ -0,0 +1 @@
module github.com/go-test/deep

@ -109,6 +109,8 @@ github.com/docker/go-connections/tlsconfig
github.com/docker/go-events
# github.com/docker/go-units v0.4.0
github.com/docker/go-units
# github.com/go-test/deep v1.0.4
github.com/go-test/deep
# github.com/gogo/googleapis v1.3.0
github.com/gogo/googleapis/google/rpc
# github.com/gogo/protobuf v1.3.0

Loading…
Cancel
Save