Skip to content
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
The table of contents is too big for display.
Diff view
Diff view
  •  
  •  
  •  
2 changes: 2 additions & 0 deletions .goreleaser.yml
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@ builds:
asmflags: "{{ .Env.GO_BUILD_ASMFLAGS }}"
gcflags: "{{ .Env.GO_BUILD_GCFLAGS }}"
ldflags: "{{ .Env.GO_BUILD_LDFLAGS }}"
tags:
- "{{ .Env.GO_BUILD_TAGS }}"
goos:
- linux
goarch:
Expand Down
21 changes: 15 additions & 6 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -91,7 +91,7 @@ help-extended: #HELP Display extended help.

.PHONY: lint
lint: $(GOLANGCI_LINT) #HELP Run golangci linter.
$(GOLANGCI_LINT) run $(GOLANGCI_LINT_ARGS)
$(GOLANGCI_LINT) run --build-tags $(GO_BUILD_TAGS) $(GOLANGCI_LINT_ARGS)

.PHONY: tidy
tidy: #HELP Update dependencies.
Expand All @@ -111,15 +111,15 @@ verify: tidy fmt vet generate manifests #HELP Verify all generated code is up-to

.PHONY: fix-lint
fix-lint: $(GOLANGCI_LINT) #EXHELP Fix lint issues
$(GOLANGCI_LINT) run --fix $(GOLANGCI_LINT_ARGS)
$(GOLANGCI_LINT) run --fix --build-tags $(GO_BUILD_TAGS) $(GOLANGCI_LINT_ARGS)

.PHONY: fmt
fmt: #EXHELP Formats code
go fmt ./...

.PHONY: vet
vet: #EXHELP Run go vet against code.
go vet ./...
go vet -tags '$(GO_BUILD_TAGS)' ./...

.PHONY: test
test: manifests generate fmt vet test-unit test-e2e #HELP Run all tests.
Expand Down Expand Up @@ -148,10 +148,17 @@ UNIT_TEST_DIRS := $(shell go list ./... | grep -v /test/)
COVERAGE_UNIT_DIR := $(ROOT_DIR)/coverage/unit
test-unit: $(SETUP_ENVTEST) #HELP Run the unit tests
rm -rf $(COVERAGE_UNIT_DIR) && mkdir -p $(COVERAGE_UNIT_DIR)
eval $$($(SETUP_ENVTEST) use -p env $(ENVTEST_VERSION) $(SETUP_ENVTEST_BIN_DIR_OVERRIDE)) && CGO_ENABLED=1 go test -count=1 -race -short $(UNIT_TEST_DIRS) -cover -coverprofile ${ROOT_DIR}/coverage/unit.out -test.gocoverdir=$(ROOT_DIR)/coverage/unit

eval $$($(SETUP_ENVTEST) use -p env $(ENVTEST_VERSION) $(SETUP_ENVTEST_BIN_DIR_OVERRIDE)) && \
CGO_ENABLED=1 go test \
-tags '$(GO_BUILD_TAGS)' \
-cover -coverprofile ${ROOT_DIR}/coverage/unit.out \
-count=1 -race -short \
$(UNIT_TEST_DIRS) \
-test.gocoverdir=$(ROOT_DIR)/coverage/unit

E2E_REGISTRY_CERT_REF := ClusterIssuer/olmv1-ca # By default, we'll use a trusted CA for the registry.
image-registry: ## Setup in-cluster image registry
./hack/test/image-registry.sh $(E2E_REGISTRY_NAMESPACE) $(E2E_REGISTRY_NAME)
./hack/test/image-registry.sh $(E2E_REGISTRY_NAMESPACE) $(E2E_REGISTRY_NAME) $(E2E_REGISTRY_CERT_REF)

build-push-e2e-catalog: ## Build the testdata catalog used for e2e tests and push it to the image registry
./hack/test/build-push-e2e-catalog.sh $(E2E_REGISTRY_NAMESPACE) $(LOCAL_REGISTRY_HOST)/$(E2E_TEST_CATALOG_V1)
Expand All @@ -166,6 +173,7 @@ build-push-e2e-catalog: ## Build the testdata catalog used for e2e tests and pus
test-e2e: KIND_CLUSTER_NAME := operator-controller-e2e
test-e2e: KUSTOMIZE_BUILD_DIR := config/overlays/e2e
test-e2e: GO_BUILD_FLAGS := -cover
test-e2e: E2E_REGISTRY_CERT_REF := Issuer/selfsigned-issuer
test-e2e: run image-registry build-push-e2e-catalog registry-load-bundles e2e e2e-coverage kind-clean #HELP Run e2e test suite on local kind cluster

