Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Unable to mirror Helm Chart with aliased sub-chart: no images detected #1037

Open
rm3l opened this issue Jan 23, 2025 · 0 comments · May be fixed by #1038
Open

Unable to mirror Helm Chart with aliased sub-chart: no images detected #1037

rm3l opened this issue Jan 23, 2025 · 0 comments · May be fixed by #1038
Labels
kind/bug Categorizes issue or PR as related to a bug.

Comments

@rm3l
Copy link
Member

rm3l commented Jan 23, 2025

/kind bug

Description

Hi there,
I'm trying to mirror this Helm Chart (https://github.com/openshift-helm-charts/charts/blob/main/charts/redhat/redhat/redhat-developer-hub/1.4.1/redhat-developer-hub-1.4.1.tgz), but for some reason, oc-mirror is not able to detect the images to mirror.

Here is my image set config:

apiVersion: mirror.openshift.io/v1alpha2
kind: ImageSetConfiguration
mirror:
  helm:
    repositories:
      - name: openshift-charts
        url: https://charts.openshift.io
        charts:
          - name: redhat-developer-hub
            version: "1.4.1"

Output of oc-mirror:

$ oc-mirror --config=.asoro/airgap/my-image-set-configuration.yaml file://mirror-archive

Creating directory: mirror-archive/oc-mirror-workspace/src/publish
Creating directory: mirror-archive/oc-mirror-workspace/src/v2
Creating directory: mirror-archive/oc-mirror-workspace/src/charts
Creating directory: mirror-archive/oc-mirror-workspace/src/release-signatures
backend is not configured in .asoro/airgap/my-image-set-configuration.yaml, using stateless mode
backend is not configured in .asoro/airgap/my-image-set-configuration.yaml, using stateless mode
No metadata detected, creating new workspace
Pulling chart redhat-developer-hub
error image list []
No new images detected, process stopping

Am I missing something? I would expect at least the images to be detected. I even tried forcing the imagePaths, but no luck.

After checking out and debugging the source code of oc-mirror, I narrowed it down to the way the Chart is being rendered. By manually updating and running the mirror.TestFindImages test case against the Chart above, I noticed the following err:

=== RUN   TestFindImages
    helm_test.go:158: 
        	Error Trace:	/home/asoro/work/tools/oc-mirror/pkg/cli/mirror/helm_test.go:158
        	Error:      	Received unexpected error:
        	            	error rendering chart redhat-developer-hub: template: redhat-developer-hub/templates/tests/test-connection.yaml:38:166: executing "redhat-developer-hub/templates/tests/test-connection.yaml" at <.Values.upstream.service.ports.backend>: nil pointer evaluating interface {}.backend
        	Test:       	TestFindImages
--- FAIL: TestFindImages (0.07s)

FAIL

Then I dug a little bit, and noticed that's because the Chart has a dependency as an alias, and it seems oc-mirror does not correctly merge the values.yaml files from both the parent and the aliased charts, hence the error with this upstream.service.ports.backend, which is missing from the parent chart, but declared in the subchart values.

NOTE: helm template renders the resources correctly against the same Chart:

helm template
$ helm repo add openshift-charts https://charts.openshift.io/     
"openshift-charts" has been added to your repositories

$ helm template openshift-charts/redhat-developer-hub --version 1.4.1

---
# Source: redhat-developer-hub/charts/upstream/charts/postgresql/templates/secrets.yaml
apiVersion: v1
kind: Secret
metadata:
  name: release-name-postgresql
  namespace: "my-ns"
  labels:
    app.kubernetes.io/instance: release-name
    app.kubernetes.io/managed-by: Helm
    app.kubernetes.io/name: postgresql
    app.kubernetes.io/version: 15.4.0
    helm.sh/chart: postgresql-12.10.0
type: Opaque
data:
  postgres-password: "UzhpdlNHQXdyYQ=="
  password: "alRMa3JNZkU0Qw=="
  # We don't auto-generate LDAP password when it's not provided as we do for other passwords
