Skip to content

Commit bdff0c4

Browse files
committed
fix: return full status object from the info endpoint
Ensure that all fields of the `FunctionStatus` are populated based on the function `Deployment`. In particular, this change ensures that the env variables, constrains, and the read-only root filesystem values are populuated correctly. Signed-off-by: Lucas Roesler <[email protected]>
1 parent e131309 commit bdff0c4

File tree

2 files changed

+115
-11
lines changed

2 files changed

+115
-11
lines changed

Diff for: pkg/k8s/function_status.go

+37-10
Original file line numberDiff line numberDiff line change
@@ -23,16 +23,19 @@ func AsFunctionStatus(item appsv1.Deployment) *types.FunctionStatus {
2323

2424
labels := item.Spec.Template.Labels
2525
function := types.FunctionStatus{
26-
Name: item.Name,
27-
Replicas: replicas,
28-
Image: functionContainer.Image,
29-
AvailableReplicas: uint64(item.Status.AvailableReplicas),
30-
InvocationCount: 0,
31-
Labels: &labels,
32-
Annotations: &item.Spec.Template.Annotations,
33-
Namespace: item.Namespace,
34-
Secrets: ReadFunctionSecretsSpec(item),
35-
CreatedAt: item.CreationTimestamp.Time,
26+
Name: item.Name,
27+
Replicas: replicas,
28+
Image: functionContainer.Image,
29+
AvailableReplicas: uint64(item.Status.AvailableReplicas),
30+
InvocationCount: 0,
31+
Labels: &labels,
32+
Annotations: &item.Spec.Template.Annotations,
33+
Namespace: item.Namespace,
34+
Secrets: ReadFunctionSecretsSpec(item),
35+
CreatedAt: item.CreationTimestamp.Time,
36+
Constraints: nodeSelectorToConstraint(item),
37+
ReadOnlyRootFilesystem: hasReadOnlyRootFilesystem(item),
38+
EnvVars: map[string]string{},
3639
}
3740

3841
req := &types.FunctionResources{Memory: functionContainer.Resources.Requests.Memory().String(), CPU: functionContainer.Resources.Requests.Cpu().String()}
@@ -48,8 +51,32 @@ func AsFunctionStatus(item appsv1.Deployment) *types.FunctionStatus {
4851
for _, v := range functionContainer.Env {
4952
if EnvProcessName == v.Name {
5053
function.EnvProcess = v.Value
54+
continue
5155
}
56+
function.EnvVars[v.Name] = v.Value
5257
}
5358

5459
return &function
5560
}
61+
62+
func nodeSelectorToConstraint(deploy appsv1.Deployment) []string {
63+
nodeSelector := deploy.Spec.Template.Spec.NodeSelector
64+
constraints := []string{}
65+
for k, v := range nodeSelector {
66+
constraints = append(constraints, k+"="+v)
67+
}
68+
return constraints
69+
}
70+
71+
func hasReadOnlyRootFilesystem(function appsv1.Deployment) bool {
72+
securityContext := function.Spec.Template.Spec.Containers[0].SecurityContext
73+
if securityContext == nil {
74+
return false
75+
}
76+
77+
if securityContext.ReadOnlyRootFilesystem == nil {
78+
return false
79+
}
80+
81+
return *securityContext.ReadOnlyRootFilesystem
82+
}

Diff for: pkg/k8s/function_status_test.go

+78-1
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ import (
1010

1111
appsv1 "k8s.io/api/apps/v1"
1212
corev1 "k8s.io/api/core/v1"
13+
"k8s.io/apimachinery/pkg/api/resource"
1314
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
1415
)
1516

@@ -23,7 +24,10 @@ func Test_AsFunctionStatus(t *testing.T) {
2324
annotations := map[string]string{"data": "datavalue"}
2425
namespace := "func-namespace"
2526
envProcess := "process string here"
27+
envVars := map[string]string{"env1": "env1value", "env2": "env2value"}
2628
secrets := []string{"0-imagepullsecret", "1-genericsecret", "2-genericsecret"}
29+
readOnlyRootFilesystem := false
30+
constraints := []string{"node-label=node-value"}
2731

2832
deploy := appsv1.Deployment{
2933
ObjectMeta: metav1.ObjectMeta{
@@ -39,6 +43,9 @@ func Test_AsFunctionStatus(t *testing.T) {
3943
Labels: labels,
4044
},
4145
Spec: corev1.PodSpec{
46+
NodeSelector: map[string]string{
47+
"node-label": "node-value",
48+
},
4249
ImagePullSecrets: []corev1.LocalObjectReference{
4350
{Name: "0-imagepullsecret"},
4451
},
@@ -48,7 +55,8 @@ func Test_AsFunctionStatus(t *testing.T) {
4855
Image: image,
4956
Env: []corev1.EnvVar{
5057
{Name: "fprocess", Value: envProcess},
51-
{Name: "customEnv", Value: "customValue"},
58+
{Name: "env1", Value: "env1value"},
59+
{Name: "env2", Value: "env2value"},
5260
},
5361
},
5462
},
@@ -122,4 +130,73 @@ func Test_AsFunctionStatus(t *testing.T) {
122130
t.Errorf("incorrect Secrets: expected %v, got : %v", secrets, status.Secrets)
123131
}
124132

133+
if !reflect.DeepEqual(status.EnvVars, envVars) {
134+
t.Errorf("incorrect EnvVars: expected %+v, got %+v", envVars, status.EnvVars)
135+
}
136+
137+
if !reflect.DeepEqual(status.Constraints, constraints) {
138+
t.Errorf("incorrect Constraints: expected %+v, got %+v", constraints, status.Constraints)
139+
}
140+
141+
if status.ReadOnlyRootFilesystem != readOnlyRootFilesystem {
142+
t.Errorf("incorrect ReadOnlyRootFilesystem: expected %v, got : %v", readOnlyRootFilesystem, status.ReadOnlyRootFilesystem)
143+
}
144+
145+
t.Run("can parse readonly root filesystem when nil", func(t *testing.T) {
146+
readOnlyRootFilesystem := false
147+
deployment := deploy
148+
deployment.Spec.Template.Spec.Containers[0].SecurityContext = &corev1.SecurityContext{}
149+
150+
status := AsFunctionStatus(deployment)
151+
if status.ReadOnlyRootFilesystem != readOnlyRootFilesystem {
152+
t.Errorf("incorrect ReadOnlyRootFilesystem: expected %v, got : %v", readOnlyRootFilesystem, status.ReadOnlyRootFilesystem)
153+
}
154+
})
155+
156+
t.Run("can parse readonly root filesystem enabled", func(t *testing.T) {
157+
readOnlyRootFilesystem := true
158+
deployment := deploy
159+
deployment.Spec.Template.Spec.Containers[0].SecurityContext = &corev1.SecurityContext{
160+
ReadOnlyRootFilesystem: &readOnlyRootFilesystem,
161+
}
162+
163+
status := AsFunctionStatus(deployment)
164+
if status.ReadOnlyRootFilesystem != readOnlyRootFilesystem {
165+
t.Errorf("incorrect ReadOnlyRootFilesystem: expected %v, got : %v", readOnlyRootFilesystem, status.ReadOnlyRootFilesystem)
166+
}
167+
})
168+
169+
t.Run("returns non-empty resource requests", func(t *testing.T) {
170+
deployment := deploy
171+
deployment.Spec.Template.Spec.Containers[0].Resources.Requests = corev1.ResourceList{
172+
corev1.ResourceCPU: resource.MustParse("100m"),
173+
corev1.ResourceMemory: resource.MustParse("100Mi"),
174+
}
175+
176+
status := AsFunctionStatus(deployment)
177+
if status.Requests.CPU != "100m" {
178+
t.Errorf("incorrect Requests.CPU: expected %s, got %s", "100m", status.Requests.CPU)
179+
}
180+
181+
if status.Requests.Memory != "100Mi" {
182+
t.Errorf("incorrect Requests.Memory: expected %s, got %s", "100Mi", status.Requests.Memory)
183+
}
184+
})
185+
186+
t.Run("returns non-empty resource limits", func(t *testing.T) {
187+
deployment := deploy
188+
deployment.Spec.Template.Spec.Containers[0].Resources.Limits = corev1.ResourceList{
189+
corev1.ResourceCPU: resource.MustParse("100m"),
190+
corev1.ResourceMemory: resource.MustParse("100Mi"),
191+
}
192+
193+
status := AsFunctionStatus(deployment)
194+
if status.Limits.CPU != "100m" {
195+
t.Errorf("incorrect Limits.CPU: expected %s, got %s", "100m", status.Limits.CPU)
196+
}
197+
198+
if status.Limits.Memory != "100Mi" {
199+
t.Errorf("incorrect Limits.Memory: expected %s, got %s", "100Mi", status.Limits.Memory)
200+
}
201+
})
125202
}

0 commit comments

Comments
 (0)