Skip to content
Merged
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
Jump to file
Failed to load files.
Loading
Diff view
Diff view
24 changes: 2 additions & 22 deletions pkg/daemon/daemon.go
Original file line number Diff line number Diff line change
Expand Up @@ -1677,30 +1677,10 @@ func (dn *Daemon) checkStateOnFirstRun() error {
if !osMatch {
logSystem("Bootstrap pivot required to: %s", targetOSImageURL)

// Check to see if we have a layered/new format image
isLayeredImage, err := dn.NodeUpdaterClient.IsBootableImage(targetOSImageURL)
if err != nil {
return fmt.Errorf("error checking type of target image: %w", err)
if err := dn.updateLayeredOS(state.currentConfig); err != nil {
return err
}

if isLayeredImage {
// If this is a new format image, we don't have to extract it,
// we can just update it the proper way
if err := dn.updateLayeredOS(state.currentConfig); err != nil {
return err
}
} else {
osImageContentDir, err := ExtractOSImage(targetOSImageURL)
if err != nil {
return err
}
if err := dn.updateOS(state.currentConfig, osImageContentDir); err != nil {
return err
}
if err := os.RemoveAll(osImageContentDir); err != nil {
return err
}
}
return dn.reboot(fmt.Sprintf("Node will reboot into config %v", state.currentConfig.GetName()))
}
logSystem("No bootstrap pivot required; unlinking bootstrap node annotations")
Expand Down
14 changes: 0 additions & 14 deletions pkg/daemon/rpm-ostree.go
Original file line number Diff line number Diff line change
Expand Up @@ -282,20 +282,6 @@ func (r *RpmOstreeClient) Rebase(imgURL, osImageContentDir string) (changed bool
return
}

// IsBootableImage determines if the image is a bootable (new container formet) image, or a wrapper (old container format)
func (r *RpmOstreeClient) IsBootableImage(imgURL string) (bool, error) {

var isBootableImage string
var imageData *types.ImageInspectInfo
var err error
if imageData, _, err = imageInspect(imgURL); err != nil {
return false, err
}
isBootableImage = imageData.Labels["ostree.bootable"]

return isBootableImage == "true", nil
}

// RpmOstreeIsNewEnoughForLayering returns true if the version of rpm-ostree on the
// host system is new enough for layering.
// VersionData represents the static information about rpm-ostree.
Expand Down
136 changes: 5 additions & 131 deletions pkg/daemon/update.go
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,6 @@ const (
// fipsFile is the file to check if FIPS is enabled
fipsFile = "/proc/sys/crypto/fips_enabled"
extensionsRepo = "/etc/yum.repos.d/coreos-extensions.repo"
osImageContentBaseDir = "/run/mco-machine-os-content/"
osExtensionsContentBaseDir = "/run/mco-extensions/"

// These are the actions for a node to take after applying config changes. (e.g. a new machineconfig is applied)
Expand Down Expand Up @@ -160,17 +159,8 @@ func (dn *Daemon) compareMachineConfig(oldConfig, newConfig *mcfgv1.MachineConfi
}

// addExtensionsRepo adds a repo into /etc/yum.repos.d/ which we use later to
// install extensions and rt-kernel
func addExtensionsRepo(osImageContentDir string) error {
repoContent := "[coreos-extensions]\nenabled=1\nmetadata_expire=1m\nbaseurl=" + osImageContentDir + "/extensions/\ngpgcheck=0\nskip_if_unavailable=False\n"
return writeFileAtomicallyWithDefaults(extensionsRepo, []byte(repoContent))
}

// addLayeredExtensionsRepo adds a repo into /etc/yum.repos.d/ which we use later to
// install extensions and rt-kernel. This is separate from addExtensionsRepo because when we're
// extracting only the extensions container (because with the new format images they are packaged separately),
// we extract to a different location
func addLayeredExtensionsRepo(extensionsImageContentDir string) error {
// install extensions (additional packages).
func addExtensionsRepo(extensionsImageContentDir string) error {
repoContent := "[coreos-extensions]\nenabled=1\nmetadata_expire=1m\nbaseurl=" + extensionsImageContentDir + "/usr/share/rpm-ostree/extensions/\ngpgcheck=0\nskip_if_unavailable=False\n"
return writeFileAtomicallyWithDefaults(extensionsRepo, []byte(repoContent))
}
Expand Down Expand Up @@ -228,40 +218,6 @@ func podmanCopy(imgURL, osImageContentDir string) (err error) {
return
}

// ExtractOSImage extracts OS image content in a temporary directory under /run/machine-os-content/
// and returns the path on successful extraction.
// Note that since we do this in the MCD container, cluster proxy configuration must also be injected
// into the container. See the MCD daemonset.
func ExtractOSImage(imgURL string) (osImageContentDir string, err error) {
var registryConfig []string
if _, err := os.Stat(kubeletAuthFile); err == nil {
registryConfig = append(registryConfig, "--registry-config", kubeletAuthFile)
}
if err = os.MkdirAll(osImageContentBaseDir, 0o755); err != nil {
err = fmt.Errorf("error creating directory %s: %w", osImageContentBaseDir, err)
return
}

if osImageContentDir, err = os.MkdirTemp(osImageContentBaseDir, "os-content-"); err != nil {
return
}

// Extract the image
args := []string{"image", "extract", "-v", "10", "--path", "/:" + osImageContentDir}
args = append(args, registryConfig...)
args = append(args, imgURL)
if _, err = pivotutils.RunExtBackground(cmdRetriesCount, "oc", args...); err != nil {
// Workaround fixes for the environment where oc image extract fails.
// See https://bugzilla.redhat.com/show_bug.cgi?id=1862979
klog.Infof("Falling back to using podman cp to fetch OS image content")
if err = podmanCopy(imgURL, osImageContentDir); err != nil {
return
}
}

return
}

// ExtractExtensionsImage extracts the OS extensions content in a temporary directory under /run/machine-os-extensions
// and returns the path on successful extraction
func ExtractExtensionsImage(imgURL string) (osExtensionsImageContentDir string, err error) {
Expand Down Expand Up @@ -325,24 +281,10 @@ func (dn *CoreOSDaemon) applyOSChanges(mcDiff machineConfigDiff, oldConfig, newC
dn.nodeWriter.Eventf(corev1.EventTypeNormal, "OSUpdateStarted", mcDiff.osChangesString())
}

// The steps from here on are different depending on the image type, so check the image type
isLayeredImage, err := dn.NodeUpdaterClient.IsBootableImage(newConfig.Spec.OSImageURL)
if err != nil {
return fmt.Errorf("error checking type of update image: %w", err)
if err := dn.applyLayeredOSChanges(mcDiff, oldConfig, newConfig); err != nil {
return err
}

// TODO(jkyros): we can remove the format check and simplify this once we retire the "old format" images
if isLayeredImage {
// If it's a layered/bootable image, then apply it the "new" way
if err := dn.applyLayeredOSChanges(mcDiff, oldConfig, newConfig); err != nil {
return err
}
} else {
// Otherwise fall back to the old way -- we can take this out someday when it goes away
if err := dn.applyLegacyOSChanges(mcDiff, oldConfig, newConfig); err != nil {
return err
}
}
if dn.nodeWriter != nil {
var nodeName string
var nodeObjRef corev1.ObjectReference
Expand Down Expand Up @@ -1997,7 +1939,7 @@ func (dn *CoreOSDaemon) applyLayeredOSChanges(mcDiff machineConfigDiff, oldConfi
// Delete extracted OS image once we are done.
defer os.RemoveAll(osExtensionsContentDir)

if err := addLayeredExtensionsRepo(osExtensionsContentDir); err != nil {
if err := addExtensionsRepo(osExtensionsContentDir); err != nil {
return err
}
defer os.Remove(extensionsRepo)
Expand Down Expand Up @@ -2069,71 +2011,3 @@ func (dn *CoreOSDaemon) applyLayeredOSChanges(mcDiff machineConfigDiff, oldConfi
// Apply extensions
return dn.applyExtensions(oldConfig, newConfig)
}

func (dn *CoreOSDaemon) applyLegacyOSChanges(mcDiff machineConfigDiff, oldConfig, newConfig *mcfgv1.MachineConfig) (retErr error) {
var osImageContentDir string
var err error
if mcDiff.osUpdate || mcDiff.extensions || mcDiff.kernelType {

if osImageContentDir, err = ExtractOSImage(newConfig.Spec.OSImageURL); err != nil {
return err
}
// Delete extracted OS image once we are done.
defer os.RemoveAll(osImageContentDir)

if err := addExtensionsRepo(osImageContentDir); err != nil {
return err
}
defer os.Remove(extensionsRepo)
}

// Update OS
if mcDiff.osUpdate {
if err := dn.updateOS(newConfig, osImageContentDir); err != nil {
mcdPivotErr.Inc()
return err
}
if dn.nodeWriter != nil {
dn.nodeWriter.Eventf(corev1.EventTypeNormal, "OSUpgradeApplied", "OS upgrade applied; new MachineConfig (%s) has new OS image (%s)", newConfig.Name, newConfig.Spec.OSImageURL)
}
} else { //nolint:gocritic // The nil check for dn.nodeWriter has nothing to do with an OS update being unavailable.
// An OS upgrade is not available
if dn.nodeWriter != nil {
dn.nodeWriter.Eventf(corev1.EventTypeNormal, "OSUpgradeSkipped", "OS upgrade skipped; new MachineConfig (%s) has same OS image (%s) as old MachineConfig (%s)", newConfig.Name, newConfig.Spec.OSImageURL, oldConfig.Name)
}
}

// if we're here, we've successfully pivoted, or pivoting wasn't necessary, so we reset the error gauge
mcdPivotErr.Set(0)

defer func() {
// Operations performed by rpm-ostree on the booted system are available
// as staged deployment. It gets applied only when we reboot the system.
// In case of an error during any rpm-ostree transaction, removing pending deployment
// should be sufficient to discard any applied changes.
if retErr != nil {
// Print out the error now so that if we fail to cleanup -p, we don't lose it.
klog.Infof("Rolling back applied changes to OS due to error: %v", retErr)
if err := removePendingDeployment(); err != nil {
errs := kubeErrs.NewAggregate([]error{err, retErr})
retErr = fmt.Errorf("error removing staged deployment: %w", errs)
return
}
}
}()

// Apply kargs
if mcDiff.kargs {
if err := dn.updateKernelArguments(oldConfig.Spec.KernelArguments, newConfig.Spec.KernelArguments); err != nil {
return err
}
}

// Switch to real time kernel
if err := dn.switchKernel(oldConfig, newConfig); err != nil {
return err
}

// Apply extensions
return dn.applyExtensions(oldConfig, newConfig)
}