mirror of
https://github.com/k3s-io/kubernetes.git
synced 2025-07-23 19:56:01 +00:00
Fix interface{} in api/types.go; plumb through system.
This commit is contained in:
parent
d523ccb428
commit
049bc6b6d4
@ -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 {
|
||||||
|
@ -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
|
||||||
}
|
}
|
||||||
|
@ -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)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -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
|
||||||
|
@ -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.")
|
||||||
|
@ -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)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -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
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -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)
|
||||||
|
|
||||||
|
@ -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)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user