---
# Source: redhat-developer-hub/templates/secrets.yaml
apiVersion: v1
kind: Secret
metadata:
  name: release-name-auth
  namespace: "my-ns"
  labels:
    app.kubernetes.io/name: developer-hub
    helm.sh/chart: redhat-developer-hub-1.4.1
    app.kubernetes.io/instance: release-name
    app.kubernetes.io/managed-by: Helm
    app.kubernetes.io/version: "1.4-1737055846"
    app.kubernetes.io/component: backstage
  annotations:
type: Opaque
data:
  backend-secret: "aTJMZ3hmY1JGeW4waThIVTA2Ukt4R2JM"
---
# Source: redhat-developer-hub/charts/upstream/templates/app-config-configmap.yaml
apiVersion: v1
kind: ConfigMap
metadata:
  name: release-name-developer-hub-app-config
  namespace: "my-ns"
data:
  app-config.yaml: |
    app:
      baseUrl: https://release-name-developer-hub-my-ns.apps.example.com
    auth:
      providers: {}
    backend:
      auth:
        externalAccess:
        - options:
            secret: ${BACKEND_SECRET}
            subject: legacy-default-config
          type: legacy
      baseUrl: https://release-name-developer-hub-my-ns.apps.example.com
      cors:
        origin: https://release-name-developer-hub-my-ns.apps.example.com
      database:
        connection:
          password: ${POSTGRESQL_ADMIN_PASSWORD}
          user: postgres
---
# Source: redhat-developer-hub/templates/dynamic-plugins-configmap.yaml
apiVersion: v1
kind: ConfigMap
metadata:
  name: release-name-dynamic-plugins
data:
  dynamic-plugins.yaml: |
    includes:
    - dynamic-plugins.default.yaml
    plugins: []
---
# Source: redhat-developer-hub/templates/pvcs.yaml
kind: PersistentVolumeClaim
apiVersion: v1
metadata:
  name: release-name-dynamic-plugins-root
spec:
  accessModes:
    - ReadWriteOnce
  resources:
    requests:
      storage: 5Gi
---
# Source: redhat-developer-hub/charts/upstream/charts/postgresql/templates/primary/svc-headless.yaml
apiVersion: v1
kind: Service
metadata:
  name: release-name-postgresql-hl
  namespace: "my-ns"
  labels:
    app.kubernetes.io/instance: release-name
    app.kubernetes.io/managed-by: Helm
    app.kubernetes.io/name: postgresql
    app.kubernetes.io/version: 15.4.0
    helm.sh/chart: postgresql-12.10.0
    app.kubernetes.io/component: primary
  annotations:
    # Use this annotation in addition to the actual publishNotReadyAddresses
    # field below because the annotation will stop being respected soon but the
    # field is broken in some versions of Kubernetes:
    # https://github.com/kubernetes/kubernetes/issues/58662
    service.alpha.kubernetes.io/tolerate-unready-endpoints: "true"
spec:
  type: ClusterIP
  clusterIP: None
  # We want all pods in the StatefulSet to have their addresses published for
  # the sake of the other Postgresql pods even before they're ready, since they
  # have to be able to talk to each other in order to become ready.
  publishNotReadyAddresses: true
  ports:
    - name: tcp-postgresql
      port: 5432
      targetPort: tcp-postgresql
  selector:
    app.kubernetes.io/instance: release-name
    app.kubernetes.io/name: postgresql
    app.kubernetes.io/component: primary
---
# Source: redhat-developer-hub/charts/upstream/charts/postgresql/templates/primary/svc.yaml
apiVersion: v1
kind: Service
metadata:
  name: release-name-postgresql
  namespace: "my-ns"
  labels:
    app.kubernetes.io/instance: release-name
    app.kubernetes.io/managed-by: Helm
    app.kubernetes.io/name: postgresql
    app.kubernetes.io/version: 15.4.0
    helm.sh/chart: postgresql-12.10.0
    app.kubernetes.io/component: primary
