refactor: move setup logic into machined
The responsibility of init should only be to mount the rootfs. This change moves Talos specific logic into machined. This will allow us to define a version of Talos in a single binary instead of split across two. This will enable cleaner upgrades and helps make the codebase easier to reason about. Signed-off-by: Andrew Rynhard <andrew@andrewrynhard.com>
This commit is contained in:
parent
a7d76b9410
commit
b7a9acbe88
@ -218,14 +218,6 @@ COPY --from=rootfs-base /rootfs /
|
||||
|
||||
FROM build AS initramfs-archive
|
||||
WORKDIR /initramfs
|
||||
COPY --from=docker.io/autonomy/fhs:8467184 / /initramfs
|
||||
COPY --from=docker.io/autonomy/ca-certificates:20f39f7 / /initramfs
|
||||
COPY --from=docker.io/autonomy/dosfstools:767dee6 / /initramfs
|
||||
COPY --from=docker.io/autonomy/musl:9bc7430 / /initramfs
|
||||
COPY --from=docker.io/autonomy/syslinux:85e1f9c / /initramfs
|
||||
COPY --from=docker.io/autonomy/xfsprogs:5e50579 / /initramfs
|
||||
COPY ./hack/cleanup.sh /toolchain/bin/cleanup.sh
|
||||
RUN cleanup.sh /initramfs
|
||||
COPY --from=rootfs-squashfs /rootfs.sqsh .
|
||||
COPY --from=init /init .
|
||||
RUN set -o pipefail && find . 2>/dev/null | cpio -H newc -o | xz -v -C crc32 -0 -e -T 0 -z >/initramfs.xz
|
||||
|
@ -9,14 +9,8 @@ import (
|
||||
"os"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
"github.com/talos-systems/talos/internal/app/init/internal/platform"
|
||||
"github.com/talos-systems/talos/internal/pkg/constants"
|
||||
"github.com/talos-systems/talos/internal/pkg/kernel"
|
||||
"github.com/talos-systems/talos/internal/pkg/network"
|
||||
"github.com/talos-systems/talos/internal/pkg/rootfs"
|
||||
"github.com/talos-systems/talos/internal/pkg/rootfs/mount"
|
||||
"github.com/talos-systems/talos/internal/pkg/security/kspp"
|
||||
"github.com/talos-systems/talos/pkg/userdata"
|
||||
|
||||
"golang.org/x/sys/unix"
|
||||
)
|
||||
@ -39,72 +33,26 @@ func initram() (err error) {
|
||||
if initializer, err = mount.NewInitializer(constants.NewRoot); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Mount the special devices.
|
||||
if err = initializer.InitSpecial(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Setup logging to /dev/kmsg.
|
||||
_, err = kmsg("[talos] [initramfs]")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
// Enforce KSPP kernel parameters.
|
||||
log.Println("checking for KSPP kernel parameters")
|
||||
if err = kspp.EnforceKSPPKernelParameters(); err != nil {
|
||||
return err
|
||||
}
|
||||
// Setup hostname if provided.
|
||||
var hostname *string
|
||||
if hostname = kernel.Cmdline().Get(constants.KernelParamHostname).First(); hostname != nil {
|
||||
log.Println("setting hostname")
|
||||
if err = unix.Sethostname([]byte(*hostname)); err != nil {
|
||||
return err
|
||||
}
|
||||
log.Printf("hostname is: %s", *hostname)
|
||||
}
|
||||
// Discover the platform.
|
||||
log.Println("discovering the platform")
|
||||
var p platform.Platform
|
||||
if p, err = platform.NewPlatform(); err != nil {
|
||||
return err
|
||||
}
|
||||
log.Printf("platform is: %s", p.Name())
|
||||
// Setup basic network.
|
||||
if err = network.InitNetwork(); err != nil {
|
||||
return err
|
||||
}
|
||||
// Retrieve the user data.
|
||||
var data *userdata.UserData
|
||||
log.Printf("retrieving user data")
|
||||
if data, err = p.UserData(); err != nil {
|
||||
log.Printf("encountered error retrieving userdata: %v", err)
|
||||
return err
|
||||
}
|
||||
// Setup custom network.
|
||||
if err = network.SetupNetwork(data); err != nil {
|
||||
return err
|
||||
}
|
||||
// Perform any tasks required by a particular platform.
|
||||
log.Printf("performing platform specific tasks")
|
||||
if err = p.Prepare(data); err != nil {
|
||||
return err
|
||||
}
|
||||
// Mount the owned partitions.
|
||||
log.Printf("mounting the partitions")
|
||||
if err = initializer.InitOwned(); err != nil {
|
||||
return err
|
||||
}
|
||||
// Install handles additional system setup
|
||||
if err = p.Install(data); err != nil {
|
||||
return err
|
||||
}
|
||||
// Prepare the necessary files in the rootfs.
|
||||
log.Println("preparing the root filesystem")
|
||||
if err = rootfs.Prepare(constants.NewRoot, false, data); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Perform the equivalent of switch_root.
|
||||
log.Println("entering the new root")
|
||||
log.Println("mounting the rootfs")
|
||||
if err = initializer.Rootfs(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Perform the equivalent of switch_root.
|
||||
log.Println("entering the rootfs")
|
||||
if err = initializer.Switch(); err != nil {
|
||||
return err
|
||||
}
|
||||
@ -113,10 +61,6 @@ func initram() (err error) {
|
||||
}
|
||||
|
||||
func main() {
|
||||
if err := os.Setenv("PATH", constants.PATH); err != nil {
|
||||
panic(errors.New("error setting PATH"))
|
||||
}
|
||||
|
||||
if err := initram(); err != nil {
|
||||
panic(errors.Wrap(err, "early boot failed"))
|
||||
}
|
||||
|
@ -6,13 +6,13 @@ package platform
|
||||
|
||||
import (
|
||||
"github.com/pkg/errors"
|
||||
"github.com/talos-systems/talos/internal/app/init/internal/platform/baremetal"
|
||||
"github.com/talos-systems/talos/internal/app/init/internal/platform/cloud/aws"
|
||||
"github.com/talos-systems/talos/internal/app/init/internal/platform/cloud/azure"
|
||||
"github.com/talos-systems/talos/internal/app/init/internal/platform/cloud/googlecloud"
|
||||
"github.com/talos-systems/talos/internal/app/init/internal/platform/cloud/packet"
|
||||
"github.com/talos-systems/talos/internal/app/init/internal/platform/cloud/vmware"
|
||||
"github.com/talos-systems/talos/internal/app/init/internal/platform/iso"
|
||||
"github.com/talos-systems/talos/internal/app/machined/internal/platform/baremetal"
|
||||
"github.com/talos-systems/talos/internal/app/machined/internal/platform/cloud/aws"
|
||||
"github.com/talos-systems/talos/internal/app/machined/internal/platform/cloud/azure"
|
||||
"github.com/talos-systems/talos/internal/app/machined/internal/platform/cloud/googlecloud"
|
||||
"github.com/talos-systems/talos/internal/app/machined/internal/platform/cloud/packet"
|
||||
"github.com/talos-systems/talos/internal/app/machined/internal/platform/cloud/vmware"
|
||||
"github.com/talos-systems/talos/internal/app/machined/internal/platform/iso"
|
||||
"github.com/talos-systems/talos/internal/pkg/constants"
|
||||
"github.com/talos-systems/talos/internal/pkg/kernel"
|
||||
"github.com/talos-systems/talos/pkg/userdata"
|
@ -17,13 +17,17 @@ import (
|
||||
"time"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
"github.com/talos-systems/talos/internal/app/machined/internal/platform"
|
||||
"github.com/talos-systems/talos/internal/app/machined/internal/reg"
|
||||
"github.com/talos-systems/talos/internal/app/machined/pkg/system"
|
||||
"github.com/talos-systems/talos/internal/app/machined/pkg/system/services"
|
||||
"github.com/talos-systems/talos/internal/pkg/constants"
|
||||
"github.com/talos-systems/talos/internal/pkg/grpc/factory"
|
||||
"github.com/talos-systems/talos/internal/pkg/network"
|
||||
"github.com/talos-systems/talos/internal/pkg/rootfs"
|
||||
"github.com/talos-systems/talos/internal/pkg/rootfs/etc"
|
||||
"github.com/talos-systems/talos/internal/pkg/rootfs/mount"
|
||||
"github.com/talos-systems/talos/internal/pkg/security/kspp"
|
||||
"github.com/talos-systems/talos/internal/pkg/startup"
|
||||
"github.com/talos-systems/talos/pkg/userdata"
|
||||
|
||||
@ -128,27 +132,95 @@ func createOverlay(path string) error {
|
||||
|
||||
// nolint: gocyclo
|
||||
func root() (err error) {
|
||||
// Create /etc/os-release.
|
||||
if err = etc.OSRelease(); err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
if !*inContainer {
|
||||
// Setup logging to /dev/kmsg.
|
||||
if _, err = kmsg("[talos]"); err != nil {
|
||||
return fmt.Errorf("failed to setup logging to /dev/kmsg: %v", err)
|
||||
}
|
||||
|
||||
// Enforce KSPP kernel parameters.
|
||||
log.Println("checking for KSPP kernel parameters")
|
||||
if err = kspp.EnforceKSPPKernelParameters(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Create /etc/hosts.
|
||||
log.Println("creating /etc/hosts")
|
||||
if err = etc.Hosts(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Create /etc/resolv.conf.
|
||||
log.Println("creating /etc/resolv.conf")
|
||||
if err = etc.ResolvConf(); err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
// Discover the platform.
|
||||
var p platform.Platform
|
||||
if p, err = platform.NewPlatform(); err != nil {
|
||||
return err
|
||||
}
|
||||
log.Printf("platform is %s", p.Name())
|
||||
|
||||
// Setup basic network.
|
||||
log.Println("setting up basic network")
|
||||
if err = network.InitNetwork(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Retrieve the user data.
|
||||
var data *userdata.UserData
|
||||
log.Printf("retrieving user data")
|
||||
if data, err = p.UserData(); err != nil {
|
||||
log.Printf("encountered error retrieving userdata: %v", err)
|
||||
return err
|
||||
}
|
||||
|
||||
// Setup custom network.
|
||||
log.Println("setting up user defined network")
|
||||
if err = network.SetupNetwork(data); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Perform any tasks required by a particular platform.
|
||||
log.Printf("performing platform specific tasks")
|
||||
if err = p.Prepare(data); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
var initializer *mount.Initializer
|
||||
if initializer, err = mount.NewInitializer(""); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Mount the owned partitions.
|
||||
log.Printf("mounting the owned partitions")
|
||||
if err = initializer.InitOwned(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Install handles additional system setup
|
||||
if err = p.Install(data); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Prepare the necessary files in the rootfs.
|
||||
log.Println("preparing the root filesystem")
|
||||
if err = rootfs.Prepare("", false, data); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
for _, overlay := range []string{"/etc/kubernetes", "/etc/cni", "/usr/libexec/kubernetes", "/usr/etc/udev", "/opt"} {
|
||||
if err = createOverlay(overlay); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
if err = unix.Mount("/var/hosts", "/etc/hosts", "", unix.MS_BIND, ""); err != nil {
|
||||
return errors.Wrap(err, "failed to create bind mount for /etc/hosts")
|
||||
}
|
||||
if err = unix.Mount("/var/resolv.conf", "/etc/resolv.conf", "", unix.MS_BIND, ""); err != nil {
|
||||
return errors.Wrap(err, "failed to create bind mount for /etc/resolv.conf")
|
||||
}
|
||||
if err = unix.Mount("/var/os-release", "/etc/os-release", "", unix.MS_BIND, ""); err != nil {
|
||||
return errors.Wrap(err, "failed to create bind mount for /etc/os-release")
|
||||
}
|
||||
}
|
||||
|
||||
for _, p := range []string{"/var/log", "/var/lib/kubelet", "/var/log/pods"} {
|
||||
|
@ -5,18 +5,20 @@
|
||||
package etc
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"bytes"
|
||||
"encoding/hex"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"net"
|
||||
"os"
|
||||
"path"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
"text/template"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
"github.com/talos-systems/talos/internal/pkg/constants"
|
||||
"github.com/talos-systems/talos/internal/pkg/kernel"
|
||||
"github.com/talos-systems/talos/internal/pkg/version"
|
||||
|
||||
"golang.org/x/sys/unix"
|
||||
)
|
||||
|
||||
const hostsTemplate = `
|
||||
@ -38,7 +40,21 @@ BUG_REPORT_URL="https://github.com/talos-systems/talos/issues"
|
||||
`
|
||||
|
||||
// Hosts renders a valid /etc/hosts file and writes it to disk.
|
||||
func Hosts(s, hostname, ip string) (err error) {
|
||||
func Hosts() (err error) {
|
||||
var h *string
|
||||
if h = kernel.Cmdline().Get(constants.KernelParamHostname).First(); h != nil {
|
||||
if err = unix.Sethostname([]byte(*h)); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
ip := ip()
|
||||
|
||||
var hostname string
|
||||
if hostname, err = os.Hostname(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
data := struct {
|
||||
IP string
|
||||
Hostname string
|
||||
@ -58,8 +74,12 @@ func Hosts(s, hostname, ip string) (err error) {
|
||||
return
|
||||
}
|
||||
|
||||
if err := ioutil.WriteFile(filepath.Join(s, "/var/hosts"), writer.Bytes(), 0644); err != nil {
|
||||
return fmt.Errorf("write /var/hosts: %v", err)
|
||||
if err = ioutil.WriteFile("/run/hosts", writer.Bytes(), 0644); err != nil {
|
||||
return fmt.Errorf("write /run/hosts: %v", err)
|
||||
}
|
||||
|
||||
if err = unix.Mount("/run/hosts", "/etc/hosts", "", unix.MS_BIND, ""); err != nil {
|
||||
return errors.Wrap(err, "failed to create bind mount for /etc/hosts")
|
||||
}
|
||||
|
||||
return nil
|
||||
@ -67,15 +87,17 @@ func Hosts(s, hostname, ip string) (err error) {
|
||||
|
||||
// ResolvConf copies the resolv.conf generated in the early boot to the new
|
||||
// root.
|
||||
func ResolvConf(s string) (err error) {
|
||||
source, err := ioutil.ReadFile("/etc/resolv.conf")
|
||||
if err != nil {
|
||||
func ResolvConf() (err error) {
|
||||
target := "/run/resolv.conf"
|
||||
var f *os.File
|
||||
if f, err = os.OpenFile(target, os.O_WRONLY|os.O_CREATE, 0644); err != nil {
|
||||
return err
|
||||
}
|
||||
// nolint: errcheck
|
||||
defer f.Close()
|
||||
|
||||
target := filepath.Join(s, "/var/resolv.conf")
|
||||
if err = ioutil.WriteFile(target, source, 0644); err != nil {
|
||||
return err
|
||||
if err = unix.Mount("/run/resolv.conf", "/etc/resolv.conf", "", unix.MS_BIND, ""); err != nil {
|
||||
return errors.Wrap(err, "failed to create bind mount for /etc/resolv.conf")
|
||||
}
|
||||
|
||||
return nil
|
||||
@ -83,7 +105,7 @@ func ResolvConf(s string) (err error) {
|
||||
|
||||
// OSRelease renders a valid /etc/os-release file and writes it to disk. The
|
||||
// node's OS Image field is reported by the node from /etc/os-release.
|
||||
func OSRelease(s string) (err error) {
|
||||
func OSRelease() (err error) {
|
||||
var v string
|
||||
switch version.Tag {
|
||||
case "none":
|
||||
@ -112,46 +134,29 @@ func OSRelease(s string) (err error) {
|
||||
return
|
||||
}
|
||||
|
||||
if err := ioutil.WriteFile(path.Join(s, "/var/os-release"), writer.Bytes(), 0644); err != nil {
|
||||
return fmt.Errorf("write /var/os-release: %v", err)
|
||||
if err = ioutil.WriteFile("/run/os-release", writer.Bytes(), 0644); err != nil {
|
||||
return fmt.Errorf("write /run/os-release: %v", err)
|
||||
}
|
||||
|
||||
if err = unix.Mount("/run/os-release", "/etc/os-release", "", unix.MS_BIND, ""); err != nil {
|
||||
return errors.Wrap(err, "failed to create bind mount for /etc/os-release")
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// DefaultGateway parses /proc/net/route for the IP address of the default
|
||||
// gateway.
|
||||
func DefaultGateway() (s string, err error) {
|
||||
handle, err := os.Open("/proc/net/route")
|
||||
func ip() string {
|
||||
addrs, err := net.InterfaceAddrs()
|
||||
if err != nil {
|
||||
return
|
||||
return ""
|
||||
}
|
||||
// nolint: errcheck
|
||||
defer handle.Close()
|
||||
scanner := bufio.NewScanner(handle)
|
||||
|
||||
for scanner.Scan() {
|
||||
parts := strings.Split(scanner.Text(), "\t")
|
||||
if len(parts) < 3 {
|
||||
return s, fmt.Errorf("expected at least 3 fields from /proc/net/route, got %d", len(parts))
|
||||
}
|
||||
// Skip the header.
|
||||
if parts[0] == "Iface" {
|
||||
continue
|
||||
}
|
||||
destination := parts[1]
|
||||
gateway := parts[2]
|
||||
// We are looking for the default gateway.
|
||||
if destination == "00000000" {
|
||||
var decoded []byte
|
||||
decoded, err = hex.DecodeString(gateway)
|
||||
if err != nil {
|
||||
return
|
||||
for _, address := range addrs {
|
||||
if ipnet, ok := address.(*net.IPNet); ok && !ipnet.IP.IsLoopback() {
|
||||
if ipnet.IP.To4() != nil {
|
||||
return ipnet.IP.String()
|
||||
}
|
||||
s = fmt.Sprintf("%v.%v.%v.%v", decoded[3], decoded[2], decoded[1], decoded[0])
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
return s, nil
|
||||
return ""
|
||||
}
|
||||
|
@ -99,20 +99,26 @@ func (i *Initializer) MoveSpecial() (err error) {
|
||||
return nil
|
||||
}
|
||||
|
||||
// InitOwned initializes and mounts the OS owned block devices in the early boot
|
||||
// Rootfs initializes and mounts the OS owned block devices in the early boot
|
||||
// stage.
|
||||
//
|
||||
// nolint: gocyclo
|
||||
func (i *Initializer) InitOwned() (err error) {
|
||||
func (i *Initializer) Rootfs() (err error) {
|
||||
var dev losetup.Device
|
||||
dev, err = losetup.Attach("/"+constants.RootfsAsset, 0, true)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
m := mount.NewMountPoint(dev.Path(), "/", "squashfs", unix.MS_RDONLY, "")
|
||||
if err = mount.WithRetry(m, mount.WithPrefix(i.prefix), mount.WithReadOnly(true), mount.WithShared(true)); err != nil {
|
||||
return errors.Wrap(err, "failed to mount squashfs")
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// InitOwned initializes and mounts the OS owned block devices in the early boot
|
||||
// stage.
|
||||
func (i *Initializer) InitOwned() (err error) {
|
||||
var owned *mount.Points
|
||||
if owned, err = mountpoints(); err != nil {
|
||||
return errors.Errorf("error initializing owned block devices: %v", err)
|
||||
@ -197,14 +203,6 @@ func (i *Initializer) UnmountOwned() (err error) {
|
||||
// https://github.com/karelzak/util-linux/blob/master/sys-utils/switch_root.c.
|
||||
// nolint: gocyclo
|
||||
func (i *Initializer) Switch() (err error) {
|
||||
if err = i.UnmountOwned(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err = i.MountOwned(); err != nil {
|
||||
return errors.Wrap(err, "error mounting block device")
|
||||
}
|
||||
|
||||
if err = i.MoveSpecial(); err != nil {
|
||||
return errors.Wrap(err, "error moving special devices")
|
||||
}
|
||||
|
@ -7,7 +7,6 @@ package rootfs
|
||||
import (
|
||||
"io/ioutil"
|
||||
"log"
|
||||
stdlibnet "net"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"time"
|
||||
@ -15,29 +14,12 @@ import (
|
||||
"github.com/pkg/errors"
|
||||
"github.com/talos-systems/talos/internal/pkg/constants"
|
||||
"github.com/talos-systems/talos/internal/pkg/grpc/gen"
|
||||
"github.com/talos-systems/talos/internal/pkg/rootfs/etc"
|
||||
"github.com/talos-systems/talos/internal/pkg/rootfs/proc"
|
||||
"github.com/talos-systems/talos/pkg/crypto/x509"
|
||||
"github.com/talos-systems/talos/pkg/userdata"
|
||||
yaml "gopkg.in/yaml.v2"
|
||||
)
|
||||
|
||||
func ip() string {
|
||||
addrs, err := stdlibnet.InterfaceAddrs()
|
||||
if err != nil {
|
||||
return ""
|
||||
}
|
||||
for _, address := range addrs {
|
||||
if ipnet, ok := address.(*stdlibnet.IPNet); ok && !ipnet.IP.IsLoopback() {
|
||||
if ipnet.IP.To4() != nil {
|
||||
return ipnet.IP.String()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return ""
|
||||
}
|
||||
|
||||
// Prepare creates the files required by the installed binaries and libraries.
|
||||
// nolint: gocyclo
|
||||
func Prepare(s string, inContainer bool, data *userdata.UserData) (err error) {
|
||||
@ -50,25 +32,8 @@ func Prepare(s string, inContainer bool, data *userdata.UserData) (err error) {
|
||||
if err = kernelHardening(); err != nil {
|
||||
return
|
||||
}
|
||||
// Create /etc/hosts.
|
||||
var hostname string
|
||||
if hostname, err = os.Hostname(); err != nil {
|
||||
return
|
||||
}
|
||||
ip := ip()
|
||||
if err = etc.Hosts(s, hostname, ip); err != nil {
|
||||
return
|
||||
}
|
||||
// Create /etc/resolv.conf.
|
||||
if err = etc.ResolvConf(s); err != nil {
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
// Create /etc/os-release.
|
||||
if err = etc.OSRelease(s); err != nil {
|
||||
return
|
||||
}
|
||||
// Generate the identity certificate.
|
||||
if err = generatePKI(data); err != nil {
|
||||
return
|
||||
|
Loading…
x
Reference in New Issue
Block a user