Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

osbuild-worker-executor: job-id in control.json as hostname #4208

Merged
merged 3 commits into from
Jun 14, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions cmd/osbuild-worker-executor/export_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,14 @@ var (
HandleIncludedSources = handleIncludedSources
)

func MockUnixSethostname(new func([]byte) error) (restore func()) {
saved := unixSethostname
unixSethostname = new
return func() {
unixSethostname = saved
}
}

func MockOsbuildBinary(t *testing.T, new string) (restore func()) {
t.Helper()

Expand Down
16 changes: 16 additions & 0 deletions cmd/osbuild-worker-executor/handler_build.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import (
"strings"

"golang.org/x/exp/slices"
"golang.org/x/sys/unix"

"github.com/sirupsen/logrus"
)
Expand Down Expand Up @@ -108,6 +109,7 @@ func runOsbuild(logger *logrus.Logger, buildDir string, control *controlJSON, ou
type controlJSON struct {
Environments []string `json:"environments"`
Exports []string `json:"exports"`
JobID string `json:"job-id"`
}

func mustRead(atar *tar.Reader, name string) error {
Expand Down Expand Up @@ -235,6 +237,15 @@ func handleIncludedSources(atar *tar.Reader, buildDir string) error {
}
}

var unixSethostname = unix.Sethostname

func setHostname(name string) error {
if name == "" {
return nil
}
return unixSethostname([]byte(name))
}

// test for real via:
// curl -o - --data-binary "@./test.tar" -H "Content-Type: application/x-tar" -X POST http://localhost:8001/api/v1/build
func handleBuild(logger *logrus.Logger, config *Config) http.Handler {
Expand Down Expand Up @@ -262,6 +273,11 @@ func handleBuild(logger *logrus.Logger, config *Config) http.Handler {
http.Error(w, "cannot decode control.json", http.StatusBadRequest)
return
}
if err := setHostname(control.JobID); err != nil {
logger.Error(err)
http.Error(w, "cannot set hostname", http.StatusBadRequest)
return
}

buildDir, err := createBuildDir(config)
if err != nil {
Expand Down
27 changes: 27 additions & 0 deletions cmd/osbuild-worker-executor/handler_build_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -324,3 +324,30 @@ func TestBuildErrorHandlingTar(t *testing.T) {
assert.Contains(t, string(body), "cannot tar output directory:")
assert.Contains(t, loggerHook.LastEntry().Message, "cannot tar output directory:")
}

func TestBuildSethostname(t *testing.T) {
baseURL, baseBuildDir, _ := runTestServer(t)
endpoint := baseURL + "api/v1/build"

restore := main.MockOsbuildBinary(t, fmt.Sprintf(`#!/bin/sh -e
# simulate output
mkdir -p %[1]s/build/output/image
echo "fake-build-result" > %[1]s/build/output/image/disk.img
`, baseBuildDir))
t.Cleanup(restore)

var hostnameCalls []string
restore = main.MockUnixSethostname(func(hn []byte) error {
hostnameCalls = append(hostnameCalls, string(hn))
return nil
})
t.Cleanup(restore)

buf := makeTestPost(t, `{"exports": ["tree"], "job-id": "1234-56"}`, `{"fake": "manifest"}`)
rsp, err := http.Post(endpoint, "application/x-tar", buf)
assert.NoError(t, err)
defer func() { _, _ = io.ReadAll(rsp.Body) }()
defer rsp.Body.Close()

assert.Equal(t, []string{"1234-56"}, hostnameCalls)
}
5 changes: 5 additions & 0 deletions cmd/osbuild-worker-executor/main_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,11 @@ func runTestServer(t *testing.T) (baseURL, buildBaseDir string, loggerHook *logr
buildBaseDir = t.TempDir()
baseURL = fmt.Sprintf("http://%s:%s/", host, port)

restore := main.MockUnixSethostname(func([]byte) error {
return nil
})
t.Cleanup(restore)

ctx, cancel := context.WithCancel(context.Background())
t.Cleanup(cancel)

Expand Down
11 changes: 10 additions & 1 deletion cmd/osbuild-worker/jobimpl-osbuild.go
Original file line number Diff line number Diff line change
Expand Up @@ -526,7 +526,16 @@ func (impl *OSBuildJobImpl) Run(job worker.Job) error {
exportPaths = append(exportPaths, path.Join(jobTarget.OsbuildArtifact.ExportName, jobTarget.OsbuildArtifact.ExportFilename))
}

osbuildJobResult.OSBuildOutput, err = executor.RunOSBuild(jobArgs.Manifest, impl.Store, outputDirectory, exports, exportPaths, nil, extraEnv, true, os.Stderr)
opts := &osbuildexecutor.OsbuildOpts{
StoreDir: impl.Store,
OutputDir: outputDirectory,
Exports: exports,
ExportPaths: exportPaths,
ExtraEnv: extraEnv,
Result: true,
JobID: job.Id().String(),
}
osbuildJobResult.OSBuildOutput, err = executor.RunOSBuild(jobArgs.Manifest, opts, os.Stderr)
// First handle the case when "running" osbuild failed
if err != nil {
osbuildJobResult.JobError = clienterrors.WorkerClientError(clienterrors.ErrorBuildJob, "osbuild build failed", err.Error())
Expand Down
15 changes: 14 additions & 1 deletion internal/osbuildexecutor/osbuild-executor.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,19 @@ import (
"github.com/osbuild/images/pkg/osbuild"
)

type OsbuildOpts struct {
StoreDir string
OutputDir string
Exports []string
ExportPaths []string
Checkpoints []string
ExtraEnv []string
Result bool

// not strict a osbuild opt
JobID string
}

type Executor interface {
RunOSBuild(manifest []byte, store, outputDirectory string, exports, exportPaths, checkpoints, extraEnv []string, result bool, errorWriter io.Writer) (*osbuild.Result, error)
RunOSBuild(manifest []byte, opts *OsbuildOpts, errorWriter io.Writer) (*osbuild.Result, error)
}
23 changes: 16 additions & 7 deletions internal/osbuildexecutor/runner-impl-aws-ec2.go
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,12 @@ type awsEC2Executor struct {

func prepareSources(manifest []byte, store string, extraEnv []string, result bool, errorWriter io.Writer) error {
hostExecutor := NewHostExecutor()
_, err := hostExecutor.RunOSBuild(manifest, store, "", nil, nil, nil, extraEnv, result, errorWriter)
opts := &OsbuildOpts{
StoreDir: store,
ExtraEnv: extraEnv,
Result: result,
}
_, err := hostExecutor.RunOSBuild(manifest, opts, errorWriter)
return err
}

Expand Down Expand Up @@ -68,15 +73,17 @@ func waitForSI(ctx context.Context, host string) bool {
}
}

func writeInputArchive(cacheDir, store string, exports []string, manifestData []byte) (string, error) {
func writeInputArchive(cacheDir, store, jobID string, exports []string, manifestData []byte) (string, error) {
archive := filepath.Join(cacheDir, "input.tar")
control := filepath.Join(cacheDir, "control.json")
manifest := filepath.Join(cacheDir, "manifest.json")

controlData := struct {
Exports []string `json:"exports"`
JobID string `json:"job-id"`
}{
Exports: exports,
JobID: jobID,
}
controlDataBytes, err := json.Marshal(controlData)
if err != nil {
Expand Down Expand Up @@ -243,10 +250,12 @@ func extractOutputArchive(outputDirectory, outputTar string) error {

}

func (ec2e *awsEC2Executor) RunOSBuild(manifest []byte, store, outputDirectory string, exports, exportPaths, checkpoints,
extraEnv []string, result bool, errorWriter io.Writer) (*osbuild.Result, error) {
func (ec2e *awsEC2Executor) RunOSBuild(manifest []byte, opts *OsbuildOpts, errorWriter io.Writer) (*osbuild.Result, error) {
if opts == nil {
opts = &OsbuildOpts{}
}

err := prepareSources(manifest, store, extraEnv, result, errorWriter)
err := prepareSources(manifest, opts.StoreDir, opts.ExtraEnv, opts.Result, errorWriter)
if err != nil {
return nil, fmt.Errorf("Failed to prepare sources: %w", err)
}
Expand Down Expand Up @@ -280,7 +289,7 @@ func (ec2e *awsEC2Executor) RunOSBuild(manifest []byte, store, outputDirectory s
return nil, fmt.Errorf("Timeout waiting for executor to come online")
}

inputArchive, err := writeInputArchive(ec2e.tmpDir, store, exports, manifest)
inputArchive, err := writeInputArchive(ec2e.tmpDir, opts.StoreDir, opts.JobID, opts.Exports, manifest)
if err != nil {
logrus.Errorf("Unable to write input archive: %v", err)
return nil, err
Expand All @@ -301,7 +310,7 @@ func (ec2e *awsEC2Executor) RunOSBuild(manifest []byte, store, outputDirectory s
return nil, err
}

err = extractOutputArchive(outputDirectory, outputArchive)
err = extractOutputArchive(opts.OutputDir, outputArchive)
if err != nil {
logrus.Errorf("Unable to extract executor output: %v", err)
return nil, err
Expand Down
6 changes: 5 additions & 1 deletion internal/osbuildexecutor/runner-impl-aws-ec2_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ func TestWriteInputArchive(t *testing.T) {
require.NoError(t, os.WriteFile(filepath.Join(storeDir, "contents"), []byte("storedata"), 0600))
require.NoError(t, os.WriteFile(filepath.Join(storeSubDir, "contents"), []byte("storedata"), 0600))

archive, err := osbuildexecutor.WriteInputArchive(cacheDir, storeDir, []string{"image"}, []byte("{\"version\": 2}"))
archive, err := osbuildexecutor.WriteInputArchive(cacheDir, storeDir, "some-job-id", []string{"image"}, []byte("{\"version\": 2}"))
require.NoError(t, err)

cmd := exec.Command("tar",
Expand All @@ -64,6 +64,10 @@ func TestWriteInputArchive(t *testing.T) {
"store/contents",
"",
}, strings.Split(string(out), "\n"))

output, err := exec.Command("tar", "xOf", archive, "control.json").CombinedOutput()
require.NoError(t, err)
require.Equal(t, `{"exports":["image"],"job-id":"some-job-id"}`, string(output))
}

func TestHandleBuild(t *testing.T) {
Expand Down
9 changes: 6 additions & 3 deletions internal/osbuildexecutor/runner-impl-host.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,12 @@ import (

type hostExecutor struct{}

func (he *hostExecutor) RunOSBuild(manifest []byte, store, outputDirectory string, exports, exportPaths, checkpoints,
extraEnv []string, result bool, errorWriter io.Writer) (*osbuild.Result, error) {
return osbuild.RunOSBuild(manifest, store, outputDirectory, exports, checkpoints, extraEnv, result, errorWriter)
func (he *hostExecutor) RunOSBuild(manifest []byte, opts *OsbuildOpts, errorWriter io.Writer) (*osbuild.Result, error) {
if opts == nil {
opts = &OsbuildOpts{}
}

return osbuild.RunOSBuild(manifest, opts.StoreDir, opts.OutputDir, opts.Exports, opts.Checkpoints, opts.ExtraEnv, opts.Result, errorWriter)
}

func NewHostExecutor() Executor {
Expand Down
Loading