Skip to content

Commit

Permalink
works on my machine
Browse files Browse the repository at this point in the history
  • Loading branch information
Lucas Rodriguez committed May 17, 2024
1 parent 5bf7e01 commit db8deb0
Show file tree
Hide file tree
Showing 5 changed files with 193 additions and 13 deletions.
18 changes: 9 additions & 9 deletions src/internal/agent/hooks/pods.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,20 +11,24 @@ import (
"github.com/defenseunicorns/zarf/src/config"
"github.com/defenseunicorns/zarf/src/config/lang"
"github.com/defenseunicorns/zarf/src/internal/agent/operations"
"github.com/defenseunicorns/zarf/src/internal/agent/state"
"github.com/defenseunicorns/zarf/src/pkg/message"
"github.com/defenseunicorns/zarf/src/pkg/transform"
"github.com/defenseunicorns/zarf/src/types"
v1 "k8s.io/api/admission/v1"

corev1 "k8s.io/api/core/v1"
)

// NewPodMutationHook creates a new instance of pods mutation hook.
func NewPodMutationHook() operations.Hook {
func NewPodMutationHook(zarfState *types.ZarfState) operations.Hook {
message.Debug("hooks.NewMutationHook()")
return operations.Hook{
Create: mutatePod,
Update: mutatePod,
Create: func(r *v1.AdmissionRequest) (*operations.Result, error) {
return mutatePod(r, zarfState)
},
Update: func(r *v1.AdmissionRequest) (*operations.Result, error) {
return mutatePod(r, zarfState)
},
}
}

Expand All @@ -38,7 +42,7 @@ func parsePod(object []byte) (*corev1.Pod, error) {
return &pod, nil
}

func mutatePod(r *v1.AdmissionRequest) (*operations.Result, error) {
func mutatePod(r *v1.AdmissionRequest, zarfState *types.ZarfState) (*operations.Result, error) {
message.Debugf("hooks.mutatePod()(*v1.AdmissionRequest) - %#v , %s/%s: %#v", r.Kind, r.Namespace, r.Name, r.Operation)

var patchOperations []operations.PatchOperation
Expand All @@ -59,10 +63,6 @@ func mutatePod(r *v1.AdmissionRequest) (*operations.Result, error) {
zarfSecret := []corev1.LocalObjectReference{{Name: config.ZarfImagePullSecretName}}
patchOperations = append(patchOperations, operations.ReplacePatchOperation("/spec/imagePullSecrets", zarfSecret))

zarfState, err := state.GetZarfStateFromAgentPod()
if err != nil {
return nil, fmt.Errorf(lang.AgentErrGetState, err)
}
containerRegistryURL := zarfState.RegistryInfo.Address

// update the image host for each init container
Expand Down
2 changes: 1 addition & 1 deletion src/internal/agent/http/admission.go
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,7 @@ func (h *admissionHandler) Serve(hook operations.Hook) http.HandlerFunc {

result, err := hook.Execute(review.Request)
if err != nil {
message.WarnErr(err, lang.AgentErrBindHandler)
message.Warnf("%s: %s", lang.AgentErrBindHandler, err.Error())
w.WriteHeader(http.StatusInternalServerError)
return
}
Expand Down
5 changes: 3 additions & 2 deletions src/internal/agent/http/server.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,15 +11,16 @@ import (

"github.com/defenseunicorns/zarf/src/internal/agent/hooks"
"github.com/defenseunicorns/zarf/src/pkg/message"
"github.com/defenseunicorns/zarf/src/types"
"github.com/prometheus/client_golang/prometheus/promhttp"
)

// NewAdmissionServer creates a http.Server for the mutating webhook admission handler.
func NewAdmissionServer(port string) *http.Server {
func NewAdmissionServer(port string, zarfState *types.ZarfState) *http.Server {
message.Debugf("http.NewServer(%s)", port)

// Instances hooks
podsMutation := hooks.NewPodMutationHook()
podsMutation := hooks.NewPodMutationHook(zarfState)
fluxGitRepositoryMutation := hooks.NewGitRepositoryMutationHook()
argocdApplicationMutation := hooks.NewApplicationMutationHook()
argocdRepositoryMutation := hooks.NewRepositoryMutationHook()
Expand Down
174 changes: 174 additions & 0 deletions src/internal/agent/http/server_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,174 @@
// SPDX-License-Identifier: Apache-2.0
// SPDX-FileCopyrightText: 2021-Present The Zarf Authors

package http

import (
"bytes"
"encoding/json"
"net/http"
"net/http/httptest"
"testing"

"github.com/defenseunicorns/zarf/src/config"
"github.com/defenseunicorns/zarf/src/internal/agent/operations"
"github.com/defenseunicorns/zarf/src/types"
"github.com/stretchr/testify/require"
v1 "k8s.io/api/admission/v1"
corev1 "k8s.io/api/core/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/runtime"
)

// NewTestAdmissionServer creates a test server for the admission webhook.
func NewTestAdmissionServer(t *testing.T, zarfState *types.ZarfState) *httptest.Server {
t.Helper()
server := NewAdmissionServer("0", zarfState)
return httptest.NewServer(server.Handler)
}

// createPodAdmissionRequest creates an admission request for a pod.
func createPodAdmissionRequest(t *testing.T, operation v1.Operation, pod *corev1.Pod) *v1.AdmissionRequest {
t.Helper()
raw, err := json.Marshal(pod)
require.NoError(t, err)
return &v1.AdmissionRequest{
Operation: operation,
Kind: metav1.GroupVersionKind{
Group: "",
Version: "v1",
Kind: "Pod",
},
Object: runtime.RawExtension{
Raw: raw,
},
}
}

// sendAdmissionReview sends an admission review request to the server and returns the response.
func sendAdmissionReview(t *testing.T, server *httptest.Server, endpoint string, admissionReq *v1.AdmissionRequest) *v1.AdmissionResponse {
t.Helper()

b, err := json.Marshal(&v1.AdmissionReview{
Request: admissionReq,
})
require.NoError(t, err)

req := httptest.NewRequest(http.MethodPost, endpoint, bytes.NewBuffer(b))
req.Header.Set("Content-Type", "application/json")

rr := httptest.NewRecorder()
server.Config.Handler.ServeHTTP(rr, req)

require.Equal(t, http.StatusOK, rr.Code)

var admissionReview v1.AdmissionReview
err = json.NewDecoder(rr.Body).Decode(&admissionReview)
require.NoError(t, err)

resp := admissionReview.Response
require.NotNil(t, resp)
require.True(t, resp.Allowed)

return resp
}

// TestPodMutationWebhook tests the pod mutation webhook.
func TestPodMutationWebhook(t *testing.T) {
t.Parallel()

server := NewTestAdmissionServer(
t,
&types.ZarfState{
RegistryInfo: types.RegistryInfo{
Address: "127.0.0.1:31999",
},
})
defer server.Close()

tests := []struct {
name string
admissionReq *v1.AdmissionRequest
expectedPatch []operations.PatchOperation
}{
{
name: "pod with label should be mutated",
admissionReq: createPodAdmissionRequest(
t,
v1.Create,
&corev1.Pod{
ObjectMeta: metav1.ObjectMeta{
Name: "test-pod-mutation",
Namespace: "test-pod-mutation",
Labels: map[string]string{"should-be": "mutated"},
},
Spec: corev1.PodSpec{
Containers: []corev1.Container{
{
Name: "nginx",
Image: "nginx",
},
},
InitContainers: []corev1.Container{
{
Name: "busybox",
Image: "busybox",
},
},
EphemeralContainers: []corev1.EphemeralContainer{
{
EphemeralContainerCommon: corev1.EphemeralContainerCommon{
Name: "alpine",
Image: "alpine",
},
},
},
},
}),
expectedPatch: []operations.PatchOperation{
operations.ReplacePatchOperation("/spec/imagePullSecrets", []corev1.LocalObjectReference{{Name: config.ZarfImagePullSecretName}}),
operations.ReplacePatchOperation("/spec/initContainers/0/image", "127.0.0.1:31999/library/busybox:latest-zarf-2140033595"),
operations.ReplacePatchOperation("/spec/ephemeralContainers/0/image", "127.0.0.1:31999/library/alpine:latest-zarf-1117969859"),
operations.ReplacePatchOperation("/spec/containers/0/image", "127.0.0.1:31999/library/nginx:latest-zarf-3793515731"),
operations.ReplacePatchOperation("/metadata/labels/zarf-agent", "patched"),
},
},
{
name: "pod with zarf-agent patched label",
admissionReq: createPodAdmissionRequest(
t,
v1.Create,
&corev1.Pod{
ObjectMeta: metav1.ObjectMeta{
Name: "nginx",
Namespace: "nginx",
Labels: map[string]string{"zarf-agent": "patched"},
},
Spec: corev1.PodSpec{
Containers: []corev1.Container{
{
Name: "nginx",
Image: "nginx",
},
},
},
}),
expectedPatch: nil,
},
}

for _, tt := range tests {
tt := tt
t.Run(tt.name, func(t *testing.T) {
t.Parallel()
resp := sendAdmissionReview(t, server, "/mutate/pod", tt.admissionReq)
if tt.expectedPatch != nil {
expectedPatchJSON, err := json.Marshal(tt.expectedPatch)
require.NoError(t, err)
require.JSONEq(t, string(expectedPatchJSON), string(resp.Patch))
} else {
require.Nil(t, resp.Patch)
}
})
}
}
7 changes: 6 additions & 1 deletion src/internal/agent/start.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import (

"github.com/defenseunicorns/zarf/src/config/lang"
agentHttp "github.com/defenseunicorns/zarf/src/internal/agent/http"
"github.com/defenseunicorns/zarf/src/internal/agent/state"
"github.com/defenseunicorns/zarf/src/pkg/message"
)

Expand All @@ -30,7 +31,11 @@ const (
func StartWebhook() {
message.Debug("agent.StartWebhook()")

startServer(agentHttp.NewAdmissionServer(httpPort))
zarfState, err := state.GetZarfStateFromAgentPod()
if err != nil {
message.Fatal(err, err.Error())
}
startServer(agentHttp.NewAdmissionServer(httpPort, zarfState))
}

// StartHTTPProxy launches the zarf agent proxy in the cluster.
Expand Down

0 comments on commit db8deb0

Please sign in to comment.