spec:
  type: ClusterIP
  sessionAffinity: None
  ports:
    - name: tcp-postgresql
      port: 5432
      targetPort: tcp-postgresql
      nodePort: null
  selector:
    app.kubernetes.io/instance: release-name
    app.kubernetes.io/name: postgresql
    app.kubernetes.io/component: primary
---
# Source: redhat-developer-hub/charts/upstream/templates/service.yaml
apiVersion: v1
kind: Service
metadata:
  name: release-name-developer-hub
  namespace: "my-ns" 
  labels:
    app.kubernetes.io/name: developer-hub
    helm.sh/chart: upstream-2.1.0
    app.kubernetes.io/instance: release-name
    app.kubernetes.io/managed-by: Helm
    app.kubernetes.io/component: backstage
spec:
  type: ClusterIP
  sessionAffinity: None
  ports:
    - name: http-backend
      port: 7007
      targetPort: backend
      protocol: TCP
      nodePort: null
    - name: http-metrics
      port: 9464
      targetPort: 9464  
  selector:
    app.kubernetes.io/name: developer-hub
    app.kubernetes.io/instance: release-name
    app.kubernetes.io/component: backstage
---
# Source: redhat-developer-hub/charts/upstream/templates/backstage-deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: release-name-developer-hub
  namespace: "my-ns"
  labels: 
    app.kubernetes.io/name: developer-hub
    helm.sh/chart: upstream-2.1.0
    app.kubernetes.io/instance: release-name
    app.kubernetes.io/managed-by: Helm
    app.kubernetes.io/component: backstage
  annotations:
