Skip to content

Commit

Permalink
fix: return full status object from the info endpoint
Browse files Browse the repository at this point in the history
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]>
  • Loading branch information
LucasRoesler committed Feb 26, 2022
1 parent e131309 commit bdff0c4
Show file tree
Hide file tree
Showing 2 changed files with 115 additions and 11 deletions.
47 changes: 37 additions & 10 deletions pkg/k8s/function_status.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,16 +23,19 @@ func AsFunctionStatus(item appsv1.Deployment) *types.FunctionStatus {

labels := item.Spec.Template.Labels
function := types.FunctionStatus{
Name: item.Name,
Replicas: replicas,
Image: functionContainer.Image,
AvailableReplicas: uint64(item.Status.AvailableReplicas),
InvocationCount: 0,
Labels: &labels,
Annotations: &item.Spec.Template.Annotations,
Namespace: item.Namespace,
Secrets: ReadFunctionSecretsSpec(item),
CreatedAt: item.CreationTimestamp.Time,
Name: item.Name,
Replicas: replicas,
Image: functionContainer.Image,
AvailableReplicas: uint64(item.Status.AvailableReplicas),
InvocationCount: 0,
Labels: &labels,
Annotations: &item.Spec.Template.Annotations,
Namespace: item.Namespace,
Secrets: ReadFunctionSecretsSpec(item),
CreatedAt: item.CreationTimestamp.Time,
Constraints: nodeSelectorToConstraint(item),
ReadOnlyRootFilesystem: hasReadOnlyRootFilesystem(item),
EnvVars: map[string]string{},
}

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

return &function
}

func nodeSelectorToConstraint(deploy appsv1.Deployment) []string {
nodeSelector := deploy.Spec.Template.Spec.NodeSelector
constraints := []string{}
for k, v := range nodeSelector {
constraints = append(constraints, k+"="+v)
}
return constraints
}

func hasReadOnlyRootFilesystem(function appsv1.Deployment) bool {
securityContext := function.Spec.Template.Spec.Containers[0].SecurityContext
if securityContext == nil {
return false
}

if securityContext.ReadOnlyRootFilesystem == nil {
return false
}

return *securityContext.ReadOnlyRootFilesystem
}
79 changes: 78 additions & 1 deletion pkg/k8s/function_status_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import (

appsv1 "k8s.io/api/apps/v1"
corev1 "k8s.io/api/core/v1"
"k8s.io/apimachinery/pkg/api/resource"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
)

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

deploy := appsv1.Deployment{
ObjectMeta: metav1.ObjectMeta{
Expand All @@ -39,6 +43,9 @@ func Test_AsFunctionStatus(t *testing.T) {
Labels: labels,
},
Spec: corev1.PodSpec{
NodeSelector: map[string]string{
"node-label": "node-value",
},
ImagePullSecrets: []corev1.LocalObjectReference{
{Name: "0-imagepullsecret"},
},
Expand All @@ -48,7 +55,8 @@ func Test_AsFunctionStatus(t *testing.T) {
Image: image,
Env: []corev1.EnvVar{
{Name: "fprocess", Value: envProcess},
{Name: "customEnv", Value: "customValue"},
{Name: "env1", Value: "env1value"},
{Name: "env2", Value: "env2value"},
},
},
},
Expand Down Expand Up @@ -122,4 +130,73 @@ func Test_AsFunctionStatus(t *testing.T) {
t.Errorf("incorrect Secrets: expected %v, got : %v", secrets, status.Secrets)
}

if !reflect.DeepEqual(status.EnvVars, envVars) {
t.Errorf("incorrect EnvVars: expected %+v, got %+v", envVars, status.EnvVars)
}

if !reflect.DeepEqual(status.Constraints, constraints) {
t.Errorf("incorrect Constraints: expected %+v, got %+v", constraints, status.Constraints)
}

if status.ReadOnlyRootFilesystem != readOnlyRootFilesystem {
t.Errorf("incorrect ReadOnlyRootFilesystem: expected %v, got : %v", readOnlyRootFilesystem, status.ReadOnlyRootFilesystem)
}

t.Run("can parse readonly root filesystem when nil", func(t *testing.T) {
readOnlyRootFilesystem := false
deployment := deploy
deployment.Spec.Template.Spec.Containers[0].SecurityContext = &corev1.SecurityContext{}

status := AsFunctionStatus(deployment)
if status.ReadOnlyRootFilesystem != readOnlyRootFilesystem {
t.Errorf("incorrect ReadOnlyRootFilesystem: expected %v, got : %v", readOnlyRootFilesystem, status.ReadOnlyRootFilesystem)
}
})

t.Run("can parse readonly root filesystem enabled", func(t *testing.T) {
readOnlyRootFilesystem := true
deployment := deploy
deployment.Spec.Template.Spec.Containers[0].SecurityContext = &corev1.SecurityContext{
ReadOnlyRootFilesystem: &readOnlyRootFilesystem,
}

status := AsFunctionStatus(deployment)
if status.ReadOnlyRootFilesystem != readOnlyRootFilesystem {
t.Errorf("incorrect ReadOnlyRootFilesystem: expected %v, got : %v", readOnlyRootFilesystem, status.ReadOnlyRootFilesystem)
}
})

t.Run("returns non-empty resource requests", func(t *testing.T) {
deployment := deploy
deployment.Spec.Template.Spec.Containers[0].Resources.Requests = corev1.ResourceList{
corev1.ResourceCPU: resource.MustParse("100m"),
corev1.ResourceMemory: resource.MustParse("100Mi"),
}

status := AsFunctionStatus(deployment)
if status.Requests.CPU != "100m" {
t.Errorf("incorrect Requests.CPU: expected %s, got %s", "100m", status.Requests.CPU)
}

if status.Requests.Memory != "100Mi" {
t.Errorf("incorrect Requests.Memory: expected %s, got %s", "100Mi", status.Requests.Memory)
}
})

t.Run("returns non-empty resource limits", func(t *testing.T) {
deployment := deploy
deployment.Spec.Template.Spec.Containers[0].Resources.Limits = corev1.ResourceList{
corev1.ResourceCPU: resource.MustParse("100m"),
corev1.ResourceMemory: resource.MustParse("100Mi"),
}

status := AsFunctionStatus(deployment)
if status.Limits.CPU != "100m" {
t.Errorf("incorrect Limits.CPU: expected %s, got %s", "100m", status.Limits.CPU)
}

if status.Limits.Memory != "100Mi" {
t.Errorf("incorrect Limits.Memory: expected %s, got %s", "100Mi", status.Limits.Memory)
}
})
}

0 comments on commit bdff0c4

Please sign in to comment.