Add support for OCI upload provider

Signed-off-by: Roy Golan <rgolan@redhat.com>
This commit is contained in:
Roy Golan 2021-11-18 09:52:25 +02:00 committed by Sanne Raymaekers
parent d9051c23e6
commit bee932e222
18 changed files with 495 additions and 4 deletions

View file

@ -115,6 +115,7 @@ build:
go build -o bin/osbuild-upload-azure ./cmd/osbuild-upload-azure/
go build -o bin/osbuild-upload-aws ./cmd/osbuild-upload-aws/
go build -o bin/osbuild-upload-gcp ./cmd/osbuild-upload-gcp/
go build -o bin/osbuild-upload-oci ./cmd/osbuild-upload-oci/
go build -o bin/osbuild-mock-openid-provider ./cmd/osbuild-mock-openid-provider
go build -o bin/osbuild-service-maintenance ./cmd/osbuild-service-maintenance
go test -c -tags=integration -o bin/osbuild-composer-cli-tests ./cmd/osbuild-composer-cli-tests/main_test.go

View file

@ -0,0 +1,104 @@
package main
import (
"crypto/rand"
"fmt"
"github.com/osbuild/osbuild-composer/internal/upload/oci"
"github.com/spf13/cobra"
"io/ioutil"
"math"
"math/big"
"os"
)
var (
tenancy string
region string
userID string
privateKeyFile string
fingerprint string
bucketName string
bucketNamespace string
fileName string
objectName string
compartment string
)
var uploadCmd = &cobra.Command{
Example: "This tool uses the $HOME/.oci/config file to create the OCI client and can be\noverridden using CLI flags.",
SilenceUsage: true,
RunE: func(cmd *cobra.Command, args []string) error {
uploader, err := uploaderFromConfig()
if err != nil {
return err
}
file, err := os.Open(fileName)
if err != nil {
return err
}
defer file.Close()
imageID, err := uploader.Upload(objectName, bucketName, bucketNamespace, file, compartment, fileName)
if err != nil {
return fmt.Errorf("failed to upload the image: %v", err)
}
fmt.Printf("Image %s was uploaded and created successfully\n", imageID)
return nil
},
}
func main() {
i, _ := rand.Int(rand.Reader, big.NewInt(math.MaxInt64))
uploadCmd.Flags().StringVarP(&tenancy, "tenancy", "t", "", "target tenancy")
uploadCmd.Flags().StringVarP(&region, "region", "r", "", "target region")
uploadCmd.Flags().StringVarP(&userID, "user-id", "u", "", "user OCI ID")
uploadCmd.Flags().StringVarP(&bucketName, "bucket-name", "b", "", "target OCI bucket name")
uploadCmd.Flags().StringVarP(&bucketNamespace, "bucket-namespace", "", "", "target OCI bucket namespace")
uploadCmd.Flags().StringVarP(&fileName, "filename", "f", "", "image file to upload")
uploadCmd.Flags().StringVarP(&objectName, "object-name", "o", fmt.Sprintf("osbuild-upload-%v", i), "the target name of the uploaded object in the bucket")
uploadCmd.Flags().StringVarP(&privateKeyFile, "private-key", "p", "", "private key for authenticating OCI API requests")
uploadCmd.Flags().StringVarP(&fingerprint, "fingerprint", "", "", "the private key's fingerprint")
uploadCmd.Flags().StringVarP(&compartment, "compartment-id", "c", "", "the compartment ID of the target image")
_ = uploadCmd.MarkFlagRequired("bucket-name")
_ = uploadCmd.MarkFlagRequired("bucket-namespace")
_ = uploadCmd.MarkFlagRequired("compartment-id")
_ = uploadCmd.MarkFlagRequired("filename")
if err := uploadCmd.Execute(); err != nil {
fmt.Fprintln(os.Stderr, err)
os.Exit(1)
}
}
func uploaderFromConfig() (oci.Uploader, error) {
if privateKeyFile != "" {
if tenancy == "" || region == "" || userID == "" || fingerprint == "" {
return nil, fmt.Errorf("when suppling a private key the following args are mandatory as well:" +
" fingerprint, tenancy, region, and user-id")
}
pk, err := ioutil.ReadFile(privateKeyFile)
if err != nil {
return nil, fmt.Errorf("failed to read private key file %w", err)
}
uploader, err := oci.NewClient(
&oci.ClientParams{
Tenancy: tenancy,
User: userID,
Region: region,
PrivateKey: string(pk),
Fingerprint: fingerprint,
})
if err != nil {
return nil, fmt.Errorf("failed to create an OCI client %w", err)
}
return uploader, nil
}
fmt.Printf("Creating an uploader from default config\n")
uploader, err := oci.NewClient(nil)
if err != nil {
return nil, err
}
return uploader, nil
}

