Skip to content

Commit

Permalink
feat: EKS IAM Roles for Service Accounts for Runner Pods
Browse files Browse the repository at this point in the history
One of the pod recreation conditions has been modified to use hash of runner spec, so that the controller does not keep restarting pods mutated by admission webhooks. This naturally allows us, for example, to use IRSA for EKS that requires its admission webhook to mutate the runner pod to have additional, IRSA-related volumes, volume mounts and env.

Resolves #200
  • Loading branch information
Yusuke Kuoka committed Dec 7, 2020
1 parent 85c29a9 commit c1deeaf
Show file tree
Hide file tree
Showing 3 changed files with 63 additions and 3 deletions.
24 changes: 21 additions & 3 deletions controllers/runner_controller.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ package controllers
import (
"context"
"fmt"
"reflect"
"github.com/summerwind/actions-runner-controller/hash"
"strings"

"github.com/go-logr/logr"
Expand All @@ -39,6 +39,8 @@ import (
const (
containerName = "runner"
finalizerName = "runner.actions.summerwind.dev"

runnerHashAnnotationKey = "runner-hash"
)

// RunnerReconciler reconciles a Runner object
Expand Down Expand Up @@ -198,7 +200,10 @@ func (r *RunnerReconciler) Reconcile(req ctrl.Request) (ctrl.Result, error) {
return ctrl.Result{}, nil
}

if !runnerBusy && (!reflect.DeepEqual(pod.Spec.Containers[0].Env, newPod.Spec.Containers[0].Env) || pod.Spec.Containers[0].Image != newPod.Spec.Containers[0].Image) {
curHash := pod.Annotations[runnerHashAnnotationKey]
newHash := newPod.Annotations[runnerHashAnnotationKey]

if !runnerBusy && curHash != newHash {
restart = true
}

Expand Down Expand Up @@ -357,12 +362,25 @@ func (r *RunnerReconciler) newPod(runner v1alpha1.Runner) (corev1.Pod, error) {
}

env = append(env, runner.Spec.Env...)

annotations := map[string]string{}

for k, v := range runner.Annotations {
annotations[k] = v
}

// This implies that we recreate the runner pod whenever the runner has changes in:
// - metadata.labels
// - metadata.annotations
// - metadata.spec (including image, env, organization, repository, group, token, and so on)
annotations[runnerHashAnnotationKey] = hash.FNVHashStringObjects(runner.Labels, runner.Annotations, runner.Spec)

pod := corev1.Pod{
ObjectMeta: metav1.ObjectMeta{
Name: runner.Name,
Namespace: runner.Namespace,
Labels: runner.Labels,
Annotations: runner.Annotations,
Annotations: annotations,
},
Spec: corev1.PodSpec{
RestartPolicy: "OnFailure",
Expand Down
17 changes: 17 additions & 0 deletions hash/fnv.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
package hash

import (
"fmt"
"hash/fnv"
"k8s.io/apimachinery/pkg/util/rand"
)

func FNVHashStringObjects(objs ...interface{}) string {
hash := fnv.New32a()

for _, obj := range objs {
DeepHashObject(hash, obj)
}

return rand.SafeEncodeString(fmt.Sprint(hash.Sum32()))
}
25 changes: 25 additions & 0 deletions hash/hash.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
// Copyright 2015 The Kubernetes Authors.
// hash.go is copied from kubernetes's pkg/util/hash.go
// See https://github.com/kubernetes/kubernetes/blob/e1c617a88ec286f5f6cb2589d6ac562d095e1068/pkg/util/hash/hash.go#L25-L37

package hash

import (
"hash"

"github.com/davecgh/go-spew/spew"
)

// DeepHashObject writes specified object to hash using the spew library
// which follows pointers and prints actual values of the nested objects
// ensuring the hash does not change when a pointer changes.
func DeepHashObject(hasher hash.Hash, objectToWrite interface{}) {
hasher.Reset()
printer := spew.ConfigState{
Indent: " ",
SortKeys: true,
DisableMethods: true,
SpewKeys: true,
}
printer.Fprintf(hasher, "%#v", objectToWrite)
}

0 comments on commit c1deeaf

Please sign in to comment.