Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
The table of contents is too big for display.
Diff view
Diff view
  •  
  •  
  •  
31 changes: 31 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -218,6 +218,37 @@ for more information about the `.boto` file.

`user_domain` is required on some newer versions of OpenStack using Keystone V3 but is optional on older versions. `floating_ip_pool` and `region_name` can be optionally specified here to be used as a default if not specified on the command line.

### oraclecloud
`oraclecloud` uses the OCI SDK config file at the absolute path `$HOME/.oci/config` by default, and profile `DEFAULT`.
Use `--oraclecloud-config-file` and `--oraclecloud-profile` to override those values.
OCI API requests use the SDK's default retry policy for transient service and eventual-consistency failures. Mantle separately polls instance and image lifecycle state until each resource is ready.

The Oracle platform also requires the target compartment, availability domain, subnet, and image:
```
kola run -p oraclecloud <test-name> \
--oraclecloud-compartment-id=<compartment-ocid> \
--oraclecloud-availability-domain=<availability-domain> \
--oraclecloud-subnet-id=<subnet-ocid> \
--oraclecloud-image-id=<image-ocid>
```

For CI runs with a local image, upload and import the image first:
```
IMAGE_ID=$(ore oraclecloud \
--oraclecloud-compartment-id=<compartment-ocid> \
create-image \
--oraclecloud-bucket=<object-storage-bucket> \
--board=<arch>-usr \
--name=<image-name> \
--file=<flatcar-oraclecloud-image.qcow2>)

kola run -p oraclecloud <test-name> \
--oraclecloud-compartment-id=<compartment-ocid> \
--oraclecloud-availability-domain=<availability-domain> \
--oraclecloud-subnet-id=<subnet-ocid> \
--oraclecloud-image-id="${IMAGE_ID}"
```

