github.com/operator-framework/operator-lifecycle-manager@v0.30.0/test/e2e/skopeo.go (about)

     1  package e2e
     2  
     3  import (
     4  	"context"
     5  	"fmt"
     6  	"os/exec"
     7  	"path"
     8  
     9  	"github.com/operator-framework/operator-lifecycle-manager/pkg/lib/operatorclient"
    10  	"k8s.io/utils/ptr"
    11  
    12  	corev1 "k8s.io/api/core/v1"
    13  	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
    14  )
    15  
    16  const (
    17  	insecure              = "--insecure-policy=true"
    18  	skopeo                = "skopeo"
    19  	debug                 = "--debug"
    20  	skipTLS               = "--dest-tls-verify=false"
    21  	skipCreds             = "--dest-no-creds=true"
    22  	destCreds             = "--dest-authfile="
    23  	v2format              = "--format=v2s2"
    24  	skopeoImage           = "quay.io/skopeo/stable:v1.15.0"
    25  	BuilderServiceAccount = "builder"
    26  	authPath              = "/mnt/registry-auth"
    27  	cachePath             = ".local"
    28  )
    29  
    30  func getRegistryAuthSecretName(client operatorclient.ClientInterface, namespace string) (string, error) {
    31  	var sa *corev1.ServiceAccount
    32  	var err error
    33  
    34  	// wait for the builder service account to exist and contain image pull secrets
    35  	err = waitFor(func() (bool, error) {
    36  		sa, err = client.KubernetesInterface().CoreV1().ServiceAccounts(namespace).Get(context.TODO(), BuilderServiceAccount, metav1.GetOptions{})
    37  		if err != nil {
    38  			return false, err
    39  		}
    40  		return len(sa.ImagePullSecrets) > 0, nil
    41  	})
    42  
    43  	if err != nil {
    44  		return "", err
    45  	}
    46  
    47  	secretName := sa.ImagePullSecrets[0].Name
    48  	secret, err := client.KubernetesInterface().CoreV1().Secrets(namespace).Get(context.TODO(), secretName, metav1.GetOptions{})
    49  	if err != nil {
    50  		return "", err
    51  	}
    52  	return secret.GetName(), nil
    53  }
    54  
    55  func skopeoCopyCmd(newImage, newTag, oldImage, oldTag, auth string) []string {
    56  	newImageName := fmt.Sprint(newImage, newTag)
    57  	oldImageName := fmt.Sprint(oldImage, oldTag)
    58  
    59  	var creds string
    60  	if auth == "" {
    61  		creds = skipCreds
    62  	} else {
    63  		creds = fmt.Sprint(destCreds, path.Join(cachePath, "auth.json"))
    64  	}
    65  
    66  	cmd := []string{debug, insecure, "copy", skipTLS, v2format, creds, oldImageName, newImageName}
    67  
    68  	return cmd
    69  }
    70  
    71  func createSkopeoPod(client operatorclient.ClientInterface, args []string, namespace string, registrySecret string) error {
    72  	pod := &corev1.Pod{
    73  		ObjectMeta: metav1.ObjectMeta{
    74  			Name:      skopeo,
    75  			Namespace: namespace,
    76  			Labels:    map[string]string{"name": skopeo},
    77  		},
    78  		Spec: corev1.PodSpec{
    79  			SecurityContext: &corev1.PodSecurityContext{
    80  				SeccompProfile: &corev1.SeccompProfile{
    81  					Type: corev1.SeccompProfileTypeRuntimeDefault,
    82  				},
    83  			},
    84  			Containers: []corev1.Container{
    85  				{
    86  					Name:  skopeo,
    87  					Image: skopeoImage,
    88  					Args:  args,
    89  					SecurityContext: &corev1.SecurityContext{
    90  						ReadOnlyRootFilesystem:   ptr.To(false),
    91  						AllowPrivilegeEscalation: ptr.To(false),
    92  						Capabilities: &corev1.Capabilities{
    93  							Drop: []corev1.Capability{"ALL"},
    94  						},
    95  						RunAsNonRoot: ptr.To(true),
    96  						RunAsUser:    ptr.To(int64(1001)),
    97  					},
    98  				},
    99  			},
   100  			RestartPolicy: corev1.RestartPolicyNever,
   101  			// ServiceAccountName: "builder",
   102  		},
   103  	}
   104  
   105  	if registrySecret != "" {
   106  		// update container command to first convert the dockercfg to an auth.json file that skopeo can use
   107  		authJsonPath := path.Join(cachePath, "auth.json")
   108  		authJson := "\"{\\\"auths\\\": $(cat /mnt/registry-auth/.dockercfg)}\""
   109  		cmd := fmt.Sprintf("echo %s > %s && exec skopeo $@", authJson, authJsonPath)
   110  
   111  		pod.Spec.Containers[0].Command = []string{"bash", "-c", cmd}
   112  
   113  		pod.Spec.Containers[0].VolumeMounts = []corev1.VolumeMount{
   114  			{
   115  				Name:      "registry-auth",
   116  				MountPath: authPath,
   117  				ReadOnly:  true,
   118  			}, {
   119  				Name:      "cache",
   120  				MountPath: cachePath,
   121  				ReadOnly:  false,
   122  			},
   123  		}
   124  		pod.Spec.Volumes = []corev1.Volume{
   125  			{
   126  				Name: "registry-auth",
   127  				VolumeSource: corev1.VolumeSource{
   128  					Secret: &corev1.SecretVolumeSource{
   129  						SecretName: registrySecret,
   130  					},
   131  				},
   132  			},
   133  			{
   134  				Name: "cache",
   135  				VolumeSource: corev1.VolumeSource{
   136  					EmptyDir: &corev1.EmptyDirVolumeSource{},
   137  				},
   138  			},
   139  		}
   140  	}
   141  
   142  	_, err := client.KubernetesInterface().CoreV1().Pods(namespace).Create(context.TODO(), pod, metav1.CreateOptions{})
   143  	if err != nil {
   144  		return err
   145  	}
   146  	return nil
   147  }
   148  
   149  func deleteSkopeoPod(client operatorclient.ClientInterface, namespace string) error {
   150  	err := client.KubernetesInterface().CoreV1().Pods(namespace).Delete(context.TODO(), skopeo, metav1.DeleteOptions{})
   151  	if err != nil {
   152  		return err
   153  	}
   154  	return nil
   155  }
   156  
   157  func skopeoLocalCopy(newImage, newTag string, oldImage, oldTag string) (string, error) {
   158  	newImageName := fmt.Sprint(newImage, newTag)
   159  	oldImageName := fmt.Sprint(oldImage, oldTag)
   160  	cmd := exec.Command(skopeo, debug, insecure, "copy", skipTLS, v2format, skipCreds, oldImageName, newImageName)
   161  
   162  	out, err := cmd.Output()
   163  	fmt.Println(string(out))
   164  	if err != nil {
   165  		return "", fmt.Errorf("failed to exec %#v: %v", cmd.Args, err)
   166  	}
   167  
   168  	return newImageName, nil
   169  }