diff --git a/pkg/daemon/rpm-ostree.go b/pkg/daemon/rpm-ostree.go index f11bdca0ae..4c207d4802 100644 --- a/pkg/daemon/rpm-ostree.go +++ b/pkg/daemon/rpm-ostree.go @@ -236,7 +236,7 @@ func (r *RpmOstreeClient) IsNewEnoughForLayering() (bool, error) { return false, nil } -// RebaseLayered rebases system or errors if already rebased +// RebaseLayered rebases system or errors if already rebased. func (r *RpmOstreeClient) RebaseLayered(imgURL string) (err error) { // Try to re-link the merged pull secrets if they exist, since it could have been populated without a daemon reboot useMergedPullSecrets() @@ -244,6 +244,14 @@ func (r *RpmOstreeClient) RebaseLayered(imgURL string) (err error) { return runRpmOstree("rebase", "--experimental", "ostree-unverified-registry:"+imgURL) } +// RebaseLayeredFromContainerStorage rebases the system from an existing local container storage image. +func (r *RpmOstreeClient) RebaseLayeredFromContainerStorage(imgURL string) (err error) { + // Try to re-link the merged pull secrets if they exist, since it could have been populated without a daemon reboot + useMergedPullSecrets() + klog.Infof("Executing local container storage rebase to %s", imgURL) + return runRpmOstree("rebase", "--experimental", "ostree-unverified-image:containers-storage:"+imgURL) +} + // linkOstreeAuthFile gives the rpm-ostree client access to secrets in the file located at `path` by symlinking so that // rpm-ostree can use those secrets to pull images. This can be called multiple times to overwrite an older link. func linkOstreeAuthFile(path string) error { diff --git a/pkg/daemon/update.go b/pkg/daemon/update.go index b506444e35..f5cbfa2a27 100644 --- a/pkg/daemon/update.go +++ b/pkg/daemon/update.go @@ -2579,11 +2579,34 @@ func (dn *Daemon) updateLayeredOSToPullspec(newURL string) error { // This currently will incur a double reboot; see https://github.com/coreos/rpm-ostree/issues/4018 if !newEnough { logSystem("rpm-ostree is not new enough for layering; forcing an update via container") - if err := dn.InplaceUpdateViaNewContainer(newURL); err != nil { + return dn.InplaceUpdateViaNewContainer(newURL) + } + + isOsImagePresent := false + + // not set during firstboot + if dn.featureGatesAccessor != nil { + fg, err := dn.featureGatesAccessor.CurrentFeatureGates() + if err != nil { return err } - } else if err := dn.NodeUpdaterClient.RebaseLayered(newURL); err != nil { - return fmt.Errorf("failed to update OS to %s : %w", newURL, err) + + if fg.Enabled(features.FeatureGatePinnedImages) { + isOsImagePresent, err = isImagePresent(newURL) + if err != nil { + return err + } + } + } + + if isOsImagePresent { + if err := dn.NodeUpdaterClient.RebaseLayeredFromContainerStorage(newURL); err != nil { + return fmt.Errorf("failed to update OS from local storage: %s: %w", newURL, err) + } + } else { + if err := dn.NodeUpdaterClient.RebaseLayered(newURL); err != nil { + return fmt.Errorf("failed to update OS to %s: %w", newURL, err) + } } return nil