many: remove jobsite code

This was replaced by `cmd/osbuild-worker-executor`.
This commit is contained in:
Sanne Raymaekers 2025-06-11 10:11:42 +02:00 committed by Tomáš Hozza
parent f6c1709d8d
commit 7dea1bcd01
6 changed files with 1 additions and 975 deletions

View file

@ -149,8 +149,6 @@ build: $(BUILDDIR)/bin/ build-maintenance
go build -o $<osbuild-upload-oci ./cmd/osbuild-upload-oci/ go build -o $<osbuild-upload-oci ./cmd/osbuild-upload-oci/
go build -o $<osbuild-upload-generic-s3 ./cmd/osbuild-upload-generic-s3/ go build -o $<osbuild-upload-generic-s3 ./cmd/osbuild-upload-generic-s3/
go build -o $<osbuild-mock-openid-provider ./cmd/osbuild-mock-openid-provider go build -o $<osbuild-mock-openid-provider ./cmd/osbuild-mock-openid-provider
go build -o $<osbuild-jobsite-manager ./cmd/osbuild-jobsite-manager
go build -o $<osbuild-jobsite-builder ./cmd/osbuild-jobsite-builder
# also build the test binaries # also build the test binaries
go test -c -tags=integration -o $<osbuild-composer-cli-tests ./cmd/osbuild-composer-cli-tests/main_test.go go test -c -tags=integration -o $<osbuild-composer-cli-tests ./cmd/osbuild-composer-cli-tests/main_test.go
go test -c -tags=integration -o $<osbuild-weldr-tests ./internal/client/ go test -c -tags=integration -o $<osbuild-weldr-tests ./internal/client/

View file

@ -10,10 +10,6 @@ osbuild-worker-executor: The binary that runs osbuild to build an image on an is
osbuild-koji: Submits builds to Koji. osbuild-koji: Submits builds to Koji.
osbuild-jobsite-*: Provides an isolated set of services to run builds in. They can be separated
from the rest of the system through network segmentation or other means. The jobsite and what's
in it are only available to things inside it.
Service binaries Service binaries
================ ================

View file

