Skip to content
This repository has been archived by the owner on May 7, 2021. It is now read-only.

Commit

Permalink
Merge pull request #1168 from jlebon/pr/fcos-upgrade
Browse files Browse the repository at this point in the history
kola: add `run-upgrade` command
  • Loading branch information
jlebon authored Jan 27, 2020
2 parents b9ad41e + 0cf89ca commit e7b3cc6
Show file tree
Hide file tree
Showing 20 changed files with 698 additions and 43 deletions.
196 changes: 193 additions & 3 deletions cmd/kola/kola.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,19 +17,26 @@ package main
import (
"encoding/json"
"fmt"
"io/ioutil"
"log"
"net/http"
"os"
"path/filepath"
"sort"
"strings"
"text/tabwriter"

"github.com/coreos/pkg/capnslog"
"github.com/pkg/errors"
"github.com/spf13/cobra"

"github.com/coreos/mantle/cli"
"github.com/coreos/mantle/cosa"
"github.com/coreos/mantle/fcos"
"github.com/coreos/mantle/kola"
"github.com/coreos/mantle/kola/register"
"github.com/coreos/mantle/sdk"
"github.com/coreos/mantle/util"

// register OS test suite
_ "github.com/coreos/mantle/kola/registry"
Expand Down Expand Up @@ -57,6 +64,16 @@ will be ignored.
PreRun: preRun,
}

cmdRunUpgrade = &cobra.Command{
Use: "run-upgrade [glob pattern...]",
Short: "Run upgrade kola tests",
Long: `Run all upgrade kola tests (default) or related groups.`,
RunE: runRunUpgrade,
PreRunE: preRunUpgrade,
PostRun: postRunUpgrade,
SilenceUsage: true,
}

cmdList = &cobra.Command{
Use: "list",
Short: "List kola test names",
Expand All @@ -73,18 +90,25 @@ This can be useful for e.g. serving locally built OSTree repos to qemu.
Run: runHttpServer,
}

listJSON bool
httpPort int
listJSON bool
httpPort int
findParentImage bool
qemuImageDir string
qemuImageDirIsTemp bool
)

func init() {
root.AddCommand(cmdRun)
root.AddCommand(cmdList)

root.AddCommand(cmdList)
cmdList.Flags().BoolVar(&listJSON, "json", false, "format output in JSON")

root.AddCommand(cmdHttpServer)
cmdHttpServer.Flags().IntVarP(&httpPort, "port", "P", 8000, "Listen on provided port")

root.AddCommand(cmdRunUpgrade)
cmdRunUpgrade.Flags().BoolVar(&findParentImage, "find-parent-image", false, "automatically find parent image if not provided -- note on qemu, this will download the image")
cmdRunUpgrade.Flags().StringVar(&qemuImageDir, "qemu-image-dir", "", "directory in which to cache QEMU images if --fetch-parent-image is enabled")
}