### packet
`packet` uses `~/.config/packet.json`. This can be configured manually:
```
Expand Down
41 changes: 28 additions & 13 deletions cmd/kola/kola.go
Original file line number Diff line number Diff line change
Expand Up @@ -190,24 +190,32 @@ func writeProps() error {
Image string `json:"image"`
Flavor string `json:"flavor"`
}
type OracleCloud struct {
AvailabilityDomain string `json:"availabilityDomain"`
ImageID string `json:"imageId"`
Shape string `json:"shape"`
OCPUs float32 `json:"ocpus"`
MemoryGB float32 `json:"memoryGb"`
}
type QEMU struct {
Image string `json:"image"`
Mangled bool `json:"mangled"`
}
return enc.Encode(&struct {
Cmdline []string `json:"cmdline"`
Platform string `json:"platform"`
Distro string `json:"distro"`
IgnitionVersion string `json:"ignitionversion"`
Board string `json:"board"`
OSContainer string `json:"oscontainer"`
AWS AWS `json:"aws"`
Azure Azure `json:"azure"`
DO DO `json:"do"`
ESX ESX `json:"esx"`
GCE GCE `json:"gce"`
OpenStack OpenStack `json:"openstack"`
QEMU QEMU `json:"qemu"`
Cmdline []string `json:"cmdline"`
Platform string `json:"platform"`
Distro string `json:"distro"`
IgnitionVersion string `json:"ignitionversion"`
Board string `json:"board"`
OSContainer string `json:"oscontainer"`
AWS AWS `json:"aws"`
Azure Azure `json:"azure"`
DO DO `json:"do"`
ESX ESX `json:"esx"`
GCE GCE `json:"gce"`
OpenStack OpenStack `json:"openstack"`
OracleCloud OracleCloud `json:"oraclecloud"`
QEMU QEMU `json:"qemu"`
}{
Cmdline: os.Args,
Platform: kolaPlatform,
Expand Down Expand Up @@ -251,6 +259,13 @@ func writeProps() error {
Image: kola.OpenStackOptions.Image,
Flavor: kola.OpenStackOptions.Flavor,
},
OracleCloud: OracleCloud{
AvailabilityDomain: kola.OracleCloudOptions.AvailabilityDomain,
ImageID: kola.OracleCloudOptions.ImageID,
Shape: kola.OracleCloudOptions.Shape,
OCPUs: kola.OracleCloudOptions.OCPUs,
MemoryGB: kola.OracleCloudOptions.MemoryGB,
},
QEMU: QEMU{
Image: kola.QEMUOptions.DiskImage,
Mangled: !kola.QEMUOptions.UseVanillaImage,
Expand Down
50 changes: 48 additions & 2 deletions cmd/kola/options.go
Original file line number Diff line number Diff line change
Expand Up @@ -40,8 +40,8 @@ var (
kolaImageVersion string // ${VERSION_ID} or ${VERSION_ID}+${BUILD_ID}
kolaDisableSELinuxAVCChecks bool
defaultTargetBoard = sdk.DefaultBoard()
kolaArchitectures = []string{"amd64"}
kolaPlatforms = []string{"akamai", "aws", "azure", "brightbox", "do", "esx", "external", "gce", "hetzner", "openstack", "qemu", "qemu-unpriv", "scaleway", "stackit"}
kolaArchitectures = []string{"amd64", "arm64"}
kolaPlatforms = []string{"akamai", "aws", "azure", "brightbox", "do", "esx", "external", "gce", "hetzner", "openstack", "oraclecloud", "qemu", "qemu-unpriv", "scaleway", "stackit"}
kolaDistros = []string{"cl", "fcos", "rhcos"}
kolaChannels = []string{"alpha", "beta", "stable", "edge", "lts"}
kolaOfferings = []string{"basic", "pro"}
Expand Down Expand Up @@ -70,6 +70,7 @@ func init() {
ss := root.PersistentFlags().StringSlice
dv := root.PersistentFlags().DurationVar
iv := root.PersistentFlags().IntVar
f32v := root.PersistentFlags().Float32Var

// general options
sv(&outputDir, "output-dir", "", "Temporary output directory for test data and logs")
Expand Down Expand Up @@ -187,6 +188,22 @@ func init() {
sv(&kola.OpenStackOptions.User, "openstack-user", "", "User is the one used for the SSH connection to the Host")
sv(&kola.OpenStackOptions.Keyfile, "openstack-keyfile", "", "Keyfile is the absolute path to private SSH key file for the User on the Host")

// Oracle Cloud Infrastructure specific options
sv(&kola.OracleCloudOptions.Tenancy, "oraclecloud-tenancy", "", "Oracle Cloud tenancy")
sv(&kola.OracleCloudOptions.User, "oraclecloud-user", "", "Oracle Cloud user")
sv(&kola.OracleCloudOptions.Region, "oraclecloud-region", "", "Oracle Cloud fingerprint")

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
sv(&kola.OracleCloudOptions.Region, "oraclecloud-region", "", "Oracle Cloud fingerprint")
sv(&kola.OracleCloudOptions.Region, "oraclecloud-region", "", "Oracle Cloud region")

sv(&kola.OracleCloudOptions.PrivateKey, "oraclecloud-private-key", "", "Oracle Cloud private key")
sv(&kola.OracleCloudOptions.PrivateKeyPassphrase, "oraclecloud-private-key-passphrase", "", "Oracle Cloud private key passphrase")
sv(&kola.OracleCloudOptions.Fingerprint, "oraclecloud-fingerprint", "", "Oracle Cloud fingerprint")

sv(&kola.OracleCloudOptions.CompartmentID, "oraclecloud-compartment-id", "", "Oracle Cloud Infrastructure compartment OCID")
sv(&kola.OracleCloudOptions.AvailabilityDomain, "oraclecloud-availability-domain", "", "Oracle Cloud Infrastructure availability domain")
sv(&kola.OracleCloudOptions.SubnetID, "oraclecloud-subnet-id", "", "Oracle Cloud Infrastructure subnet OCID")
sv(&kola.OracleCloudOptions.ImageID, "oraclecloud-image-id", "", "Oracle Cloud Infrastructure custom image OCID")
sv(&kola.OracleCloudOptions.Shape, "oraclecloud-shape", "", "Oracle Cloud Infrastructure instance shape (default depends on --board)")
f32v(&kola.OracleCloudOptions.OCPUs, "oraclecloud-ocpus", 2, "Oracle Cloud Infrastructure flexible shape OCPUs")
f32v(&kola.OracleCloudOptions.MemoryGB, "oraclecloud-memory-gb", 8, "Oracle Cloud Infrastructure flexible shape memory in GB")

// QEMU-specific options
sv(&kola.QEMUOptions.Board, "board", defaultTargetBoard, "target board")
sv(&kola.QEMUOptions.DiskImage, "qemu-image", "", "path to CoreOS disk image")
Expand Down Expand Up @@ -254,8 +271,20 @@ func syncOptions() error {
kola.ScalewayOptions.Board = board
kola.HetznerOptions.Board = board
kola.AkamaiOptions.Board = board
kola.OracleCloudOptions.Board = board
kola.STACKITOptions.Board = board

if kola.OracleCloudOptions.Shape == "" {
switch board {
case "amd64-usr":
kola.OracleCloudOptions.Shape = "VM.Standard.E4.Flex"
case "arm64-usr":
kola.OracleCloudOptions.Shape = "VM.Standard.A1.Flex"
default:
return fmt.Errorf("unsupported Oracle Cloud board %q", board)
}
}

validateOption := func(name, item string, valid []string) error {
for _, v := range valid {
if v == item {
Expand Down Expand Up @@ -342,6 +371,23 @@ func syncOptions() error {
}
}

if kolaPlatform == "oraclecloud" {
required := []struct {
name string
value string
}{
{"oraclecloud-compartment-id", kola.OracleCloudOptions.CompartmentID},
{"oraclecloud-availability-domain", kola.OracleCloudOptions.AvailabilityDomain},
{"oraclecloud-subnet-id", kola.OracleCloudOptions.SubnetID},
{"oraclecloud-image-id", kola.OracleCloudOptions.ImageID},
}
for _, item := range required {
if item.value == "" {
return fmt.Errorf("--%s is required for --platform=oraclecloud", item.name)
}
}
}

return nil
}

Expand Down
10 changes: 10 additions & 0 deletions cmd/ore/oraclecloud.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
// Copyright The Mantle Authors.
// SPDX-License-Identifier: Apache-2.0

package main

import "github.com/flatcar/mantle/cmd/ore/oraclecloud"

func init() {
root.AddCommand(oraclecloud.OracleCloud)
}
66 changes: 66 additions & 0 deletions cmd/ore/oraclecloud/create-image.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
// Copyright The Mantle Authors.
// SPDX-License-Identifier: Apache-2.0

package oraclecloud

import (
"fmt"
"path/filepath"

"github.com/spf13/cobra"
)

var (
cmdCreateImage = &cobra.Command{
Use: "create-image",
Short: "Create Oracle Cloud Infrastructure image",
Long: "Upload an image to Object Storage and import it as an OCI custom image",
RunE: runCreateImage,
Example: `IMAGE_ID=$(ore oraclecloud \
--oraclecloud-compartment-id "${ORACLE_COMPARTMENT_ID}" \
create-image \
--oraclecloud-bucket "${ORACLE_BUCKET}" \
--board "${CIA_ARCH}-usr" \
--name "${kola_test_basename}" \
--file "${ORACLE_IMAGE_NAME}")`,
}

imageFile string
imageName string
imageBoard string
imageObjectName string
imageSourceImageType string
)

func init() {
OracleCloud.AddCommand(cmdCreateImage)
cmdCreateImage.Flags().StringVar(&options.Namespace, "oraclecloud-namespace", "", "Oracle Cloud Infrastructure Object Storage namespace (default: auto-detect)")
cmdCreateImage.Flags().StringVar(&options.Bucket, "oraclecloud-bucket", "", "Oracle Cloud Infrastructure Object Storage bucket for image uploads")
cmdCreateImage.Flags().StringVar(&imageFile, "file", "flatcar_production_oraclecloud_image.qcow2", "path to local Flatcar image (.qcow2 or .vmdk)")
cmdCreateImage.Flags().StringVar(&imageName, "name", "flatcar-kola-test", "name of the image")
cmdCreateImage.Flags().StringVar(&imageBoard, "board", "amd64-usr", "board of the image")
cmdCreateImage.Flags().StringVar(&imageObjectName, "oraclecloud-object-name", "", "Object Storage object name to use for the upload (default: <board>/<basename of --file>)")
cmdCreateImage.Flags().StringVar(&imageSourceImageType, "source-image-type", "QCOW2", "image import source type: QCOW2 or VMDK")
}

func runCreateImage(cmd *cobra.Command, args []string) error {
if options.CompartmentID == "" {
return fmt.Errorf("--oraclecloud-compartment-id is required")
}
if options.Bucket == "" {
return fmt.Errorf("--oraclecloud-bucket is required")
}

objectName := imageObjectName
if objectName == "" {
objectName = fmt.Sprintf("%s/%s", imageBoard, filepath.Base(imageFile))
}

ID, err := api.UploadImage(cmd.Context(), imageName, imageFile, objectName, imageSourceImageType)
if err != nil {
return fmt.Errorf("creating Flatcar image: %w", err)
}

fmt.Println(ID)
return nil
}
39 changes: 39 additions & 0 deletions cmd/ore/oraclecloud/gc.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
// Copyright The Mantle Authors.
// SPDX-License-Identifier: Apache-2.0

package oraclecloud

import (
"fmt"
"time"

"github.com/spf13/cobra"
)

var (
cmdGC = &cobra.Command{
Use: "gc",
Short: "GC resources in Oracle Cloud Infrastructure",
Long: "Delete mantle-managed instances created over the given duration ago",
RunE: runGC,
}

gcDuration time.Duration
)

func init() {
OracleCloud.AddCommand(cmdGC)
cmdGC.Flags().DurationVar(&gcDuration, "duration", 5*time.Hour, "how old resources must be before they're considered garbage")
}

func runGC(cmd *cobra.Command, args []string) error {
if options.CompartmentID == "" {
return fmt.Errorf("--oraclecloud-compartment-id is required")
}

if err := api.GC(cmd.Context(), gcDuration); err != nil {
return fmt.Errorf("running garbage collection: %w", err)
}

return nil
}
51 changes: 51 additions & 0 deletions cmd/ore/oraclecloud/oraclecloud.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
// Copyright The Mantle Authors.
// SPDX-License-Identifier: Apache-2.0

package oraclecloud

import (
"fmt"
"os"

"github.com/coreos/pkg/capnslog"
"github.com/flatcar/mantle/cli"
"github.com/flatcar/mantle/platform"
oraclecloudapi "github.com/flatcar/mantle/platform/api/oraclecloud"
"github.com/spf13/cobra"
)

var (
plog = capnslog.NewPackageLogger("github.com/flatcar/mantle", "ore/oraclecloud")

OracleCloud = &cobra.Command{
Use: "oraclecloud [command]",
Short: "Oracle Cloud Infrastructure utilities",
}

api *oraclecloudapi.API
options oraclecloudapi.Options
)

func init() {
cli.WrapPreRun(OracleCloud, preflightCheck)
OracleCloud.PersistentFlags().StringVar(&options.Tenancy, "oraclecloud-tenancy", "", "Oracle Cloud tenancy")
OracleCloud.PersistentFlags().StringVar(&options.User, "oraclecloud-user", "", "Oracle Cloud user")
OracleCloud.PersistentFlags().StringVar(&options.Region, "oraclecloud-region", "us-ashburn-1", "Oracle Cloud fingerprint")
OracleCloud.PersistentFlags().StringVar(&options.PrivateKey, "oraclecloud-private-key", "", "Oracle Cloud private key")
OracleCloud.PersistentFlags().StringVar(&options.PrivateKeyPassphrase, "oraclecloud-private-key-passphrase", "", "Oracle Cloud private key passphrase")
OracleCloud.PersistentFlags().StringVar(&options.Fingerprint, "oraclecloud-fingerprint", "", "Oracle Cloud fingerprint")
OracleCloud.PersistentFlags().StringVar(&options.CompartmentID, "oraclecloud-compartment-id", "", "Oracle Cloud Infrastructure compartment OCID")
}

func preflightCheck(cmd *cobra.Command, args []string) error {
options.Options = &platform.Options{Board: imageBoard}

a, err := oraclecloudapi.New(&options)
if err != nil {
fmt.Fprintf(os.Stderr, "could not create Oracle Cloud Infrastructure API client: %v\n", err)
os.Exit(1)
}

api = a
return nil
}
4 changes: 4 additions & 0 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ require (
github.com/kballard/go-shellquote v0.0.0-20150810074751-d8ec1a69a250
github.com/kylelemons/godebug v1.1.0
github.com/linode/linodego v1.69.1
github.com/oracle/oci-go-sdk/v65 v65.117.1
github.com/pborman/uuid v1.2.1
github.com/pin/tftp v2.1.0+incompatible
github.com/scaleway/scaleway-sdk-go v1.0.0-beta.37
Expand Down Expand Up @@ -83,6 +84,7 @@ require (
github.com/go-logr/stdr v1.2.2 // indirect
github.com/go-resty/resty/v2 v2.17.2 // indirect
github.com/goccy/go-json v0.10.2 // indirect
github.com/gofrs/flock v0.10.0 // indirect
github.com/gogo/protobuf v1.3.2 // indirect
github.com/golang-jwt/jwt/v4 v4.5.2 // indirect
github.com/golang-jwt/jwt/v5 v5.3.1 // indirect
Expand Down Expand Up @@ -115,7 +117,9 @@ require (
github.com/prometheus/common v0.66.1 // indirect
github.com/prometheus/procfs v0.16.1 // indirect
github.com/stackitcloud/stackit-sdk-go/services/resourcemanager v0.24.1 // indirect
github.com/sony/gobreaker/v2 v2.4.0 // indirect
github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2 // indirect
github.com/youmark/pkcs8 v0.0.0-20240726163527-a2c0da244d78 // indirect
go.etcd.io/bbolt v1.3.9 // indirect
go.etcd.io/etcd/api/v3 v3.5.13 // indirect
go.etcd.io/etcd/client/v2 v2.305.13 // indirect
Expand Down
Loading