spec:
  replicas: 1
  revisionHistoryLimit: 10
  selector:
    matchLabels:
      app.kubernetes.io/name: developer-hub
      app.kubernetes.io/instance: release-name
      app.kubernetes.io/component: backstage
  template:
    metadata:
      labels:
        app.kubernetes.io/name: developer-hub
        helm.sh/chart: upstream-2.1.0
        app.kubernetes.io/instance: release-name
        app.kubernetes.io/managed-by: Helm
        app.kubernetes.io/component: backstage
      annotations:
        checksum/app-config: a51552987cdb96e1fb3edccca2150e003a888839c9ff5894826e4771b17fdd3c
        checksum/dynamic-plugins: 'f1f9a92f14a31362d7eb30e67ac1458faf1c685765610f93a8967194d8bc1a5f'
    spec:
      serviceAccountName: default
      volumes:
        - name: dynamic-plugins-root
          persistentVolumeClaim:
            claimName: 'release-name-dynamic-plugins-root'
        - configMap:
            defaultMode: 420
            name: 'release-name-dynamic-plugins'
            optional: true
          name: dynamic-plugins
        - name: dynamic-plugins-npmrc
          secret:
            defaultMode: 420
            optional: true
            secretName: 'release-name-dynamic-plugins-npmrc'
        - name: dynamic-plugins-registry-auth
          secret:
            defaultMode: 416
            optional: true
            secretName: 'release-name-dynamic-plugins-registry-auth'
        - emptyDir: {}
          name: npmcacache
        - name: backstage-app-config
          configMap:
            name: release-name-developer-hub-app-config
      
      initContainers:
        - command:
          - ./install-dynamic-plugins.sh
          - /dynamic-plugins-root
          env:
          - name: NPM_CONFIG_USERCONFIG
            value: /opt/app-root/src/.npmrc.dynamic-plugins
          image: 'registry.redhat.io/rhdh/rhdh-hub-rhel9@sha256:d8268197ba0466643efb818fcad8f0fc29e32463f75b0f7f51d9ce75ec717572'
          imagePullPolicy: Always
          name: install-dynamic-plugins
          resources:
            limits:
              cpu: 1000m
              ephemeral-storage: 5Gi
              memory: 2.5Gi
            requests:
              cpu: 250m
              memory: 256Mi
          securityContext:
            allowPrivilegeEscalation: false
            capabilities:
              drop:
              - ALL
            runAsNonRoot: true
            seccompProfile:
              type: RuntimeDefault
          volumeMounts:
          - mountPath: /dynamic-plugins-root
            name: dynamic-plugins-root
          - mountPath: /opt/app-root/src/dynamic-plugins.yaml
            name: dynamic-plugins
            readOnly: true
            subPath: dynamic-plugins.yaml
          - mountPath: /opt/app-root/src/.npmrc.dynamic-plugins
            name: dynamic-plugins-npmrc
            readOnly: true
            subPath: .npmrc
          - mountPath: /opt/app-root/src/.config/containers
            name: dynamic-plugins-registry-auth
            readOnly: true
          - mountPath: /opt/app-root/src/.npm/_cacache
            name: npmcacache
          workingDir: /opt/app-root/src
      containers:
        - name: backstage-backend
          image: registry.redhat.io/rhdh/rhdh-hub-rhel9@sha256:d8268197ba0466643efb818fcad8f0fc29e32463f75b0f7f51d9ce75ec717572
          imagePullPolicy: "Always"
          securityContext:
            allowPrivilegeEscalation: false
            capabilities:
              drop:
              - ALL
            runAsNonRoot: true
            seccompProfile:
              type: RuntimeDefault
          args:
            - "--config"
            - "dynamic-plugins-root/app-config.dynamic-plugins.yaml"
            - "--config"
            - "/opt/app-root/src/app-config-from-configmap.yaml"
          resources:
            limits:
              cpu: 1000m
              ephemeral-storage: 5Gi
              memory: 2.5Gi
            requests:
              cpu: 250m
              memory: 1Gi
          readinessProbe:
            failureThreshold: 3
            httpGet:
              path: /.backstage/health/v1/readiness
              port: backend
              scheme: HTTP
            periodSeconds: 10
            successThreshold: 2
            timeoutSeconds: 4
          livenessProbe:
            failureThreshold: 3
            httpGet:
              path: /.backstage/health/v1/liveness
              port: backend
              scheme: HTTP
            periodSeconds: 10
            successThreshold: 1
            timeoutSeconds: 4
          startupProbe:
            failureThreshold: 3
            httpGet:
              path: /.backstage/health/v1/liveness
              port: backend
              scheme: HTTP
            initialDelaySeconds: 30
            periodSeconds: 20
            successThreshold: 1
            timeoutSeconds: 4
          env:
            - name: APP_CONFIG_backend_listen_port
              value: "7007"
            - name: POSTGRES_HOST
              value: release-name-postgresql
            - name: POSTGRES_PORT
              value: "5432"
            - name: POSTGRES_USER
              value: bn_backstage
            - name: POSTGRES_PASSWORD
              valueFrom:
                secretKeyRef:
                  name: release-name-postgresql
                  key: password
            - name: BACKEND_SECRET
              valueFrom:
                secretKeyRef:
                  key: backend-secret
                  name: 'release-name-auth'
            - name: POSTGRESQL_ADMIN_PASSWORD
              valueFrom:
                secretKeyRef:
                  key: postgres-password
                  name: 'release-name-postgresql'
          ports:
            - name: backend
              containerPort: 7007
              protocol: TCP
          volumeMounts:
            - name: backstage-app-config
              mountPath: "/opt/app-root/src/app-config-from-configmap.yaml"
              subPath: app-config.yaml
            - mountPath: /opt/app-root/src/dynamic-plugins-root
              name: dynamic-plugins-root
---
# Source: redhat-developer-hub/charts/upstream/charts/postgresql/templates/primary/statefulset.yaml
apiVersion: apps/v1
kind: StatefulSet
metadata:
  name: release-name-postgresql
  namespace: "my-ns"
  labels:
    app.kubernetes.io/instance: release-name
    app.kubernetes.io/managed-by: Helm
    app.kubernetes.io/name: postgresql
    app.kubernetes.io/version: 15.4.0
    helm.sh/chart: postgresql-12.10.0
    app.kubernetes.io/component: primary
