targets/local: drop Location field

When support for osbuild result was added into osbuild-composer it was in
a bit hacky way - localtarget's location was reused as a path for the
result. This didn't make much sense because we want to store the result
even when image build has no localtarget.

Several past commits made store less dependant on the localtarget. The
responsibility for "holding the paths" to build artifacts was gradually
switched from the localtarget to the store while still maintaining
backwards compatibility - localtarget.Location still pointed at the
correct location.

This commit finishes the switch: local target now has no Location field.
The store is now fully responsible for managing the artifacts and paths
to them. LocalTarget is now just a simple "switch" - if image build has it,
then worker uploads an image into the store and it's then available for
download using the weldr API.
This commit is contained in:
Ondřej Budai 2020-02-13 11:19:06 +01:00 committed by Tom Gundersen
parent 6902f730cb
commit 55d3854033
5 changed files with 50 additions and 42 deletions

View file

@ -71,14 +71,14 @@ func (ib *ImageBuild) DeepCopy() ImageBuild {
} }
} }
func (ib *ImageBuild) GetLocalTarget() *target.LocalTargetOptions { func (ib *ImageBuild) HasLocalTarget() bool {
for _, t := range ib.Targets { for _, t := range ib.Targets {
if localTarget, ok := t.Options.(*target.LocalTargetOptions); ok { if _, ok := t.Options.(*target.LocalTargetOptions); ok {
return localTarget return true
} }
} }
return nil return false
} }
// A Compose represent the task of building a set of images from a single blueprint. // A Compose represent the task of building a set of images from a single blueprint.

View file

