debian-forge-composer/internal/worker/client.go
Tom Gundersen 0417c6d8bb distro: make the osbuild package internal to the distros
Rather than Manifest() returning an osbuild.Manifest object, introduce a
new distro.Manifest object which represents it as an opaque, JSON
serializable object. This new type has the following properties:

1) its serialization is compatible with the input to osbuild,
2) any valid osbuild input can be deserialized into it, and
3) marshalling and unmarshaling to and from JSON is lossless.

This means that even as we change the subset of valid osbulid manifests
that we support, we can still load any previous state from disk, and it
will continue to work just as before, even though we can no longer
deserialize it into our internal notion of osbuild.Manifest.

This fixes the underlying problem of which #685 was a symptom.

Signed-off-by: Tom Gundersen <teg@jklm.no>
2020-06-03 00:30:01 +02:00

130 lines
2.8 KiB
Go

package worker
import (
"bytes"
"context"
"crypto/tls"
"encoding/json"
"errors"
"fmt"
"io"
"net"
"net/http"
"github.com/google/uuid"
"github.com/osbuild/osbuild-composer/internal/common"
"github.com/osbuild/osbuild-composer/internal/distro"
"github.com/osbuild/osbuild-composer/internal/target"
)
type Client struct {
client *http.Client
scheme string
hostname string
}
type Job struct {
Id uuid.UUID
Manifest distro.Manifest
Targets []*target.Target
}
func NewClient(address string, conf *tls.Config) *Client {
client := &http.Client{
Transport: &http.Transport{
TLSClientConfig: conf,
},
}
var scheme string
// Use https if the TLS configuration is present, otherwise use http.
if conf != nil {
scheme = "https"
} else {
scheme = "http"
}
return &Client{client, scheme, address}
}
func NewClientUnix(path string) *Client {
client := &http.Client{
Transport: &http.Transport{
DialContext: func(context context.Context, network, addr string) (net.Conn, error) {
return net.Dial("unix", path)
},
},
}
return &Client{client, "http", "localhost"}
}
func (c *Client) AddJob() (*Job, error) {
var b bytes.Buffer
err := json.NewEncoder(&b).Encode(addJobRequest{})
if err != nil {
panic(err)
}
response, err := c.client.Post(c.createURL("/job-queue/v1/jobs"), "application/json", &b)
if err != nil {
return nil, err
}
defer response.Body.Close()
if response.StatusCode != http.StatusCreated {
var er errorResponse
_ = json.NewDecoder(response.Body).Decode(&er)
return nil, fmt.Errorf("couldn't create job, got %d: %s", response.StatusCode, er.Message)
}
var jr addJobResponse
err = json.NewDecoder(response.Body).Decode(&jr)
if err != nil {
return nil, err
}
return &Job{
jr.Id,
jr.Manifest,
jr.Targets,
}, nil
}
func (c *Client) UpdateJob(job *Job, status common.ImageBuildState, result *common.ComposeResult) error {
var b bytes.Buffer
err := json.NewEncoder(&b).Encode(&updateJobRequest{status, result})
if err != nil {
panic(err)
}
urlPath := fmt.Sprintf("/job-queue/v1/jobs/%s", job.Id)
url := c.createURL(urlPath)
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 *Client) UploadImage(job uuid.UUID, name string, reader io.Reader) error {
url := c.createURL(fmt.Sprintf("/job-queue/v1/jobs/%s/artifacts/%s", job, name))
_, err := c.client.Post(url, "application/octet-stream", reader)
return err
}
func (c *Client) createURL(path string) string {
return c.scheme + "://" + c.hostname + path
}