diff --git a/README.md b/README.md index 98597901a2..9fb5b6f3c6 100644 --- a/README.md +++ b/README.md @@ -15,10 +15,11 @@ controllers, and tooling that support the packaging, distribution, and lifecycli - provide secure, high-quality, and predictable user experiences centered around declarative GitOps concepts - give cluster admins the minimal necessary controls to build their desired cluster architectures and to have ultimate control -OLM v1 consists of two different components: +OLM v1 consists of the following components: * operator-controller * catalogd +* object-controller (experimental): manages `ClusterObjectSet` resources independently of `ClusterExtension` For a more complete overview of OLM v1 and how it differs from OLM v0, see our [overview](docs/project/olmv1_design_decisions.md). diff --git a/Tiltfile b/Tiltfile index d736b8f94d..6a2154cff7 100644 --- a/Tiltfile +++ b/Tiltfile @@ -20,4 +20,19 @@ olmv1 = { 'yaml': 'helm/tilt.yaml', } +values = read_yaml(olmv1['yaml']) +options = values.get('options', {}) +features = options.get('operatorController', {}).get('features', {}) +object_controller_enabled = options.get('objectController', {}).get('enabled') +if object_controller_enabled == None: + object_controller_enabled = options.get('operatorController', {}).get('enabled', True) and 'BoxcutterRuntime' in features.get('enabled', []) and 'BoxcutterRuntime' not in features.get('disabled', ['BoxcutterRuntime']) +if object_controller_enabled: + olmv1['repos']['object-controller'] = { + 'image': 'quay.io/operator-framework/object-controller', + 'binary': './cmd/object-controller', + 'deployment': 'object-controller-controller-manager', + 'deps': ['api', 'cmd/object-controller', 'internal/object-controller', 'internal/shared', 'go.mod', 'go.sum'], + 'starting_debug_port': 40000, + } + deploy_repo(olmv1, '-tags containers_image_openpgp') diff --git a/docs/draft/concepts/clusterobjectsets.md b/docs/draft/concepts/clusterobjectsets.md index 87992d6a96..21c7531a69 100644 --- a/docs/draft/concepts/clusterobjectsets.md +++ b/docs/draft/concepts/clusterobjectsets.md @@ -18,6 +18,49 @@ Each ClusterObjectSet has: ClusterObjectSets can be used by any controller or system that needs to manage the rollout of a set of Kubernetes resources in a controlled, phased manner. Within OLM, the operator-controller uses ClusterObjectSets as the mechanism to deploy and upgrade ClusterExtensions. +### Controller deployment + +The experimental `object-controller` runs in its own Deployment with its own service +account and leader-election lease. It watches ClusterObjectSets and the objects they +manage; it does not require ClusterExtension or ClusterCatalog resources or controllers. +The operator-controller continues to resolve and unpack bundles, create ClusterObjectSets, +and observe their status when `BoxcutterRuntime` is enabled. + +The Helm chart automatically enables object-controller alongside operator-controller +when `BoxcutterRuntime` is enabled. To deploy it independently, first build an image +and make it available to your cluster (push it to a registry, or load it into your +local cluster). Set the image reference below, then render and apply the manifests: + +```sh +helm template object-controller helm/olmv1 \ + --set options.featureSet=experimental \ + --set options.objectController.enabled=true \ + --set options.operatorController.enabled=false \ + --set options.catalogd.enabled=false \ + --set-string options.objectController.deployment.image='' \ + > object-controller.yaml +kubectl apply -f object-controller.yaml +kubectl -n olmv1-system rollout status deployment/object-controller-controller-manager --timeout=180s +``` + +Set `options.objectController.deployment.image` to the built image when using a local +or downstream image. `make go-build-local` builds `bin/object-controller`; +`make docker-build` builds its image alongside the existing controller images. +`OBJECT_CONTROLLER_IMAGE_REPO` controls its build and release repository. + +Object-controller reads immutable referenced Secrets directly from the API server in +the namespace specified by each reference. Metrics require a TLS certificate and key; +the chart configures these through cert-manager or the OpenShift service CA when enabled. +The minimal standalone example above enables neither certificate provider, so metrics +are disabled. Health and readiness probes remain enabled. +The default service account has cluster-admin privileges because ClusterObjectSets can +manage arbitrary Kubernetes resources, matching the existing experimental runtime. + +For downstream builds enabling `BoxcutterRuntime`, package the new binary and configure +its image in addition to the operator-controller image. It is possible to package both +binaries in one image while running them in separate Deployments. Standard installations +and default Helm installations without `BoxcutterRuntime` do not enable object-controller. + ## Why ClusterObjectSets? ClusterObjectSets solve several problems that arise when managing sets of related Kubernetes resources: @@ -382,6 +425,9 @@ kubectl get clusterobjectsets -l olm.operatorframework.io/owner-name=my-extensio # View full details for a specific revision kubectl get clusterobjectset -o yaml + +# Inspect reconciliation in the independent controller +kubectl -n olmv1-system logs deployment/object-controller-controller-manager ``` Example output: diff --git a/hack/test/e2e-coverage.sh b/hack/test/e2e-coverage.sh index e4b4610d45..e0afb1d8f9 100755 --- a/hack/test/e2e-coverage.sh +++ b/hack/test/e2e-coverage.sh @@ -10,6 +10,8 @@ OPERATOR_CONTROLLER_MANAGER_DEPLOYMENT_NAME="operator-controller-controller-mana CATALOGD_NAMESPACE="olmv1-system" CATALOGD_MANAGER_DEPLOYMENT_NAME="catalogd-controller-manager" +OBJECT_CONTROLLER_MANAGER_DEPLOYMENT_NAME="object-controller-controller-manager" + COPY_POD_NAME="e2e-coverage-copy-pod" # Create a temporary directory for coverage @@ -26,6 +28,17 @@ kubectl -n "$CATALOGD_NAMESPACE" scale deployment/"$CATALOGD_MANAGER_DEPLOYMENT_ kubectl -n "$OPERATOR_CONTROLLER_NAMESPACE" wait --for=delete pods -l control-plane="$OPERATOR_CONTROLLER_MANAGER_DEPLOYMENT_NAME" --timeout=60s kubectl -n "$CATALOGD_NAMESPACE" wait --for=delete pods -l control-plane="$CATALOGD_MANAGER_DEPLOYMENT_NAME" --timeout=60s +if object_controller_lookup=$(kubectl -n "$OPERATOR_CONTROLLER_NAMESPACE" get deployment/"$OBJECT_CONTROLLER_MANAGER_DEPLOYMENT_NAME" -o name 2>&1); then + kubectl -n "$OPERATOR_CONTROLLER_NAMESPACE" scale deployment/"$OBJECT_CONTROLLER_MANAGER_DEPLOYMENT_NAME" --replicas=0 + kubectl -n "$OPERATOR_CONTROLLER_NAMESPACE" wait --for=delete pods -l control-plane="$OBJECT_CONTROLLER_MANAGER_DEPLOYMENT_NAME" --timeout=60s +else + object_controller_lookup_status=$? + if [[ "$object_controller_lookup" != *"Error from server (NotFound): deployments.apps \"$OBJECT_CONTROLLER_MANAGER_DEPLOYMENT_NAME\" not found"* ]]; then + printf '%s\n' "$object_controller_lookup" >&2 + exit "$object_controller_lookup_status" + fi +fi + # Copy the coverage data from the temporary pod kubectl -n "$OPERATOR_CONTROLLER_NAMESPACE" cp "$COPY_POD_NAME":/e2e-coverage/ "$COVERAGE_DIR" diff --git a/scripts/install.tpl.sh b/scripts/install.tpl.sh index 4be62168bf..2438f020f4 100644 --- a/scripts/install.tpl.sh +++ b/scripts/install.tpl.sh @@ -127,6 +127,16 @@ curl -L -s "${olmv1_manifest}" | sed "s/olmv1-system/${olmv1_namespace}/g" | kub kubectl_wait_rollout "${olmv1_namespace}" "deployment/catalogd-controller-manager" "60s" kubectl_wait "${olmv1_namespace}" "deployment/catalogd-controller-manager" "60s" kubectl_wait "${olmv1_namespace}" "deployment/operator-controller-controller-manager" "60s" +if object_controller_lookup=$(kubectl get deployment/object-controller-controller-manager --namespace="${olmv1_namespace}" -o name 2>&1); then + kubectl_wait_rollout "${olmv1_namespace}" "deployment/object-controller-controller-manager" "60s" + kubectl_wait "${olmv1_namespace}" "deployment/object-controller-controller-manager" "60s" +else + object_controller_lookup_status=$? + if [[ "${object_controller_lookup}" != *'Error from server (NotFound): deployments.apps "object-controller-controller-manager" not found'* ]]; then + printf '%s\n' "${object_controller_lookup}" >&2 + exit "${object_controller_lookup_status}" + fi +fi if [[ "${install_default_catalogs}" != "false" ]]; then kubectl apply -f "${default_catalogs_manifest}"