mirror of
https://github.com/k3s-io/kubernetes.git
synced 2025-08-04 01:40:07 +00:00
Merge pull request #5730 from yujuhong/static_stats
Kubelet: support retrieving stats using UID of mirror pods
This commit is contained in:
commit
4d2e7981bb
@ -95,7 +95,7 @@ type SyncHandler interface {
|
|||||||
// Syncs current state to match the specified pods. SyncPodType specified what
|
// Syncs current state to match the specified pods. SyncPodType specified what
|
||||||
// type of sync is occuring per pod. StartTime specifies the time at which
|
// type of sync is occuring per pod. StartTime specifies the time at which
|
||||||
// syncing began (for use in monitoring).
|
// syncing began (for use in monitoring).
|
||||||
SyncPods(pods []api.Pod, podSyncTypes map[types.UID]metrics.SyncPodType, mirrorPods util.StringSet,
|
SyncPods(pods []api.Pod, podSyncTypes map[types.UID]metrics.SyncPodType, mirrorPods mirrorPods,
|
||||||
startTime time.Time) error
|
startTime time.Time) error
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -267,7 +267,7 @@ type Kubelet struct {
|
|||||||
// similar to pods, this is not immutable and is protected by the same podLock.
|
// similar to pods, this is not immutable and is protected by the same podLock.
|
||||||
// Note that Kubelet.pods do not contain mirror pods as they are filtered
|
// Note that Kubelet.pods do not contain mirror pods as they are filtered
|
||||||
// out beforehand.
|
// out beforehand.
|
||||||
mirrorPods util.StringSet
|
mirrorPods mirrorPods
|
||||||
|
|
||||||
// A pod status cache stores statuses for pods (both rejected and synced).
|
// A pod status cache stores statuses for pods (both rejected and synced).
|
||||||
// Note that currently no thread attempts to acquire podStatusesLock while
|
// Note that currently no thread attempts to acquire podStatusesLock while
|
||||||
@ -1488,7 +1488,7 @@ func (kl *Kubelet) cleanupOrphanedVolumes(pods []api.Pod, running []*docker.Cont
|
|||||||
}
|
}
|
||||||
|
|
||||||
// SyncPods synchronizes the configured list of pods (desired state) with the host current state.
|
// SyncPods synchronizes the configured list of pods (desired state) with the host current state.
|
||||||
func (kl *Kubelet) SyncPods(allPods []api.Pod, podSyncTypes map[types.UID]metrics.SyncPodType, mirrorPods util.StringSet, start time.Time) error {
|
func (kl *Kubelet) SyncPods(allPods []api.Pod, podSyncTypes map[types.UID]metrics.SyncPodType, mirrorPods mirrorPods, start time.Time) error {
|
||||||
defer func() {
|
defer func() {
|
||||||
metrics.SyncPodsLatency.Observe(metrics.SinceInMicroseconds(start))
|
metrics.SyncPodsLatency.Observe(metrics.SinceInMicroseconds(start))
|
||||||
}()
|
}()
|
||||||
@ -1536,7 +1536,7 @@ func (kl *Kubelet) SyncPods(allPods []api.Pod, podSyncTypes map[types.UID]metric
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Run the sync in an async manifest worker.
|
// Run the sync in an async manifest worker.
|
||||||
kl.podWorkers.UpdatePod(pod, kl.mirrorPods.Has(podFullName), func() {
|
kl.podWorkers.UpdatePod(pod, kl.mirrorPods.HasMirrorPod(uid), func() {
|
||||||
metrics.SyncPodLatency.WithLabelValues(podSyncTypes[pod.UID].String()).Observe(metrics.SinceInMicroseconds(start))
|
metrics.SyncPodLatency.WithLabelValues(podSyncTypes[pod.UID].String()).Observe(metrics.SinceInMicroseconds(start))
|
||||||
})
|
})
|
||||||
|
|
||||||
@ -1606,7 +1606,7 @@ func (kl *Kubelet) SyncPods(allPods []api.Pod, podSyncTypes map[types.UID]metric
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Remove any orphaned mirror pods.
|
// Remove any orphaned mirror pods.
|
||||||
deleteOrphanedMirrorPods(pods, mirrorPods, kl.mirrorManager)
|
deleteOrphanedMirrorPods(mirrorPods, kl.mirrorManager)
|
||||||
|
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@ -1885,7 +1885,7 @@ func (kl *Kubelet) GetHostname() string {
|
|||||||
|
|
||||||
// GetPods returns all pods bound to the kubelet and their spec, and the mirror
|
// GetPods returns all pods bound to the kubelet and their spec, and the mirror
|
||||||
// pod map.
|
// pod map.
|
||||||
func (kl *Kubelet) GetPods() ([]api.Pod, util.StringSet) {
|
func (kl *Kubelet) GetPods() ([]api.Pod, mirrorPods) {
|
||||||
kl.podLock.RLock()
|
kl.podLock.RLock()
|
||||||
defer kl.podLock.RUnlock()
|
defer kl.podLock.RUnlock()
|
||||||
return append([]api.Pod{}, kl.pods...), kl.mirrorPods
|
return append([]api.Pod{}, kl.pods...), kl.mirrorPods
|
||||||
@ -2057,6 +2057,8 @@ func getPodReadyCondition(spec *api.PodSpec, info api.PodInfo) []api.PodConditio
|
|||||||
|
|
||||||
// GetPodStatus returns information from Docker about the containers in a pod
|
// GetPodStatus returns information from Docker about the containers in a pod
|
||||||
func (kl *Kubelet) GetPodStatus(podFullName string, uid types.UID) (api.PodStatus, error) {
|
func (kl *Kubelet) GetPodStatus(podFullName string, uid types.UID) (api.PodStatus, error) {
|
||||||
|
uid = kl.translatePodUID(uid)
|
||||||
|
|
||||||
// Check to see if we have a cached version of the status.
|
// Check to see if we have a cached version of the status.
|
||||||
cachedPodStatus, found := kl.getPodStatusFromCache(podFullName)
|
cachedPodStatus, found := kl.getPodStatusFromCache(podFullName)
|
||||||
if found {
|
if found {
|
||||||
@ -2119,6 +2121,8 @@ func (kl *Kubelet) ServeLogs(w http.ResponseWriter, req *http.Request) {
|
|||||||
|
|
||||||
// Run a command in a container, returns the combined stdout, stderr as an array of bytes
|
// Run a command in a container, returns the combined stdout, stderr as an array of bytes
|
||||||
func (kl *Kubelet) RunInContainer(podFullName string, uid types.UID, container string, cmd []string) ([]byte, error) {
|
func (kl *Kubelet) RunInContainer(podFullName string, uid types.UID, container string, cmd []string) ([]byte, error) {
|
||||||
|
uid = kl.translatePodUID(uid)
|
||||||
|
|
||||||
if kl.runner == nil {
|
if kl.runner == nil {
|
||||||
return nil, fmt.Errorf("no runner specified.")
|
return nil, fmt.Errorf("no runner specified.")
|
||||||
}
|
}
|
||||||
@ -2136,6 +2140,8 @@ func (kl *Kubelet) RunInContainer(podFullName string, uid types.UID, container s
|
|||||||
// ExecInContainer executes a command in a container, connecting the supplied
|
// ExecInContainer executes a command in a container, connecting the supplied
|
||||||
// stdin/stdout/stderr to the command's IO streams.
|
// stdin/stdout/stderr to the command's IO streams.
|
||||||
func (kl *Kubelet) ExecInContainer(podFullName string, uid types.UID, container string, cmd []string, stdin io.Reader, stdout, stderr io.WriteCloser, tty bool) error {
|
func (kl *Kubelet) ExecInContainer(podFullName string, uid types.UID, container string, cmd []string, stdin io.Reader, stdout, stderr io.WriteCloser, tty bool) error {
|
||||||
|
uid = kl.translatePodUID(uid)
|
||||||
|
|
||||||
if kl.runner == nil {
|
if kl.runner == nil {
|
||||||
return fmt.Errorf("no runner specified.")
|
return fmt.Errorf("no runner specified.")
|
||||||
}
|
}
|
||||||
@ -2153,6 +2159,8 @@ func (kl *Kubelet) ExecInContainer(podFullName string, uid types.UID, container
|
|||||||
// PortForward connects to the pod's port and copies data between the port
|
// PortForward connects to the pod's port and copies data between the port
|
||||||
// and the stream.
|
// and the stream.
|
||||||
func (kl *Kubelet) PortForward(podFullName string, uid types.UID, port uint16, stream io.ReadWriteCloser) error {
|
func (kl *Kubelet) PortForward(podFullName string, uid types.UID, port uint16, stream io.ReadWriteCloser) error {
|
||||||
|
uid = kl.translatePodUID(uid)
|
||||||
|
|
||||||
if kl.runner == nil {
|
if kl.runner == nil {
|
||||||
return fmt.Errorf("no runner specified.")
|
return fmt.Errorf("no runner specified.")
|
||||||
}
|
}
|
||||||
@ -2185,8 +2193,30 @@ func (kl *Kubelet) StreamingConnectionIdleTimeout() time.Duration {
|
|||||||
return kl.streamingConnectionIdleTimeout
|
return kl.streamingConnectionIdleTimeout
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// If the UID belongs to a mirror pod, maps it to the UID of its static pod.
|
||||||
|
// Otherwise, return the original UID. All public-facing functions should
|
||||||
|
// perform this translation for UIDs because user may provide a mirror pod UID,
|
||||||
|
// which is not recognized by internal Kubelet functions.
|
||||||
|
func (kl *Kubelet) translatePodUID(uid types.UID) types.UID {
|
||||||
|
if uid == "" {
|
||||||
|
return uid
|
||||||
|
}
|
||||||
|
|
||||||
|
kl.podLock.RLock()
|
||||||
|
defer kl.podLock.RUnlock()
|
||||||
|
staticUID, ok := kl.mirrorPods.GetStaticUID(uid)
|
||||||
|
if ok {
|
||||||
|
return staticUID
|
||||||
|
} else {
|
||||||
|
return uid
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// GetContainerInfo returns stats (from Cadvisor) for a container.
|
// GetContainerInfo returns stats (from Cadvisor) for a container.
|
||||||
func (kl *Kubelet) GetContainerInfo(podFullName string, uid types.UID, containerName string, req *cadvisorApi.ContainerInfoRequest) (*cadvisorApi.ContainerInfo, error) {
|
func (kl *Kubelet) GetContainerInfo(podFullName string, uid types.UID, containerName string, req *cadvisorApi.ContainerInfoRequest) (*cadvisorApi.ContainerInfo, error) {
|
||||||
|
|
||||||
|
uid = kl.translatePodUID(uid)
|
||||||
|
|
||||||
dockerContainers, err := dockertools.GetKubeletDockerContainers(kl.dockerClient, false)
|
dockerContainers, err := dockertools.GetKubeletDockerContainers(kl.dockerClient, false)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
|
@ -447,7 +447,7 @@ func TestSyncPodsDoesNothing(t *testing.T) {
|
|||||||
},
|
},
|
||||||
}
|
}
|
||||||
waitGroup.Add(1)
|
waitGroup.Add(1)
|
||||||
err := kubelet.SyncPods(kubelet.pods, emptyPodUIDs, util.NewStringSet(), time.Now())
|
err := kubelet.SyncPods(kubelet.pods, emptyPodUIDs, *newMirrorPods(), time.Now())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Errorf("unexpected error: %v", err)
|
t.Errorf("unexpected error: %v", err)
|
||||||
}
|
}
|
||||||
@ -481,7 +481,7 @@ func TestSyncPodsWithTerminationLog(t *testing.T) {
|
|||||||
},
|
},
|
||||||
}
|
}
|
||||||
waitGroup.Add(1)
|
waitGroup.Add(1)
|
||||||
err := kubelet.SyncPods(kubelet.pods, emptyPodUIDs, util.NewStringSet(), time.Now())
|
err := kubelet.SyncPods(kubelet.pods, emptyPodUIDs, *newMirrorPods(), time.Now())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Errorf("unexpected error: %v", err)
|
t.Errorf("unexpected error: %v", err)
|
||||||
}
|
}
|
||||||
@ -531,7 +531,7 @@ func TestSyncPodsCreatesNetAndContainer(t *testing.T) {
|
|||||||
},
|
},
|
||||||
}
|
}
|
||||||
waitGroup.Add(1)
|
waitGroup.Add(1)
|
||||||
err := kubelet.SyncPods(kubelet.pods, emptyPodUIDs, util.NewStringSet(), time.Now())
|
err := kubelet.SyncPods(kubelet.pods, emptyPodUIDs, *newMirrorPods(), time.Now())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Errorf("unexpected error: %v", err)
|
t.Errorf("unexpected error: %v", err)
|
||||||
}
|
}
|
||||||
@ -585,7 +585,7 @@ func TestSyncPodsCreatesNetAndContainerPullsImage(t *testing.T) {
|
|||||||
},
|
},
|
||||||
}
|
}
|
||||||
waitGroup.Add(1)
|
waitGroup.Add(1)
|
||||||
err := kubelet.SyncPods(kubelet.pods, emptyPodUIDs, util.NewStringSet(), time.Now())
|
err := kubelet.SyncPods(kubelet.pods, emptyPodUIDs, *newMirrorPods(), time.Now())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Errorf("unexpected error: %v", err)
|
t.Errorf("unexpected error: %v", err)
|
||||||
}
|
}
|
||||||
@ -636,7 +636,7 @@ func TestSyncPodsWithPodInfraCreatesContainer(t *testing.T) {
|
|||||||
},
|
},
|
||||||
}
|
}
|
||||||
waitGroup.Add(1)
|
waitGroup.Add(1)
|
||||||
err := kubelet.SyncPods(kubelet.pods, emptyPodUIDs, util.NewStringSet(), time.Now())
|
err := kubelet.SyncPods(kubelet.pods, emptyPodUIDs, *newMirrorPods(), time.Now())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Errorf("unexpected error: %v", err)
|
t.Errorf("unexpected error: %v", err)
|
||||||
}
|
}
|
||||||
@ -694,7 +694,7 @@ func TestSyncPodsWithPodInfraCreatesContainerCallsHandler(t *testing.T) {
|
|||||||
},
|
},
|
||||||
}
|
}
|
||||||
waitGroup.Add(1)
|
waitGroup.Add(1)
|
||||||
err := kubelet.SyncPods(kubelet.pods, emptyPodUIDs, util.NewStringSet(), time.Now())
|
err := kubelet.SyncPods(kubelet.pods, emptyPodUIDs, *newMirrorPods(), time.Now())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Errorf("unexpected error: %v", err)
|
t.Errorf("unexpected error: %v", err)
|
||||||
}
|
}
|
||||||
@ -764,7 +764,7 @@ func TestSyncPodsDeletesWithNoPodInfraContainer(t *testing.T) {
|
|||||||
},
|
},
|
||||||
}
|
}
|
||||||
waitGroup.Add(2)
|
waitGroup.Add(2)
|
||||||
err := kubelet.SyncPods(kubelet.pods, emptyPodUIDs, util.NewStringSet(), time.Now())
|
err := kubelet.SyncPods(kubelet.pods, emptyPodUIDs, *newMirrorPods(), time.Now())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Errorf("unexpected error: %v", err)
|
t.Errorf("unexpected error: %v", err)
|
||||||
}
|
}
|
||||||
@ -805,7 +805,7 @@ func TestSyncPodsDeletesWhenSourcesAreReady(t *testing.T) {
|
|||||||
ID: "9876",
|
ID: "9876",
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
if err := kubelet.SyncPods([]api.Pod{}, emptyPodUIDs, util.NewStringSet(), time.Now()); err != nil {
|
if err := kubelet.SyncPods([]api.Pod{}, emptyPodUIDs, *newMirrorPods(), time.Now()); err != nil {
|
||||||
t.Errorf("unexpected error: %v", err)
|
t.Errorf("unexpected error: %v", err)
|
||||||
}
|
}
|
||||||
// Validate nothing happened.
|
// Validate nothing happened.
|
||||||
@ -813,7 +813,7 @@ func TestSyncPodsDeletesWhenSourcesAreReady(t *testing.T) {
|
|||||||
fakeDocker.ClearCalls()
|
fakeDocker.ClearCalls()
|
||||||
|
|
||||||
ready = true
|
ready = true
|
||||||
if err := kubelet.SyncPods([]api.Pod{}, emptyPodUIDs, util.NewStringSet(), time.Now()); err != nil {
|
if err := kubelet.SyncPods([]api.Pod{}, emptyPodUIDs, *newMirrorPods(), time.Now()); err != nil {
|
||||||
t.Errorf("unexpected error: %v", err)
|
t.Errorf("unexpected error: %v", err)
|
||||||
}
|
}
|
||||||
verifyCalls(t, fakeDocker, []string{"list", "stop", "stop", "inspect_container", "inspect_container"})
|
verifyCalls(t, fakeDocker, []string{"list", "stop", "stop", "inspect_container", "inspect_container"})
|
||||||
@ -852,7 +852,7 @@ func TestSyncPodsDeletes(t *testing.T) {
|
|||||||
ID: "4567",
|
ID: "4567",
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
err := kubelet.SyncPods([]api.Pod{}, emptyPodUIDs, util.NewStringSet(), time.Now())
|
err := kubelet.SyncPods([]api.Pod{}, emptyPodUIDs, *newMirrorPods(), time.Now())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Errorf("unexpected error: %v", err)
|
t.Errorf("unexpected error: %v", err)
|
||||||
}
|
}
|
||||||
@ -1731,7 +1731,7 @@ func TestSyncPodsWithPullPolicy(t *testing.T) {
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
}, emptyPodUIDs, util.NewStringSet(), time.Now())
|
}, emptyPodUIDs, *newMirrorPods(), time.Now())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Errorf("unexpected error: %v", err)
|
t.Errorf("unexpected error: %v", err)
|
||||||
}
|
}
|
||||||
@ -2936,7 +2936,7 @@ func TestPurgingObsoleteStatusMapEntries(t *testing.T) {
|
|||||||
t.Fatalf("expected length of status map to be 1. Got map %#v.", kl.podStatuses)
|
t.Fatalf("expected length of status map to be 1. Got map %#v.", kl.podStatuses)
|
||||||
}
|
}
|
||||||
// Sync with empty pods so that the entry in status map will be removed.
|
// Sync with empty pods so that the entry in status map will be removed.
|
||||||
kl.SyncPods([]api.Pod{}, emptyPodUIDs, util.NewStringSet(), time.Now())
|
kl.SyncPods([]api.Pod{}, emptyPodUIDs, *newMirrorPods(), time.Now())
|
||||||
if len(kl.podStatuses) != 0 {
|
if len(kl.podStatuses) != 0 {
|
||||||
t.Fatalf("expected length of status map to be 0. Got map %#v.", kl.podStatuses)
|
t.Fatalf("expected length of status map to be 0. Got map %#v.", kl.podStatuses)
|
||||||
}
|
}
|
||||||
@ -3183,23 +3183,119 @@ func TestDeleteOrphanedMirrorPods(t *testing.T) {
|
|||||||
testKubelet.fakeCadvisor.On("MachineInfo").Return(&cadvisorApi.MachineInfo{}, nil)
|
testKubelet.fakeCadvisor.On("MachineInfo").Return(&cadvisorApi.MachineInfo{}, nil)
|
||||||
kl := testKubelet.kubelet
|
kl := testKubelet.kubelet
|
||||||
manager := testKubelet.fakeMirrorManager
|
manager := testKubelet.fakeMirrorManager
|
||||||
orphanedPodNames := []string{"pod1_ns", "pod2_ns"}
|
orphanPods := []api.Pod{
|
||||||
mirrorPods := util.NewStringSet()
|
{
|
||||||
for _, name := range orphanedPodNames {
|
ObjectMeta: api.ObjectMeta{
|
||||||
mirrorPods.Insert(name)
|
UID: "12345678",
|
||||||
|
Name: "pod1",
|
||||||
|
Namespace: "ns",
|
||||||
|
Annotations: map[string]string{
|
||||||
|
ConfigSourceAnnotationKey: "api",
|
||||||
|
ConfigMirrorAnnotationKey: "mirror",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
ObjectMeta: api.ObjectMeta{
|
||||||
|
UID: "12345679",
|
||||||
|
Name: "pod2",
|
||||||
|
Namespace: "ns",
|
||||||
|
Annotations: map[string]string{
|
||||||
|
ConfigSourceAnnotationKey: "api",
|
||||||
|
ConfigMirrorAnnotationKey: "mirror",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
mirrorPods := newMirrorPods()
|
||||||
|
for _, pod := range orphanPods {
|
||||||
|
mirrorPods.Insert(&pod)
|
||||||
}
|
}
|
||||||
// Sync with an empty pod list to delete all mirror pods.
|
// Sync with an empty pod list to delete all mirror pods.
|
||||||
err := kl.SyncPods([]api.Pod{}, emptyPodUIDs, mirrorPods, time.Now())
|
err := kl.SyncPods([]api.Pod{}, emptyPodUIDs, *mirrorPods, time.Now())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Errorf("unexpected error: %v", err)
|
t.Errorf("unexpected error: %v", err)
|
||||||
}
|
}
|
||||||
if manager.NumOfPods() != 0 {
|
if manager.NumOfPods() != 0 {
|
||||||
t.Errorf("expected zero mirror pods, got %v", manager.GetPods())
|
t.Errorf("expected zero mirror pods, got %v", manager.GetPods())
|
||||||
}
|
}
|
||||||
for _, name := range orphanedPodNames {
|
for _, pod := range orphanPods {
|
||||||
|
name := GetPodFullName(&pod)
|
||||||
creates, deletes := manager.GetCounts(name)
|
creates, deletes := manager.GetCounts(name)
|
||||||
if creates != 0 || deletes != 1 {
|
if creates != 0 || deletes != 1 {
|
||||||
t.Errorf("expected 0 creation and one deletion of %q, got %d, %d", name, creates, deletes)
|
t.Errorf("expected 0 creation and one deletion of %q, got %d, %d", name, creates, deletes)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestGetContainerInfoForMirrorPods(t *testing.T) {
|
||||||
|
// pods contain one static and one mirror pod with the same name but
|
||||||
|
// different UIDs.
|
||||||
|
pods := []api.Pod{
|
||||||
|
{
|
||||||
|
ObjectMeta: api.ObjectMeta{
|
||||||
|
UID: "1234",
|
||||||
|
Name: "qux",
|
||||||
|
Namespace: "ns",
|
||||||
|
Annotations: map[string]string{
|
||||||
|
ConfigSourceAnnotationKey: "file",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
Spec: api.PodSpec{
|
||||||
|
Containers: []api.Container{
|
||||||
|
{Name: "foo"},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
ObjectMeta: api.ObjectMeta{
|
||||||
|
UID: "5678",
|
||||||
|
Name: "qux",
|
||||||
|
Namespace: "ns",
|
||||||
|
Annotations: map[string]string{
|
||||||
|
ConfigSourceAnnotationKey: "api",
|
||||||
|
ConfigMirrorAnnotationKey: "mirror",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
Spec: api.PodSpec{
|
||||||
|
Containers: []api.Container{
|
||||||
|
{Name: "foo"},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
containerID := "ab2cdf"
|
||||||
|
containerPath := fmt.Sprintf("/docker/%v", containerID)
|
||||||
|
containerInfo := cadvisorApi.ContainerInfo{
|
||||||
|
ContainerReference: cadvisorApi.ContainerReference{
|
||||||
|
Name: containerPath,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
testKubelet := newTestKubelet(t)
|
||||||
|
kubelet := testKubelet.kubelet
|
||||||
|
fakeDocker := testKubelet.fakeDocker
|
||||||
|
mockCadvisor := testKubelet.fakeCadvisor
|
||||||
|
cadvisorReq := &cadvisorApi.ContainerInfoRequest{}
|
||||||
|
mockCadvisor.On("DockerContainer", containerID, cadvisorReq).Return(containerInfo, nil)
|
||||||
|
|
||||||
|
fakeDocker.ContainerList = []docker.APIContainers{
|
||||||
|
{
|
||||||
|
ID: containerID,
|
||||||
|
Names: []string{"/k8s_foo_qux_ns_1234_42"},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
kubelet.pods, kubelet.mirrorPods = filterAndCategorizePods(pods)
|
||||||
|
// Use the mirror pod UID to retrieve the stats.
|
||||||
|
stats, err := kubelet.GetContainerInfo("qux_ns", "5678", "foo", cadvisorReq)
|
||||||
|
if err != nil {
|
||||||
|
t.Errorf("unexpected error: %v", err)
|
||||||
|
}
|
||||||
|
if stats == nil {
|
||||||
|
t.Fatalf("stats should not be nil")
|
||||||
|
}
|
||||||
|
mockCadvisor.AssertExpectations(t)
|
||||||
|
}
|
||||||
|
@ -21,7 +21,7 @@ import (
|
|||||||
|
|
||||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/api"
|
"github.com/GoogleCloudPlatform/kubernetes/pkg/api"
|
||||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/client"
|
"github.com/GoogleCloudPlatform/kubernetes/pkg/client"
|
||||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/util"
|
"github.com/GoogleCloudPlatform/kubernetes/pkg/types"
|
||||||
"github.com/golang/glog"
|
"github.com/golang/glog"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -86,17 +86,12 @@ func (self *basicMirrorManager) DeleteMirrorPod(podFullName string) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Delete all orphaned mirror pods.
|
// Delete all orphaned mirror pods.
|
||||||
func deleteOrphanedMirrorPods(pods []api.Pod, mirrorPods util.StringSet, manager mirrorManager) {
|
func deleteOrphanedMirrorPods(mirrorPods mirrorPods, manager mirrorManager) {
|
||||||
existingPods := util.NewStringSet()
|
podFullNames := mirrorPods.GetOrphanedMirrorPodNames()
|
||||||
for _, pod := range pods {
|
for _, podFullName := range podFullNames {
|
||||||
existingPods.Insert(GetPodFullName(&pod))
|
|
||||||
}
|
|
||||||
for podFullName := range mirrorPods {
|
|
||||||
if !existingPods.Has(podFullName) {
|
|
||||||
manager.DeleteMirrorPod(podFullName)
|
manager.DeleteMirrorPod(podFullName)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
// Helper functions.
|
// Helper functions.
|
||||||
func getPodSource(pod *api.Pod) (string, error) {
|
func getPodSource(pod *api.Pod) (string, error) {
|
||||||
@ -123,16 +118,90 @@ func isMirrorPod(pod *api.Pod) bool {
|
|||||||
|
|
||||||
// This function separate the mirror pods from regular pods to
|
// This function separate the mirror pods from regular pods to
|
||||||
// facilitate pods syncing and mirror pod creation/deletion.
|
// facilitate pods syncing and mirror pod creation/deletion.
|
||||||
func filterAndCategorizePods(pods []api.Pod) ([]api.Pod, util.StringSet) {
|
func filterAndCategorizePods(pods []api.Pod) ([]api.Pod, mirrorPods) {
|
||||||
filteredPods := []api.Pod{}
|
filteredPods := []api.Pod{}
|
||||||
mirrorPods := util.NewStringSet()
|
mirrorPods := newMirrorPods()
|
||||||
|
|
||||||
for _, pod := range pods {
|
for _, pod := range pods {
|
||||||
name := GetPodFullName(&pod)
|
mirrorPods.Insert(&pod)
|
||||||
if isMirrorPod(&pod) {
|
if !isMirrorPod(&pod) {
|
||||||
mirrorPods.Insert(name)
|
|
||||||
} else {
|
|
||||||
filteredPods = append(filteredPods, pod)
|
filteredPods = append(filteredPods, pod)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return filteredPods, mirrorPods
|
return filteredPods, *mirrorPods
|
||||||
|
}
|
||||||
|
|
||||||
|
// mirrorPods is thread-compatible.
|
||||||
|
// TODO (yujuhong): Replace this with a pod manager that manages both regular
|
||||||
|
// pods and mirror pods.
|
||||||
|
type mirrorPods struct {
|
||||||
|
// Static pod UIDs indexed by pod full name.
|
||||||
|
static map[string]types.UID
|
||||||
|
// Mirror pod UIDs indexed by pod full name.
|
||||||
|
mirror map[string]types.UID
|
||||||
|
|
||||||
|
// Bi-directional UID mappings.
|
||||||
|
staticToMirror map[types.UID]types.UID
|
||||||
|
mirrorToStatic map[types.UID]types.UID
|
||||||
|
}
|
||||||
|
|
||||||
|
func newMirrorPods() *mirrorPods {
|
||||||
|
mirrorPods := mirrorPods{}
|
||||||
|
mirrorPods.static = make(map[string]types.UID)
|
||||||
|
mirrorPods.mirror = make(map[string]types.UID)
|
||||||
|
mirrorPods.staticToMirror = make(map[types.UID]types.UID)
|
||||||
|
mirrorPods.mirrorToStatic = make(map[types.UID]types.UID)
|
||||||
|
return &mirrorPods
|
||||||
|
}
|
||||||
|
|
||||||
|
func (self *mirrorPods) Insert(pod *api.Pod) {
|
||||||
|
podFullName := GetPodFullName(pod)
|
||||||
|
if isMirrorPod(pod) {
|
||||||
|
self.mirror[podFullName] = pod.UID
|
||||||
|
} else if isStaticPod(pod) {
|
||||||
|
self.static[podFullName] = pod.UID
|
||||||
|
}
|
||||||
|
staticUID, found1 := self.static[podFullName]
|
||||||
|
mirrorUID, found2 := self.mirror[podFullName]
|
||||||
|
// Update the UID mappings.
|
||||||
|
if found1 && found2 {
|
||||||
|
self.staticToMirror[staticUID] = mirrorUID
|
||||||
|
self.mirrorToStatic[mirrorUID] = staticUID
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (self *mirrorPods) HasStaticPod(key types.UID) bool {
|
||||||
|
_, ok := self.mirrorToStatic[key]
|
||||||
|
return ok
|
||||||
|
}
|
||||||
|
|
||||||
|
func (self *mirrorPods) HasMirrorPod(key types.UID) bool {
|
||||||
|
_, ok := self.staticToMirror[key]
|
||||||
|
return ok
|
||||||
|
}
|
||||||
|
|
||||||
|
func (self *mirrorPods) GetMirrorUID(key types.UID) (types.UID, bool) {
|
||||||
|
value, ok := self.staticToMirror[key]
|
||||||
|
if !ok {
|
||||||
|
return "", false
|
||||||
|
}
|
||||||
|
return value, true
|
||||||
|
}
|
||||||
|
|
||||||
|
func (self *mirrorPods) GetStaticUID(key types.UID) (types.UID, bool) {
|
||||||
|
value, ok := self.mirrorToStatic[key]
|
||||||
|
if !ok {
|
||||||
|
return "", false
|
||||||
|
}
|
||||||
|
return value, true
|
||||||
|
}
|
||||||
|
|
||||||
|
func (self *mirrorPods) GetOrphanedMirrorPodNames() []string {
|
||||||
|
orphanedPodNames := []string{}
|
||||||
|
for podFullName := range self.mirror {
|
||||||
|
if _, ok := self.static[podFullName]; !ok {
|
||||||
|
orphanedPodNames = append(orphanedPodNames, podFullName)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return orphanedPodNames
|
||||||
}
|
}
|
||||||
|
@ -121,7 +121,7 @@ func TestFilterOutMirrorPods(t *testing.T) {
|
|||||||
if !reflect.DeepEqual(expectedPods, actualPods) {
|
if !reflect.DeepEqual(expectedPods, actualPods) {
|
||||||
t.Errorf("expected %#v, got %#v", expectedPods, actualPods)
|
t.Errorf("expected %#v, got %#v", expectedPods, actualPods)
|
||||||
}
|
}
|
||||||
if !actualMirrorPods.Has(GetPodFullName(&mirrorPod)) {
|
if _, ok := actualMirrorPods.mirror[GetPodFullName(&mirrorPod)]; !ok {
|
||||||
t.Errorf("mirror pod is not recorded")
|
t.Errorf("mirror pod is not recorded")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -37,7 +37,6 @@ import (
|
|||||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/httplog"
|
"github.com/GoogleCloudPlatform/kubernetes/pkg/httplog"
|
||||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/runtime"
|
"github.com/GoogleCloudPlatform/kubernetes/pkg/runtime"
|
||||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/types"
|
"github.com/GoogleCloudPlatform/kubernetes/pkg/types"
|
||||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/util"
|
|
||||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/util/httpstream"
|
"github.com/GoogleCloudPlatform/kubernetes/pkg/util/httpstream"
|
||||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/util/httpstream/spdy"
|
"github.com/GoogleCloudPlatform/kubernetes/pkg/util/httpstream/spdy"
|
||||||
"github.com/golang/glog"
|
"github.com/golang/glog"
|
||||||
@ -83,7 +82,7 @@ type HostInterface interface {
|
|||||||
GetRootInfo(req *cadvisorApi.ContainerInfoRequest) (*cadvisorApi.ContainerInfo, error)
|
GetRootInfo(req *cadvisorApi.ContainerInfoRequest) (*cadvisorApi.ContainerInfo, error)
|
||||||
GetDockerVersion() ([]uint, error)
|
GetDockerVersion() ([]uint, error)
|
||||||
GetCachedMachineInfo() (*cadvisorApi.MachineInfo, error)
|
GetCachedMachineInfo() (*cadvisorApi.MachineInfo, error)
|
||||||
GetPods() ([]api.Pod, util.StringSet)
|
GetPods() ([]api.Pod, mirrorPods)
|
||||||
GetPodByName(namespace, name string) (*api.Pod, bool)
|
GetPodByName(namespace, name string) (*api.Pod, bool)
|
||||||
GetPodStatus(name string, uid types.UID) (api.PodStatus, error)
|
GetPodStatus(name string, uid types.UID) (api.PodStatus, error)
|
||||||
RunInContainer(name string, uid types.UID, container string, cmd []string) ([]byte, error)
|
RunInContainer(name string, uid types.UID, container string, cmd []string) ([]byte, error)
|
||||||
|
@ -33,7 +33,6 @@ import (
|
|||||||
|
|
||||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/api"
|
"github.com/GoogleCloudPlatform/kubernetes/pkg/api"
|
||||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/types"
|
"github.com/GoogleCloudPlatform/kubernetes/pkg/types"
|
||||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/util"
|
|
||||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/util/httpstream"
|
"github.com/GoogleCloudPlatform/kubernetes/pkg/util/httpstream"
|
||||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/util/httpstream/spdy"
|
"github.com/GoogleCloudPlatform/kubernetes/pkg/util/httpstream/spdy"
|
||||||
cadvisorApi "github.com/google/cadvisor/info/v1"
|
cadvisorApi "github.com/google/cadvisor/info/v1"
|
||||||
@ -45,7 +44,7 @@ type fakeKubelet struct {
|
|||||||
containerInfoFunc func(podFullName string, uid types.UID, containerName string, req *cadvisorApi.ContainerInfoRequest) (*cadvisorApi.ContainerInfo, error)
|
containerInfoFunc func(podFullName string, uid types.UID, containerName string, req *cadvisorApi.ContainerInfoRequest) (*cadvisorApi.ContainerInfo, error)
|
||||||
rootInfoFunc func(query *cadvisorApi.ContainerInfoRequest) (*cadvisorApi.ContainerInfo, error)
|
rootInfoFunc func(query *cadvisorApi.ContainerInfoRequest) (*cadvisorApi.ContainerInfo, error)
|
||||||
machineInfoFunc func() (*cadvisorApi.MachineInfo, error)
|
machineInfoFunc func() (*cadvisorApi.MachineInfo, error)
|
||||||
podsFunc func() ([]api.Pod, util.StringSet)
|
podsFunc func() ([]api.Pod, mirrorPods)
|
||||||
logFunc func(w http.ResponseWriter, req *http.Request)
|
logFunc func(w http.ResponseWriter, req *http.Request)
|
||||||
runFunc func(podFullName string, uid types.UID, containerName string, cmd []string) ([]byte, error)
|
runFunc func(podFullName string, uid types.UID, containerName string, cmd []string) ([]byte, error)
|
||||||
dockerVersionFunc func() ([]uint, error)
|
dockerVersionFunc func() ([]uint, error)
|
||||||
@ -80,7 +79,7 @@ func (fk *fakeKubelet) GetCachedMachineInfo() (*cadvisorApi.MachineInfo, error)
|
|||||||
return fk.machineInfoFunc()
|
return fk.machineInfoFunc()
|
||||||
}
|
}
|
||||||
|
|
||||||
func (fk *fakeKubelet) GetPods() ([]api.Pod, util.StringSet) {
|
func (fk *fakeKubelet) GetPods() ([]api.Pod, mirrorPods) {
|
||||||
return fk.podsFunc()
|
return fk.podsFunc()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user