Skip to content

Commit

Permalink
Add support for the pod runtimeclass
Browse files Browse the repository at this point in the history
**What**
- Allow policies to configure the Pod RunTimeClassName

Signed-off-by: Lucas Roesler <roesler.lucas@gmail.com>
  • Loading branch information
LucasRoesler authored and alexellis committed Jul 15, 2020
1 parent 3e7bc7c commit 86f7312
Show file tree
Hide file tree
Showing 2 changed files with 120 additions and 0 deletions.
43 changes: 43 additions & 0 deletions k8s/policies.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,8 +26,23 @@ type PolicyClient interface {
// to functions by annotating them with `com.openfaas/policy: name1,name2`
type Policy struct {
// If specified, the function's pod tolerations.
//
// copied to the Pod Tolerations
//
// +optional
Tolerations []corev1.Toleration `json:"tolerations,omitempty"`

// RuntimeClassName refers to a RuntimeClass object in the node.k8s.io group, which should be used
// to run this pod. If no RuntimeClass resource matches the named class, the pod will not be run.
// If unset or empty, the "legacy" RuntimeClass will be used, which is an implicit class with an
// empty definition that uses the default runtime handler.
// More info: https://git.k8s.io/enhancements/keps/sig-node/runtime-class.md
// This is a beta feature as of Kubernetes v1.14.
//
// copied to the Pod RunTimeClass
//
// +optional
RuntimeClassName *string `json:"runtimeClassName,omitempty"`
}

// Apply adds or mutates the configuration of the Deployment with the values defined
Expand All @@ -37,6 +52,11 @@ func (p Policy) Apply(deployment *appsv1.Deployment) *appsv1.Deployment {
if len(p.Tolerations) > 0 {
deployment.Spec.Template.Spec.Tolerations = append(deployment.Spec.Template.Spec.Tolerations, p.Tolerations...)
}

if p.RuntimeClassName != nil {
deployment.Spec.Template.Spec.RuntimeClassName = p.RuntimeClassName
}

return deployment
}

Expand All @@ -56,9 +76,32 @@ func (p Policy) Remove(deployment *appsv1.Deployment) *appsv1.Deployment {
deployment.Spec.Template.Spec.Tolerations = newTolerations
}

if p.RuntimeClassName != nil {
if equalStrings(deployment.Spec.Template.Spec.RuntimeClassName, p.RuntimeClassName) {
deployment.Spec.Template.Spec.RuntimeClassName = nil
}
}

return deployment
}

func equalStrings(a, b *string) bool {
if a == nil && b == nil {
return true
}

if a != nil && b == nil {
return false
}

if a == nil && b != nil {
return false
}

// now we know both values are non-nil
return *a == *b
}

type policyClient struct {
kube typedCorev1.ConfigMapsGetter
}
Expand Down
77 changes: 77 additions & 0 deletions k8s/policies_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -153,6 +153,83 @@ func Test_TolerationsPolicy_Apply(t *testing.T) {
}
}

func Test_RunTimeClassPolicy_Apply(t *testing.T) {
expectedClass := "fastRunTime"
p := Policy{RuntimeClassName: &expectedClass}

basicDeployment := &appsv1.Deployment{
Spec: appsv1.DeploymentSpec{
Template: apiv1.PodTemplateSpec{
Spec: apiv1.PodSpec{
Containers: []apiv1.Container{
{Name: "testfunc", Image: "alpine:latest"},
},
},
},
},
}

basicDeployment = p.Apply(basicDeployment)
result := basicDeployment.Spec.Template.Spec.RuntimeClassName
if result == nil {
t.Fatalf("expected %s, got nil", expectedClass)
}
if expectedClass != *result {
t.Fatalf("expected %s, got %v", expectedClass, *result)
}
}

func Test_RunTimeClaasPolicy_Remove(t *testing.T) {
t.Run("remove matching runtime class ", func(t *testing.T) {
expectedClass := "fastRunTime"
p := Policy{RuntimeClassName: &expectedClass}

basicDeployment := &appsv1.Deployment{
Spec: appsv1.DeploymentSpec{
Template: apiv1.PodTemplateSpec{
Spec: apiv1.PodSpec{
RuntimeClassName: &expectedClass,
Containers: []apiv1.Container{
{Name: "testfunc", Image: "alpine:latest"},
},
},
},
},
}

basicDeployment = p.Remove(basicDeployment)
result := basicDeployment.Spec.Template.Spec.RuntimeClassName
if result != nil {
t.Fatalf("expected nil, got %s", *result)
}
})

t.Run("leaves runtime class that does not match", func(t *testing.T) {
expectedClass := "fastRunTime"
policyClass := "slowRunTime"
p := Policy{RuntimeClassName: &policyClass}

basicDeployment := &appsv1.Deployment{
Spec: appsv1.DeploymentSpec{
Template: apiv1.PodTemplateSpec{
Spec: apiv1.PodSpec{
RuntimeClassName: &expectedClass,
Containers: []apiv1.Container{
{Name: "testfunc", Image: "alpine:latest"},
},
},
},
},
}

basicDeployment = p.Remove(basicDeployment)
result := basicDeployment.Spec.Template.Spec.RuntimeClassName
if !equalStrings(result, &expectedClass) {
t.Fatalf("expected %s, got %v", expectedClass, result)
}
})
}

func Test_TolerationsPolicy_Remove(t *testing.T) {
tolerations := []corev1.Toleration{
{
Expand Down

0 comments on commit 86f7312

Please sign in to comment.