@ -75,9 +75,7 @@ func createBaseStoreFixture() *store.Store {
ImageName: "localimage", ImageName: "localimage",
Created: date, Created: date,
Status: common.IBWaiting, Status: common.IBWaiting,
Options: &target.LocalTargetOptions{ Options: &target.LocalTargetOptions{},
Location: "/tmp/localimage",
},
} }
var awsTarget = &target.Target{ var awsTarget = &target.Target{

View file

@ -461,6 +461,42 @@ func (s *Store) GetImageBuildResult(composeId uuid.UUID, imageBuildId int) (io.R
return os.Open(s.getImageBuildDirectory(composeId, imageBuildId) + "/result.json") return os.Open(s.getImageBuildDirectory(composeId, imageBuildId) + "/result.json")
} }
func (s *Store) GetImageBuildImage(composeId uuid.UUID, imageBuildId int) (io.ReadCloser, int64, error) {
c, ok := s.Composes[composeId]
if !ok {
return nil, 0, &NotFoundError{"compose does not exist"}
}
imageBuild := c.ImageBuilds[imageBuildId]
if !imageBuild.HasLocalTarget() {
return nil, 0, &NoLocalTargetError{"compose does not have local target"}
}
compatString, _ := imageBuild.ImageType.ToCompatString()
filename, _, err := s.distro.FilenameFromType(compatString)
if err != nil {
panic(err)
}
path := fmt.Sprintf("%s/%s", s.getImageBuildDirectory(composeId, imageBuildId), filename)
f, err := os.Open(path)
if err != nil {
return nil, 0, err
}
fileInfo, err := f.Stat()
if err != nil {
return nil, 0, err
}
return f, fileInfo.Size(), err
}
func (s *Store) getComposeDirectory(composeID uuid.UUID) string { func (s *Store) getComposeDirectory(composeID uuid.UUID) string {
return fmt.Sprintf("%s/outputs/%s", *s.stateDir, composeID.String()) return fmt.Sprintf("%s/outputs/%s", *s.stateDir, composeID.String())
} }
@ -487,9 +523,7 @@ func (s *Store) PushCompose(composeID uuid.UUID, bp *blueprint.Blueprint, checks
} }
targets = append(targets, target.NewLocalTarget( targets = append(targets, target.NewLocalTarget(
&target.LocalTargetOptions{ &target.LocalTargetOptions{},
Location: outputDir,
},
)) ))
} }
@ -749,9 +783,7 @@ func (s *Store) AddImageToImageUpload(composeID uuid.UUID, imageBuildID int, rea
} }
imageBuild := currentCompose.ImageBuilds[imageBuildID] imageBuild := currentCompose.ImageBuilds[imageBuildID]
localTarget := imageBuild.GetLocalTarget() if !imageBuild.HasLocalTarget() {
if localTarget == nil {
return &NoLocalTargetError{fmt.Sprintf("image upload requested for compse %s and image build %d but it has no local target", composeID.String(), imageBuildID)} return &NoLocalTargetError{fmt.Sprintf("image upload requested for compse %s and image build %d but it has no local target", composeID.String(), imageBuildID)}
} }
@ -762,8 +794,8 @@ func (s *Store) AddImageToImageUpload(composeID uuid.UUID, imageBuildID int, rea
return &InvalidRequestError{err.Error()} return &InvalidRequestError{err.Error()}
} }
path := fmt.Sprintf("%s/%s", localTarget.Location, filename) path := fmt.Sprintf("%s/%s", s.getImageBuildDirectory(composeID, imageBuildID), filename)
f, err := os.OpenFile(path, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0600) f, err := os.Create(path)
if err != nil { if err != nil {
return err return err

View file

@ -1,7 +1,6 @@
package target package target
type LocalTargetOptions struct { type LocalTargetOptions struct {
Location string `json:"location"`
} }
func (LocalTargetOptions) isTargetOptions() {} func (LocalTargetOptions) isTargetOptions() {}

View file

@ -11,7 +11,6 @@ import (
"net" "net"
"net/http" "net/http"
"net/url" "net/url"
"os"
"sort" "sort"
"strconv" "strconv"
"strings" "strings"
@ -1566,17 +1565,6 @@ func (api *API) composeImageHandler(writer http.ResponseWriter, request *http.Re
} }
imageBuild := compose.ImageBuilds[0] imageBuild := compose.ImageBuilds[0]
localTarget := imageBuild.GetLocalTarget()
if localTarget == nil {
errors := responseError{
ID: "BadCompose",
Msg: fmt.Sprintf("Compose %s is ill-formed: it doesn't contain LocalTarget", uuidString),
}
statusResponseError(writer, http.StatusInternalServerError, errors)
return
}
imageType, _ := imageBuild.ImageType.ToCompatString() imageType, _ := imageBuild.ImageType.ToCompatString()
imageName, imageMime, err := api.distro.FilenameFromType(imageType) imageName, imageMime, err := api.distro.FilenameFromType(imageType)
@ -1589,7 +1577,9 @@ func (api *API) composeImageHandler(writer http.ResponseWriter, request *http.Re
return return
} }
file, err := os.Open(localTarget.Location + "/" + imageName) reader, fileSize, err := api.store.GetImageBuildImage(uuid, 0)
// TODO: this might return misleading error
if err != nil { if err != nil {
errors := responseError{ errors := responseError{
ID: "BuildMissingFile", ID: "BuildMissingFile",
@ -1599,22 +1589,11 @@ func (api *API) composeImageHandler(writer http.ResponseWriter, request *http.Re
return return
} }
stat, err := file.Stat()
if err != nil {
errors := responseError{
ID: "BuildStatFailed",
Msg: fmt.Sprintf("Cannot stat image for build %s!", uuidString),
}
statusResponseError(writer, http.StatusBadRequest, errors)
return
}
writer.Header().Set("Content-Disposition", "attachment; filename="+uuid.String()+"-"+imageName) writer.Header().Set("Content-Disposition", "attachment; filename="+uuid.String()+"-"+imageName)
writer.Header().Set("Content-Type", imageMime) writer.Header().Set("Content-Type", imageMime)
writer.Header().Set("Content-Length", fmt.Sprintf("%d", stat.Size())) writer.Header().Set("Content-Length", fmt.Sprintf("%d", fileSize))
io.Copy(writer, file) io.Copy(writer, reader)
} }
func (api *API) composeLogsHandler(writer http.ResponseWriter, request *http.Request, params httprouter.Params) { func (api *API) composeLogsHandler(writer http.ResponseWriter, request *http.Request, params httprouter.Params) {