kubelet: Add container reference manager.

Move the reference managing logic into container reference manager.
This enables pluggable container runtime to manage the container references.
pull/6/head
Yifan Gu 2015-03-25 21:25:08 -07:00
parent dc0fdcc6f4
commit a06bc96414
6 changed files with 103 additions and 59 deletions

View File

@ -0,0 +1,87 @@
/*
Copyright 2014 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 (
"sync"
"github.com/GoogleCloudPlatform/kubernetes/pkg/api"
)
// ContainerRefManager manages the references for the containers.
// The references are used for reporting events such as creation,
// failure, etc. This manager is thread-safe, no locks are necessary
// for the caller.
type ContainerRefManager struct {
sync.RWMutex
// TODO(yifan): To use strong type.
containerIDToRef map[string]*api.ObjectReference
}
// newContainerRefManager creates and returns a container reference manager
// with empty contents.
func newContainerRefManager() *ContainerRefManager {
c := ContainerRefManager{}
c.containerIDToRef = make(map[string]*api.ObjectReference)
return &c
}
// SetRef stores a reference to a pod's container, associating it with the given container id.
func (c *ContainerRefManager) SetRef(id string, ref *api.ObjectReference) {
c.Lock()
defer c.Unlock()
c.containerIDToRef[id] = ref
}
// ClearRef forgets the given container id and its associated container reference.
// TODO(yifan): This is currently never called. Consider to remove this function,
// or figure out when to clear the references.
func (c *ContainerRefManager) ClearRef(id string) {
c.Lock()
defer c.Unlock()
delete(c.containerIDToRef, id)
}
// GetRef returns the container reference of the given id, or (nil, false) if none is stored.
func (c *ContainerRefManager) GetRef(id string) (ref *api.ObjectReference, ok bool) {
c.RLock()
defer c.RUnlock()
ref, ok = c.containerIDToRef[id]
return ref, ok
}
// GenerateContainerRef returns an *api.ObjectReference which references the given container within the
// given pod. Returns an error if the reference can't be constructed or the container doesn't
// actually belong to the pod.
// TODO: Pods that came to us by static config or over HTTP have no selfLink set, which makes
// this fail and log an error. Figure out how we want to identify these pods to the rest of the
// system.
// TODO(yifan): Revisit this function later, for current case, it does not need to use ContainerRefManager
// as a receiver, and does not need to be exported.
func (c *ContainerRefManager) GenerateContainerRef(pod *api.Pod, container *api.Container) (*api.ObjectReference, error) {
fieldPath, err := fieldPath(pod, container)
if err != nil {
// TODO: figure out intelligent way to refer to containers that we implicitly
// start (like the pod infra container). This is not a good way, ugh.
fieldPath = "implicitly required container " + container.Name
}
ref, err := api.GetPartialReference(pod, fieldPath)
if err != nil {
return nil, err
}
return ref, nil
}

View File

@ -218,7 +218,7 @@ func NewMainKubelet(
rootDirectory: rootDirectory,
resyncInterval: resyncInterval,
podInfraContainerImage: podInfraContainerImage,
containerIDToRef: map[string]*api.ObjectReference{},
containerRefManager: newContainerRefManager(),
runner: dockertools.NewDockerContainerCommandRunner(dockerClient),
httpClient: &http.Client{},
pullQPS: pullQPS,
@ -296,8 +296,7 @@ type Kubelet struct {
// Needed to report events for containers belonging to deleted/modified pods.
// Tracks references for reporting events
containerIDToRef map[string]*api.ObjectReference
refLock sync.RWMutex
containerRefManager *ContainerRefManager
// Optional, defaults to simple Docker implementation
dockerPuller dockertools.DockerPuller
@ -685,54 +684,9 @@ func fieldPath(pod *api.Pod, container *api.Container) (string, error) {
return "", fmt.Errorf("container %#v not found in pod %#v", container, pod)
}
// containerRef returns an *api.ObjectReference which references the given container within the
// given pod. Returns an error if the reference can't be constructed or the container doesn't
// actually belong to the pod.
// TODO: Pods that came to us by static config or over HTTP have no selfLink set, which makes
// this fail and log an error. Figure out how we want to identify these pods to the rest of the
// system.
func containerRef(pod *api.Pod, container *api.Container) (*api.ObjectReference, error) {
fieldPath, err := fieldPath(pod, container)
if err != nil {
// TODO: figure out intelligent way to refer to containers that we implicitly
// start (like the pod infra container). This is not a good way, ugh.
fieldPath = "implicitly required container " + container.Name
}
ref, err := api.GetPartialReference(pod, fieldPath)
if err != nil {
return nil, err
}
return ref, nil
}
// setRef stores a reference to a pod's container, associating it with the given docker id.
func (kl *Kubelet) setRef(id string, ref *api.ObjectReference) {
kl.refLock.Lock()
defer kl.refLock.Unlock()
if kl.containerIDToRef == nil {
kl.containerIDToRef = map[string]*api.ObjectReference{}
}
kl.containerIDToRef[id] = ref
}
// clearRef forgets the given docker id and its associated container reference.
func (kl *Kubelet) clearRef(id string) {
kl.refLock.Lock()
defer kl.refLock.Unlock()
delete(kl.containerIDToRef, id)
}
// getRef returns the container reference of the given id, or (nil, false) if none is stored.
func (kl *Kubelet) getRef(id string) (ref *api.ObjectReference, ok bool) {
kl.refLock.RLock()
defer kl.refLock.RUnlock()
ref, ok = kl.containerIDToRef[id]
return ref, ok
}
// Run a single container from a pod. Returns the docker container ID
func (kl *Kubelet) runContainer(pod *api.Pod, container *api.Container, podVolumes volumeMap, netMode, ipcMode string) (id dockertools.DockerID, err error) {
ref, err := containerRef(pod, container)
ref, err := kl.containerRefManager.GenerateContainerRef(pod, container)
if err != nil {
glog.Errorf("Couldn't make a ref to pod %v, container %v: '%v'", pod.Name, container.Name, err)
}
@ -773,7 +727,7 @@ func (kl *Kubelet) runContainer(pod *api.Pod, container *api.Container, podVolum
}
// Remember this reference so we can report events about this container
if ref != nil {
kl.setRef(dockerContainer.ID, ref)
kl.containerRefManager.SetRef(dockerContainer.ID, ref)
kl.recorder.Eventf(ref, "created", "Created with docker id %v", dockerContainer.ID)
}
@ -993,7 +947,7 @@ func (kl *Kubelet) killContainerByID(ID string) error {
kl.readiness.remove(ID)
err := kl.dockerClient.StopContainer(ID, 10)
ref, ok := kl.getRef(ID)
ref, ok := kl.containerRefManager.GetRef(ID)
if !ok {
glog.Warningf("No ref for pod '%v'", ID)
} else {
@ -1043,7 +997,7 @@ func (kl *Kubelet) createPodInfraContainer(pod *api.Pod) (dockertools.DockerID,
Image: kl.podInfraContainerImage,
Ports: ports,
}
ref, err := containerRef(pod, container)
ref, err := kl.containerRefManager.GenerateContainerRef(pod, container)
if err != nil {
glog.Errorf("Couldn't make a ref to pod %v, container %v: '%v'", pod.Name, container.Name, err)
}
@ -1201,7 +1155,7 @@ func (kl *Kubelet) getPodInfraContainer(podFullName string, uid types.UID,
func (kl *Kubelet) pullImageAndRunContainer(pod *api.Pod, container *api.Container, podVolumes *volumeMap,
podInfraContainerID dockertools.DockerID) (dockertools.DockerID, error) {
podFullName := kubecontainer.GetPodFullName(pod)
ref, err := containerRef(pod, container)
ref, err := kl.containerRefManager.GenerateContainerRef(pod, container)
if err != nil {
glog.Errorf("Couldn't make a ref to pod %v, container %v: '%v'", pod.Name, container.Name, err)
}

View File

@ -110,6 +110,7 @@ func newTestKubelet(t *testing.T) *TestKubelet {
kubelet.cadvisor = mockCadvisor
podManager, fakeMirrorClient := newFakePodManager()
kubelet.podManager = podManager
kubelet.containerRefManager = newContainerRefManager()
return &TestKubelet{kubelet, fakeDocker, mockCadvisor, fakeKubeClient, waitGroup, fakeMirrorClient}
}

View File

@ -65,7 +65,7 @@ func (kl *Kubelet) probeContainer(pod *api.Pod, status api.PodStatus, container
glog.V(1).Infof("Readiness probe failed/errored: %v, %v", ready, err)
kl.readiness.set(containerID, false)
ref, ok := kl.getRef(containerID)
ref, ok := kl.containerRefManager.GetRef(containerID)
if !ok {
glog.Warningf("No ref for pod '%v' - '%v'", containerID, container.Name)
} else {

View File

@ -153,6 +153,7 @@ func makeTestKubelet(result probe.Result, err error) *Kubelet {
err: err,
},
},
containerRefManager: newContainerRefManager(),
}
}

View File

@ -74,11 +74,12 @@ func TestRunOnce(t *testing.T) {
cadvisor := &cadvisor.Mock{}
cadvisor.On("MachineInfo").Return(&cadvisorApi.MachineInfo{}, nil)
kb := &Kubelet{
rootDirectory: "/tmp/kubelet",
recorder: &record.FakeRecorder{},
cadvisor: cadvisor,
nodeLister: testNodeLister{},
statusManager: newStatusManager(nil),
rootDirectory: "/tmp/kubelet",
recorder: &record.FakeRecorder{},
cadvisor: cadvisor,
nodeLister: testNodeLister{},
statusManager: newStatusManager(nil),
containerRefManager: newContainerRefManager(),
}
kb.networkPlugin, _ = network.InitNetworkPlugin([]network.NetworkPlugin{}, "", network.NewFakeHost(nil))