View file

@ -2,12 +2,18 @@ package main
import (
"context"
"crypto/rand"
"fmt"
"io/ioutil"
"log"
"math"
"math/big"
"os"
"path"
"strings"
"github.com/osbuild/osbuild-composer/internal/upload/oci"
"github.com/google/uuid"
"github.com/sirupsen/logrus"
@ -517,6 +523,49 @@ func (impl *OSBuildJobImpl) Run(job worker.Job) error {
ImageName: args.Targets[0].ImageName,
}))
osbuildJobResult.Success = true
osbuildJobResult.UploadStatus = "success"
case *target.OCITargetOptions:
// create an ociClient uploader with a valid storage client
var ociClient oci.Client
ociClient, err = oci.NewClient(&oci.ClientParams{
User: options.User,
Region: options.Region,
Tenancy: options.Tenancy,
Fingerprint: options.Fingerprint,
PrivateKey: options.PrivateKey,
})
if err != nil {
appendTargetError(osbuildJobResult, fmt.Errorf("failed to create an OCI uploder: %w", err))
return nil
}
log.Print("[OCI] 🔑 Logged in OCI")
log.Print("[OCI] ⬆ Uploading the image")
file, err := os.Open(path.Join(outputDirectory, exportPath, options.FileName))
if err != nil {
appendTargetError(osbuildJobResult, fmt.Errorf("failed to create an OCI uploder: %w", err))
return nil
}
defer file.Close()
i, _ := rand.Int(rand.Reader, big.NewInt(math.MaxInt64))
imageID, err := ociClient.Upload(
fmt.Sprintf("osbuild-upload-%d", i),
options.Bucket,
options.Namespace,
file,
options.Compartment,
args.Targets[0].ImageName,
)
if err != nil {
appendTargetError(osbuildJobResult, fmt.Errorf("failed to upload the image: %w", err))
return nil
}
log.Print("[OCI] 🎉 Image uploaded and registered!")
osbuildJobResult.TargetResults = append(
osbuildJobResult.TargetResults,
target.NewOCITargetResult(&target.OCITargetResultOptions{ImageID: imageID}),
)
osbuildJobResult.Success = true
osbuildJobResult.UploadStatus = "success"
default:

View file

