cmd/osbuild-worker: add default OCI configuration

Useful for hosted deployments, where target options are often empty or
incomplete.
This commit is contained in:
Sanne Raymaekers 2023-09-06 13:49:05 +02:00
parent a7794dc634
commit a632848c59
5 changed files with 111 additions and 17 deletions

View file

@ -38,6 +38,10 @@ type awsConfig struct {
Bucket string `toml:"bucket"` Bucket string `toml:"bucket"`
} }
type ociConfig struct {
Credentials string `toml:"credentials"`
}
type genericS3Config struct { type genericS3Config struct {
Credentials string `toml:"credentials"` Credentials string `toml:"credentials"`
Endpoint string `toml:"endpoint"` Endpoint string `toml:"endpoint"`
@ -71,6 +75,7 @@ type workerConfig struct {
GenericS3 *genericS3Config `toml:"generic_s3"` GenericS3 *genericS3Config `toml:"generic_s3"`
Authentication *authenticationConfig `toml:"authentication"` Authentication *authenticationConfig `toml:"authentication"`
Containers *containersConfig `toml:"containers"` Containers *containersConfig `toml:"containers"`
OCI *ociConfig `toml:"oci"`
// default value: /api/worker/v1 // default value: /api/worker/v1
BasePath string `toml:"base_path"` BasePath string `toml:"base_path"`
DNFJson string `toml:"dnf-json"` DNFJson string `toml:"dnf-json"`

View file

@ -49,6 +49,9 @@ upload_threads = 8
credentials = "/etc/osbuild-worker/aws-creds" credentials = "/etc/osbuild-worker/aws-creds"
bucket = "buckethead" bucket = "buckethead"
[oci]
credentials = "/etc/osbuild-worker/oci-creds"
[generic_s3] [generic_s3]
credentials = "/etc/osbuild-worker/s3-creds" credentials = "/etc/osbuild-worker/s3-creds"
endpoint = "http://s3.example.com" endpoint = "http://s3.example.com"
@ -96,6 +99,9 @@ offline_token = "/etc/osbuild-worker/offline_token"
Credentials: "/etc/osbuild-worker/aws-creds", Credentials: "/etc/osbuild-worker/aws-creds",
Bucket: "buckethead", Bucket: "buckethead",
}, },
OCI: &ociConfig{
Credentials: "/etc/osbuild-worker/oci-creds",
},
GenericS3: &genericS3Config{ GenericS3: &genericS3Config{
Credentials: "/etc/osbuild-worker/s3-creds", Credentials: "/etc/osbuild-worker/s3-creds",
Endpoint: "http://s3.example.com", Endpoint: "http://s3.example.com",

View file

@ -58,12 +58,20 @@ type AzureConfiguration struct {
UploadThreads int UploadThreads int
} }
type OCIConfiguration struct {
ClientParams *oci.ClientParams
Compartment string
Bucket string
Namespace string
}
type OSBuildJobImpl struct { type OSBuildJobImpl struct {
Store string Store string
Output string Output string
KojiServers map[string]kojiServer KojiServers map[string]kojiServer
GCPConfig GCPConfiguration GCPConfig GCPConfiguration
AzureConfig AzureConfiguration AzureConfig AzureConfiguration
OCIConfig OCIConfiguration
AWSCreds string AWSCreds string
AWSBucket string AWSBucket string
S3Config S3Configuration S3Config S3Configuration
@ -179,6 +187,30 @@ func (impl *OSBuildJobImpl) getGCP(credentials []byte) (*gcp.GCP, error) {
} }
} }
// Takes the worker config as a base and overwrites it with both t1 and t2's options
func (impl *OSBuildJobImpl) getOCI(tcp oci.ClientParams) (oci.Client, error) {
var cp oci.ClientParams
if impl.OCIConfig.ClientParams != nil {
cp = *impl.OCIConfig.ClientParams
}
if tcp.User != "" {
cp.User = tcp.User
}
if tcp.Region != "" {
cp.Region = tcp.Region
}
if tcp.Tenancy != "" {
cp.Tenancy = tcp.Tenancy
}
if tcp.PrivateKey != "" {
cp.PrivateKey = tcp.PrivateKey
}
if tcp.Fingerprint != "" {
cp.Fingerprint = tcp.Fingerprint
}
return oci.NewClient(&cp)
}
func validateResult(result *worker.OSBuildJobResult, jobID string) { func validateResult(result *worker.OSBuildJobResult, jobID string) {
logWithId := logrus.WithField("jobId", jobID) logWithId := logrus.WithField("jobId", jobID)
if result.JobError != nil { if result.JobError != nil {
@ -848,7 +880,7 @@ func (impl *OSBuildJobImpl) Run(job worker.Job) error {
targetResult = target.NewOCITargetResult(nil) targetResult = target.NewOCITargetResult(nil)
// create an ociClient uploader with a valid storage client // create an ociClient uploader with a valid storage client
var ociClient oci.Client var ociClient oci.Client
ociClient, err = oci.NewClient(&oci.ClientParams{ ociClient, err = impl.getOCI(oci.ClientParams{
User: targetOptions.User, User: targetOptions.User,
Region: targetOptions.Region, Region: targetOptions.Region,
Tenancy: targetOptions.Tenancy, Tenancy: targetOptions.Tenancy,
@ -868,10 +900,18 @@ func (impl *OSBuildJobImpl) Run(job worker.Job) error {
} }
defer file.Close() defer file.Close()
i, _ := rand.Int(rand.Reader, big.NewInt(math.MaxInt64)) i, _ := rand.Int(rand.Reader, big.NewInt(math.MaxInt64))
bucket := impl.OCIConfig.Bucket
if targetOptions.Bucket != "" {
bucket = targetOptions.Bucket
}
namespace := impl.OCIConfig.Namespace
if targetOptions.Namespace != "" {
namespace = targetOptions.Namespace
}
err = ociClient.Upload( err = ociClient.Upload(
fmt.Sprintf("osbuild-upload-%d", i), fmt.Sprintf("osbuild-upload-%d", i),
targetOptions.Bucket, bucket,
targetOptions.Namespace, namespace,
file, file,
) )
if err != nil { if err != nil {
@ -879,11 +919,15 @@ func (impl *OSBuildJobImpl) Run(job worker.Job) error {
break break
} }
compartment := impl.OCIConfig.Compartment
if targetOptions.Compartment != "" {
compartment = targetOptions.Compartment
}
imageID, err := ociClient.CreateImage( imageID, err := ociClient.CreateImage(
fmt.Sprintf("osbuild-upload-%d", i), fmt.Sprintf("osbuild-upload-%d", i),
targetOptions.Bucket, bucket,
targetOptions.Namespace, namespace,
targetOptions.Compartment, compartment,
jobTarget.ImageName, jobTarget.ImageName,
) )
if err != nil { if err != nil {
@ -896,8 +940,7 @@ func (impl *OSBuildJobImpl) Run(job worker.Job) error {
case *target.OCIObjectStorageTargetOptions: case *target.OCIObjectStorageTargetOptions:
targetResult = target.NewOCIObjectStorageTargetResult(nil) targetResult = target.NewOCIObjectStorageTargetResult(nil)
// create an ociClient uploader with a valid storage client // create an ociClient uploader with a valid storage client
var ociClient oci.Client ociClient, err := impl.getOCI(oci.ClientParams{
ociClient, err = oci.NewClient(&oci.ClientParams{
User: targetOptions.User, User: targetOptions.User,
Region: targetOptions.Region, Region: targetOptions.Region,
Tenancy: targetOptions.Tenancy, Tenancy: targetOptions.Tenancy,
@ -917,10 +960,18 @@ func (impl *OSBuildJobImpl) Run(job worker.Job) error {
} }
defer file.Close() defer file.Close()
i, _ := rand.Int(rand.Reader, big.NewInt(math.MaxInt64)) i, _ := rand.Int(rand.Reader, big.NewInt(math.MaxInt64))
bucket := impl.OCIConfig.Bucket
if targetOptions.Bucket != "" {
bucket = targetOptions.Bucket
}
namespace := impl.OCIConfig.Namespace
if targetOptions.Namespace != "" {
namespace = targetOptions.Namespace
}
err = ociClient.Upload( err = ociClient.Upload(
fmt.Sprintf("osbuild-upload-%d", i), fmt.Sprintf("osbuild-upload-%d", i),
targetOptions.Bucket, bucket,
targetOptions.Namespace, namespace,
file, file,
) )
if err != nil { if err != nil {
@ -928,12 +979,12 @@ func (impl *OSBuildJobImpl) Run(job worker.Job) error {
break break
} }
uri, err := ociClient.PreAuthenticatedRequest(fmt.Sprintf("osbuild-upload-%d", i), targetOptions.Bucket, targetOptions.Namespace) uri, err := ociClient.PreAuthenticatedRequest(fmt.Sprintf("osbuild-upload-%d", i), bucket, namespace)
if err != nil { if err != nil {
targetResult.TargetError = clienterrors.WorkerClientError(clienterrors.ErrorGeneratingSignedURL, err.Error(), nil) targetResult.TargetError = clienterrors.WorkerClientError(clienterrors.ErrorGeneratingSignedURL, err.Error(), nil)
break break
} }
logWithId.Info("[OCI] 🎉 Image uploaded and registered!") logWithId.Info("[OCI] 🎉 Image uploaded and pre-authenticated request generated!")
targetResult.Options = &target.OCIObjectStorageTargetResultOptions{URL: uri} targetResult.Options = &target.OCIObjectStorageTargetResultOptions{URL: uri}
case *target.ContainerTargetOptions: case *target.ContainerTargetOptions:
targetResult = target.NewContainerTargetResult(nil) targetResult = target.NewContainerTargetResult(nil)

View file

@ -24,6 +24,7 @@ import (
"github.com/osbuild/osbuild-composer/internal/dnfjson" "github.com/osbuild/osbuild-composer/internal/dnfjson"
"github.com/osbuild/osbuild-composer/internal/upload/azure" "github.com/osbuild/osbuild-composer/internal/upload/azure"
"github.com/osbuild/osbuild-composer/internal/upload/koji" "github.com/osbuild/osbuild-composer/internal/upload/koji"
"github.com/osbuild/osbuild-composer/internal/upload/oci"
"github.com/osbuild/osbuild-composer/internal/worker" "github.com/osbuild/osbuild-composer/internal/worker"
) )
@ -395,6 +396,36 @@ func main() {
containersTLSVerify = config.Containers.TLSVerify containersTLSVerify = config.Containers.TLSVerify
} }
var ociConfig OCIConfiguration
if config.OCI != nil {
var creds struct {
User string `toml:"user"`
Tenancy string `toml:"tenancy"`
Region string `toml:"region"`
Fingerprint string `toml:"fingerprint"`
PrivateKey string `toml:"private_key"`
Bucket string `toml:"bucket"`
Namespace string `toml:"namespace"`
Compartment string `toml:"compartment"`
}
_, err := toml.DecodeFile(config.OCI.Credentials, &creds)
if err != nil {
logrus.Fatalf("cannot load oci credentials: %v", err)
}
ociConfig = OCIConfiguration{
ClientParams: &oci.ClientParams{
User: creds.User,
Region: creds.Region,
Tenancy: creds.Tenancy,
PrivateKey: creds.PrivateKey,
Fingerprint: creds.Fingerprint,
},
Bucket: creds.Bucket,
Namespace: creds.Namespace,
Compartment: creds.Compartment,
}
}
// depsolve jobs can be done during other jobs // depsolve jobs can be done during other jobs
depsolveCtx, depsolveCtxCancel := context.WithCancel(context.Background()) depsolveCtx, depsolveCtxCancel := context.WithCancel(context.Background())
solver := dnfjson.NewBaseSolver(rpmmd_cache) solver := dnfjson.NewBaseSolver(rpmmd_cache)
@ -438,6 +469,7 @@ func main() {
KojiServers: kojiServers, KojiServers: kojiServers,
GCPConfig: gcpConfig, GCPConfig: gcpConfig,
AzureConfig: azureConfig, AzureConfig: azureConfig,
OCIConfig: ociConfig,
AWSCreds: awsCredentials, AWSCreds: awsCredentials,
AWSBucket: awsBucket, AWSBucket: awsBucket,
S3Config: S3Configuration{ S3Config: S3Configuration{

View file

@ -238,11 +238,11 @@ func (c Client) createImage(objectName, bucketName, namespace, compartmentID, im
} }
type ClientParams struct { type ClientParams struct {
User string User string `toml:"user"`
Region string Region string `toml:"region"`
Tenancy string Tenancy string `toml:"tenancy"`
PrivateKey string PrivateKey string `toml:"private_key"`
Fingerprint string Fingerprint string `toml:"fingerprint"`
} }
type ociClient struct { type ociClient struct {