Skip to content

Commit

Permalink
feat: support pack different arch image together
Browse files Browse the repository at this point in the history
  • Loading branch information
kakzhou719 committed Apr 13, 2023
1 parent 70bb9ff commit 615bb15
Show file tree
Hide file tree
Showing 7 changed files with 165 additions and 58 deletions.
2 changes: 1 addition & 1 deletion build/kubefile/parser/image_engine_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -133,7 +133,7 @@ func (testImageEngine) PushManifest(name, destSpec string, opts *options.PushOpt
panic("implement me")
}

func (testImageEngine) AddToManifest(name, imageSpec string, opts *options.ManifestAddOpts) error {
func (testImageEngine) AddToManifest(name string, imageSpec []string, opts *options.ManifestAddOpts) error {
panic("implement me")
}

Expand Down
30 changes: 11 additions & 19 deletions cmd/sealer/cmd/alpha/manifest.go
Original file line number Diff line number Diff line change
Expand Up @@ -101,35 +101,26 @@ func manifestAddCommand() *cobra.Command {
Long: manifestAddDescription,
RunE: func(cmd *cobra.Command, args []string) error {
var (
name, imageSpec string
manifestName = addManifestOpts.TargetImageName
imagesToAdd = args
)

switch len(args) {
case 0, 1:
return errors.New("at least a manifest name and an image name to add must be specified")
case 2:
name = args[0]
if name == "" {
return fmt.Errorf(`invalid manifest name "%s" `, args[0])
}
imageSpec = args[1]
if imageSpec == "" {
return fmt.Errorf(`invalid image name "%s" `, args[1])
}
default:
return errors.New("at least two arguments are necessary: manifest name and an image name to add to list ")
// if not set `-t` flag , assume the first one is the manifestName,others is the images need to be added to.
if manifestName == "" {
manifestName = args[0]
imagesToAdd = args[1:]
}

engine, err := imageengine.NewImageEngine(options.EngineGlobalConfigurations{})
if err != nil {
return err
}

return engine.AddToManifest(name, imageSpec, &addManifestOpts)
return engine.AddToManifest(manifestName, imagesToAdd, &addManifestOpts)
},
Example: `sealer alpha manifest add mylist:v1.11 image:v1.11-amd64
sealer alpha manifest add mylist:v1.11 transport:imageName`,
Args: cobra.MinimumNArgs(2),
Example: `sealer alpha manifest add app-amd:v1 app-arm:v1 -t all-in-one:v1
sealer alpha manifest add mylist:v1.11 image:v1.11-amd64`,
Args: cobra.MinimumNArgs(1),
}

flags := addCommand.Flags()
Expand All @@ -140,6 +131,7 @@ func manifestAddCommand() *cobra.Command {
flags.StringSliceVar(&addManifestOpts.OsFeatures, "os-features", nil, "override the OS `features` of the specified image")
flags.StringSliceVar(&addManifestOpts.Annotations, "annotation", nil, "set an `annotation` for the specified image")
flags.BoolVar(&addManifestOpts.All, "all", false, "add all of the list's images if the image is a list")
flags.StringVarP(&addManifestOpts.TargetImageName, "target-image", "t", "", "target image name,if it is not exist,will create a new one")

return addCommand
}
Expand Down
15 changes: 8 additions & 7 deletions pkg/define/options/options.go
Original file line number Diff line number Diff line change
Expand Up @@ -179,13 +179,14 @@ type ManifestDeleteOpts struct {
}

type ManifestAddOpts struct {
Os string
Arch string
Variant string
OsVersion string
OsFeatures []string
Annotations []string
All bool
Os string
Arch string
Variant string
OsVersion string
OsFeatures []string
Annotations []string
All bool
TargetImageName string
}

type ManifestRemoveOpts struct {
Expand Down
18 changes: 3 additions & 15 deletions pkg/imageengine/buildah/load.go
Original file line number Diff line number Diff line change
Expand Up @@ -127,21 +127,9 @@ func (engine *Engine) Load(opts *options.LoadOptions) error {
return fmt.Errorf("failed to create new manifest %s :%v ", manifestName, err)
}

defer func() {
if errors.Is(err, LoadError) {
err = engine.DeleteManifests([]string{manifestName}, &options.ManifestDeleteOpts{})
if err != nil {
logrus.Errorf("failed to delete manifest %s :%v ", manifestName, err)
}
}
}()

for _, imageID := range instancesIDs {
err = engine.AddToManifest(manifestName, imageID, &options.ManifestAddOpts{})
if err != nil {
logrus.Errorf("failed to add new image %s to %s :%v ", imageID, manifestName, err)
return LoadError
}
err = engine.AddToManifest(manifestName, instancesIDs, &options.ManifestAddOpts{})
if err != nil {
return fmt.Errorf("failed to add new image to %s :%v ", manifestName, err)
}

return nil
Expand Down
137 changes: 130 additions & 7 deletions pkg/imageengine/buildah/manifest.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,9 @@ import (
"os"
"strings"

"github.com/containers/storage"
"github.com/pkg/errors"

"github.com/containers/buildah/util"
"github.com/containers/common/libimage"
"github.com/containers/common/libimage/manifests"
Expand Down Expand Up @@ -158,20 +161,88 @@ func (engine *Engine) PushManifest(name, destSpec string, opts *options.PushOpti
return err
}

func (engine *Engine) AddToManifest(name, imageSpec string, opts *options.ManifestAddOpts) error {
runtime := engine.ImageRuntime()
store := engine.ImageStore()
systemCxt := engine.SystemContext()
// AddToManifest :
//for `manifestName`: if it is not exist,will create a new one. if not, it must be an existed manifest name.
//for `imageNameOrIDList`:
//if element is a single image just add it,
//if element is a manifest will add it’s s all instance no matter what platform it is.
func (engine *Engine) AddToManifest(manifestName string, imageNameOrIDList []string, opts *options.ManifestAddOpts) error {
var (
runtime = engine.ImageRuntime()
)

// check whether manifestName is already existed.
manifestList, err := runtime.LookupManifestList(manifestName)
if err == nil {
return engine.addToManifestList(manifestList, imageNameOrIDList, opts)
}

manifestList, err := runtime.LookupManifestList(name)
if !errors.Is(err, storage.ErrImageUnknown) {
return err
}

logrus.Infof("will create a new one manifest with name %s", manifestName)
// if not exit,create a new one
_, err = engine.CreateManifest(manifestName, &options.ManifestCreateOpts{})
if err != nil {
return fmt.Errorf("failed to create a new one manifest with name %s :%v", manifestName, err)
}
manifestList, err = runtime.LookupManifestList(manifestName)
if err != nil {
return err
}

err = engine.addToManifestList(manifestList, imageNameOrIDList, opts)
if err != nil {
delErr := engine.DeleteManifests([]string{manifestName}, &options.ManifestDeleteOpts{})
if delErr != nil {
return fmt.Errorf("failed to delete %s : %v", manifestName, delErr)
}
return err
}

return nil
}

func (engine *Engine) addToManifestList(manifestList *libimage.ManifestList, imageNameOrIDList []string, opts *options.ManifestAddOpts) error {
var (
imageIDToAdd []string
err error
store = engine.ImageStore()
)

// determine all images
for _, imageNameOrID := range imageNameOrIDList {
ret, err := engine.getImageID(imageNameOrID)
if err != nil {
return fmt.Errorf("failed to look up %s", imageNameOrID)
}

imageIDToAdd = append(imageIDToAdd, ret...)
}

_, list, err := manifests.LoadFromImage(store, manifestList.ID())
if err != nil {
return err
}

// add each to manifest list
for _, imageID := range imageIDToAdd {
err = engine.addOneToManifestList(list, imageID, opts)
if err != nil {
return fmt.Errorf("failed to add new image %s to manifest :%v ", imageID, err)
}
}

_, err = list.SaveToImage(store, manifestList.ID(), nil, "")

return err
}

func (engine *Engine) addOneToManifestList(list manifests.List, imageSpec string, opts *options.ManifestAddOpts) error {
store := engine.ImageStore()
systemCxt := engine.SystemContext()

ref, err := alltransports.ParseImageName(imageSpec)
if err != nil {
if ref, err = alltransports.ParseImageName(util.DefaultTransport + imageSpec); err != nil {
Expand Down Expand Up @@ -238,9 +309,61 @@ func (engine *Engine) AddToManifest(name, imageSpec string, opts *options.Manife
}
}

_, err = list.SaveToImage(store, manifestList.ID(), nil, "")
logrus.Infof("adding image %s successfully", imageSpec)

return err
return nil
}

//getImageId get imageID by name Or id,what ever it is an image or a manifest
// if it is image just return imageID
// if it is a manifest, return its included instance IDs.
func (engine *Engine) getImageID(imageNameOrID string) ([]string, error) {
// try to look up `imageNameOrID` as ManifestList
store := engine.ImageStore()
img, _, err := engine.ImageRuntime().LookupImage(imageNameOrID, &libimage.LookupImageOptions{
ManifestList: true,
})
if err != nil {
return nil, err
}

isManifest, err := img.IsManifestList(getContext())
if err != nil {
return nil, err
}

// if not manifest, just return its ID.
if !isManifest {
return []string{img.ID()}, nil
}

// if it is a manifest, return its included instance ID.
logrus.Infof("image %q is a manifest list, looking up matching instances", imageNameOrID)

imageName := img.Names()[0]
manifestList, err := engine.ImageRuntime().LookupManifestList(imageName)
if err != nil {
return nil, err
}

_, list, err := manifests.LoadFromImage(store, manifestList.ID())
if err != nil {
return nil, err
}

var imageIDList []string
for _, instanceDigest := range list.Instances() {
images, err := store.ImagesByDigest(instanceDigest)
if err != nil {
return nil, err
}
if len(images) == 0 {
return nil, fmt.Errorf("no image matched with digest %s", instanceDigest)
}
imageIDList = append(imageIDList, images[0].ID)
}

return imageIDList, nil
}

func (engine *Engine) RemoveFromManifest(name string, instanceDigest digest.Digest, opts *options.ManifestRemoveOpts) error {
Expand Down
19 changes: 11 additions & 8 deletions pkg/imageengine/buildah/save.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,20 +22,21 @@ import (
"path/filepath"

"github.com/containers/common/libimage"
"github.com/containers/common/libimage/manifests"
"github.com/pkg/errors"
"github.com/sirupsen/logrus"

"github.com/sealerio/sealer/common"
"github.com/sealerio/sealer/pkg/define/options"
"github.com/sealerio/sealer/utils/archive"
osi "github.com/sealerio/sealer/utils/os"
"github.com/sealerio/sealer/utils/os/fs"
"github.com/sirupsen/logrus"
)

// Save image as tar file, if image is multi-arch image, will save all its instances and manifest name as tar file.
func (engine *Engine) Save(opts *options.SaveOptions) error {
imageNameOrID := opts.ImageNameOrID
imageTar := opts.Output
store := engine.ImageStore()

if len(imageNameOrID) == 0 {
return errors.New("image name or id must be specified")
Expand Down Expand Up @@ -98,23 +99,25 @@ func (engine *Engine) Save(opts *options.SaveOptions) error {
return err
}

schema2List, err := manifestList.Inspect()
_, list, err := manifests.LoadFromImage(store, manifestList.ID())
if err != nil {
return err
}

for _, m := range schema2List.Manifests {
instance, err := manifestList.LookupInstance(engine.Context(), m.Platform.Architecture, m.Platform.OS, m.Platform.Variant)
for _, instanceDigest := range list.Instances() {
images, err := store.ImagesByDigest(instanceDigest)
if err != nil {
return err
}
if len(images) == 0 {
return fmt.Errorf("no image matched with digest %s", instanceDigest)
}

instanceTar := filepath.Join(tempDir, instance.ID()+".tar")
err = engine.saveOneImage(instance.ID(), opts.Format, instanceTar, opts.Compress)
instanceTar := filepath.Join(tempDir, images[0].ID+".tar")
err = engine.saveOneImage(images[0].ID, opts.Format, instanceTar, opts.Compress)
if err != nil {
return err
}

pathsToCompress = append(pathsToCompress, instanceTar)
}

Expand Down
2 changes: 1 addition & 1 deletion pkg/imageengine/interface.go
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,7 @@ type Interface interface {

PushManifest(name, destSpec string, opts *options.PushOptions) error

AddToManifest(name, imageSpec string, opts *options.ManifestAddOpts) error
AddToManifest(name string, imageNameOrIDList []string, opts *options.ManifestAddOpts) error

RemoveFromManifest(name string, instanceDigest digest.Digest, opts *options.ManifestRemoveOpts) error
}

0 comments on commit 615bb15

Please sign in to comment.