Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
---
apiVersion: admissionregistration.k8s.io/v1
kind: MutatingWebhookConfiguration
metadata:
labels:
app: tekton-operator
name: tekton-operator-webhook
name: webhook.operator.tekton.dev
webhooks:
- admissionReviewVersions:
- v1beta1
- v1
clientConfig:
service:
name: tekton-operator-webhook
namespace: openshift-operators
failurePolicy: Fail
name: webhook.operator.tekton.dev
sideEffects: None
---
apiVersion: admissionregistration.k8s.io/v1
kind: ValidatingWebhookConfiguration
metadata:
labels:
app: tekton-operator
name: tekton-operator-webhook
name: config.webhook.operator.tekton.dev
webhooks:
- admissionReviewVersions:
- v1beta1
- v1
clientConfig:
service:
name: tekton-operator-webhook
namespace: openshift-operators
failurePolicy: Fail
name: config.webhook.operator.tekton.dev
namespaceSelector:
matchExpressions:
- key: operator.tekton.dev/release
operator: Exists
sideEffects: None
---
apiVersion: admissionregistration.k8s.io/v1
kind: ValidatingWebhookConfiguration
metadata:
labels:
app: tekton-operator
name: tekton-operator-webhook
name: validation.webhook.operator.tekton.dev
webhooks:
- admissionReviewVersions:
- v1beta1
- v1
clientConfig:
service:
name: tekton-operator-webhook
namespace: openshift-operators
failurePolicy: Fail
name: validation.webhook.operator.tekton.dev
sideEffects: None
50 changes: 38 additions & 12 deletions pkg/webhook/webhook_init.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ import (
"github.com/tektoncd/operator/pkg/apis/operator/v1alpha1"
clientset "github.com/tektoncd/operator/pkg/client/clientset/versioned"
operatorclient "github.com/tektoncd/operator/pkg/client/injection/client"
"k8s.io/apimachinery/pkg/api/errors"
apierror "k8s.io/apimachinery/pkg/api/errors"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"

"github.com/tektoncd/operator/pkg/reconciler/common"
Expand All @@ -22,36 +22,62 @@ import (
)

const WEBHOOK_INSTALLERSET_LABEL = "validating-defaulting-webhooks.operator.tekton.dev"
const POD_NAMESPACE_ENV_KEY = "SYSTEM_NAMESPACE"

var (
ERR_NAMESPACE_ENV_NOT_SET = fmt.Errorf("Pod namespace env %q not set", POD_NAMESPACE_ENV_KEY)
)

func CreateWebhookResources(ctx context.Context) {
logger := logging.FromContext(ctx)

mfclient, err := mfc.NewClient(injection.GetConfig(ctx))
manifest, err := fetchManifests(ctx)
if err != nil {
logger.Fatalw("error creating initial manifest", zap.Error(err))
}

client := operatorclient.Get(ctx)
err = checkAndDeleteInstallerSet(ctx, client)
if err != nil {
logger.Fatalw("error creating client from injected config", zap.Error(err))
}

if err := createInstallerSet(ctx, client, *manifest); err != nil {
logger.Fatalw("error creating client from injected config", zap.Error(err))
}
}

func fetchManifests(ctx context.Context) (*mf.Manifest, error) {
logger := logging.FromContext(ctx)
mfclient, err := mfc.NewClient(injection.GetConfig(ctx))
if err != nil {
return nil, err
}
mflogger := zapr.NewLogger(logger.Named("manifestival").Desugar())
manifest, err := mf.ManifestFrom(mf.Slice{}, mf.UseClient(mfclient), mf.UseLogger(mflogger))
if err != nil {
logger.Fatalw("error creating initial manifest", zap.Error(err))
return nil, err
}

// Read manifests
koDataDir := os.Getenv(common.KoEnvKey)
validating_defaulting_webhooks := filepath.Join(koDataDir, "validating-defaulting-webhook")
if err := common.AppendManifest(&manifest, validating_defaulting_webhooks); err != nil {
logger.Fatalw("error creating initial manifest", zap.Error(err))
return nil, err
}
return manifestTransform(&manifest)
}

client := operatorclient.Get(ctx)
err = checkAndDeleteInstallerSet(ctx, client)
if err != nil {
logger.Fatalw("error creating client from injected config", zap.Error(err))
func manifestTransform(m *mf.Manifest) (*mf.Manifest, error) {
ns, ok := os.LookupEnv(POD_NAMESPACE_ENV_KEY)
if !ok || ns == "" {
return nil, ERR_NAMESPACE_ENV_NOT_SET
}

if err := createInstallerSet(ctx, client, manifest); err != nil {
logger.Fatalw("error creating client from injected config", zap.Error(err))
tfs := []mf.Transformer{
mf.InjectNamespace(ns),
}
result, err := m.Transform(tfs...)
return &result, err
}

func checkAndDeleteInstallerSet(ctx context.Context, oc clientset.Interface) error {
Expand All @@ -60,7 +86,7 @@ func checkAndDeleteInstallerSet(ctx context.Context, oc clientset.Interface) err
LabelSelector: WEBHOOK_INSTALLERSET_LABEL,
})
if err != nil {
if errors.IsNotFound(err) {
if apierror.IsNotFound(err) {
return nil
}
return err
Expand Down
59 changes: 59 additions & 0 deletions pkg/webhook/webhook_init_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
package webhook

import (
mf "github.com/manifestival/manifestival"
"gotest.tools/v3/assert"
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
"os"
"path/filepath"
"testing"
)

const (
KoEnvKey = "KO_DATA_PATH"
)

func TestCreateWebhookResources(t *testing.T) {
t.Run("transform manifest when pod namespace env is set", func(t *testing.T) {
namespace_new := "not-the-default-value"
testdataPath := filepath.Join("testdata", "validating-defaulting-webhook")
m, err := mf.ManifestFrom(mf.Path(testdataPath))
assert.NilError(t, err)
os.Setenv(POD_NAMESPACE_ENV_KEY, namespace_new)
defer func() {
os.Unsetenv(POD_NAMESPACE_ENV_KEY)
}()
mOut, err := manifestTransform(&m)
assert.NilError(t, err)
for _, res := range mOut.Resources() {
assertServiceNamespace(t, &res, namespace_new)
}

})
t.Run("return err when pod namespace env is not set", func(t *testing.T) {
testdataPath := filepath.Join("testdata", "validating-defaulting-webhook")
m, err := mf.ManifestFrom(mf.Path(testdataPath))
assert.NilError(t, err)
_, err = manifestTransform(&m)
assert.Error(t, err, ERR_NAMESPACE_ENV_NOT_SET.Error())
})
}

func assertServiceNamespace(t *testing.T, u *unstructured.Unstructured, ns string) {
t.Helper()
hooks, _, _ := unstructured.NestedFieldNoCopy(u.Object, "webhooks")
for _, hook := range hooks.([]interface{}) {
srv, found, err := unstructured.NestedFieldNoCopy(hook.(map[string]interface{}), "clientConfig", "service")
if err != nil {
assert.NilError(t, err)
}
if found {
m := srv.(map[string]interface{})
got := m["namespace"]
if got != ns {
t.Errorf("expected namespace %q, got %q", ns, got)
}
}
}

}