Skip to content

Commit

Permalink
Merge pull request #9 from lngoquy1/ibefore
Browse files Browse the repository at this point in the history
add support for prepending initContainers during injection
  • Loading branch information
krmayankk authored May 4, 2020
2 parents 7903411 + 52d8694 commit 4732abb
Show file tree
Hide file tree
Showing 8 changed files with 112 additions and 17 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
# Files generated by JetBrains IDEs, e.g. IntelliJ IDEA
.idea/
*.iml

5 changes: 4 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -84,7 +84,8 @@ mutationConfigs:
volumeMounts:
- name: "volume-mounts"
containerRefs: ["rsyslog-sidecar"]
initContainers: ["rsyslog-init"]
initContainersBeforePodInitContainers: ["vault-init"]
initContainers: ["rsyslog-init", "vault-init"]
containers: ["rsyslog-sidecar"]
volumes: ["rsyslog-spool-vol", "rsyslog-conf-tpl", "rsyslog-conf-gen"]
volumeMounts: []
Expand All @@ -101,6 +102,8 @@ the above example, the mutating webhook only looks at the annotations that begi
`annotationTrigger`: The injection is only triggered if the kPod has the following annotation
rsyslog.k8s-integration.sfdc.com/inject present

`initContainersBeforePodInitContainers`: This is a list of init containers to inject before all other init containers

`initContainers`: This is a list of init containers to inject when the annotation is present on
the pod. The name of the initContainers should match an init container in the -sidecar-config-file

Expand Down
28 changes: 25 additions & 3 deletions pkg/injectionwebhook/webhook.go
Original file line number Diff line number Diff line change
Expand Up @@ -441,9 +441,12 @@ func (whsvr *WebhookServer) createPatches(pod *corev1.Pod, mutationConfig *mutat
c.VolumeMounts = util.MergeVolumeMounts(c.VolumeMounts, sidecarConfig.VolumeMounts)
})...)

// Add InitContainers, keep the pod consistent with the patch
patches = append(patches, addContainers(pod.Spec.InitContainers, sidecarConfig.InitContainers, "/spec/initContainers")...)
pod.Spec.InitContainers = append(pod.Spec.InitContainers, sidecarConfig.InitContainers...)
// Adding initContainers, keep the pod consistent with the patch
initsBefore, initsAfter := getInitContainers(mutationConfig.InitContainersBeforePodInitContainers, sidecarConfig.InitContainers)
patches = append(addContainers(pod.Spec.InitContainers, initsBefore, "/spec/initContainers"), patches...)
pod.Spec.InitContainers = append(initsBefore, pod.Spec.InitContainers...)
patches = append(patches, addContainers(pod.Spec.InitContainers, initsAfter, "/spec/initContainers")...)
pod.Spec.InitContainers = append(pod.Spec.InitContainers, initsAfter...)

// Inject sidecar containers if we're NOT looking at a Pod OR this injection runs sidecars for Jobs
// A long-running sidecar Container can cause the Job to never complete,
Expand Down Expand Up @@ -509,3 +512,22 @@ func setAllStatusesToFailed(statusForMutations map[string]mutationStatus) {
}
}
}

