Skip to content

Commit

Permalink
add a round-tripper to ensure we label non-OLM resources
Browse files Browse the repository at this point in the history
This round-tripper is added to our *rest.Config when it's possible to
detect that we're in a CI environment. Developers should set $CI=true to
get this behavior locally.

Signed-off-by: Steve Kuznetsov <[email protected]>
  • Loading branch information
stevekuznetsov committed Aug 23, 2023
1 parent 2976198 commit dd247bd
Show file tree
Hide file tree
Showing 3 changed files with 64 additions and 3 deletions.
6 changes: 5 additions & 1 deletion cmd/olm/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import (

configclientset "github.com/openshift/client-go/config/clientset/versioned"
configv1client "github.com/openshift/client-go/config/clientset/versioned/typed/config/v1"
"github.com/operator-framework/operator-lifecycle-manager/pkg/controller/operators/validatingroundtripper"
"github.com/sirupsen/logrus"
"github.com/spf13/pflag"
corev1 "k8s.io/api/core/v1"
Expand Down Expand Up @@ -139,6 +140,9 @@ func main() {
}
config := mgr.GetConfig()

// create a config that validates we're creating objects with labels
validatingConfig := validatingroundtripper.Wrap(config)

versionedConfigClient, err := configclientset.NewForConfig(config)
if err != nil {
logger.WithError(err).Fatal("error configuring openshift proxy client")
Expand All @@ -147,7 +151,7 @@ func main() {
if err != nil {
logger.WithError(err).Fatal("error configuring config client")
}
opClient, err := operatorclient.NewClientFromRestConfig(config)
opClient, err := operatorclient.NewClientFromRestConfig(validatingConfig)
if err != nil {
logger.WithError(err).Fatal("error configuring operator client")
}
Expand Down
8 changes: 6 additions & 2 deletions pkg/controller/operators/catalog/operator.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import (
"sync"
"time"

"github.com/operator-framework/operator-lifecycle-manager/pkg/controller/operators/validatingroundtripper"
errorwrap "github.com/pkg/errors"
"github.com/sirupsen/logrus"
"google.golang.org/grpc/connectivity"
Expand Down Expand Up @@ -140,8 +141,11 @@ func NewOperator(ctx context.Context, kubeconfigPath string, clock utilclock.Clo
return nil, err
}

// create a config that validates we're creating objects with labels
validatingConfig := validatingroundtripper.Wrap(config)

// Create a new client for dynamic types (CRs)
dynamicClient, err := dynamic.NewForConfig(config)
dynamicClient, err := dynamic.NewForConfig(validatingConfig)
if err != nil {
return nil, err
}
Expand All @@ -152,7 +156,7 @@ func NewOperator(ctx context.Context, kubeconfigPath string, clock utilclock.Clo
}

// Create a new queueinformer-based operator.
opClient, err := operatorclient.NewClientFromRestConfig(config)
opClient, err := operatorclient.NewClientFromRestConfig(validatingConfig)
if err != nil {
return nil, err
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
package validatingroundtripper

import (
"fmt"
"net/http"
"os"

"github.com/operator-framework/operator-lifecycle-manager/pkg/controller/install"
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
"k8s.io/apimachinery/pkg/util/yaml"
"k8s.io/client-go/rest"
)

type validatingRoundTripper struct {
delegate http.RoundTripper
}

func (rt *validatingRoundTripper) RoundTrip(req *http.Request) (*http.Response, error) {
if req.Method == "POST" {
b, err := req.GetBody()
if err != nil {
panic(err)
}
dec := yaml.NewYAMLOrJSONDecoder(b, 10)
unstructuredObject := &unstructured.Unstructured{}
if err := dec.Decode(unstructuredObject); err != nil {
panic(fmt.Errorf("error decoding object to an unstructured object: %w", err))
}
gvk := unstructuredObject.GroupVersionKind()
if gvk.Kind != "Event" {
if labels := unstructuredObject.GetLabels(); labels[install.OLMManagedLabelKey] != install.OLMManagedLabelValue {
panic(fmt.Errorf("%s.%s/%v %s/%s does not have labels[%s]=%s", gvk.Kind, gvk.Group, gvk.Version, unstructuredObject.GetNamespace(), unstructuredObject.GetName(), install.OLMManagedLabelKey, install.OLMManagedLabelValue))
}
}
}
return rt.delegate.RoundTrip(req)
}

var _ http.RoundTripper = (*validatingRoundTripper)(nil)

// Wrap is meant to be used in developer environments and CI to make it easy to find places
// where we accidentally create Kubernetes objects without our management label.
func Wrap(cfg *rest.Config) *rest.Config {
if _, set := os.LookupEnv("CI"); !set {
return cfg
}

cfgCopy := *cfg
cfgCopy.Wrap(func(rt http.RoundTripper) http.RoundTripper {
return &validatingRoundTripper{delegate: rt}
})
return &cfgCopy
}

0 comments on commit dd247bd

Please sign in to comment.