...

Source file src/github.com/redhat-developer/odo/pkg/devfile/image/image.go

Documentation: github.com/redhat-developer/odo/pkg/devfile/image

     1  // image package provides functions to work with Components of type Image declared in the devfile
     2  package image
     3  
     4  import (
     5  	"context"
     6  	"errors"
     7  	"os/exec"
     8  	"path/filepath"
     9  
    10  	devfile "github.com/devfile/api/v2/pkg/apis/workspaces/v1alpha2"
    11  	"github.com/devfile/library/v2/pkg/devfile/parser/data/v2/common"
    12  
    13  	envcontext "github.com/redhat-developer/odo/pkg/config/context"
    14  	"github.com/redhat-developer/odo/pkg/libdevfile"
    15  	"github.com/redhat-developer/odo/pkg/log"
    16  	odocontext "github.com/redhat-developer/odo/pkg/odo/context"
    17  	"github.com/redhat-developer/odo/pkg/testingutil/filesystem"
    18  )
    19  
    20  // Backend is in interface that must be implemented by container runtimes
    21  type Backend interface {
    22  	// Build the image as defined in the devfile.
    23  	// The filesystem specified will be used to download and store the Dockerfile if it is referenced as a remote URL.
    24  	Build(fs filesystem.Filesystem, image *devfile.ImageComponent, devfilePath string) error
    25  	// Push the image to its registry as defined in the devfile
    26  	Push(image string) error
    27  	// Return the name of the backend
    28  	String() string
    29  }
    30  
    31  var lookPathCmd = exec.LookPath
    32  
    33  // BuildPushImages build all images defined in the devfile with the detected backend
    34  // If push is true, also push the images to their registries
    35  func BuildPushImages(ctx context.Context, backend Backend, fs filesystem.Filesystem, push bool) error {
    36  	var (
    37  		devfileObj  = odocontext.GetEffectiveDevfileObj(ctx)
    38  		devfilePath = odocontext.GetDevfilePath(ctx)
    39  		path        = filepath.Dir(devfilePath)
    40  	)
    41  
    42  	if backend == nil {
    43  		//revive:disable:error-strings This is a top-level error message displayed as is to the end user
    44  		return errors.New("odo requires either Podman or Docker to be installed in your environment. Please install one of them and try again.")
    45  		//revive:enable:error-strings
    46  	}
    47  
    48  	components, err := devfileObj.Data.GetComponents(common.DevfileOptions{
    49  		ComponentOptions: common.ComponentOptions{ComponentType: devfile.ImageComponentType},
    50  	})
    51  	if err != nil {
    52  		return err
    53  	}
    54  	if len(components) == 0 {
    55  		return libdevfile.NewComponentTypeNotFoundError(devfile.ImageComponentType)
    56  	}
    57  
    58  	for _, component := range components {
    59  		err = buildPushImage(backend, fs, component.Image, path, push)
    60  		if err != nil {
    61  			return err
    62  		}
    63  	}
    64  	return nil
    65  }
    66  
    67  // BuildPushSpecificImage build an image defined in the devfile present in devfilePath
    68  // If push is true, also push the image to its registry
    69  func BuildPushSpecificImage(ctx context.Context, backend Backend, fs filesystem.Filesystem, component devfile.Component, push bool) error {
    70  	var (
    71  		devfilePath = odocontext.GetDevfilePath(ctx)
    72  		path        = filepath.Dir(devfilePath)
    73  	)
    74  
    75  	if backend == nil {
    76  		//revive:disable:error-strings This is a top-level error message displayed as is to the end user
    77  		return errors.New("odo requires either Podman or Docker to be installed in your environment. Please install one of them and try again.")
    78  		//revive:enable:error-strings
    79  	}
    80  
    81  	return buildPushImage(backend, fs, component.Image, path, push)
    82  }
    83  
    84  // buildPushImage build an image using the provided backend
    85  // If push is true, also push the image to its registry
    86  func buildPushImage(backend Backend, fs filesystem.Filesystem, image *devfile.ImageComponent, devfilePath string, push bool) error {
    87  	if image == nil {
    88  		return errors.New("image should not be nil")
    89  	}
    90  	var msg string
    91  	if push {
    92  		msg = "Building & Pushing Image: %s"
    93  	} else {
    94  		msg = "Building Image: %s"
    95  	}
    96  	log.Sectionf(msg, image.ImageName)
    97  	err := backend.Build(fs, image, devfilePath)
    98  	if err != nil {
    99  		return err
   100  	}
   101  	if push {
   102  		err = backend.Push(image.ImageName)
   103  		if err != nil {
   104  			return err
   105  		}
   106  	}
   107  	return nil
   108  }
   109  
   110  // SelectBackend selects the container backend to use for building and pushing images
   111  // It will detect podman and docker CLIs (in this order),
   112  // or return nil if none are present locally
   113  func SelectBackend(ctx context.Context) Backend {
   114  
   115  	podmanCmd := envcontext.GetEnvConfig(ctx).PodmanCmd
   116  	globalExtraArgs := envcontext.GetEnvConfig(ctx).OdoContainerBackendGlobalArgs
   117  	buildExtraArgs := envcontext.GetEnvConfig(ctx).OdoImageBuildArgs
   118  	if _, err := lookPathCmd(podmanCmd); err == nil {
   119  
   120  		// Podman does NOT build x86 images on Apple Silicon / M1 and we must *WARN* the user that this will not work.
   121  		// There is a temporary workaround in order to build x86 images on Apple Silicon / M1 by running the following commands:
   122  		// podman machine ssh sudo rpm-ostree install qemu-user-static
   123  		// podman machine ssh sudo systemctl reboot
   124  		//
   125  		// The problem is that Fedora CoreOS does not have qemu-user-static installed by default,
   126  		// and the workaround is to install it manually as the dependencies need to be integrated into the Fedora ecosystem
   127  		// The open discussion is here: https://github.com/containers/podman/discussions/12899
   128  		//
   129  		// TODO: Remove this warning when Podman natively supports x86 images on Apple Silicon / M1.
   130  		if log.IsAppleSilicon() {
   131  			log.Warning("WARNING: Building images on Apple Silicon / M1 is not (yet) supported natively on Podman")
   132  			log.Warning("There is however a temporary workaround: https://github.com/containers/podman/discussions/12899")
   133  		}
   134  		return NewDockerCompatibleBackend(podmanCmd, globalExtraArgs, buildExtraArgs)
   135  	}
   136  
   137  	dockerCmd := envcontext.GetEnvConfig(ctx).DockerCmd
   138  	if _, err := lookPathCmd(dockerCmd); err == nil {
   139  		return NewDockerCompatibleBackend(dockerCmd, globalExtraArgs, buildExtraArgs)
   140  	}
   141  	return nil
   142  }
   143  

View as plain text