.PHONY: extension-developer-e2e
Expand Down Expand Up @@ -236,6 +244,7 @@ export CGO_ENABLED

export GIT_REPO := $(shell go list -m)
export VERSION_PATH := ${GIT_REPO}/internal/version
export GO_BUILD_TAGS := containers_image_openpgp
export GO_BUILD_ASMFLAGS := all=-trimpath=$(PWD)
export GO_BUILD_GCFLAGS := all=-trimpath=$(PWD)
export GO_BUILD_FLAGS :=
Expand Down
2 changes: 1 addition & 1 deletion Tiltfile
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,6 @@ repo = {

for r in repos:
if r == 'operator-controller':
deploy_repo('operator-controller', repo)
deploy_repo('operator-controller', repo, '-tags containers_image_openpgp')
else:
include('../{}/Tiltfile'.format(r))
118 changes: 86 additions & 32 deletions cmd/manager/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,21 +23,27 @@ import (
"net/http"
"os"
"path/filepath"
"strings"
"time"

"github.com/containers/image/v5/types"
"github.com/go-logr/logr"
"github.com/spf13/pflag"
"go.uber.org/zap/zapcore"
corev1 "k8s.io/api/core/v1"
apiextensionsv1client "k8s.io/apiextensions-apiserver/pkg/client/clientset/clientset/typed/apiextensions/v1"
"k8s.io/apimachinery/pkg/fields"
k8slabels "k8s.io/apimachinery/pkg/labels"
"k8s.io/apimachinery/pkg/selection"
k8stypes "k8s.io/apimachinery/pkg/types"
apimachineryrand "k8s.io/apimachinery/pkg/util/rand"
corev1client "k8s.io/client-go/kubernetes/typed/core/v1"
_ "k8s.io/client-go/plugin/pkg/client/auth"
"k8s.io/klog/v2"
"k8s.io/klog/v2/textlogger"
ctrl "sigs.k8s.io/controller-runtime"
crcache "sigs.k8s.io/controller-runtime/pkg/cache"
"sigs.k8s.io/controller-runtime/pkg/client"
crfinalizer "sigs.k8s.io/controller-runtime/pkg/finalizer"
"sigs.k8s.io/controller-runtime/pkg/healthz"
"sigs.k8s.io/controller-runtime/pkg/log/zap"
"sigs.k8s.io/controller-runtime/pkg/metrics/server"

catalogd "github.com/operator-framework/catalogd/api/core/v1alpha1"
Expand All @@ -52,7 +58,6 @@ import (
"github.com/operator-framework/operator-controller/internal/contentmanager"
"github.com/operator-framework/operator-controller/internal/controllers"
"github.com/operator-framework/operator-controller/internal/httputil"
"github.com/operator-framework/operator-controller/internal/labels"
"github.com/operator-framework/operator-controller/internal/resolve"
"github.com/operator-framework/operator-controller/internal/rukpak/preflights/crdupgradesafety"
"github.com/operator-framework/operator-controller/internal/rukpak/source"
Expand All @@ -66,6 +71,8 @@ var (
defaultSystemNamespace = "olmv1-system"
)

const authFilePrefix = "operator-controller-global-pull-secrets"

// podNamespace checks whether the controller is running in a Pod vs.
// being run locally by inspecting the namespace file that gets mounted
// automatically for Pods at runtime. If that file doesn't exist, then
Expand All @@ -87,6 +94,7 @@ func main() {
operatorControllerVersion bool
systemNamespace string
caCertDir string
globalPullSecret string
)
flag.StringVar(&metricsAddr, "metrics-bind-address", ":8080", "The address the metric endpoint binds to.")
flag.StringVar(&probeAddr, "health-probe-bind-address", ":8081", "The address the probe endpoint binds to.")
Expand All @@ -97,11 +105,9 @@ func main() {
flag.StringVar(&cachePath, "cache-path", "/var/cache", "The local directory path used for filesystem based caching")
flag.BoolVar(&operatorControllerVersion, "version", false, "Prints operator-controller version information")
flag.StringVar(&systemNamespace, "system-namespace", "", "Configures the namespace that gets used to deploy system resources.")
opts := zap.Options{
Development: true,
TimeEncoder: zapcore.RFC3339NanoTimeEncoder,
}
opts.BindFlags(flag.CommandLine)
flag.StringVar(&globalPullSecret, "global-pull-secret", "", "The <namespace>/<name> of the global pull secret that is going to be used to pull bundle images.")

klog.InitFlags(flag.CommandLine)

pflag.CommandLine.AddGoFlagSet(flag.CommandLine)
features.OperatorControllerFeatureGate.AddFlag(pflag.CommandLine)
Expand All @@ -112,37 +118,55 @@ func main() {
os.Exit(0)
}

ctrl.SetLogger(zap.New(zap.UseFlagOptions(&opts), zap.StacktraceLevel(zapcore.DPanicLevel)))
ctrl.SetLogger(textlogger.NewLogger(textlogger.NewConfig()))

setupLog.Info("starting up the controller", "version info", version.String())

if systemNamespace == "" {
systemNamespace = podNamespace()
authFilePath := filepath.Join(os.TempDir(), fmt.Sprintf("%s-%s.json", authFilePrefix, apimachineryrand.String(8)))
var globalPullSecretKey *k8stypes.NamespacedName
if globalPullSecret != "" {
secretParts := strings.Split(globalPullSecret, "/")
if len(secretParts) != 2 {
setupLog.Error(fmt.Errorf("incorrect number of components"), "value of global-pull-secret should be of the format <namespace>/<name>")
os.Exit(1)
}
globalPullSecretKey = &k8stypes.NamespacedName{Name: secretParts[1], Namespace: secretParts[0]}
}

dependentRequirement, err := k8slabels.NewRequirement(labels.OwnerKindKey, selection.In, []string{ocv1alpha1.ClusterExtensionKind})
if err != nil {
setupLog.Error(err, "unable to create dependent label selector for cache")
os.Exit(1)
if systemNamespace == "" {
systemNamespace = podNamespace()
}
dependentSelector := k8slabels.NewSelector().Add(*dependentRequirement)

setupLog.Info("set up manager")
cacheOptions := crcache.Options{
ByObject: map[client.Object]crcache.ByObject{
&ocv1alpha1.ClusterExtension{}: {Label: k8slabels.Everything()},
&catalogd.ClusterCatalog{}: {Label: k8slabels.Everything()},
},
DefaultNamespaces: map[string]crcache.Config{
systemNamespace: {LabelSelector: k8slabels.Everything()},
},
DefaultLabelSelector: k8slabels.Nothing(),
}
if globalPullSecretKey != nil {
cacheOptions.ByObject[&corev1.Secret{}] = crcache.ByObject{
Namespaces: map[string]crcache.Config{
globalPullSecretKey.Namespace: {
LabelSelector: k8slabels.Everything(),
FieldSelector: fields.SelectorFromSet(map[string]string{
"metadata.name": globalPullSecretKey.Name,
}),
},
},
}
}
mgr, err := ctrl.NewManager(ctrl.GetConfigOrDie(), ctrl.Options{
Scheme: scheme.Scheme,
Metrics: server.Options{BindAddress: metricsAddr},
HealthProbeBindAddress: probeAddr,
LeaderElection: enableLeaderElection,
LeaderElectionID: "9c4404e7.operatorframework.io",
Cache: crcache.Options{
ByObject: map[client.Object]crcache.ByObject{
&ocv1alpha1.ClusterExtension{}: {Label: k8slabels.Everything()},
&catalogd.ClusterCatalog{}: {Label: k8slabels.Everything()},
},
DefaultNamespaces: map[string]crcache.Config{
systemNamespace: {LabelSelector: k8slabels.Everything()},
},
DefaultLabelSelector: dependentSelector,
},
Cache: cacheOptions,
// LeaderElectionReleaseOnCancel defines if the leader should step down voluntarily
// when the Manager ends. This requires the binary to immediately end when the
// Manager is stopped, otherwise, this setting is unsafe. Setting this significantly
Expand Down Expand Up @@ -194,12 +218,24 @@ func main() {
setupLog.Error(err, "unable to create CA certificate pool")
os.Exit(1)
}
unpacker := &source.ImageRegistry{

unpacker := &source.ContainersImageRegistry{
BaseCachePath: filepath.Join(cachePath, "unpack"),
// TODO: This needs to be derived per extension via ext.Spec.InstallNamespace
AuthNamespace: systemNamespace,
CertPoolWatcher: certPoolWatcher,
}
SourceContextFunc: func(logger logr.Logger) (*types.SystemContext, error) {
srcContext := &types.SystemContext{
DockerCertPath: caCertDir,
OCICertPath: caCertDir,
}
if _, err := os.Stat(authFilePath); err == nil && globalPullSecretKey != nil {
logger.Info("using available authentication information for pulling image")
srcContext.AuthFilePath = authFilePath
} else if os.IsNotExist(err) {
logger.Info("no authentication information found for pulling image, proceeding without auth")
} else {
return nil, fmt.Errorf("could not stat auth file, error: %w", err)
}
return srcContext, nil
}}

clusterExtensionFinalizers := crfinalizer.NewFinalizers()
domain := ocv1alpha1.GroupVersion.Group
Expand Down Expand Up @@ -266,6 +302,20 @@ func main() {
setupLog.Error(err, "unable to create controller", "controller", "ClusterExtension")
os.Exit(1)
}

if globalPullSecretKey != nil {
setupLog.Info("creating SecretSyncer controller for watching secret", "Secret", globalPullSecret)
err := (&controllers.PullSecretReconciler{
Client: mgr.GetClient(),
AuthFilePath: authFilePath,
SecretKey: *globalPullSecretKey,
}).SetupWithManager(mgr)
if err != nil {
setupLog.Error(err, "unable to create controller", "controller", "SecretSyncer")
os.Exit(1)
}
}

//+kubebuilder:scaffold:builder

if err := mgr.AddHealthzCheck("healthz", healthz.Ping); err != nil {
Expand All @@ -283,6 +333,10 @@ func main() {
setupLog.Error(err, "problem running manager")
os.Exit(1)
}
if err := os.Remove(authFilePath); err != nil {
setupLog.Error(err, "failed to cleanup temporary auth file")
os.Exit(1)
}
}

type finalizerFunc func(ctx context.Context, obj client.Object) (crfinalizer.Result, error)
Expand Down
1 change: 0 additions & 1 deletion config/base/manager/manager.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -96,7 +96,6 @@ spec:
- "--secure-listen-address=0.0.0.0:8443"
- "--upstream=http://127.0.0.1:8080/"
- "--logtostderr=true"
- "--v=0"
ports:
- containerPort: 8443
protocol: TCP
Expand Down
7 changes: 7 additions & 0 deletions config/components/registries-conf/kustomization.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
apiVersion: kustomize.config.k8s.io/v1alpha1
kind: Component
namespace: olmv1-system
resources:
- registries_conf_configmap.yaml
patches:
- path: manager_e2e_registries_conf_patch.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
apiVersion: apps/v1
kind: Deployment
metadata:
name: controller-manager
namespace: system
spec:
template:
spec:
containers:
- name: kube-rbac-proxy
- name: manager
volumeMounts:
- name: e2e-registries-conf
mountPath: /etc/containers
volumes:
- name: e2e-registries-conf
configMap:
name: e2e-registries-conf
11 changes: 11 additions & 0 deletions config/components/registries-conf/registries_conf_configmap.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
apiVersion: v1
kind: ConfigMap
metadata:
name: e2e-registries-conf
namespace: system
data:
registries.conf: |
[[registry]]
prefix = "docker-registry.operator-controller-e2e.svc.cluster.local:5000"
insecure = true
location = "docker-registry.operator-controller-e2e.svc.cluster.local:5000"
1 change: 1 addition & 0 deletions config/overlays/e2e/kustomization.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -7,5 +7,6 @@ resources:
components:
- ../../components/tls
- ../../components/coverage
- ../../components/registries-conf
# ca must be last or (tls|coverage) will overwrite the namespaces
- ../../components/ca
Loading