func main() {
Expand Down Expand Up @@ -358,3 +382,169 @@ func runHttpServer(cmd *cobra.Command, args []string) {
fmt.Fprintf(os.Stdout, "Serving HTTP on port: %d\n", httpPort)
log.Fatal(http.ListenAndServe(fmt.Sprintf(":%d", httpPort), nil))
}

func preRunUpgrade(cmd *cobra.Command, args []string) error {
// unlike `kola run`, we *require* the --cosa-build arg -- XXX: figure out
// how to get this working using cobra's MarkFlagRequired()
if kola.Options.CosaBuild == "" {
errors.New("Error: missing required argument --cosa-build")
}

err := syncOptions()
if err != nil {
return err
}

if findParentImage {
err = syncFindParentImageOptions()
if err != nil {
return err
}
}

return nil
}

func postRunUpgrade(cmd *cobra.Command, args []string) {
if qemuImageDir != "" && qemuImageDirIsTemp {
os.RemoveAll(qemuImageDir)
}
}

// syncFindParentImageOptions handles --find-parent-image automagic.
func syncFindParentImageOptions() error {
var err error

var parentBaseUrl string
switch kola.Options.Distribution {
case "fcos":
parentBaseUrl, err = getParentFcosBuildBase()
if err != nil {
return err
}
default:
return fmt.Errorf("--find-parent-image not yet supported for distro %s", kola.Options.Distribution)
}

var parentCosaBuild *cosa.Build
parentCosaBuild, err = cosa.FetchAndParseBuild(parentBaseUrl + "meta.json")
if err != nil {
return err
}

// Here we handle the --fetch-parent-image --> platform-specific options
// based on its cosa build metadata
switch kolaPlatform {
case "qemu-unpriv":
if qemuImageDir == "" {
if qemuImageDir, err = ioutil.TempDir("", "kola-run-upgrade"); err != nil {
return err
}
qemuImageDirIsTemp = true
}
qcowUrl := parentBaseUrl + parentCosaBuild.Images.QEMU.Path
qcowLocal := filepath.Join(qemuImageDir, parentCosaBuild.Images.QEMU.Path)
decompressedQcowLocal, err := downloadImageAndDecompress(qcowUrl, qcowLocal)
if err != nil {
return err
}
kola.QEMUOptions.DiskImage = decompressedQcowLocal
case "aws":
kola.AWSOptions.AMI, err = parentCosaBuild.FindAMI(kola.AWSOptions.Region)
if err != nil {
return err
}
default:
err = fmt.Errorf("--find-parent-image not yet supported for platform %s", kolaPlatform)
}

return nil
}

// Note this is a no-op if the decompressed dest already exists.
func downloadImageAndDecompress(url, compressedDest string) (string, error) {
var decompressedDest string
if strings.HasSuffix(compressedDest, ".xz") {
// if the decompressed file is already present locally, assume it's
// good and verified already
decompressedDest = strings.TrimSuffix(compressedDest, ".xz")
if exists, err := util.PathExists(decompressedDest); err != nil {
return "", err
} else if exists {
return decompressedDest, nil
} else {
if err := sdk.DownloadCompressedSignedFile(decompressedDest, url, nil, "", util.XzDecompressStream); err != nil {
return "", err
}
return decompressedDest, nil
}
}

if err := sdk.DownloadSignedFile(compressedDest, url, nil, ""); err != nil {
return "", err
}

return compressedDest, nil
}

func getParentFcosBuildBase() (string, error) {
// For FCOS, we can be clever and automagically fetch the metadata for the
// parent release, which should be the latest release on that stream.

// We're taking liberal shortcuts here... the cleaner way to do this is
// parse commitmeta.json for `fedora-coreos.stream`, then fetch the stream
// metadata for that stream, then fetch the release metadata

if kola.CosaBuild.Ref == "" {
return "", errors.New("no ref in build metadata")
}

stream := filepath.Base(kola.CosaBuild.Ref)

var parentVersion string
if kola.CosaBuild.FedoraCoreOSParentVersion != "" {
parentVersion = kola.CosaBuild.FedoraCoreOSParentVersion
} else {
// ok, we're probably operating on a local dev build since the pipeline
// always injects the parent; just instead fetch the release index
// for that stream and get the last build id from there
index, err := fcos.FetchAndParseCanonicalReleaseIndex(stream)
if err != nil {
return "", err
}

n := len(index.Releases)
if n == 0 {
return "", fmt.Errorf("no parent version in build metadata, and no build on stream %s", stream)
}

parentVersion = index.Releases[n-1].Version
}

// XXX: multi-arch
// XXX: centralize URL and parameterize
return fmt.Sprintf("https://builds.coreos.fedoraproject.org/prod/streams/%s/builds/%s/x86_64/", stream, parentVersion), nil
}

func runRunUpgrade(cmd *cobra.Command, args []string) error {
outputDir, err := kola.SetupOutputDir(outputDir, kolaPlatform)
if err != nil {
return err
}

var patterns []string
if len(args) == 0 {
patterns = []string{"*"} // run all tests by default
} else {
patterns = args
}

runErr := kola.RunUpgradeTests(patterns, kolaPlatform, outputDir, !kola.Options.NoTestExitError)

// needs to be after RunTests() because harness empties the directory
if err := writeProps(); err != nil {
return err
}

return runErr
}
1 change: 1 addition & 0 deletions cmd/kolet/kolet.go
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,7 @@ func registerTestMap(m map[string]*register.Test) {

func main() {
registerTestMap(register.Tests)
registerTestMap(register.UpgradeTests)
root.AddCommand(cmdRun)

cli.Execute(root)
Expand Down
2 changes: 1 addition & 1 deletion cmd/plume/prerelease.go
Original file line number Diff line number Diff line change
Expand Up @@ -234,7 +234,7 @@ func getFedoraImageFile(client *http.Client, spec *channelSpec, src *storage.Buc

// decompress it
plog.Printf("Decompressing %q...", rawxzPath)
if err := util.XZ2File(imagePath, rawxzPath); err != nil {
if err := util.XzDecompressFile(imagePath, rawxzPath); err != nil {
return "", err
}
return imagePath, nil
Expand Down
1 change: 1 addition & 0 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,7 @@ require (
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2
golang.org/x/net v0.0.0-20190311183353-d8887717615a
golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45
golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4
golang.org/x/sys v0.0.0-20190610200419-93c9922d18ae
golang.org/x/text v0.3.2
google.golang.org/api v0.1.0
Expand Down
1 change: 1 addition & 0 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -234,6 +234,7 @@ golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45 h1:SVwTIAaPC2U/AvvLNZ2a7O
golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4 h1:YUO/7uOKsKeq9UokNS62b8FYywz3ker1l1vDZRCRefw=
golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
Expand Down
2 changes: 1 addition & 1 deletion kola/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -190,4 +190,4 @@ import (
_ "github.com/coreos/mantle/kola/tests/systemd"
_ "github.com/coreos/mantle/kola/tests/update"
)
```
```
4 changes: 4 additions & 0 deletions kola/harness.go
Original file line number Diff line number Diff line change
Expand Up @@ -431,6 +431,10 @@ func RunTests(patterns []string, pltfrm, outputDir string, propagateTestErrors b
return runProvidedTests(register.Tests, patterns, pltfrm, outputDir, propagateTestErrors)
}

func RunUpgradeTests(patterns []string, pltfrm, outputDir string, propagateTestErrors bool) error {
return runProvidedTests(register.UpgradeTests, patterns, pltfrm, outputDir, propagateTestErrors)
}

// getClusterSemVer returns the CoreOS semantic version via starting a
// machine and checking
func getClusterSemver(flight platform.Flight, outputDir string) (*semver.Version, error) {
Expand Down
8 changes: 8 additions & 0 deletions kola/register/register.go
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,10 @@ type Test struct {
// to tests.
var Tests = map[string]*Test{}

// Registered tests that run as part of `kola run-upgrade` live here. Mapping of
// names to tests.
var UpgradeTests = map[string]*Test{}

// Register is usually called via init() functions and is how kola test
// harnesses knows which tests it can choose from. Panics if existing name is
// registered
Expand All @@ -102,6 +106,10 @@ func RegisterTest(t *Test) {
Register(Tests, t)
}

func RegisterUpgradeTest(t *Test) {
Register(UpgradeTests, t)
}

func (t *Test) HasFlag(flag Flag) bool {
for _, f := range t.Flags {
if f == flag {
Expand Down
1 change: 1 addition & 0 deletions kola/registry/registry.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,4 +16,5 @@ import (
_ "github.com/coreos/mantle/kola/tests/rhcos"
_ "github.com/coreos/mantle/kola/tests/rpmostree"
_ "github.com/coreos/mantle/kola/tests/systemd"
_ "github.com/coreos/mantle/kola/tests/upgrade"
)
Loading

0 comments on commit e7b3cc6

Please sign in to comment.