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

Weldr/Cloud API: simplify GCP upload options #3023

Merged
merged 10 commits into from
Oct 11, 2022
1 change: 1 addition & 0 deletions cmd/osbuild-worker/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ type kojiServerConfig struct {

type gcpConfig struct {
Credentials string `toml:"credentials"`
Bucket string `toml:"bucket"`
}

type azureConfig struct {
Expand Down
61 changes: 46 additions & 15 deletions cmd/osbuild-worker/jobimpl-osbuild.go
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,11 @@ import (
"github.com/osbuild/osbuild-composer/internal/worker/clienterrors"
)

type GCPConfiguration struct {
Creds string
Bucket string
}

type S3Configuration struct {
Creds string
Endpoint string
Expand All @@ -52,7 +57,7 @@ type OSBuildJobImpl struct {
Store string
Output string
KojiServers map[string]kojiServer
GCPCreds string
GCPConfig GCPConfiguration
AzureCreds *azure.Credentials
AWSCreds string
AWSBucket string
Expand Down Expand Up @@ -121,8 +126,11 @@ func (impl *OSBuildJobImpl) getAWSForS3Target(options *target.AWSS3TargetOptions
// Endpoint == "" && Region != "" => AWS (Weldr and Composer)
if options.Endpoint == "" && options.Region != "" {
aws, err = impl.getAWS(options.Region, options.AccessKeyID, options.SecretAccessKey, options.SessionToken)
if impl.AWSBucket != "" {
if bucket == "" {
bucket = impl.AWSBucket
if bucket == "" {
err = fmt.Errorf("No AWS bucket provided")
}
}
} else if options.Endpoint != "" && options.Region != "" { // Endpoint != "" && Region != "" => Generic S3 Weldr API
aws, err = impl.getAWSForS3TargetFromOptions(options)
Expand Down Expand Up @@ -157,9 +165,9 @@ func (impl *OSBuildJobImpl) getGCP(credentials []byte) (*gcp.GCP, error) {
if credentials != nil {
logrus.Info("[GCP] 🔑 using credentials provided with the job request")
return gcp.New(credentials)
} else if impl.GCPCreds != "" {
} else if impl.GCPConfig.Creds != "" {
logrus.Info("[GCP] 🔑 using credentials from the worker configuration")
return gcp.NewFromFile(impl.GCPCreds)
return gcp.NewFromFile(impl.GCPConfig.Creds)
} else {
logrus.Info("[GCP] 🔑 using Application Default Credentials via Google library")
return gcp.New(nil)
Expand Down Expand Up @@ -465,14 +473,18 @@ func (impl *OSBuildJobImpl) Run(job worker.Job) error {
break
}

key := targetOptions.Key
if key == "" {
key = uuid.New().String()
if targetOptions.Key == "" {
targetResult.TargetError = clienterrors.WorkerClientError(clienterrors.ErrorInvalidTargetConfig, "No AWS object key provided", nil)
break
}

bucket := targetOptions.Bucket
thozza marked this conversation as resolved.
Show resolved Hide resolved
if impl.AWSBucket != "" {
if bucket == "" {
thozza marked this conversation as resolved.
Show resolved Hide resolved
bucket = impl.AWSBucket
if bucket == "" {
targetResult.TargetError = clienterrors.WorkerClientError(clienterrors.ErrorInvalidTargetConfig, "No AWS bucket provided", nil)
break
}
}

// TODO: Remove this once multiple exports will be supported and used by image definitions
Expand All @@ -489,13 +501,13 @@ func (impl *OSBuildJobImpl) Run(job worker.Job) error {
}
}

_, err = a.Upload(imagePath, bucket, key)
_, err = a.Upload(imagePath, bucket, targetOptions.Key)
if err != nil {
targetResult.TargetError = clienterrors.WorkerClientError(clienterrors.ErrorUploadingImage, err.Error(), nil)
break
}

ami, err := a.Register(jobTarget.ImageName, bucket, key, targetOptions.ShareWithAccounts, common.CurrentArch())
ami, err := a.Register(jobTarget.ImageName, bucket, targetOptions.Key, targetOptions.ShareWithAccounts, common.CurrentArch())
if err != nil {
targetResult.TargetError = clienterrors.WorkerClientError(clienterrors.ErrorImportingImage, err.Error(), nil)
break
Expand All @@ -518,6 +530,11 @@ func (impl *OSBuildJobImpl) Run(job worker.Job) error {
break
}

if targetOptions.Key == "" {
targetResult.TargetError = clienterrors.WorkerClientError(clienterrors.ErrorInvalidTargetConfig, "No AWS object key provided", nil)
break
}

url, targetError := uploadToS3(a, outputDirectory, jobTarget.OsbuildArtifact.ExportName, bucket, targetOptions.Key, jobTarget.OsbuildArtifact.ExportFilename, targetOptions.Public)
if targetError != nil {
targetResult.TargetError = targetError
Expand Down Expand Up @@ -563,24 +580,38 @@ func (impl *OSBuildJobImpl) Run(job worker.Job) error {
break
}

logWithId.Infof("[GCP] 🚀 Uploading image to: %s/%s", targetOptions.Bucket, targetOptions.Object)
if targetOptions.Object == "" {
targetResult.TargetError = clienterrors.WorkerClientError(clienterrors.ErrorInvalidTargetConfig, "No GCP object key provided", nil)
break
}

bucket := targetOptions.Bucket
thozza marked this conversation as resolved.
Show resolved Hide resolved
if bucket == "" {
bucket = impl.GCPConfig.Bucket
if bucket == "" {
targetResult.TargetError = clienterrors.WorkerClientError(clienterrors.ErrorInvalidTargetConfig, "No GCP bucket provided", nil)
break
}
}

logWithId.Infof("[GCP] 🚀 Uploading image to: %s/%s", bucket, targetOptions.Object)
_, err = g.StorageObjectUpload(ctx, path.Join(outputDirectory, jobTarget.OsbuildArtifact.ExportName, jobTarget.OsbuildArtifact.ExportFilename),
targetOptions.Bucket, targetOptions.Object, map[string]string{gcp.MetadataKeyImageName: jobTarget.ImageName})
bucket, targetOptions.Object, map[string]string{gcp.MetadataKeyImageName: jobTarget.ImageName})
if err != nil {
targetResult.TargetError = clienterrors.WorkerClientError(clienterrors.ErrorUploadingImage, err.Error(), nil)
break
}

logWithId.Infof("[GCP] 📥 Importing image into Compute Engine as '%s'", jobTarget.ImageName)

_, importErr := g.ComputeImageInsert(ctx, targetOptions.Bucket, targetOptions.Object, jobTarget.ImageName, []string{targetOptions.Region}, gcp.GuestOsFeaturesByDistro(targetOptions.Os))
_, importErr := g.ComputeImageInsert(ctx, bucket, targetOptions.Object, jobTarget.ImageName, []string{targetOptions.Region}, gcp.GuestOsFeaturesByDistro(targetOptions.Os))
if importErr == nil {
logWithId.Infof("[GCP] 🎉 Image import finished successfully")
}

// Cleanup storage before checking for errors
logWithId.Infof("[GCP] 🧹 Deleting uploaded image file: %s/%s", targetOptions.Bucket, targetOptions.Object)
if err = g.StorageObjectDelete(ctx, targetOptions.Bucket, targetOptions.Object); err != nil {
logWithId.Infof("[GCP] 🧹 Deleting uploaded image file: %s/%s", bucket, targetOptions.Object)
if err = g.StorageObjectDelete(ctx, bucket, targetOptions.Object); err != nil {
logWithId.Errorf("[GCP] Encountered error while deleting object: %v", err)
}

Expand Down
7 changes: 4 additions & 3 deletions cmd/osbuild-worker/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -351,9 +351,10 @@ func main() {

// If the credentials are not provided in the configuration, then the
// worker will rely on the GCP library to authenticate using default means.
var gcpCredentials string
var gcpConfig GCPConfiguration
if config.GCP != nil {
gcpCredentials = config.GCP.Credentials
gcpConfig.Creds = config.GCP.Credentials
gcpConfig.Bucket = config.GCP.Bucket
}

// If the credentials are not provided in the configuration, then the
Expand Down Expand Up @@ -435,7 +436,7 @@ func main() {
Store: store,
Output: output,
KojiServers: kojiServers,
GCPCreds: gcpCredentials,
GCPConfig: gcpConfig,
AzureCreds: azureCredentials,
AWSCreds: awsCredentials,
AWSBucket: awsBucket,
Expand Down
6 changes: 5 additions & 1 deletion internal/cloudapi/v2/handler.go
Original file line number Diff line number Diff line change
Expand Up @@ -448,10 +448,14 @@ func (h *apiHandlers) PostCompose(ctx echo.Context) error {
}

imageName := fmt.Sprintf("composer-api-%s", uuid.New().String())
var bucket string
if gcpUploadOptions.Bucket != nil {
bucket = *gcpUploadOptions.Bucket
}
t := target.NewGCPTarget(&target.GCPTargetOptions{
Region: gcpUploadOptions.Region,
Os: imageType.Arch().Distro().Name(), // not exposed in cloudapi
Bucket: gcpUploadOptions.Bucket,
Bucket: bucket,
// the uploaded object must have a valid extension
Object: fmt.Sprintf("%s.tar.gz", imageName),
ShareWithAccounts: share,
Expand Down
138 changes: 69 additions & 69 deletions internal/cloudapi/v2/openapi.v2.gen.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 0 additions & 1 deletion internal/cloudapi/v2/openapi.v2.yml
Original file line number Diff line number Diff line change
Expand Up @@ -862,7 +862,6 @@ components:
type: object
required:
- region
- bucket
properties:
region:
type: string
Expand Down
Loading