@ -1,479 +0,0 @@
package main
import (
"archive/tar"
"bufio"
"bytes"
"context"
"encoding/json"
"flag"
"fmt"
"io"
"log/slog"
"net/http"
"os"
"os/exec"
"path"
"path/filepath"
"strings"
"sync"
"time"
)
const (
ExitOk int = iota
ExitError
)
type State int
type Handler func(w http.ResponseWriter, r *http.Request) error
const (
StateClaim State = iota
StateProvision
StatePopulate
StateBuild
StateProgress
StateExport
StateDone
StateError
StateSignal
StateTimeout
)
var (
argJSON bool
argBuilderHost string
argBuilderPort int
argTimeoutClaim int
argTimeoutProvision int
argTimeoutPopulate int
argTimeoutBuild int
argTimeoutExport int
argBuildPath string
)
type BuildRequest struct {
Pipelines []string `json:"pipelines"`
Environments []string `json:"environments"`
}
func init() {
flag.BoolVar(&argJSON, "json", false, "Enable JSON output")
flag.StringVar(&argBuilderHost, "builder-host", "localhost", "Hostname or IP where this program will listen on.")
flag.IntVar(&argBuilderPort, "builder-port", 3333, "Port this program will listen on.")
flag.IntVar(&argTimeoutClaim, "timeout-claim", 600, "Timeout before the claim phase needs to be completed in seconds.")
flag.IntVar(&argTimeoutProvision, "timeout-provision", 30, "Timeout before the provision phase needs to be completed in seconds.")
flag.IntVar(&argTimeoutPopulate, "timeout-populate", 300, "Timeout before the populate phase needs to be completed in seconds.")
flag.IntVar(&argTimeoutBuild, "timeout-build", 3600, "Timeout before the build phase needs to be completed in seconds.")
flag.IntVar(&argTimeoutExport, "timeout-export", 1800, "Timeout before the export phase needs to be completed in seconds.")
flag.StringVar(&argBuildPath, "build-path", "/run/osbuild", "Path to use as a build directory.")
flag.Parse()
opts := &slog.HandlerOptions{Level: slog.LevelInfo}
if argJSON {
slog.SetDefault(slog.New(slog.NewJSONHandler(os.Stdout, opts)))
} else {
slog.SetDefault(slog.New(slog.NewTextHandler(os.Stdout, opts)))
}
}
type Builder struct {
Host string
Port int
State State
StateLock sync.Mutex
StateChannel chan State
Build *BackgroundProcess
net *http.Server
}
type BackgroundProcess struct {
Process *exec.Cmd
Stdout *bytes.Buffer
Stderr io.ReadCloser
Done bool
Error error
}
func (builder *Builder) SetState(state State) {
builder.StateLock.Lock()
defer builder.StateLock.Unlock()
if state <= builder.State {
builder.State = StateError
} else {
builder.State = state
}
builder.StateChannel <- builder.State
}
func (builder *Builder) GetState() State {
builder.StateLock.Lock()
defer builder.StateLock.Unlock()
return builder.State
}
func (builder *Builder) GuardState(stateWanted State) {
if stateCurrent := builder.GetState(); stateWanted != stateCurrent {
slog.Error("Builder.GuardState: Guard state mismatch", "requested", stateWanted, "current", stateCurrent)
os.Exit(ExitError)
}
}
func (builder *Builder) RegisterHandler(h Handler) http.HandlerFunc {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
if err := h(w, r); err != nil {
slog.Error("Handler: error", "error", err)
}
})
}
func (builder *Builder) HandleClaim(w http.ResponseWriter, r *http.Request) error {
builder.GuardState(StateClaim)
if r.Method != "POST" {
slog.Error("Builder.HandleClaim: unexpected request method", "method", r.Method)
}
fmt.Fprintf(w, "%s", "done")
slog.Info("Builder.HandleClaim: Done")
builder.SetState(StateProvision)
return nil
}
func (builder *Builder) HandleProvision(w http.ResponseWriter, r *http.Request) (err error) {
builder.GuardState(StateProvision)
if r.Method != "PUT" {
return fmt.Errorf("Builder.HandleProvision: Unexpected request method")
}
slog.Debug("Builder.HandleProvision: Opening manifest.json", "argBuildPath", argBuildPath)
dst, err := os.OpenFile(
path.Join(argBuildPath, "manifest.json"),
os.O_WRONLY|os.O_CREATE|os.O_EXCL,
0400,
)
defer func() {
if cerr := dst.Close(); cerr != nil {
err = cerr
}
}()
if err != nil {
return fmt.Errorf("Builder.HandleProvision: Failed to open manifest.json")
}
slog.Debug("Builder.HandleProvision: Writing manifest.json")
_, err = io.Copy(dst, r.Body)
if err != nil {
return fmt.Errorf("Builder.HandleProvision: Failed to write manifest.json")
}
w.WriteHeader(http.StatusCreated)
if _, err := w.Write([]byte(`done`)); err != nil {
return fmt.Errorf("Builder.HandleProvision: Failed to write response")
}
slog.Info("Builder.HandleProvision: Done")
builder.SetState(StatePopulate)
return nil
}
func (builder *Builder) HandlePopulate(w http.ResponseWriter, r *http.Request) error {
builder.GuardState(StatePopulate)
if r.Method != "POST" {
return fmt.Errorf("Builder.HandlePopulate: unexpected request method")
}
storePath := path.Join(argBuildPath, "store")
err := os.Mkdir(storePath, 0755)
if err != nil {
return fmt.Errorf("Builder.HandlePopulate: failed to make store directory: %v", err)
}
tarReader := tar.NewReader(r.Body)
for header, err := tarReader.Next(); err != io.EOF; header, err = tarReader.Next() {
if err != nil {
return fmt.Errorf("Builder.HandlerPopulate: failed to unpack sources: %v", err)
}
// gosec seems overly zealous here, as the destination gets verified
dest := filepath.Join(storePath, header.Name) // #nosec G305
if !strings.HasPrefix(dest, filepath.Clean(storePath)) {
return fmt.Errorf("Builder.HandlerPopulate: name not clean: %v doesn't have %v prefix", dest, filepath.Clean(storePath))
}
switch header.Typeflag {
case tar.TypeDir:
if err := os.Mkdir(dest, header.FileInfo().Mode()); err != nil {
return fmt.Errorf("Builder.HandlerPopulate: unable to make dir in sources: %v", err)
}
case tar.TypeReg:
file, err := os.Create(dest)
if err != nil {
return fmt.Errorf("Builder.HandlerPopulate: unable to open file in sources: %v", err)
}
defer file.Close()
// the inputs are trusted so ignore G110
_, err = io.Copy(file, tarReader) // #nosec G110
if err != nil {
return fmt.Errorf("Builder.HandlerPopulate: unable to write file in sources: %v", err)
}
file.Close()
default:
return fmt.Errorf("Builder.HandlerPopulate: unexpected tar header type: %v", header.Typeflag)
}
}
w.WriteHeader(http.StatusOK)
if _, err := w.Write([]byte(`done`)); err != nil {
return fmt.Errorf("Builder.HandlePopulate: Failed to write response")
}
slog.Info("Builder.HandlePopulate: Done")
builder.SetState(StateBuild)
return nil
}
func (builder *Builder) HandleBuild(w http.ResponseWriter, r *http.Request) error {
builder.GuardState(StateBuild)
if r.Method != "POST" {
return fmt.Errorf("Builder.HandleBuild: Unexpected request method")
}
var buildRequest BuildRequest
var err error
if err = json.NewDecoder(r.Body).Decode(&buildRequest); err != nil {
return fmt.Errorf("HandleBuild: Failed to decode body")
}
if builder.Build != nil {
slog.Error("HandleBuild: Build started but Build was non-nil")
os.Exit(ExitError)
}
args := []string{
"--store", path.Join(argBuildPath, "store"),
"--cache-max-size", "0",
"--output-directory", path.Join(argBuildPath, "export"),
"--json",
}
for _, pipeline := range buildRequest.Pipelines {
args = append(args, "--export")
args = append(args, pipeline)
}
args = append(args, path.Join(argBuildPath, "manifest.json"))
envs := os.Environ()
envs = append(envs, buildRequest.Environments...)
builder.Build = &BackgroundProcess{}
builder.Build.Process = exec.Command(
"/usr/bin/osbuild",
args...,
)
builder.Build.Process.Env = envs
slog.Info("BackgroundProcess: Starting", "process", builder.Build.Process, "env", envs)
builder.Build.Stdout = &bytes.Buffer{}
builder.Build.Process.Stdout = builder.Build.Stdout
builder.Build.Stderr, err = builder.Build.Process.StderrPipe()
if err != nil {
return err
}
if err := builder.Build.Process.Start(); err != nil {
return fmt.Errorf("BackgroundProcess: Failed to start process")
}
go func() {
builder.Build.Error = builder.Build.Process.Wait()
builder.Build.Done = true
slog.Info("BackgroundProcess: Exited")
}()
go func() {
scanner := bufio.NewScanner(builder.Build.Stderr)
for scanner.Scan() {
m := scanner.Text()
slog.Info("BackgroundProcess: Stderr", "text", m)
}
}()
w.WriteHeader(http.StatusCreated)
builder.SetState(StateProgress)
return nil
}
func (builder *Builder) HandleProgress(w http.ResponseWriter, r *http.Request) error {
builder.GuardState(StateProgress)
if r.Method != "GET" {
return fmt.Errorf("Builder.HandleProgress: Unexpected request method")
}
if builder.Build == nil {
return fmt.Errorf("HandleProgress: Progress requested but Build was nil")
}
if builder.Build.Done {
w.WriteHeader(http.StatusOK)
if builder.Build.Error != nil {
return fmt.Errorf("Builder.HandleBuild: Buildprocess exited with error: %s", builder.Build.Error)
}
if _, err := w.Write(builder.Build.Stdout.Bytes()); err != nil {
return fmt.Errorf("Builder.HandleBuild: Failed to write response")
}
builder.SetState(StateExport)
} else {
w.WriteHeader(http.StatusAccepted)
}
slog.Info("Builder.HandleBuild: Done")
return nil
}
func (builder *Builder) HandleExport(w http.ResponseWriter, r *http.Request) error {
builder.GuardState(StateExport)
if r.Method != "GET" {
return fmt.Errorf("Builder.HandleExport: unexpected request method")
}
exportPath := r.URL.Query().Get("path")
if exportPath == "" {
return fmt.Errorf("Builder.HandleExport: Missing export")
}
// XXX check subdir
srcPath := path.Join(argBuildPath, "export", exportPath)
src, err := os.Open(
srcPath,
)
if err != nil {
return fmt.Errorf("Builder.HandleExport: Failed to open source: %s", err)
}
_, err = io.Copy(w, src)
if err != nil {
return fmt.Errorf("Builder.HandleExport: Failed to write response: %s", err)
}
slog.Info("Builder.HandleExport: Done")
builder.SetState(StateDone)
return nil
}
func (builder *Builder) Serve() error {
mux := http.NewServeMux()
mux.HandleFunc("/claim", builder.RegisterHandler(builder.HandleClaim))
mux.HandleFunc("/provision", builder.RegisterHandler(builder.HandleProvision))
mux.HandleFunc("/populate", builder.RegisterHandler(builder.HandlePopulate))
mux.HandleFunc("/build", builder.RegisterHandler(builder.HandleBuild))
mux.HandleFunc("/progress", builder.RegisterHandler(builder.HandleProgress))
mux.HandleFunc("/export", builder.RegisterHandler(builder.HandleExport))
/* #nosec G112 */
builder.net = &http.Server{
Addr: fmt.Sprintf("%s:%d", builder.Host, builder.Port),
Handler: mux,
}
return builder.net.ListenAndServe()
}
func main() {
slog.With(
slog.Bool("argJSON", argJSON),
slog.String("argBuilderHost", argBuilderHost),
slog.Int("argBuilderPort", argBuilderPort),
slog.Int("argTimeoutClaim", argTimeoutClaim),
slog.Int("argTimeoutProvision", argTimeoutProvision),
slog.Int("argTimeoutBuild", argTimeoutBuild),
slog.Int("argTimeoutExport", argTimeoutExport),
).Info("main: Starting up")
builder := Builder{
State: StateClaim,
StateChannel: make(chan State, 1),
Host: argBuilderHost,
Port: argBuilderPort,
}
errs := make(chan error, 1)
go func(errs chan<- error) {
if err := builder.Serve(); err != nil {
errs <- err
}
}(errs)
for {
select {
case state := <-builder.StateChannel:
if state == StateDone {
ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second)
if err := builder.net.Shutdown(ctx); err != nil {
slog.Error("main: server shutdown failed", "err", err)
}
cancel()
slog.Info("main: Shutting down successfully")
os.Exit(ExitOk)
}
case err := <-errs:
slog.Error("ErrorChannel", "err", err)
os.Exit(ExitError)
}
}
}

