diff --git a/assets/optional/metrics-server/00-namespace.yaml b/assets/optional/metrics-server/00-namespace.yaml new file mode 100644 index 0000000000..17f727565a --- /dev/null +++ b/assets/optional/metrics-server/00-namespace.yaml @@ -0,0 +1,9 @@ +apiVersion: v1 +kind: Namespace +metadata: + name: openshift-monitoring + labels: + name: openshift-monitoring + pod-security.kubernetes.io/enforce: privileged + pod-security.kubernetes.io/audit: privileged + pod-security.kubernetes.io/warn: privileged diff --git a/assets/optional/metrics-server/01-cluster-role-binding-auth-delegator.yaml b/assets/optional/metrics-server/01-cluster-role-binding-auth-delegator.yaml new file mode 100644 index 0000000000..fad58afef1 --- /dev/null +++ b/assets/optional/metrics-server/01-cluster-role-binding-auth-delegator.yaml @@ -0,0 +1,17 @@ +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRoleBinding +metadata: + labels: + app.kubernetes.io/component: metrics-server + app.kubernetes.io/managed-by: cluster-monitoring-operator + app.kubernetes.io/name: auth-delegator + app.kubernetes.io/part-of: openshift-monitoring + name: metrics-server:system:auth-delegator +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: ClusterRole + name: system:auth-delegator +subjects: +- kind: ServiceAccount + name: metrics-server + namespace: openshift-monitoring diff --git a/assets/optional/metrics-server/01-cluster-role-binding.yaml b/assets/optional/metrics-server/01-cluster-role-binding.yaml new file mode 100644 index 0000000000..0bf14bd3e2 --- /dev/null +++ b/assets/optional/metrics-server/01-cluster-role-binding.yaml @@ -0,0 +1,18 @@ +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRoleBinding +metadata: + labels: + app.kubernetes.io/managed-by: cluster-monitoring-operator + app.kubernetes.io/name: metrics-server + app.kubernetes.io/part-of: openshift-monitoring + name: system:metrics-server +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: ClusterRole + name: system:metrics-server +subjects: + - kind: ServiceAccount + name: metrics-server + namespace: openshift-monitoring + - kind: User + name: system:metrics-server diff --git a/assets/optional/metrics-server/01-cluster-role.yaml b/assets/optional/metrics-server/01-cluster-role.yaml new file mode 100644 index 0000000000..19be5ca4b0 --- /dev/null +++ b/assets/optional/metrics-server/01-cluster-role.yaml @@ -0,0 +1,25 @@ +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + labels: + app.kubernetes.io/component: metrics-server + app.kubernetes.io/managed-by: cluster-monitoring-operator + app.kubernetes.io/name: metrics-server + app.kubernetes.io/part-of: openshift-monitoring + name: system:metrics-server +rules: +- apiGroups: + - "" + resources: + - nodes/metrics + verbs: + - get +- apiGroups: + - "" + resources: + - pods + - nodes + verbs: + - get + - list + - watch diff --git a/assets/optional/metrics-server/01-role-binding-auth-reader.yaml b/assets/optional/metrics-server/01-role-binding-auth-reader.yaml new file mode 100644 index 0000000000..6b11a238ce --- /dev/null +++ b/assets/optional/metrics-server/01-role-binding-auth-reader.yaml @@ -0,0 +1,18 @@ +apiVersion: rbac.authorization.k8s.io/v1 +kind: RoleBinding +metadata: + labels: + app.kubernetes.io/component: metrics-server + app.kubernetes.io/managed-by: cluster-monitoring-operator + app.kubernetes.io/name: metrics-server-auth-reader + app.kubernetes.io/part-of: openshift-monitoring + name: metrics-server-auth-reader + namespace: kube-system +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: Role + name: extension-apiserver-authentication-reader +subjects: +- kind: ServiceAccount + name: metrics-server + namespace: openshift-monitoring diff --git a/assets/optional/metrics-server/01-service-account.yaml b/assets/optional/metrics-server/01-service-account.yaml new file mode 100644 index 0000000000..310685e790 --- /dev/null +++ b/assets/optional/metrics-server/01-service-account.yaml @@ -0,0 +1,10 @@ +apiVersion: v1 +kind: ServiceAccount +metadata: + labels: + app.kubernetes.io/component: metrics-server + app.kubernetes.io/managed-by: cluster-monitoring-operator + app.kubernetes.io/name: metrics-server + app.kubernetes.io/part-of: openshift-monitoring + name: metrics-server + namespace: openshift-monitoring diff --git a/assets/optional/metrics-server/02-configmap-audit-profiles.yaml b/assets/optional/metrics-server/02-configmap-audit-profiles.yaml new file mode 100644 index 0000000000..1cff598a6d --- /dev/null +++ b/assets/optional/metrics-server/02-configmap-audit-profiles.yaml @@ -0,0 +1,45 @@ +apiVersion: v1 +data: + metadata-profile.yaml: |- + "apiVersion": "audit.k8s.io/v1" + "kind": "Policy" + "metadata": + "name": "Metadata" + "omitStages": + - "RequestReceived" + "rules": + - "level": "Metadata" + none-profile.yaml: |- + "apiVersion": "audit.k8s.io/v1" + "kind": "Policy" + "metadata": + "name": "None" + "omitStages": + - "RequestReceived" + "rules": + - "level": "None" + request-profile.yaml: |- + "apiVersion": "audit.k8s.io/v1" + "kind": "Policy" + "metadata": + "name": "Request" + "omitStages": + - "RequestReceived" + "rules": + - "level": "Request" + requestresponse-profile.yaml: |- + "apiVersion": "audit.k8s.io/v1" + "kind": "Policy" + "metadata": + "name": "RequestResponse" + "omitStages": + - "RequestReceived" + "rules": + - "level": "RequestResponse" +kind: ConfigMap +metadata: + labels: + app.kubernetes.io/managed-by: cluster-monitoring-operator + app.kubernetes.io/part-of: openshift-monitoring + name: metrics-server-audit-profiles + namespace: openshift-monitoring diff --git a/assets/optional/metrics-server/03-deployment.yaml b/assets/optional/metrics-server/03-deployment.yaml new file mode 100644 index 0000000000..1830ee8fc2 --- /dev/null +++ b/assets/optional/metrics-server/03-deployment.yaml @@ -0,0 +1,114 @@ +apiVersion: apps/v1 +kind: Deployment +metadata: + labels: + app.kubernetes.io/component: metrics-server + app.kubernetes.io/managed-by: cluster-monitoring-operator + app.kubernetes.io/name: metrics-server + app.kubernetes.io/part-of: openshift-monitoring + name: metrics-server + namespace: openshift-monitoring +spec: + replicas: 1 + selector: + matchLabels: + app.kubernetes.io/component: metrics-server + app.kubernetes.io/name: metrics-server + app.kubernetes.io/part-of: openshift-monitoring + strategy: + type: Recreate + template: + metadata: + annotations: + openshift.io/required-scc: restricted-v2 + target.workload.openshift.io/management: '{"effect": "PreferredDuringScheduling"}' + labels: + app.kubernetes.io/component: metrics-server + app.kubernetes.io/name: metrics-server + app.kubernetes.io/part-of: openshift-monitoring + spec: + containers: + - args: + - --secure-port=10250 + - --kubelet-preferred-address-types=InternalIP,ExternalIP,Hostname + - --kubelet-use-node-status-port + - --metric-resolution=15s + - --kubelet-certificate-authority=/etc/tls/kubelet-serving-ca-bundle/ca-bundle.crt + - --kubelet-client-certificate=/etc/tls/metrics-server-client-certs/tls.crt + - --kubelet-client-key=/etc/tls/metrics-server-client-certs/tls.key + - --tls-cert-file=/etc/tls/private/tls.crt + - --tls-private-key-file=/etc/tls/private/tls.key + - --tls-cipher-suites=TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256,TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256,TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384,TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384,TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305,TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305 + - --shutdown-send-retry-after=true + - --shutdown-delay-duration=150s + - --disable-http2-serving=true + image: "quay.io/openshift/kube-metrics-server" + imagePullPolicy: IfNotPresent + livenessProbe: + failureThreshold: 3 + httpGet: + path: /livez + port: https + scheme: HTTPS + periodSeconds: 10 + name: metrics-server + ports: + - containerPort: 10250 + name: https + protocol: TCP + readinessProbe: + failureThreshold: 6 + httpGet: + path: /readyz + port: https + scheme: HTTPS + initialDelaySeconds: 20 + periodSeconds: 20 + resources: + requests: + cpu: 1m + memory: 40Mi + securityContext: + allowPrivilegeEscalation: false + readOnlyRootFilesystem: true + runAsNonRoot: true + capabilities: + drop: + - ALL + terminationMessagePolicy: FallbackToLogsOnError + volumeMounts: + - mountPath: /etc/tls/private + name: secret-metrics-server-tls + - mountPath: /etc/tls/metrics-server-client-certs + name: secret-metrics-server-client-certs + - mountPath: /etc/tls/kubelet-serving-ca-bundle + name: configmap-kubelet-serving-ca-bundle + - mountPath: /etc/audit + name: metrics-server-audit-profiles + readOnly: true + - mountPath: /var/log/metrics-server + name: audit-log + readOnly: false + nodeSelector: + kubernetes.io/os: linux + priorityClassName: system-cluster-critical + serviceAccountName: metrics-server + terminationGracePeriodSeconds: 170 + tolerations: + - effect: NoSchedule + key: node-role.kubernetes.io/master + volumes: + - name: secret-metrics-server-client-certs + secret: + secretName: metrics-server-client-certs + - name: secret-metrics-server-tls + secret: + secretName: metrics-server-tls + - configMap: + name: kubelet-serving-ca-bundle + name: configmap-kubelet-serving-ca-bundle + - emptyDir: {} + name: audit-log + - configMap: + name: metrics-server-audit-profiles + name: metrics-server-audit-profiles diff --git a/assets/optional/metrics-server/04-api-service.yaml b/assets/optional/metrics-server/04-api-service.yaml new file mode 100644 index 0000000000..54303f0d9d --- /dev/null +++ b/assets/optional/metrics-server/04-api-service.yaml @@ -0,0 +1,21 @@ +apiVersion: apiregistration.k8s.io/v1 +kind: APIService +metadata: + annotations: + service.beta.openshift.io/inject-cabundle: "true" + labels: + app.kubernetes.io/component: metrics-server + app.kubernetes.io/managed-by: cluster-monitoring-operator + app.kubernetes.io/name: metrics-server + app.kubernetes.io/part-of: openshift-monitoring + name: v1beta1.metrics.k8s.io +spec: + group: metrics.k8s.io + groupPriorityMinimum: 100 + insecureSkipTLSVerify: false + service: + name: metrics-server + namespace: openshift-monitoring + port: 443 + version: v1beta1 + versionPriority: 100 diff --git a/assets/optional/metrics-server/04-service.yaml b/assets/optional/metrics-server/04-service.yaml new file mode 100644 index 0000000000..3a485b2dad --- /dev/null +++ b/assets/optional/metrics-server/04-service.yaml @@ -0,0 +1,22 @@ +apiVersion: v1 +kind: Service +metadata: + annotations: + openshift.io/description: Expose the metrics-server web server on port 443. This port is for internal use, and no other usage is guaranteed. + service.beta.openshift.io/serving-cert-secret-name: metrics-server-tls + labels: + app.kubernetes.io/component: metrics-server + app.kubernetes.io/managed-by: cluster-monitoring-operator + app.kubernetes.io/name: metrics-server + app.kubernetes.io/part-of: openshift-monitoring + name: metrics-server + namespace: openshift-monitoring +spec: + ports: + - name: https + port: 443 + protocol: TCP + targetPort: https + selector: + app.kubernetes.io/name: metrics-server + app.kubernetes.io/part-of: openshift-monitoring diff --git a/assets/optional/metrics-server/kustomization.aarch64.yaml b/assets/optional/metrics-server/kustomization.aarch64.yaml new file mode 100644 index 0000000000..0a79cdb357 --- /dev/null +++ b/assets/optional/metrics-server/kustomization.aarch64.yaml @@ -0,0 +1,4 @@ +images: + - name: quay.io/openshift/kube-metrics-server + newName: quay.io/openshift-release-dev/ocp-v5.0-art-dev + digest: sha256:790dcea1d4cf5eb3a989bf3d14d460148d23a743951644668a300b7fc21f29ec diff --git a/assets/optional/metrics-server/kustomization.x86_64.yaml b/assets/optional/metrics-server/kustomization.x86_64.yaml new file mode 100644 index 0000000000..49529cad12 --- /dev/null +++ b/assets/optional/metrics-server/kustomization.x86_64.yaml @@ -0,0 +1,4 @@ +images: + - name: quay.io/openshift/kube-metrics-server + newName: quay.io/openshift-release-dev/ocp-v5.0-art-dev + digest: sha256:0590e13d7955f71db964f601f5ce6c66416a1e2e5acee5c2831f41fb2b13435c diff --git a/assets/optional/metrics-server/kustomization.yaml b/assets/optional/metrics-server/kustomization.yaml new file mode 100644 index 0000000000..ca034994ff --- /dev/null +++ b/assets/optional/metrics-server/kustomization.yaml @@ -0,0 +1,13 @@ +apiVersion: kustomize.config.k8s.io/v1beta1 +kind: Kustomization +resources: + - 00-namespace.yaml + - 01-service-account.yaml + - 01-cluster-role.yaml + - 01-cluster-role-binding.yaml + - 01-cluster-role-binding-auth-delegator.yaml + - 01-role-binding-auth-reader.yaml + - 02-configmap-audit-profiles.yaml + - 03-deployment.yaml + - 04-service.yaml + - 04-api-service.yaml diff --git a/assets/optional/metrics-server/release-metrics-server-aarch64.json b/assets/optional/metrics-server/release-metrics-server-aarch64.json new file mode 100644 index 0000000000..c12ffcbb53 --- /dev/null +++ b/assets/optional/metrics-server/release-metrics-server-aarch64.json @@ -0,0 +1,8 @@ +{ + "release": { + "base": "5.0.0-0.nightly-arm64-2026-06-19-154904" + }, + "images": { + "metrics_server": "quay.io/openshift-release-dev/ocp-v5.0-art-dev@sha256:790dcea1d4cf5eb3a989bf3d14d460148d23a743951644668a300b7fc21f29ec" + } +} diff --git a/assets/optional/metrics-server/release-metrics-server-x86_64.json b/assets/optional/metrics-server/release-metrics-server-x86_64.json new file mode 100644 index 0000000000..57ab6cbd6a --- /dev/null +++ b/assets/optional/metrics-server/release-metrics-server-x86_64.json @@ -0,0 +1,8 @@ +{ + "release": { + "base": "5.0.0-0.nightly-2026-06-19-155631" + }, + "images": { + "metrics_server": "quay.io/openshift-release-dev/ocp-v5.0-art-dev@sha256:0590e13d7955f71db964f601f5ce6c66416a1e2e5acee5c2831f41fb2b13435c" + } +} diff --git a/etcd/vendor/github.com/openshift/microshift/pkg/util/cryptomaterial/certinfo.go b/etcd/vendor/github.com/openshift/microshift/pkg/util/cryptomaterial/certinfo.go index aed383b9fa..12c413d114 100644 --- a/etcd/vendor/github.com/openshift/microshift/pkg/util/cryptomaterial/certinfo.go +++ b/etcd/vendor/github.com/openshift/microshift/pkg/util/cryptomaterial/certinfo.go @@ -74,6 +74,10 @@ func AdminKubeconfigClientCertDir(certsDir string) string { return filepath.Join(AdminKubeconfigSignerDir(certsDir), "admin-kubeconfig-client") } +func MetricsServerKubeletClientCertDir(certsDir string) string { + return filepath.Join(KubeAPIServerToKubeletSignerCertDir(certsDir), "metrics-server-kubelet-client") +} + // KubeletCSRSignerSignerCertDir returns path to the signer that signs kubelet CSRs // and the signer that signs CSRs of the CSR API func KubeletCSRSignerSignerCertDir(certsDir string) string { @@ -167,6 +171,10 @@ func KubeletClientCAPath(certsDir string) string { return filepath.Join(certsDir, "ca-bundle", "kubelet-ca.crt") } +func KubeletServingCAPath(certsDir string) string { + return filepath.Join(certsDir, "ca-bundle", "kubelet-serving-ca.crt") +} + func ServiceAccountTokenCABundlePath(certsDir string) string { return filepath.Join(certsDir, "ca-bundle", "service-account-token-ca.crt") } diff --git a/packaging/rpm/microshift.spec b/packaging/rpm/microshift.spec index 6362e4f552..e720a65bad 100644 --- a/packaging/rpm/microshift.spec +++ b/packaging/rpm/microshift.spec @@ -261,6 +261,25 @@ The microshift-cert-manager-release-info package provides release information fi release. These files contain the list of container image references used by Cert Manager and can be used to embed those images into osbuilder blueprints or bootc containerfiles. +%package metrics-server +Summary: Kubernetes metrics-server for MicroShift +ExclusiveArch: x86_64 aarch64 +Requires: microshift = %{version} + +%description metrics-server +The microshift-metrics-server package provides the metrics-server for MicroShift. +Install this package to enable kubectl top and resource metrics via the Metrics API. + +%package metrics-server-release-info +Summary: Release information for metrics-server for MicroShift +BuildArch: noarch +Requires: microshift-release-info = %{version} + +%description metrics-server-release-info +The microshift-metrics-server-release-info package provides release information files for this +release. These files contain the list of container image references used by the metrics-server +and can be used to embed those images into osbuilder blueprints or bootc containerfiles. + %package sriov Summary: SR-IOV Network Operator for MicroShift ExclusiveArch: x86_64 aarch64 @@ -599,6 +618,31 @@ cat assets/optional/cert-manager/manager/images-x86_64.yaml >> %{buildroot}/%{_p mkdir -p -m755 %{buildroot}%{_datadir}/microshift/release install -p -m644 assets/optional/cert-manager/release-cert-manager-{x86_64,aarch64}.json %{buildroot}%{_datadir}/microshift/release/ +# metrics-server +install -d -m755 %{buildroot}/%{_prefix}/lib/microshift/manifests.d/080-microshift-metrics-server +install -p -m644 assets/optional/metrics-server/00-namespace.yaml %{buildroot}/%{_prefix}/lib/microshift/manifests.d/080-microshift-metrics-server +install -p -m644 assets/optional/metrics-server/01-service-account.yaml %{buildroot}/%{_prefix}/lib/microshift/manifests.d/080-microshift-metrics-server +install -p -m644 assets/optional/metrics-server/01-cluster-role.yaml %{buildroot}/%{_prefix}/lib/microshift/manifests.d/080-microshift-metrics-server +install -p -m644 assets/optional/metrics-server/01-cluster-role-binding.yaml %{buildroot}/%{_prefix}/lib/microshift/manifests.d/080-microshift-metrics-server +install -p -m644 assets/optional/metrics-server/01-cluster-role-binding-auth-delegator.yaml %{buildroot}/%{_prefix}/lib/microshift/manifests.d/080-microshift-metrics-server +install -p -m644 assets/optional/metrics-server/01-role-binding-auth-reader.yaml %{buildroot}/%{_prefix}/lib/microshift/manifests.d/080-microshift-metrics-server +install -p -m644 assets/optional/metrics-server/02-configmap-audit-profiles.yaml %{buildroot}/%{_prefix}/lib/microshift/manifests.d/080-microshift-metrics-server +install -p -m644 assets/optional/metrics-server/03-deployment.yaml %{buildroot}/%{_prefix}/lib/microshift/manifests.d/080-microshift-metrics-server +install -p -m644 assets/optional/metrics-server/04-service.yaml %{buildroot}/%{_prefix}/lib/microshift/manifests.d/080-microshift-metrics-server +install -p -m644 assets/optional/metrics-server/04-api-service.yaml %{buildroot}/%{_prefix}/lib/microshift/manifests.d/080-microshift-metrics-server +install -p -m644 assets/optional/metrics-server/kustomization.yaml %{buildroot}/%{_prefix}/lib/microshift/manifests.d/080-microshift-metrics-server + +%ifarch %{arm} aarch64 +cat assets/optional/metrics-server/kustomization.aarch64.yaml >> %{buildroot}/%{_prefix}/lib/microshift/manifests.d/080-microshift-metrics-server/kustomization.yaml +%endif +%ifarch x86_64 +cat assets/optional/metrics-server/kustomization.x86_64.yaml >> %{buildroot}/%{_prefix}/lib/microshift/manifests.d/080-microshift-metrics-server/kustomization.yaml +%endif + +# metrics-server-release-info +mkdir -p -m755 %{buildroot}%{_datadir}/microshift/release +install -p -m644 assets/optional/metrics-server/release-metrics-server-{x86_64,aarch64}.json %{buildroot}%{_datadir}/microshift/release/ + # sriov install -d -m755 %{buildroot}/%{_prefix}/lib/microshift/manifests.d/070-microshift-sriov install -d -m755 %{buildroot}/%{_prefix}/lib/microshift/manifests.d/070-microshift-sriov/crd @@ -802,6 +846,13 @@ fi %files cert-manager-release-info %{_datadir}/microshift/release/release-cert-manager-{x86_64,aarch64}.json +%files metrics-server +%dir %{_prefix}/lib/microshift/manifests.d/080-microshift-metrics-server +%{_prefix}/lib/microshift/manifests.d/080-microshift-metrics-server/* + +%files metrics-server-release-info +%{_datadir}/microshift/release/release-metrics-server-{x86_64,aarch64}.json + %files sriov %dir %{_prefix}/lib/microshift/manifests.d/070-microshift-sriov %dir %{_prefix}/lib/microshift/manifests.d/070-microshift-sriov/crd diff --git a/pkg/cmd/init.go b/pkg/cmd/init.go index 50851ed33e..8c8e9ec6ff 100644 --- a/pkg/cmd/init.go +++ b/pkg/cmd/init.go @@ -155,6 +155,13 @@ func certSetup(cfg *config.Config) (*certchains.CertificateChains, error) { Validity: alignValidity(cryptomaterial.ShortLivedCertificateValidity), }, UserInfo: &user.DefaultInfo{Name: "system:kube-apiserver", Groups: []string{"kube-master"}}, + }).WithClientCertificates( + &certchains.ClientCertificateSigningRequestInfo{ + CSRMeta: certchains.CSRMeta{ + Name: "metrics-server-kubelet-client", + Validity: alignValidity(cryptomaterial.ShortLivedCertificateValidity), + }, + UserInfo: &user.DefaultInfo{Name: "system:metrics-server"}, }), // admin-kubeconfig-signer @@ -175,7 +182,7 @@ func certSetup(cfg *config.Config) (*certchains.CertificateChains, error) { Name: "openshift-observability-client", Validity: alignValidity(cryptomaterial.ShortLivedCertificateValidity), }, - UserInfo: &user.DefaultInfo{Name: "openshift-observability-client", Groups: []string{""}}, + UserInfo: &user.DefaultInfo{Name: "openshift-observability-client"}, }, ), @@ -364,6 +371,10 @@ func certSetup(cfg *config.Config) (*certchains.CertificateChains, error) { []string{"admin-kubeconfig-signer"}, []string{"kubelet-signer"}, []string{"kubelet-signer", "kube-csr-signer"}, + ).WithCABundle( + cryptomaterial.KubeletServingCAPath(certsDir), + []string{"kubelet-signer"}, + []string{"kubelet-signer", "kube-csr-signer"}, ).WithCABundle( cryptomaterial.ServiceAccountTokenCABundlePath(certsDir), []string{"kube-apiserver-localhost-signer"}, diff --git a/pkg/cmd/run.go b/pkg/cmd/run.go index 94c2fbd8f6..99b4864bad 100644 --- a/pkg/cmd/run.go +++ b/pkg/cmd/run.go @@ -14,6 +14,7 @@ import ( "github.com/coreos/go-systemd/daemon" "github.com/openshift/microshift/pkg/admin/data" "github.com/openshift/microshift/pkg/admin/prerun" + "github.com/openshift/microshift/pkg/components" "github.com/openshift/microshift/pkg/config" "github.com/openshift/microshift/pkg/controllers" "github.com/openshift/microshift/pkg/controllers/c2cc" @@ -303,6 +304,11 @@ func RunMicroshift(cfg *config.Config) error { // After MicroShift's core becomes ready, run the kustomizer (delete and/or apply manifests). kustomize.NewKustomizer(cfg).RunStandalone(runCtx) + // Provision certs for optional components after kustomize creates their namespaces. + if err := components.ProvisionMetricsServerCerts(runCtx, cfg); err != nil { + return fmt.Errorf("failed to provision metrics-server certs: %w", err) + } + // Watch for SIGTERM or service error to exit, now that we are ready. select { case <-sigTerm: diff --git a/pkg/components/metrics.go b/pkg/components/metrics.go new file mode 100644 index 0000000000..3539cb0de6 --- /dev/null +++ b/pkg/components/metrics.go @@ -0,0 +1,132 @@ +package components + +import ( + "context" + "fmt" + "os" + "time" + + "github.com/openshift/library-go/pkg/operator/events" + "github.com/openshift/library-go/pkg/operator/resource/resourceapply" + "github.com/openshift/microshift/pkg/config" + "github.com/openshift/microshift/pkg/util" + "github.com/openshift/microshift/pkg/util/cryptomaterial" + corev1 "k8s.io/api/core/v1" + apierrors "k8s.io/apimachinery/pkg/api/errors" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/util/wait" + "k8s.io/klog/v2" + "k8s.io/utils/clock" +) + +const ( + metricsServerManifestPath = "/usr/lib/microshift/manifests.d/080-microshift-metrics-server" + metricsServerNamespace = "openshift-monitoring" +) + +var metricsEventRecorder events.Recorder = events.NewLoggingEventRecorder("microshift-metrics-server", clock.RealClock{}) + +func ProvisionMetricsServerCerts(ctx context.Context, cfg *config.Config) error { + exists, err := util.PathExists(metricsServerManifestPath) + if err != nil { + return err + } + if !exists { + klog.V(2).Infof("Metrics-server manifests not found at %s, skipping cert provisioning", metricsServerManifestPath) + return nil + } + + kubeconfigPath := cfg.KubeConfigPath(config.KubeAdmin) + + clientset, err := getKubernetesClient(kubeconfigPath) + if err != nil { + return fmt.Errorf("creating clientset: %w", err) + } + + err = wait.PollUntilContextTimeout(ctx, 2*time.Second, 5*time.Minute, true, func(ctx context.Context) (bool, error) { + _, err := clientset.CoreV1().Namespaces().Get(ctx, metricsServerNamespace, metav1.GetOptions{}) + if err == nil { + return true, nil + } + if !apierrors.IsNotFound(err) { + klog.Errorf("getting namespace %s: %v", metricsServerNamespace, err) + return false, nil + } + klog.V(2).Infof("Waiting for namespace %s to be created by kustomize", metricsServerNamespace) + return false, nil + }) + if err != nil { + return fmt.Errorf("waiting for namespace %s: %w", metricsServerNamespace, err) + } + + certsDir := cryptomaterial.CertsDirectory(config.DataDir) + + certDir := cryptomaterial.MetricsServerKubeletClientCertDir(certsDir) + certPEM, err := os.ReadFile(cryptomaterial.ClientCertPath(certDir)) + if err != nil { + return err + } + keyPEM, err := os.ReadFile(cryptomaterial.ClientKeyPath(certDir)) + if err != nil { + return err + } + + secret := &corev1.Secret{ + ObjectMeta: metav1.ObjectMeta{ + Name: "metrics-server-client-certs", + Namespace: metricsServerNamespace, + Annotations: map[string]string{ + "openshift.io/owning-component": "metrics-server", + }, + }, + Type: corev1.SecretTypeTLS, + Data: map[string][]byte{ + "tls.crt": certPEM, + "tls.key": keyPEM, + }, + } + + err = wait.PollUntilContextTimeout(ctx, 2*time.Second, 1*time.Minute, true, func(ctx context.Context) (bool, error) { + _, _, err := resourceapply.ApplySecret(ctx, clientset.CoreV1(), metricsEventRecorder, secret) + if err != nil { + klog.Errorf("applying metrics-server client cert secret: %v", err) + return false, nil + } + return true, nil + }) + if err != nil { + return fmt.Errorf("applying metrics-server client cert secret: %w", err) + } + + caPEM, err := os.ReadFile(cryptomaterial.KubeletServingCAPath(certsDir)) + if err != nil { + return err + } + + cm := &corev1.ConfigMap{ + ObjectMeta: metav1.ObjectMeta{ + Name: "kubelet-serving-ca-bundle", + Namespace: metricsServerNamespace, + Annotations: map[string]string{ + "openshift.io/owning-component": "metrics-server", + }, + }, + Data: map[string]string{ + "ca-bundle.crt": string(caPEM), + }, + } + + err = wait.PollUntilContextTimeout(ctx, 2*time.Second, 1*time.Minute, true, func(ctx context.Context) (bool, error) { + _, _, err := resourceapply.ApplyConfigMap(ctx, clientset.CoreV1(), metricsEventRecorder, cm) + if err != nil { + return false, fmt.Errorf("applying kubelet serving CA configmap: %w", err) + } + return true, nil + }) + if err != nil { + return fmt.Errorf("applying kubelet serving CA configmap: %v", err) + } + + klog.Infof("Provisioned metrics-server kubelet client cert and CA bundle") + return nil +} diff --git a/pkg/healthcheck/microshift_optional_workloads.go b/pkg/healthcheck/microshift_optional_workloads.go index 80e2d9a3b0..7772b1e36c 100644 --- a/pkg/healthcheck/microshift_optional_workloads.go +++ b/pkg/healthcheck/microshift_optional_workloads.go @@ -1,6 +1,8 @@ package healthcheck import ( + "slices" + "github.com/openshift/microshift/pkg/config" "github.com/openshift/microshift/pkg/util" "k8s.io/klog/v2" @@ -38,6 +40,20 @@ var optionalWorkloadPaths = map[string]optionalWorkloads{ Namespace: "sriov-network-operator", Workloads: NamespaceWorkloads{Deployments: []string{"sriov-network-operator"}}, }, + + "/usr/lib/microshift/manifests.d/080-microshift-metrics-server": { + Namespace: "openshift-monitoring", + Workloads: NamespaceWorkloads{Deployments: []string{"metrics-server"}}, + }, +} + +// mergeWorkloads combines two NamespaceWorkloads into one. +func mergeWorkloads(existing, incoming NamespaceWorkloads) NamespaceWorkloads { + return NamespaceWorkloads{ + Deployments: slices.Concat(existing.Deployments, incoming.Deployments), + DaemonSets: slices.Concat(existing.DaemonSets, incoming.DaemonSets), + StatefulSets: slices.Concat(existing.StatefulSets, incoming.StatefulSets), + } } // fillOptionalMicroShiftWorkloads assembles list of optional MicroShift workloads @@ -73,7 +89,7 @@ func fillOptionalMicroShiftWorkloads(workloadsToCheck map[string]NamespaceWorklo } klog.Infof("Optional component path exists and is configured: %s - expecting %v in namespace %q", path, ow.Workloads.String(), ow.Namespace) - workloadsToCheck[ow.Namespace] = ow.Workloads + workloadsToCheck[ow.Namespace] = mergeWorkloads(workloadsToCheck[ow.Namespace], ow.Workloads) } return nil } diff --git a/pkg/util/cryptomaterial/certinfo.go b/pkg/util/cryptomaterial/certinfo.go index aed383b9fa..12c413d114 100644 --- a/pkg/util/cryptomaterial/certinfo.go +++ b/pkg/util/cryptomaterial/certinfo.go @@ -74,6 +74,10 @@ func AdminKubeconfigClientCertDir(certsDir string) string { return filepath.Join(AdminKubeconfigSignerDir(certsDir), "admin-kubeconfig-client") } +func MetricsServerKubeletClientCertDir(certsDir string) string { + return filepath.Join(KubeAPIServerToKubeletSignerCertDir(certsDir), "metrics-server-kubelet-client") +} + // KubeletCSRSignerSignerCertDir returns path to the signer that signs kubelet CSRs // and the signer that signs CSRs of the CSR API func KubeletCSRSignerSignerCertDir(certsDir string) string { @@ -167,6 +171,10 @@ func KubeletClientCAPath(certsDir string) string { return filepath.Join(certsDir, "ca-bundle", "kubelet-ca.crt") } +func KubeletServingCAPath(certsDir string) string { + return filepath.Join(certsDir, "ca-bundle", "kubelet-serving-ca.crt") +} + func ServiceAccountTokenCABundlePath(certsDir string) string { return filepath.Join(certsDir, "ca-bundle", "service-account-token-ca.crt") } diff --git a/scripts/auto-rebase/assets_cluster_monitoring_operator.yaml b/scripts/auto-rebase/assets_cluster_monitoring_operator.yaml new file mode 100644 index 0000000000..b252b3ef12 --- /dev/null +++ b/scripts/auto-rebase/assets_cluster_monitoring_operator.yaml @@ -0,0 +1,37 @@ +assets: + - dir: optional/metrics-server/ + no_clean: True + src: cluster-monitoring-operator/assets/metrics-server/ + files: + - file: 00-namespace.yaml + ignore: "MicroShift-specific, no upstream equivalent" + git_restore: True + - file: 01-service-account.yaml + src: service-account.yaml + - file: 01-cluster-role.yaml + src: cluster-role.yaml + - file: 01-cluster-role-binding.yaml + src: cluster-role-binding.yaml + - file: 01-cluster-role-binding-auth-delegator.yaml + src: cluster-role-binding-auth-delegator.yaml + - file: 01-role-binding-auth-reader.yaml + src: role-binding-auth-reader.yaml + - file: 02-configmap-audit-profiles.yaml + src: configmap-audit-profiles.yaml + - file: 03-deployment.yaml + src: deployment.yaml + - file: 04-service.yaml + src: service.yaml + - file: 04-api-service.yaml + src: api-service.yaml + - file: kustomization.yaml + ignore: "MicroShift-specific kustomization" + git_restore: True + - file: kustomization.x86_64.yaml + ignore: "gets generated during image rebase" + - file: kustomization.aarch64.yaml + ignore: "gets generated during image rebase" + - file: release-metrics-server-x86_64.json + ignore: "gets generated during image rebase" + - file: release-metrics-server-aarch64.json + ignore: "gets generated during image rebase" diff --git a/scripts/auto-rebase/last_rebase_cluster_monitoring_operator.sh b/scripts/auto-rebase/last_rebase_cluster_monitoring_operator.sh new file mode 100755 index 0000000000..f61200df82 --- /dev/null +++ b/scripts/auto-rebase/last_rebase_cluster_monitoring_operator.sh @@ -0,0 +1,2 @@ +#!/bin/bash -x +./scripts/auto-rebase/rebase_cluster_monitoring_operator.sh to "registry.ci.openshift.org/ocp/release-5:5.0.0-0.nightly-2026-06-19-155631" "registry.ci.openshift.org/ocp-arm64/release-5-arm64:5.0.0-0.nightly-arm64-2026-06-19-154904" diff --git a/scripts/auto-rebase/presubmit.py b/scripts/auto-rebase/presubmit.py index 5e90ed4639..ea3f6199b4 100755 --- a/scripts/auto-rebase/presubmit.py +++ b/scripts/auto-rebase/presubmit.py @@ -29,6 +29,7 @@ "./scripts/auto-rebase/assets_ai_model_serving.yaml", "./scripts/auto-rebase/assets_cert_manager.yaml", "./scripts/auto-rebase/assets_sriov.yaml", + "./scripts/auto-rebase/assets_cluster_monitoring_operator.yaml", ] diff --git a/scripts/auto-rebase/rebase_cluster_monitoring_operator.sh b/scripts/auto-rebase/rebase_cluster_monitoring_operator.sh new file mode 100755 index 0000000000..be1124f04e --- /dev/null +++ b/scripts/auto-rebase/rebase_cluster_monitoring_operator.sh @@ -0,0 +1,375 @@ +#!/usr/bin/env bash +# shellcheck disable=all +# Copyright 2022 The MicroShift authors +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +set -o errexit +set -o errtrace +set -o nounset +set -o pipefail + +shopt -s expand_aliases +shopt -s extglob + +#debugging options +#trap 'echo "#L$LINENO: $BASH_COMMAND" >&2' DEBUG +#set -xo functrace +#PS4='+ $LINENO ' +REPOROOT="$(readlink -f "$(dirname "${BASH_SOURCE[0]}")/../..")" +STAGING_DIR="$REPOROOT/_output/staging" +PULL_SECRET_FILE="${HOME}/.pull-secret.json" +REBASE_USE_SSH="${REBASE_USE_SSH:-false}" + +declare -a ARCHS=("amd64" "arm64") +declare -A GOARCH_TO_UNAME_MAP=( ["amd64"]="x86_64" ["arm64"]="aarch64" ) + +# Maps kustomization image name -> OCP release tag name +declare -A IMAGE_MAP=( + ["quay.io/openshift/kube-metrics-server"]="kube-metrics-server" + ["quay.io/openshift/kube-state-metrics"]="kube-state-metrics" + ["quay.io/openshift/node-exporter"]="prometheus-node-exporter" + ["quay.io/openshift/kube-rbac-proxy"]="kube-rbac-proxy" +) + +# Maps component dir -> release JSON key +declare -A COMPONENT_JSON_KEY=( + ["metrics-server"]="metrics_server" + ["kube-state-metrics"]="kube_state_metrics" + ["node-exporter"]="node_exporter" +) + +# Maps release JSON key -> OCP release tag name +declare -A EXPORTER_TAG_MAP=( + ["metrics_server"]="kube-metrics-server" + ["kube_state_metrics"]="kube-state-metrics" + ["node_exporter"]="prometheus-node-exporter" +) + +title() { + echo -e "\E[34m$1\E[00m"; +} + +retry_cmd() { + local -r max_attempts=5 + local timeout=1 + local attempt=1 + local exit_code=0 + + while (( attempt <= max_attempts )); do + if "$@"; then + return 0 + else + exit_code=$? + fi + echo "Attempt ${attempt} of ${max_attempts} failed (exit code ${exit_code}). Retrying in ${timeout}s..." + sleep "${timeout}" + attempt=$(( attempt + 1 )) + timeout=$(( timeout * 2 )) + done + + echo "Command failed after ${max_attempts} attempts: $@" + return "${exit_code}" +} + +check_preconditions() { + if ! hash yq; then + title "Installing yq" + sudo DEST_DIR=/usr/bin/ "${REPOROOT}/scripts/fetch_tools.sh" yq + fi + + if ! hash python3; then + echo "ERROR: python3 is not present on the system - please install" + exit 1 + fi + + if ! python3 -c "import yaml"; then + echo "ERROR: missing python's yaml library - please install" + exit 1 + fi +} + +clone_repo() { + local repo="$1" + local commit="$2" + local destdir="$3" + + local repodir="${destdir}/${repo##*/}" + + if [[ -d "${repodir}" ]]; then + return + fi + + if "${REBASE_USE_SSH}"; then + repo="git@github.com:${repo#https://github.com/}" + fi + + git init "${repodir}" + pushd "${repodir}" >/dev/null + git remote add origin "${repo}" + retry_cmd git fetch origin --quiet --filter=tree:0 --tags "${commit}" + git checkout "${commit}" + popd >/dev/null +} + +download_cluster_monitoring_operator() { + local release_image_amd64="$1" + local release_image_arm64="$2" + + rm -rf "${STAGING_DIR}" + mkdir -p "${STAGING_DIR}" + pushd "${STAGING_DIR}" >/dev/null + + local authentication="" + if [[ -f "${PULL_SECRET_FILE}" ]]; then + authentication="-a ${PULL_SECRET_FILE}" + else + >&2 echo "Warning: no pull secret found at ${PULL_SECRET_FILE}" + fi + + title "# Fetching release info for ${release_image_amd64} (amd64)" + oc adm release info ${authentication} "${release_image_amd64}" -o json > release_amd64.json + title "# Fetching release info for ${release_image_arm64} (arm64)" + oc adm release info ${authentication} "${release_image_arm64}" -o json > release_arm64.json + + title "# Extracting cluster-monitoring-operator source commit" + cat release_amd64.json \ + | jq -r '.references.spec.tags[] | "\(.name) \(.annotations."io.openshift.build.source-location") \(.annotations."io.openshift.build.commit.id")"' > source-commits + + local cmo_line + cmo_line=$(grep '^cluster-monitoring-operator ' source-commits) || { + >&2 echo "ERROR: cluster-monitoring-operator not found in release payload" + return 1 + } + + local repo commit + repo=$(echo "${cmo_line}" | cut -d ' ' -f 2) + commit=$(echo "${cmo_line}" | cut -d ' ' -f 3) + + title "# Cloning cluster-monitoring-operator at ${commit}" + clone_repo "${repo}" "${commit}" "." + + popd >/dev/null +} + +update_metrics_server_manifests() { + [[ -d "${REPOROOT}/assets/optional/metrics-server" ]] || return 0 + + title "Rebasing metrics-server manifests" + + local ms_crb="${REPOROOT}/assets/optional/metrics-server/01-cluster-role-binding.yaml" + yq -i '.subjects += [{"kind": "User", "name": "system:metrics-server"}]' "$ms_crb" + + local ms_deploy="${REPOROOT}/assets/optional/metrics-server/03-deployment.yaml" + yq -i '.spec.replicas = 1' "$ms_deploy" + yq -i '.spec.strategy = {"type": "Recreate"}' "$ms_deploy" + yq -i 'del(.spec.template.spec.affinity)' "$ms_deploy" + yq -i '.spec.template.spec.containers[0].image = "quay.io/openshift/kube-metrics-server"' "$ms_deploy" + yq -i '.spec.template.spec.containers[0].securityContext.capabilities.drop = ["ALL"]' "$ms_deploy" +} + +update_kube_state_metrics_manifests() { + [[ -d "${REPOROOT}/assets/optional/kube-state-metrics" ]] || return 0 + + title "Rebasing kube-state-metrics manifests" + + local ksm_deploy="${REPOROOT}/assets/optional/kube-state-metrics/03-deployment.yaml" + + yq -i '.spec.template.spec.containers[0].image = "quay.io/openshift/kube-state-metrics"' "$ksm_deploy" + yq -i '.spec.template.spec.containers[1].image = "quay.io/openshift/kube-rbac-proxy"' "$ksm_deploy" + yq -i '.spec.template.spec.containers[2].image = "quay.io/openshift/kube-rbac-proxy"' "$ksm_deploy" + + yq -i '.spec.template.spec.containers[0].securityContext = {"allowPrivilegeEscalation": false, "readOnlyRootFilesystem": true, "runAsNonRoot": true}' "$ksm_deploy" + yq -i '.spec.template.spec.containers[1].securityContext = {"allowPrivilegeEscalation": false, "readOnlyRootFilesystem": true, "runAsNonRoot": true}' "$ksm_deploy" + yq -i '.spec.template.spec.containers[2].securityContext = {"allowPrivilegeEscalation": false, "readOnlyRootFilesystem": true, "runAsNonRoot": true}' "$ksm_deploy" + yq -i '.spec.template.spec.securityContext = {"runAsNonRoot": true}' "$ksm_deploy" + + yq -i '.spec.template.spec.containers[0].resources.limits = {"cpu": "100m", "memory": "200Mi"}' "$ksm_deploy" + yq -i '.spec.template.spec.containers[1].resources.limits = {"cpu": "20m", "memory": "40Mi"}' "$ksm_deploy" + yq -i '.spec.template.spec.containers[2].resources.limits = {"cpu": "20m", "memory": "40Mi"}' "$ksm_deploy" + + yq -i '(.spec.template.spec.containers[1].volumeMounts[] | select(.name == "kube-state-metrics-tls")).readOnly = true' "$ksm_deploy" + yq -i '(.spec.template.spec.containers[2].volumeMounts[] | select(.name == "kube-state-metrics-tls")).readOnly = true' "$ksm_deploy" + + yq -i '(.spec.template.spec.containers[1].args[] | select(test("--client-ca-file="))) |= "--client-ca-file=/etc/tls/client-ca/ca.crt"' "$ksm_deploy" + yq -i '(.spec.template.spec.containers[2].args[] | select(test("--client-ca-file="))) |= "--client-ca-file=/etc/tls/client-ca/ca.crt"' "$ksm_deploy" + yq -i 'del(.spec.template.spec.volumes[] | select(.name == "metrics-client-ca"))' "$ksm_deploy" + yq -i '.spec.template.spec.volumes += [{"hostPath": {"path": "/var/lib/microshift/certs/admin-kubeconfig-signer/ca.crt", "type": "File"}, "name": "admin-kubeconfig-signer-ca"}]' "$ksm_deploy" + yq -i 'del(.spec.template.spec.containers[1].volumeMounts[] | select(.name == "metrics-client-ca"))' "$ksm_deploy" + yq -i 'del(.spec.template.spec.containers[2].volumeMounts[] | select(.name == "metrics-client-ca"))' "$ksm_deploy" + yq -i '.spec.template.spec.containers[1].volumeMounts += [{"mountPath": "/etc/tls/client-ca/ca.crt", "name": "admin-kubeconfig-signer-ca", "readOnly": true}]' "$ksm_deploy" + yq -i '.spec.template.spec.containers[2].volumeMounts += [{"mountPath": "/etc/tls/client-ca/ca.crt", "name": "admin-kubeconfig-signer-ca", "readOnly": true}]' "$ksm_deploy" + + local ksm_secret="${REPOROOT}/assets/optional/kube-state-metrics/02-kube-rbac-proxy-secret.yaml" + sed -i '/"user":/,/"name":/d' "$ksm_secret" +} + +update_node_exporter_manifests() { + [[ -d "${REPOROOT}/assets/optional/node-exporter" ]] || return 0 + + title "Rebasing node-exporter manifests" + + local ne_ds="${REPOROOT}/assets/optional/node-exporter/03-daemonset.yaml" + + yq -i '.spec.template.spec.containers[0].image = "quay.io/openshift/node-exporter"' "$ne_ds" + yq -i '.spec.template.spec.containers[1].image = "quay.io/openshift/kube-rbac-proxy"' "$ne_ds" + yq -i '.spec.template.spec.initContainers[0].image = "quay.io/openshift/node-exporter"' "$ne_ds" + + yq -i '(.spec.template.spec.containers[1].args[] | select(test("--secure-listen-address="))) |= "--secure-listen-address=0.0.0.0:9100"' "$ne_ds" + + yq -i '(.spec.template.spec.containers[1].args[] | select(test("--client-ca-file="))) |= "--client-ca-file=/etc/tls/client-ca/ca.crt"' "$ne_ds" + yq -i 'del(.spec.template.spec.volumes[] | select(.name == "metrics-client-ca"))' "$ne_ds" + yq -i '.spec.template.spec.volumes += [{"hostPath": {"path": "/var/lib/microshift/certs/admin-kubeconfig-signer/ca.crt", "type": "File"}, "name": "admin-kubeconfig-signer-ca"}]' "$ne_ds" + yq -i 'del(.spec.template.spec.containers[1].volumeMounts[] | select(.name == "metrics-client-ca"))' "$ne_ds" + yq -i '.spec.template.spec.containers[1].volumeMounts += [{"mountPath": "/etc/tls/client-ca/ca.crt", "name": "admin-kubeconfig-signer-ca", "readOnly": true}]' "$ne_ds" + + yq -i '(.spec.template.spec.containers[1].volumeMounts[] | select(.name == "node-exporter-tls")).readOnly = true' "$ne_ds" + + local ne_secret="${REPOROOT}/assets/optional/node-exporter/02-kube-rbac-proxy-secret.yaml" + sed -i '/"user":/,/"name":/d' "$ne_secret" +} + +update_cluster_monitoring_operator_images() { + title "Rebasing metrics component images" + + for goarch in amd64 arm64; do + local arch=${GOARCH_TO_UNAME_MAP["${goarch}"]:-noarch} + local release_file="${STAGING_DIR}/release_${goarch}.json" + + local base_release + base_release=$(jq -r ".metadata.version" "${release_file}") + + for component_dir in metrics-server kube-state-metrics node-exporter; do + [[ -d "${REPOROOT}/assets/optional/${component_dir}" ]] || continue + + local json_key="${COMPONENT_JSON_KEY[$component_dir]}" + local release_tag="${EXPORTER_TAG_MAP[$json_key]}" + local new_image + new_image=$(jq -r ".references.spec.tags[] | select(.name == \"${release_tag}\") | .from.name" "${release_file}") + if [[ -z "${new_image}" || "${new_image}" == "null" ]]; then + >&2 echo "ERROR: Release tag '${release_tag}' not found in payload for ${component_dir}" + return 1 + fi + local component_release_json="${REPOROOT}/assets/optional/${component_dir}/release-${component_dir}-${arch}.json" + jq -n --arg base "$base_release" --arg img "${new_image}" \ + "{\"release\": {\"base\": \$base}, \"images\": {\"${json_key}\": \$img}}" > "${component_release_json}" + + local kustomization_arch_file="${REPOROOT}/assets/optional/${component_dir}/kustomization.${arch}.yaml" + + cat < "${kustomization_arch_file}" +images: +EOF + + local image_names + image_names=$(grep -h 'image:' "${REPOROOT}/assets/optional/${component_dir}/"*.yaml 2>/dev/null \ + | sed 's/.*image: *//; s/"//g; s/:.*//; s/@.*//' | sort -u | grep -v '^$') + + for orig_image in ${image_names}; do + local release_tag="${IMAGE_MAP[$orig_image]:-}" + if [[ -z "${release_tag}" ]]; then + >&2 echo "ERROR: Unknown metrics image '${orig_image}' in ${component_dir}" + return 1 + fi + + local new_image + new_image=$(jq -r ".references.spec.tags[] | select(.name == \"${release_tag}\") | .from.name" "${release_file}") + if [[ -z "${new_image}" || "${new_image}" == "null" ]]; then + >&2 echo "ERROR: Image for release tag '${release_tag}' not found in payload for ${component_dir}" + return 1 + fi + local new_image_name="${new_image%@*}" + local new_image_digest="${new_image#*@}" + + cat <> "${kustomization_arch_file}" + - name: ${orig_image} + newName: ${new_image_name} + digest: ${new_image_digest} +EOF + done + done + done +} + +copy_manifests() { + title "Copying manifests" + "$REPOROOT/scripts/auto-rebase/handle_assets.py" "./scripts/auto-rebase/assets_cluster_monitoring_operator.yaml" +} + +update_last_rebase() { + local release_image_amd64="$1" + local release_image_arm64="$2" + + title "## Updating last_rebase_cluster_monitoring_operator.sh" + + local last_rebase_script="${REPOROOT}/scripts/auto-rebase/last_rebase_cluster_monitoring_operator.sh" + + rm -f "${last_rebase_script}" + cat - >"${last_rebase_script}" <