Prior this commit local target copied the image from a worker to a composer using cp(1) command. This prevented the local target to work on remote workers. This commit switches the local target implementation to using the jobqueue API introduced in the previous commit. I had some concerns about speed of this solution (imho nothing can beat pure cp(1) implementation) but ad hoc sanity tests showed the copying of the image using the jobqueue API when running the worker on the same machine as the composer is still more or less instant.
118 lines
2.7 KiB
Go
118 lines
2.7 KiB
Go
package main
|
|
|
|
import (
|
|
"bytes"
|
|
"context"
|
|
"encoding/json"
|
|
"errors"
|
|
"fmt"
|
|
"io"
|
|
"log"
|
|
"net"
|
|
"net/http"
|
|
|
|
"github.com/osbuild/osbuild-composer/internal/common"
|
|
"github.com/osbuild/osbuild-composer/internal/jobqueue"
|
|
)
|
|
|
|
type ComposerClient struct {
|
|
client *http.Client
|
|
}
|
|
|
|
func NewClient() *ComposerClient {
|
|
client := &http.Client{
|
|
Transport: &http.Transport{
|
|
DialContext: func(context context.Context, network, addr string) (net.Conn, error) {
|
|
return net.Dial("unix", "/run/osbuild-composer/job.socket")
|
|
},
|
|
},
|
|
}
|
|
return &ComposerClient{client}
|
|
}
|
|
|
|
func (c *ComposerClient) AddJob() (*jobqueue.Job, error) {
|
|
type request struct {
|
|
}
|
|
|
|
var b bytes.Buffer
|
|
json.NewEncoder(&b).Encode(request{})
|
|
response, err := c.client.Post("http://localhost/job-queue/v1/jobs", "application/json", &b)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
defer response.Body.Close()
|
|
|
|
if response.StatusCode != http.StatusCreated {
|
|
return nil, errors.New("couldn't create job")
|
|
}
|
|
|
|
job := &jobqueue.Job{}
|
|
err = json.NewDecoder(response.Body).Decode(job)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
return job, nil
|
|
}
|
|
|
|
func (c *ComposerClient) UpdateJob(job *jobqueue.Job, status common.ImageBuildState, result *common.ComposeResult) error {
|
|
var b bytes.Buffer
|
|
json.NewEncoder(&b).Encode(&jobqueue.JobStatus{status, result})
|
|
url := fmt.Sprintf("http://localhost/job-queue/v1/jobs/%s/builds/%d", job.ID.String(), job.ImageBuildID)
|
|
req, err := http.NewRequest("PATCH", url, &b)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
req.Header.Set("Content-Type", "application/json")
|
|
response, err := c.client.Do(req)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
defer response.Body.Close()
|
|
|
|
if response.StatusCode != http.StatusOK {
|
|
return errors.New("error setting job status")
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
func (c *ComposerClient) UploadImage(job *jobqueue.Job, reader io.Reader) error {
|
|
// content type doesn't really matter
|
|
url := fmt.Sprintf("http://localhost/job-queue/v1/jobs/%s/builds/%d/image", job.ID.String(), job.ImageBuildID)
|
|
_, err := c.client.Post(url, "application/octet-stream", reader)
|
|
|
|
return err
|
|
}
|
|
|
|
func handleJob(client *ComposerClient) error {
|
|
fmt.Println("Waiting for a new job...")
|
|
job, err := client.AddJob()
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
err = client.UpdateJob(job, common.IBRunning, nil)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
fmt.Printf("Running job %s\n", job.ID.String())
|
|
result, err := job.Run(client)
|
|
if err != nil {
|
|
log.Printf(" Job failed: %v", err)
|
|
return client.UpdateJob(job, common.IBFailed, result)
|
|
}
|
|
|
|
return client.UpdateJob(job, common.IBFinished, result)
|
|
}
|
|
|
|
func main() {
|
|
client := NewClient()
|
|
for {
|
|
if err := handleJob(client); err != nil {
|
|
log.Fatalf("Failed to handle job: " + err.Error())
|
|
}
|
|
}
|
|
}
|