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

fix mount and umount bug #2029

Merged
merged 1 commit into from
Mar 7, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
195 changes: 131 additions & 64 deletions cmd/sealer/cmd/alpha/mount.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,31 +16,44 @@ package alpha

import (
"fmt"
"os"
"path/filepath"
"strings"
"time"

"github.com/containers/buildah"
"github.com/containers/storage"
"github.com/olekukonko/tablewriter"
"github.com/sirupsen/logrus"
"github.com/spf13/cobra"

"github.com/sealerio/sealer/common"
"github.com/sealerio/sealer/pkg/define/options"
"github.com/sealerio/sealer/pkg/imageengine/buildah"
imagebuildah "github.com/sealerio/sealer/pkg/imageengine/buildah"
utilsstrings "github.com/sealerio/sealer/utils/strings"
)

var longMountCmdDescription = `
mount the cluster image to '/var/lib/sealer/data/overlay2' the directory and check whether the contents of the build image and rootfs are consistent in advance
mount the cluster image to '/var/lib/containers/storage/overlay' the directory and check whether the contents of the build image and rootfs are consistent in advance
`

var exampleForMountCmd = `
sealer alpha mount(show mount list)
sealer alpha mount my-image
sealer alpha mount ba15e47f5969
sealer alpha mount imageID
`

const (
tableHeaderMountPath = "MOUNT PATH"
tableHeaderContainerID = "CONTAINER ID"
)

type MountService struct {
table *tablewriter.Table
engine *imagebuildah.Engine
store storage.Store
images []storage.Image
containers []storage.Container
builders []*buildah.Builder
}

func NewMountCmd() *cobra.Command {
mountCmd := &cobra.Command{
Use: "mount",
Expand All @@ -49,88 +62,142 @@ func NewMountCmd() *cobra.Command {
Example: exampleForMountCmd,
Args: cobra.MaximumNArgs(1),
RunE: func(cmd *cobra.Command, args []string) error {
var (
path string
imageID string
)

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

store := engine.ImageStore()
images, err := store.Images()
mountInfo, err := NewMountService()
if err != nil {
return err
}

//output mount list
if len(args) == 0 {
if err := mountList(images); err != nil {
if err := mountInfo.Show(); err != nil {
return err
}
return nil
}

for _, i := range images {
for _, name := range i.Names {
if name == args[0] || strings.Contains(i.ID, args[0]) {
imageID = i.ID
path = filepath.Join(common.DefaultLayerDir, imageID)
}
}
}

cid, err := engine.CreateContainer(&options.FromOptions{
Image: args[0],
Quiet: false,
})
_, err = mountInfo.Mount(args[0])
if err != nil {
return err
}
return nil
},
}
return mountCmd
}

//too fast to mount.
time.Sleep(time.Second * 1)
func NewMountService() (MountService, error) {
engine, err := imagebuildah.NewBuildahImageEngine(options.EngineGlobalConfigurations{})
if err != nil {
return MountService{}, err
}
store := engine.ImageStore()
containers, err := store.Containers()
if err != nil {
return MountService{}, err
}
images, err := store.Images()
if err != nil {
return MountService{}, err
}

mounts, err := engine.Mount(&options.MountOptions{Containers: []string{cid}})
if err != nil {
return err
}
builders, err := buildah.OpenAllBuilders(store)
if err != nil {
return MountService{}, err
}

// remove destination dir if it exists, otherwise the Symlink will fail.
if _, err = os.Stat(path); err == nil {
return fmt.Errorf("destination directionay %s exists, you should remove it first", path)
}
table := tablewriter.NewWriter(common.StdOut)
table.SetHeader([]string{tableHeaderContainerID, tableHeaderMountPath})

return MountService{
table: table,
engine: engine,
store: store,
images: images,
containers: containers,
builders: builders,
}, nil
}

mountPoint := mounts[0].MountPoint
if err := os.Symlink(mountPoint, path); err != nil {
return err
func (m MountService) Show() error {
clients, err := buildah.OpenAllBuilders(m.store)
if err != nil {
return fmt.Errorf("reading build Containers: %w", err)
}
for _, client := range clients {
mounted, err := client.Mounted()
if err != nil {
return err
}
for _, container := range m.containers {
if client.ContainerID == container.ID && mounted {
containerID := imagebuildah.TruncateID(client.ContainerID, true)
m.table.Append([]string{containerID, client.MountPoint})
}
}
}
m.table.Render()
return nil
}

logrus.Infof("mount cluster image %s to %s successful", args[0], path)
return nil
},
func (m MountService) getMountedImageID(container storage.Container) string {
var imageID string
for _, image := range m.images {
if container.ImageID == image.ID {
imageID = image.ID
}
}
return mountCmd
return imageID
}

func mountList(images []storage.Image) error {
table := tablewriter.NewWriter(common.StdOut)
table.SetHeader([]string{imageName, "mountpath"})
for _, i := range images {
for _, name := range i.Names {
err := filepath.Walk(common.DefaultLayerDir, func(path string, f os.FileInfo, err error) error {
if f.Name() == i.ID {
table.Append([]string{name, filepath.Join(common.DefaultLayerDir, i.ID)})
}
return nil
})
if err != nil {
return err
func (m MountService) getImageID(name string) string {
for _, image := range m.images {
if strings.HasPrefix(image.ID, name) {
return image.ID
}
for _, n := range image.Names {
if name == n {
return image.ID
}
}
}
table.Render()
return nil
return ""
}

func (m MountService) Mount(imageNameOrID string) (string, error) {
var imageIDList []string

for _, builder := range m.builders {
mounted, err := builder.Mounted()
if err != nil {
return "", err
}
for _, container := range m.containers {
if builder.ContainerID == container.ID && mounted {
imageID := m.getMountedImageID(container)
imageIDList = append(imageIDList, imageID)
}
}
}

imageID := m.getImageID(imageNameOrID)
ok := utilsstrings.IsInSlice(imageID, imageIDList)
if ok {
logrus.Warnf("this image has already been mounted, please do not repeat the operation")
return "", nil
}
cid, err := m.engine.CreateContainer(&options.FromOptions{
Image: imageID,
Quiet: false,
})
if err != nil {
return "", err
}
mounts, err := m.engine.Mount(&options.MountOptions{Containers: []string{cid}})
if err != nil {
return "", err
}
mountPoint := mounts[0].MountPoint
logrus.Infof("mount cluster image %s to %s successful", imageNameOrID, mountPoint)

return mountPoint, nil
}
Loading