Skip to content

Commit

Permalink
kola: Add RHCOS LUKS upgrade test
Browse files Browse the repository at this point in the history
I really think osmet is key for the RHCOS Live ISO experience and
we don't have that right now because of the LUKS container
thing.

I thought then about putting the LUKS header in `/boot`
and dropping the LUKS container by default
(that came up before) so we could also skip the dm-linear
thing.  That way it'd be the same as FCOS.

I started looking at that code but then I was reminded of a
moment of fear I had when something related came up last week -
we have absolutely no testing of upgrades around it, and that
is *highly* likely to break if we start trying to make any
fundamental changes.

This paves some of the infrastructure for a bit more "real" upgrade
testing where we boot the old OS with a target Ignition (in
this case the LUKS config), then reboot into the new OSTree
commit.  This is in contrast to the "synthetic" `offline-upgrade`
which directly overlays the new OSTree commit.

Run this test via e.g.:
`kola run-upgrade --ignition-version v2 -b rhcos -v --find-parent-image --qemu-image-dir tmp/`
which needs to be plumbed into the pipeline.
  • Loading branch information
cgwalters committed May 20, 2020
1 parent f7eebc1 commit cbdf3ae
Show file tree
Hide file tree
Showing 2 changed files with 148 additions and 8 deletions.
55 changes: 47 additions & 8 deletions mantle/cmd/kola/kola.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
package main

