diff --git a/cmd/main.go b/cmd/main.go index 65da0efa..c9b9ce2d 100644 --- a/cmd/main.go +++ b/cmd/main.go @@ -38,6 +38,7 @@ import ( "github.com/openshift/platform-operators/controllers" "github.com/openshift/platform-operators/internal/clusteroperator" "github.com/openshift/platform-operators/internal/sourcer" + "github.com/openshift/platform-operators/internal/util" //+kubebuilder:scaffold:imports ) @@ -56,14 +57,18 @@ func init() { } func main() { - var metricsAddr string - var enableLeaderElection bool - var probeAddr string + var ( + metricsAddr string + enableLeaderElection bool + probeAddr string + systemNamespace 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.") flag.BoolVar(&enableLeaderElection, "leader-elect", false, "Enable leader election for controller manager. "+ "Enabling this will ensure there is only one active controller manager.") + flag.StringVar(&systemNamespace, "system-namespace", "openshift-platform-operators", "Configures the namespace that gets used to deploy system resources.") opts := zap.Options{ Development: true, } @@ -96,8 +101,9 @@ func main() { // Add Aggregated CO controller to manager if err = (&controllers.AggregatedClusterOperatorReconciler{ - Client: mgr.GetClient(), - ReleaseVersion: clusteroperator.GetReleaseVariable(), + Client: mgr.GetClient(), + ReleaseVersion: clusteroperator.GetReleaseVariable(), + SystemNamespace: util.PodNamespace(systemNamespace), }).SetupWithManager(mgr); err != nil { setupLog.Error(err, "unable to create controller", "controller", "AggregatedCO") os.Exit(1) diff --git a/config/aggregatedclusteroperator/aggregated_clusteroperator.yaml b/config/aggregatedclusteroperator/aggregated_clusteroperator.yaml deleted file mode 100644 index 6d893acf..00000000 --- a/config/aggregatedclusteroperator/aggregated_clusteroperator.yaml +++ /dev/null @@ -1,9 +0,0 @@ -apiVersion: config.openshift.io/v1 -kind: ClusterOperator -metadata: - name: aggregated -spec: {} -status: - versions: - - name: operator - version: "0.0.1-snapshot" diff --git a/config/clusteroperator/aggregated_clusteroperator.yaml b/config/clusteroperator/aggregated_clusteroperator.yaml new file mode 100644 index 00000000..0c0ebac8 --- /dev/null +++ b/config/clusteroperator/aggregated_clusteroperator.yaml @@ -0,0 +1,22 @@ +apiVersion: config.openshift.io/v1 +kind: ClusterOperator +metadata: + name: aggregated +spec: {} +status: + versions: + - name: operator + version: "0.0.1-snapshot" + relatedObjects: + - group: '' + name: openshift-platform-operators + resource: namespaces + - group: platform.openshift.io + name: "" + resource: platformoperators + - group: core.rukpak.io + name: "" + resource: bundles + - group: core.rukpak.io + name: "" + resource: bundledeployments diff --git a/config/aggregatedclusteroperator/kustomization.yaml b/config/clusteroperator/kustomization.yaml similarity index 100% rename from config/aggregatedclusteroperator/kustomization.yaml rename to config/clusteroperator/kustomization.yaml diff --git a/config/default/kustomization.yaml b/config/default/kustomization.yaml index 2ea98367..48d63838 100644 --- a/config/default/kustomization.yaml +++ b/config/default/kustomization.yaml @@ -28,7 +28,7 @@ bases: - ../rbac - ../manager - ../rukpak -- ../aggregatedclusteroperator +- ../clusteroperator # [WEBHOOK] To enable webhook, uncomment all the sections with [WEBHOOK] prefix including the one in # crd/kustomization.yaml #- ../webhook diff --git a/config/default/manager_auth_proxy_patch.yaml b/config/default/manager_auth_proxy_patch.yaml index 300b2503..d719e11c 100644 --- a/config/default/manager_auth_proxy_patch.yaml +++ b/config/default/manager_auth_proxy_patch.yaml @@ -20,6 +20,10 @@ spec: - containerPort: 8443 protocol: TCP name: https + resources: + requests: + cpu: 1m + memory: 15Mi securityContext: allowPrivilegeEscalation: false capabilities: diff --git a/config/manager/manager.yaml b/config/manager/manager.yaml index 116ef8a8..15ec31f5 100644 --- a/config/manager/manager.yaml +++ b/config/manager/manager.yaml @@ -30,6 +30,7 @@ spec: runAsNonRoot: true seccompProfile: type: RuntimeDefault + priorityClassName: "system-cluster-critical" containers: - command: - /manager @@ -57,12 +58,7 @@ spec: port: 8081 initialDelaySeconds: 5 periodSeconds: 10 - # TODO(user): Configure the resources accordingly based on the project requirements. - # More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/ resources: - limits: - cpu: 500m - memory: 128Mi requests: cpu: 10m memory: 64Mi diff --git a/config/rukpak/apis/webhooks/resources/deployment.yaml b/config/rukpak/apis/webhooks/resources/deployment.yaml index 48d64778..c7f3cb20 100644 --- a/config/rukpak/apis/webhooks/resources/deployment.yaml +++ b/config/rukpak/apis/webhooks/resources/deployment.yaml @@ -17,6 +17,7 @@ spec: runAsNonRoot: true seccompProfile: type: RuntimeDefault + priorityClassName: "system-cluster-critical" serviceAccountName: webhooks-admin containers: - name: webhooks @@ -32,6 +33,10 @@ spec: - containerPort: 9443 name: webhook-server protocol: TCP + resources: + requests: + cpu: 10m + memory: 50Mi volumeMounts: - mountPath: /tmp/k8s-webhook-server/serving-certs name: cert diff --git a/config/rukpak/core/resources/deployment.yaml b/config/rukpak/core/resources/deployment.yaml index ead16fd0..b829d978 100644 --- a/config/rukpak/core/resources/deployment.yaml +++ b/config/rukpak/core/resources/deployment.yaml @@ -21,6 +21,7 @@ spec: runAsNonRoot: true seccompProfile: type: RuntimeDefault + priorityClassName: "system-cluster-critical" containers: - name: kube-rbac-proxy securityContext: @@ -41,6 +42,10 @@ spec: - containerPort: 8443 protocol: TCP name: https + resources: + requests: + cpu: 1m + memory: 15Mi volumeMounts: - name: tls mountPath: /etc/pki/tls @@ -65,6 +70,10 @@ spec: - "--bundle-ca-file=/etc/pki/tls/tls.crt" ports: - containerPort: 8080 + resources: + requests: + cpu: 15m + memory: 100Mi volumeMounts: - name: bundle-cache mountPath: /var/cache/bundles diff --git a/controllers/aggregated_clusteroperator_controller.go b/controllers/aggregated_clusteroperator_controller.go index 96c31b20..fff65937 100644 --- a/controllers/aggregated_clusteroperator_controller.go +++ b/controllers/aggregated_clusteroperator_controller.go @@ -35,7 +35,8 @@ import ( type AggregatedClusterOperatorReconciler struct { client.Client - ReleaseVersion string + ReleaseVersion string + SystemNamespace string } const aggregateCOName = "platform-operators-aggregated" @@ -49,16 +50,16 @@ const aggregateCOName = "platform-operators-aggregated" // // For more details, check Reconcile and its Result here: // - https://pkg.go.dev/sigs.k8s.io/controller-runtime@v0.10.0/pkg/reconcile -func (a *AggregatedClusterOperatorReconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.Result, error) { +func (r *AggregatedClusterOperatorReconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.Result, error) { log := logr.FromContext(ctx) log.Info("reconciling request", "req", req.NamespacedName) defer log.Info("finished reconciling request", "req", req.NamespacedName) coBuilder := clusteroperator.NewBuilder() - coWriter := clusteroperator.NewWriter(a.Client) + coWriter := clusteroperator.NewWriter(r.Client) aggregatedCO := &openshiftconfigv1.ClusterOperator{} - if err := a.Get(ctx, req.NamespacedName, aggregatedCO); err != nil { + if err := r.Get(ctx, req.NamespacedName, aggregatedCO); err != nil { return ctrl.Result{}, client.IgnoreNotFound(err) } defer func() { @@ -71,10 +72,14 @@ func (a *AggregatedClusterOperatorReconciler) Reconcile(ctx context.Context, req coBuilder.WithProgressing(openshiftconfigv1.ConditionTrue, "") coBuilder.WithDegraded(openshiftconfigv1.ConditionFalse) coBuilder.WithAvailable(openshiftconfigv1.ConditionFalse, "", "") - coBuilder.WithVersion("operator", a.ReleaseVersion) + coBuilder.WithVersion("operator", r.ReleaseVersion) + coBuilder.WithRelatedObject("", "namespaces", "", r.SystemNamespace) + coBuilder.WithRelatedObject("platform.openshift.io", "platformoperators", "", "") + coBuilder.WithRelatedObject("core.rukpak.io", "bundles", "", "") + coBuilder.WithRelatedObject("core.rukpak.io", "bundledeployments", "", "") poList := &platformv1alpha1.PlatformOperatorList{} - if err := a.List(ctx, poList); err != nil { + if err := r.List(ctx, poList); err != nil { return ctrl.Result{}, err } if len(poList.Items) == 0 { @@ -98,11 +103,11 @@ func (a *AggregatedClusterOperatorReconciler) Reconcile(ctx context.Context, req } // SetupWithManager sets up the controller with the Manager. -func (a *AggregatedClusterOperatorReconciler) SetupWithManager(mgr ctrl.Manager) error { +func (r *AggregatedClusterOperatorReconciler) SetupWithManager(mgr ctrl.Manager) error { return ctrl.NewControllerManagedBy(mgr). For(&openshiftconfigv1.ClusterOperator{}, builder.WithPredicates(predicate.NewPredicateFuncs(func(object client.Object) bool { return object.GetName() == aggregateCOName }))). Watches(&source.Kind{Type: &platformv1alpha1.PlatformOperator{}}, handler.EnqueueRequestsFromMapFunc(util.RequeueClusterOperator(mgr.GetClient(), aggregateCOName))). - Complete(a) + Complete(r) } diff --git a/internal/util/util.go b/internal/util/util.go index 6e25b9d8..50ca9657 100644 --- a/internal/util/util.go +++ b/internal/util/util.go @@ -3,6 +3,7 @@ package util import ( "context" "fmt" + "os" configv1 "github.com/openshift/api/config/v1" rukpakv1alpha1 "github.com/operator-framework/rukpak/api/v1alpha1" @@ -18,6 +19,18 @@ import ( platformtypes "github.com/openshift/platform-operators/api/v1alpha1" ) +// GetPodNamespace 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 +// return the value of the defaultNamespace parameter. +func PodNamespace(defaultNamespace string) string { + namespace, err := os.ReadFile("/var/run/secrets/kubernetes.io/serviceaccount/namespace") + if err != nil { + return defaultNamespace + } + return string(namespace) +} + func RequeuePlatformOperators(cl client.Client) handler.MapFunc { return func(object client.Object) []reconcile.Request { poList := &platformv1alpha1.PlatformOperatorList{} diff --git a/manifests/0000_50_cluster-platform-operator-manager_04-rukpak-core.deployment.yaml b/manifests/0000_50_cluster-platform-operator-manager_04-rukpak-core.deployment.yaml index 5238585d..779fd4fb 100644 --- a/manifests/0000_50_cluster-platform-operator-manager_04-rukpak-core.deployment.yaml +++ b/manifests/0000_50_cluster-platform-operator-manager_04-rukpak-core.deployment.yaml @@ -42,6 +42,10 @@ spec: - containerPort: 8443 name: https protocol: TCP + resources: + requests: + cpu: 1m + memory: 15Mi securityContext: allowPrivilegeEscalation: false capabilities: @@ -68,6 +72,10 @@ spec: name: manager ports: - containerPort: 8080 + resources: + requests: + cpu: 15m + memory: 100Mi securityContext: allowPrivilegeEscalation: false capabilities: @@ -80,6 +88,7 @@ spec: name: upload-cache - mountPath: /etc/pki/tls name: tls + priorityClassName: system-cluster-critical securityContext: runAsNonRoot: true seccompProfile: diff --git a/manifests/0000_50_cluster-platform-operator-manager_04-rukpak-webhooks.deployment.yaml b/manifests/0000_50_cluster-platform-operator-manager_04-rukpak-webhooks.deployment.yaml index 83213a1b..c5514c17 100644 --- a/manifests/0000_50_cluster-platform-operator-manager_04-rukpak-webhooks.deployment.yaml +++ b/manifests/0000_50_cluster-platform-operator-manager_04-rukpak-webhooks.deployment.yaml @@ -46,6 +46,10 @@ spec: - containerPort: 9443 name: webhook-server protocol: TCP + resources: + requests: + cpu: 10m + memory: 50Mi securityContext: allowPrivilegeEscalation: false capabilities: @@ -55,6 +59,7 @@ spec: - mountPath: /tmp/k8s-webhook-server/serving-certs name: cert readOnly: true + priorityClassName: system-cluster-critical securityContext: runAsNonRoot: true seccompProfile: diff --git a/manifests/0000_50_cluster-platform-operator-manager_06-deployment.yaml b/manifests/0000_50_cluster-platform-operator-manager_06-deployment.yaml index 578b7ae2..c4aa28b3 100644 --- a/manifests/0000_50_cluster-platform-operator-manager_06-deployment.yaml +++ b/manifests/0000_50_cluster-platform-operator-manager_06-deployment.yaml @@ -38,6 +38,10 @@ spec: - containerPort: 8443 name: https protocol: TCP + resources: + requests: + cpu: 1m + memory: 15Mi securityContext: allowPrivilegeEscalation: false capabilities: @@ -68,9 +72,6 @@ spec: initialDelaySeconds: 5 periodSeconds: 10 resources: - limits: - cpu: 500m - memory: 128Mi requests: cpu: 10m memory: 64Mi @@ -79,6 +80,7 @@ spec: capabilities: drop: - ALL + priorityClassName: system-cluster-critical securityContext: runAsNonRoot: true seccompProfile: diff --git a/manifests/0000_50_cluster-platform-operator-manager_07-aggregated-clusteroperator.yaml b/manifests/0000_50_cluster-platform-operator-manager_07-aggregated-clusteroperator.yaml index b4631822..8166cf22 100644 --- a/manifests/0000_50_cluster-platform-operator-manager_07-aggregated-clusteroperator.yaml +++ b/manifests/0000_50_cluster-platform-operator-manager_07-aggregated-clusteroperator.yaml @@ -10,6 +10,19 @@ metadata: namespace: openshift-platform-operators spec: {} status: + relatedObjects: + - group: "" + name: openshift-platform-operators + resource: namespaces + - group: platform.openshift.io + name: "" + resource: platformoperators + - group: core.rukpak.io + name: "" + resource: bundles + - group: core.rukpak.io + name: "" + resource: bundledeployments versions: - name: operator version: 0.0.1-snapshot diff --git a/test/e2e/aggregated_clusteroperator_test.go b/test/e2e/aggregated_clusteroperator_test.go index 3eb079cd..d85e28ea 100644 --- a/test/e2e/aggregated_clusteroperator_test.go +++ b/test/e2e/aggregated_clusteroperator_test.go @@ -43,7 +43,7 @@ var _ = Describe("aggregated clusteroperator controller", func() { WithTransform(func(c *configv1.ClusterOperatorStatusCondition) string { return c.Message }, ContainSubstring("No POs are present in the cluster")), )) }) - It("should consistently contain a populated status.versions", func() { + It("should consistently contain a populated status.versions array", func() { Consistently(func() (bool, error) { co := &configv1.ClusterOperator{} if err := c.Get(ctx, types.NamespacedName{Name: aggregateCOName}, co); err != nil { @@ -57,6 +57,15 @@ var _ = Describe("aggregated clusteroperator controller", func() { return version.Name != "" && version.Version != "", nil }).Should(BeTrue()) }) + It("should consistently contain a populated status.relatedObjects array", func() { + Consistently(func() (bool, error) { + co := &configv1.ClusterOperator{} + if err := c.Get(ctx, types.NamespacedName{Name: aggregateCOName}, co); err != nil { + return false, err + } + return len(co.Status.RelatedObjects) == 4, nil + }).Should(BeTrue()) + }) }) When("installing a series of POs successfully", func() {