Commit 9439c0f3 authored by Dawn Chen's avatar Dawn Chen

Merge pull request #5103 from yujuhong/naming

kubelet: revamp the pod/container naming scheme
parents 9e5c79a5 fe70be92
...@@ -410,7 +410,7 @@ func createAndInitKubelet(kc *KubeletConfig, pc *config.PodConfig) (*kubelet.Kub ...@@ -410,7 +410,7 @@ func createAndInitKubelet(kc *KubeletConfig, pc *config.PodConfig) (*kubelet.Kub
kc.RegistryBurst, kc.RegistryBurst,
kc.MinimumGCAge, kc.MinimumGCAge,
kc.MaxContainerCount, kc.MaxContainerCount,
pc.IsSourceSeen, pc.SeenAllSources,
kc.ClusterDomain, kc.ClusterDomain,
net.IP(kc.ClusterDNS), net.IP(kc.ClusterDNS),
kc.MasterServiceNamespace, kc.MasterServiceNamespace,
......
...@@ -18,6 +18,7 @@ package config ...@@ -18,6 +18,7 @@ package config
import ( import (
"fmt" "fmt"
"os"
"reflect" "reflect"
"sync" "sync"
...@@ -55,6 +56,10 @@ type PodConfig struct { ...@@ -55,6 +56,10 @@ type PodConfig struct {
// the channel of denormalized changes passed to listeners // the channel of denormalized changes passed to listeners
updates chan kubelet.PodUpdate updates chan kubelet.PodUpdate
// contains the list of all configured sources
sourcesLock sync.Mutex
sources util.StringSet
} }
// NewPodConfig creates an object that can merge many configuration sources into a stream // NewPodConfig creates an object that can merge many configuration sources into a stream
...@@ -66,6 +71,7 @@ func NewPodConfig(mode PodConfigNotificationMode, recorder record.EventRecorder) ...@@ -66,6 +71,7 @@ func NewPodConfig(mode PodConfigNotificationMode, recorder record.EventRecorder)
pods: storage, pods: storage,
mux: config.NewMux(storage), mux: config.NewMux(storage),
updates: updates, updates: updates,
sources: util.StringSet{},
} }
return podConfig return podConfig
} }
...@@ -73,17 +79,20 @@ func NewPodConfig(mode PodConfigNotificationMode, recorder record.EventRecorder) ...@@ -73,17 +79,20 @@ func NewPodConfig(mode PodConfigNotificationMode, recorder record.EventRecorder)
// Channel creates or returns a config source channel. The channel // Channel creates or returns a config source channel. The channel
// only accepts PodUpdates // only accepts PodUpdates
func (c *PodConfig) Channel(source string) chan<- interface{} { func (c *PodConfig) Channel(source string) chan<- interface{} {
c.sourcesLock.Lock()
defer c.sourcesLock.Unlock()
c.sources.Insert(source)
return c.mux.Channel(source) return c.mux.Channel(source)
} }
// IsSourceSeen returns true if the specified source string has previously // SeenAllSources returns true if this config has received a SET
// been marked as seen. // message from all configured sources, false otherwise.
func (c *PodConfig) IsSourceSeen(source string) bool { func (c *PodConfig) SeenAllSources() bool {
if c.pods == nil { if c.pods == nil {
return false return false
} }
glog.V(6).Infof("Looking for %v, have seen %v", source, c.pods.sourcesSeen) glog.V(6).Infof("Looking for %v, have seen %v", c.sources.List(), c.pods.sourcesSeen)
return c.pods.seenSources(source) return c.pods.seenSources(c.sources.List()...)
} }
// Updates returns a channel of updates to the configuration, properly denormalized. // Updates returns a channel of updates to the configuration, properly denormalized.
...@@ -198,7 +207,7 @@ func (s *podStorage) merge(source string, change interface{}) (adds, updates, de ...@@ -198,7 +207,7 @@ func (s *podStorage) merge(source string, change interface{}) (adds, updates, de
filtered := filterInvalidPods(update.Pods, source, s.recorder) filtered := filterInvalidPods(update.Pods, source, s.recorder)
for _, ref := range filtered { for _, ref := range filtered {
name := podUniqueName(ref) name := kubelet.GetPodFullName(ref)
if existing, found := pods[name]; found { if existing, found := pods[name]; found {
if !reflect.DeepEqual(existing.Spec, ref.Spec) { if !reflect.DeepEqual(existing.Spec, ref.Spec) {
// this is an update // this is an update
...@@ -221,7 +230,7 @@ func (s *podStorage) merge(source string, change interface{}) (adds, updates, de ...@@ -221,7 +230,7 @@ func (s *podStorage) merge(source string, change interface{}) (adds, updates, de
case kubelet.REMOVE: case kubelet.REMOVE:
glog.V(4).Infof("Removing a pod %v", update) glog.V(4).Infof("Removing a pod %v", update)
for _, value := range update.Pods { for _, value := range update.Pods {
name := podUniqueName(&value) name := kubelet.GetPodFullName(&value)
if existing, found := pods[name]; found { if existing, found := pods[name]; found {
// this is a delete // this is a delete
delete(pods, name) delete(pods, name)
...@@ -240,7 +249,7 @@ func (s *podStorage) merge(source string, change interface{}) (adds, updates, de ...@@ -240,7 +249,7 @@ func (s *podStorage) merge(source string, change interface{}) (adds, updates, de
filtered := filterInvalidPods(update.Pods, source, s.recorder) filtered := filterInvalidPods(update.Pods, source, s.recorder)
for _, ref := range filtered { for _, ref := range filtered {
name := podUniqueName(ref) name := kubelet.GetPodFullName(ref)
if existing, found := oldPods[name]; found { if existing, found := oldPods[name]; found {
pods[name] = existing pods[name] = existing
if !reflect.DeepEqual(existing.Spec, ref.Spec) { if !reflect.DeepEqual(existing.Spec, ref.Spec) {
...@@ -298,7 +307,7 @@ func filterInvalidPods(pods []api.BoundPod, source string, recorder record.Event ...@@ -298,7 +307,7 @@ func filterInvalidPods(pods []api.BoundPod, source string, recorder record.Event
// If validation fails, don't trust it any further - // If validation fails, don't trust it any further -
// even Name could be bad. // even Name could be bad.
} else { } else {
name := podUniqueName(pod) name := kubelet.GetPodFullName(pod)
if names.Has(name) { if names.Has(name) {
errlist = append(errlist, apierrs.NewFieldDuplicate("name", pod.Name)) errlist = append(errlist, apierrs.NewFieldDuplicate("name", pod.Name))
} else { } else {
...@@ -341,12 +350,6 @@ func (s *podStorage) MergedState() interface{} { ...@@ -341,12 +350,6 @@ func (s *podStorage) MergedState() interface{} {
return pods return pods
} }
// podUniqueName returns a value for a given pod that is unique across a source,
// which is the combination of namespace and name.
func podUniqueName(pod *api.BoundPod) string {
return fmt.Sprintf("%s.%s", pod.Name, pod.Namespace)
}
func bestPodIdentString(pod *api.BoundPod) string { func bestPodIdentString(pod *api.BoundPod) string {
namespace := pod.Namespace namespace := pod.Namespace
if namespace == "" { if namespace == "" {
...@@ -358,3 +361,11 @@ func bestPodIdentString(pod *api.BoundPod) string { ...@@ -358,3 +361,11 @@ func bestPodIdentString(pod *api.BoundPod) string {
} }
return fmt.Sprintf("%s.%s", name, namespace) return fmt.Sprintf("%s.%s", name, namespace)
} }
func GeneratePodName(name string) (string, error) {
hostname, err := os.Hostname() //TODO: kubelet name would be better
if err != nil {
return "", err
}
return fmt.Sprintf("%s-%s", name, hostname), nil
}
...@@ -108,11 +108,8 @@ func eventToPods(ev watch.Event) ([]api.BoundPod, error) { ...@@ -108,11 +108,8 @@ func eventToPods(ev watch.Event) ([]api.BoundPod, error) {
} }
for _, pod := range boundPods.Items { for _, pod := range boundPods.Items {
// Backwards compatibility with old api servers // Always overrides the namespace provided by the etcd event.
// TODO: Remove this after 1.0 release. pod.Namespace = kubelet.NamespaceDefault
if len(pod.Namespace) == 0 {
pod.Namespace = api.NamespaceDefault
}
pods = append(pods, pod) pods = append(pods, pod)
} }
......
...@@ -102,8 +102,14 @@ func TestEventToPods(t *testing.T) { ...@@ -102,8 +102,14 @@ func TestEventToPods(t *testing.T) {
}, },
}, },
pods: []api.BoundPod{ pods: []api.BoundPod{
{ObjectMeta: api.ObjectMeta{UID: "111", Name: "foo", Namespace: "foo"}, Spec: api.PodSpec{}}, {
{ObjectMeta: api.ObjectMeta{UID: "222", Name: "bar", Namespace: "bar"}, Spec: api.PodSpec{}}, ObjectMeta: api.ObjectMeta{UID: "111", Name: "foo", Namespace: kubelet.NamespaceDefault},
Spec: api.PodSpec{},
},
{
ObjectMeta: api.ObjectMeta{UID: "222", Name: "bar", Namespace: kubelet.NamespaceDefault},
Spec: api.PodSpec{},
},
}, },
fail: false, fail: false,
}, },
...@@ -116,7 +122,9 @@ func TestEventToPods(t *testing.T) { ...@@ -116,7 +122,9 @@ func TestEventToPods(t *testing.T) {
}, },
}, },
pods: []api.BoundPod{ pods: []api.BoundPod{
{ObjectMeta: api.ObjectMeta{UID: "111", Name: "foo", Namespace: "default"}, Spec: api.PodSpec{}}, {
ObjectMeta: api.ObjectMeta{UID: "111", Name: "foo", Namespace: kubelet.NamespaceDefault},
Spec: api.PodSpec{}},
}, },
fail: false, fail: false,
}, },
......
...@@ -21,7 +21,6 @@ import ( ...@@ -21,7 +21,6 @@ import (
"crypto/md5" "crypto/md5"
"encoding/hex" "encoding/hex"
"fmt" "fmt"
"hash/adler32"
"io/ioutil" "io/ioutil"
"os" "os"
"path/filepath" "path/filepath"
...@@ -186,17 +185,16 @@ func extractFromFile(filename string) (api.BoundPod, error) { ...@@ -186,17 +185,16 @@ func extractFromFile(filename string) (api.BoundPod, error) {
// completely deprecate ContainerManifest. // completely deprecate ContainerManifest.
if len(pod.Name) == 0 { if len(pod.Name) == 0 {
pod.Name = string(pod.UID) pod.Name = string(pod.UID)
glog.V(5).Infof("Generated Name %q for UID %q from file %s", pod.Name, pod.UID, filename)
} }
if len(pod.Namespace) == 0 { if pod.Name, err = GeneratePodName(pod.Name); err != nil {
hasher := adler32.New() return pod, err
fmt.Fprint(hasher, filename)
// TODO: file-<sum>.hostname would be better, if DNS subdomains
// are allowed for namespace (some places only allow DNS
// labels).
pod.Namespace = fmt.Sprintf("file-%08x-%s", hasher.Sum32(), hostname)
glog.V(5).Infof("Generated namespace %q for pod %q from file %s", pod.Namespace, pod.Name, filename)
} }
glog.V(5).Infof("Generated Name %q for UID %q from file %s", pod.Name, pod.UID, filename)
// Always overrides the namespace provided by the file.
pod.Namespace = kubelet.NamespaceDefault
glog.V(5).Infof("Using namespace %q for pod %q from file %s", pod.Namespace, pod.Name, filename)
// TODO(dchen1107): BoundPod is not type of runtime.Object. Once we allow kubelet talks // TODO(dchen1107): BoundPod is not type of runtime.Object. Once we allow kubelet talks
// about Pod directly, we can use SelfLinker defined in package: latest // about Pod directly, we can use SelfLinker defined in package: latest
// Currently just simply follow the same format in resthandler.go // Currently just simply follow the same format in resthandler.go
......
...@@ -54,8 +54,9 @@ func ExampleManifestAndPod(id string) (v1beta1.ContainerManifest, api.BoundPod) ...@@ -54,8 +54,9 @@ func ExampleManifestAndPod(id string) (v1beta1.ContainerManifest, api.BoundPod)
} }
expectedPod := api.BoundPod{ expectedPod := api.BoundPod{
ObjectMeta: api.ObjectMeta{ ObjectMeta: api.ObjectMeta{
Name: id, Name: id,
UID: types.UID(id), UID: types.UID(id),
Namespace: kubelet.NamespaceDefault,
}, },
Spec: api.PodSpec{ Spec: api.PodSpec{
Containers: []api.Container{ Containers: []api.Container{
...@@ -131,27 +132,30 @@ func TestReadFromFile(t *testing.T) { ...@@ -131,27 +132,30 @@ func TestReadFromFile(t *testing.T) {
update := got.(kubelet.PodUpdate) update := got.(kubelet.PodUpdate)
expected := CreatePodUpdate(kubelet.SET, kubelet.FileSource, api.BoundPod{ expected := CreatePodUpdate(kubelet.SET, kubelet.FileSource, api.BoundPod{
ObjectMeta: api.ObjectMeta{ ObjectMeta: api.ObjectMeta{
Name: "test", Name: "",
UID: "12345", UID: "12345",
Namespace: "", Namespace: kubelet.NamespaceDefault,
SelfLink: "", SelfLink: "",
}, },
Spec: api.PodSpec{Containers: []api.Container{{Image: "test/image"}}}, Spec: api.PodSpec{Containers: []api.Container{{Image: "test/image"}}},
}) })
if !strings.HasPrefix(update.Pods[0].Name, "test-") {
t.Errorf("Unexpected name: %s", update.Pods[0].Name)
}
// There's no way to provide namespace in ContainerManifest, so // There's no way to provide namespace in ContainerManifest, so
// it will be defaulted. // it will be defaulted.
if !strings.HasPrefix(update.Pods[0].ObjectMeta.Namespace, "file-") { if update.Pods[0].Namespace != kubelet.NamespaceDefault {
t.Errorf("Unexpected namespace: %s", update.Pods[0].ObjectMeta.Namespace) t.Errorf("Unexpected namespace: %s", update.Pods[0].Namespace)
} }
update.Pods[0].ObjectMeta.Namespace = ""
// SelfLink depends on namespace. // SelfLink depends on namespace.
if !strings.HasPrefix(update.Pods[0].ObjectMeta.SelfLink, "/api/") { if !strings.HasPrefix(update.Pods[0].SelfLink, "/api/") {
t.Errorf("Unexpected selflink: %s", update.Pods[0].ObjectMeta.SelfLink) t.Errorf("Unexpected selflink: %s", update.Pods[0].SelfLink)
} }
update.Pods[0].ObjectMeta.SelfLink = ""
// Reset the fileds that we don't want to compare.
update.Pods[0].Name = ""
update.Pods[0].SelfLink = ""
if !api.Semantic.DeepDerivative(expected, update) { if !api.Semantic.DeepDerivative(expected, update) {
t.Fatalf("Expected %#v, Got %#v", expected, update) t.Fatalf("Expected %#v, Got %#v", expected, update)
} }
...@@ -179,7 +183,7 @@ func TestReadFromFileWithoutID(t *testing.T) { ...@@ -179,7 +183,7 @@ func TestReadFromFileWithoutID(t *testing.T) {
ObjectMeta: api.ObjectMeta{ ObjectMeta: api.ObjectMeta{
Name: "", Name: "",
UID: "12345", UID: "12345",
Namespace: "", Namespace: kubelet.NamespaceDefault,
SelfLink: "", SelfLink: "",
}, },
Spec: api.PodSpec{Containers: []api.Container{{Image: "test/image"}}}, Spec: api.PodSpec{Containers: []api.Container{{Image: "test/image"}}},
...@@ -188,10 +192,9 @@ func TestReadFromFileWithoutID(t *testing.T) { ...@@ -188,10 +192,9 @@ func TestReadFromFileWithoutID(t *testing.T) {
if len(update.Pods[0].ObjectMeta.Name) == 0 { if len(update.Pods[0].ObjectMeta.Name) == 0 {
t.Errorf("Name did not get defaulted") t.Errorf("Name did not get defaulted")
} }
update.Pods[0].ObjectMeta.Name = "" // Reset the fileds that we don't want to compare.
update.Pods[0].ObjectMeta.Namespace = "" update.Pods[0].Name = ""
update.Pods[0].ObjectMeta.SelfLink = "" update.Pods[0].SelfLink = ""
if !api.Semantic.DeepDerivative(expected, update) { if !api.Semantic.DeepDerivative(expected, update) {
t.Fatalf("Expected %#v, Got %#v", expected, update) t.Fatalf("Expected %#v, Got %#v", expected, update)
} }
...@@ -218,17 +221,17 @@ func TestReadV1Beta2FromFile(t *testing.T) { ...@@ -218,17 +221,17 @@ func TestReadV1Beta2FromFile(t *testing.T) {
update := got.(kubelet.PodUpdate) update := got.(kubelet.PodUpdate)
expected := CreatePodUpdate(kubelet.SET, kubelet.FileSource, api.BoundPod{ expected := CreatePodUpdate(kubelet.SET, kubelet.FileSource, api.BoundPod{
ObjectMeta: api.ObjectMeta{ ObjectMeta: api.ObjectMeta{
Name: "test", Name: "",
UID: "12345", UID: "12345",
Namespace: "", Namespace: kubelet.NamespaceDefault,
SelfLink: "", SelfLink: "",
}, },
Spec: api.PodSpec{Containers: []api.Container{{Image: "test/image"}}}, Spec: api.PodSpec{Containers: []api.Container{{Image: "test/image"}}},
}) })
update.Pods[0].ObjectMeta.Namespace = "" // Reset the fileds that we don't want to compare.
update.Pods[0].ObjectMeta.SelfLink = "" update.Pods[0].Name = ""
update.Pods[0].SelfLink = ""
if !api.Semantic.DeepDerivative(expected, update) { if !api.Semantic.DeepDerivative(expected, update) {
t.Fatalf("Expected %#v, Got %#v", expected, update) t.Fatalf("Expected %#v, Got %#v", expected, update)
} }
...@@ -252,8 +255,8 @@ func TestReadFromFileWithDefaults(t *testing.T) { ...@@ -252,8 +255,8 @@ func TestReadFromFileWithDefaults(t *testing.T) {
select { select {
case got := <-ch: case got := <-ch:
update := got.(kubelet.PodUpdate) update := got.(kubelet.PodUpdate)
if update.Pods[0].ObjectMeta.UID == "" { if update.Pods[0].UID == "" {
t.Errorf("Unexpected UID: %s", update.Pods[0].ObjectMeta.UID) t.Errorf("Unexpected UID: %s", update.Pods[0].UID)
} }
case <-time.After(time.Second): case <-time.After(time.Second):
...@@ -337,12 +340,16 @@ func TestExtractFromDir(t *testing.T) { ...@@ -337,12 +340,16 @@ func TestExtractFromDir(t *testing.T) {
update := (<-ch).(kubelet.PodUpdate) update := (<-ch).(kubelet.PodUpdate)
for i := range update.Pods { for i := range update.Pods {
update.Pods[i].Namespace = "foobar" // Pod name is generated with hash and is unique. Skip the comparision
// here by setting it to a simple value.
update.Pods[i].Name = manifests[i].ID
update.Pods[i].SelfLink = "" update.Pods[i].SelfLink = ""
} }
expected := CreatePodUpdate(kubelet.SET, kubelet.FileSource, pods...) expected := CreatePodUpdate(kubelet.SET, kubelet.FileSource, pods...)
for i := range expected.Pods { for i := range expected.Pods {
expected.Pods[i].Namespace = "foobar" // Pod name is generated with hash and is unique. Skip the comparision
// here by setting it to a simple value.
expected.Pods[i].Name = manifests[i].ID
} }
sort.Sort(sortedPods(update.Pods)) sort.Sort(sortedPods(update.Pods))
sort.Sort(sortedPods(expected.Pods)) sort.Sort(sortedPods(expected.Pods))
...@@ -351,7 +358,7 @@ func TestExtractFromDir(t *testing.T) { ...@@ -351,7 +358,7 @@ func TestExtractFromDir(t *testing.T) {
} }
for i := range update.Pods { for i := range update.Pods {
if errs := validation.ValidateBoundPod(&update.Pods[i]); len(errs) != 0 { if errs := validation.ValidateBoundPod(&update.Pods[i]); len(errs) != 0 {
t.Errorf("Expected no validation errors on %#v, Got %#v", update.Pods[i], errs) t.Errorf("Expected no validation errors on %#v, Got %q", update.Pods[i], errs)
} }
} }
} }
...@@ -22,7 +22,6 @@ import ( ...@@ -22,7 +22,6 @@ import (
"crypto/md5" "crypto/md5"
"encoding/hex" "encoding/hex"
"fmt" "fmt"
"hash/adler32"
"io/ioutil" "io/ioutil"
"net/http" "net/http"
"time" "time"
...@@ -92,7 +91,9 @@ func (s *sourceURL) extractFromURL() error { ...@@ -92,7 +91,9 @@ func (s *sourceURL) extractFromURL() error {
return singleErr return singleErr
} }
// It parsed! // It parsed!
applyDefaults(&pod, s.url) if err = applyDefaults(&pod, s.url); err != nil {
return err
}
s.updates <- kubelet.PodUpdate{[]api.BoundPod{pod}, kubelet.SET, kubelet.HTTPSource} s.updates <- kubelet.PodUpdate{[]api.BoundPod{pod}, kubelet.SET, kubelet.HTTPSource}
return nil return nil
} }
...@@ -114,7 +115,9 @@ func (s *sourceURL) extractFromURL() error { ...@@ -114,7 +115,9 @@ func (s *sourceURL) extractFromURL() error {
// Assume it parsed. // Assume it parsed.
for i := range pods.Items { for i := range pods.Items {
pod := &pods.Items[i] pod := &pods.Items[i]
applyDefaults(pod, s.url) if err = applyDefaults(pod, s.url); err != nil {
return err
}
} }
s.updates <- kubelet.PodUpdate{pods.Items, kubelet.SET, kubelet.HTTPSource} s.updates <- kubelet.PodUpdate{pods.Items, kubelet.SET, kubelet.HTTPSource}
return nil return nil
...@@ -180,7 +183,7 @@ func tryDecodeList(data []byte) (parsed bool, manifests []v1beta1.ContainerManif ...@@ -180,7 +183,7 @@ func tryDecodeList(data []byte) (parsed bool, manifests []v1beta1.ContainerManif
return true, manifests, pods, nil return true, manifests, pods, nil
} }
func applyDefaults(pod *api.BoundPod, url string) { func applyDefaults(pod *api.BoundPod, url string) error {
if len(pod.UID) == 0 { if len(pod.UID) == 0 {
hasher := md5.New() hasher := md5.New()
fmt.Fprintf(hasher, "url:%s", url) fmt.Fprintf(hasher, "url:%s", url)
...@@ -190,14 +193,18 @@ func applyDefaults(pod *api.BoundPod, url string) { ...@@ -190,14 +193,18 @@ func applyDefaults(pod *api.BoundPod, url string) {
} }
// This is required for backward compatibility, and should be removed once we // This is required for backward compatibility, and should be removed once we
// completely deprecate ContainerManifest. // completely deprecate ContainerManifest.
var err error
if len(pod.Name) == 0 { if len(pod.Name) == 0 {
pod.Name = string(pod.UID) pod.Name = string(pod.UID)
glog.V(5).Infof("Generate Name %q from UID %q from URL %s", pod.Name, pod.UID, url)
} }
if len(pod.Namespace) == 0 { pod.Name, err = GeneratePodName(pod.Name)
hasher := adler32.New() if err != nil {
fmt.Fprint(hasher, url) return err
pod.Namespace = fmt.Sprintf("url-%08x", hasher.Sum32())
glog.V(5).Infof("Generated namespace %q for pod %q from URL %s", pod.Namespace, pod.Name, url)
} }
glog.V(5).Infof("Generated Name %q for UID %q from URL %s", pod.Name, pod.UID, url)
// Always overrides the namespace.
pod.Namespace = kubelet.NamespaceDefault
glog.V(5).Infof("Using namespace %q for pod %q from URL %s", pod.Namespace, pod.Name, url)
return nil
} }
...@@ -19,7 +19,7 @@ package config ...@@ -19,7 +19,7 @@ package config
import ( import (
"encoding/json" "encoding/json"
"net/http/httptest" "net/http/httptest"
"strings" "os"
"testing" "testing"
"time" "time"
...@@ -117,6 +117,8 @@ func TestExtractInvalidManifest(t *testing.T) { ...@@ -117,6 +117,8 @@ func TestExtractInvalidManifest(t *testing.T) {
} }
func TestExtractFromHTTP(t *testing.T) { func TestExtractFromHTTP(t *testing.T) {
hostname, _ := os.Hostname()
var testCases = []struct { var testCases = []struct {
desc string desc string
manifests interface{} manifests interface{}
...@@ -131,7 +133,7 @@ func TestExtractFromHTTP(t *testing.T) { ...@@ -131,7 +133,7 @@ func TestExtractFromHTTP(t *testing.T) {
api.BoundPod{ api.BoundPod{
ObjectMeta: api.ObjectMeta{ ObjectMeta: api.ObjectMeta{
UID: "111", UID: "111",
Name: "foo", Name: "foo" + "-" + hostname,
Namespace: "foobar", Namespace: "foobar",
}, },
Spec: api.PodSpec{ Spec: api.PodSpec{
...@@ -153,7 +155,7 @@ func TestExtractFromHTTP(t *testing.T) { ...@@ -153,7 +155,7 @@ func TestExtractFromHTTP(t *testing.T) {
api.BoundPod{ api.BoundPod{
ObjectMeta: api.ObjectMeta{ ObjectMeta: api.ObjectMeta{
UID: "111", UID: "111",
Name: "111", Name: "111" + "-" + hostname,
Namespace: "foobar", Namespace: "foobar",
}, },
Spec: api.PodSpec{ Spec: api.PodSpec{
...@@ -171,7 +173,7 @@ func TestExtractFromHTTP(t *testing.T) { ...@@ -171,7 +173,7 @@ func TestExtractFromHTTP(t *testing.T) {
api.BoundPod{ api.BoundPod{
ObjectMeta: api.ObjectMeta{ ObjectMeta: api.ObjectMeta{
UID: "111", UID: "111",
Name: "foo", Name: "foo" + "-" + hostname,
Namespace: "foobar", Namespace: "foobar",
}, },
Spec: api.PodSpec{ Spec: api.PodSpec{
...@@ -198,7 +200,7 @@ func TestExtractFromHTTP(t *testing.T) { ...@@ -198,7 +200,7 @@ func TestExtractFromHTTP(t *testing.T) {
api.BoundPod{ api.BoundPod{
ObjectMeta: api.ObjectMeta{ ObjectMeta: api.ObjectMeta{
UID: "111", UID: "111",
Name: "foo", Name: "foo" + "-" + hostname,
Namespace: "foobar", Namespace: "foobar",
}, },
Spec: api.PodSpec{ Spec: api.PodSpec{
...@@ -214,7 +216,7 @@ func TestExtractFromHTTP(t *testing.T) { ...@@ -214,7 +216,7 @@ func TestExtractFromHTTP(t *testing.T) {
api.BoundPod{ api.BoundPod{
ObjectMeta: api.ObjectMeta{ ObjectMeta: api.ObjectMeta{
UID: "222", UID: "222",
Name: "bar", Name: "bar" + "-" + hostname,
Namespace: "foobar", Namespace: "foobar",
}, },
Spec: api.PodSpec{ Spec: api.PodSpec{
...@@ -234,6 +236,7 @@ func TestExtractFromHTTP(t *testing.T) { ...@@ -234,6 +236,7 @@ func TestExtractFromHTTP(t *testing.T) {
expected: CreatePodUpdate(kubelet.SET, kubelet.HTTPSource), expected: CreatePodUpdate(kubelet.SET, kubelet.HTTPSource),
}, },
} }
for _, testCase := range testCases { for _, testCase := range testCases {
data, err := json.Marshal(testCase.manifests) data, err := json.Marshal(testCase.manifests)
if err != nil { if err != nil {
...@@ -256,8 +259,8 @@ func TestExtractFromHTTP(t *testing.T) { ...@@ -256,8 +259,8 @@ func TestExtractFromHTTP(t *testing.T) {
for i := range update.Pods { for i := range update.Pods {
// There's no way to provide namespace in ContainerManifest, so // There's no way to provide namespace in ContainerManifest, so
// it will be defaulted. // it will be defaulted.
if !strings.HasPrefix(update.Pods[i].ObjectMeta.Namespace, "url-") { if update.Pods[i].Namespace != kubelet.NamespaceDefault {
t.Errorf("Unexpected namespace: %s", update.Pods[0].ObjectMeta.Namespace) t.Errorf("Unexpected namespace: %s", update.Pods[0].Namespace)
} }
update.Pods[i].ObjectMeta.Namespace = "foobar" update.Pods[i].ObjectMeta.Namespace = "foobar"
} }
......
...@@ -719,11 +719,11 @@ func ParseDockerName(name string) (podFullName string, podUID types.UID, contain ...@@ -719,11 +719,11 @@ func ParseDockerName(name string) (podFullName string, podUID types.UID, contain
if len(parts) == 0 || parts[0] != containerNamePrefix { if len(parts) == 0 || parts[0] != containerNamePrefix {
return return
} }
if len(parts) < 5 { if len(parts) < 6 {
// We have at least 5 fields. We may have more in the future. // We have at least 5 fields. We may have more in the future.
// Anything with less fields than this is not something we can // Anything with less fields than this is not something we can
// manage. // manage.
glog.Warningf("found a container with the %q prefix, but too few fields (%d): ", containerNamePrefix, len(parts), name) glog.Warningf("found a container with the %q prefix, but too few fields (%d): %q", containerNamePrefix, len(parts), name)
return return
} }
...@@ -739,11 +739,10 @@ func ParseDockerName(name string) (podFullName string, podUID types.UID, contain ...@@ -739,11 +739,10 @@ func ParseDockerName(name string) (podFullName string, podUID types.UID, contain
} }
// Pod fullname. // Pod fullname.
podFullName = parts[2] podFullName = parts[2] + "_" + parts[3]
// Pod UID. // Pod UID.
podUID = types.UID(parts[3]) podUID = types.UID(parts[4])
return return
} }
......
...@@ -54,11 +54,11 @@ func TestGetContainerID(t *testing.T) { ...@@ -54,11 +54,11 @@ func TestGetContainerID(t *testing.T) {
fakeDocker.ContainerList = []docker.APIContainers{ fakeDocker.ContainerList = []docker.APIContainers{
{ {
ID: "foobar", ID: "foobar",
Names: []string{"/k8s_foo_qux_1234_42"}, Names: []string{"/k8s_foo_qux_ns_1234_42"},
}, },
{ {
ID: "barbar", ID: "barbar",
Names: []string{"/k8s_bar_qux_2565_42"}, Names: []string{"/k8s_bar_qux_ns_2565_42"},
}, },
} }
fakeDocker.Container = &docker.Container{ fakeDocker.Container = &docker.Container{
...@@ -73,7 +73,7 @@ func TestGetContainerID(t *testing.T) { ...@@ -73,7 +73,7 @@ func TestGetContainerID(t *testing.T) {
t.Errorf("Expected %#v, Got %#v", fakeDocker.ContainerList, dockerContainers) t.Errorf("Expected %#v, Got %#v", fakeDocker.ContainerList, dockerContainers)
} }
verifyCalls(t, fakeDocker, []string{"list"}) verifyCalls(t, fakeDocker, []string{"list"})
dockerContainer, found, _ := dockerContainers.FindPodContainer("qux", "", "foo") dockerContainer, found, _ := dockerContainers.FindPodContainer("qux_ns", "", "foo")
if dockerContainer == nil || !found { if dockerContainer == nil || !found {
t.Errorf("Failed to find container %#v", dockerContainer) t.Errorf("Failed to find container %#v", dockerContainer)
} }
...@@ -91,7 +91,7 @@ func verifyPackUnpack(t *testing.T, podNamespace, podUID, podName, containerName ...@@ -91,7 +91,7 @@ func verifyPackUnpack(t *testing.T, podNamespace, podUID, podName, containerName
hasher := adler32.New() hasher := adler32.New()
util.DeepHashObject(hasher, *container) util.DeepHashObject(hasher, *container)
computedHash := uint64(hasher.Sum32()) computedHash := uint64(hasher.Sum32())
podFullName := fmt.Sprintf("%s.%s", podName, podNamespace) podFullName := fmt.Sprintf("%s_%s", podName, podNamespace)
name := BuildDockerName(types.UID(podUID), podFullName, container) name := BuildDockerName(types.UID(podUID), podFullName, container)
returnedPodFullName, returnedUID, returnedContainerName, hash := ParseDockerName(name) returnedPodFullName, returnedUID, returnedContainerName, hash := ParseDockerName(name)
if podFullName != returnedPodFullName || podUID != string(returnedUID) || containerName != returnedContainerName || computedHash != hash { if podFullName != returnedPodFullName || podUID != string(returnedUID) || containerName != returnedContainerName || computedHash != hash {
...@@ -111,8 +111,8 @@ func TestContainerManifestNaming(t *testing.T) { ...@@ -111,8 +111,8 @@ func TestContainerManifestNaming(t *testing.T) {
container := &api.Container{Name: "container"} container := &api.Container{Name: "container"}
podName := "foo" podName := "foo"
podNamespace := "test" podNamespace := "test"
name := fmt.Sprintf("k8s_%s_%s.%s_%s_42", container.Name, podName, podNamespace, podUID) name := fmt.Sprintf("k8s_%s_%s_%s_%s_42", container.Name, podName, podNamespace, podUID)
podFullName := fmt.Sprintf("%s.%s", podName, podNamespace) podFullName := fmt.Sprintf("%s_%s", podName, podNamespace)
returnedPodFullName, returnedPodUID, returnedContainerName, hash := ParseDockerName(name) returnedPodFullName, returnedPodUID, returnedContainerName, hash := ParseDockerName(name)
if returnedPodFullName != podFullName || string(returnedPodUID) != podUID || returnedContainerName != container.Name || hash != 0 { if returnedPodFullName != podFullName || string(returnedPodUID) != podUID || returnedContainerName != container.Name || hash != 0 {
...@@ -463,15 +463,15 @@ func TestFindContainersByPod(t *testing.T) { ...@@ -463,15 +463,15 @@ func TestFindContainersByPod(t *testing.T) {
DockerContainers{ DockerContainers{
"foobar": &docker.APIContainers{ "foobar": &docker.APIContainers{
ID: "foobar", ID: "foobar",
Names: []string{"/k8s_foo_qux_1234_42"}, Names: []string{"/k8s_foo_qux_ns_1234_42"},
}, },
"barbar": &docker.APIContainers{ "barbar": &docker.APIContainers{
ID: "barbar", ID: "barbar",
Names: []string{"/k8s_foo_qux_1234_42"}, Names: []string{"/k8s_foo_qux_ns_1234_42"},
}, },
"baz": &docker.APIContainers{ "baz": &docker.APIContainers{
ID: "baz", ID: "baz",
Names: []string{"/k8s_foo_qux_1234_42"}, Names: []string{"/k8s_foo_qux_ns_1234_42"},
}, },
}, },
types.UID("1234"), types.UID("1234"),
...@@ -479,15 +479,15 @@ func TestFindContainersByPod(t *testing.T) { ...@@ -479,15 +479,15 @@ func TestFindContainersByPod(t *testing.T) {
DockerContainers{ DockerContainers{
"foobar": &docker.APIContainers{ "foobar": &docker.APIContainers{
ID: "foobar", ID: "foobar",
Names: []string{"/k8s_foo_qux_1234_42"}, Names: []string{"/k8s_foo_qux_ns_1234_42"},
}, },
"barbar": &docker.APIContainers{ "barbar": &docker.APIContainers{
ID: "barbar", ID: "barbar",
Names: []string{"/k8s_foo_qux_1234_42"}, Names: []string{"/k8s_foo_qux_ns_1234_42"},
}, },
"baz": &docker.APIContainers{ "baz": &docker.APIContainers{
ID: "baz", ID: "baz",
Names: []string{"/k8s_foo_qux_1234_42"}, Names: []string{"/k8s_foo_qux_ns_1234_42"},
}, },
}, },
}, },
...@@ -495,15 +495,15 @@ func TestFindContainersByPod(t *testing.T) { ...@@ -495,15 +495,15 @@ func TestFindContainersByPod(t *testing.T) {
DockerContainers{ DockerContainers{
"foobar": &docker.APIContainers{ "foobar": &docker.APIContainers{
ID: "foobar", ID: "foobar",
Names: []string{"/k8s_foo_qux_1234_42"}, Names: []string{"/k8s_foo_qux_ns_1234_42"},
}, },
"barbar": &docker.APIContainers{ "barbar": &docker.APIContainers{
ID: "barbar", ID: "barbar",
Names: []string{"/k8s_foo_qux_2343_42"}, Names: []string{"/k8s_foo_qux_ns_2343_42"},
}, },
"baz": &docker.APIContainers{ "baz": &docker.APIContainers{
ID: "baz", ID: "baz",
Names: []string{"/k8s_foo_qux_1234_42"}, Names: []string{"/k8s_foo_qux_ns_1234_42"},
}, },
}, },
types.UID("1234"), types.UID("1234"),
...@@ -511,11 +511,11 @@ func TestFindContainersByPod(t *testing.T) { ...@@ -511,11 +511,11 @@ func TestFindContainersByPod(t *testing.T) {
DockerContainers{ DockerContainers{
"foobar": &docker.APIContainers{ "foobar": &docker.APIContainers{
ID: "foobar", ID: "foobar",
Names: []string{"/k8s_foo_qux_1234_42"}, Names: []string{"/k8s_foo_qux_ns_1234_42"},
}, },
"baz": &docker.APIContainers{ "baz": &docker.APIContainers{
ID: "baz", ID: "baz",
Names: []string{"/k8s_foo_qux_1234_42"}, Names: []string{"/k8s_foo_qux_ns_1234_42"},
}, },
}, },
}, },
...@@ -523,15 +523,15 @@ func TestFindContainersByPod(t *testing.T) { ...@@ -523,15 +523,15 @@ func TestFindContainersByPod(t *testing.T) {
DockerContainers{ DockerContainers{
"foobar": &docker.APIContainers{ "foobar": &docker.APIContainers{
ID: "foobar", ID: "foobar",
Names: []string{"/k8s_foo_qux_1234_42"}, Names: []string{"/k8s_foo_qux_ns_1234_42"},
}, },
"barbar": &docker.APIContainers{ "barbar": &docker.APIContainers{
ID: "barbar", ID: "barbar",
Names: []string{"/k8s_foo_qux_2343_42"}, Names: []string{"/k8s_foo_qux_ns_2343_42"},
}, },
"baz": &docker.APIContainers{ "baz": &docker.APIContainers{
ID: "baz", ID: "baz",
Names: []string{"/k8s_foo_qux_1234_42"}, Names: []string{"/k8s_foo_qux_ns_1234_42"},
}, },
}, },
types.UID("5678"), types.UID("5678"),
...@@ -542,7 +542,7 @@ func TestFindContainersByPod(t *testing.T) { ...@@ -542,7 +542,7 @@ func TestFindContainersByPod(t *testing.T) {
DockerContainers{ DockerContainers{
"foobar": &docker.APIContainers{ "foobar": &docker.APIContainers{
ID: "foobar", ID: "foobar",
Names: []string{"/k8s_foo_qux_1234_42"}, Names: []string{"/k8s_foo_qux_ns_1234_42"},
}, },
"barbar": &docker.APIContainers{ "barbar": &docker.APIContainers{
ID: "barbar", ID: "barbar",
...@@ -550,7 +550,7 @@ func TestFindContainersByPod(t *testing.T) { ...@@ -550,7 +550,7 @@ func TestFindContainersByPod(t *testing.T) {
}, },
"baz": &docker.APIContainers{ "baz": &docker.APIContainers{
ID: "baz", ID: "baz",
Names: []string{"/k8s_foo_qux_5678_42"}, Names: []string{"/k8s_foo_qux_ns_5678_42"},
}, },
}, },
types.UID("5678"), types.UID("5678"),
...@@ -558,7 +558,7 @@ func TestFindContainersByPod(t *testing.T) { ...@@ -558,7 +558,7 @@ func TestFindContainersByPod(t *testing.T) {
DockerContainers{ DockerContainers{
"baz": &docker.APIContainers{ "baz": &docker.APIContainers{
ID: "baz", ID: "baz",
Names: []string{"/k8s_foo_qux_5678_42"}, Names: []string{"/k8s_foo_qux_ns_5678_42"},
}, },
}, },
}, },
...@@ -566,23 +566,23 @@ func TestFindContainersByPod(t *testing.T) { ...@@ -566,23 +566,23 @@ func TestFindContainersByPod(t *testing.T) {
DockerContainers{ DockerContainers{
"foobar": &docker.APIContainers{ "foobar": &docker.APIContainers{
ID: "foobar", ID: "foobar",
Names: []string{"/k8s_foo_qux_1234_42"}, Names: []string{"/k8s_foo_qux_ns_1234_42"},
}, },
"barbar": &docker.APIContainers{ "barbar": &docker.APIContainers{
ID: "barbar", ID: "barbar",
Names: []string{"/k8s_foo_abc_5678_42"}, Names: []string{"/k8s_foo_abc_ns_5678_42"},
}, },
"baz": &docker.APIContainers{ "baz": &docker.APIContainers{
ID: "baz", ID: "baz",
Names: []string{"/k8s_foo_qux_5678_42"}, Names: []string{"/k8s_foo_qux_ns_5678_42"},
}, },
}, },
"", "",
"abc", "abc_ns",
DockerContainers{ DockerContainers{
"barbar": &docker.APIContainers{ "barbar": &docker.APIContainers{
ID: "barbar", ID: "barbar",
Names: []string{"/k8s_foo_abc_5678_42"}, Names: []string{"/k8s_foo_abc_ns_5678_42"},
}, },
}, },
}, },
......
...@@ -69,7 +69,7 @@ type SyncHandler interface { ...@@ -69,7 +69,7 @@ type SyncHandler interface {
SyncPods(pods []api.BoundPod, podSyncTypes map[types.UID]metrics.SyncPodType, startTime time.Time) error SyncPods(pods []api.BoundPod, podSyncTypes map[types.UID]metrics.SyncPodType, startTime time.Time) error
} }
type SourceReadyFn func(source string) bool type SourcesReadyFn func() bool
type volumeMap map[string]volume.Interface type volumeMap map[string]volume.Interface
...@@ -86,7 +86,7 @@ func NewMainKubelet( ...@@ -86,7 +86,7 @@ func NewMainKubelet(
pullBurst int, pullBurst int,
minimumGCAge time.Duration, minimumGCAge time.Duration,
maxContainerCount int, maxContainerCount int,
sourceReady SourceReadyFn, sourcesReady SourcesReadyFn,
clusterDomain string, clusterDomain string,
clusterDNS net.IP, clusterDNS net.IP,
masterServiceNamespace string, masterServiceNamespace string,
...@@ -135,7 +135,7 @@ func NewMainKubelet( ...@@ -135,7 +135,7 @@ func NewMainKubelet(
pullBurst: pullBurst, pullBurst: pullBurst,
minimumGCAge: minimumGCAge, minimumGCAge: minimumGCAge,
maxContainerCount: maxContainerCount, maxContainerCount: maxContainerCount,
sourceReady: sourceReady, sourcesReady: sourcesReady,
clusterDomain: clusterDomain, clusterDomain: clusterDomain,
clusterDNS: clusterDNS, clusterDNS: clusterDNS,
serviceLister: serviceLister, serviceLister: serviceLister,
...@@ -185,7 +185,7 @@ type Kubelet struct { ...@@ -185,7 +185,7 @@ type Kubelet struct {
podInfraContainerImage string podInfraContainerImage string
podWorkers *podWorkers podWorkers *podWorkers
resyncInterval time.Duration resyncInterval time.Duration
sourceReady SourceReadyFn sourcesReady SourcesReadyFn
// Protects the pods array // Protects the pods array
// We make complete array copies out of this while locked, which is OK because once added to this array, // We make complete array copies out of this while locked, which is OK because once added to this array,
...@@ -1402,10 +1402,16 @@ func (kl *Kubelet) SyncPods(allPods []api.BoundPod, podSyncTypes map[types.UID]m ...@@ -1402,10 +1402,16 @@ func (kl *Kubelet) SyncPods(allPods []api.BoundPod, podSyncTypes map[types.UID]m
metrics.ContainersPerPodCount.Observe(float64(len(pod.Spec.Containers))) metrics.ContainersPerPodCount.Observe(float64(len(pod.Spec.Containers)))
} }
} }
// Stop the workers for no-longer existing pods. // Stop the workers for no-longer existing pods.
kl.podWorkers.ForgetNonExistingPodWorkers(desiredPods) kl.podWorkers.ForgetNonExistingPodWorkers(desiredPods)
if !kl.sourcesReady() {
// If the sources aren't ready, skip deletion, as we may accidentally delete pods
// for sources that haven't reported yet.
glog.V(4).Infof("Skipping deletes, sources aren't ready yet.")
return nil
}
// Kill any containers we don't need. // Kill any containers we don't need.
killed := []string{} killed := []string{}
for ix := range dockerContainers { for ix := range dockerContainers {
...@@ -1415,13 +1421,7 @@ func (kl *Kubelet) SyncPods(allPods []api.BoundPod, podSyncTypes map[types.UID]m ...@@ -1415,13 +1421,7 @@ func (kl *Kubelet) SyncPods(allPods []api.BoundPod, podSyncTypes map[types.UID]m
// syncPod() will handle this one. // syncPod() will handle this one.
continue continue
} }
_, _, podAnnotations := ParsePodFullName(podFullName)
if source := podAnnotations[ConfigSourceAnnotationKey]; !kl.sourceReady(source) {
// If the source for this container is not ready, skip deletion, so that we don't accidentally
// delete containers for sources that haven't reported yet.
glog.V(4).Infof("Skipping delete of container (%q), source (%s) aren't ready yet.", podFullName, source)
continue
}
pc := podContainer{podFullName, uid, containerName} pc := podContainer{podFullName, uid, containerName}
if _, ok := desiredContainers[pc]; !ok { if _, ok := desiredContainers[pc]; !ok {
glog.V(1).Infof("Killing unwanted container %+v", pc) glog.V(1).Infof("Killing unwanted container %+v", pc)
......
...@@ -76,7 +76,7 @@ func TestRunOnce(t *testing.T) { ...@@ -76,7 +76,7 @@ func TestRunOnce(t *testing.T) {
} }
podContainers := []docker.APIContainers{ podContainers := []docker.APIContainers{
{ {
Names: []string{"/k8s_bar." + strconv.FormatUint(dockertools.HashContainer(&api.Container{Name: "bar"}), 16) + "_foo.new.test_12345678_42"}, Names: []string{"/k8s_bar." + strconv.FormatUint(dockertools.HashContainer(&api.Container{Name: "bar"}), 16) + "_foo_new_12345678_42"},
ID: "1234", ID: "1234",
Status: "running", Status: "running",
}, },
...@@ -130,10 +130,9 @@ func TestRunOnce(t *testing.T) { ...@@ -130,10 +130,9 @@ func TestRunOnce(t *testing.T) {
results, err := kb.runOnce([]api.BoundPod{ results, err := kb.runOnce([]api.BoundPod{
{ {
ObjectMeta: api.ObjectMeta{ ObjectMeta: api.ObjectMeta{
UID: "12345678", UID: "12345678",
Name: "foo", Name: "foo",
Namespace: "new", Namespace: "new",
Annotations: map[string]string{ConfigSourceAnnotationKey: "test"},
}, },
Spec: api.PodSpec{ Spec: api.PodSpec{
Containers: []api.Container{ Containers: []api.Container{
......
...@@ -129,9 +129,6 @@ func newServerTest() *serverTestFramework { ...@@ -129,9 +129,6 @@ func newServerTest() *serverTestFramework {
ObjectMeta: api.ObjectMeta{ ObjectMeta: api.ObjectMeta{
Namespace: namespace, Namespace: namespace,
Name: name, Name: name,
Annotations: map[string]string{
ConfigSourceAnnotationKey: "etcd",
},
}, },
}, true }, true
}, },
...@@ -157,6 +154,14 @@ func readResp(resp *http.Response) (string, error) { ...@@ -157,6 +154,14 @@ func readResp(resp *http.Response) (string, error) {
return string(body), err return string(body), err
} }
// A helper function to return the correct pod name.
func getPodName(name, namespace string) string {
if namespace == "" {
namespace = NamespaceDefault
}
return name + "_" + namespace
}
func TestPodStatus(t *testing.T) { func TestPodStatus(t *testing.T) {
fw := newServerTest() fw := newServerTest()
expected := api.PodStatus{ expected := api.PodStatus{
...@@ -165,7 +170,7 @@ func TestPodStatus(t *testing.T) { ...@@ -165,7 +170,7 @@ func TestPodStatus(t *testing.T) {
}, },
} }
fw.fakeKubelet.statusFunc = func(name string) (api.PodStatus, error) { fw.fakeKubelet.statusFunc = func(name string) (api.PodStatus, error) {
if name == "goodpod.default.etcd" { if name == "goodpod_default" {
return expected, nil return expected, nil
} }
return api.PodStatus{}, fmt.Errorf("bad pod %s", name) return api.PodStatus{}, fmt.Errorf("bad pod %s", name)
...@@ -191,7 +196,7 @@ func TestContainerInfo(t *testing.T) { ...@@ -191,7 +196,7 @@ func TestContainerInfo(t *testing.T) {
fw := newServerTest() fw := newServerTest()
expectedInfo := &info.ContainerInfo{} expectedInfo := &info.ContainerInfo{}
podID := "somepod" podID := "somepod"
expectedPodID := "somepod" + ".default.etcd" expectedPodID := getPodName(podID, "")
expectedContainerName := "goodcontainer" expectedContainerName := "goodcontainer"
fw.fakeKubelet.containerInfoFunc = func(podID string, uid types.UID, containerName string, req *info.ContainerInfoRequest) (*info.ContainerInfo, error) { fw.fakeKubelet.containerInfoFunc = func(podID string, uid types.UID, containerName string, req *info.ContainerInfoRequest) (*info.ContainerInfo, error) {
if podID != expectedPodID || containerName != expectedContainerName { if podID != expectedPodID || containerName != expectedContainerName {
...@@ -220,7 +225,7 @@ func TestContainerInfoWithUidNamespace(t *testing.T) { ...@@ -220,7 +225,7 @@ func TestContainerInfoWithUidNamespace(t *testing.T) {
expectedInfo := &info.ContainerInfo{} expectedInfo := &info.ContainerInfo{}
podID := "somepod" podID := "somepod"
expectedNamespace := "custom" expectedNamespace := "custom"
expectedPodID := "somepod" + "." + expectedNamespace + ".etcd" expectedPodID := getPodName(podID, expectedNamespace)
expectedContainerName := "goodcontainer" expectedContainerName := "goodcontainer"
expectedUid := "9b01b80f-8fb4-11e4-95ab-4200af06647" expectedUid := "9b01b80f-8fb4-11e4-95ab-4200af06647"
fw.fakeKubelet.containerInfoFunc = func(podID string, uid types.UID, containerName string, req *info.ContainerInfoRequest) (*info.ContainerInfo, error) { fw.fakeKubelet.containerInfoFunc = func(podID string, uid types.UID, containerName string, req *info.ContainerInfoRequest) (*info.ContainerInfo, error) {
...@@ -344,7 +349,7 @@ func TestServeRunInContainer(t *testing.T) { ...@@ -344,7 +349,7 @@ func TestServeRunInContainer(t *testing.T) {
output := "foo bar" output := "foo bar"
podNamespace := "other" podNamespace := "other"
podName := "foo" podName := "foo"
expectedPodName := podName + "." + podNamespace + ".etcd" expectedPodName := getPodName(podName, podNamespace)
expectedContainerName := "baz" expectedContainerName := "baz"
expectedCommand := "ls -a" expectedCommand := "ls -a"
fw.fakeKubelet.runFunc = func(podFullName string, uid types.UID, containerName string, cmd []string) ([]byte, error) { fw.fakeKubelet.runFunc = func(podFullName string, uid types.UID, containerName string, cmd []string) ([]byte, error) {
...@@ -384,7 +389,7 @@ func TestServeRunInContainerWithUID(t *testing.T) { ...@@ -384,7 +389,7 @@ func TestServeRunInContainerWithUID(t *testing.T) {
output := "foo bar" output := "foo bar"
podNamespace := "other" podNamespace := "other"
podName := "foo" podName := "foo"
expectedPodName := podName + "." + podNamespace + ".etcd" expectedPodName := getPodName(podName, podNamespace)
expectedUID := "7e00838d_-_3523_-_11e4_-_8421_-_42010af0a720" expectedUID := "7e00838d_-_3523_-_11e4_-_8421_-_42010af0a720"
expectedContainerName := "baz" expectedContainerName := "baz"
expectedCommand := "ls -a" expectedCommand := "ls -a"
...@@ -509,9 +514,6 @@ func setPodByNameFunc(fw *serverTestFramework, namespace, pod, container string) ...@@ -509,9 +514,6 @@ func setPodByNameFunc(fw *serverTestFramework, namespace, pod, container string)
ObjectMeta: api.ObjectMeta{ ObjectMeta: api.ObjectMeta{
Namespace: namespace, Namespace: namespace,
Name: pod, Name: pod,
Annotations: map[string]string{
ConfigSourceAnnotationKey: "etcd",
},
}, },
Spec: api.PodSpec{ Spec: api.PodSpec{
Containers: []api.Container{ Containers: []api.Container{
...@@ -548,7 +550,7 @@ func TestContainerLogs(t *testing.T) { ...@@ -548,7 +550,7 @@ func TestContainerLogs(t *testing.T) {
output := "foo bar" output := "foo bar"
podNamespace := "other" podNamespace := "other"
podName := "foo" podName := "foo"
expectedPodName := podName + ".other.etcd" expectedPodName := getPodName(podName, podNamespace)
expectedContainerName := "baz" expectedContainerName := "baz"
expectedTail := "" expectedTail := ""
expectedFollow := false expectedFollow := false
...@@ -575,7 +577,7 @@ func TestContainerLogsWithTail(t *testing.T) { ...@@ -575,7 +577,7 @@ func TestContainerLogsWithTail(t *testing.T) {
output := "foo bar" output := "foo bar"
podNamespace := "other" podNamespace := "other"
podName := "foo" podName := "foo"
expectedPodName := podName + ".other.etcd" expectedPodName := getPodName(podName, podNamespace)
expectedContainerName := "baz" expectedContainerName := "baz"
expectedTail := "5" expectedTail := "5"
expectedFollow := false expectedFollow := false
...@@ -602,7 +604,7 @@ func TestContainerLogsWithFollow(t *testing.T) { ...@@ -602,7 +604,7 @@ func TestContainerLogsWithFollow(t *testing.T) {
output := "foo bar" output := "foo bar"
podNamespace := "other" podNamespace := "other"
podName := "foo" podName := "foo"
expectedPodName := podName + ".other.etcd" expectedPodName := getPodName(podName, podNamespace)
expectedContainerName := "baz" expectedContainerName := "baz"
expectedTail := "" expectedTail := ""
expectedFollow := true expectedFollow := true
...@@ -693,7 +695,7 @@ func TestServeExecInContainer(t *testing.T) { ...@@ -693,7 +695,7 @@ func TestServeExecInContainer(t *testing.T) {
podNamespace := "other" podNamespace := "other"
podName := "foo" podName := "foo"
expectedPodName := podName + "." + podNamespace + ".etcd" expectedPodName := getPodName(podName, podNamespace)
expectedUid := "9b01b80f-8fb4-11e4-95ab-4200af06647" expectedUid := "9b01b80f-8fb4-11e4-95ab-4200af06647"
expectedContainerName := "baz" expectedContainerName := "baz"
expectedCommand := "ls -a" expectedCommand := "ls -a"
...@@ -955,7 +957,7 @@ func TestServePortForward(t *testing.T) { ...@@ -955,7 +957,7 @@ func TestServePortForward(t *testing.T) {
podNamespace := "other" podNamespace := "other"
podName := "foo" podName := "foo"
expectedPodName := podName + "." + podNamespace + ".etcd" expectedPodName := getPodName(podName, podNamespace)
expectedUid := "9b01b80f-8fb4-11e4-95ab-4200af06647" expectedUid := "9b01b80f-8fb4-11e4-95ab-4200af06647"
for i, test := range tests { for i, test := range tests {
......
...@@ -18,10 +18,8 @@ package kubelet ...@@ -18,10 +18,8 @@ package kubelet
import ( import (
"fmt" "fmt"
"strings"
"github.com/GoogleCloudPlatform/kubernetes/pkg/api" "github.com/GoogleCloudPlatform/kubernetes/pkg/api"
"github.com/golang/glog"
) )
const ConfigSourceAnnotationKey = "kubernetes.io/config.source" const ConfigSourceAnnotationKey = "kubernetes.io/config.source"
...@@ -52,6 +50,8 @@ const ( ...@@ -52,6 +50,8 @@ const (
ApiserverSource = "api" ApiserverSource = "api"
// Updates from all sources // Updates from all sources
AllSource = "*" AllSource = "*"
NamespaceDefault = api.NamespaceDefault
) )
// PodUpdate defines an operation sent on the channel. You can add or remove single services by // PodUpdate defines an operation sent on the channel. You can add or remove single services by
...@@ -71,22 +71,12 @@ type PodUpdate struct { ...@@ -71,22 +71,12 @@ type PodUpdate struct {
// GetPodFullName returns a name that uniquely identifies a pod across all config sources. // GetPodFullName returns a name that uniquely identifies a pod across all config sources.
func GetPodFullName(pod *api.BoundPod) string { func GetPodFullName(pod *api.BoundPod) string {
return fmt.Sprintf("%s.%s.%s", pod.Name, pod.Namespace, pod.Annotations[ConfigSourceAnnotationKey]) // Use underscore as the delimiter because it is not allowed in pod name
// (DNS subdomain format), while allowed in the container name format.
return fmt.Sprintf("%s_%s", pod.Name, pod.Namespace)
} }
// ParsePodFullName unpacks a pod full name and returns the pod name, namespace, and annotations. // Build the pod full name from pod name and namespace.
// If the pod full name is invalid, empty strings are returend. func BuildPodFullName(name, namespace string) string {
func ParsePodFullName(podFullName string) (podName, podNamespace string, podAnnotations map[string]string) { return name + "_" + namespace
parts := strings.Split(podFullName, ".")
expectedNumFields := 3
actualNumFields := len(parts)
if actualNumFields != expectedNumFields {
glog.Errorf("found a podFullName (%q) with too few fields: expected %d, actual %d.", podFullName, expectedNumFields, actualNumFields)
return
}
podName = parts[0]
podNamespace = parts[1]
podAnnotations = make(map[string]string)
podAnnotations[ConfigSourceAnnotationKey] = parts[2]
return
} }
/*
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 (
"testing"
)
func TestParsePodFullName(t *testing.T) {
// Arrange
podFullName := "ca4e7148-9ab9-11e4-924c-f0921cde18c1.default.etcd"
// Act
podName, podNamespace, podAnnotations := ParsePodFullName(podFullName)
// Assert
expectedPodName := "ca4e7148-9ab9-11e4-924c-f0921cde18c1"
expectedPodNamespace := "default"
expectedSource := "etcd"
if podName != expectedPodName {
t.Errorf("Unexpected PodName. Expected: %q Actual: %q", expectedPodName, podName)
}
if podNamespace != expectedPodNamespace {
t.Errorf("Unexpected PodNamespace. Expected: %q Actual: %q", expectedPodNamespace, podNamespace)
}
if podAnnotations[ConfigSourceAnnotationKey] != expectedSource {
t.Errorf("Unexpected PodSource. Expected: %q Actual: %q", expectedPodNamespace, podNamespace)
}
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment