api: implement /compose/logs route
The implementation is just a stub returning always the same tar archive. The ability to return actual logs will be implemented in the future - osbuild isn't currently returning any logs.
This commit is contained in:
parent
d7f81b36e6
commit
4e62f181fa
2 changed files with 124 additions and 0 deletions
|
|
@ -1,6 +1,7 @@
|
||||||
package weldr
|
package weldr
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"archive/tar"
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
|
@ -92,6 +93,7 @@ func New(rpmmd rpmmd.RPMMD, distro distro.Distro, logger *log.Logger, store *sto
|
||||||
api.router.GET("/api/v:version/compose/finished", api.composeFinishedHandler)
|
api.router.GET("/api/v:version/compose/finished", api.composeFinishedHandler)
|
||||||
api.router.GET("/api/v:version/compose/failed", api.composeFailedHandler)
|
api.router.GET("/api/v:version/compose/failed", api.composeFailedHandler)
|
||||||
api.router.GET("/api/v:version/compose/image/:uuid", api.composeImageHandler)
|
api.router.GET("/api/v:version/compose/image/:uuid", api.composeImageHandler)
|
||||||
|
api.router.GET("/api/v:version/compose/logs/:uuid", api.composeLogsHandler)
|
||||||
api.router.POST("/api/v:version/compose/uploads/schedule/:uuid", api.uploadsScheduleHandler)
|
api.router.POST("/api/v:version/compose/uploads/schedule/:uuid", api.uploadsScheduleHandler)
|
||||||
|
|
||||||
api.router.DELETE("/api/v:version/upload/delete/:uuid", api.uploadsDeleteHandler)
|
api.router.DELETE("/api/v:version/upload/delete/:uuid", api.uploadsDeleteHandler)
|
||||||
|
|
@ -1463,6 +1465,59 @@ func (api *API) composeImageHandler(writer http.ResponseWriter, request *http.Re
|
||||||
io.Copy(writer, file)
|
io.Copy(writer, file)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (api *API) composeLogsHandler(writer http.ResponseWriter, request *http.Request, params httprouter.Params) {
|
||||||
|
if !verifyRequestVersion(writer, params, 0) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
uuidString := params.ByName("uuid")
|
||||||
|
id, err := uuid.Parse(uuidString)
|
||||||
|
if err != nil {
|
||||||
|
errors := responseError{
|
||||||
|
ID: "UnknownUUID",
|
||||||
|
Msg: fmt.Sprintf("%s is not a valid build uuid", uuidString),
|
||||||
|
}
|
||||||
|
statusResponseError(writer, http.StatusBadRequest, errors)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
compose, exists := api.store.GetCompose(id)
|
||||||
|
if !exists {
|
||||||
|
errors := responseError{
|
||||||
|
ID: "UnknownUUID",
|
||||||
|
Msg: fmt.Sprintf("Compose %s doesn't exist", uuidString),
|
||||||
|
}
|
||||||
|
statusResponseError(writer, http.StatusBadRequest, errors)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if compose.QueueStatus != "FINISHED" && compose.QueueStatus != "FAILED" {
|
||||||
|
errors := responseError{
|
||||||
|
ID: "BuildInWrongState",
|
||||||
|
Msg: fmt.Sprintf("Build %s not in FINISHED or FAILED state.", uuidString),
|
||||||
|
}
|
||||||
|
statusResponseError(writer, http.StatusBadRequest, errors)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
writer.Header().Set("Content-Disposition", "attachment; filename="+id.String()+"-logs.tar")
|
||||||
|
writer.Header().Set("Content-Type", "application/x-tar")
|
||||||
|
|
||||||
|
tw := tar.NewWriter(writer)
|
||||||
|
|
||||||
|
// TODO: return real log from osbuild
|
||||||
|
fileContents := []byte("SUCCESS\n")
|
||||||
|
|
||||||
|
header := &tar.Header{
|
||||||
|
Name: "logs/osbuild.log",
|
||||||
|
Mode: 0644,
|
||||||
|
Size: int64(len(fileContents)),
|
||||||
|
}
|
||||||
|
|
||||||
|
tw.WriteHeader(header)
|
||||||
|
tw.Write(fileContents)
|
||||||
|
}
|
||||||
|
|
||||||
func (api *API) composeFinishedHandler(writer http.ResponseWriter, request *http.Request, params httprouter.Params) {
|
func (api *API) composeFinishedHandler(writer http.ResponseWriter, request *http.Request, params httprouter.Params) {
|
||||||
if !verifyRequestVersion(writer, params, 0) {
|
if !verifyRequestVersion(writer, params, 0) {
|
||||||
return
|
return
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,9 @@
|
||||||
package weldr_test
|
package weldr_test
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"archive/tar"
|
||||||
"bytes"
|
"bytes"
|
||||||
|
"io"
|
||||||
"math/rand"
|
"math/rand"
|
||||||
"net/http"
|
"net/http"
|
||||||
"net/http/httptest"
|
"net/http/httptest"
|
||||||
|
|
@ -389,6 +391,73 @@ func TestComposeInfo(t *testing.T) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestComposeLogs(t *testing.T) {
|
||||||
|
if len(os.Getenv("OSBUILD_COMPOSER_TEST_EXTERNAL")) > 0 {
|
||||||
|
t.Skip("This test is for internal testing only")
|
||||||
|
}
|
||||||
|
|
||||||
|
var successCases = []struct {
|
||||||
|
Path string
|
||||||
|
ExpectedContentDisposition string
|
||||||
|
ExpectedContentType string
|
||||||
|
ExpectedFileName string
|
||||||
|
ExpectedFileContent string
|
||||||
|
}{
|
||||||
|
{"/api/v0/compose/logs/30000000-0000-0000-0000-000000000002", "attachment; filename=30000000-0000-0000-0000-000000000002-logs.tar", "application/x-tar", "logs/osbuild.log", "SUCCESS\n"},
|
||||||
|
{"/api/v1/compose/logs/30000000-0000-0000-0000-000000000002", "attachment; filename=30000000-0000-0000-0000-000000000002-logs.tar", "application/x-tar", "logs/osbuild.log", "SUCCESS\n"},
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, c := range successCases {
|
||||||
|
api, _ := createWeldrAPI(rpmmd_mock.BaseFixture)
|
||||||
|
|
||||||
|
response := test.SendHTTP(api, false, "GET", c.Path, "")
|
||||||
|
if response.Header.Get("content-disposition") != c.ExpectedContentDisposition {
|
||||||
|
t.Errorf("%s: expected content-disposition: %s, but got: %s", c.Path, c.ExpectedContentDisposition, response.Header.Get("content-disposition"))
|
||||||
|
}
|
||||||
|
|
||||||
|
if response.Header.Get("content-type") != c.ExpectedContentType {
|
||||||
|
t.Errorf("%s: expected content-type: %s, but got: %s", c.Path, c.ExpectedContentType, response.Header.Get("content-type"))
|
||||||
|
}
|
||||||
|
|
||||||
|
tr := tar.NewReader(response.Body)
|
||||||
|
h, err := tr.Next()
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
t.Errorf("untarring failed with error: %s", err.Error())
|
||||||
|
}
|
||||||
|
|
||||||
|
if h.Name != c.ExpectedFileName {
|
||||||
|
t.Errorf("%s: expected log content: %s, but got: %s", c.Path, c.ExpectedFileName, h.Name)
|
||||||
|
}
|
||||||
|
|
||||||
|
var buffer bytes.Buffer
|
||||||
|
|
||||||
|
io.Copy(&buffer, tr)
|
||||||
|
|
||||||
|
if buffer.String() != c.ExpectedFileContent {
|
||||||
|
t.Errorf("%s: expected log content: %s, but got: %s", c.Path, c.ExpectedFileContent, buffer.String())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var failureCases = []struct {
|
||||||
|
Path string
|
||||||
|
ExpectedJSON string
|
||||||
|
}{
|
||||||
|
{"/api/v1/compose/logs/30000000-0000-0000-0000", `{"status":false,"errors":[{"id":"UnknownUUID","msg":"30000000-0000-0000-0000 is not a valid build uuid"}]}`},
|
||||||
|
{"/api/v1/compose/logs/42000000-0000-0000-0000-000000000000", `{"status":false,"errors":[{"id":"UnknownUUID","msg":"Compose 42000000-0000-0000-0000-000000000000 doesn't exist"}]}`},
|
||||||
|
{"/api/v1/compose/logs/30000000-0000-0000-0000-000000000000", `{"status":false,"errors":[{"id":"BuildInWrongState","msg":"Build 30000000-0000-0000-0000-000000000000 not in FINISHED or FAILED state."}]}`},
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(os.Getenv("OSBUILD_COMPOSER_TEST_EXTERNAL")) > 0 {
|
||||||
|
t.Skip("This test is for internal testing only")
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, c := range failureCases {
|
||||||
|
api, _ := createWeldrAPI(rpmmd_mock.BaseFixture)
|
||||||
|
test.TestRoute(t, api, false, "GET", c.Path, "", http.StatusBadRequest, c.ExpectedJSON)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func TestComposeQueue(t *testing.T) {
|
func TestComposeQueue(t *testing.T) {
|
||||||
var cases = []struct {
|
var cases = []struct {
|
||||||
Fixture rpmmd_mock.FixtureGenerator
|
Fixture rpmmd_mock.FixtureGenerator
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue