mirror of
https://github.com/siderolabs/talos.git
synced 2025-08-20 22:21:13 +02:00
This PR will add in some code to pre-pull the installer image before we run an upgrade of a given talos node. Additionally, this will add some functional args to the install package to allow for specifying whether or not to pull the installer image. This was needed since there was no sense in pulling the installer again once we made it that far into the upgrade process. Signed-off-by: Spencer Smith <robertspencersmith@gmail.com>
128 lines
3.3 KiB
Go
128 lines
3.3 KiB
Go
// This Source Code Form is subject to the terms of the Mozilla Public
|
|
// License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
// file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
|
|
|
package install
|
|
|
|
import (
|
|
"context"
|
|
"fmt"
|
|
|
|
"github.com/containerd/containerd"
|
|
"github.com/containerd/containerd/cio"
|
|
"github.com/containerd/containerd/namespaces"
|
|
"github.com/containerd/containerd/oci"
|
|
"github.com/opencontainers/runtime-spec/specs-go"
|
|
|
|
"github.com/talos-systems/talos/internal/pkg/kernel"
|
|
"github.com/talos-systems/talos/internal/pkg/runtime"
|
|
"github.com/talos-systems/talos/pkg/constants"
|
|
)
|
|
|
|
// RunInstallerContainer performs an installation via the installer container.
|
|
//nolint: gocyclo
|
|
func RunInstallerContainer(r runtime.Runtime, opts ...Option) error {
|
|
options := DefaultInstallOptions()
|
|
|
|
for _, opt := range opts {
|
|
if err := opt(&options); err != nil {
|
|
return err
|
|
}
|
|
}
|
|
|
|
ctx := namespaces.WithNamespace(context.Background(), constants.SystemContainerdNamespace)
|
|
|
|
client, err := containerd.New(constants.SystemContainerdAddress)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
var image containerd.Image
|
|
|
|
if options.ImagePull {
|
|
image, err = client.Pull(ctx, r.Config().Machine().Install().Image(), []containerd.RemoteOpt{containerd.WithPullUnpack}...)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
} else {
|
|
image, err = client.GetImage(ctx, r.Config().Machine().Install().Image())
|
|
if err != nil {
|
|
return err
|
|
}
|
|
}
|
|
|
|
mounts := []specs.Mount{
|
|
{Type: "bind", Destination: "/dev", Source: "/dev", Options: []string{"rbind", "rshared", "rw"}},
|
|
}
|
|
|
|
// TODO(andrewrynhard): To handle cases when the newer version changes the
|
|
// platform name, this should be determined in the installer container.
|
|
var config *string
|
|
if config = kernel.ProcCmdline().Get(constants.KernelParamConfig).First(); config == nil {
|
|
return fmt.Errorf("no config option was found")
|
|
}
|
|
|
|
upgrade := "false"
|
|
if r.Sequence() == runtime.Upgrade {
|
|
upgrade = "true"
|
|
}
|
|
|
|
args := []string{
|
|
"/bin/installer",
|
|
"install",
|
|
"--disk=" + r.Config().Machine().Install().Disk(),
|
|
"--platform=" + r.Platform().Name(),
|
|
"--config=" + *config,
|
|
"--upgrade=" + upgrade,
|
|
}
|
|
|
|
for _, arg := range r.Config().Machine().Install().ExtraKernelArgs() {
|
|
args = append(args, []string{"--extra-kernel-arg", arg}...)
|
|
}
|
|
|
|
specOpts := []oci.SpecOpts{
|
|
oci.WithImageConfig(image),
|
|
oci.WithProcessArgs(args...),
|
|
oci.WithHostNamespace(specs.NetworkNamespace),
|
|
oci.WithHostNamespace(specs.PIDNamespace),
|
|
oci.WithMounts(mounts),
|
|
oci.WithHostHostsFile,
|
|
oci.WithHostResolvconf,
|
|
oci.WithParentCgroupDevices,
|
|
oci.WithPrivileged,
|
|
}
|
|
containerOpts := []containerd.NewContainerOpts{
|
|
containerd.WithImage(image),
|
|
containerd.WithNewSnapshot("upgrade", image),
|
|
containerd.WithNewSpec(specOpts...),
|
|
}
|
|
|
|
container, err := client.NewContainer(ctx, "upgrade", containerOpts...)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
t, err := container.NewTask(ctx, cio.LogFile("/dev/kmsg"))
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
if err = t.Start(ctx); err != nil {
|
|
return fmt.Errorf("failed to start %q task: %w", "upgrade", err)
|
|
}
|
|
|
|
statusC, err := t.Wait(ctx)
|
|
if err != nil {
|
|
return fmt.Errorf("failed waiting for %q task: %w", "upgrade", err)
|
|
}
|
|
|
|
status := <-statusC
|
|
|
|
code := status.ExitCode()
|
|
if code != 0 {
|
|
return fmt.Errorf("task %q failed: exit code %d", "upgrade", code)
|
|
}
|
|
|
|
return nil
|
|
}
|