View file

@ -1,483 +0,0 @@
// # `jobsite-manager`
package main
import (
"archive/tar"
"bytes"
"context"
"encoding/json"
"errors"
"flag"
"fmt"
"io"
"log/slog"
"net/http"
"net/url"
"os"
"os/signal"
"path"
"path/filepath"
"strings"
"syscall"
"time"
)
const (
ExitOk int = iota
ExitError
ExitTimeout
ExitSignal
)
type ArgumentList []string
func (AL *ArgumentList) String() string {
return ""
}
func (AL *ArgumentList) Set(value string) error {
*AL = append(*AL, value)
return nil
}
var (
argJSON bool
argJobsiteHost string
argJobsitePort int
argBuilderHost string
argBuilderPort int
argTimeoutClaim int
argTimeoutProvision int
argTimeoutPopulate int
argTimeoutBuild int
argTimeoutProgress int
argTimeoutExport int
argPipelines ArgumentList
argEnvironments ArgumentList
argExports ArgumentList
argOutputPath string
argStore string
)
type BuildRequest struct {
Pipelines []string `json:"pipelines"`
Environments []string `json:"environments"`
}
type Step func(chan<- struct{}, chan<- error)
func init() {
flag.BoolVar(&argJSON, "json", false, "Enable JSON output")
flag.StringVar(&argJobsiteHost, "manager-host", "localhost", "Hostname or IP where this program will listen on.")
flag.IntVar(&argJobsitePort, "manager-port", 3333, "Port this program will listen on.")
flag.StringVar(&argBuilderHost, "builder-host", "localhost", "Hostname or IP of a jobsite-builder that this program will connect to.")
flag.IntVar(&argBuilderPort, "builder-port", 3333, "Port of a jobsite-builder that this program will connect to.")
flag.IntVar(&argTimeoutClaim, "timeout-claim", 600, "Timeout before the claim phase needs to be completed in seconds.")
flag.IntVar(&argTimeoutProvision, "timeout-provision", 30, "Timeout before the provision phase needs to be completed in seconds.")
flag.IntVar(&argTimeoutPopulate, "timeout-populate", 300, "Timeout before the populate phase needs to be completed in seconds.")
flag.IntVar(&argTimeoutBuild, "timeout-build", 30, "Timeout before the build phase needs to be completed in seconds.")
flag.IntVar(&argTimeoutProgress, "timeout-progress", 3600, "Timeout before the progress phase needs to be completed in seconds.")
flag.IntVar(&argTimeoutExport, "timeout-export", 1800, "Timeout before the export phase needs to be completed in seconds.")
flag.Var(&argPipelines, "export", "Pipelines to export. Can be passed multiple times.")
flag.Var(&argExports, "export-file", "Files to export. Can be passed multiple times.")
flag.Var(&argEnvironments, "environment", "Environments to add. Can be passed multiple times.")
flag.StringVar(&argOutputPath, "output", "/dev/null", "Output directory to write to.")
flag.StringVar(&argStore, "store", "", "Store to send to builder.")
flag.Parse()
opts := &slog.HandlerOptions{Level: slog.LevelInfo}
if argJSON {
slog.SetDefault(slog.New(slog.NewJSONHandler(os.Stdout, opts)))
} else {
slog.SetDefault(slog.New(slog.NewTextHandler(os.Stdout, opts)))
}
}
func main() {
slog.Info("main: Starting up")
sigs := make(chan os.Signal, 1)
signal.Notify(sigs, syscall.SIGINT, syscall.SIGTERM)
done := make(chan struct{}, 1)
errs := make(chan error, 1)
go Dance(done, errs)
for {
select {
case sig := <-sigs:
slog.Info("main: Exiting on signal", "signal", sig)
os.Exit(ExitSignal)
case err := <-errs:
slog.Info("main: Exiting on error", "error", err)
os.Exit(ExitError)
case <-done:
slog.Info("main: Shutting down succesfully")
os.Exit(ExitOk)
}
}
}
func Dance(done chan<- struct{}, errs chan<- error) {
manifest, err := io.ReadAll(os.Stdin)
if err != nil {
errs <- err
return
}
if err := StepClaim(); err != nil {
errs <- err
return
}
if err := StepProvision(manifest); err != nil {
errs <- err
return
}
if err := StepPopulate(); err != nil {
errs <- err
return
}
if err := StepBuild(); err != nil {
errs <- err
return
}
if err := StepProgress(); err != nil {
errs <- err
return
}
if err := StepExport(); err != nil {
errs <- err
return
}
close(done)
}
func Request(method string, path string, body io.Reader, bodySeeker io.ReadSeeker) (*http.Response, error) {
ctx := context.Background()
cli := &http.Client{}
url := fmt.Sprintf("http://%s:%d/%s", argBuilderHost, argBuilderPort, path)
var req *http.Request
var err error
if bodySeeker != nil {
req, err = http.NewRequestWithContext(ctx, method, url, bodySeeker)
} else {
req, err = http.NewRequestWithContext(ctx, method, url, body)
}
if err != nil {
return nil, err
}
// Don't accept any compression on the return value; it intermittently leads to unexpected EOFs during the larger
// download when the exports are requested.
req.Header.Set("Accept-Encoding", "identity")
slog.DebugContext(ctx, "Request: Making a request", "method", method, "url", url)
for {
res, err := cli.Do(req)
if err != nil {
if errors.Is(err, syscall.ECONNABORTED) || errors.Is(err, syscall.ECONNRESET) || errors.Is(err, syscall.ECONNREFUSED) {
if bodySeeker != nil {
_, err = bodySeeker.Seek(0, io.SeekStart)
if err != nil {
return nil, err
}
}
time.Sleep(1 * time.Second)
continue
}
return nil, err
}
return res, nil
}
}
func Wait(timeout int, fn Step) error {
done := make(chan struct{}, 1)
errs := make(chan error, 1)
go fn(done, errs)
select {
case <-time.After(time.Duration(timeout) * time.Second):
return fmt.Errorf("timeout")
case <-done:
return nil
case err := <-errs:
return err
}
}
func StepClaim() error {
return Wait(argTimeoutClaim, func(done chan<- struct{}, errs chan<- error) {
res, err := Request("POST", "claim", nil, nil)
if err != nil {
errs <- err
return
}
defer res.Body.Close()
if res.StatusCode != http.StatusOK {
errs <- fmt.Errorf("StepClaim: Got an unexpected response %d while expecting %d. Exiting", res.StatusCode, http.StatusOK)
return
}
slog.Info("StepClaim: Done")
close(done)
})
}
func StepProvision(manifest []byte) error {
return Wait(argTimeoutProvision, func(done chan<- struct{}, errs chan<- error) {
res, err := Request("PUT", "provision", bytes.NewBuffer(manifest), nil)
if err != nil {
errs <- err
return
}
defer res.Body.Close()
if res.StatusCode != http.StatusCreated {
errs <- fmt.Errorf("StepProvision: Got an unexpected response %d while expecting %d. Exiting", res.StatusCode, http.StatusCreated)
return
}
slog.Info("StepProvision: Done")
close(done)
})
}
func StepPopulate() error {
return Wait(argTimeoutPopulate, func(done chan<- struct{}, errs chan<- error) {
file, err := os.CreateTemp(filepath.Dir(argStore), "store.*.tar")
if err != nil {
errs <- err
return
}
defer os.Remove(file.Name())
tw := tar.NewWriter(file)
defer tw.Close()
err = filepath.Walk(argStore, func(filePath string, fi os.FileInfo, err error) error {
if err != nil {
return err
}
// skip the store direction itself, just package the contents
if filePath == argStore {
return nil
}
if !fi.Mode().IsRegular() && !fi.Mode().IsDir() {
return nil
}
header, err := tar.FileInfoHeader(fi, fi.Name())
if err != nil {
return err
}
// FileInfo only contains the basename, see https://pkg.go.dev/archive/tar#FileInfoHeader.
header.Name = strings.TrimPrefix(strings.Replace(filePath, argStore, "", -1), string(filepath.Separator))
if err := tw.WriteHeader(header); err != nil {
return err
}
if fi.Mode().IsRegular() {
f, err := os.Open(filePath)
if err != nil {
return err
}
defer f.Close()
if err != nil {
return err
}
if _, err := io.Copy(tw, f); err != nil {
return err
}
f.Close()
}
return nil
})
if err != nil {
errs <- err
return
}
err = tw.Close()
if err != nil {
errs <- err
return
}
_, err = file.Seek(0, io.SeekStart)
if err != nil {
errs <- err
return
}
res, err := Request("POST", "populate", nil, file)
if err != nil {
errs <- err
return
}
defer res.Body.Close()
if res.StatusCode != http.StatusOK {
errs <- fmt.Errorf("StepPopulate: Got an unexpected response %d while expecting %d. Exiting", res.StatusCode, http.StatusOK)
return
}
slog.Info("StepPopulate: Done")
close(done)
})
}
func StepBuild() error {
return Wait(argTimeoutBuild, func(done chan<- struct{}, errs chan<- error) {
arg := BuildRequest{
Pipelines: argPipelines,
Environments: argEnvironments,
}
dat, err := json.Marshal(arg)
if err != nil {
slog.Error("StepBuild: Failed to marshal data", "err", err)
os.Exit(ExitError)
}
res, err := Request("POST", "build", bytes.NewBuffer(dat), nil)
if err != nil {
errs <- err
return
}
defer res.Body.Close()
if res.StatusCode != http.StatusCreated {
errs <- fmt.Errorf("StepBuild: Got an unexpected response %d while expecting %d. Exiting", res.StatusCode, http.StatusOK)
return
}
slog.Info("StepBuild: Done")
close(done)
})
}
func StepProgress() error {
return Wait(argTimeoutProgress, func(done chan<- struct{}, errs chan<- error) {
for {
res, err := Request("GET", "progress", nil, nil)
if err != nil {
errs <- err
return
}
defer res.Body.Close()
if res.StatusCode == http.StatusAccepted {
slog.Info("StepProgress: Build is pending. Retry")
time.Sleep(5 * time.Second)
continue
}
if res.StatusCode != http.StatusOK {
errs <- fmt.Errorf("StepProgress: Got an unexpected response %d while expecting %d. Exiting", res.StatusCode, http.StatusOK)
return
}
_, err = io.Copy(os.Stdout, res.Body)
if err != nil {
errs <- fmt.Errorf("StepProgress: Unable to write response body to stdout: %v", err)
}
break
}
slog.Info("StepProgress: Done")
close(done)
})
}
func StepExport() error {
return Wait(argTimeoutExport, func(done chan<- struct{}, errs chan<- error) {
for _, export := range argExports {
res, err := Request("GET", fmt.Sprintf("export?path=%s", url.PathEscape(export)), nil, nil)
if err != nil {
errs <- err
return
}
defer res.Body.Close()
if res.StatusCode != http.StatusOK {
errs <- fmt.Errorf("StepExport: Got an unexpected response %d while expecting %d. Exiting", res.StatusCode, http.StatusOK)
return
}
dstPath := path.Join(argOutputPath, export)
dstDir := filepath.Dir(dstPath)
if _, err := os.Stat(dstDir); os.IsNotExist(err) {
slog.Info("StepExport: Destination directory does not exist. Creating", "dir", dstDir)
if err := os.MkdirAll(dstDir, 0700); err != nil {
errs <- fmt.Errorf("StepExport: Failed to create destination directory: %s", err)
}
}
dst, err := os.OpenFile(
path.Join(argOutputPath, export),
os.O_WRONLY|os.O_CREATE|os.O_EXCL,
0400,
)
if err != nil {
errs <- fmt.Errorf("StepExport: Failed to open destination response: %s", err)
return
}
_, err = io.Copy(dst, res.Body)
if err != nil {
errs <- fmt.Errorf("StepExport: Failed to copy response: %s", err)
return
}
}
slog.Info("StepExport: Done")
close(done)
})
}

