Fix interface{} in api/types.go; plumb through system.

This commit is contained in:
Daniel Smith 2014-06-30 19:46:10 -07:00
parent d523ccb428
commit 049bc6b6d4
10 changed files with 219 additions and 93 deletions

View File

@ -16,6 +16,10 @@ limitations under the License.
package api package api
import (
"github.com/fsouza/go-dockerclient"
)
// Common string formats // Common string formats
// --------------------- // ---------------------
// Many fields in this API have formatting requirements. The commonly used // Many fields in this API have formatting requirements. The commonly used
@ -159,7 +163,13 @@ type PodState struct {
Status PodStatus `json:"status,omitempty" yaml:"status,omitempty"` Status PodStatus `json:"status,omitempty" yaml:"status,omitempty"`
Host string `json:"host,omitempty" yaml:"host,omitempty"` Host string `json:"host,omitempty" yaml:"host,omitempty"`
HostIP string `json:"hostIP,omitempty" yaml:"hostIP,omitempty"` HostIP string `json:"hostIP,omitempty" yaml:"hostIP,omitempty"`
Info interface{} `json:"info,omitempty" yaml:"info,omitempty"`
// The key of this map is the *name* of the container within the manifest; it has one
// entry per container in the manifest. The value of this map is currently the output
// of `docker inspect`. This output format is *not* final and should not be relied
// upon.
// TODO: Make real decisions about what our info should look like.
Info map[string]docker.Container `json:"info,omitempty" yaml:"info,omitempty"`
} }
type PodList struct { type PodList struct {

View File

@ -20,15 +20,20 @@ import (
"encoding/json" "encoding/json"
"fmt" "fmt"
"io/ioutil" "io/ioutil"
"net"
"net/http" "net/http"
"strconv"
"github.com/fsouza/go-dockerclient"
) )
// ContainerInfo is an interface for things that can get information about a container. // ContainerInfo is an interface for things that can get information about a container.
// Injectable for easy testing. // Injectable for easy testing.
type ContainerInfo interface { type ContainerInfo interface {
// GetContainerInfo returns information about container 'name' on 'host' // GetContainerInfo returns information about container 'name' on 'host'
// Returns an untyped interface, and an error, if one occurs // Returns a json-formatted []byte (which can be unmarshalled into a
GetContainerInfo(host, name string) (interface{}, error) // map[string]interface{}) or an error if one occurs.
GetContainerInfo(host, name string) (*docker.Container, error)
} }
// The default implementation, accesses the kubelet over HTTP // The default implementation, accesses the kubelet over HTTP
@ -37,8 +42,14 @@ type HTTPContainerInfo struct {
Port uint Port uint
} }
func (c *HTTPContainerInfo) GetContainerInfo(host, name string) (interface{}, error) { func (c *HTTPContainerInfo) GetContainerInfo(host, name string) (*docker.Container, error) {
request, err := http.NewRequest("GET", fmt.Sprintf("http://%s:%d/containerInfo?container=%s", host, c.Port, name), nil) request, err := http.NewRequest(
"GET",
fmt.Sprintf(
"http://%s/containerInfo?container=%s",
net.JoinHostPort(host, strconv.FormatUint(uint64(c.Port), 10)),
name),
nil)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -51,17 +62,21 @@ func (c *HTTPContainerInfo) GetContainerInfo(host, name string) (interface{}, er
if err != nil { if err != nil {
return nil, err return nil, err
} }
var data interface{} // Check that this data can be unmarshalled
err = json.Unmarshal(body, &data) var container docker.Container
return data, err err = json.Unmarshal(body, &container)
if err != nil {
return nil, err
}
return &container, nil
} }
// Useful for testing. // Useful for testing.
type FakeContainerInfo struct { type FakeContainerInfo struct {
data interface{} data *docker.Container
err error err error
} }
func (c *FakeContainerInfo) GetContainerInfo(host, name string) (interface{}, error) { func (c *FakeContainerInfo) GetContainerInfo(host, name string) (*docker.Container, error) {
return c.data, c.err return c.data, c.err
} }

View File

@ -26,6 +26,7 @@ import (
"testing" "testing"
"github.com/GoogleCloudPlatform/kubernetes/pkg/util" "github.com/GoogleCloudPlatform/kubernetes/pkg/util"
"github.com/fsouza/go-dockerclient"
) )
// TODO: This doesn't reduce typing enough to make it worth the less readable errors. Remove. // TODO: This doesn't reduce typing enough to make it worth the less readable errors. Remove.
@ -36,10 +37,12 @@ func expectNoError(t *testing.T, err error) {
} }
func TestHTTPContainerInfo(t *testing.T) { func TestHTTPContainerInfo(t *testing.T) {
body := `{"items":[]}` expectObj := &docker.Container{ID: "myID"}
body, err := json.Marshal(expectObj)
expectNoError(t, err)
fakeHandler := util.FakeHandler{ fakeHandler := util.FakeHandler{
StatusCode: 200, StatusCode: 200,
ResponseBody: body, ResponseBody: string(body),
} }
testServer := httptest.NewServer(&fakeHandler) testServer := httptest.NewServer(&fakeHandler)
@ -53,10 +56,11 @@ func TestHTTPContainerInfo(t *testing.T) {
Client: http.DefaultClient, Client: http.DefaultClient,
Port: uint(port), Port: uint(port),
} }
data, err := containerInfo.GetContainerInfo(parts[0], "foo") gotObj, err := containerInfo.GetContainerInfo(parts[0], "foo")
expectNoError(t, err) expectNoError(t, err)
dataString, _ := json.Marshal(data)
if string(dataString) != body { // reflect.DeepEqual(expectObj, gotObj) doesn't handle blank times well
t.Errorf("Unexpected response. Expected: %s, received %s", body, string(dataString)) if expectObj.ID != gotObj.ID {
t.Errorf("Unexpected response. Expected: %#v, received %#v", expectObj, gotObj)
} }
} }

