osbuild-worker: add ostree resolve job

This job resolves an ostree ref. Similar to the depsolve and container
resolve jobs, this should be a dependency of a manifest job.
This commit is contained in:
Sanne Raymaekers 2022-10-18 15:24:34 +02:00
parent b01792d9dd
commit ebeb339f96
6 changed files with 217 additions and 0 deletions

View file

@ -0,0 +1,79 @@
package main
import (
"fmt"
"github.com/sirupsen/logrus"
"github.com/osbuild/osbuild-composer/internal/ostree"
"github.com/osbuild/osbuild-composer/internal/worker"
"github.com/osbuild/osbuild-composer/internal/worker/clienterrors"
)
type OSTreeResolveJobImpl struct {
}
func setError(err error, result *worker.OSTreeResolveJobResult) {
switch err.(type) {
case ostree.RefError:
result.JobError = clienterrors.WorkerClientError(
clienterrors.ErrorOSTreeRefInvalid,
"Invalid OSTree ref",
err,
)
case ostree.ResolveRefError:
result.JobError = clienterrors.WorkerClientError(
clienterrors.ErrorOSTreeRefResolution,
"Error resolving OSTree ref",
err,
)
default:
result.JobError = clienterrors.WorkerClientError(
clienterrors.ErrorOSTreeParamsInvalid,
"Invalid OSTree parameters or parameter combination",
err,
)
}
}
func (impl *OSTreeResolveJobImpl) Run(job worker.Job) error {
logWithId := logrus.WithField("jobId", job.Id())
var args worker.OSTreeResolveJob
err := job.Args(&args)
if err != nil {
return err
}
result := worker.OSTreeResolveJobResult{
Specs: make([]worker.OSTreeResolveResultSpec, len(args.Specs)),
}
logWithId.Infof("Resolving (%d) ostree commits", len(args.Specs))
for _, s := range args.Specs {
reqParams := ostree.RequestParams{
URL: s.URL,
Ref: s.Ref,
Parent: s.Parent,
}
ref, checksum, err := ostree.ResolveParams(reqParams)
if err != nil {
setError(err, &result)
break
}
result.Specs = append(result.Specs, worker.OSTreeResolveResultSpec{
URL: s.URL,
Ref: ref,
Checksum: checksum,
})
}
err = job.Update(&result)
if err != nil {
return fmt.Errorf("Error reporting job result: %v", err)
}
return nil
}

View file

