diff --git a/api/raczylo.com/v1/zz_generated.deepcopy.go b/api/raczylo.com/v1/zz_generated.deepcopy.go index 56474ee..d3f3639 100644 --- a/api/raczylo.com/v1/zz_generated.deepcopy.go +++ b/api/raczylo.com/v1/zz_generated.deepcopy.go @@ -21,6 +21,7 @@ limitations under the License. package v1 import ( + corev1 "k8s.io/api/core/v1" runtime "k8s.io/apimachinery/pkg/runtime" ) @@ -142,6 +143,11 @@ func (in *ClusterImageExportSpec) DeepCopyInto(out *ClusterImageExportSpec) { (*out)[key] = val } } + if in.ImagePullSecrets != nil { + in, out := &in.ImagePullSecrets, &out.ImagePullSecrets + *out = make([]corev1.LocalObjectReference, len(*in)) + copy(*out, *in) + } } // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ClusterImageExportSpec. @@ -211,6 +217,11 @@ func (in *ClusterImageSpec) DeepCopyInto(out *ClusterImageSpec) { (*out)[key] = val } } + if in.ImagePullSecrets != nil { + in, out := &in.ImagePullSecrets, &out.ImagePullSecrets + *out = make([]corev1.LocalObjectReference, len(*in)) + copy(*out, *in) + } } // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ClusterImageSpec. diff --git a/chart/Chart.yaml b/chart/Chart.yaml index 2e520cb..e96fb15 100644 --- a/chart/Chart.yaml +++ b/chart/Chart.yaml @@ -10,9 +10,9 @@ description: | type: application -version: 0.1.23 +version: 0.1.27 -appVersion: "0.1.23" +appVersion: "0.1.27" home: https://github.com/lukaszraczylo/kubernetes-images-sync-operator diff --git a/chart/values.yaml b/chart/values.yaml index 909a6b8..0b8d34e 100644 --- a/chart/values.yaml +++ b/chart/values.yaml @@ -12,7 +12,7 @@ sa: - ALL image: repository: ghcr.io/lukaszraczylo/kubernetes-images-sync-operator - tag: 0.1.23 + tag: 0.1.27 resources: limits: cpu: 500m diff --git a/docker-image-worker/Dockerfile b/docker-image-worker/Dockerfile index 06fa4f1..f78befc 100644 --- a/docker-image-worker/Dockerfile +++ b/docker-image-worker/Dockerfile @@ -9,6 +9,7 @@ RUN apt-get update && apt-get install -y --no-install-recommends \ gnupg2 \ python3-pip \ sudo \ + jq \ && rm -rf /var/lib/apt/lists/* RUN echo "deb [arch=${TARGETARCH}] https://download.opensuse.org/repositories/devel:/kubic:/libcontainers:/unstable/xUbuntu_22.04/ /" | tee /etc/apt/sources.list.d/devel:kubic:libcontainers:unstable.list \ @@ -30,7 +31,10 @@ RUN adduser --disabled-password --gecos "" --uid 1001 runner \ WORKDIR /home/runner COPY storage.conf containers.conf registries.conf /home/runner/.config/containers/ -COPY requirements.txt export.py cleanup.py s3_utils.py ./ +COPY requirements.txt export.py cleanup.py s3_utils.py podman-preauth.sh ./ USER runner RUN sudo chown -R runner:runner /home/runner/.config \ - && python3 -m pip install --no-cache-dir --only-binary=:all: -r requirements.txt \ No newline at end of file + && python3 -m pip install --no-cache-dir --only-binary=:all: -r requirements.txt \ + && sudo chmod +x podman-preauth.sh +ENTRYPOINT ["/home/runner/podman-preauth.sh"] +CMD ["bash", "-c"] \ No newline at end of file diff --git a/docker-image-worker/podman-preauth.sh b/docker-image-worker/podman-preauth.sh new file mode 100755 index 0000000..cebd935 --- /dev/null +++ b/docker-image-worker/podman-preauth.sh @@ -0,0 +1,33 @@ +#!/bin/bash +set -e + +PODMAN_AUTH_FILE="/home/runner/.config/containers/auth.json" + +# Initialize the auth file if it doesn't exist or is empty +mkdir -p $(dirname $PODMAN_AUTH_FILE) +if [ ! -s "$PODMAN_AUTH_FILE" ]; then + echo '{"auths":{}}' > $PODMAN_AUTH_FILE +fi + +# Loop through all mounted secret directories +for secret_dir in /home/runner/.docker-secret-*; do + if [ -d "$secret_dir" ]; then + config_file="$secret_dir/.dockerconfigjson" + if [ -f "$config_file" ]; then + # Merge the auth data into the podman auth file + jq -s '.[0].auths * .[1].auths | {auths: .}' $PODMAN_AUTH_FILE $config_file > ${PODMAN_AUTH_FILE}.tmp + mv ${PODMAN_AUTH_FILE}.tmp $PODMAN_AUTH_FILE + # Extract registry, username, and password from the config file + jq -r '.auths | to_entries[] | "\(.key) \(.value.auth)"' $config_file | while read registry auth; do + username=$(echo $auth | base64 -d | cut -d: -f1) + password=$(echo $auth | base64 -d | cut -d: -f2-) + # Perform podman login + podman login --username "$username" --password "$password" "$registry" + echo "podman: Successfully logged into $registry" + done + fi + fi +done + +# Run the original command +exec "$@" \ No newline at end of file diff --git a/internal/controller/raczylo.com/clusterimage_controller.go b/internal/controller/raczylo.com/clusterimage_controller.go index 8a8d87e..fee33bb 100644 --- a/internal/controller/raczylo.com/clusterimage_controller.go +++ b/internal/controller/raczylo.com/clusterimage_controller.go @@ -82,7 +82,7 @@ func (r *ClusterImageReconciler) Reconcile(ctx context.Context, req ctrl.Request case shared.STATUS_SUCCESS, shared.STATUS_FAILED, shared.STATUS_PRESENT: return ctrl.Result{}, nil // No further action needed default: - l.Info("Unexpected ClusterImage status", "Status", clusterImage.Status.Progress) + // l.Info("Unexpected ClusterImage status", "Status", clusterImage.Status.Progress) return ctrl.Result{}, nil } } @@ -188,7 +188,7 @@ func (r *ClusterImageReconciler) handleRunningClusterImage(ctx context.Context, } } - l.Info("Reconciling ClusterImage completed", "Name", clusterImage.Name, "Status", clusterImage.Status.Progress) + // l.Info("Reconciling ClusterImage completed", "Name", clusterImage.Name, "Status", clusterImage.Status.Progress) return r.updateClusterImageExportStatus(ctx, clusterImage) } diff --git a/internal/controller/raczylo.com/clusterimageexport_controller.go b/internal/controller/raczylo.com/clusterimageexport_controller.go index f2db199..c84e3a8 100644 --- a/internal/controller/raczylo.com/clusterimageexport_controller.go +++ b/internal/controller/raczylo.com/clusterimageexport_controller.go @@ -45,7 +45,7 @@ const clusterImageExportFinalizer = "finalizer.clusterimageexport.raczylo.com" func (r *ClusterImageExportReconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.Result, error) { l := log.FromContext(ctx) - l.Info("Reconciling ClusterImageExport") + // l.Info("Reconciling ClusterImageExport") // Fetch the ClusterImageExport instance clusterImageExport := &raczylocomv1.ClusterImageExport{} @@ -224,7 +224,7 @@ func (r *ClusterImageExportReconciler) listImagesInCluster(ctx context.Context, } containersList = shared.RemoveDuplicates(containersList) - l.Info("List of containers in the cluster", "containers", containersList) + // l.Info("List of containers in the cluster", "containers", containersList) return containersList, nil } @@ -270,12 +270,13 @@ func (r *ClusterImageExportReconciler) runCleanupJob(ctx context.Context, cluste } jobParams := shared.JobParams{ - Name: normalisedImageName, - Namespace: clusterImageExport.Namespace, - Image: shared.BACKUP_JOB_IMAGE, - Commands: defaultCommands, - Annotations: clusterImageExport.Spec.JobAnnotations, - ServiceAccount: os.Getenv("POD_SERVICE_ACCOUNT"), + Name: normalisedImageName, + Namespace: clusterImageExport.Namespace, + Image: shared.BACKUP_JOB_IMAGE, + Commands: defaultCommands, + Annotations: clusterImageExport.Spec.JobAnnotations, + ServiceAccount: os.Getenv("POD_SERVICE_ACCOUNT"), + ImagePullSecrets: clusterImageExport.Spec.ImagePullSecrets, } cleanupJob := shared.CreateJob(jobParams, func(raczylocomv1.ClusterImageExport) []string { return nil }) diff --git a/internal/shared/jobs.go b/internal/shared/jobs.go index f397c71..1bfed92 100644 --- a/internal/shared/jobs.go +++ b/internal/shared/jobs.go @@ -24,7 +24,28 @@ type JobParams struct { } func CreateJob[T any](params JobParams, setupFunc func(T) []string) *batchv1.Job { - return &batchv1.Job{ + volumes := []corev1.Volume{} + volumeMounts := []corev1.VolumeMount{} + + if len(params.ImagePullSecrets) > 0 { + for i, secret := range params.ImagePullSecrets { + volumes = append(volumes, corev1.Volume{ + Name: fmt.Sprintf("secret-%d", i), + VolumeSource: corev1.VolumeSource{ + Secret: &corev1.SecretVolumeSource{ + SecretName: secret.Name, + }, + }, + }) + volumeMounts = append(volumeMounts, corev1.VolumeMount{ + Name: fmt.Sprintf("secret-%d", i), + MountPath: fmt.Sprintf("/home/runner/.docker-secret-%d", i), + ReadOnly: true, + }) + } + } + + j := &batchv1.Job{ ObjectMeta: metav1.ObjectMeta{ Name: params.Name, Namespace: params.Namespace, @@ -46,17 +67,16 @@ func CreateJob[T any](params JobParams, setupFunc func(T) []string) *batchv1.Job RestartPolicy: corev1.RestartPolicyOnFailure, ServiceAccountName: params.ServiceAccount, ImagePullSecrets: params.ImagePullSecrets, + Volumes: volumes, Containers: []corev1.Container{ { - Name: "export", - Image: params.Image, - TTY: true, - Command: []string{ - "bash", - "-c", - strings.Join(params.Commands, " && "), - }, - Env: params.EnvVars, + Name: "exporter", + Image: params.Image, + TTY: true, + Command: []string{}, + Args: []string{"/bin/bash", "-c", strings.Join(params.Commands, " && ")}, + VolumeMounts: volumeMounts, + Env: params.EnvVars, SecurityContext: &corev1.SecurityContext{ Privileged: pointer.Bool(true), }, @@ -66,6 +86,7 @@ func CreateJob[T any](params JobParams, setupFunc func(T) []string) *batchv1.Job }, }, } + return j } func SetupS3Params(s3Config raczylocomv1.ClusterImageStorageS3) []string {