Skip to content

Commit

Permalink
Add combined remote resolvers binary
Browse files Browse the repository at this point in the history
Part of #4710

This adds the `hub`, `git`, and `bundles` resolvers. The individual resolvers can be enabled via the `enable-hub-resolver`, `enable-git-resolver`, and `enable-bundles-resolver` feature flags.

Signed-off-by: Andrew Bayer <andrew.bayer@gmail.com>
  • Loading branch information
abayer authored and tekton-robot committed Aug 30, 2022
1 parent cd8f4f0 commit 9d9aa9d
Show file tree
Hide file tree
Showing 21 changed files with 423 additions and 35 deletions.
1 change: 1 addition & 0 deletions cmd/resolvers/kodata/HEAD
1 change: 1 addition & 0 deletions cmd/resolvers/kodata/LICENSE
1 change: 1 addition & 0 deletions cmd/resolvers/kodata/refs
1 change: 1 addition & 0 deletions cmd/resolvers/kodata/third_party
37 changes: 37 additions & 0 deletions cmd/resolvers/main.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
/*
Copyright 2022 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 (
"github.com/tektoncd/pipeline/pkg/apis/resolution/v1alpha1"
"github.com/tektoncd/pipeline/pkg/resolution/resolver/bundle"
"github.com/tektoncd/pipeline/pkg/resolution/resolver/framework"
"github.com/tektoncd/pipeline/pkg/resolution/resolver/git"
"github.com/tektoncd/pipeline/pkg/resolution/resolver/hub"
filteredinformerfactory "knative.dev/pkg/client/injection/kube/informers/factory/filtered"
"knative.dev/pkg/injection/sharedmain"
"knative.dev/pkg/signals"
)

func main() {
ctx := filteredinformerfactory.WithSelectors(signals.NewContext(), v1alpha1.ManagedByLabelKey)

sharedmain.MainWithContext(ctx, "controller",
framework.NewController(ctx, &git.Resolver{}),
framework.NewController(ctx, &hub.Resolver{}),
framework.NewController(ctx, &bundle.Resolver{}))
}
4 changes: 2 additions & 2 deletions docs/bundle-resolver.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

## Resolver Type

This Resolver responds to type `bundle`.
This Resolver responds to type `bundles`.

## Parameters

Expand All @@ -17,7 +17,7 @@ This Resolver responds to type `bundle`.

- A cluster running Tekton Pipeline v0.40.0 or later, with the `alpha` feature gate enabled.
- The [built-in remote resolvers installed](./install.md#installing-and-configuring-remote-task-and-pipeline-resolution).
- The `enable-tekton-oci-bundles` feature flag set to `true`.
- The `enable-bundles-resolver` feature flag set to `true`.

## Configuration

Expand Down
2 changes: 1 addition & 1 deletion docs/install.md
Original file line number Diff line number Diff line change
Expand Up @@ -287,7 +287,7 @@ Three remote resolvers are currently provided as part of the `resolvers.yaml` in
By default, these remote resolvers are disabled. Each resolver is enabled by setting
[the appropriate feature flag](#customizing-the-pipelines-controller-behavior).

1. [The `bundle` resolver](./bundle-resolver.md), enabled by setting the `enable-tekton-oci-bundles`
1. [The `bundles` resolver](./bundle-resolver.md), enabled by setting the `enable-bundles-resolver`
feature flag to `true`.
1. [The `git` resolver](./git-resolver.md), enabled by setting the `enable-git-resolver`
feature flag to `true`.
Expand Down
2 changes: 1 addition & 1 deletion docs/resolution-getting-started.md
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ kubectl patch -n tekton-pipelines configmap feature-flags -p '{"data":{"enable-a

The feature flags for the built-in resolvers are:

* The `bundles` resolver: `enable-tekton-oci-bundles`
* The `bundles` resolver: `enable-bundles-resolver`
* The `git` resolver: `enable-git-resolver`
* The `hub` resolver: `enable-hub-resolver`

Expand Down
2 changes: 1 addition & 1 deletion docs/resolution.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ For new users getting started with Tekton Pipeilne remote resolution, check out

## Built-in Resolvers

1. [The `bundle` resolver](./bundle-resolver.md), enabled by setting the `enable-tekton-oci-bundles`
1. [The `bundles` resolver](./bundle-resolver.md), enabled by setting the `enable-bundles-resolver`
feature flag to `true`.
1. [The `git` resolver](./git-resolver.md), enabled by setting the `enable-git-resolver`
feature flag to `true`.
Expand Down
26 changes: 26 additions & 0 deletions pkg/apis/config/feature_flags.go
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,12 @@ const (
DefaultSendCloudEventsForRuns = false
// DefaultEmbeddedStatus is the default value for "embedded-status".
DefaultEmbeddedStatus = FullEmbeddedStatus
// DefaultEnableGitResolver is the default value for "enable-git-resolver".
DefaultEnableGitResolver = false
// DefaultEnableHubResolver is the default value for "enable-hub-resolver".
DefaultEnableHubResolver = false
// DefaultEnableBundlesResolver is the default value for "enable-bundles-resolver".
DefaultEnableBundlesResolver = false

disableAffinityAssistantKey = "disable-affinity-assistant"
disableCredsInitKey = "disable-creds-init"
Expand All @@ -71,6 +77,13 @@ const (
enableAPIFields = "enable-api-fields"
sendCloudEventsForRuns = "send-cloudevents-for-runs"
embeddedStatus = "embedded-status"

// EnableGitResolver is the flag used to enable the git remote resolver
EnableGitResolver = "enable-git-resolver"
// EnableHubResolver is the flag used to enable the hub remote resolver
EnableHubResolver = "enable-hub-resolver"
// EnableBundlesResolver is the flag used to enable the bundle remote resolver
EnableBundlesResolver = "enable-bundles-resolver"
)

// FeatureFlags holds the features configurations
Expand All @@ -87,6 +100,9 @@ type FeatureFlags struct {
SendCloudEventsForRuns bool
AwaitSidecarReadiness bool
EmbeddedStatus string
EnableGitResolver bool
EnableHubResolver bool
EnableBundleResolver bool
}

// GetFeatureFlagsConfigName returns the name of the configmap containing all
Expand Down Expand Up @@ -138,6 +154,15 @@ func NewFeatureFlagsFromMap(cfgMap map[string]string) (*FeatureFlags, error) {
if err := setEmbeddedStatus(cfgMap, DefaultEmbeddedStatus, &tc.EmbeddedStatus); err != nil {
return nil, err
}
if err := setFeature(EnableGitResolver, DefaultEnableGitResolver, &tc.EnableGitResolver); err != nil {
return nil, err
}
if err := setFeature(EnableHubResolver, DefaultEnableHubResolver, &tc.EnableHubResolver); err != nil {
return nil, err
}
if err := setFeature(EnableBundlesResolver, DefaultEnableBundlesResolver, &tc.EnableBundleResolver); err != nil {
return nil, err
}

// Given that they are alpha features, Tekton Bundles and Custom Tasks should be switched on if
// enable-api-fields is "alpha". If enable-api-fields is not "alpha" then fall back to the value of
Expand All @@ -147,6 +172,7 @@ func NewFeatureFlagsFromMap(cfgMap map[string]string) (*FeatureFlags, error) {
// defeat the purpose of having a single shared gate for all alpha features.
if tc.EnableAPIFields == AlphaAPIFields {
tc.EnableTektonOCIBundles = true
tc.EnableBundleResolver = true
tc.EnableCustomTasks = true
} else {
if err := setFeature(enableTektonOCIBundles, DefaultEnableTektonOciBundles, &tc.EnableTektonOCIBundles); err != nil {
Expand Down
2 changes: 2 additions & 0 deletions pkg/apis/config/feature_flags_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,7 @@ func TestNewFeatureFlagsFromConfigMap(t *testing.T) {
EnableAPIFields: "alpha",
SendCloudEventsForRuns: true,
EmbeddedStatus: "both",
EnableBundleResolver: true,
},
fileName: "feature-flags-all-flags-set",
},
Expand All @@ -78,6 +79,7 @@ func TestNewFeatureFlagsFromConfigMap(t *testing.T) {
RequireGitSSHSecretKnownHosts: config.DefaultRequireGitSSHSecretKnownHosts,
SendCloudEventsForRuns: config.DefaultSendCloudEventsForRuns,
EmbeddedStatus: config.DefaultEmbeddedStatus,
EnableBundleResolver: true,
},
fileName: "feature-flags-enable-api-fields-overrides-bundles-and-custom-tasks",
},
Expand Down
19 changes: 19 additions & 0 deletions pkg/resolution/resolver/bundle/resolver.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,15 +18,19 @@ package bundle

import (
"context"
"errors"
"time"

"github.com/google/go-containerregistry/pkg/authn/k8schain"
"github.com/tektoncd/pipeline/pkg/apis/config"
"github.com/tektoncd/pipeline/pkg/resolution/common"
"github.com/tektoncd/pipeline/pkg/resolution/resolver/framework"
"k8s.io/client-go/kubernetes"
"knative.dev/pkg/client/injection/kube/client"
)

const disabledError = "cannot handle resolution request, enable-bundles-resolver feature flag not true"

// LabelValueBundleResolverType is the value to use for the
// resolution.tekton.dev/type label on resource requests
const LabelValueBundleResolverType string = "bundles"
Expand Down Expand Up @@ -65,6 +69,9 @@ func (r *Resolver) GetSelector(context.Context) map[string]string {

// ValidateParams ensures parameters from a request are as expected.
func (r *Resolver) ValidateParams(ctx context.Context, params map[string]string) error {
if r.isDisabled(ctx) {
return errors.New(disabledError)
}
if _, err := OptionsFromParams(ctx, params); err != nil {
return err
}
Expand All @@ -73,6 +80,9 @@ func (r *Resolver) ValidateParams(ctx context.Context, params map[string]string)

// Resolve uses the given params to resolve the requested file or resource.
func (r *Resolver) Resolve(ctx context.Context, params map[string]string) (framework.ResolvedResource, error) {
if r.isDisabled(ctx) {
return nil, errors.New(disabledError)
}
opts, err := OptionsFromParams(ctx, params)
if err != nil {
return nil, err
Expand All @@ -86,3 +96,12 @@ func (r *Resolver) Resolve(ctx context.Context, params map[string]string) (frame
defer cancelFn()
return GetEntry(ctx, kc, opts)
}

func (r *Resolver) isDisabled(ctx context.Context) bool {
cfg := config.FromContextOrDefaults(ctx)
if cfg.FeatureFlags.EnableTektonOCIBundles || cfg.FeatureFlags.EnableBundleResolver {
return false
}

return true
}
57 changes: 53 additions & 4 deletions pkg/resolution/resolver/bundle/resolver_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,10 @@ import (
"context"
"testing"

"github.com/google/go-cmp/cmp"
resolutioncommon "github.com/tektoncd/pipeline/pkg/resolution/common"
frtesting "github.com/tektoncd/pipeline/pkg/resolution/resolver/framework/testing"
"github.com/tektoncd/pipeline/test/diff"
)

func TestGetSelector(t *testing.T) {
Expand All @@ -42,7 +45,7 @@ func TestValidateParams(t *testing.T) {
ParamBundle: "bar",
ParamServiceAccount: "baz",
}
if err := resolver.ValidateParams(context.Background(), paramsWithTask); err != nil {
if err := resolver.ValidateParams(resolverContext(), paramsWithTask); err != nil {
t.Fatalf("unexpected error validating params: %v", err)
}

Expand All @@ -52,11 +55,32 @@ func TestValidateParams(t *testing.T) {
ParamBundle: "bar",
ParamServiceAccount: "baz",
}
if err := resolver.ValidateParams(context.Background(), paramsWithPipeline); err != nil {
if err := resolver.ValidateParams(resolverContext(), paramsWithPipeline); err != nil {
t.Fatalf("unexpected error validating params: %v", err)
}
}

func TestValidateParamsDisabled(t *testing.T) {
resolver := Resolver{}

var err error

params := map[string]string{
ParamKind: "task",
ParamName: "foo",
ParamBundle: "bar",
ParamServiceAccount: "baz",
}
err = resolver.ValidateParams(context.Background(), params)
if err == nil {
t.Fatalf("expected disabled err")
}

if d := cmp.Diff(disabledError, err.Error()); d != "" {
t.Errorf("unexpected error: %s", diff.PrintWantGot(d))
}
}

func TestValidateParamsMissing(t *testing.T) {
resolver := Resolver{}

Expand All @@ -67,7 +91,7 @@ func TestValidateParamsMissing(t *testing.T) {
ParamName: "foo",
ParamServiceAccount: "baz",
}
err = resolver.ValidateParams(context.Background(), paramsMissingBundle)
err = resolver.ValidateParams(resolverContext(), paramsMissingBundle)
if err == nil {
t.Fatalf("expected missing kind err")
}
Expand All @@ -77,9 +101,34 @@ func TestValidateParamsMissing(t *testing.T) {
ParamBundle: "bar",
ParamServiceAccount: "baz",
}
err = resolver.ValidateParams(context.Background(), paramsMissingName)
err = resolver.ValidateParams(resolverContext(), paramsMissingName)
if err == nil {
t.Fatalf("expected missing name err")
}

}

func TestResolveDisabled(t *testing.T) {
resolver := Resolver{}

var err error

params := map[string]string{
ParamKind: "task",
ParamName: "foo",
ParamBundle: "bar",
ParamServiceAccount: "baz",
}
_, err = resolver.Resolve(context.Background(), params)
if err == nil {
t.Fatalf("expected disabled err")
}

if d := cmp.Diff(disabledError, err.Error()); d != "" {
t.Errorf("unexpected error: %s", diff.PrintWantGot(d))
}
}

func resolverContext() context.Context {
return frtesting.ContextWithBundlesResolverEnabled(context.Background())
}
27 changes: 26 additions & 1 deletion pkg/resolution/resolver/framework/configstore.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ package framework
import (
"context"

"github.com/tektoncd/pipeline/pkg/apis/config"
corev1 "k8s.io/api/core/v1"
"knative.dev/pkg/configmap"
)
Expand All @@ -44,10 +45,34 @@ func DataFromConfigMap(config *corev1.ConfigMap) (map[string]string, error) {
// ConfigStore wraps a knative untyped store and provides helper methods
// for working with a resolver's configuration data.
type ConfigStore struct {
*config.Store
resolverConfigName string
untyped *configmap.UntypedStore
}

// NewConfigStore creates a new untyped store for the resolver's configuration and a config.Store for general Pipeline configuration.
func NewConfigStore(resolverConfigName string, logger configmap.Logger) *ConfigStore {
return &ConfigStore{
Store: config.NewStore(logger),
resolverConfigName: resolverConfigName,
untyped: configmap.NewUntypedStore(
"resolver-config",
logger,
configmap.Constructors{
resolverConfigName: DataFromConfigMap,
},
),
}
}

// WatchConfigs uses the provided configmap.Watcher
// to setup watches for the config names provided in the
// Constructors map
func (store *ConfigStore) WatchConfigs(w configmap.Watcher) {
store.untyped.WatchConfigs(w)
store.Store.WatchConfigs(w)
}

// GetResolverConfig returns a copy of the resolver's current
// configuration or an empty map if the stored config is nil or invalid.
func (store *ConfigStore) GetResolverConfig() map[string]string {
Expand All @@ -65,7 +90,7 @@ func (store *ConfigStore) GetResolverConfig() map[string]string {
// data stored in it.
func (store *ConfigStore) ToContext(ctx context.Context) context.Context {
conf := store.GetResolverConfig()
return InjectResolverConfigToContext(ctx, conf)
return InjectResolverConfigToContext(store.Store.ToContext(ctx), conf)
}

// InjectResolverConfigToContext returns a new context with a
Expand Down
13 changes: 2 additions & 11 deletions pkg/resolution/resolver/framework/controller.go
Original file line number Diff line number Diff line change
Expand Up @@ -167,17 +167,8 @@ func watchConfigChanges(ctx context.Context, reconciler *Reconciler, cmw configm
if resolverConfigName == "" {
panic("resolver returned empty config name")
}
reconciler.configStore = &ConfigStore{
resolverConfigName: resolverConfigName,
untyped: configmap.NewUntypedStore(
"resolver-config",
logger,
configmap.Constructors{
resolverConfigName: DataFromConfigMap,
},
),
}
reconciler.configStore.untyped.WatchConfigs(cmw)
reconciler.configStore = NewConfigStore(resolverConfigName, logger)
reconciler.configStore.WatchConfigs(cmw)
}
}

Expand Down
Loading

0 comments on commit 9d9aa9d

Please sign in to comment.