import (
"compress/gzip"
"encoding/json"
"fmt"
"io/ioutil"
Expand All @@ -37,6 +38,7 @@ import (
"github.com/coreos/mantle/kola"
"github.com/coreos/mantle/kola/register"
"github.com/coreos/mantle/sdk"
"github.com/coreos/mantle/system"
"github.com/coreos/mantle/util"

// register OS test suite
Expand Down Expand Up @@ -524,6 +526,7 @@ func syncFindParentImageOptions() error {
var err error

var parentBaseUrl string
skipSignature := false
switch kola.Options.Distribution {
case "fcos":
// We're taking liberal shortcuts here... the cleaner way to do this is
Expand All @@ -536,6 +539,11 @@ func syncFindParentImageOptions() error {
if err != nil {
return err
}
case "rhcos":
// Hardcoded for now based on https://github.com/openshift/installer/blob/release-4.3/data/data/rhcos.json
parentBaseUrl = fmt.Sprintf("https://releases-art-rhcos.svc.ci.openshift.org/art/storage/releases/rhcos-4.3/43.81.202003111353.0/%s/", system.RpmArch())
// sigh...someday we'll get the stuff signed by ART or maybe https://github.com/openshift/enhancements/pull/201 will just happen
skipSignature = true
default:
return fmt.Errorf("--find-parent-image not yet supported for distro %s", kola.Options.Distribution)
}
Expand All @@ -558,7 +566,7 @@ func syncFindParentImageOptions() error {
}
qcowUrl := parentBaseUrl + parentCosaBuild.BuildArtifacts.Qemu.Path
qcowLocal := filepath.Join(qemuImageDir, parentCosaBuild.BuildArtifacts.Qemu.Path)
decompressedQcowLocal, err := downloadImageAndDecompress(qcowUrl, qcowLocal)
decompressedQcowLocal, err := downloadImageAndDecompress(qcowUrl, qcowLocal, skipSignature)
if err != nil {
return err
}
Expand All @@ -576,26 +584,57 @@ func syncFindParentImageOptions() error {
}

// Note this is a no-op if the decompressed dest already exists.
func downloadImageAndDecompress(url, compressedDest string) (string, error) {
func downloadImageAndDecompress(url, compressedDest string, skipSignature bool) (string, error) {
var decompressedDest string
if strings.HasSuffix(compressedDest, ".xz") {
if strings.HasSuffix(compressedDest, ".xz") || strings.HasSuffix(compressedDest, ".gz") {
// if the decompressed file is already present locally, assume it's
// good and verified already
decompressedDest = strings.TrimSuffix(compressedDest, ".xz")
decompressedDest = strings.TrimSuffix(strings.TrimSuffix(compressedDest, ".xz"), ".gz")
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
if !skipSignature {
if err := sdk.DownloadCompressedSignedFile(decompressedDest, url, nil, "", util.XzDecompressStream); err != nil {
return "", err
}
} else {
req, err := http.NewRequest("GET", url, nil)
if err != nil {
return "", err
}

resp, err := http.DefaultClient.Do(req)
if err != nil {
return "", err
}
defer resp.Body.Close()
if resp.StatusCode != http.StatusOK {
return "", fmt.Errorf("url %s status: %s", url, resp.Status)
}
gzr, err := gzip.NewReader(resp.Body)
if err != nil {
return "", err
}
dst, err := os.OpenFile(decompressedDest, os.O_WRONLY|os.O_CREATE, 0666)
if err != nil {
return "", err
}
defer dst.Close()
prefix := filepath.Base(decompressedDest)
if _, err := util.CopyProgress(capnslog.INFO, prefix, dst, gzr, resp.ContentLength); err != nil {
return "", err
}
}
return decompressedDest, nil
}
}

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

return compressedDest, nil
Expand Down
101 changes: 101 additions & 0 deletions mantle/kola/tests/rhcos/upgrade.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,101 @@
// Copyright 2020 Red Hat, Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package rhcos

import (
"path/filepath"

"github.com/coreos/pkg/capnslog"

"github.com/coreos/mantle/kola"
"github.com/coreos/mantle/kola/cluster"
"github.com/coreos/mantle/kola/register"
"github.com/coreos/mantle/kola/tests/util"
"github.com/coreos/mantle/platform/conf"
)

var plog = capnslog.NewPackageLogger("github.com/coreos/mantle", "kola/tests/upgrade")

func init() {
register.RegisterUpgradeTest(&register.Test{
Run: rhcosUpgradeLuks,
ClusterSize: 1,
// if renaming this, also rename the command in kolet-httpd.service below
Name: "rhcos.upgrade.luks",
FailFast: true,
Tags: []string{"upgrade"},
Distros: []string{"rhcos"},
UserData: conf.Ignition(`{
"ignition": {
"version": "2.2.0"
},
"storage": {
"files": [
{
"filesystem": "root",
"path": "/etc/clevis.json",
"contents": {
"source": "data:text/plain;base64,e30K"
},
"mode": 420
}
]
}
}`),
})
}

// Ensure that we can still boot into a system with LUKS rootfs after
// an upgrade.
func rhcosUpgradeLuks(c cluster.TestCluster) {
m := c.Machines()[0]
ostreeCommit := kola.CosaBuild.Meta.OstreeCommit
ostreeTarName := kola.CosaBuild.Meta.BuildArtifacts.Ostree.Path
// See tests/upgrade/basic.go for some more information on this; in the future
// we should optimize this to use virtio-fs for qemu.
c.Run("setup", func(c cluster.TestCluster) {
ostreeTarPath := filepath.Join(kola.CosaBuild.Dir, ostreeTarName)
if err := cluster.DropFile(c.Machines(), ostreeTarPath); err != nil {
c.Fatal(err)
}

// XXX: Note the '&& sync' here; this is to work around sysroot
// remounting in libostree forcing a cache flush and blocking D-Bus.
// Should drop this once we fix it more properly in {rpm-,}ostree.
// https://github.com/coreos/coreos-assembler/issues/1301
// Also we should really add a streaming import for this
c.MustSSHf(m, "sudo tar -xf %s -C /var/srv && sudo rm %s", ostreeTarName, ostreeTarName)
c.MustSSHf(m, "sudo ostree --repo=/sysroot/ostree/repo pull-local /var/srv %s && sudo rm -rf /var/srv/* && sudo sync", ostreeCommit)
})

c.Run("upgrade-from-previous", func(c cluster.TestCluster) {
c.MustSSHf(m, "sudo rpm-ostree rebase :%s", ostreeCommit)
err := m.Reboot()
if err != nil {
c.Fatalf("Failed to reboot machine: %v", err)
}
})

c.Run("verify", func(c cluster.TestCluster) {
d, err := util.GetBootedDeployment(c, m)
if err != nil {
c.Fatal(err)
}
if d.Checksum != kola.CosaBuild.Meta.OstreeCommit {
c.Fatalf("Got booted checksum=%s expected=%s", d.Checksum, kola.CosaBuild.Meta.OstreeCommit)
}
// And we should also like systemctl --failed here and stuff
})
}

0 comments on commit cbdf3ae

Please sign in to comment.