mirror of
https://github.com/siderolabs/talos.git
synced 2025-10-07 13:41:20 +02:00
There's a cyclic dependency on siderolink library which imports talos machinery back. We will fix that after we get talos pushed under a new name. Signed-off-by: Andrey Smirnov <andrey.smirnov@talos-systems.com>
111 lines
2.9 KiB
Go
111 lines
2.9 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/errdefs"
|
|
"github.com/containerd/containerd/namespaces"
|
|
"github.com/containerd/containerd/oci"
|
|
|
|
"github.com/siderolabs/talos/internal/pkg/containers/image"
|
|
"github.com/siderolabs/talos/pkg/machinery/config"
|
|
"github.com/siderolabs/talos/pkg/machinery/constants"
|
|
)
|
|
|
|
// PullAndValidateInstallerImage pulls down the installer and validates that it can run.
|
|
//
|
|
//nolint:gocyclo
|
|
func PullAndValidateInstallerImage(ctx context.Context, reg config.Registries, ref string) error {
|
|
// Pull down specified installer image early so we can bail if it doesn't exist in the upstream registry
|
|
containerdctx := namespaces.WithNamespace(ctx, constants.SystemContainerdNamespace)
|
|
|
|
const containerID = "validate"
|
|
|
|
client, err := containerd.New(constants.SystemContainerdAddress)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
defer client.Close() //nolint:errcheck
|
|
|
|
img, err := image.Pull(containerdctx, reg, client, ref, image.WithSkipIfAlreadyPulled())
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
// See if there's previous container/snapshot to clean up
|
|
var oldcontainer containerd.Container
|
|
|
|
if oldcontainer, err = client.LoadContainer(containerdctx, containerID); err == nil {
|
|
if err = oldcontainer.Delete(containerdctx, containerd.WithSnapshotCleanup); err != nil {
|
|
return fmt.Errorf("error deleting old container instance: %w", err)
|
|
}
|
|
}
|
|
|
|
if err = client.SnapshotService("").Remove(containerdctx, containerID); err != nil && !errdefs.IsNotFound(err) {
|
|
return fmt.Errorf("error cleaning up stale snapshot: %w", err)
|
|
}
|
|
|
|
// Launch the container with a known help command for a simple check to make sure the image is valid
|
|
args := []string{
|
|
"/bin/installer",
|
|
"--help",
|
|
}
|
|
|
|
specOpts := []oci.SpecOpts{
|
|
oci.WithImageConfig(img),
|
|
oci.WithProcessArgs(args...),
|
|
}
|
|
|
|
containerOpts := []containerd.NewContainerOpts{
|
|
containerd.WithImage(img),
|
|
containerd.WithNewSnapshot(containerID, img),
|
|
containerd.WithNewSpec(specOpts...),
|
|
}
|
|
|
|
container, err := client.NewContainer(containerdctx, containerID, containerOpts...)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
//nolint:errcheck
|
|
defer container.Delete(containerdctx, containerd.WithSnapshotCleanup)
|
|
|
|
task, err := container.NewTask(containerdctx, cio.NullIO)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
//nolint:errcheck
|
|
defer task.Delete(containerdctx)
|
|
|
|
exitStatusC, err := task.Wait(containerdctx)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
if err = task.Start(containerdctx); err != nil {
|
|
return err
|
|
}
|
|
|
|
status := <-exitStatusC
|
|
|
|
code, _, err := status.Result()
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
if code != 0 {
|
|
return fmt.Errorf("installer help returned non-zero exit. assuming invalid installer")
|
|
}
|
|
|
|
return nil
|
|
}
|