View file

@ -106,8 +106,6 @@ export LDFLAGS="${LDFLAGS} -X 'github.com/osbuild/osbuild-composer/internal/comm
%gobuild ${GOTAGS:+-tags=$GOTAGS} -o _bin/osbuild-composer %{goipath}/cmd/osbuild-composer %gobuild ${GOTAGS:+-tags=$GOTAGS} -o _bin/osbuild-composer %{goipath}/cmd/osbuild-composer
%gobuild ${GOTAGS:+-tags=$GOTAGS} -o _bin/osbuild-worker %{goipath}/cmd/osbuild-worker %gobuild ${GOTAGS:+-tags=$GOTAGS} -o _bin/osbuild-worker %{goipath}/cmd/osbuild-worker
%gobuild ${GOTAGS:+-tags=$GOTAGS} -o _bin/osbuild-worker-executor %{goipath}/cmd/osbuild-worker-executor %gobuild ${GOTAGS:+-tags=$GOTAGS} -o _bin/osbuild-worker-executor %{goipath}/cmd/osbuild-worker-executor
%gobuild ${GOTAGS:+-tags=$GOTAGS} -o _bin/osbuild-jobsite-manager %{goipath}/cmd/osbuild-jobsite-manager
%gobuild ${GOTAGS:+-tags=$GOTAGS} -o _bin/osbuild-jobsite-builder %{goipath}/cmd/osbuild-jobsite-builder
make man make man
@ -140,8 +138,6 @@ install -m 0755 -vd %{buildroot}%
install -m 0755 -vp _bin/osbuild-composer %{buildroot}%{_libexecdir}/osbuild-composer/ install -m 0755 -vp _bin/osbuild-composer %{buildroot}%{_libexecdir}/osbuild-composer/
install -m 0755 -vp _bin/osbuild-worker %{buildroot}%{_libexecdir}/osbuild-composer/ install -m 0755 -vp _bin/osbuild-worker %{buildroot}%{_libexecdir}/osbuild-composer/
install -m 0755 -vp _bin/osbuild-worker-executor %{buildroot}%{_libexecdir}/osbuild-composer/ install -m 0755 -vp _bin/osbuild-worker-executor %{buildroot}%{_libexecdir}/osbuild-composer/
install -m 0755 -vp _bin/osbuild-jobsite-manager %{buildroot}%{_libexecdir}/osbuild-composer/
install -m 0755 -vp _bin/osbuild-jobsite-builder %{buildroot}%{_libexecdir}/osbuild-composer/
# Only include repositories for the distribution and release # Only include repositories for the distribution and release
install -m 0755 -vd %{buildroot}%{_datadir}/osbuild-composer/repositories install -m 0755 -vd %{buildroot}%{_datadir}/osbuild-composer/repositories
@ -347,8 +343,6 @@ The worker for osbuild-composer
%files worker %files worker
%{_libexecdir}/osbuild-composer/osbuild-worker %{_libexecdir}/osbuild-composer/osbuild-worker
%{_libexecdir}/osbuild-composer/osbuild-worker-executor %{_libexecdir}/osbuild-composer/osbuild-worker-executor
%{_libexecdir}/osbuild-composer/osbuild-jobsite-manager
%{_libexecdir}/osbuild-composer/osbuild-jobsite-builder
%{_unitdir}/osbuild-worker@.service %{_unitdir}/osbuild-worker@.service
%{_unitdir}/osbuild-remote-worker@.service %{_unitdir}/osbuild-remote-worker@.service

View file

@ -32,5 +32,5 @@ sinks:
EOF EOF
sudo systemctl enable --now vector sudo systemctl enable --now vector
echo "Starting osbuild-jobsite-builder." echo "Starting worker executor"
/usr/libexec/osbuild-composer/osbuild-worker-executor -host 0.0.0.0 /usr/libexec/osbuild-composer/osbuild-worker-executor -host 0.0.0.0