View File

@ -784,17 +784,16 @@ func (kl *Kubelet) getContainerIdFromName(name string) (DockerId, bool, error) {
} }
// Returns docker info for a container // Returns docker info for a container
func (kl *Kubelet) GetContainerInfo(name string) (string, error) { func (kl *Kubelet) GetContainerInfo(name string) (*docker.Container, error) {
dockerId, found, err := kl.getContainerIdFromName(name) dockerId, found, err := kl.getContainerIdFromName(name)
if err != nil || !found { if err != nil || !found {
return "{}", err return nil, err
} }
info, err := kl.DockerClient.InspectContainer(string(dockerId)) info, err := kl.DockerClient.InspectContainer(string(dockerId))
if err != nil { if err != nil {
return "{}", err return nil, err
} }
data, err := json.Marshal(info) return info, nil
return string(data), err
} }
//Returns stats (from Cadvisor) for a container //Returns stats (from Cadvisor) for a container

View File

@ -24,6 +24,7 @@ import (
"net/url" "net/url"
"github.com/GoogleCloudPlatform/kubernetes/pkg/api" "github.com/GoogleCloudPlatform/kubernetes/pkg/api"
"github.com/fsouza/go-dockerclient"
"gopkg.in/v1/yaml" "gopkg.in/v1/yaml"
) )
@ -36,7 +37,7 @@ type KubeletServer struct {
// For testablitiy. // For testablitiy.
type kubeletInterface interface { type kubeletInterface interface {
GetContainerStats(name string) (*api.ContainerStats, error) GetContainerStats(name string) (*api.ContainerStats, error)
GetContainerInfo(name string) (string, error) GetContainerInfo(name string) (*docker.Container, error)
} }
func (s *KubeletServer) error(w http.ResponseWriter, err error) { func (s *KubeletServer) error(w http.ResponseWriter, err error) {
@ -113,7 +114,13 @@ func (s *KubeletServer) ServeHTTP(w http.ResponseWriter, req *http.Request) {
fmt.Fprint(w, "Missing container selector arg.") fmt.Fprint(w, "Missing container selector arg.")
return return
} }
data, err := s.Kubelet.GetContainerInfo(container) info, err := s.Kubelet.GetContainerInfo(container)
if err != nil {
w.WriteHeader(http.StatusInternalServerError)
fmt.Fprintf(w, "Internal Error: %v", err)
return
}
data, err := json.Marshal(info)
if err != nil { if err != nil {
w.WriteHeader(http.StatusInternalServerError) w.WriteHeader(http.StatusInternalServerError)
fmt.Fprintf(w, "Internal Error: %v", err) fmt.Fprintf(w, "Internal Error: %v", err)
@ -121,7 +128,7 @@ func (s *KubeletServer) ServeHTTP(w http.ResponseWriter, req *http.Request) {
} }
w.WriteHeader(http.StatusOK) w.WriteHeader(http.StatusOK)
w.Header().Add("Content-type", "application/json") w.Header().Add("Content-type", "application/json")
fmt.Fprint(w, data) w.Write(data)
default: default:
w.WriteHeader(http.StatusNotFound) w.WriteHeader(http.StatusNotFound)
fmt.Fprint(w, "Not found.") fmt.Fprint(w, "Not found.")

View File

@ -28,14 +28,15 @@ import (
"github.com/GoogleCloudPlatform/kubernetes/pkg/api" "github.com/GoogleCloudPlatform/kubernetes/pkg/api"
"github.com/GoogleCloudPlatform/kubernetes/pkg/util" "github.com/GoogleCloudPlatform/kubernetes/pkg/util"
"github.com/fsouza/go-dockerclient"
) )
type fakeKubelet struct { type fakeKubelet struct {
infoFunc func(name string) (string, error) infoFunc func(name string) (*docker.Container, error)
statsFunc func(name string) (*api.ContainerStats, error) statsFunc func(name string) (*api.ContainerStats, error)
} }
func (fk *fakeKubelet) GetContainerInfo(name string) (string, error) { func (fk *fakeKubelet) GetContainerInfo(name string) (*docker.Container, error) {
return fk.infoFunc(name) return fk.infoFunc(name)
} }
@ -116,12 +117,12 @@ func TestContainers(t *testing.T) {
func TestContainerInfo(t *testing.T) { func TestContainerInfo(t *testing.T) {
fw := makeServerTest() fw := makeServerTest()
expected := "good container info string" expected := &docker.Container{ID: "myContainerID"}
fw.fakeKubelet.infoFunc = func(name string) (string, error) { fw.fakeKubelet.infoFunc = func(name string) (*docker.Container, error) {
if name == "goodcontainer" { if name == "goodcontainer" {
return expected, nil return expected, nil
} }
return "", fmt.Errorf("bad container") return nil, fmt.Errorf("bad container")
} }
resp, err := http.Get(fw.testHttpServer.URL + "/containerInfo?container=goodcontainer") resp, err := http.Get(fw.testHttpServer.URL + "/containerInfo?container=goodcontainer")
if err != nil { if err != nil {
@ -131,7 +132,11 @@ func TestContainerInfo(t *testing.T) {
if err != nil { if err != nil {
t.Errorf("Error reading body: %v", err) t.Errorf("Error reading body: %v", err)
} }
if got != expected { expectedBytes, err := json.Marshal(expected)
if err != nil {
t.Fatalf("Unexpected marshal error %v", err)
}
if got != string(expectedBytes) {
t.Errorf("Expected: '%v', got: '%v'", expected, got) t.Errorf("Expected: '%v', got: '%v'", expected, got)
} }
} }

View File

@ -17,6 +17,7 @@ limitations under the License.
package master package master
import ( import (
"errors"
"sync" "sync"
"time" "time"
@ -24,6 +25,7 @@ import (
"github.com/GoogleCloudPlatform/kubernetes/pkg/labels" "github.com/GoogleCloudPlatform/kubernetes/pkg/labels"
"github.com/GoogleCloudPlatform/kubernetes/pkg/registry" "github.com/GoogleCloudPlatform/kubernetes/pkg/registry"
"github.com/GoogleCloudPlatform/kubernetes/pkg/util" "github.com/GoogleCloudPlatform/kubernetes/pkg/util"
"github.com/fsouza/go-dockerclient"
"github.com/golang/glog" "github.com/golang/glog"
) )
@ -32,7 +34,7 @@ import (
type PodCache struct { type PodCache struct {
containerInfo client.ContainerInfo containerInfo client.ContainerInfo
pods registry.PodRegistry pods registry.PodRegistry
podInfo map[string]interface{} podInfo map[string]docker.Container
period time.Duration period time.Duration
podLock sync.Mutex podLock sync.Mutex
} }
@ -41,21 +43,20 @@ func NewPodCache(info client.ContainerInfo, pods registry.PodRegistry, period ti
return &PodCache{ return &PodCache{
containerInfo: info, containerInfo: info,
pods: pods, pods: pods,
podInfo: map[string]interface{}{}, podInfo: map[string]docker.Container{},
period: period, period: period,
} }
} }
// Implements the ContainerInfo interface // Implements the ContainerInfo interface.
// The returned value should be treated as read-only func (p *PodCache) GetContainerInfo(host, id string) (*docker.Container, error) {
func (p *PodCache) GetContainerInfo(host, id string) (interface{}, error) {
p.podLock.Lock() p.podLock.Lock()
defer p.podLock.Unlock() defer p.podLock.Unlock()
value, ok := p.podInfo[id] value, ok := p.podInfo[id]
if !ok { if !ok {
return nil, nil return nil, errors.New("No cached pod info")
} else { } else {
return value, nil return &value, nil
} }
} }
@ -66,7 +67,7 @@ func (p *PodCache) updateContainerInfo(host, id string) error {
} }
p.podLock.Lock() p.podLock.Lock()
defer p.podLock.Unlock() defer p.podLock.Unlock()
p.podInfo[id] = info p.podInfo[id] = *info
return nil return nil
} }

View File

@ -23,16 +23,17 @@ import (
"github.com/GoogleCloudPlatform/kubernetes/pkg/api" "github.com/GoogleCloudPlatform/kubernetes/pkg/api"
"github.com/GoogleCloudPlatform/kubernetes/pkg/registry" "github.com/GoogleCloudPlatform/kubernetes/pkg/registry"
"github.com/fsouza/go-dockerclient"
) )
type FakeContainerInfo struct { type FakeContainerInfo struct {
host string host string
id string id string
data interface{} data *docker.Container
err error err error
} }
func (f *FakeContainerInfo) GetContainerInfo(host, id string) (interface{}, error) { func (f *FakeContainerInfo) GetContainerInfo(host, id string) (*docker.Container, error) {
f.host = host f.host = host
f.id = id f.id = id
return f.data, f.err return f.data, f.err
@ -41,17 +42,15 @@ func (f *FakeContainerInfo) GetContainerInfo(host, id string) (interface{}, erro
func TestPodCacheGet(t *testing.T) { func TestPodCacheGet(t *testing.T) {
cache := NewPodCache(nil, nil, time.Second*1) cache := NewPodCache(nil, nil, time.Second*1)
pod := api.Pod{ expected := docker.Container{ID: "foo"}
JSONBase: api.JSONBase{ID: "foo"}, cache.podInfo["foo"] = expected
}
cache.podInfo["foo"] = pod
info, err := cache.GetContainerInfo("host", "foo") info, err := cache.GetContainerInfo("host", "foo")
if err != nil { if err != nil {
t.Errorf("Unexpected error: %#v", err) t.Errorf("Unexpected error: %#v", err)
} }
if !reflect.DeepEqual(info, pod) { if !reflect.DeepEqual(info, &expected) {
t.Errorf("Unexpected mismatch. Expected: %#v, Got: #%v", pod, info) t.Errorf("Unexpected mismatch. Expected: %#v, Got: #%v", &expected, info)
} }
} }
@ -59,8 +58,8 @@ func TestPodCacheGetMissing(t *testing.T) {
cache := NewPodCache(nil, nil, time.Second*1) cache := NewPodCache(nil, nil, time.Second*1)
info, err := cache.GetContainerInfo("host", "foo") info, err := cache.GetContainerInfo("host", "foo")
if err != nil { if err == nil {
t.Errorf("Unexpected error: %#v", err) t.Errorf("Unexpected non-error: %#v", err)
} }
if info != nil { if info != nil {
t.Errorf("Unexpected info: %#v", info) t.Errorf("Unexpected info: %#v", info)
@ -68,11 +67,9 @@ func TestPodCacheGetMissing(t *testing.T) {
} }
func TestPodGetContainerInfo(t *testing.T) { func TestPodGetContainerInfo(t *testing.T) {
pod := api.Pod{ expected := docker.Container{ID: "foo"}
JSONBase: api.JSONBase{ID: "foo"},
}
fake := FakeContainerInfo{ fake := FakeContainerInfo{
data: pod, data: &expected,
} }
cache := NewPodCache(&fake, nil, time.Second*1) cache := NewPodCache(&fake, nil, time.Second*1)
@ -86,8 +83,8 @@ func TestPodGetContainerInfo(t *testing.T) {
if err != nil { if err != nil {
t.Errorf("Unexpected error: %#v", err) t.Errorf("Unexpected error: %#v", err)
} }
if !reflect.DeepEqual(info, pod) { if !reflect.DeepEqual(info, &expected) {
t.Errorf("Unexpected mismatch. Expected: %#v, Got: #%v", pod, info) t.Errorf("Unexpected mismatch. Expected: %#v, Got: #%v", &expected, info)
} }
} }
@ -98,10 +95,13 @@ func TestPodUpdateAllContainers(t *testing.T) {
Host: "machine", Host: "machine",
}, },
} }
pods := []api.Pod{pod} pods := []api.Pod{pod}
mockRegistry := registry.MakeMockPodRegistry(pods) mockRegistry := registry.MakeMockPodRegistry(pods)
expected := docker.Container{ID: "foo"}
fake := FakeContainerInfo{ fake := FakeContainerInfo{
data: pod, data: &expected,
} }
cache := NewPodCache(&fake, mockRegistry, time.Second*1) cache := NewPodCache(&fake, mockRegistry, time.Second*1)
@ -115,7 +115,7 @@ func TestPodUpdateAllContainers(t *testing.T) {
if err != nil { if err != nil {
t.Errorf("Unexpected error: %#v", err) t.Errorf("Unexpected error: %#v", err)
} }
if !reflect.DeepEqual(info, pod) { if !reflect.DeepEqual(info, &expected) {
t.Errorf("Unexpected mismatch. Expected: %#v, Got: #%v", pod, info) t.Errorf("Unexpected mismatch. Expected: %#v, Got: #%v", &expected, info)
} }
} }

View File

@ -27,6 +27,7 @@ import (
"github.com/GoogleCloudPlatform/kubernetes/pkg/cloudprovider" "github.com/GoogleCloudPlatform/kubernetes/pkg/cloudprovider"
"github.com/GoogleCloudPlatform/kubernetes/pkg/labels" "github.com/GoogleCloudPlatform/kubernetes/pkg/labels"
"github.com/GoogleCloudPlatform/kubernetes/pkg/scheduler" "github.com/GoogleCloudPlatform/kubernetes/pkg/scheduler"
"github.com/fsouza/go-dockerclient"
"github.com/golang/glog" "github.com/golang/glog"
) )
@ -71,34 +72,62 @@ func (storage *PodRegistryStorage) List(selector labels.Selector) (interface{},
pods, err := storage.registry.ListPods(selector) pods, err := storage.registry.ListPods(selector)
if err == nil { if err == nil {
result.Items = pods result.Items = pods
// Get cached info for the list currently. for i := range result.Items {
// TODO: Optionally use fresh info storage.fillPodInfo(&result.Items[i])
if storage.podCache != nil {
for ix, pod := range pods {
info, err := storage.podCache.GetContainerInfo(pod.CurrentState.Host, pod.ID)
if err != nil {
glog.Errorf("Error getting container info: %#v", err)
continue
}
result.Items[ix].CurrentState.Info = info
}
} }
} }
return result, err return result, err
} }
func makePodStatus(info interface{}) api.PodStatus { func (storage *PodRegistryStorage) fillPodInfo(pod *api.Pod) {
if state, ok := info.(map[string]interface{})["State"]; ok { // Get cached info for the list currently.
if running, ok := state.(map[string]interface{})["Running"]; ok { // TODO: Optionally use fresh info
if running.(bool) { if storage.podCache != nil {
return api.PodRunning pod.CurrentState.Info = map[string]docker.Container{}
} else { infoMap := pod.CurrentState.Info
return api.PodStopped
for _, container := range pod.DesiredState.Manifest.Containers {
// TODO: clearly need to pass both pod ID and container name here.
info, err := storage.podCache.GetContainerInfo(pod.CurrentState.Host, pod.ID)
if err != nil {
glog.Errorf("Error getting container info: %#v", err)
continue
} }
infoMap[container.Name] = *info
} }
} }
return api.PodPending }
func makePodStatus(pod *api.Pod) api.PodStatus {
if pod.CurrentState.Info == nil {
return api.PodPending
}
running := 0
stopped := 0
unknown := 0
for _, container := range pod.DesiredState.Manifest.Containers {
if info, ok := pod.CurrentState.Info[container.Name]; ok {
if info.State.Running {
running++
} else {
stopped++
}
} else {
unknown++
}
}
switch {
case running > 0 && stopped == 0 && unknown == 0:
return api.PodRunning
case running == 0 && stopped > 0 && unknown == 0:
return api.PodStopped
case running == 0 && stopped == 0 && unknown > 0:
return api.PodPending
default:
return api.PodPending
}
} }
func getInstanceIP(cloud cloudprovider.Interface, host string) string { func getInstanceIP(cloud cloudprovider.Interface, host string) string {
@ -130,12 +159,8 @@ func (storage *PodRegistryStorage) Get(id string) (interface{}, error) {
return pod, nil return pod, nil
} }
if storage.containerInfo != nil { if storage.containerInfo != nil {
info, err := storage.containerInfo.GetContainerInfo(pod.CurrentState.Host, id) storage.fillPodInfo(pod)
if err != nil { pod.CurrentState.Status = makePodStatus(pod)
return pod, err
}
pod.CurrentState.Info = info
pod.CurrentState.Status = makePodStatus(info)
} }
pod.CurrentState.HostIP = getInstanceIP(storage.cloud, pod.CurrentState.Host) pod.CurrentState.HostIP = getInstanceIP(storage.cloud, pod.CurrentState.Host)

View File

@ -26,6 +26,7 @@ import (
"github.com/GoogleCloudPlatform/kubernetes/pkg/cloudprovider" "github.com/GoogleCloudPlatform/kubernetes/pkg/cloudprovider"
"github.com/GoogleCloudPlatform/kubernetes/pkg/labels" "github.com/GoogleCloudPlatform/kubernetes/pkg/labels"
"github.com/GoogleCloudPlatform/kubernetes/pkg/scheduler" "github.com/GoogleCloudPlatform/kubernetes/pkg/scheduler"
"github.com/fsouza/go-dockerclient"
) )
func expectNoError(t *testing.T, err error) { func expectNoError(t *testing.T, err error) {
@ -153,29 +154,88 @@ func TestGetPodCloud(t *testing.T) {
} }
func TestMakePodStatus(t *testing.T) { func TestMakePodStatus(t *testing.T) {
status := makePodStatus(map[string]interface{}{}) desiredState := api.PodState{
Manifest: api.ContainerManifest{
Containers: []api.Container{
{Name: "containerA"},
{Name: "containerB"},
},
},
}
pod := &api.Pod{DesiredState: desiredState}
status := makePodStatus(pod)
if status != api.PodPending { if status != api.PodPending {
t.Errorf("Expected 'Pending', got '%s'", status) t.Errorf("Expected 'Pending', got '%s'", status)
} }
status = makePodStatus(map[string]interface{}{ runningState := docker.Container{
"State": map[string]interface{}{ State: docker.State{
"Running": false, Running: true,
}, },
}) }
stoppedState := docker.Container{
State: docker.State{
Running: false,
},
}
// All running.
pod = &api.Pod{
DesiredState: desiredState,
CurrentState: api.PodState{
Info: map[string]docker.Container{
"containerA": runningState,
"containerB": runningState,
},
},
}
status = makePodStatus(pod)
if status != api.PodRunning {
t.Errorf("Expected 'Running', got '%s'", status)
}
// All stopped.
pod = &api.Pod{
DesiredState: desiredState,
CurrentState: api.PodState{
Info: map[string]docker.Container{
"containerA": stoppedState,
"containerB": stoppedState,
},
},
}
status = makePodStatus(pod)
if status != api.PodStopped { if status != api.PodStopped {
t.Errorf("Expected 'Stopped', got '%s'", status) t.Errorf("Expected 'Stopped', got '%s'", status)
} }
status = makePodStatus(map[string]interface{}{ // Mixed state.
"State": map[string]interface{}{ pod = &api.Pod{
"Running": true, DesiredState: desiredState,
CurrentState: api.PodState{
Info: map[string]docker.Container{
"containerA": runningState,
"containerB": stoppedState,
},
}, },
}) }
status = makePodStatus(pod)
if status != api.PodPending {
t.Errorf("Expected 'Pending', got '%s'", status)
}
if status != api.PodRunning { // Mixed state.
t.Errorf("Expected 'Running', got '%s'", status) pod = &api.Pod{
DesiredState: desiredState,
CurrentState: api.PodState{
Info: map[string]docker.Container{
"containerA": runningState,
},
},
}
status = makePodStatus(pod)
if status != api.PodPending {
t.Errorf("Expected 'Pending', got '%s'", status)
} }
} }