func getInitContainers(initsBeforeNames []string, allInits []corev1.Container) ([]corev1.Container, []corev1.Container) {
var initsAfter, initsBefore []corev1.Container
m := make(map[string]bool)
for _, i := range initsBeforeNames {
m[i] = true
}

for _, i := range allInits {
if m[i.Name] {
biCopy := i.DeepCopy()
initsBefore = append(initsBefore, *biCopy)
} else {
aiCopy := i.DeepCopy()
initsAfter = append(initsAfter, *aiCopy)
}
}
return initsBefore, initsAfter
}
58 changes: 57 additions & 1 deletion pkg/injectionwebhook/webhook_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ package injectionwebhook
import (
"encoding/json"
"fmt"
"github.com/stretchr/testify/require"
"io/ioutil"
"net/http"
"net/http/httptest"
Expand Down Expand Up @@ -126,7 +127,7 @@ func TestMutate(t *testing.T) {
data, _ := ioutil.ReadFile(admissionReviewResultFile)
assert.Equal(t, string(data), string(admissionResponse.Patch),
fmt.Sprintf("## EXPECTED ##\n%s\n\n## ACTUAL ##\n%s", toHumanReadablePatch(data), toHumanReadablePatch(admissionResponse.Patch)))
assert.Len(t, statusForMutations, 5)
assert.Len(t, statusForMutations, 6)
for key, val := range statusForMutations {
if strings.HasPrefix(key, "keymaker") || strings.HasPrefix(key, "madkub") {
assert.Equal(t, succeededMutation, val)
Expand Down Expand Up @@ -541,6 +542,40 @@ func TestMutatePodWithBadVolumeMountAnnotations(t *testing.T) {
assert.Error(t, err)
}

func TestMutateWithInitBeforePodInit(t *testing.T) {
pod := corev1.Pod{
ObjectMeta: metav1.ObjectMeta{
Annotations: map[string]string{
"vaultReverse.k8s-integration.sfdc.com/inject": "enabled",
},
},
Spec: corev1.PodSpec{
Containers: []corev1.Container{
{
Name: "container",
},
},
InitContainers: []corev1.Container{
{
Name: "init-container",
},
},
ServiceAccountName: "secretServiceAccountName",
RestartPolicy: corev1.RestartPolicyAlways,
},
}

m := mc.MutationConfigs[5]
mutatedPod := doTestMutateAndExpectSuccess(t, pod, []mutationconfig.MutationConfig{m})
// consul-template-init is listed before pod's initContainers because of this line in mutationConfig:
// initContainersBeforePodInitContainers: ["consul-template-init"]
assert.Len(t, mutatedPod.Spec.InitContainers, 3)
assert.Equal(t, "consul-template-init", mutatedPod.Spec.InitContainers[0].Name)
assert.Equal(t, "init-container", mutatedPod.Spec.InitContainers[1].Name)
assert.Equal(t, "vault-agent-init", mutatedPod.Spec.InitContainers[2].Name)
assert.Equal(t, m.VolumeMounts[0], mutatedPod.Spec.InitContainers[1].VolumeMounts[0].Name)
}

func TestHealthz(t *testing.T) {
// Arrange
wc := &config.WebhookConfig{}
Expand All @@ -555,3 +590,24 @@ func TestHealthz(t *testing.T) {
// Assert
assert.Equal(t, http.StatusOK, respWriter.Code)
}

func TestGetInitContainersBeforeAfterPodInitContainers(t *testing.T) {
scf, _ := ioutil.ReadFile(sidecarConfigFile)
pod := corev1.Pod{
ObjectMeta: metav1.ObjectMeta{
Annotations: map[string]string{
"vaultReverse.k8s-integration.sfdc.com/inject": "enabled",
},
},
}
tpl, _ := template.New("test").Delims("{%", "%}").Parse(string(scf))
sc, err := sidecarconfig.RenderTemplate(pod, tpl)
require.NoError(t, err)
m := mc.MutationConfigs[5]
s := sc.NewPerMutationConfig(m)
initsBefore, initsAfter := getInitContainers(m.InitContainersBeforePodInitContainers, s.InitContainers)
assert.Len(t, initsBefore, 1)
assert.Len(t, initsAfter, 1)
assert.Equal(t, "consul-template-init", initsBefore[0].Name)
assert.Equal(t, "vault-agent-init", initsAfter[0].Name)
}
23 changes: 12 additions & 11 deletions pkg/mutationconfig/mutationconfig.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,17 +21,18 @@ type MutationConfigs struct {

// MutationConfig encapsulates a single mutation config
type MutationConfig struct {
Name string `yaml:"name"`
AnnotationNamespace string `yaml:"annotationNamespace"`
AnnotationTrigger string `yaml:"annotationTrigger"`
AnnotationConfig annotationConfig `yaml:"annotationConfig,flow"`
InitContainers []string `yaml:"initContainers,flow"`
Containers []string `yaml:"containers,flow"`
Volumes []string `yaml:"volumes,flow"`
VolumeMounts []string `yaml:"volumeMounts,flow"`
IgnoreNamespaces []string `yaml:"ignoreNamespaces,flow"`
WhitelistNamespaces []string `yaml:"whitelistNamespaces,flow"`
ImplementsSidecarLifecycle bool `yaml:"implementsSidecarLifecycle,omitempty,flow"`
Name string `yaml:"name"`
AnnotationNamespace string `yaml:"annotationNamespace"`
AnnotationTrigger string `yaml:"annotationTrigger"`
AnnotationConfig annotationConfig `yaml:"annotationConfig,flow"`
InitContainersBeforePodInitContainers []string `yaml:"initContainersBeforePodInitContainers,omitempty,flow"`
InitContainers []string `yaml:"initContainers,flow"`
Containers []string `yaml:"containers,flow"`
Volumes []string `yaml:"volumes,flow"`
VolumeMounts []string `yaml:"volumeMounts,flow"`
IgnoreNamespaces []string `yaml:"ignoreNamespaces,flow"`
WhitelistNamespaces []string `yaml:"whitelistNamespaces,flow"`
ImplementsSidecarLifecycle bool `yaml:"implementsSidecarLifecycle,omitempty,flow"`
}

type annotationConfig struct {
Expand Down
2 changes: 1 addition & 1 deletion pkg/sidecarconfig/sidecarconfig_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@ func TestLoadConfig(t *testing.T) {
assert.Len(t, s.InitContainers, 8)
assert.Len(t, s.Volumes, 13)
assert.Len(t, s.Containers, 6)
assert.Len(t, s.VolumeMounts, 6)
assert.Len(t, s.VolumeMounts, 7)
}

func TestNewPerMutationConfig(t *testing.T) {
Expand Down
10 changes: 10 additions & 0 deletions testdata/mutationconfigs.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -52,4 +52,14 @@ mutationConfigs:
volumes: []
volumeMounts: []
ignoreNamespaces: []
whitelistNamespaces: []
- name: "vaultReverse"
annotationNamespace: "vaultReverse.k8s-integration.sfdc.com"
annotationTrigger: "inject"
initContainersBeforePodInitContainers: ["consul-template-init"]
initContainers: ["vault-agent-init", "consul-template-init"]
containers: ["vault-agent", "consul-template"]
volumes: ["vault-token", "secrets-volume", "consul-template-config", "aws-iam-credentials"]
volumeMounts: ["secrets-volume"]
ignoreNamespaces: []
whitelistNamespaces: []
2 changes: 2 additions & 0 deletions testdata/sidecarconfigs.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -268,6 +268,8 @@ volumeMounts:
name: keytabs
- mountPath: "/secrets/serviceaccount"
name: svcaccount
- mountPath: /secrets
name: secrets-volume
containers:
- name: simple-sidecar
- name: rsyslog-sidecar
Expand Down

0 comments on commit 4732abb

Please sign in to comment.