@ -900,6 +900,40 @@ func newDistro(name, modulePlatformID, ostreeRef string) distro.Distro {
},
}
ociImageType := imageType{
name: "oci",
filename: "disk.qcow2",
mimeType: "application/x-qemu-disk",
packages: []string{
"@Fedora Cloud Server",
"chrony",
"systemd-udev",
"selinux-policy-targeted",
"langpacks-en",
},
excludedPackages: []string{
"dracut-config-rescue",
"etables",
"firewalld",
"geolite2-city",
"geolite2-country",
"gobject-introspection",
"plymouth",
"zram-generator-defaults",
},
enabledServices: []string{
"cloud-init.service",
"cloud-config.service",
"cloud-final.service",
"cloud-init-local.service",
},
bootable: true,
defaultSize: 2 * GigaByte,
assembler: func(uefi bool, options distro.ImageOptions, arch distro.Arch) *osbuild.Assembler {
return qemuAssembler("qcow2", "disk.qcow2", uefi, options)
},
}
r := distribution{
buildPackages: []string{
"dnf",
@ -935,6 +969,7 @@ func newDistro(name, modulePlatformID, ostreeRef string) distro.Distro {
openstackImgType,
vhdImgType,
vmdkImgType,
ociImageType,
)
aarch64 := architecture{
@ -953,6 +988,7 @@ func newDistro(name, modulePlatformID, ostreeRef string) distro.Distro {
amiImgType,
qcow2ImageType,
openstackImgType,
ociImageType,
)
r.setArches(x8664, aarch64)

View file

@ -710,6 +710,25 @@ func newDistro(name, modulePlatformID, ostreeRef string) distro.Distro {
basePartitionTables: defaultBasePartitionTables,
}
ociImageType := imageType{
name: "oci",
filename: "disk.qcow2",
mimeType: "application/x-qemu-disk",
defaultTarget: "multi-user.target",
kernelOptions: "console=tty0 console=ttyS0,115200n8 no_timer_check net.ifnames=0 crashkernel=auto",
packageSets: map[string]packageSetFunc{
buildPkgsKey: distroBuildPackageSet,
osPkgsKey: qcow2CommonPackageSet,
},
bootable: true,
defaultSize: 10 * GigaByte,
pipelines: qcow2Pipelines,
buildPipelines: []string{"build"},
payloadPipelines: []string{"os", "image", "qcow2"},
exports: []string{"qcow2"},
basePartitionTables: defaultBasePartitionTables,
}
// EC2 services
ec2EnabledServices := []string{
"sshd",
@ -862,7 +881,7 @@ func newDistro(name, modulePlatformID, ostreeRef string) distro.Distro {
exports: []string{"bootiso"},
}
x86_64.addImageTypes(qcow2ImgType, vhdImgType, vmdkImgType, openstackImgType, amiImgTypeX86_64, ec2ImgTypeX86_64, ec2HaImgTypeX86_64, tarImgType, tarInstallerImgTypeX86_64, edgeCommitImgType, edgeInstallerImgType, edgeOCIImgType, edgeRawImgType, edgeSimplifiedInstallerImgType)
x86_64.addImageTypes(qcow2ImgType, vhdImgType, vmdkImgType, openstackImgType, amiImgTypeX86_64, ec2ImgTypeX86_64, ec2HaImgTypeX86_64, tarImgType, tarInstallerImgTypeX86_64, edgeCommitImgType, edgeInstallerImgType, edgeOCIImgType, edgeRawImgType, edgeSimplifiedInstallerImgType, ociImageType)
aarch64.addImageTypes(qcow2ImgType, openstackImgType, amiImgTypeAarch64, ec2ImgTypeAarch64, tarImgType, edgeCommitImgType, edgeInstallerImgType, edgeOCIImgType, edgeRawImgType, edgeSimplifiedInstallerImgType)
ppc64le.addImageTypes(qcow2ImgType, tarImgType)
s390x.addImageTypes(qcow2ImgType, tarImgType)

View file

@ -452,6 +452,7 @@ func TestArchitecture_ListImageTypes(t *testing.T) {
"edge-simplified-installer",
"tar",
"image-installer",
"oci",
},
},
{

View file

@ -1259,7 +1259,10 @@ func newDistro(distroName string) distro.Distro {
exports: []string{"bootiso"},
}
x86_64.addImageTypes(qcow2ImgType, vhdImgType, vmdkImgType, openstackImgType, amiImgTypeX86_64, tarImgType, tarInstallerImgTypeX86_64, edgeCommitImgType, edgeInstallerImgType, edgeOCIImgType, edgeRawImgType, edgeSimplifiedInstallerImgType)
ociImgType := qcow2ImgType
ociImgType.name = "oci"
x86_64.addImageTypes(qcow2ImgType, vhdImgType, vmdkImgType, openstackImgType, amiImgTypeX86_64, tarImgType, tarInstallerImgTypeX86_64, edgeCommitImgType, edgeInstallerImgType, edgeOCIImgType, edgeRawImgType, edgeSimplifiedInstallerImgType, ociImgType)
aarch64.addImageTypes(qcow2ImgType, openstackImgType, amiImgTypeAarch64, tarImgType, edgeCommitImgType, edgeInstallerImgType, edgeOCIImgType, edgeRawImgType, edgeSimplifiedInstallerImgType)
ppc64le.addImageTypes(qcow2ImgType, tarImgType)
s390x.addImageTypes(qcow2ImgType, tarImgType)

View file

@ -462,6 +462,7 @@ func TestArchitecture_ListImageTypes(t *testing.T) {
"edge-simplified-installer",
"tar",
"image-installer",
"oci",
},
},
{

View file

@ -1260,7 +1260,10 @@ func newDistro(distroName string) distro.Distro {
exports: []string{"bootiso"},
}
x86_64.addImageTypes(qcow2ImgType, vhdImgType, vmdkImgType, openstackImgType, amiImgTypeX86_64, tarImgType, tarInstallerImgTypeX86_64, edgeCommitImgType, edgeInstallerImgType, edgeOCIImgType, edgeRawImgType, edgeSimplifiedInstallerImgType)
ociImgType := qcow2ImgType
ociImgType.name = "oci"
x86_64.addImageTypes(qcow2ImgType, vhdImgType, vmdkImgType, openstackImgType, amiImgTypeX86_64, tarImgType, tarInstallerImgTypeX86_64, edgeCommitImgType, edgeInstallerImgType, edgeOCIImgType, edgeRawImgType, edgeSimplifiedInstallerImgType, ociImgType)
aarch64.addImageTypes(qcow2ImgType, openstackImgType, amiImgTypeAarch64, tarImgType, edgeCommitImgType, edgeInstallerImgType, edgeOCIImgType, edgeRawImgType, edgeSimplifiedInstallerImgType)
ppc64le.addImageTypes(qcow2ImgType, tarImgType)
s390x.addImageTypes(qcow2ImgType, tarImgType)

View file

@ -462,6 +462,7 @@ func TestArchitecture_ListImageTypes(t *testing.T) {
"edge-simplified-installer",
"tar",
"image-installer",
"oci",
},
},
{

View file

@ -871,7 +871,10 @@ func newDistro(name, modulePlatformID, ostreeRef string) distro.Distro {
exports: []string{"bootiso"},
}
x86_64.addImageTypes(qcow2ImgType, vhdImgType, vmdkImgType, openstackImgType, amiImgTypeX86_64, ec2ImgTypeX86_64, ec2HaImgTypeX86_64, ec2SapImgTypeX86_64, tarImgType, tarInstallerImgTypeX86_64, edgeCommitImgType, edgeInstallerImgType, edgeOCIImgType)
ociImgtype := qcow2ImgType
ociImgtype.name = "oci"
x86_64.addImageTypes(qcow2ImgType, vhdImgType, vmdkImgType, openstackImgType, amiImgTypeX86_64, ec2ImgTypeX86_64, ec2HaImgTypeX86_64, ec2SapImgTypeX86_64, tarImgType, tarInstallerImgTypeX86_64, edgeCommitImgType, edgeInstallerImgType, edgeOCIImgType, ociImgtype)
aarch64.addImageTypes(qcow2ImgType, openstackImgType, amiImgTypeAarch64, ec2ImgTypeAarch64, tarImgType, edgeCommitImgType, edgeOCIImgType)
ppc64le.addImageTypes(qcow2ImgType, tarImgType)
s390x.addImageTypes(qcow2ImgType, tarImgType)

View file

@ -458,6 +458,7 @@ func TestArchitecture_ListImageTypes(t *testing.T) {
"edge-installer",
"tar",
"image-installer",
"oci",
},
},
{

View file

@ -366,6 +366,7 @@ var imageTypeCompatMapping = map[string]string{
"test_type_invalid": "test_type_invalid", // used only in json_test.go
"ec2": "ec2",
"ec2-ha": "ec2-ha",
"oci": "oci",
}
func imageTypeToCompatString(imgType distro.ImageType) string {

View file

@ -0,0 +1,30 @@
package target
type OCITargetOptions struct {
User string `json:"user"`
Tenancy string `json:"tenancy"`
Region string `json:"region"`
FileName string `json:"filename"`
Fingerprint string `json:"fingerprint"`
PrivateKey string `json:"private_key"`
Bucket string `json:"bucket"`
Namespace string `json:"namespace"`
Compartment string `json:"compartment_id"`
}
func (OCITargetOptions) isTargetOptions() {}
func NewOCITarget(options *OCITargetOptions) *Target {
return newTarget("org.osbuild.oci", options)
}
type OCITargetResultOptions struct {
Region string `json:"region"`
ImageID string `json:"image_id"`
}
func (OCITargetResultOptions) isTargetResultOptions() {}
func NewOCITargetResult(options *OCITargetResultOptions) *TargetResult {
return newTargetResult("org.osbuild.oci", options)
}

View file

@ -81,6 +81,8 @@ func UnmarshalTargetOptions(targetName string, rawOptions json.RawMessage) (Targ
options = new(KojiTargetOptions)
case "org.osbuild.vmware":
options = new(VMWareTargetOptions)
case "org.osbuild.oci":
options = new(OCITargetOptions)
default:
return nil, errors.New("unexpected target name")
}

View file

@ -53,6 +53,8 @@ func UnmarshalTargetResultOptions(trName string, rawOptions json.RawMessage) (Ta
options = new(GCPTargetResultOptions)
case "org.osbuild.azure.image":
options = new(AzureImageTargetResultOptions)
case "org.osbuild.oci":
options = new(OCITargetResultOptions)
default:
return nil, fmt.Errorf("Unexpected target result name: %s", trName)
}

View file

@ -0,0 +1,206 @@
package oci
import (
"context"
"fmt"
"log"
"net/http"
"os"
"time"
"github.com/oracle/oci-go-sdk/v54/common"
"github.com/oracle/oci-go-sdk/v54/core"
"github.com/oracle/oci-go-sdk/v54/identity"
"github.com/oracle/oci-go-sdk/v54/objectstorage"
"github.com/oracle/oci-go-sdk/v54/objectstorage/transfer"
"github.com/oracle/oci-go-sdk/v54/workrequests"
)
type Uploader interface {
Upload(name string, bucketName string, namespace string, file *os.File, user, compartment string) (string, error)
}
type ImageCreator interface {
create(imageName, bucketName, namespace, compartmentID string) (string, error)
}
type Client struct {
Uploader
ImageCreator
ociClient
}
// Upload uploads a file into an objectName under the bucketName in the namespace.
func (c Client) Upload(objectName string, bucketName string, namespace string, file *os.File, compartmentID, imageName string) (string, error) {
err := c.uploadToBucket(objectName, bucketName, namespace, file)
// clean up the object even if we fail
defer func() {
if err := c.deleteObjectFromBucket(objectName, bucketName, namespace); err != nil {
log.Printf("failed to clean up the object '%s' from bucket '%s'", objectName, bucketName)
}
}()
if err != nil {
return "", err
}
imageID, err := c.createImage(objectName, bucketName, namespace, compartmentID, imageName)
if err != nil {
return "", fmt.Errorf("failed to create a custom image using object '%s' bucket '%s' in namespace '%s': %w",
objectName,
bucketName,
namespace,
err)
}
return imageID, nil
}
func (c Client) uploadToBucket(objectName string, bucketName string, namespace string, file *os.File) error {
req := transfer.UploadFileRequest{
UploadRequest: transfer.UploadRequest{
NamespaceName: common.String(namespace),
BucketName: common.String(bucketName),
ObjectName: common.String(objectName),
CallBack: func(multiPartUploadPart transfer.MultiPartUploadPart) {
if multiPartUploadPart.Err != nil {
log.Printf("upload failure: %s\n", multiPartUploadPart.Err)
}
log.Printf("multipart upload stats: parts %d, total-parts %d\n",
multiPartUploadPart.PartNum,
multiPartUploadPart.TotalParts)
},
ObjectStorageClient: &c.storageClient,
},
FilePath: file.Name(),
}
uploadManager := transfer.NewUploadManager()
ctx := context.Background()
resp, err := uploadManager.UploadFile(ctx, req)
if err != nil {
if resp.IsResumable() {
resp, err = uploadManager.ResumeUploadFile(ctx, *resp.MultipartUploadResponse.UploadID)
if err != nil {
return err
}
} else {
return fmt.Errorf("failed to upload the file to object %s: %w", objectName, err)
}
}
return nil
}
// Create creates an image from the storageObjectName stored in the bucketName.
// The result is an image ID or an error if the operation failed.
func (c Client) createImage(objectName, bucketName, namespace, compartmentID, imageName string) (string, error) {
request := core.CreateImageRequest{
CreateImageDetails: core.CreateImageDetails{
DisplayName: common.String(imageName),
CompartmentId: common.String(compartmentID),
FreeformTags: map[string]string{
"Uploaded-By": "osbuild-composer",
"Name": imageName,
},
ImageSourceDetails: core.ImageSourceViaObjectStorageTupleDetails{
BucketName: common.String(bucketName),
NamespaceName: common.String(namespace),
ObjectName: common.String(objectName),
SourceImageType: core.ImageSourceDetailsSourceImageTypeQcow2,
},
},
}
createImageResponse, err := c.computeClient.CreateImage(context.Background(), request)
if err != nil {
return "", fmt.Errorf("failed to create an image from storage object: %w", err)
}
log.Printf("waiting for the work request to complete, this may take a while. Work request ID: %s\n", *createImageResponse.OpcWorkRequestId)
for {
r, err := c.workRequestsClient.GetWorkRequest(context.Background(), workrequests.GetWorkRequestRequest{
WorkRequestId: createImageResponse.OpcWorkRequestId,
OpcRequestId: createImageResponse.OpcRequestId,
})
if err != nil {
return "", fmt.Errorf("failed to fetch the work request for creating the image: %w", err)
}
switch r.Status {
case workrequests.WorkRequestStatusSucceeded:
return *createImageResponse.Id, nil
case workrequests.WorkRequestStatusCanceled, workrequests.WorkRequestStatusFailed:
return "", fmt.Errorf("the work request for creating an image is in status %s", r.Status)
}
time.Sleep(1 * time.Second)
}
}
type ClientParams struct {
User string
Region string
Tenancy string
PrivateKey string
Fingerprint string
}
type ociClient struct {
storageClient objectstorage.ObjectStorageClient
identityClient identity.IdentityClient
computeClient core.ComputeClient
workRequestsClient workrequests.WorkRequestClient
}
// deleteObjectFromBucket deletes the object by name from the bucket.
func (c Client) deleteObjectFromBucket(name string, bucket string, namespace string) error {
_, err := c.storageClient.DeleteObject(context.Background(), objectstorage.DeleteObjectRequest{
NamespaceName: common.String(namespace),
BucketName: common.String(bucket),
ObjectName: common.String(name),
})
return err
}
// NewClient creates a new oci client from the passed in params.
// Pass nil clientParams if you want the client to automatically detect
// the configuration from the official disk location or and env file
// From the docs its: $HOME/.oci/config, $HOME/.obmcs/config and variable
// names starting with TF_VAR.
// Last is the environment variable OCI_CONFIG_FILE
func NewClient(clientParams *ClientParams) (Client, error) {
var configProvider common.ConfigurationProvider
if clientParams != nil {
configProvider = common.NewRawConfigurationProvider(
clientParams.Tenancy,
clientParams.User,
clientParams.Region,
clientParams.Fingerprint,
clientParams.PrivateKey,
nil,
)
} else {
configProvider = common.DefaultConfigProvider()
}
storageClient, err := objectstorage.NewObjectStorageClientWithConfigurationProvider(configProvider)
// this disables the default 60 seconds timeout, to support big files upload (the common scenario)
storageClient.HTTPClient = &http.Client{}
if err != nil {
return Client{}, fmt.Errorf("failed to create an Oracle objectstorage client: %w", err)
}
identityClient, err := identity.NewIdentityClientWithConfigurationProvider(configProvider)
if err != nil {
return Client{}, fmt.Errorf("failed to create an Oracle identity client: %w", err)
}
computeClient, err := core.NewComputeClientWithConfigurationProvider(configProvider)
if err != nil {
return Client{}, fmt.Errorf("failed to create an Oracle compute client: %w", err)
}
workRequestsClient, err := workrequests.NewWorkRequestClientWithConfigurationProvider(configProvider)
if err != nil {
return Client{}, fmt.Errorf("failed to create an Oracle workrequests client: %w", err)
}
return Client{ociClient: ociClient{
storageClient: storageClient,
identityClient: identityClient,
computeClient: computeClient,
workRequestsClient: workRequestsClient,
}}, nil
}

View file

@ -55,6 +55,19 @@ type vmwareUploadSettings struct {
func (vmwareUploadSettings) isUploadSettings() {}
type ociUploadSettings struct {
Tenancy string `json:"tenancy"`
Region string `json:"region"`
User string `json:"user"`
Bucket string `json:"bucket"`
Namespace string `json:"namespace"`
PrivateKey string `json:"private_key"`
Fingerprint string `json:"fingerprint"`
Compartment string `json:"compartment"`
}
func (ociUploadSettings) isUploadSettings() {}
type uploadRequest struct {
Provider string `json:"provider"`
ImageName string `json:"image_name"`
@ -82,6 +95,8 @@ func (u *uploadRequest) UnmarshalJSON(data []byte) error {
settings = new(awsUploadSettings)
case "vmware":
settings = new(vmwareUploadSettings)
case "oci":
settings = new(ociUploadSettings)
default:
return errors.New("unexpected provider name")
}
@ -197,6 +212,19 @@ func uploadRequestToTarget(u uploadRequest, imageType distro.ImageType) *target.
Datacenter: options.Datacenter,
Datastore: options.Datastore,
}
case *ociUploadSettings:
t.Name = "org.osbuild.oci"
t.Options = &target.OCITargetOptions{
User: options.User,
Tenancy: options.Tenancy,
Region: options.Region,
FileName: imageType.Filename(),
PrivateKey: options.PrivateKey,
Fingerprint: options.Fingerprint,
Bucket: options.Bucket,
Namespace: options.Namespace,
Compartment: options.Compartment,
}
}
return &t