Blame cmd/osbuild-worker/main.go

Packit 63bb0d
package main
Packit 63bb0d
Packit 63bb0d
import (
Packit 63bb0d
	"context"
Packit 63bb0d
	"crypto/tls"
Packit 63bb0d
	"crypto/x509"
Packit 63bb0d
	"errors"
Packit 63bb0d
	"flag"
Packit 63bb0d
	"fmt"
Packit 63bb0d
	"io/ioutil"
Packit 63bb0d
	"log"
Packit 63bb0d
	"os"
Packit 63bb0d
	"path"
Packit 63bb0d
	"time"
Packit 63bb0d
Packit Service 509fd4
	"github.com/BurntSushi/toml"
Packit Service 509fd4
Packit Service 509fd4
	"github.com/osbuild/osbuild-composer/internal/upload/koji"
Packit 63bb0d
	"github.com/osbuild/osbuild-composer/internal/worker"
Packit 63bb0d
)
Packit 63bb0d
Packit Service 509fd4
const configFile = "/etc/osbuild-worker/osbuild-worker.toml"
Packit Service 509fd4
Packit 63bb0d
type connectionConfig struct {
Packit 63bb0d
	CACertFile     string
Packit 63bb0d
	ClientKeyFile  string
Packit 63bb0d
	ClientCertFile string
Packit 63bb0d
}
Packit 63bb0d
Packit Service 509fd4
// Represents the implementation of a job type as defined by the worker API.
Packit Service 509fd4
type JobImplementation interface {
Packit Service 509fd4
	Run(job worker.Job) error
Packit Service 509fd4
}
Packit Service 509fd4
Packit 63bb0d
func createTLSConfig(config *connectionConfig) (*tls.Config, error) {
Packit 63bb0d
	caCertPEM, err := ioutil.ReadFile(config.CACertFile)
Packit 63bb0d
	if err != nil {
Packit 63bb0d
		return nil, err
Packit 63bb0d
	}
Packit 63bb0d
Packit 63bb0d
	roots := x509.NewCertPool()
Packit 63bb0d
	ok := roots.AppendCertsFromPEM(caCertPEM)
Packit 63bb0d
	if !ok {
Packit 63bb0d
		return nil, errors.New("failed to append root certificate")
Packit 63bb0d
	}
Packit 63bb0d
Packit 63bb0d
	cert, err := tls.LoadX509KeyPair(config.ClientCertFile, config.ClientKeyFile)
Packit 63bb0d
	if err != nil {
Packit 63bb0d
		return nil, err
Packit 63bb0d
	}
Packit 63bb0d
Packit 63bb0d
	return &tls.Config{
Packit 63bb0d
		RootCAs:      roots,
Packit 63bb0d
		Certificates: []tls.Certificate{cert},
Packit 63bb0d
	}, nil
Packit 63bb0d
}
Packit 63bb0d
Packit 63bb0d
// Regularly ask osbuild-composer if the compose we're currently working on was
Packit 63bb0d
// canceled and exit the process if it was.
Packit 63bb0d
// It would be cleaner to kill the osbuild process using (`exec.CommandContext`
Packit 63bb0d
// or similar), but osbuild does not currently support this. Exiting here will
Packit 63bb0d
// make systemd clean up the whole cgroup and restart this service.
Packit Service 509fd4
func WatchJob(ctx context.Context, job worker.Job) {
Packit 63bb0d
	for {
Packit 63bb0d
		select {
Packit 63bb0d
		case <-time.After(15 * time.Second):
Packit Service 509fd4
			canceled, err := job.Canceled()
Packit Service 509fd4
			if err == nil && canceled {
Packit 63bb0d
				log.Println("Job was canceled. Exiting.")
Packit 63bb0d
				os.Exit(0)
Packit 63bb0d
			}
Packit 63bb0d
		case <-ctx.Done():
Packit 63bb0d
			return
Packit 63bb0d
		}
Packit 63bb0d
	}
Packit 63bb0d
}
Packit 63bb0d
Packit 63bb0d
func main() {
Packit Service 509fd4
	var config struct {
Packit Service 509fd4
		KojiServers map[string]struct {
Packit Service 509fd4
			Kerberos *struct {
Packit Service 509fd4
				Principal string `toml:"principal"`
Packit Service 509fd4
				KeyTab    string `toml:"keytab"`
Packit Service 509fd4
			} `toml:"kerberos,omitempty"`
Packit Service 509fd4
		} `toml:"koji"`
Packit Service 509fd4
	}
Packit 63bb0d
	var unix bool
Packit 63bb0d
	flag.BoolVar(&unix, "unix", false, "Interpret 'address' as a path to a unix domain socket instead of a network address")
Packit 63bb0d
Packit 63bb0d
	flag.Usage = func() {
Packit 63bb0d
		fmt.Fprintf(flag.CommandLine.Output(), "Usage: %s [-unix] address\n", os.Args[0])
Packit 63bb0d
		flag.PrintDefaults()
Packit 63bb0d
		os.Exit(0)
Packit 63bb0d
	}
Packit 63bb0d
Packit 63bb0d
	flag.Parse()
Packit 63bb0d
Packit 63bb0d
	address := flag.Arg(0)
Packit 63bb0d
	if address == "" {
Packit 63bb0d
		flag.Usage()
Packit 63bb0d
	}
Packit 63bb0d
Packit Service 509fd4
	_, err := toml.DecodeFile(configFile, &config)
Packit Service 509fd4
	if err == nil {
Packit Service 509fd4
		log.Println("Composer configuration:")
Packit Service 509fd4
		encoder := toml.NewEncoder(log.Writer())
Packit Service 509fd4
		err := encoder.Encode(&config)
Packit Service 509fd4
		if err != nil {
Packit Service 509fd4
			log.Fatalf("Could not print config: %v", err)
Packit Service 509fd4
		}
Packit Service 509fd4
	} else if !os.IsNotExist(err) {
Packit Service 509fd4
		log.Fatalf("Could not load config file '%s': %v", configFile, err)
Packit Service 509fd4
	}
Packit Service 509fd4
Packit 63bb0d
	cacheDirectory, ok := os.LookupEnv("CACHE_DIRECTORY")
Packit 63bb0d
	if !ok {
Packit 63bb0d
		log.Fatal("CACHE_DIRECTORY is not set. Is the service file missing CacheDirectory=?")
Packit 63bb0d
	}
Packit 63bb0d
	store := path.Join(cacheDirectory, "osbuild-store")
Packit 63bb0d
Packit Service 509fd4
	kojiServers := make(map[string]koji.GSSAPICredentials)
Packit Service 509fd4
	for server, creds := range config.KojiServers {
Packit Service 509fd4
		if creds.Kerberos == nil {
Packit Service 509fd4
			// For now we only support Kerberos authentication.
Packit Service 509fd4
			continue
Packit Service 509fd4
		}
Packit Service 509fd4
		kojiServers[server] = koji.GSSAPICredentials{
Packit Service 509fd4
			Principal: creds.Kerberos.Principal,
Packit Service 509fd4
			KeyTab:    creds.Kerberos.KeyTab,
Packit Service 509fd4
		}
Packit Service 509fd4
	}
Packit Service 509fd4
Packit 63bb0d
	var client *worker.Client
Packit 63bb0d
	if unix {
Packit 63bb0d
		client = worker.NewClientUnix(address)
Packit 63bb0d
	} else {
Packit 63bb0d
		conf, err := createTLSConfig(&connectionConfig{
Packit 63bb0d
			CACertFile:     "/etc/osbuild-composer/ca-crt.pem",
Packit 63bb0d
			ClientKeyFile:  "/etc/osbuild-composer/worker-key.pem",
Packit 63bb0d
			ClientCertFile: "/etc/osbuild-composer/worker-crt.pem",
Packit 63bb0d
		})
Packit 63bb0d
		if err != nil {
Packit 63bb0d
			log.Fatalf("Error creating TLS config: %v", err)
Packit 63bb0d
		}
Packit 63bb0d
Packit Service 509fd4
		client, err = worker.NewClient("https://"+address, conf)
Packit Service 509fd4
		if err != nil {
Packit Service 509fd4
			log.Fatalf("Error creating worker client: %v", err)
Packit Service 509fd4
		}
Packit Service 509fd4
	}
Packit Service 509fd4
Packit Service 509fd4
	jobImpls := map[string]JobImplementation{
Packit Service 509fd4
		"osbuild": &OSBuildJobImpl{
Packit Service 509fd4
			Store:       store,
Packit Service 509fd4
			KojiServers: kojiServers,
Packit Service 509fd4
		},
Packit Service 509fd4
		"osbuild-koji": &OSBuildKojiJobImpl{
Packit Service 509fd4
			Store:       store,
Packit Service 509fd4
			KojiServers: kojiServers,
Packit Service 509fd4
		},
Packit Service 509fd4
		"koji-init": &KojiInitJobImpl{
Packit Service 509fd4
			KojiServers: kojiServers,
Packit Service 509fd4
		},
Packit Service 509fd4
		"koji-finalize": &KojiFinalizeJobImpl{
Packit Service 509fd4
			KojiServers: kojiServers,
Packit Service 509fd4
		},
Packit Service 509fd4
	}
Packit Service 509fd4
Packit Service 509fd4
	acceptedJobTypes := []string{}
Packit Service 509fd4
	for jt := range jobImpls {
Packit Service 509fd4
		acceptedJobTypes = append(acceptedJobTypes, jt)
Packit 63bb0d
	}
Packit 63bb0d
Packit 63bb0d
	for {
Packit 63bb0d
		fmt.Println("Waiting for a new job...")
Packit Service 509fd4
		job, err := client.RequestJob(acceptedJobTypes)
Packit 63bb0d
		if err != nil {
Packit 63bb0d
			log.Fatal(err)
Packit 63bb0d
		}
Packit 63bb0d
Packit Service 509fd4
		impl, exists := jobImpls[job.Type()]
Packit Service 509fd4
		if !exists {
Packit Service 509fd4
			log.Printf("Ignoring job with unknown type %s", job.Type())
Packit Service 509fd4
			continue
Packit 63bb0d
		}
Packit 63bb0d
Packit Service 509fd4
		fmt.Printf("Running '%s' job %v\n", job.Type(), job.Id())
Packit 63bb0d
Packit Service 509fd4
		ctx, cancelWatcher := context.WithCancel(context.Background())
Packit Service 509fd4
		go WatchJob(ctx, job)
Packit Service 509fd4
Packit Service 509fd4
		err = impl.Run(job)
Packit Service 509fd4
		cancelWatcher()
Packit 63bb0d
		if err != nil {
Packit Service 509fd4
			log.Printf("Job %s failed: %v", job.Id(), err)
Packit Service 509fd4
			continue
Packit 63bb0d
		}
Packit Service 509fd4
Packit Service 509fd4
		log.Printf("Job %s finished", job.Id())
Packit 63bb0d
	}
Packit 63bb0d
}