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

lxd/image: Acquire image lock for uploaded images #14100

Merged
Merged
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
102 changes: 49 additions & 53 deletions lxd/images.go
Original file line number Diff line number Diff line change
Expand Up @@ -689,6 +689,8 @@ func getImgPostInfo(s *state.State, r *http.Request, builddir string, project st

sha256 := sha256.New()
var size int64
var imageTmpFilename string
var rootfsTmpFilename string

if ctype == "multipart/form-data" {
// Create a temporary file for the image tarball
Expand All @@ -699,6 +701,8 @@ func getImgPostInfo(s *state.State, r *http.Request, builddir string, project st

defer func() { _ = os.Remove(imageTarf.Name()) }()

imageTmpFilename = imageTarf.Name()

// Parse the POST data
_, err = post.Seek(0, io.SeekStart)
if err != nil {
Expand Down Expand Up @@ -750,6 +754,8 @@ func getImgPostInfo(s *state.State, r *http.Request, builddir string, project st

defer func() { _ = os.Remove(rootfsTarf.Name()) }()

rootfsTmpFilename = rootfsTarf.Name()

size, err = io.Copy(io.MultiWriter(rootfsTarf, sha256), part)
info.Size += size

Expand All @@ -760,39 +766,6 @@ func getImgPostInfo(s *state.State, r *http.Request, builddir string, project st
}

info.Filename = part.FileName()
info.Fingerprint = fmt.Sprintf("%x", sha256.Sum(nil))

expectedFingerprint := r.Header.Get("X-LXD-fingerprint")
if expectedFingerprint != "" && info.Fingerprint != expectedFingerprint {
err = fmt.Errorf("fingerprints don't match, got %s expected %s", info.Fingerprint, expectedFingerprint)
return nil, err
}

imageMeta, _, err = getImageMetadata(imageTarf.Name())
if err != nil {
l.Error("Failed to get image metadata", logger.Ctx{"err": err})
return nil, err
}

imgfname := shared.VarPath("images", info.Fingerprint)
err = shared.FileMove(imageTarf.Name(), imgfname)
if err != nil {
l.Error("Failed to move the image tarfile", logger.Ctx{
"err": err,
"source": imageTarf.Name(),
"dest": imgfname})
return nil, err
}

rootfsfname := shared.VarPath("images", info.Fingerprint+".rootfs")
err = shared.FileMove(rootfsTarf.Name(), rootfsfname)
if err != nil {
l.Error("Failed to move the rootfs tarfile", logger.Ctx{
"err": err,
"source": rootfsTarf.Name(),
"dest": imgfname})
return nil, err
}
} else {
_, err = post.Seek(0, io.SeekStart)
if err != nil {
Expand All @@ -808,32 +781,55 @@ func getImgPostInfo(s *state.State, r *http.Request, builddir string, project st
info.Size = size

info.Filename = r.Header.Get("X-LXD-filename")
info.Fingerprint = fmt.Sprintf("%x", sha256.Sum(nil))

expectedFingerprint := r.Header.Get("X-LXD-fingerprint")
if expectedFingerprint != "" && info.Fingerprint != expectedFingerprint {
l.Error("Fingerprints don't match", logger.Ctx{
"got": info.Fingerprint,
"expected": expectedFingerprint})
err = fmt.Errorf("fingerprints don't match, got %s expected %s", info.Fingerprint, expectedFingerprint)
return nil, err
}

var imageType string
imageMeta, imageType, err = getImageMetadata(post.Name())
if err != nil {
l.Error("Failed to get image metadata", logger.Ctx{"err": err})
return nil, err
}
imageTmpFilename = post.Name()
}

info.Fingerprint = fmt.Sprintf("%x", sha256.Sum(nil))

expectedFingerprint := r.Header.Get("X-LXD-fingerprint")
if expectedFingerprint != "" && info.Fingerprint != expectedFingerprint {
l.Error("Fingerprints don't match", logger.Ctx{
"got": info.Fingerprint,
"expected": expectedFingerprint})
err = fmt.Errorf("Fingerprints don't match, got %s expected %s", info.Fingerprint, expectedFingerprint)
return nil, err
}

unlock, err := imageOperationLock(info.Fingerprint)
if err != nil {
return nil, err
}

defer unlock()

imageMeta, imageType, err := getImageMetadata(imageTmpFilename)
if err != nil {
l.Error("Failed to get image metadata", logger.Ctx{"err": err})
return nil, err
}

if info.Type == "" {
info.Type = imageType
}

imgfname := shared.VarPath("images", info.Fingerprint)
err = shared.FileMove(post.Name(), imgfname)
imgfname := shared.VarPath("images", info.Fingerprint)
err = shared.FileMove(imageTmpFilename, imgfname)
if err != nil {
l.Error("Failed to move the image tarfile", logger.Ctx{
"err": err,
"source": imageTmpFilename,
"dest": imgfname})
return nil, err
}

if rootfsTmpFilename != "" {
rootfsfname := shared.VarPath("images", info.Fingerprint+".rootfs")
err = shared.FileMove(rootfsTmpFilename, rootfsfname)
if err != nil {
l.Error("Failed to move the tarfile", logger.Ctx{
l.Error("Failed to move the rootfs tarfile", logger.Ctx{
"err": err,
"source": post.Name(),
"source": rootfsTmpFilename,
"dest": imgfname})
return nil, err
}
Expand Down
Loading