Skip to content

Commit 6378ff9

Browse files
committed
Merge pull request #6 from technosophos/feat/downward-api-namespace
feat(aboutme): retrieve namespace from DAPI
2 parents b2ffa64 + 734c1f6 commit 6378ff9

2 files changed

Lines changed: 71 additions & 12 deletions

File tree

aboutme/aboutme.go

Lines changed: 49 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,20 @@ import (
2424
"k8s.io/kubernetes/pkg/labels"
2525
)
2626

27+
// DefaultNamespace is the Kubernetes default namespace.
28+
const DefaultNamespace = "default"
29+
30+
var (
31+
// EnvNamespace is the environment variable this looks for to get the namespace.
32+
//
33+
// You can set this via the Downward API.
34+
EnvNamespace = "POD_NAMESPACE"
35+
// EnvName is the environment variable this looks for to get the pod name.
36+
//
37+
// You can set this via the Downward API.
38+
EnvName = "POD_NAME"
39+
)
40+
2741
type Me struct {
2842
ApiServer, Name string
2943
IP, NodeIP, Namespace, SelfLink, UID string
@@ -42,7 +56,7 @@ func FromEnv() (*Me, error) {
4256

4357
host := os.Getenv("KUBERNETES_SERVICE_HOST")
4458
port := os.Getenv("KUBERNETES_SERVICE_PORT")
45-
name := os.Getenv("HOSTNAME")
59+
name := NameFromEnv()
4660

4761
// FIXME: Better way? Probably scanning secrets for
4862
// an SSL cert would help?
@@ -53,10 +67,7 @@ func FromEnv() (*Me, error) {
5367
me := &Me{
5468
ApiServer: url,
5569
Name: name,
56-
57-
// FIXME: This is a chicken-and-egg problem. We need the namespace
58-
// to get pod info, and we can only get info from the pod.
59-
Namespace: "default",
70+
Namespace: NamespaceFromEnv(),
6071
}
6172

6273
client, err := k8s.PodClient()
@@ -75,6 +86,27 @@ func (me *Me) Client() *unversioned.Client {
7586
return me.c
7687
}
7788

89+
// NameFromEnv gets the pod name from either the Downward API or the hostname.
90+
func NameFromEnv() string {
91+
n := os.Getenv(EnvName)
92+
if n == "" {
93+
return os.Getenv("HOSTNAME")
94+
}
95+
return n
96+
}
97+
98+
//NamespaceFromEnv attempts to get the namespace from the downward API.
99+
//
100+
// If EnvNamespace is not set, or if the name is not recovered from the
101+
// environment, then the DefaultNamespace is used.
102+
func NamespaceFromEnv() string {
103+
ns := os.Getenv(EnvNamespace)
104+
if ns == "" {
105+
return DefaultNamespace
106+
}
107+
return ns
108+
}
109+
78110
// ShuntEnv puts the Me object into the environment.
79111
//
80112
// The properties of Me are placed into the environment according to the
@@ -108,7 +140,7 @@ func (me *Me) ShuntEnv() {
108140
}
109141

110142
func (me *Me) init() error {
111-
p, n, err := me.findPodInNamespaces()
143+
p, n, err := me.loadPod()
112144
if err != nil {
113145
return err
114146
}
@@ -125,7 +157,7 @@ func (me *Me) init() error {
125157
// PodIP, even though the pod is issued an IP. We need to figure out why,
126158
// and if this is an expected case. In the meantime, we get the IP by
127159
// scanning interfaces.
128-
if me.IP == "" {
160+
if strings.TrimSpace(me.IP) == "" {
129161
// We swallow the error, letting me.IP set the interface address to
130162
// 0.0.0.0.
131163
me.IP, _ = MyIP()
@@ -134,17 +166,22 @@ func (me *Me) init() error {
134166
return nil
135167
}
136168

169+
// loadPod loads a pod using the downward API.
170+
func (me *Me) loadPod() (*api.Pod, string, error) {
171+
ns := NamespaceFromEnv()
172+
p, err := me.c.Pods(ns).Get(me.Name)
173+
return p, ns, err
174+
}
175+
137176
// findPodInNamespaces searches relevant namespaces for this pod.
138177
//
139178
// It returns a PodInterface for working with the pod, a namespace name as a
140179
// string, and an error if something goes wrong.
141180
//
142-
// The search pattern is to look for namespaces that have the "deis" name in
143-
// their labels, and then to fall back to default. We don't look at all
144-
// namespaces.
145-
func (me *Me) findPodInNamespaces() (*api.Pod, string, error) {
181+
// The selector must be a label selector.
182+
func (me *Me) findPodInNamespaces(selector string) (*api.Pod, string, error) {
146183
// Get the deis namespace. If it does not exist, get the default namespce.
147-
s, err := labels.Parse("name=deis")
184+
s, err := labels.Parse(selector)
148185
if err == nil {
149186
ns, err := me.c.Namespaces().List(s, nil)
150187
if err != nil {

aboutme/aboutme_test.go

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,28 @@ func TestFromEnv(t *testing.T) {
2323
}
2424
}
2525

26+
func TestNamespaceFromEnv(t *testing.T) {
27+
if ns := NamespaceFromEnv(); ns != DefaultNamespace {
28+
t.Errorf("You did something stupid.")
29+
}
30+
31+
os.Setenv(EnvNamespace, "slurm")
32+
if ns := NamespaceFromEnv(); ns != "slurm" {
33+
t.Errorf("Expected slurm, got %q", ns)
34+
}
35+
}
36+
37+
func TestNameFromEnv(t *testing.T) {
38+
os.Setenv("HOSTNAME", "example")
39+
if n := NameFromEnv(); n != "example" {
40+
t.Errorf("Expected example, got %q", n)
41+
}
42+
os.Setenv(EnvName, "slumber")
43+
if n := NameFromEnv(); n != "slumber" {
44+
t.Errorf("Expected slumber, got %s", n)
45+
}
46+
}
47+
2648
func TestShuntEnv(t *testing.T) {
2749
e := &Me{
2850
Annotations: map[string]string{"a": "a"},

0 commit comments

Comments
 (0)