spec:
  replicas: 1
  serviceName: release-name-postgresql-hl
  updateStrategy:
    rollingUpdate: {}
    type: RollingUpdate
  selector:
    matchLabels:
      app.kubernetes.io/instance: release-name
      app.kubernetes.io/name: postgresql
      app.kubernetes.io/component: primary
  template:
    metadata:
      name: release-name-postgresql
      labels:
        app.kubernetes.io/instance: release-name
        app.kubernetes.io/managed-by: Helm
        app.kubernetes.io/name: postgresql
        app.kubernetes.io/version: 15.4.0
        helm.sh/chart: postgresql-12.10.0
        app.kubernetes.io/component: primary
    spec:
      serviceAccountName: default
      
      affinity:
        podAffinity:
          
        podAntiAffinity:
          preferredDuringSchedulingIgnoredDuringExecution:
            - podAffinityTerm:
                labelSelector:
                  matchLabels:
                    app.kubernetes.io/instance: release-name
                    app.kubernetes.io/name: postgresql
                    app.kubernetes.io/component: primary
                topologyKey: kubernetes.io/hostname
              weight: 1
        nodeAffinity:
          
      hostNetwork: false
      hostIPC: false
      containers:
        - name: postgresql
          image: registry.redhat.io/rhel9/postgresql-15@sha256:44a08b83a6c50714b52f4cf1c3476bc16b66faec21dd9a9bc07d1be5f97b8150
          imagePullPolicy: "IfNotPresent"
          env:
            - name: BITNAMI_DEBUG
              value: "false"
            - name: POSTGRESQL_PORT_NUMBER
              value: "5432"
            - name: POSTGRESQL_VOLUME_DIR
              value: "/var/lib/pgsql/data"
            - name: PGDATA
              value: "/var/lib/pgsql/data/userdata"
            # Authentication
            - name: POSTGRES_USER
              value: "bn_backstage"
            - name: POSTGRES_PASSWORD
              valueFrom:
                secretKeyRef:
                  name: release-name-postgresql
                  key: password
            - name: POSTGRES_POSTGRES_PASSWORD
              valueFrom:
                secretKeyRef:
                  name: release-name-postgresql
                  key: postgres-password
            # Replication
            # Initdb
            # Standby
            # LDAP
            - name: POSTGRESQL_ENABLE_LDAP
              value: "no"
            # TLS
            - name: POSTGRESQL_ENABLE_TLS
              value: "no"
            # Audit
            - name: POSTGRESQL_LOG_HOSTNAME
              value: "false"
            - name: POSTGRESQL_LOG_CONNECTIONS
              value: "false"
            - name: POSTGRESQL_LOG_DISCONNECTIONS
              value: "false"
            - name: POSTGRESQL_PGAUDIT_LOG_CATALOG
              value: "off"
            # Others
            - name: POSTGRESQL_CLIENT_MIN_MESSAGES
              value: "error"
            - name: POSTGRESQL_SHARED_PRELOAD_LIBRARIES
              value: "pgaudit"
            - name: POSTGRESQL_ADMIN_PASSWORD
              valueFrom:
                secretKeyRef:
                  key: postgres-password
                  name: 'release-name-postgresql'
          ports:
            - name: tcp-postgresql
              containerPort: 5432
          livenessProbe:
            failureThreshold: 6
            initialDelaySeconds: 30
            periodSeconds: 10
            successThreshold: 1
            timeoutSeconds: 5
            exec:
              command:
                - /bin/sh
                - -c
                - exec pg_isready -U "bn_backstage" -h 127.0.0.1 -p 5432
          readinessProbe:
            failureThreshold: 6
            initialDelaySeconds: 5
            periodSeconds: 10
            successThreshold: 1
            timeoutSeconds: 5
            exec:
              command:
                - /bin/sh
                - -c
                - -e
                - |
                  exec pg_isready -U "bn_backstage" -h 127.0.0.1 -p 5432
          resources:
            limits:
              cpu: 250m
              ephemeral-storage: 20Mi
              memory: 1024Mi
            requests:
              cpu: 250m
              memory: 256Mi
          volumeMounts:
            - name: dshm
              mountPath: /dev/shm
            - name: data
              mountPath: /var/lib/pgsql/data
      volumes:
        - name: dshm
          emptyDir:
            medium: Memory
  volumeClaimTemplates:
    - apiVersion: v1
      kind: PersistentVolumeClaim
      metadata:
        name: data
      spec:
        accessModes:
          - "ReadWriteOnce"
        resources:
          requests:
            storage: "1Gi"
