Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[remote-resolution] Proof-of-Concept Controller #806

Closed
wants to merge 1 commit into from
Closed
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
4 changes: 4 additions & 0 deletions remote-resolution/OWNERS
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
# The OWNERS file is used by prow to automatically merge approved PRs.

approvers:
- sbwsg
65 changes: 65 additions & 0 deletions remote-resolution/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
# Remote Resolution Experimental Controller

This directory contains a proof-of-concept controller for testing
alternative implementations of [Remote
Resolution](https://github.com/tektoncd/community/blob/main/teps/0060-remote-resource-resolution.md).

## How to Try

1. Ensure [Pipelines](https://github.com/tektoncd/pipeline) and
[Triggers](https://github.com/tektoncd/triggers) are both installed
in your Kubernetes cluster.
2. Run `ko apply -f ./config` from the directory this readme is in.

Once that's done a new namespace will be created in your cluster called
`tekton-remote-resolution` and there will be controller + webhook
deployments running inside it.

To test it out try applying a PipelineRun using git resolution:

```bash
kubectl apply -f ./remote-resolution/pr-git.yaml
kubectl get pipelineruns -w
```

If everything's working as expected you should see this PR start in a
Pending state and then resolve, run and succeed.

## Resolution Modes

This proof-of-concept implements two of [the alternatives from
TEP-0060](https://github.com/tektoncd/community/blob/main/teps/0060-remote-resource-resolution.md#alternatives):

- A `ResourceRequest` CRD.
- A `ClusterInterceptor`-based HTTP interface.

Both of these modes support fetching `Pipelines` from `git` or `in-cluster`.

### Switching mode

By default the controller starts in `ResourceRequest` mode. It can be
switched into `ClusterInterceptor` mode by setting an environment
variable.

To change the mode open [./config/controller.yaml](./config/controller.yaml)
and set the `RESOLUTION_MODE` environment variable to `"rr"` for
`ResourceRequests` or `"ci"` for `ClusterInterceptors`.

## Resolver Framework

Also included here is a hokey attempt at a "Resolver Framework". At this
early stage it's just a golang interface that both `git` and
`in-cluster` resolvers implement, which makes it easy to support both
the `ResourceRequest` and `ClusterInterceptor` alternatives without
a large duplication of logic. The eventual intention is that writing a
basic resolver should only require a few dozen lines of Go and should be
independent of the "protocol" that's being used.

The interface is defined in
[./pkg/reconciler/framework/interface.go](./pkg/reconciler/framework/interface.go)
and the three included resolvers demonstrate how it can be implemented
for different use-cases:

[Git Resolver](./pkg/resolvers/gitref/resolver.go).
[ClusterRef Resolver](./pkg/resolvers/clusterref/resolver.go).
[No-Op Resolver](./pkg/resolvers/noopref/resolver.go).
42 changes: 42 additions & 0 deletions remote-resolution/cmd/controller/main.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
/*
Copyright 2021 The Tekton Authors

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

package main

import (
"os"

"github.com/tektoncd/experimental/remote-resolution/pkg/reconciler/framework"
"github.com/tektoncd/experimental/remote-resolution/pkg/reconciler/pipelineruns"
"github.com/tektoncd/experimental/remote-resolution/pkg/reconciler/resourcerequest"
"github.com/tektoncd/experimental/remote-resolution/pkg/resolvers/clusterref"
"github.com/tektoncd/experimental/remote-resolution/pkg/resolvers/gitref"
"github.com/tektoncd/experimental/remote-resolution/pkg/resolvers/noopref"

// This defines the shared main for injected controllers.
"knative.dev/pkg/injection/sharedmain"
)

func main() {
rmode := pipelineruns.NewResolutionMode(os.Getenv("RESOLUTION_MODE"))
sharedmain.Main("controller",
resourcerequest.NewController,
pipelineruns.NewPipelineRunResolverController(rmode),
framework.NewController(&gitref.Resolver{}, "8081"),
framework.NewController(&clusterref.Resolver{}, "8082"),
framework.NewController(&noopref.Resolver{}, "8083"),
)
}
127 changes: 127 additions & 0 deletions remote-resolution/cmd/webhook/main.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,127 @@
/*
Copyright 2021 The Tekton Authors

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

package main

import (
"context"

"k8s.io/apimachinery/pkg/runtime/schema"
"knative.dev/pkg/configmap"
"knative.dev/pkg/controller"
"knative.dev/pkg/injection/sharedmain"
"knative.dev/pkg/logging"
"knative.dev/pkg/metrics"
"knative.dev/pkg/signals"
"knative.dev/pkg/webhook"
"knative.dev/pkg/webhook/certificates"
"knative.dev/pkg/webhook/configmaps"
"knative.dev/pkg/webhook/resourcesemantics"
"knative.dev/pkg/webhook/resourcesemantics/defaulting"
"knative.dev/pkg/webhook/resourcesemantics/validation"

"github.com/tektoncd/experimental/remote-resolution/pkg/apis/resolution/v1alpha1"
)

var types = map[schema.GroupVersionKind]resourcesemantics.GenericCRD{
// List the types to validate.
v1alpha1.SchemeGroupVersion.WithKind("ResourceRequest"): &v1alpha1.ResourceRequest{},
}

var callbacks = map[schema.GroupVersionKind]validation.Callback{}

func NewDefaultingAdmissionController(ctx context.Context, cmw configmap.Watcher) *controller.Impl {
return defaulting.NewAdmissionController(ctx,

// Name of the resource webhook.
"defaulting.webhook.resolution.tekton.dev",

// The path on which to serve the webhook.
"/defaulting",

// The resources to default.
types,

// A function that infuses the context passed to Validate/SetDefaults with custom metadata.
func(ctx context.Context) context.Context {
// Here is where you would infuse the context with state
// (e.g. attach a store with configmap data)
return ctx
},

// Whether to disallow unknown fields.
true,
)
}

func NewValidationAdmissionController(ctx context.Context, cmw configmap.Watcher) *controller.Impl {
return validation.NewAdmissionController(ctx,

// Name of the resource webhook.
"validation.webhook.resolution.tekton.dev",

// The path on which to serve the webhook.
"/resource-validation",

// The resources to validate.
types,

// A function that infuses the context passed to Validate/SetDefaults with custom metadata.
func(ctx context.Context) context.Context {
// Here is where you would infuse the context with state
// (e.g. attach a store with configmap data)
return ctx
},

// Whether to disallow unknown fields.
true,

// Extra validating callbacks to be applied to resources.
callbacks,
)
}

func NewConfigValidationController(ctx context.Context, cmw configmap.Watcher) *controller.Impl {
return configmaps.NewAdmissionController(ctx,

// Name of the configmap webhook.
"config.webhook.resolution.tekton.dev",

// The path on which to serve the webhook.
"/config-validation",

// The configmaps to validate.
configmap.Constructors{
logging.ConfigMapName(): logging.NewConfigFromConfigMap,
metrics.ConfigMapName(): metrics.NewObservabilityConfigFromConfigMap,
},
)
}

func main() {
ctx := webhook.WithOptions(signals.NewContext(), webhook.Options{
ServiceName: "webhook",
Port: 8443,
SecretName: "webhook-certs",
})

sharedmain.WebhookMainWithContext(ctx, "webhook",
certificates.NewController,
NewDefaultingAdmissionController,
NewValidationAdmissionController,
NewConfigValidationController,
)
}
21 changes: 21 additions & 0 deletions remote-resolution/config/100-namespace.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
# Copyright 2021 The Tekton Authors
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# https://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

apiVersion: v1
kind: Namespace
metadata:
name: tekton-remote-resolution
labels:
istio-injection: enabled
resolution.tekton.dev/release: devel
Loading