talos/internal/pkg/install/install.go
Andrey Smirnov e1779ac77c feat: implement registry mirror & config for image pull
When images are pulled by Talos or via CRI plugin, configuration
for each registry is applied. Mirrors allow to redirect pull request to
either local registry or cached registry. Auth & TLS enable
authentication and TLS authentication for non-public registries.

Signed-off-by: Andrey Smirnov <smirnov.andrey@gmail.com>
2020-02-14 00:28:59 +03:00

132 lines
3.4 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"
"log"
"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/containers/image"
"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
}
log.Printf("pulling installer container image: %q", r.Config().Machine().Install().Image())
var img containerd.Image
if options.ImagePull {
img, err = image.Pull(ctx, r.Config().Machine().Registries(), client, r.Config().Machine().Install().Image())
if err != nil {
return err
}
} else {
img, 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(img),
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(img),
containerd.WithNewSnapshot("upgrade", img),
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
}