mirror of
https://github.com/k3s-io/kubernetes.git
synced 2025-07-21 19:01:49 +00:00
Merge pull request #4943 from vmarmol/image-manager
Implementing ImageManager to take over image lifecycle.
This commit is contained in:
commit
3835e0e6e6
6
Godeps/Godeps.json
generated
6
Godeps/Godeps.json
generated
@ -1,6 +1,6 @@
|
||||
{
|
||||
"ImportPath": "github.com/GoogleCloudPlatform/kubernetes",
|
||||
"GoVersion": "go1.4",
|
||||
"GoVersion": "go1.4.1",
|
||||
"Packages": [
|
||||
"./..."
|
||||
],
|
||||
@ -271,6 +271,10 @@
|
||||
"ImportPath": "github.com/stretchr/testify/mock",
|
||||
"Rev": "e4ec8152c15fc46bd5056ce65997a07c7d415325"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/stretchr/testify/require",
|
||||
"Rev": "e4ec8152c15fc46bd5056ce65997a07c7d415325"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/vaughan0/go-ini",
|
||||
"Rev": "a98ad7ee00ec53921f08832bc06ecf7fd600e6a1"
|
||||
|
77
Godeps/_workspace/src/github.com/stretchr/testify/require/doc.go
generated
vendored
Normal file
77
Godeps/_workspace/src/github.com/stretchr/testify/require/doc.go
generated
vendored
Normal file
@ -0,0 +1,77 @@
|
||||
// Alternative testing tools which stop test execution if test failed.
|
||||
//
|
||||
// Example Usage
|
||||
//
|
||||
// The following is a complete example using require in a standard test function:
|
||||
// import (
|
||||
// "testing"
|
||||
// "github.com/stretchr/testify/require"
|
||||
// )
|
||||
//
|
||||
// func TestSomething(t *testing.T) {
|
||||
//
|
||||
// var a string = "Hello"
|
||||
// var b string = "Hello"
|
||||
//
|
||||
// require.Equal(t, a, b, "The two words should be the same.")
|
||||
//
|
||||
// }
|
||||
//
|
||||
// Assertions
|
||||
//
|
||||
// The `require` package have same global functions as in the `assert` package,
|
||||
// but instead of returning a boolean result they call `t.FailNow()`.
|
||||
//
|
||||
// Every assertion function also takes an optional string message as the final argument,
|
||||
// allowing custom error messages to be appended to the message the assertion method outputs.
|
||||
//
|
||||
// Here is an overview of the assert functions:
|
||||
//
|
||||
// require.Equal(t, expected, actual [, message [, format-args])
|
||||
//
|
||||
// require.NotEqual(t, notExpected, actual [, message [, format-args]])
|
||||
//
|
||||
// require.True(t, actualBool [, message [, format-args]])
|
||||
//
|
||||
// require.False(t, actualBool [, message [, format-args]])
|
||||
//
|
||||
// require.Nil(t, actualObject [, message [, format-args]])
|
||||
//
|
||||
// require.NotNil(t, actualObject [, message [, format-args]])
|
||||
//
|
||||
// require.Empty(t, actualObject [, message [, format-args]])
|
||||
//
|
||||
// require.NotEmpty(t, actualObject [, message [, format-args]])
|
||||
//
|
||||
// require.Error(t, errorObject [, message [, format-args]])
|
||||
//
|
||||
// require.NoError(t, errorObject [, message [, format-args]])
|
||||
//
|
||||
// require.EqualError(t, theError, errString [, message [, format-args]])
|
||||
//
|
||||
// require.Implements(t, (*MyInterface)(nil), new(MyObject) [,message [, format-args]])
|
||||
//
|
||||
// require.IsType(t, expectedObject, actualObject [, message [, format-args]])
|
||||
//
|
||||
// require.Contains(t, string, substring [, message [, format-args]])
|
||||
//
|
||||
// require.NotContains(t, string, substring [, message [, format-args]])
|
||||
//
|
||||
// require.Panics(t, func(){
|
||||
//
|
||||
// // call code that should panic
|
||||
//
|
||||
// } [, message [, format-args]])
|
||||
//
|
||||
// require.NotPanics(t, func(){
|
||||
//
|
||||
// // call code that should not panic
|
||||
//
|
||||
// } [, message [, format-args]])
|
||||
//
|
||||
// require.WithinDuration(t, timeA, timeB, deltaTime, [, message [, format-args]])
|
||||
//
|
||||
// require.InDelta(t, numA, numB, delta, [, message [, format-args]])
|
||||
//
|
||||
// require.InEpsilon(t, numA, numB, epsilon, [, message [, format-args]])
|
||||
package require
|
211
Godeps/_workspace/src/github.com/stretchr/testify/require/forward_requirements.go
generated
vendored
Normal file
211
Godeps/_workspace/src/github.com/stretchr/testify/require/forward_requirements.go
generated
vendored
Normal file
@ -0,0 +1,211 @@
|
||||
package require
|
||||
|
||||
import (
|
||||
"time"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
type Assertions struct {
|
||||
t TestingT
|
||||
}
|
||||
|
||||
func New(t TestingT) *Assertions {
|
||||
return &Assertions{
|
||||
t: t,
|
||||
}
|
||||
}
|
||||
|
||||
// Fail reports a failure through
|
||||
func (a *Assertions) Fail(failureMessage string, msgAndArgs ...interface{}) {
|
||||
FailNow(a.t, failureMessage, msgAndArgs...)
|
||||
}
|
||||
|
||||
// Implements asserts that an object is implemented by the specified interface.
|
||||
|
||||
func (a *Assertions) Implements(interfaceObject interface{}, object interface{}, msgAndArgs ...interface{}) {
|
||||
Implements(a.t, interfaceObject, object, msgAndArgs...)
|
||||
}
|
||||
|
||||
// IsType asserts that the specified objects are of the same type.
|
||||
func (a *Assertions) IsType(expectedType interface{}, object interface{}, msgAndArgs ...interface{}) {
|
||||
IsType(a.t, expectedType, object, msgAndArgs...)
|
||||
}
|
||||
|
||||
// Equal asserts that two objects are equal.
|
||||
//
|
||||
// require.Equal(123, 123, "123 and 123 should be equal")
|
||||
func (a *Assertions) Equal(expected, actual interface{}, msgAndArgs ...interface{}) {
|
||||
Equal(a.t, expected, actual, msgAndArgs...)
|
||||
}
|
||||
|
||||
// Exactly asserts that two objects are equal is value and type.
|
||||
//
|
||||
// require.Exactly(int32(123), int64(123), "123 and 123 should NOT be equal")
|
||||
func (a *Assertions) Exactly(expected, actual interface{}, msgAndArgs ...interface{}) {
|
||||
Exactly(a.t, expected, actual, msgAndArgs...)
|
||||
}
|
||||
|
||||
// NotNil asserts that the specified object is not nil.
|
||||
//
|
||||
// require.NotNil(err, "err should be something")
|
||||
func (a *Assertions) NotNil(object interface{}, msgAndArgs ...interface{}) {
|
||||
NotNil(a.t, object, msgAndArgs...)
|
||||
}
|
||||
|
||||
// Nil asserts that the specified object is nil.
|
||||
//
|
||||
// require.Nil(err, "err should be nothing")
|
||||
func (a *Assertions) Nil(object interface{}, msgAndArgs ...interface{}) {
|
||||
Nil(a.t, object, msgAndArgs...)
|
||||
}
|
||||
|
||||
// Empty asserts that the specified object is empty. I.e. nil, "", false, 0 or a
|
||||
// slice with len == 0.
|
||||
//
|
||||
// require.Empty(obj)
|
||||
func (a *Assertions) Empty(object interface{}, msgAndArgs ...interface{}) {
|
||||
Empty(a.t, object, msgAndArgs...)
|
||||
}
|
||||
|
||||
// Empty asserts that the specified object is NOT empty. I.e. not nil, "", false, 0 or a
|
||||
// slice with len == 0.
|
||||
//
|
||||
// if require.NotEmpty(obj) {
|
||||
// require.Equal("two", obj[1])
|
||||
// }
|
||||
func (a *Assertions) NotEmpty(object interface{}, msgAndArgs ...interface{}) {
|
||||
NotEmpty(a.t, object, msgAndArgs...)
|
||||
}
|
||||
|
||||
// Len asserts that the specified object has specific length.
|
||||
// Len also fails if the object has a type that len() not accept.
|
||||
//
|
||||
// require.Len(mySlice, 3, "The size of slice is not 3")
|
||||
func (a *Assertions) Len(object interface{}, length int, msgAndArgs ...interface{}) {
|
||||
Len(a.t, object, length, msgAndArgs...)
|
||||
}
|
||||
|
||||
// True asserts that the specified value is true.
|
||||
//
|
||||
// require.True(myBool, "myBool should be true")
|
||||
func (a *Assertions) True(value bool, msgAndArgs ...interface{}) {
|
||||
True(a.t, value, msgAndArgs...)
|
||||
}
|
||||
|
||||
// False asserts that the specified value is true.
|
||||
//
|
||||
// require.False(myBool, "myBool should be false")
|
||||
func (a *Assertions) False(value bool, msgAndArgs ...interface{}) {
|
||||
False(a.t, value, msgAndArgs...)
|
||||
}
|
||||
|
||||
// NotEqual asserts that the specified values are NOT equal.
|
||||
//
|
||||
// require.NotEqual(obj1, obj2, "two objects shouldn't be equal")
|
||||
func (a *Assertions) NotEqual(expected, actual interface{}, msgAndArgs ...interface{}) {
|
||||
NotEqual(a.t, expected, actual, msgAndArgs...)
|
||||
}
|
||||
|
||||
// Contains asserts that the specified string contains the specified substring.
|
||||
//
|
||||
// require.Contains("Hello World", "World", "But 'Hello World' does contain 'World'")
|
||||
func (a *Assertions) Contains(s, contains interface{}, msgAndArgs ...interface{}) {
|
||||
Contains(a.t, s, contains, msgAndArgs...)
|
||||
}
|
||||
|
||||
// NotContains asserts that the specified string does NOT contain the specified substring.
|
||||
//
|
||||
// require.NotContains("Hello World", "Earth", "But 'Hello World' does NOT contain 'Earth'")
|
||||
func (a *Assertions) NotContains(s, contains interface{}, msgAndArgs ...interface{}) {
|
||||
NotContains(a.t, s, contains, msgAndArgs...)
|
||||
}
|
||||
|
||||
// Uses a Comparison to assert a complex condition.
|
||||
func (a *Assertions) Condition(comp assert.Comparison, msgAndArgs ...interface{}) {
|
||||
Condition(a.t, comp, msgAndArgs...)
|
||||
}
|
||||
|
||||
// Panics asserts that the code inside the specified PanicTestFunc panics.
|
||||
//
|
||||
// require.Panics(func(){
|
||||
// GoCrazy()
|
||||
// }, "Calling GoCrazy() should panic")
|
||||
func (a *Assertions) Panics(f assert.PanicTestFunc, msgAndArgs ...interface{}) {
|
||||
Panics(a.t, f, msgAndArgs...)
|
||||
}
|
||||
|
||||
// NotPanics asserts that the code inside the specified PanicTestFunc does NOT panic.
|
||||
//
|
||||
// require.NotPanics(func(){
|
||||
// RemainCalm()
|
||||
// }, "Calling RemainCalm() should NOT panic")
|
||||
func (a *Assertions) NotPanics(f assert.PanicTestFunc, msgAndArgs ...interface{}) {
|
||||
NotPanics(a.t, f, msgAndArgs...)
|
||||
}
|
||||
|
||||
// WithinDuration asserts that the two times are within duration delta of each other.
|
||||
//
|
||||
// require.WithinDuration(time.Now(), time.Now(), 10*time.Second, "The difference should not be more than 10s")
|
||||
func (a *Assertions) WithinDuration(expected, actual time.Time, delta time.Duration, msgAndArgs ...interface{}) {
|
||||
WithinDuration(a.t, expected, actual, delta, msgAndArgs...)
|
||||
}
|
||||
|
||||
// InDelta asserts that the two numerals are within delta of each other.
|
||||
//
|
||||
// require.InDelta(t, math.Pi, (22 / 7.0), 0.01)
|
||||
func (a *Assertions) InDelta(expected, actual interface{}, delta float64, msgAndArgs ...interface{}) {
|
||||
InDelta(a.t, expected, actual, delta, msgAndArgs...)
|
||||
}
|
||||
|
||||
// InEpsilon asserts that expected and actual have a relative error less than epsilon
|
||||
func (a *Assertions) InEpsilon(expected, actual interface{}, epsilon float64, msgAndArgs ...interface{}) {
|
||||
InEpsilon(a.t, expected, actual, epsilon, msgAndArgs...)
|
||||
}
|
||||
|
||||
// NoError asserts that a function returned no error (i.e. `nil`).
|
||||
//
|
||||
// actualObj, err := SomeFunction()
|
||||
// if require.NoError(err) {
|
||||
// require.Equal(actualObj, expectedObj)
|
||||
// }
|
||||
func (a *Assertions) NoError(theError error, msgAndArgs ...interface{}) {
|
||||
NoError(a.t, theError, msgAndArgs...)
|
||||
}
|
||||
|
||||
// Error asserts that a function returned an error (i.e. not `nil`).
|
||||
//
|
||||
// actualObj, err := SomeFunction()
|
||||
// if require.Error(err, "An error was expected") {
|
||||
// require.Equal(err, expectedError)
|
||||
// }
|
||||
func (a *Assertions) Error(theError error, msgAndArgs ...interface{}) {
|
||||
Error(a.t, theError, msgAndArgs...)
|
||||
}
|
||||
|
||||
// EqualError asserts that a function returned an error (i.e. not `nil`)
|
||||
// and that it is equal to the provided error.
|
||||
//
|
||||
// actualObj, err := SomeFunction()
|
||||
// if require.Error(err, "An error was expected") {
|
||||
// require.Equal(err, expectedError)
|
||||
// }
|
||||
func (a *Assertions) EqualError(theError error, errString string, msgAndArgs ...interface{}) {
|
||||
EqualError(a.t, theError, errString, msgAndArgs...)
|
||||
}
|
||||
|
||||
// Regexp asserts that a specified regexp matches a string.
|
||||
//
|
||||
// require.Regexp(t, regexp.MustCompile("start"), "it's starting")
|
||||
// require.Regexp(t, "start...$", "it's not starting")
|
||||
func (a *Assertions) Regexp(rx interface{}, str interface{}, msgAndArgs ...interface{}) {
|
||||
Regexp(a.t, rx, str, msgAndArgs...)
|
||||
}
|
||||
|
||||
// NotRegexp asserts that a specified regexp does not match a string.
|
||||
//
|
||||
// require.NotRegexp(t, regexp.MustCompile("starts"), "it's starting")
|
||||
// require.NotRegexp(t, "^start", "it's not starting")
|
||||
func (a *Assertions) NotRegexp(rx interface{}, str interface{}, msgAndArgs ...interface{}) {
|
||||
NotRegexp(a.t, rx, str, msgAndArgs...)
|
||||
}
|
260
Godeps/_workspace/src/github.com/stretchr/testify/require/forward_requirements_test.go
generated
vendored
Normal file
260
Godeps/_workspace/src/github.com/stretchr/testify/require/forward_requirements_test.go
generated
vendored
Normal file
@ -0,0 +1,260 @@
|
||||
package require
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"testing"
|
||||
"time"
|
||||
)
|
||||
|
||||
func TestImplementsWrapper(t *testing.T) {
|
||||
require := New(t)
|
||||
|
||||
require.Implements((*AssertionTesterInterface)(nil), new(AssertionTesterConformingObject))
|
||||
|
||||
mockT := new(MockT)
|
||||
mockRequire := New(mockT)
|
||||
mockRequire.Implements((*AssertionTesterInterface)(nil), new(AssertionTesterNonConformingObject))
|
||||
if !mockT.Failed {
|
||||
t.Error("Check should fail")
|
||||
}
|
||||
}
|
||||
|
||||
func TestIsTypeWrapper(t *testing.T) {
|
||||
require := New(t)
|
||||
require.IsType(new(AssertionTesterConformingObject), new(AssertionTesterConformingObject))
|
||||
|
||||
mockT := new(MockT)
|
||||
mockRequire := New(mockT)
|
||||
mockRequire.IsType(new(AssertionTesterConformingObject), new(AssertionTesterNonConformingObject))
|
||||
if !mockT.Failed {
|
||||
t.Error("Check should fail")
|
||||
}
|
||||
}
|
||||
|
||||
func TestEqualWrapper(t *testing.T) {
|
||||
require := New(t)
|
||||
require.Equal(1, 1)
|
||||
|
||||
mockT := new(MockT)
|
||||
mockRequire := New(mockT)
|
||||
mockRequire.Equal(1, 2)
|
||||
if !mockT.Failed {
|
||||
t.Error("Check should fail")
|
||||
}
|
||||
}
|
||||
|
||||
func TestNotEqualWrapper(t *testing.T) {
|
||||
require := New(t)
|
||||
require.NotEqual(1, 2)
|
||||
|
||||
mockT := new(MockT)
|
||||
mockRequire := New(mockT)
|
||||
mockRequire.NotEqual(2, 2)
|
||||
if !mockT.Failed {
|
||||
t.Error("Check should fail")
|
||||
}
|
||||
}
|
||||
|
||||
func TestExactlyWrapper(t *testing.T) {
|
||||
require := New(t)
|
||||
|
||||
a := float32(1)
|
||||
b := float32(1)
|
||||
c := float64(1)
|
||||
|
||||
require.Exactly(a, b)
|
||||
|
||||
mockT := new(MockT)
|
||||
mockRequire := New(mockT)
|
||||
mockRequire.Exactly(a, c)
|
||||
if !mockT.Failed {
|
||||
t.Error("Check should fail")
|
||||
}
|
||||
}
|
||||
|
||||
func TestNotNilWrapper(t *testing.T) {
|
||||
require := New(t)
|
||||
require.NotNil(t, new(AssertionTesterConformingObject))
|
||||
|
||||
mockT := new(MockT)
|
||||
mockRequire := New(mockT)
|
||||
mockRequire.NotNil(nil)
|
||||
if !mockT.Failed {
|
||||
t.Error("Check should fail")
|
||||
}
|
||||
}
|
||||
|
||||
func TestNilWrapper(t *testing.T) {
|
||||
require := New(t)
|
||||
require.Nil(nil)
|
||||
|
||||
mockT := new(MockT)
|
||||
mockRequire := New(mockT)
|
||||
mockRequire.Nil(new(AssertionTesterConformingObject))
|
||||
if !mockT.Failed {
|
||||
t.Error("Check should fail")
|
||||
}
|
||||
}
|
||||
|
||||
func TestTrueWrapper(t *testing.T) {
|
||||
require := New(t)
|
||||
require.True(true)
|
||||
|
||||
mockT := new(MockT)
|
||||
mockRequire := New(mockT)
|
||||
mockRequire.True(false)
|
||||
if !mockT.Failed {
|
||||
t.Error("Check should fail")
|
||||
}
|
||||
}
|
||||
|
||||
func TestFalseWrapper(t *testing.T) {
|
||||
require := New(t)
|
||||
require.False(false)
|
||||
|
||||
mockT := new(MockT)
|
||||
mockRequire := New(mockT)
|
||||
mockRequire.False(true)
|
||||
if !mockT.Failed {
|
||||
t.Error("Check should fail")
|
||||
}
|
||||
}
|
||||
|
||||
func TestContainsWrapper(t *testing.T) {
|
||||
require := New(t)
|
||||
require.Contains("Hello World", "Hello")
|
||||
|
||||
mockT := new(MockT)
|
||||
mockRequire := New(mockT)
|
||||
mockRequire.Contains("Hello World", "Salut")
|
||||
if !mockT.Failed {
|
||||
t.Error("Check should fail")
|
||||
}
|
||||
}
|
||||
|
||||
func TestNotContainsWrapper(t *testing.T) {
|
||||
require := New(t)
|
||||
require.NotContains("Hello World", "Hello!")
|
||||
|
||||
mockT := new(MockT)
|
||||
mockRequire := New(mockT)
|
||||
mockRequire.NotContains("Hello World", "Hello")
|
||||
if !mockT.Failed {
|
||||
t.Error("Check should fail")
|
||||
}
|
||||
}
|
||||
|
||||
func TestPanicsWrapper(t *testing.T) {
|
||||
require := New(t)
|
||||
require.Panics(func() {
|
||||
panic("Panic!")
|
||||
})
|
||||
|
||||
mockT := new(MockT)
|
||||
mockRequire := New(mockT)
|
||||
mockRequire.Panics(func() {})
|
||||
if !mockT.Failed {
|
||||
t.Error("Check should fail")
|
||||
}
|
||||
}
|
||||
|
||||
func TestNotPanicsWrapper(t *testing.T) {
|
||||
require := New(t)
|
||||
require.NotPanics(func() {})
|
||||
|
||||
mockT := new(MockT)
|
||||
mockRequire := New(mockT)
|
||||
mockRequire.NotPanics(func() {
|
||||
panic("Panic!")
|
||||
})
|
||||
if !mockT.Failed {
|
||||
t.Error("Check should fail")
|
||||
}
|
||||
}
|
||||
|
||||
func TestNoErrorWrapper(t *testing.T) {
|
||||
require := New(t)
|
||||
require.NoError(nil)
|
||||
|
||||
mockT := new(MockT)
|
||||
mockRequire := New(mockT)
|
||||
mockRequire.NoError(errors.New("some error"))
|
||||
if !mockT.Failed {
|
||||
t.Error("Check should fail")
|
||||
}
|
||||
}
|
||||
|
||||
func TestErrorWrapper(t *testing.T) {
|
||||
require := New(t)
|
||||
require.Error(errors.New("some error"))
|
||||
|
||||
mockT := new(MockT)
|
||||
mockRequire := New(mockT)
|
||||
mockRequire.Error(nil)
|
||||
if !mockT.Failed {
|
||||
t.Error("Check should fail")
|
||||
}
|
||||
}
|
||||
|
||||
func TestEqualErrorWrapper(t *testing.T) {
|
||||
require := New(t)
|
||||
require.EqualError(errors.New("some error"), "some error")
|
||||
|
||||
mockT := new(MockT)
|
||||
mockRequire := New(mockT)
|
||||
mockRequire.EqualError(errors.New("some error"), "Not some error")
|
||||
if !mockT.Failed {
|
||||
t.Error("Check should fail")
|
||||
}
|
||||
}
|
||||
|
||||
func TestEmptyWrapper(t *testing.T) {
|
||||
require := New(t)
|
||||
require.Empty("")
|
||||
|
||||
mockT := new(MockT)
|
||||
mockRequire := New(mockT)
|
||||
mockRequire.Empty("x")
|
||||
if !mockT.Failed {
|
||||
t.Error("Check should fail")
|
||||
}
|
||||
}
|
||||
|
||||
func TestNotEmptyWrapper(t *testing.T) {
|
||||
require := New(t)
|
||||
require.NotEmpty("x")
|
||||
|
||||
mockT := new(MockT)
|
||||
mockRequire := New(mockT)
|
||||
mockRequire.NotEmpty("")
|
||||
if !mockT.Failed {
|
||||
t.Error("Check should fail")
|
||||
}
|
||||
}
|
||||
|
||||
func TestWithinDurationWrapper(t *testing.T) {
|
||||
require := New(t)
|
||||
a := time.Now()
|
||||
b := a.Add(10 * time.Second)
|
||||
|
||||
require.WithinDuration(a, b, 15*time.Second)
|
||||
|
||||
mockT := new(MockT)
|
||||
mockRequire := New(mockT)
|
||||
mockRequire.WithinDuration(a, b, 5*time.Second)
|
||||
if !mockT.Failed {
|
||||
t.Error("Check should fail")
|
||||
}
|
||||
}
|
||||
|
||||
func TestInDeltaWrapper(t *testing.T) {
|
||||
require := New(t)
|
||||
require.InDelta(1.001, 1, 0.01)
|
||||
|
||||
mockT := new(MockT)
|
||||
mockRequire := New(mockT)
|
||||
mockRequire.InDelta(1, 2, 0.5)
|
||||
if !mockT.Failed {
|
||||
t.Error("Check should fail")
|
||||
}
|
||||
}
|
271
Godeps/_workspace/src/github.com/stretchr/testify/require/requirements.go
generated
vendored
Normal file
271
Godeps/_workspace/src/github.com/stretchr/testify/require/requirements.go
generated
vendored
Normal file
@ -0,0 +1,271 @@
|
||||
package require
|
||||
|
||||
import (
|
||||
"time"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
type TestingT interface {
|
||||
Errorf(format string, args ...interface{})
|
||||
FailNow()
|
||||
}
|
||||
|
||||
// Fail reports a failure through
|
||||
func FailNow(t TestingT, failureMessage string, msgAndArgs ...interface{}) {
|
||||
assert.Fail(t, failureMessage, msgAndArgs...)
|
||||
t.FailNow()
|
||||
}
|
||||
|
||||
// Implements asserts that an object is implemented by the specified interface.
|
||||
//
|
||||
// require.Implements(t, (*MyInterface)(nil), new(MyObject), "MyObject")
|
||||
func Implements(t TestingT, interfaceObject interface{}, object interface{}, msgAndArgs ...interface{}) {
|
||||
if !assert.Implements(t, interfaceObject, object, msgAndArgs...) {
|
||||
t.FailNow()
|
||||
}
|
||||
}
|
||||
|
||||
// IsType asserts that the specified objects are of the same type.
|
||||
func IsType(t TestingT, expectedType interface{}, object interface{}, msgAndArgs ...interface{}) {
|
||||
if !assert.IsType(t, expectedType, object, msgAndArgs...) {
|
||||
t.FailNow()
|
||||
}
|
||||
}
|
||||
|
||||
// Equal asserts that two objects are equal.
|
||||
//
|
||||
// require.Equal(t, 123, 123, "123 and 123 should be equal")
|
||||
func Equal(t TestingT, expected, actual interface{}, msgAndArgs ...interface{}) {
|
||||
if !assert.Equal(t, expected, actual, msgAndArgs...) {
|
||||
t.FailNow()
|
||||
}
|
||||
}
|
||||
|
||||
// EqualValues asserts that two objects are equal or convertable to each other.
|
||||
//
|
||||
// require.EqualValues(t, uint32(123), int32(123), "123 and 123 should be equal")
|
||||
func EqualValues(t TestingT, expected, actual interface{}, msgAndArgs ...interface{}) {
|
||||
if !assert.EqualValues(t, expected, actual, msgAndArgs...) {
|
||||
t.FailNow()
|
||||
}
|
||||
}
|
||||
|
||||
// Exactly asserts that two objects are equal is value and type.
|
||||
//
|
||||
// require.Exactly(t, int32(123), int64(123), "123 and 123 should NOT be equal")
|
||||
func Exactly(t TestingT, expected, actual interface{}, msgAndArgs ...interface{}) {
|
||||
if !assert.Exactly(t, expected, actual, msgAndArgs...) {
|
||||
t.FailNow()
|
||||
}
|
||||
}
|
||||
|
||||
// NotNil asserts that the specified object is not nil.
|
||||
//
|
||||
// require.NotNil(t, err, "err should be something")
|
||||
func NotNil(t TestingT, object interface{}, msgAndArgs ...interface{}) {
|
||||
if !assert.NotNil(t, object, msgAndArgs...) {
|
||||
t.FailNow()
|
||||
}
|
||||
}
|
||||
|
||||
// Nil asserts that the specified object is nil.
|
||||
//
|
||||
// require.Nil(t, err, "err should be nothing")
|
||||
func Nil(t TestingT, object interface{}, msgAndArgs ...interface{}) {
|
||||
if !assert.Nil(t, object, msgAndArgs...) {
|
||||
t.FailNow()
|
||||
}
|
||||
}
|
||||
|
||||
// Empty asserts that the specified object is empty. I.e. nil, "", false, 0 or either
|
||||
// a slice or a channel with len == 0.
|
||||
//
|
||||
// require.Empty(t, obj)
|
||||
func Empty(t TestingT, object interface{}, msgAndArgs ...interface{}) {
|
||||
if !assert.Empty(t, object, msgAndArgs...) {
|
||||
t.FailNow()
|
||||
}
|
||||
}
|
||||
|
||||
// NotEmpty asserts that the specified object is NOT empty. I.e. not nil, "", false, 0 or either
|
||||
// a slice or a channel with len == 0.
|
||||
//
|
||||
// require.NotEmpty(t, obj)
|
||||
// require.Equal(t, "one", obj[0])
|
||||
func NotEmpty(t TestingT, object interface{}, msgAndArgs ...interface{}) {
|
||||
if !assert.NotEmpty(t, object, msgAndArgs...) {
|
||||
t.FailNow()
|
||||
}
|
||||
}
|
||||
|
||||
// Len asserts that the specified object has specific length.
|
||||
// Len also fails if the object has a type that len() not accept.
|
||||
//
|
||||
// require.Len(t, mySlice, 3, "The size of slice is not 3")
|
||||
func Len(t TestingT, object interface{}, length int, msgAndArgs ...interface{}) {
|
||||
if !assert.Len(t, object, length, msgAndArgs...) {
|
||||
t.FailNow()
|
||||
}
|
||||
}
|
||||
|
||||
// True asserts that the specified value is true.
|
||||
//
|
||||
// require.True(t, myBool, "myBool should be true")
|
||||
func True(t TestingT, value bool, msgAndArgs ...interface{}) {
|
||||
if !assert.True(t, value, msgAndArgs...) {
|
||||
t.FailNow()
|
||||
}
|
||||
}
|
||||
|
||||
// False asserts that the specified value is true.
|
||||
//
|
||||
// require.False(t, myBool, "myBool should be false")
|
||||
func False(t TestingT, value bool, msgAndArgs ...interface{}) {
|
||||
if !assert.False(t, value, msgAndArgs...) {
|
||||
t.FailNow()
|
||||
}
|
||||
}
|
||||
|
||||
// NotEqual asserts that the specified values are NOT equal.
|
||||
//
|
||||
// require.NotEqual(t, obj1, obj2, "two objects shouldn't be equal")
|
||||
func NotEqual(t TestingT, expected, actual interface{}, msgAndArgs ...interface{}) {
|
||||
if !assert.NotEqual(t, expected, actual, msgAndArgs...) {
|
||||
t.FailNow()
|
||||
}
|
||||
}
|
||||
|
||||
// Contains asserts that the specified string contains the specified substring.
|
||||
//
|
||||
// require.Contains(t, "Hello World", "World", "But 'Hello World' does contain 'World'")
|
||||
func Contains(t TestingT, s, contains interface{}, msgAndArgs ...interface{}) {
|
||||
if !assert.Contains(t, s, contains, msgAndArgs...) {
|
||||
t.FailNow()
|
||||
}
|
||||
}
|
||||
|
||||
// NotContains asserts that the specified string does NOT contain the specified substring.
|
||||
//
|
||||
// require.NotContains(t, "Hello World", "Earth", "But 'Hello World' does NOT contain 'Earth'")
|
||||
func NotContains(t TestingT, s, contains interface{}, msgAndArgs ...interface{}) {
|
||||
if !assert.NotContains(t, s, contains, msgAndArgs...) {
|
||||
t.FailNow()
|
||||
}
|
||||
}
|
||||
|
||||
// Condition uses a Comparison to assert a complex condition.
|
||||
func Condition(t TestingT, comp assert.Comparison, msgAndArgs ...interface{}) {
|
||||
if !assert.Condition(t, comp, msgAndArgs...) {
|
||||
t.FailNow()
|
||||
}
|
||||
}
|
||||
|
||||
// Panics asserts that the code inside the specified PanicTestFunc panics.
|
||||
//
|
||||
// require.Panics(t, func(){
|
||||
// GoCrazy()
|
||||
// }, "Calling GoCrazy() should panic")
|
||||
func Panics(t TestingT, f assert.PanicTestFunc, msgAndArgs ...interface{}) {
|
||||
if !assert.Panics(t, f, msgAndArgs...) {
|
||||
t.FailNow()
|
||||
}
|
||||
}
|
||||
|
||||
// NotPanics asserts that the code inside the specified PanicTestFunc does NOT panic.
|
||||
//
|
||||
// require.NotPanics(t, func(){
|
||||
// RemainCalm()
|
||||
// }, "Calling RemainCalm() should NOT panic")
|
||||
func NotPanics(t TestingT, f assert.PanicTestFunc, msgAndArgs ...interface{}) {
|
||||
if !assert.NotPanics(t, f, msgAndArgs...) {
|
||||
t.FailNow()
|
||||
}
|
||||
}
|
||||
|
||||
// WithinDuration asserts that the two times are within duration delta of each other.
|
||||
//
|
||||
// require.WithinDuration(t, time.Now(), time.Now(), 10*time.Second, "The difference should not be more than 10s")
|
||||
func WithinDuration(t TestingT, expected, actual time.Time, delta time.Duration, msgAndArgs ...interface{}) {
|
||||
if !assert.WithinDuration(t, expected, actual, delta, msgAndArgs...) {
|
||||
t.FailNow()
|
||||
}
|
||||
}
|
||||
|
||||
// InDelta asserts that the two numerals are within delta of each other.
|
||||
//
|
||||
// require.InDelta(t, math.Pi, (22 / 7.0), 0.01)
|
||||
func InDelta(t TestingT, expected, actual interface{}, delta float64, msgAndArgs ...interface{}) {
|
||||
if !assert.InDelta(t, expected, actual, delta, msgAndArgs...) {
|
||||
t.FailNow()
|
||||
}
|
||||
}
|
||||
|
||||
// InEpsilon asserts that expected and actual have a relative error less than epsilon
|
||||
func InEpsilon(t TestingT, expected, actual interface{}, epsilon float64, msgAndArgs ...interface{}) {
|
||||
if !assert.InEpsilon(t, expected, actual, epsilon, msgAndArgs...) {
|
||||
t.FailNow()
|
||||
}
|
||||
}
|
||||
|
||||
// Regexp asserts that a specified regexp matches a string.
|
||||
//
|
||||
// require.Regexp(t, regexp.MustCompile("start"), "it's starting")
|
||||
// require.Regexp(t, "start...$", "it's not starting")
|
||||
func Regexp(t TestingT, rx interface{}, str interface{}, msgAndArgs ...interface{}) {
|
||||
if !assert.Regexp(t, rx, str, msgAndArgs...) {
|
||||
t.FailNow()
|
||||
}
|
||||
}
|
||||
|
||||
// NotRegexp asserts that a specified regexp does not match a string.
|
||||
//
|
||||
// require.NotRegexp(t, regexp.MustCompile("starts"), "it's starting")
|
||||
// require.NotRegexp(t, "^start", "it's not starting")
|
||||
func NotRegexp(t TestingT, rx interface{}, str interface{}, msgAndArgs ...interface{}) {
|
||||
if !assert.NotRegexp(t, rx, str, msgAndArgs...) {
|
||||
t.FailNow()
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
Errors
|
||||
*/
|
||||
|
||||
// NoError asserts that a function returned no error (i.e. `nil`).
|
||||
//
|
||||
// actualObj, err := SomeFunction()
|
||||
// require.NoError(t, err)
|
||||
// require.Equal(t, actualObj, expectedObj)
|
||||
//
|
||||
// Returns whether the assertion was successful (true) or not (false).
|
||||
func NoError(t TestingT, err error, msgAndArgs ...interface{}) {
|
||||
if !assert.NoError(t, err, msgAndArgs...) {
|
||||
t.FailNow()
|
||||
}
|
||||
}
|
||||
|
||||
// Error asserts that a function returned an error (i.e. not `nil`).
|
||||
//
|
||||
// actualObj, err := SomeFunction()
|
||||
// require.Error(t, err, "An error was expected")
|
||||
// require.Equal(t, err, expectedError)
|
||||
// }
|
||||
func Error(t TestingT, err error, msgAndArgs ...interface{}) {
|
||||
if !assert.Error(t, err, msgAndArgs...) {
|
||||
t.FailNow()
|
||||
}
|
||||
}
|
||||
|
||||
// EqualError asserts that a function returned an error (i.e. not `nil`)
|
||||
// and that it is equal to the provided error.
|
||||
//
|
||||
// actualObj, err := SomeFunction()
|
||||
// require.Error(t, err, "An error was expected")
|
||||
// require.Equal(t, err, expectedError)
|
||||
// }
|
||||
func EqualError(t TestingT, theError error, errString string, msgAndArgs ...interface{}) {
|
||||
if !assert.EqualError(t, theError, errString, msgAndArgs...) {
|
||||
t.FailNow()
|
||||
}
|
||||
}
|
266
Godeps/_workspace/src/github.com/stretchr/testify/require/requirements_test.go
generated
vendored
Normal file
266
Godeps/_workspace/src/github.com/stretchr/testify/require/requirements_test.go
generated
vendored
Normal file
@ -0,0 +1,266 @@
|
||||
package require
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"testing"
|
||||
"time"
|
||||
)
|
||||
|
||||
// AssertionTesterInterface defines an interface to be used for testing assertion methods
|
||||
type AssertionTesterInterface interface {
|
||||
TestMethod()
|
||||
}
|
||||
|
||||
// AssertionTesterConformingObject is an object that conforms to the AssertionTesterInterface interface
|
||||
type AssertionTesterConformingObject struct {
|
||||
}
|
||||
|
||||
func (a *AssertionTesterConformingObject) TestMethod() {
|
||||
}
|
||||
|
||||
// AssertionTesterNonConformingObject is an object that does not conform to the AssertionTesterInterface interface
|
||||
type AssertionTesterNonConformingObject struct {
|
||||
}
|
||||
|
||||
type MockT struct {
|
||||
Failed bool
|
||||
}
|
||||
|
||||
func (t *MockT) FailNow() {
|
||||
t.Failed = true
|
||||
}
|
||||
|
||||
func (t *MockT) Errorf(format string, args ...interface{}) {
|
||||
_, _ = format, args
|
||||
}
|
||||
|
||||
func TestImplements(t *testing.T) {
|
||||
|
||||
Implements(t, (*AssertionTesterInterface)(nil), new(AssertionTesterConformingObject))
|
||||
|
||||
mockT := new(MockT)
|
||||
Implements(mockT, (*AssertionTesterInterface)(nil), new(AssertionTesterNonConformingObject))
|
||||
if !mockT.Failed {
|
||||
t.Error("Check should fail")
|
||||
}
|
||||
}
|
||||
|
||||
func TestIsType(t *testing.T) {
|
||||
|
||||
IsType(t, new(AssertionTesterConformingObject), new(AssertionTesterConformingObject))
|
||||
|
||||
mockT := new(MockT)
|
||||
IsType(mockT, new(AssertionTesterConformingObject), new(AssertionTesterNonConformingObject))
|
||||
if !mockT.Failed {
|
||||
t.Error("Check should fail")
|
||||
}
|
||||
}
|
||||
|
||||
func TestEqual(t *testing.T) {
|
||||
|
||||
Equal(t, 1, 1)
|
||||
|
||||
mockT := new(MockT)
|
||||
Equal(mockT, 1, 2)
|
||||
if !mockT.Failed {
|
||||
t.Error("Check should fail")
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
func TestNotEqual(t *testing.T) {
|
||||
|
||||
NotEqual(t, 1, 2)
|
||||
mockT := new(MockT)
|
||||
NotEqual(mockT, 2, 2)
|
||||
if !mockT.Failed {
|
||||
t.Error("Check should fail")
|
||||
}
|
||||
}
|
||||
|
||||
func TestExactly(t *testing.T) {
|
||||
|
||||
a := float32(1)
|
||||
b := float32(1)
|
||||
c := float64(1)
|
||||
|
||||
Exactly(t, a, b)
|
||||
|
||||
mockT := new(MockT)
|
||||
Exactly(mockT, a, c)
|
||||
if !mockT.Failed {
|
||||
t.Error("Check should fail")
|
||||
}
|
||||
}
|
||||
|
||||
func TestNotNil(t *testing.T) {
|
||||
|
||||
NotNil(t, new(AssertionTesterConformingObject))
|
||||
|
||||
mockT := new(MockT)
|
||||
NotNil(mockT, nil)
|
||||
if !mockT.Failed {
|
||||
t.Error("Check should fail")
|
||||
}
|
||||
}
|
||||
|
||||
func TestNil(t *testing.T) {
|
||||
|
||||
Nil(t, nil)
|
||||
|
||||
mockT := new(MockT)
|
||||
Nil(mockT, new(AssertionTesterConformingObject))
|
||||
if !mockT.Failed {
|
||||
t.Error("Check should fail")
|
||||
}
|
||||
}
|
||||
|
||||
func TestTrue(t *testing.T) {
|
||||
|
||||
True(t, true)
|
||||
|
||||
mockT := new(MockT)
|
||||
True(mockT, false)
|
||||
if !mockT.Failed {
|
||||
t.Error("Check should fail")
|
||||
}
|
||||
}
|
||||
|
||||
func TestFalse(t *testing.T) {
|
||||
|
||||
False(t, false)
|
||||
|
||||
mockT := new(MockT)
|
||||
False(mockT, true)
|
||||
if !mockT.Failed {
|
||||
t.Error("Check should fail")
|
||||
}
|
||||
}
|
||||
|
||||
func TestContains(t *testing.T) {
|
||||
|
||||
Contains(t, "Hello World", "Hello")
|
||||
|
||||
mockT := new(MockT)
|
||||
Contains(mockT, "Hello World", "Salut")
|
||||
if !mockT.Failed {
|
||||
t.Error("Check should fail")
|
||||
}
|
||||
}
|
||||
|
||||
func TestNotContains(t *testing.T) {
|
||||
|
||||
NotContains(t, "Hello World", "Hello!")
|
||||
|
||||
mockT := new(MockT)
|
||||
NotContains(mockT, "Hello World", "Hello")
|
||||
if !mockT.Failed {
|
||||
t.Error("Check should fail")
|
||||
}
|
||||
}
|
||||
|
||||
func TestPanics(t *testing.T) {
|
||||
|
||||
Panics(t, func() {
|
||||
panic("Panic!")
|
||||
})
|
||||
|
||||
mockT := new(MockT)
|
||||
Panics(mockT, func() {})
|
||||
if !mockT.Failed {
|
||||
t.Error("Check should fail")
|
||||
}
|
||||
}
|
||||
|
||||
func TestNotPanics(t *testing.T) {
|
||||
|
||||
NotPanics(t, func() {})
|
||||
|
||||
mockT := new(MockT)
|
||||
NotPanics(mockT, func() {
|
||||
panic("Panic!")
|
||||
})
|
||||
if !mockT.Failed {
|
||||
t.Error("Check should fail")
|
||||
}
|
||||
}
|
||||
|
||||
func TestNoError(t *testing.T) {
|
||||
|
||||
NoError(t, nil)
|
||||
|
||||
mockT := new(MockT)
|
||||
NoError(mockT, errors.New("some error"))
|
||||
if !mockT.Failed {
|
||||
t.Error("Check should fail")
|
||||
}
|
||||
}
|
||||
|
||||
func TestError(t *testing.T) {
|
||||
|
||||
Error(t, errors.New("some error"))
|
||||
|
||||
mockT := new(MockT)
|
||||
Error(mockT, nil)
|
||||
if !mockT.Failed {
|
||||
t.Error("Check should fail")
|
||||
}
|
||||
}
|
||||
|
||||
func TestEqualError(t *testing.T) {
|
||||
|
||||
EqualError(t, errors.New("some error"), "some error")
|
||||
|
||||
mockT := new(MockT)
|
||||
EqualError(mockT, errors.New("some error"), "Not some error")
|
||||
if !mockT.Failed {
|
||||
t.Error("Check should fail")
|
||||
}
|
||||
}
|
||||
|
||||
func TestEmpty(t *testing.T) {
|
||||
|
||||
Empty(t, "")
|
||||
|
||||
mockT := new(MockT)
|
||||
Empty(mockT, "x")
|
||||
if !mockT.Failed {
|
||||
t.Error("Check should fail")
|
||||
}
|
||||
}
|
||||
|
||||
func TestNotEmpty(t *testing.T) {
|
||||
|
||||
NotEmpty(t, "x")
|
||||
|
||||
mockT := new(MockT)
|
||||
NotEmpty(mockT, "")
|
||||
if !mockT.Failed {
|
||||
t.Error("Check should fail")
|
||||
}
|
||||
}
|
||||
|
||||
func TestWithinDuration(t *testing.T) {
|
||||
|
||||
a := time.Now()
|
||||
b := a.Add(10 * time.Second)
|
||||
|
||||
WithinDuration(t, a, b, 15*time.Second)
|
||||
|
||||
mockT := new(MockT)
|
||||
WithinDuration(mockT, a, b, 5*time.Second)
|
||||
if !mockT.Failed {
|
||||
t.Error("Check should fail")
|
||||
}
|
||||
}
|
||||
|
||||
func TestInDelta(t *testing.T) {
|
||||
|
||||
InDelta(t, 1.001, 1, 0.01)
|
||||
|
||||
mockT := new(MockT)
|
||||
InDelta(mockT, 1, 2, 0.5)
|
||||
if !mockT.Failed {
|
||||
t.Error("Check should fail")
|
||||
}
|
||||
}
|
222
pkg/kubelet/image_manager.go
Normal file
222
pkg/kubelet/image_manager.go
Normal file
@ -0,0 +1,222 @@
|
||||
/*
|
||||
Copyright 2015 Google Inc. All rights reserved.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package kubelet
|
||||
|
||||
import (
|
||||
"sort"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/kubelet/dockertools"
|
||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/util"
|
||||
docker "github.com/fsouza/go-dockerclient"
|
||||
"github.com/golang/glog"
|
||||
)
|
||||
|
||||
// Manages lifecycle of all images.
|
||||
//
|
||||
// Class is thread-safe.
|
||||
type imageManager interface {
|
||||
// Starts the image manager.
|
||||
Start() error
|
||||
|
||||
// Tries to free bytesToFree worth of images on the disk.
|
||||
//
|
||||
// Returns the number of bytes free and an error if any occured. The number of
|
||||
// bytes freed is always returned.
|
||||
// Note that error may be nil and the number of bytes free may be less
|
||||
// than bytesToFree.
|
||||
FreeSpace(bytesToFree int64) (int64, error)
|
||||
|
||||
// TODO(vmarmol): Have this subsume pulls as well.
|
||||
}
|
||||
|
||||
type realImageManager struct {
|
||||
// Connection to the Docker daemon.
|
||||
dockerClient dockertools.DockerInterface
|
||||
|
||||
// Records of images and their use.
|
||||
imageRecords map[string]*imageRecord
|
||||
|
||||
// Lock for imageRecords.
|
||||
imageRecordsLock sync.Mutex
|
||||
}
|
||||
|
||||
// Information about the images we track.
|
||||
type imageRecord struct {
|
||||
// Time when this image was first detected.
|
||||
detected time.Time
|
||||
|
||||
// Time when we last saw this image being used.
|
||||
lastUsed time.Time
|
||||
|
||||
// Size of the image in bytes.
|
||||
size int64
|
||||
}
|
||||
|
||||
func newImageManager(dockerClient dockertools.DockerInterface) imageManager {
|
||||
return &realImageManager{
|
||||
dockerClient: dockerClient,
|
||||
imageRecords: make(map[string]*imageRecord),
|
||||
}
|
||||
}
|
||||
|
||||
func (self *realImageManager) Start() error {
|
||||
// Initial detection make detected time "unknown" in the past.
|
||||
var zero time.Time
|
||||
err := self.detectImages(zero)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
util.Forever(func() {
|
||||
err := self.detectImages(time.Now())
|
||||
if err != nil {
|
||||
glog.Warningf("[ImageManager] Failed to monitor images: %v", err)
|
||||
}
|
||||
}, 5*time.Minute)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (self *realImageManager) detectImages(detected time.Time) error {
|
||||
images, err := self.dockerClient.ListImages(docker.ListImagesOptions{})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
containers, err := self.dockerClient.ListContainers(docker.ListContainersOptions{
|
||||
All: true,
|
||||
})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Make a set of images in use by containers.
|
||||
imagesInUse := util.NewStringSet()
|
||||
for _, container := range containers {
|
||||
imagesInUse.Insert(container.Image)
|
||||
}
|
||||
|
||||
// Add new images and record those being used.
|
||||
now := time.Now()
|
||||
currentImages := util.NewStringSet()
|
||||
self.imageRecordsLock.Lock()
|
||||
defer self.imageRecordsLock.Unlock()
|
||||
for _, image := range images {
|
||||
currentImages.Insert(image.ID)
|
||||
|
||||
// New image, set it as detected now.
|
||||
if _, ok := self.imageRecords[image.ID]; !ok {
|
||||
self.imageRecords[image.ID] = &imageRecord{
|
||||
detected: detected,
|
||||
}
|
||||
}
|
||||
|
||||
// Set last used time to now if the image is being used.
|
||||
if isImageUsed(&image, imagesInUse) {
|
||||
self.imageRecords[image.ID].lastUsed = now
|
||||
}
|
||||
|
||||
self.imageRecords[image.ID].size = image.VirtualSize
|
||||
}
|
||||
|
||||
// Remove old images from our records.
|
||||
for image := range self.imageRecords {
|
||||
if !currentImages.Has(image) {
|
||||
delete(self.imageRecords, image)
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (self *realImageManager) FreeSpace(bytesToFree int64) (int64, error) {
|
||||
startTime := time.Now()
|
||||
err := self.detectImages(startTime)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
|
||||
self.imageRecordsLock.Lock()
|
||||
defer self.imageRecordsLock.Unlock()
|
||||
|
||||
// Get all images in eviction order.
|
||||
images := make([]evictionInfo, 0, len(self.imageRecords))
|
||||
for image, record := range self.imageRecords {
|
||||
images = append(images, evictionInfo{
|
||||
id: image,
|
||||
imageRecord: *record,
|
||||
})
|
||||
}
|
||||
sort.Sort(byLastUsedAndDetected(images))
|
||||
|
||||
// Delete unused images until we've freed up enough space.
|
||||
var lastErr error
|
||||
spaceFreed := int64(0)
|
||||
for _, image := range images {
|
||||
// Images that are currently in used were given a newer lastUsed.
|
||||
if image.lastUsed.After(startTime) {
|
||||
break
|
||||
}
|
||||
|
||||
// Remove image. Continue despite errors.
|
||||
err := self.dockerClient.RemoveImage(image.id)
|
||||
if err != nil {
|
||||
lastErr = err
|
||||
continue
|
||||
}
|
||||
delete(self.imageRecords, image.id)
|
||||
spaceFreed += image.size
|
||||
|
||||
if spaceFreed >= bytesToFree {
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
return spaceFreed, lastErr
|
||||
}
|
||||
|
||||
type evictionInfo struct {
|
||||
id string
|
||||
imageRecord
|
||||
}
|
||||
|
||||
type byLastUsedAndDetected []evictionInfo
|
||||
|
||||
func (self byLastUsedAndDetected) Len() int { return len(self) }
|
||||
func (self byLastUsedAndDetected) Swap(i, j int) { self[i], self[j] = self[j], self[i] }
|
||||
func (self byLastUsedAndDetected) Less(i, j int) bool {
|
||||
// Sort by last used, break ties by detected.
|
||||
if self[i].lastUsed.Equal(self[j].lastUsed) {
|
||||
return self[i].detected.Before(self[j].detected)
|
||||
} else {
|
||||
return self[i].lastUsed.Before(self[j].lastUsed)
|
||||
}
|
||||
}
|
||||
|
||||
func isImageUsed(image *docker.APIImages, imagesInUse util.StringSet) bool {
|
||||
// Check the image ID and all the RepoTags.
|
||||
if _, ok := imagesInUse[image.ID]; ok {
|
||||
return true
|
||||
}
|
||||
for _, tag := range image.RepoTags {
|
||||
if _, ok := imagesInUse[tag]; ok {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
301
pkg/kubelet/image_manager_test.go
Normal file
301
pkg/kubelet/image_manager_test.go
Normal file
@ -0,0 +1,301 @@
|
||||
/*
|
||||
Copyright 2015 Google Inc. All rights reserved.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package kubelet
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/kubelet/dockertools"
|
||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/util"
|
||||
docker "github.com/fsouza/go-dockerclient"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
var zero time.Time
|
||||
|
||||
func newRealImageManager(dockerClient dockertools.DockerInterface) *realImageManager {
|
||||
return newImageManager(dockerClient).(*realImageManager)
|
||||
}
|
||||
|
||||
// Returns the name of the image with the given ID.
|
||||
func imageName(id int) string {
|
||||
return fmt.Sprintf("image-%d", id)
|
||||
}
|
||||
|
||||
// Make an image with the specified ID.
|
||||
func makeImage(id int, size int64) docker.APIImages {
|
||||
return docker.APIImages{
|
||||
ID: imageName(id),
|
||||
VirtualSize: size,
|
||||
}
|
||||
}
|
||||
|
||||
// Make a container with the specified ID. It will use the image with the same ID.
|
||||
func makeContainer(id int) docker.APIContainers {
|
||||
return docker.APIContainers{
|
||||
ID: fmt.Sprintf("container-%d", id),
|
||||
Image: imageName(id),
|
||||
}
|
||||
}
|
||||
|
||||
func TestDetectImagesInitialDetect(t *testing.T) {
|
||||
fakeDocker := &dockertools.FakeDockerClient{
|
||||
Images: []docker.APIImages{
|
||||
makeImage(0, 1024),
|
||||
makeImage(1, 2048),
|
||||
},
|
||||
ContainerList: []docker.APIContainers{
|
||||
makeContainer(1),
|
||||
},
|
||||
}
|
||||
manager := newRealImageManager(fakeDocker)
|
||||
|
||||
startTime := time.Now().Add(-time.Millisecond)
|
||||
err := manager.detectImages(zero)
|
||||
assert := assert.New(t)
|
||||
require.Nil(t, err)
|
||||
assert.Len(manager.imageRecords, 2)
|
||||
noContainer, ok := manager.imageRecords[imageName(0)]
|
||||
require.True(t, ok)
|
||||
assert.Equal(zero, noContainer.detected)
|
||||
assert.Equal(zero, noContainer.lastUsed)
|
||||
withContainer, ok := manager.imageRecords[imageName(1)]
|
||||
require.True(t, ok)
|
||||
assert.Equal(zero, withContainer.detected)
|
||||
assert.True(withContainer.lastUsed.After(startTime))
|
||||
}
|
||||
|
||||
func TestDetectImagesWithNewImage(t *testing.T) {
|
||||
// Just one image initially.
|
||||
fakeDocker := &dockertools.FakeDockerClient{
|
||||
Images: []docker.APIImages{
|
||||
makeImage(0, 1024),
|
||||
makeImage(1, 2048),
|
||||
},
|
||||
ContainerList: []docker.APIContainers{
|
||||
makeContainer(1),
|
||||
},
|
||||
}
|
||||
manager := newRealImageManager(fakeDocker)
|
||||
|
||||
err := manager.detectImages(zero)
|
||||
assert := assert.New(t)
|
||||
require.Nil(t, err)
|
||||
assert.Len(manager.imageRecords, 2)
|
||||
|
||||
// Add a new image.
|
||||
fakeDocker.Images = []docker.APIImages{
|
||||
makeImage(0, 1024),
|
||||
makeImage(1, 1024),
|
||||
makeImage(2, 1024),
|
||||
}
|
||||
|
||||
detectedTime := zero.Add(time.Second)
|
||||
startTime := time.Now().Add(-time.Millisecond)
|
||||
err = manager.detectImages(detectedTime)
|
||||
require.Nil(t, err)
|
||||
assert.Len(manager.imageRecords, 3)
|
||||
noContainer, ok := manager.imageRecords[imageName(0)]
|
||||
require.True(t, ok)
|
||||
assert.Equal(zero, noContainer.detected)
|
||||
assert.Equal(zero, noContainer.lastUsed)
|
||||
withContainer, ok := manager.imageRecords[imageName(1)]
|
||||
require.True(t, ok)
|
||||
assert.Equal(zero, withContainer.detected)
|
||||
assert.True(withContainer.lastUsed.After(startTime))
|
||||
newContainer, ok := manager.imageRecords[imageName(2)]
|
||||
require.True(t, ok)
|
||||
assert.Equal(detectedTime, newContainer.detected)
|
||||
assert.Equal(zero, noContainer.lastUsed)
|
||||
}
|
||||
|
||||
func TestDetectImagesContainerStopped(t *testing.T) {
|
||||
fakeDocker := &dockertools.FakeDockerClient{
|
||||
Images: []docker.APIImages{
|
||||
makeImage(0, 1024),
|
||||
makeImage(1, 2048),
|
||||
},
|
||||
ContainerList: []docker.APIContainers{
|
||||
makeContainer(1),
|
||||
},
|
||||
}
|
||||
manager := newRealImageManager(fakeDocker)
|
||||
|
||||
err := manager.detectImages(zero)
|
||||
assert := assert.New(t)
|
||||
require.Nil(t, err)
|
||||
assert.Len(manager.imageRecords, 2)
|
||||
withContainer, ok := manager.imageRecords[imageName(1)]
|
||||
require.True(t, ok)
|
||||
|
||||
// Simulate container being stopped.
|
||||
fakeDocker.ContainerList = []docker.APIContainers{}
|
||||
err = manager.detectImages(time.Now())
|
||||
require.Nil(t, err)
|
||||
assert.Len(manager.imageRecords, 2)
|
||||
container1, ok := manager.imageRecords[imageName(0)]
|
||||
require.True(t, ok)
|
||||
assert.Equal(zero, container1.detected)
|
||||
assert.Equal(zero, container1.lastUsed)
|
||||
container2, ok := manager.imageRecords[imageName(1)]
|
||||
require.True(t, ok)
|
||||
assert.Equal(zero, container2.detected)
|
||||
assert.True(container2.lastUsed.Equal(withContainer.lastUsed))
|
||||
}
|
||||
|
||||
func TestDetectImagesWithRemovedImages(t *testing.T) {
|
||||
fakeDocker := &dockertools.FakeDockerClient{
|
||||
Images: []docker.APIImages{
|
||||
makeImage(0, 1024),
|
||||
makeImage(1, 2048),
|
||||
},
|
||||
ContainerList: []docker.APIContainers{
|
||||
makeContainer(1),
|
||||
},
|
||||
}
|
||||
manager := newRealImageManager(fakeDocker)
|
||||
|
||||
err := manager.detectImages(zero)
|
||||
assert := assert.New(t)
|
||||
require.Nil(t, err)
|
||||
assert.Len(manager.imageRecords, 2)
|
||||
|
||||
// Simulate both images being removed.
|
||||
fakeDocker.Images = []docker.APIImages{}
|
||||
err = manager.detectImages(time.Now())
|
||||
require.Nil(t, err)
|
||||
assert.Len(manager.imageRecords, 0)
|
||||
}
|
||||
|
||||
func TestFreeSpaceImagesInUseContainersAreIgnored(t *testing.T) {
|
||||
fakeDocker := &dockertools.FakeDockerClient{
|
||||
Images: []docker.APIImages{
|
||||
makeImage(0, 1024),
|
||||
makeImage(1, 2048),
|
||||
},
|
||||
ContainerList: []docker.APIContainers{
|
||||
makeContainer(1),
|
||||
},
|
||||
RemovedImages: util.NewStringSet(),
|
||||
}
|
||||
manager := newRealImageManager(fakeDocker)
|
||||
|
||||
spaceFreed, err := manager.FreeSpace(2048)
|
||||
assert := assert.New(t)
|
||||
require.Nil(t, err)
|
||||
assert.Equal(1024, spaceFreed)
|
||||
assert.Len(fakeDocker.RemovedImages, 1)
|
||||
assert.True(fakeDocker.RemovedImages.Has(imageName(0)))
|
||||
}
|
||||
|
||||
func TestFreeSpaceRemoveByLeastRecentlyUsed(t *testing.T) {
|
||||
fakeDocker := &dockertools.FakeDockerClient{
|
||||
Images: []docker.APIImages{
|
||||
makeImage(0, 1024),
|
||||
makeImage(1, 2048),
|
||||
},
|
||||
ContainerList: []docker.APIContainers{
|
||||
makeContainer(0),
|
||||
makeContainer(1),
|
||||
},
|
||||
RemovedImages: util.NewStringSet(),
|
||||
}
|
||||
manager := newRealImageManager(fakeDocker)
|
||||
|
||||
// Make 1 be more recently used than 0.
|
||||
require.Nil(t, manager.detectImages(zero))
|
||||
fakeDocker.ContainerList = []docker.APIContainers{
|
||||
makeContainer(1),
|
||||
}
|
||||
require.Nil(t, manager.detectImages(time.Now()))
|
||||
fakeDocker.ContainerList = []docker.APIContainers{}
|
||||
require.Nil(t, manager.detectImages(time.Now()))
|
||||
require.Len(t, manager.imageRecords, 2)
|
||||
|
||||
spaceFreed, err := manager.FreeSpace(1024)
|
||||
assert := assert.New(t)
|
||||
require.Nil(t, err)
|
||||
assert.Equal(1024, spaceFreed)
|
||||
assert.Len(fakeDocker.RemovedImages, 1)
|
||||
assert.True(fakeDocker.RemovedImages.Has(imageName(0)))
|
||||
}
|
||||
|
||||
func TestFreeSpaceTiesBrokenByDetectedTime(t *testing.T) {
|
||||
fakeDocker := &dockertools.FakeDockerClient{
|
||||
Images: []docker.APIImages{
|
||||
makeImage(0, 1024),
|
||||
},
|
||||
ContainerList: []docker.APIContainers{
|
||||
makeContainer(0),
|
||||
},
|
||||
RemovedImages: util.NewStringSet(),
|
||||
}
|
||||
manager := newRealImageManager(fakeDocker)
|
||||
|
||||
// Make 1 more recently detected but used at the same time as 0.
|
||||
require.Nil(t, manager.detectImages(zero))
|
||||
fakeDocker.Images = []docker.APIImages{
|
||||
makeImage(0, 1024),
|
||||
makeImage(1, 2048),
|
||||
}
|
||||
fakeDocker.ContainerList = []docker.APIContainers{
|
||||
makeContainer(0),
|
||||
makeContainer(1),
|
||||
}
|
||||
require.Nil(t, manager.detectImages(time.Now()))
|
||||
fakeDocker.ContainerList = []docker.APIContainers{}
|
||||
require.Nil(t, manager.detectImages(time.Now()))
|
||||
require.Len(t, manager.imageRecords, 2)
|
||||
|
||||
spaceFreed, err := manager.FreeSpace(1024)
|
||||
assert := assert.New(t)
|
||||
require.Nil(t, err)
|
||||
assert.Equal(1024, spaceFreed)
|
||||
assert.Len(fakeDocker.RemovedImages, 1)
|
||||
assert.True(fakeDocker.RemovedImages.Has(imageName(0)))
|
||||
}
|
||||
|
||||
func TestFreeSpaceImagesAlsoDoesLookupByRepoTags(t *testing.T) {
|
||||
fakeDocker := &dockertools.FakeDockerClient{
|
||||
Images: []docker.APIImages{
|
||||
makeImage(0, 1024),
|
||||
{
|
||||
ID: "5678",
|
||||
RepoTags: []string{"potato", "salad"},
|
||||
VirtualSize: 2048,
|
||||
},
|
||||
},
|
||||
ContainerList: []docker.APIContainers{
|
||||
{
|
||||
ID: "c5678",
|
||||
Image: "salad",
|
||||
},
|
||||
},
|
||||
RemovedImages: util.NewStringSet(),
|
||||
}
|
||||
manager := newRealImageManager(fakeDocker)
|
||||
|
||||
spaceFreed, err := manager.FreeSpace(1024)
|
||||
assert := assert.New(t)
|
||||
require.Nil(t, err)
|
||||
assert.Equal(1024, spaceFreed)
|
||||
assert.Len(fakeDocker.RemovedImages, 1)
|
||||
assert.True(fakeDocker.RemovedImages.Has(imageName(0)))
|
||||
}
|
Loading…
Reference in New Issue
Block a user