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 `bundle` resolvers. The individual resolvers can be enabled via the `enable-hub-resolver`, `enable-git-resolver`, and `enable-tekton-oci-bundles` feature flags.

Signed-off-by: Andrew Bayer <andrew.bayer@gmail.com>
  • Loading branch information
abayer committed Aug 30, 2022
1 parent d27c53c commit 5b0457a
Show file tree
Hide file tree
Showing 16 changed files with 407 additions and 30 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{}))
}
17 changes: 17 additions & 0 deletions pkg/apis/config/feature_flags.go
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,10 @@ 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

disableAffinityAssistantKey = "disable-affinity-assistant"
disableCredsInitKey = "disable-creds-init"
Expand All @@ -71,6 +75,11 @@ 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"
)

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

// GetFeatureFlagsConfigName returns the name of the configmap containing all
Expand Down Expand Up @@ -138,6 +149,12 @@ 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
}

// 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 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-tekton-oci-bundles 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 {
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.ContextWithBundleResolverEnabled(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
54 changes: 54 additions & 0 deletions pkg/resolution/resolver/framework/testing/fakecontroller.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,11 +24,13 @@ import (

"github.com/google/go-cmp/cmp"
"github.com/google/go-cmp/cmp/cmpopts"
"github.com/tektoncd/pipeline/pkg/apis/config"
"github.com/tektoncd/pipeline/pkg/apis/resolution/v1alpha1"
"github.com/tektoncd/pipeline/pkg/resolution/resolver/framework"
"github.com/tektoncd/pipeline/test"
"github.com/tektoncd/pipeline/test/diff"
"github.com/tektoncd/pipeline/test/names"
corev1 "k8s.io/api/core/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/types"
"k8s.io/apimachinery/pkg/util/clock"
Expand Down Expand Up @@ -95,6 +97,7 @@ func GetResolverFrameworkController(ctx context.Context, t *testing.T, d test.Da
func initializeResolverFrameworkControllerAssets(ctx context.Context, t *testing.T, d test.Data, resolver framework.Resolver, modifiers ...framework.ReconcilerModifier) (test.Assets, func()) {
t.Helper()
ctx, cancel := context.WithCancel(ctx)
ensureConfigurationConfigMapsExist(&d)
c, informers := test.SeedTestData(t, ctx, d)
configMapWatcher := cminformer.NewInformedWatcher(c.Kube, system.Namespace())
ctl := framework.NewController(ctx, resolver, modifiers...)(ctx, configMapWatcher)
Expand Down Expand Up @@ -125,3 +128,54 @@ func setClockOnReconciler(r *framework.Reconciler) {
r.Clock = testClock
}
}

func ensureConfigurationConfigMapsExist(d *test.Data) {
var defaultsExists, featureFlagsExists, artifactBucketExists, artifactPVCExists, metricsExists bool
for _, cm := range d.ConfigMaps {
if cm.Name == config.GetDefaultsConfigName() {
defaultsExists = true
}
if cm.Name == config.GetFeatureFlagsConfigName() {
featureFlagsExists = true
}
if cm.Name == config.GetArtifactBucketConfigName() {
artifactBucketExists = true
}
if cm.Name == config.GetArtifactPVCConfigName() {
artifactPVCExists = true
}
if cm.Name == config.GetMetricsConfigName() {
metricsExists = true
}
}
if !defaultsExists {
d.ConfigMaps = append(d.ConfigMaps, &corev1.ConfigMap{
ObjectMeta: metav1.ObjectMeta{Name: config.GetDefaultsConfigName(), Namespace: system.Namespace()},
Data: map[string]string{},
})
}
if !featureFlagsExists {
d.ConfigMaps = append(d.ConfigMaps, &corev1.ConfigMap{
ObjectMeta: metav1.ObjectMeta{Name: config.GetFeatureFlagsConfigName(), Namespace: system.Namespace()},
Data: map[string]string{},
})
}
if !artifactBucketExists {
d.ConfigMaps = append(d.ConfigMaps, &corev1.ConfigMap{
ObjectMeta: metav1.ObjectMeta{Name: config.GetArtifactBucketConfigName(), Namespace: system.Namespace()},
Data: map[string]string{},
})
}
if !artifactPVCExists {
d.ConfigMaps = append(d.ConfigMaps, &corev1.ConfigMap{
ObjectMeta: metav1.ObjectMeta{Name: config.GetArtifactPVCConfigName(), Namespace: system.Namespace()},
Data: map[string]string{},
})
}
if !metricsExists {
d.ConfigMaps = append(d.ConfigMaps, &corev1.ConfigMap{
ObjectMeta: metav1.ObjectMeta{Name: config.GetMetricsConfigName(), Namespace: system.Namespace()},
Data: map[string]string{},
})
}
}
Loading

0 comments on commit 5b0457a

Please sign in to comment.