@ -465,6 +465,7 @@ func main() {
worker.JobTypeContainerResolve: &ContainerResolveJobImpl{
AuthFilePath: containersAuthFilePath,
},
worker.JobTypeOSTreeResolve: &OSTreeResolveJobImpl{},
worker.JobTypeAWSEC2Copy: &AWSEC2CopyJobImpl{
AWSCreds: awsCredentials,
},

View file

@ -32,6 +32,10 @@ const (
ErrorParsingJobArgs ClientErrorCode = 29
ErrorContainerResolution ClientErrorCode = 30
ErrorContainerDependency ClientErrorCode = 31
ErrorOSTreeRefInvalid ClientErrorCode = 32
ErrorOSTreeRefResolution ClientErrorCode = 33
ErrorOSTreeParamsInvalid ClientErrorCode = 34
ErrorOSTreeDependency ClientErrorCode = 35
)
type ClientErrorCode int
@ -87,6 +91,8 @@ func GetStatusCode(err *Error) StatusCode {
return JobStatusUserInputError
case ErrorContainerResolution:
return JobStatusUserInputError
case ErrorOSTreeDependency:
return JobStatusUserInputError
default:
return JobStatusInternalError
}
@ -97,6 +103,8 @@ func (e *Error) IsDependencyError() bool {
switch e.ID {
case ErrorContainerDependency:
return true
case ErrorOSTreeDependency:
return true
case ErrorDepsolveDependency:
return true
case ErrorManifestDependency:

View file

@ -256,6 +256,28 @@ type ContainerResolveJobResult struct {
JobResult
}
type OSTreeResolveSpec struct {
URL string `json:"url"`
Ref string `json:"ref"`
Parent string `json:"parent"`
}
type OSTreeResolveJob struct {
Specs []OSTreeResolveSpec `json:"ostree_resolve_specs"`
}
type OSTreeResolveResultSpec struct {
URL string `json:"url"`
Ref string `json:"ref"`
Checksum string `json:"checksum"`
}
type OSTreeResolveJobResult struct {
Specs []OSTreeResolveResultSpec `json:"ostree_resolve_result_specs"`
JobResult
}
type AWSEC2ShareJob struct {
Ami string `json:"ami"`
Region string `json:"region"`

View file

@ -35,6 +35,7 @@ const (
JobTypeDepsolve string = "depsolve"
JobTypeManifestIDOnly string = "manifest-id-only"
JobTypeContainerResolve string = "container-resolve"
JobTypeOSTreeResolve string = "ostree-resolve"
JobTypeAWSEC2Copy string = "aws-ec2-copy"
JobTypeAWSEC2Share string = "aws-ec2-share"
)
@ -160,6 +161,10 @@ func (s *Server) EnqueueContainerResolveJob(job *ContainerResolveJob, channel st
return s.enqueue(JobTypeContainerResolve, job, nil, channel)
}
func (s *Server) EnqueueOSTreeResolveJob(job *OSTreeResolveJob, channel string) (uuid.UUID, error) {
return s.enqueue(JobTypeOSTreeResolve, job, nil, channel)
}
func (s *Server) EnqueueAWSEC2CopyJob(job *AWSEC2CopyJob, parent uuid.UUID, channel string) (uuid.UUID, error) {
return s.enqueue(JobTypeAWSEC2Copy, job, []uuid.UUID{parent}, channel)
}
@ -231,6 +236,13 @@ func (s *Server) JobDependencyChainErrors(id uuid.UUID) (*clienterrors.Error, er
return nil, err
}
jobResult = &containerResolveJR.JobResult
case JobTypeOSTreeResolve:
var ostreeResolveJR OSTreeResolveJobResult
jobInfo, err = s.OSTreeResolveJobInfo(id, &ostreeResolveJR)
if err != nil {
return nil, err
}
jobResult = &ostreeResolveJR.JobResult
default:
return nil, fmt.Errorf("unexpected job type: %s", jobType)
@ -370,6 +382,19 @@ func (s *Server) ContainerResolveJobInfo(id uuid.UUID, result *ContainerResolveJ
return jobInfo, nil
}
func (s *Server) OSTreeResolveJobInfo(id uuid.UUID, result *OSTreeResolveJobResult) (*JobInfo, error) {
jobInfo, err := s.jobInfo(id, result)
if err != nil {
return nil, err
}
if jobInfo.JobType != JobTypeOSTreeResolve {
return nil, fmt.Errorf("expected %q, found %q job instead", JobTypeOSTreeResolve, jobInfo.JobType)
}
return jobInfo, nil
}
func (s *Server) AWSEC2CopyJobInfo(id uuid.UUID, result *AWSEC2CopyJobResult) (*JobInfo, error) {
jobInfo, err := s.jobInfo(id, result)
if err != nil {
@ -684,6 +709,13 @@ func (s *Server) FinishJob(token uuid.UUID, result json.RawMessage) error {
return err
}
jobResult = &containerResolveJR.JobResult
case JobTypeOSTreeResolve:
var ostreeResolveJR OSTreeResolveJobResult
jobInfo, err = s.OSTreeResolveJobInfo(jobId, &ostreeResolveJR)
if err != nil {
return err
}
jobResult = &ostreeResolveJR.JobResult
default:
return fmt.Errorf("unexpected job type: %s", jobType)

View file

@ -790,6 +790,16 @@ func enqueueAndFinishTestJobDependencies(s *worker.Server, deps []testJob) ([]uu
return nil, err
}
case *worker.OSTreeResolveJob:
job := dep.main.(*worker.OSTreeResolveJob)
if len(depUUIDs) != 0 {
return nil, fmt.Errorf("dependencies are not supported for OSTreeResolveJob, got: %d", len(depUUIDs))
}
id, err = s.EnqueueOSTreeResolveJob(job, "")
if err != nil {
return nil, err
}
default:
return nil, fmt.Errorf("unexpected job type")
}
@ -1467,6 +1477,71 @@ func TestJobDependencyChainErrors(t *testing.T) {
},
expectedError: nil,
},
// osbuild + manifest + depsolve + ostree resolve
// failed ostree resolve
{
job: testJob{
main: &worker.OSBuildJob{},
deps: []testJob{
{
main: &worker.KojiInitJob{},
result: &worker.KojiInitJobResult{},
},
{
main: &worker.ManifestJobByID{},
deps: []testJob{
{
main: &worker.OSTreeResolveJob{},
result: &worker.OSTreeResolveJobResult{
JobResult: worker.JobResult{
JobError: &clienterrors.Error{
ID: clienterrors.ErrorOSTreeRefResolution,
Reason: "remote ostree ref not found",
},
},
},
},
{
main: &worker.DepsolveJob{},
result: &worker.DepsolveJobResult{},
},
},
result: &worker.ManifestJobByIDResult{
JobResult: worker.JobResult{
JobError: &clienterrors.Error{
ID: clienterrors.ErrorOSTreeDependency,
Reason: "ostree dependency job failed",
},
},
},
},
},
result: &worker.OSBuildJobResult{
JobResult: worker.JobResult{
JobError: &clienterrors.Error{
ID: clienterrors.ErrorManifestDependency,
Reason: "manifest dependency job failed",
},
},
},
},
expectedError: &clienterrors.Error{
ID: clienterrors.ErrorManifestDependency,
Reason: "manifest dependency job failed",
Details: []*clienterrors.Error{
{
ID: clienterrors.ErrorOSTreeDependency,
Reason: "ostree dependency job failed",
Details: []*clienterrors.Error{
{
ID: clienterrors.ErrorOSTreeRefResolution,
Reason: "remote ostree ref not found",
},
},
},
},
},
},
}
for idx, c := range cases {