---
# Source: redhat-developer-hub/templates/route.yaml
apiVersion: route.openshift.io/v1
kind: Route
metadata:
  name: release-name-developer-hub
  namespace: "my-ns"
  labels:
    app.kubernetes.io/name: developer-hub
    helm.sh/chart: redhat-developer-hub-1.4.1
    app.kubernetes.io/instance: release-name
    app.kubernetes.io/managed-by: Helm
    app.kubernetes.io/version: "1.4-1737055846"
    app.kubernetes.io/component: backstage
spec:
  host: release-name-developer-hub-my-ns.apps.example.com
  path: /
  port:
    targetPort: http-backend
  tls:
    insecureEdgeTerminationPolicy: Redirect
    termination: edge
  to:
    kind: Service
    name: release-name-developer-hub
    weight: 100
  wildcardPolicy: None
---
# Source: redhat-developer-hub/templates/tests/test-connection.yaml
apiVersion: v1
kind: Pod
metadata:
  name: "release-name-developer-hub-test-connection"
  labels:
    app.kubernetes.io/name: developer-hub
    helm.sh/chart: redhat-developer-hub-1.4.1
    app.kubernetes.io/instance: release-name
    app.kubernetes.io/managed-by: Helm
    app.kubernetes.io/version: "1.4-1737055846"
    app.kubernetes.io/component: backstage
  annotations:
      helm.sh/hook: test
spec:
  containers:
    - name: curl
      securityContext:
        allowPrivilegeEscalation: false
        readOnlyRootFilesystem: true
        capabilities:
          drop: ["ALL"]
        runAsNonRoot: false
      resources:
        requests:
          cpu: 10m
          memory: 20Mi
        limits:
          cpu: 10m
          memory: 20Mi
      livenessProbe:
        exec:
          command:
          - ls
          - /usr/bin/curl
      image: registry.redhat.io/ubi9:latest
      imagePullPolicy: IfNotPresent
      command: ["/bin/sh", "-c"]
      args:
        - |
          curl --connect-timeout 5 --max-time 20 --retry 20 --retry-delay 10 --retry-max-time 60 --retry-all-errors release-name-developer-hub:7007
  restartPolicy: Never

Versions of software

Operating System:
Fedora 41

Output of oc-mirror version:

$ oc mirror version                                                                     
WARNING: This version information is deprecated and will be replaced with the output from --short. Use --output=yaml|json to get the full version.
Client Version: version.Info{Major:"", Minor:"", GitVersion:"4.17.0-202412170235.p0.g07714b7.assembly.stream.el9-07714b7", GitCommit:"07714b7c836ec3ad1b776f25b44c3b2c2f083aa2", GitTreeState:"clean", BuildDate:"2024-12-17T20:25:22Z", GoVersion:"go1.22.9 (Red Hat 1.22.9-2.el9_5) X:strictfipsruntime", Compiler:"gc", Platform:"linux/amd64"}

Also tried from the main branch:

$ ./bin/oc-mirror version                                                                                                                                                             
W0123 23:20:04.652973 4016041 mirror.go:102] 

⚠️   oc-mirror v1 is deprecated (starting in 4.18 release) and will be removed in a future release - please migrate to oc-mirror --v2

WARNING: This version information is deprecated and will be replaced with the output from --short. Use --output=yaml|json to get the full version.
Client Version: version.Info{Major:"", Minor:"", GitVersion:"v0.2.0-alpha.1-352-gf6df853", GitCommit:"f6df8533", GitTreeState:"dirty", BuildDate:"2025-01-23T14:59:23Z", GoVersion:"go1.23.5", Compiler:"gc", Platform:"linux/amd64"}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
kind/bug Categorizes issue or PR as related to a bug.
Projects
None yet
1 participant