api: implement /compose/delete route
This commit is contained in:
parent
6d15833e4e
commit
6bbc89d5f3
4 changed files with 136 additions and 4 deletions
|
|
@ -99,10 +99,13 @@ func (job *Job) Run(d distro.Distro) (*store.Image, error, []error) {
|
|||
for _, t := range job.Targets {
|
||||
switch options := t.Options.(type) {
|
||||
case *target.LocalTargetOptions:
|
||||
cp := exec.Command("cp", "-a", "-L", "/var/cache/osbuild-composer/store/refs/"+result.OutputID+"/.", options.Location)
|
||||
cp.Stderr = os.Stderr
|
||||
cp.Stdout = os.Stdout
|
||||
err = cp.Run()
|
||||
err = runCommand("cp", "-a", "-L", "/var/cache/osbuild-composer/store/refs/"+result.OutputID+"/.", options.Location)
|
||||
if err != nil {
|
||||
r = append(r, err)
|
||||
continue
|
||||
}
|
||||
|
||||
err = runCommand("chown", "-R", "_osbuild-composer:_osbuild-composer", options.Location)
|
||||
if err != nil {
|
||||
r = append(r, err)
|
||||
continue
|
||||
|
|
@ -158,3 +161,10 @@ func (job *Job) Run(d distro.Distro) (*store.Image, error, []error) {
|
|||
|
||||
return &image, nil, r
|
||||
}
|
||||
|
||||
func runCommand(command string, params ...string) error {
|
||||
cp := exec.Command(command, params...)
|
||||
cp.Stderr = os.Stderr
|
||||
cp.Stdout = os.Stdout
|
||||
return cp.Run()
|
||||
}
|
||||
|
|
|
|||
|
|
@ -454,6 +454,29 @@ func (s *Store) PushCompose(composeID uuid.UUID, bp *blueprint.Blueprint, compos
|
|||
return nil
|
||||
}
|
||||
|
||||
func (s *Store) DeleteCompose(id uuid.UUID) error {
|
||||
return s.change(func() error {
|
||||
compose, exists := s.Composes[id]
|
||||
|
||||
if !exists {
|
||||
return &NotFoundError{}
|
||||
}
|
||||
|
||||
if compose.QueueStatus != "FINISHED" && compose.QueueStatus != "FAILED" {
|
||||
return &InvalidRequestError{fmt.Sprintf("Compose %s is not in FINISHED or FAILED.", id)}
|
||||
}
|
||||
|
||||
delete(s.Composes, id)
|
||||
|
||||
var err error
|
||||
if s.stateDir != nil {
|
||||
err = os.RemoveAll(*s.stateDir + "/outputs/" + id.String())
|
||||
}
|
||||
|
||||
return err
|
||||
})
|
||||
}
|
||||
|
||||
func (s *Store) PopCompose() Job {
|
||||
job := <-s.pendingJobs
|
||||
s.change(func() error {
|
||||
|
|
|
|||
|
|
@ -86,6 +86,7 @@ func New(rpmmd rpmmd.RPMMD, distro distro.Distro, logger *log.Logger, store *sto
|
|||
api.router.DELETE("/api/v:version/blueprints/workspace/:blueprint", api.blueprintDeleteWorkspaceHandler)
|
||||
|
||||
api.router.POST("/api/v:version/compose", api.composeHandler)
|
||||
api.router.DELETE("/api/v:version/compose/delete/:uuids", api.composeDeleteHandler)
|
||||
api.router.GET("/api/v:version/compose/types", api.composeTypesHandler)
|
||||
api.router.GET("/api/v:version/compose/queue", api.composeQueueHandler)
|
||||
api.router.GET("/api/v:version/compose/status/:uuids", api.composeStatusHandler)
|
||||
|
|
@ -1267,6 +1268,68 @@ func (api *API) composeHandler(writer http.ResponseWriter, request *http.Request
|
|||
json.NewEncoder(writer).Encode(reply)
|
||||
}
|
||||
|
||||
func (api *API) composeDeleteHandler(writer http.ResponseWriter, request *http.Request, params httprouter.Params) {
|
||||
if !verifyRequestVersion(writer, params, 0) {
|
||||
return
|
||||
}
|
||||
|
||||
type composeDeleteStatus struct {
|
||||
UUID uuid.UUID `json:"uuid"`
|
||||
Status bool `json:"status"`
|
||||
}
|
||||
|
||||
type composeDeleteError struct {
|
||||
ID string `json:"id"`
|
||||
Msg string `json:"msg"`
|
||||
}
|
||||
|
||||
uuidsParam := params.ByName("uuids")
|
||||
|
||||
results := []composeDeleteStatus{}
|
||||
errors := []composeDeleteError{}
|
||||
uuidStrings := strings.Split(uuidsParam, ",")
|
||||
for _, uuidString := range uuidStrings {
|
||||
id, err := uuid.Parse(uuidString)
|
||||
if err != nil {
|
||||
errors = append(errors, composeDeleteError{
|
||||
"UnknownUUID",
|
||||
fmt.Sprintf("%s is not a valid uuid", uuidString),
|
||||
})
|
||||
}
|
||||
|
||||
err = api.store.DeleteCompose(id)
|
||||
|
||||
if err != nil {
|
||||
switch err.(type) {
|
||||
case *store.NotFoundError:
|
||||
errors = append(errors, composeDeleteError{
|
||||
"UnknownUUID",
|
||||
fmt.Sprintf("compose %s doesn't exist", id),
|
||||
})
|
||||
case *store.InvalidRequestError:
|
||||
errors = append(errors, composeDeleteError{
|
||||
"BuildInWrongState",
|
||||
err.Error(),
|
||||
})
|
||||
default:
|
||||
errors = append(errors, composeDeleteError{
|
||||
"ComposeError",
|
||||
fmt.Sprintf("%s: %s", id, err.Error()),
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
results = append(results, composeDeleteStatus{id, true})
|
||||
}
|
||||
|
||||
reply := struct {
|
||||
UUIDs []composeDeleteStatus `json:"uuids"`
|
||||
Errors []composeDeleteError `json:"errors"`
|
||||
}{results, errors}
|
||||
|
||||
json.NewEncoder(writer).Encode(reply)
|
||||
}
|
||||
|
||||
func (api *API) composeTypesHandler(writer http.ResponseWriter, request *http.Request, params httprouter.Params) {
|
||||
if !verifyRequestVersion(writer, params, 0) {
|
||||
return
|
||||
|
|
|
|||
|
|
@ -23,6 +23,7 @@ import (
|
|||
|
||||
"github.com/BurntSushi/toml"
|
||||
"github.com/google/go-cmp/cmp"
|
||||
"github.com/google/go-cmp/cmp/cmpopts"
|
||||
)
|
||||
|
||||
func createWeldrAPI(fixtureGenerator rpmmd_mock.FixtureGenerator) (*weldr.API, *store.Store) {
|
||||
|
|
@ -330,6 +331,41 @@ func TestCompose(t *testing.T) {
|
|||
}
|
||||
}
|
||||
|
||||
func TestComposeDelete(t *testing.T) {
|
||||
if len(os.Getenv("OSBUILD_COMPOSER_TEST_EXTERNAL")) > 0 {
|
||||
t.Skip("This test is for internal testing only")
|
||||
}
|
||||
|
||||
var cases = []struct {
|
||||
Path string
|
||||
ExpectedJSON string
|
||||
ExpectedIDsInStore []string
|
||||
}{
|
||||
{"/api/v0/compose/delete/30000000-0000-0000-0000-000000000002", `{"uuids":[{"uuid":"30000000-0000-0000-0000-000000000002","status":true}],"errors":[]}`, []string{"30000000-0000-0000-0000-000000000000", "30000000-0000-0000-0000-000000000001", "30000000-0000-0000-0000-000000000003"}},
|
||||
{"/api/v0/compose/delete/30000000-0000-0000-0000-000000000002,30000000-0000-0000-0000-000000000003", `{"uuids":[{"uuid":"30000000-0000-0000-0000-000000000002","status":true},{"uuid":"30000000-0000-0000-0000-000000000003","status":true}],"errors":[]}`, []string{"30000000-0000-0000-0000-000000000000", "30000000-0000-0000-0000-000000000001"}},
|
||||
{"/api/v0/compose/delete/30000000-0000-0000-0000-000000000003,30000000-0000-0000-0000-000000000000", `{"uuids":[{"uuid":"30000000-0000-0000-0000-000000000003","status":true},{"uuid":"30000000-0000-0000-0000-000000000000","status":true}],"errors":[{"id":"BuildInWrongState","msg":"Compose 30000000-0000-0000-0000-000000000000 is not in FINISHED or FAILED."}]}`, []string{"30000000-0000-0000-0000-000000000000", "30000000-0000-0000-0000-000000000001", "30000000-0000-0000-0000-000000000002"}},
|
||||
{"/api/v0/compose/delete/30000000-0000-0000-0000-000000000003,30000000-0000-0000-0000", `{"uuids":[{"uuid":"30000000-0000-0000-0000-000000000003","status":true},{"uuid":"00000000-0000-0000-0000-000000000000","status":true}],"errors":[{"id":"UnknownUUID","msg":"30000000-0000-0000-0000 is not a valid uuid"},{"id":"UnknownUUID","msg":"compose 00000000-0000-0000-0000-000000000000 doesn't exist"}]}`, []string{"30000000-0000-0000-0000-000000000000", "30000000-0000-0000-0000-000000000001", "30000000-0000-0000-0000-000000000002"}},
|
||||
{"/api/v0/compose/delete/30000000-0000-0000-0000-000000000003,42000000-0000-0000-0000-000000000000", `{"uuids":[{"uuid":"30000000-0000-0000-0000-000000000003","status":true},{"uuid":"42000000-0000-0000-0000-000000000000","status":true}],"errors":[{"id":"UnknownUUID","msg":"compose 42000000-0000-0000-0000-000000000000 doesn't exist"}]}`, []string{"30000000-0000-0000-0000-000000000000", "30000000-0000-0000-0000-000000000001", "30000000-0000-0000-0000-000000000002"}},
|
||||
}
|
||||
|
||||
for _, c := range cases {
|
||||
api, s := createWeldrAPI(rpmmd_mock.BaseFixture)
|
||||
test.TestRoute(t, api, false, "DELETE", c.Path, "", http.StatusOK, c.ExpectedJSON)
|
||||
|
||||
idsInStore := []string{}
|
||||
|
||||
for id, _ := range s.Composes {
|
||||
idsInStore = append(idsInStore, id.String())
|
||||
}
|
||||
|
||||
diff := cmp.Diff(idsInStore, c.ExpectedIDsInStore, cmpopts.SortSlices(func(a, b string) bool { return a < b }))
|
||||
|
||||
if diff != "" {
|
||||
t.Errorf("%s: composes in store are different, expected: %v, got: %v, diff:\n%s", c.Path, c.ExpectedIDsInStore, idsInStore, diff)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestComposeStatus(t *testing.T) {
|
||||
var cases = []struct {
|
||||
Fixture rpmmd_mock.FixtureGenerator
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue