Skip to content

Commit

Permalink
Seed image format version OCI image label
Browse files Browse the repository at this point in the history
IBU reconciler now has a `checkSeedImageCompatibility` method that
checks if the seed image is compatible with the current version of the
lifecycle-agent. It does so by inspecting the OCI image's labels and
checking if the specified format version equals the hard-coded one that
this version of the lifecycle agent expects. That format version is set
by the imager during the image build process, and is only manually
bumped by developers when the image format changes in a way that is
incompatible with previous versions of the lifecycle-agent.
  • Loading branch information
omertuc committed Jan 2, 2024
1 parent bd3d014 commit 817d978
Show file tree
Hide file tree
Showing 3 changed files with 63 additions and 1 deletion.
51 changes: 51 additions & 0 deletions controllers/prep_handlers.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ package controllers

import (
"context"
"encoding/json"
"errors"
"fmt"
"os"
Expand Down Expand Up @@ -68,8 +69,58 @@ func (r *ImageBasedUpgradeReconciler) getSeedImage(
return fmt.Errorf("failed to pull image: %w", err)
}

r.Log.Info("Checking seed image compatibility")
if err := r.checkSeedImageCompatibility(ctx, pullSecretFilename, ibu.Spec.SeedImageRef.Image); err != nil {
return fmt.Errorf("checking seed image compatibility: %w", err)
}

return nil
}

// checkSeedImageCompatibility checks if the seed image is compatible with the
// current version of the lifecycle-agent by inspecting the OCI image's labels
// and checking if the specified format version equals the hard-coded one that
// this version of the lifecycle agent expects. That format version is set by
// the imager during the image build process, and is only manually bumped by
// developers when the image format changes in a way that is incompatible with
// previous versions of the lifecycle-agent.
func (r *ImageBasedUpgradeReconciler) checkSeedImageCompatibility(_ context.Context, pullSecretFilename, seedImageRef string) error {
inspectArgs := []string{
"inspect",
"--format", "json",
seedImageRef,
}

var inspect struct {
Labels map[string]string `json:"Labels"`
}

// TODO: use the context when execute supports it
if inspectRaw, err := r.Executor.Execute("podman", inspectArgs...); err != nil || inspectRaw == "" {
return fmt.Errorf("failed to inspect image: %w", err)
} else {
if err := json.Unmarshal([]byte(inspectRaw), &inspect); err != nil {
return fmt.Errorf("failed to unmarshal image inspect output: %w", err)
}
}

seedFormatLabelValue, ok := inspect.Labels[common.SeedFormatOCILabel]
if !ok {
return fmt.Errorf(
"seed image %s is missing the %s label, please build a new image using the latest version of the imager",
seedImageRef, common.SeedFormatOCILabel)
}

// Hard equal since we don't have backwards compatibility guarantees yet.
// In the future we might want to have backwards compatibility code to
// handle older seed formats and in that case we'll look at the version
// number and do the right thing.
if seedFormatLabelValue != fmt.Sprintf("%d", common.SeedFormatVersion) {
return fmt.Errorf("seed image format version mismatch: expected %d, got %s",
common.SeedFormatVersion, inspect.Labels[common.SeedFormatOCILabel])
}

return nil
}

func readPrecachingList(imageListFile, clusterRegistry, seedRegistry string, overrideSeedRegistry bool) (imageList []string, err error) {
Expand Down
9 changes: 8 additions & 1 deletion ibu-imager/seedcreator/seedcreator.go
Original file line number Diff line number Diff line change
Expand Up @@ -414,8 +414,15 @@ func (s *SeedCreator) createAndPushSeedImage() error {
_ = tmpfile.Close() // Close the temporary file

// Build the single OCI image (note: We could include --squash-all option, as well)
podmanBuildArgs := []string{
"build",
"--file", tmpfile.Name(),
"--tag", s.containerRegistry,
"--label", fmt.Sprintf("%s=%d", common.SeedFormatOCILabel, common.SeedFormatVersion),
s.backupDir,
}
_, err = s.ops.RunInHostNamespace(
"podman", []string{"build", "-f", tmpfile.Name(), "-t", s.containerRegistry, s.backupDir}...)
"podman", podmanBuildArgs...)
if err != nil {
return fmt.Errorf("failed to build seed image: %w", err)
}
Expand Down
4 changes: 4 additions & 0 deletions internal/common/consts.go
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,10 @@ const (
InstallConfigCM = "cluster-config-v1"
// InstallConfigCMNamespace cm namespace
InstallConfigCMNamespace = "kube-system"

// Bump this every time the seed format changes in a backwards incompatible way
SeedFormatVersion = 1
SeedFormatOCILabel = "com.openshift.lifecycle-agent.seed_format_version"
)

// CertPrefixes is the list of certificate prefixes to be backed up
Expand Down

0 comments on commit 817d978

Please sign in to comment.