Skip to content

Commit dd247bd

Browse files
add a round-tripper to ensure we label non-OLM resources
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]>
1 parent 2976198 commit dd247bd

File tree

3 files changed

+64
-3
lines changed

3 files changed

+64
-3
lines changed

cmd/olm/main.go

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ import (
1111

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

143+
// create a config that validates we're creating objects with labels
144+
validatingConfig := validatingroundtripper.Wrap(config)
145+
142146
versionedConfigClient, err := configclientset.NewForConfig(config)
143147
if err != nil {
144148
logger.WithError(err).Fatal("error configuring openshift proxy client")
@@ -147,7 +151,7 @@ func main() {
147151
if err != nil {
148152
logger.WithError(err).Fatal("error configuring config client")
149153
}
150-
opClient, err := operatorclient.NewClientFromRestConfig(config)
154+
opClient, err := operatorclient.NewClientFromRestConfig(validatingConfig)
151155
if err != nil {
152156
logger.WithError(err).Fatal("error configuring operator client")
153157
}

pkg/controller/operators/catalog/operator.go

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ import (
1111
"sync"
1212
"time"
1313

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

144+
// create a config that validates we're creating objects with labels
145+
validatingConfig := validatingroundtripper.Wrap(config)
146+
143147
// Create a new client for dynamic types (CRs)
144-
dynamicClient, err := dynamic.NewForConfig(config)
148+
dynamicClient, err := dynamic.NewForConfig(validatingConfig)
145149
if err != nil {
146150
return nil, err
147151
}
@@ -152,7 +156,7 @@ func NewOperator(ctx context.Context, kubeconfigPath string, clock utilclock.Clo
152156
}
153157

154158
// Create a new queueinformer-based operator.
155-
opClient, err := operatorclient.NewClientFromRestConfig(config)
159+
opClient, err := operatorclient.NewClientFromRestConfig(validatingConfig)
156160
if err != nil {
157161
return nil, err
158162
}
Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
package validatingroundtripper
2+
3+
import (
4+
"fmt"
5+
"net/http"
6+
"os"
7+
8+
"github.com/operator-framework/operator-lifecycle-manager/pkg/controller/install"
9+
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
10+
"k8s.io/apimachinery/pkg/util/yaml"
11+
"k8s.io/client-go/rest"
12+
)
13+
14+
type validatingRoundTripper struct {
15+
delegate http.RoundTripper
16+
}
17+
18+
func (rt *validatingRoundTripper) RoundTrip(req *http.Request) (*http.Response, error) {
19+
if req.Method == "POST" {
20+
b, err := req.GetBody()
21+
if err != nil {
22+
panic(err)
23+
}
24+
dec := yaml.NewYAMLOrJSONDecoder(b, 10)
25+
unstructuredObject := &unstructured.Unstructured{}
26+
if err := dec.Decode(unstructuredObject); err != nil {
27+
panic(fmt.Errorf("error decoding object to an unstructured object: %w", err))
28+
}
29+
gvk := unstructuredObject.GroupVersionKind()
30+
if gvk.Kind != "Event" {
31+
if labels := unstructuredObject.GetLabels(); labels[install.OLMManagedLabelKey] != install.OLMManagedLabelValue {
32+
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))
33+
}
34+
}
35+
}
36+
return rt.delegate.RoundTrip(req)
37+
}
38+
39+
var _ http.RoundTripper = (*validatingRoundTripper)(nil)
40+
41+
// Wrap is meant to be used in developer environments and CI to make it easy to find places
42+
// where we accidentally create Kubernetes objects without our management label.
43+
func Wrap(cfg *rest.Config) *rest.Config {
44+
if _, set := os.LookupEnv("CI"); !set {
45+
return cfg
46+
}
47+
48+
cfgCopy := *cfg
49+
cfgCopy.Wrap(func(rt http.RoundTripper) http.RoundTripper {
50+
return &validatingRoundTripper{delegate: rt}
51+
})
52+
return &cfgCopy
53+
}

0 commit comments

Comments
 (0)