refactor: split machined into phases
This change aims to standardize the boot process. It introduces the concept of a phase, which is comprised of tasks. Phases are ran in serial and the tasks that make up a phase are ran concurrently. Signed-off-by: Andrew Rynhard <andrew@andrewrynhard.com>
This commit is contained in:
parent
f56a9d5b96
commit
e63c882b89
@ -73,7 +73,7 @@ ARG SHA
|
||||
ARG TAG
|
||||
ARG VERSION_PKG="github.com/talos-systems/talos/internal/pkg/version"
|
||||
WORKDIR /src/internal/app/machined
|
||||
RUN --mount=type=cache,target=/.cache/go-build go build -ldflags "-s -w -X ${VERSION_PKG}.Name=Server -X ${VERSION_PKG}.SHA=${SHA} -X ${VERSION_PKG}.Tag=${TAG}" -o /machined
|
||||
RUN --mount=type=cache,target=/.cache/go-build go build -ldflags "-s -w -X ${VERSION_PKG}.Name=Talos -X ${VERSION_PKG}.SHA=${SHA} -X ${VERSION_PKG}.Tag=${TAG}" -o /machined
|
||||
RUN chmod +x /machined
|
||||
|
||||
FROM scratch AS machined
|
||||
@ -209,7 +209,7 @@ RUN ln -s /etc/ssl /rootfs/etc/ca-certificates
|
||||
|
||||
FROM rootfs-base AS rootfs-squashfs
|
||||
COPY --from=rootfs / /rootfs
|
||||
RUN mksquashfs /rootfs /rootfs.sqsh -all-root -noappend -comp xz -Xdict-size 100%
|
||||
RUN mksquashfs /rootfs /rootfs.sqsh -all-root -noappend -comp xz -Xdict-size 100% -no-progress
|
||||
|
||||
FROM scratch AS rootfs
|
||||
COPY --from=rootfs-base /rootfs /
|
||||
|
54
Makefile
54
Makefile
@ -54,15 +54,11 @@ DOCKER_TEST_ARGS = --security-opt seccomp:unconfined --privileged -v /var/lib/co
|
||||
|
||||
TESTPKGS ?= ./...
|
||||
|
||||
all: ci drone
|
||||
|
||||
.PHONY: drone
|
||||
drone: rootfs initramfs kernel binaries installer talos
|
||||
all: ci rootfs initramfs kernel osctl installer talos
|
||||
|
||||
.PHONY: ci
|
||||
ci: builddeps buildkitd
|
||||
|
||||
|
||||
.PHONY: builddeps
|
||||
builddeps: gitmeta buildctl
|
||||
|
||||
@ -109,8 +105,8 @@ ifneq ($(BUILDKIT_CONTAINER_RUNNING),$(BUILDKIT_CONTAINER_NAME))
|
||||
endif
|
||||
endif
|
||||
|
||||
.PHONY: binaries
|
||||
binaries: osctl-linux osctl-darwin
|
||||
.PHONY: osctl
|
||||
osctl: osctl-linux osctl-darwin
|
||||
|
||||
base: buildkitd
|
||||
@$(BINDIR)/buildctl --addr $(BUILDKIT_HOST) \
|
||||
@ -137,7 +133,7 @@ initramfs: buildkitd
|
||||
$(COMMON_ARGS)
|
||||
|
||||
.PHONY: rootfs
|
||||
rootfs: buildkitd
|
||||
rootfs: buildkitd osd trustd proxyd ntpd
|
||||
@$(BINDIR)/buildctl --addr $(BUILDKIT_HOST) \
|
||||
build \
|
||||
--output type=local,dest=build \
|
||||
@ -182,6 +178,27 @@ talos-aws:
|
||||
-e AWS_DEFAULT_REGION=$(AWS_DEFAULT_REGION) \
|
||||
autonomy/installer:$(TAG) ami -var regions=${AWS_PUBLISH_REGIONS} -var visibility=all
|
||||
|
||||
.PHONY: talos-azure
|
||||
talos-azure:
|
||||
@docker run --rm -v /dev:/dev -v $(PWD)/build:/out \
|
||||
--privileged $(DOCKER_ARGS) \
|
||||
autonomy/installer:$(TAG) \
|
||||
install \
|
||||
-n disk \
|
||||
-r \
|
||||
-p azure \
|
||||
-u none \
|
||||
-e rootdelay=300
|
||||
@docker run --rm -v $(PWD)/build:/out $(DOCKER_ARGS) \
|
||||
--entrypoint qemu-img \
|
||||
autonomy/installer:$(TAG) \
|
||||
convert \
|
||||
-f raw \
|
||||
-o subformat=fixed,force_size \
|
||||
-O vpc /out/disk.raw /out/disk.vhd
|
||||
@tar -C $(PWD)/build -czf $(PWD)/build/$@.tar.gz disk.vhd
|
||||
@rm -rf $(PWD)/build/disk.raw $(PWD)/build/disk.vhd
|
||||
|
||||
.PHONY: talos-raw
|
||||
talos-raw:
|
||||
@docker run --rm -v /dev:/dev -v $(PWD)/build:/out --privileged $(DOCKER_ARGS) autonomy/installer:$(TAG) install -n rootfs -r -b
|
||||
@ -295,24 +312,3 @@ push: gitmeta
|
||||
.PHONY: clean
|
||||
clean:
|
||||
@-rm -rf build images vendor
|
||||
|
||||
.PHONY: talos-azure
|
||||
talos-azure:
|
||||
@docker run --rm -v /dev:/dev -v $(PWD)/build:/out \
|
||||
--privileged $(DOCKER_ARGS) \
|
||||
autonomy/installer:$(TAG) \
|
||||
install \
|
||||
-n disk \
|
||||
-r \
|
||||
-p azure \
|
||||
-u none \
|
||||
-e rootdelay=300
|
||||
@docker run --rm -v $(PWD)/build:/out $(DOCKER_ARGS) \
|
||||
--entrypoint qemu-img \
|
||||
autonomy/installer:$(TAG) \
|
||||
convert \
|
||||
-f raw \
|
||||
-o subformat=fixed,force_size \
|
||||
-O vpc /out/disk.raw /out/disk.vhd
|
||||
@tar -C $(PWD)/build -czf $(PWD)/build/$@.tar.gz disk.vhd
|
||||
@rm -rf $(PWD)/build/disk.raw $(PWD)/build/disk.vhd
|
||||
|
@ -13,7 +13,6 @@ import (
|
||||
"github.com/docker/docker/api/types"
|
||||
"github.com/docker/docker/api/types/container"
|
||||
"github.com/docker/docker/api/types/network"
|
||||
"github.com/docker/docker/api/types/strslice"
|
||||
"github.com/docker/docker/client"
|
||||
"github.com/docker/go-connections/nat"
|
||||
"github.com/talos-systems/talos/pkg/userdata/generate"
|
||||
@ -44,7 +43,7 @@ func NewNode(clusterName string, req *Request) (err error) {
|
||||
containerConfig := &container.Config{
|
||||
Hostname: req.Name,
|
||||
Image: req.Image,
|
||||
Cmd: strslice.StrSlice{"--in-container", "--userdata=" + b64data},
|
||||
Env: []string{"PLATFORM=container", "USERDATA=" + b64data},
|
||||
Labels: map[string]string{
|
||||
"talos.owned": "true",
|
||||
"talos.cluster.name": clusterName,
|
||||
|
2
go.mod
2
go.mod
@ -79,7 +79,7 @@ require (
|
||||
go.uber.org/multierr v1.1.0 // indirect
|
||||
go.uber.org/zap v1.10.0 // indirect
|
||||
golang.org/x/crypto v0.0.0-20190506204251-e1dfcc566284
|
||||
golang.org/x/net v0.0.0-20190503192946-f4e77d36d62c // indirect
|
||||
golang.org/x/net v0.0.0-20190620200207-3b0461eec859 // indirect
|
||||
golang.org/x/oauth2 v0.0.0-20190402181905-9f3314589c9a // indirect
|
||||
golang.org/x/sync v0.0.0-20190423024810-112230192c58 // indirect
|
||||
golang.org/x/sys v0.0.0-20190508220229-2d0786266e9c
|
||||
|
4
go.sum
4
go.sum
@ -253,8 +253,8 @@ golang.org/x/net v0.0.0-20190313220215-9f648a60d977/go.mod h1:t9HGtf8HONx5eT2rtn
|
||||
golang.org/x/net v0.0.0-20190328230028-74de082e2cca/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||
golang.org/x/net v0.0.0-20190419010253-1f3472d942ba/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||
golang.org/x/net v0.0.0-20190503192946-f4e77d36d62c h1:uOCk1iQW6Vc18bnC13MfzScl+wdKBmM9Y9kU7Z83/lw=
|
||||
golang.org/x/net v0.0.0-20190503192946-f4e77d36d62c/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||
golang.org/x/net v0.0.0-20190620200207-3b0461eec859 h1:R/3boaszxrf1GEUWTVDzSKVwLmSJpwZ1yqXm8j0v2QI=
|
||||
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be h1:vEDujvNQGv4jgYKudGeI/+DAX4Jffq6hpD55MmoEvKs=
|
||||
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
|
||||
golang.org/x/oauth2 v0.0.0-20190402181905-9f3314589c9a h1:tImsplftrFpALCYumobsd0K86vlAs/eXGFms2txfJfA=
|
||||
|
@ -104,7 +104,6 @@ linters:
|
||||
disable-all: false
|
||||
fast: false
|
||||
|
||||
|
||||
issues:
|
||||
# List of regexps of issue texts to exclude, empty list by default.
|
||||
# But independently from this option we use default exclude patterns,
|
||||
@ -116,6 +115,9 @@ issues:
|
||||
- path: cmd/osctl/cmd
|
||||
linters:
|
||||
- dupl
|
||||
- path: internal/app/machined/internal/phase
|
||||
linters:
|
||||
- dupl
|
||||
|
||||
# Independently from option `exclude` we use default exclude patterns,
|
||||
# it can be disabled by this option. To list all
|
||||
|
@ -5,21 +5,11 @@
|
||||
package mount
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"log"
|
||||
"os"
|
||||
"path"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
"github.com/talos-systems/talos/internal/pkg/blockdevice"
|
||||
"github.com/talos-systems/talos/internal/pkg/blockdevice/filesystem/xfs"
|
||||
"github.com/talos-systems/talos/internal/pkg/blockdevice/probe"
|
||||
gptpartition "github.com/talos-systems/talos/internal/pkg/blockdevice/table/gpt/partition"
|
||||
"github.com/talos-systems/talos/internal/pkg/blockdevice/util"
|
||||
"github.com/talos-systems/talos/internal/pkg/constants"
|
||||
"github.com/talos-systems/talos/internal/pkg/mount"
|
||||
"github.com/talos-systems/talos/internal/pkg/mount/cgroups"
|
||||
"github.com/talos-systems/talos/pkg/userdata"
|
||||
"golang.org/x/sys/unix"
|
||||
"gopkg.in/freddierice/go-losetup.v1"
|
||||
)
|
||||
@ -28,7 +18,6 @@ import (
|
||||
type Initializer struct {
|
||||
prefix string
|
||||
|
||||
owned *mount.Points
|
||||
special *mount.Points
|
||||
}
|
||||
|
||||
@ -49,18 +38,13 @@ func NewInitializer(prefix string) (initializer *Initializer, err error) {
|
||||
return initializer, nil
|
||||
}
|
||||
|
||||
// Owned returns the OS owned block devices.
|
||||
func (i *Initializer) Owned() *mount.Points {
|
||||
return i.owned
|
||||
}
|
||||
|
||||
// Special returns the special devices.
|
||||
func (i *Initializer) Special() *mount.Points {
|
||||
return i.special
|
||||
}
|
||||
|
||||
// InitSpecial initializes and mounts the special devices in the early boot
|
||||
// stage.
|
||||
// tasks.
|
||||
func (i *Initializer) InitSpecial() (err error) {
|
||||
iter := i.special.Iter()
|
||||
for iter.Next() {
|
||||
@ -75,6 +59,23 @@ func (i *Initializer) InitSpecial() (err error) {
|
||||
return nil
|
||||
}
|
||||
|
||||
// Rootfs initializes and mounts the OS owned block devices in the early boot
|
||||
// tasks.
|
||||
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
|
||||
}
|
||||
|
||||
// MoveSpecial moves the special device mount points to the new root.
|
||||
func (i *Initializer) MoveSpecial() (err error) {
|
||||
iter := i.special.Iter()
|
||||
@ -99,106 +100,6 @@ func (i *Initializer) MoveSpecial() (err error) {
|
||||
return nil
|
||||
}
|
||||
|
||||
// Rootfs initializes and mounts the OS owned block devices in the early boot
|
||||
// stage.
|
||||
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)
|
||||
}
|
||||
i.owned = owned
|
||||
if mountpoint, ok := i.owned.Get(constants.DataPartitionLabel); ok {
|
||||
if err = repair(mountpoint); err != nil {
|
||||
return errors.Errorf("error fixing data partition: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
iter := i.owned.Iter()
|
||||
for iter.Next() {
|
||||
if err = mount.WithRetry(iter.Value(), mount.WithPrefix(i.prefix)); err != nil {
|
||||
return errors.Errorf("error mounting partitions: %v", err)
|
||||
}
|
||||
}
|
||||
if iter.Err() != nil {
|
||||
return iter.Err()
|
||||
}
|
||||
|
||||
if mountpoint, ok := i.owned.Get(constants.DataPartitionLabel); ok {
|
||||
// NB: The XFS partition MUST be mounted, or this will fail.
|
||||
log.Printf("growing the %s partition", constants.DataPartitionLabel)
|
||||
if err = xfs.GrowFS(path.Join(i.prefix, mountpoint.Target())); err != nil {
|
||||
return errors.Errorf("error growing data partition file system: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// ExtraDevices mounts the extra devices.
|
||||
func ExtraDevices(data *userdata.UserData) (err error) {
|
||||
if data.Install == nil || data.Install.ExtraDevices == nil {
|
||||
return nil
|
||||
}
|
||||
for _, extra := range data.Install.ExtraDevices {
|
||||
for i, part := range extra.Partitions {
|
||||
devname := fmt.Sprintf("%s%d", extra.Device, i+1)
|
||||
mountpoint := mount.NewMountPoint(devname, part.MountPoint, "xfs", unix.MS_NOATIME, "")
|
||||
if err = mount.WithRetry(mountpoint); err != nil {
|
||||
return errors.Errorf("failed to mount %s at %s: %v", devname, part.MountPoint, err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// MountOwned mounts the OS owned block devices.
|
||||
func (i *Initializer) MountOwned() (err error) {
|
||||
iter := i.owned.Iter()
|
||||
for iter.Next() {
|
||||
if err = mount.WithRetry(iter.Value(), mount.WithPrefix(i.prefix)); err != nil {
|
||||
return errors.Errorf("error mounting partitions: %v", err)
|
||||
}
|
||||
}
|
||||
if iter.Err() != nil {
|
||||
return iter.Err()
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// UnmountOwned unmounts the OS owned block devices.
|
||||
func (i *Initializer) UnmountOwned() (err error) {
|
||||
iter := i.owned.IterRev()
|
||||
for iter.Next() {
|
||||
if err = mount.UnWithRetry(iter.Value(), mount.WithPrefix(i.prefix)); err != nil {
|
||||
return errors.Errorf("error mounting partitions: %v", err)
|
||||
}
|
||||
}
|
||||
if iter.Err() != nil {
|
||||
return iter.Err()
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// Switch moves the root to a specified directory. See
|
||||
// https://github.com/karelzak/util-linux/blob/master/sys-utils/switch_root.c.
|
||||
// nolint: gocyclo
|
||||
@ -207,11 +108,6 @@ func (i *Initializer) Switch() (err error) {
|
||||
return errors.Wrap(err, "error moving special devices")
|
||||
}
|
||||
|
||||
// Mount the cgroups to the new root.
|
||||
if err = cgroups.Mount(i.prefix); err != nil {
|
||||
return errors.Wrap(err, "error mounting cgroups")
|
||||
}
|
||||
|
||||
if err = unix.Chdir(i.prefix); err != nil {
|
||||
return errors.Wrapf(err, "error changing working directory to %s", i.prefix)
|
||||
}
|
||||
@ -244,78 +140,6 @@ func (i *Initializer) Switch() (err error) {
|
||||
return nil
|
||||
}
|
||||
|
||||
// nolint: dupl
|
||||
func mountpoints() (mountpoints *mount.Points, err error) {
|
||||
mountpoints = mount.NewMountPoints()
|
||||
for _, name := range []string{constants.DataPartitionLabel, constants.BootPartitionLabel} {
|
||||
var target string
|
||||
switch name {
|
||||
case constants.DataPartitionLabel:
|
||||
target = constants.DataMountPoint
|
||||
case constants.BootPartitionLabel:
|
||||
target = constants.BootMountPoint
|
||||
}
|
||||
|
||||
var dev *probe.ProbedBlockDevice
|
||||
if dev, err = probe.GetDevWithFileSystemLabel(name); err != nil {
|
||||
if name == constants.BootPartitionLabel {
|
||||
// A bootloader is not always required.
|
||||
log.Println("WARNING: no ESP partition was found")
|
||||
continue
|
||||
}
|
||||
return nil, errors.Errorf("failed to find device with label %s: %v", name, err)
|
||||
}
|
||||
|
||||
mountpoint := mount.NewMountPoint(dev.Path, target, dev.SuperBlock.Type(), unix.MS_NOATIME, "")
|
||||
|
||||
mountpoints.Set(name, mountpoint)
|
||||
}
|
||||
|
||||
return mountpoints, nil
|
||||
}
|
||||
|
||||
func repair(mountpoint *mount.Point) (err error) {
|
||||
var devname string
|
||||
if devname, err = util.DevnameFromPartname(mountpoint.Source()); err != nil {
|
||||
return err
|
||||
}
|
||||
bd, err := blockdevice.Open("/dev/" + devname)
|
||||
if err != nil {
|
||||
return errors.Errorf("error opening block device %q: %v", devname, err)
|
||||
}
|
||||
// nolint: errcheck
|
||||
defer bd.Close()
|
||||
|
||||
pt, err := bd.PartitionTable(true)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err := pt.Repair(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
for _, partition := range pt.Partitions() {
|
||||
if partition.(*gptpartition.Partition).Name == constants.DataPartitionLabel {
|
||||
if err := pt.Resize(partition); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if err := pt.Write(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Rereading the partition table requires that all partitions be unmounted
|
||||
// or it will fail with EBUSY.
|
||||
if err := bd.RereadPartitionTable(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func recursiveDelete(fd int) error {
|
||||
parentDev, err := getDev(fd)
|
||||
if err != nil {
|
@ -6,27 +6,13 @@ package main
|
||||
|
||||
import (
|
||||
"log"
|
||||
"os"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
"github.com/talos-systems/talos/internal/app/init/internal/mount"
|
||||
"github.com/talos-systems/talos/internal/pkg/constants"
|
||||
"github.com/talos-systems/talos/internal/pkg/rootfs/mount"
|
||||
|
||||
"golang.org/x/sys/unix"
|
||||
"github.com/talos-systems/talos/internal/pkg/kmsg"
|
||||
)
|
||||
|
||||
func kmsg(prefix string) (*os.File, error) {
|
||||
out, err := os.OpenFile("/dev/kmsg", os.O_RDWR|unix.O_CLOEXEC|unix.O_NONBLOCK|unix.O_NOCTTY, 0666)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "failed to open /dev/kmsg")
|
||||
}
|
||||
log.SetOutput(out)
|
||||
log.SetPrefix(prefix + " ")
|
||||
log.SetFlags(0)
|
||||
|
||||
return out, nil
|
||||
}
|
||||
|
||||
// nolint: gocyclo
|
||||
func initram() (err error) {
|
||||
var initializer *mount.Initializer
|
||||
@ -40,7 +26,7 @@ func initram() (err error) {
|
||||
}
|
||||
|
||||
// Setup logging to /dev/kmsg.
|
||||
_, err = kmsg("[talos] [initramfs]")
|
||||
_, err = kmsg.Setup("[talos] [initramfs]")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
@ -26,8 +26,8 @@ var (
|
||||
)
|
||||
|
||||
// Mount creates the cgroup mount points.
|
||||
func Mount(s string) error {
|
||||
target := path.Join(s, "/sys/fs/cgroup")
|
||||
func Mount() error {
|
||||
target := "/sys/fs/cgroup"
|
||||
if err := os.MkdirAll(target, os.ModeDir); err != nil {
|
||||
return errors.Errorf("failed to create %s: %+v", target, err)
|
||||
}
|
||||
@ -50,7 +50,7 @@ func Mount(s string) error {
|
||||
"pids",
|
||||
}
|
||||
for _, c := range cgroups {
|
||||
p := path.Join(s, "/sys/fs/cgroup", c)
|
||||
p := path.Join("/sys/fs/cgroup", c)
|
||||
if err := os.MkdirAll(p, os.ModeDir); err != nil {
|
||||
return errors.Errorf("failed to create %s: %+v", p, err)
|
||||
}
|
||||
@ -60,7 +60,7 @@ func Mount(s string) error {
|
||||
}
|
||||
|
||||
// See https://www.kernel.org/doc/Documentation/cgroup-v1/memory.txt
|
||||
target = path.Join(s, "/sys/fs/cgroup", memoryCgroup, memoryUseHierarchy)
|
||||
target = path.Join("/sys/fs/cgroup", memoryCgroup, memoryUseHierarchy)
|
||||
err := ioutil.WriteFile(target, memoryUseHierarchyContents, memoryUseHierarchyPermissions)
|
||||
|
||||
return err
|
198
internal/app/machined/internal/mount/mount.go
Normal file
198
internal/app/machined/internal/mount/mount.go
Normal file
@ -0,0 +1,198 @@
|
||||
/* 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 mount
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"log"
|
||||
"path"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
"github.com/talos-systems/talos/internal/pkg/blockdevice"
|
||||
"github.com/talos-systems/talos/internal/pkg/blockdevice/filesystem/xfs"
|
||||
"github.com/talos-systems/talos/internal/pkg/blockdevice/probe"
|
||||
gptpartition "github.com/talos-systems/talos/internal/pkg/blockdevice/table/gpt/partition"
|
||||
"github.com/talos-systems/talos/internal/pkg/blockdevice/util"
|
||||
"github.com/talos-systems/talos/internal/pkg/constants"
|
||||
"github.com/talos-systems/talos/internal/pkg/mount"
|
||||
"github.com/talos-systems/talos/pkg/userdata"
|
||||
"golang.org/x/sys/unix"
|
||||
)
|
||||
|
||||
// Initializer represents the early boot initialization control.
|
||||
type Initializer struct {
|
||||
prefix string
|
||||
|
||||
owned *mount.Points
|
||||
}
|
||||
|
||||
// NewInitializer initializes and returns an Initializer struct.
|
||||
func NewInitializer(prefix string) (initializer *Initializer, err error) {
|
||||
initializer = &Initializer{
|
||||
prefix: prefix,
|
||||
}
|
||||
|
||||
return initializer, nil
|
||||
}
|
||||
|
||||
// Owned returns the OS owned block devices.
|
||||
func (i *Initializer) Owned() *mount.Points {
|
||||
return i.owned
|
||||
}
|
||||
|
||||
// InitOwned initializes and mounts the OS owned block devices in the early boot
|
||||
// tasks.
|
||||
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)
|
||||
}
|
||||
i.owned = owned
|
||||
if mountpoint, ok := i.owned.Get(constants.DataPartitionLabel); ok {
|
||||
if err = repair(mountpoint); err != nil {
|
||||
return errors.Errorf("error fixing data partition: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
iter := i.owned.Iter()
|
||||
for iter.Next() {
|
||||
if err = mount.WithRetry(iter.Value(), mount.WithPrefix(i.prefix)); err != nil {
|
||||
return errors.Errorf("error mounting partitions: %v", err)
|
||||
}
|
||||
}
|
||||
if iter.Err() != nil {
|
||||
return iter.Err()
|
||||
}
|
||||
|
||||
if mountpoint, ok := i.owned.Get(constants.DataPartitionLabel); ok {
|
||||
// NB: The XFS partition MUST be mounted, or this will fail.
|
||||
log.Printf("growing the %s partition", constants.DataPartitionLabel)
|
||||
if err = xfs.GrowFS(path.Join(i.prefix, mountpoint.Target())); err != nil {
|
||||
return errors.Errorf("error growing data partition file system: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// ExtraDevices mounts the extra devices.
|
||||
func ExtraDevices(data *userdata.UserData) (err error) {
|
||||
if data.Install == nil || data.Install.ExtraDevices == nil {
|
||||
return nil
|
||||
}
|
||||
for _, extra := range data.Install.ExtraDevices {
|
||||
for i, part := range extra.Partitions {
|
||||
devname := fmt.Sprintf("%s%d", extra.Device, i+1)
|
||||
mountpoint := mount.NewMountPoint(devname, part.MountPoint, "xfs", unix.MS_NOATIME, "")
|
||||
if err = mount.WithRetry(mountpoint); err != nil {
|
||||
return errors.Errorf("failed to mount %s at %s: %v", devname, part.MountPoint, err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// MountOwned mounts the OS owned block devices.
|
||||
func (i *Initializer) MountOwned() (err error) {
|
||||
iter := i.owned.Iter()
|
||||
for iter.Next() {
|
||||
if err = mount.WithRetry(iter.Value(), mount.WithPrefix(i.prefix)); err != nil {
|
||||
return errors.Errorf("error mounting partitions: %v", err)
|
||||
}
|
||||
}
|
||||
if iter.Err() != nil {
|
||||
return iter.Err()
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// UnmountOwned unmounts the OS owned block devices.
|
||||
func (i *Initializer) UnmountOwned() (err error) {
|
||||
iter := i.owned.IterRev()
|
||||
for iter.Next() {
|
||||
if err = mount.UnWithRetry(iter.Value(), mount.WithPrefix(i.prefix)); err != nil {
|
||||
return errors.Errorf("error mounting partitions: %v", err)
|
||||
}
|
||||
}
|
||||
if iter.Err() != nil {
|
||||
return iter.Err()
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// nolint: dupl
|
||||
func mountpoints() (mountpoints *mount.Points, err error) {
|
||||
mountpoints = mount.NewMountPoints()
|
||||
for _, name := range []string{constants.DataPartitionLabel, constants.BootPartitionLabel} {
|
||||
var target string
|
||||
switch name {
|
||||
case constants.DataPartitionLabel:
|
||||
target = constants.DataMountPoint
|
||||
case constants.BootPartitionLabel:
|
||||
target = constants.BootMountPoint
|
||||
}
|
||||
|
||||
var dev *probe.ProbedBlockDevice
|
||||
if dev, err = probe.GetDevWithFileSystemLabel(name); err != nil {
|
||||
if name == constants.BootPartitionLabel {
|
||||
// A bootloader is not always required.
|
||||
log.Println("WARNING: no ESP partition was found")
|
||||
continue
|
||||
}
|
||||
return nil, errors.Errorf("failed to find device with label %s: %v", name, err)
|
||||
}
|
||||
|
||||
mountpoint := mount.NewMountPoint(dev.Path, target, dev.SuperBlock.Type(), unix.MS_NOATIME, "")
|
||||
|
||||
mountpoints.Set(name, mountpoint)
|
||||
}
|
||||
|
||||
return mountpoints, nil
|
||||
}
|
||||
|
||||
func repair(mountpoint *mount.Point) (err error) {
|
||||
var devname string
|
||||
if devname, err = util.DevnameFromPartname(mountpoint.Source()); err != nil {
|
||||
return err
|
||||
}
|
||||
bd, err := blockdevice.Open("/dev/" + devname)
|
||||
if err != nil {
|
||||
return errors.Errorf("error opening block device %q: %v", devname, err)
|
||||
}
|
||||
// nolint: errcheck
|
||||
defer bd.Close()
|
||||
|
||||
pt, err := bd.PartitionTable(true)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err := pt.Repair(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
for _, partition := range pt.Partitions() {
|
||||
if partition.(*gptpartition.Partition).Name == constants.DataPartitionLabel {
|
||||
if err := pt.Resize(partition); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if err := pt.Write(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Rereading the partition table requires that all partitions be unmounted
|
||||
// or it will fail with EBUSY.
|
||||
if err := bd.RereadPartitionTable(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
14
internal/app/machined/internal/mount/mount_test.go
Normal file
14
internal/app/machined/internal/mount/mount_test.go
Normal file
@ -0,0 +1,14 @@
|
||||
/* 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 mount_test
|
||||
|
||||
import "testing"
|
||||
|
||||
func TestEmpty(t *testing.T) {
|
||||
// added for accurate coverage estimation
|
||||
//
|
||||
// please remove it once any unit-test is added
|
||||
// for this package
|
||||
}
|
47
internal/app/machined/internal/phase/api/acpi.go
Normal file
47
internal/app/machined/internal/phase/api/acpi.go
Normal file
@ -0,0 +1,47 @@
|
||||
/* 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 api
|
||||
|
||||
import (
|
||||
"log"
|
||||
"time"
|
||||
|
||||
"golang.org/x/sys/unix"
|
||||
)
|
||||
|
||||
func sync() {
|
||||
syncdone := make(chan struct{})
|
||||
|
||||
go func() {
|
||||
defer close(syncdone)
|
||||
unix.Sync()
|
||||
}()
|
||||
|
||||
log.Printf("waiting for sync...")
|
||||
|
||||
for i := 29; i >= 0; i-- {
|
||||
select {
|
||||
case <-syncdone:
|
||||
log.Printf("sync done")
|
||||
return
|
||||
case <-time.After(time.Second):
|
||||
}
|
||||
if i != 0 {
|
||||
log.Printf("waiting %d more seconds for sync to finish", i)
|
||||
}
|
||||
}
|
||||
|
||||
log.Printf("sync hasn't completed in time, aborting...")
|
||||
}
|
||||
|
||||
func reboot() {
|
||||
// See http://man7.org/linux/man-pages/man2/reboot.2.html.
|
||||
sync()
|
||||
|
||||
// nolint: errcheck
|
||||
unix.Reboot(unix.LINUX_REBOOT_CMD_RESTART)
|
||||
|
||||
select {}
|
||||
}
|
114
internal/app/machined/internal/phase/api/api.go
Normal file
114
internal/app/machined/internal/phase/api/api.go
Normal file
@ -0,0 +1,114 @@
|
||||
/* 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 api
|
||||
|
||||
import (
|
||||
"log"
|
||||
"os"
|
||||
"os/signal"
|
||||
"syscall"
|
||||
|
||||
"github.com/talos-systems/talos/internal/app/machined/internal/phase"
|
||||
"github.com/talos-systems/talos/internal/app/machined/internal/phase/api/reg"
|
||||
"github.com/talos-systems/talos/internal/app/machined/internal/platform"
|
||||
"github.com/talos-systems/talos/internal/app/machined/internal/runtime"
|
||||
"github.com/talos-systems/talos/internal/app/machined/pkg/system"
|
||||
"github.com/talos-systems/talos/internal/pkg/constants"
|
||||
"github.com/talos-systems/talos/internal/pkg/grpc/factory"
|
||||
"github.com/talos-systems/talos/pkg/userdata"
|
||||
"golang.org/x/sys/unix"
|
||||
"google.golang.org/grpc"
|
||||
)
|
||||
|
||||
var (
|
||||
rebootCmd int
|
||||
)
|
||||
|
||||
// API represents the API task.
|
||||
type API struct{}
|
||||
|
||||
// NewAPITask initializes and returns an API task.
|
||||
func NewAPITask() phase.Task {
|
||||
return &API{}
|
||||
}
|
||||
|
||||
// RuntimeFunc returns the runtime function.
|
||||
func (task *API) RuntimeFunc(mode runtime.Mode) phase.RuntimeFunc {
|
||||
switch mode {
|
||||
case runtime.Standard:
|
||||
return task.standard
|
||||
case runtime.Container:
|
||||
return task.container
|
||||
default:
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
func (task *API) standard(platform platform.Platform, data *userdata.UserData) (err error) {
|
||||
var (
|
||||
api *reg.Registrator
|
||||
server *grpc.Server
|
||||
)
|
||||
if api, server, err = start(data); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
go func() {
|
||||
poweroffCh, err := listenForPowerButton()
|
||||
if err != nil {
|
||||
log.Printf("WARNING: power off events will be ignored: %+v", err)
|
||||
}
|
||||
|
||||
termCh := make(chan os.Signal, 1)
|
||||
signal.Notify(termCh, syscall.SIGTERM)
|
||||
|
||||
// NB: Defer is FILO.
|
||||
defer reboot()
|
||||
defer server.Stop()
|
||||
defer system.Services(data).Shutdown()
|
||||
|
||||
select {
|
||||
case <-api.ShutdownCh:
|
||||
log.Printf("poweroff via API received")
|
||||
// poweroff, proceed to shutdown but mark as poweroff
|
||||
rebootCmd = unix.LINUX_REBOOT_CMD_POWER_OFF
|
||||
case <-poweroffCh:
|
||||
log.Printf("poweroff via ACPI received")
|
||||
// poweroff, proceed to shutdown but mark as poweroff
|
||||
rebootCmd = unix.LINUX_REBOOT_CMD_POWER_OFF
|
||||
case <-termCh:
|
||||
log.Printf("SIGTERM received, rebooting...")
|
||||
case <-api.RebootCh:
|
||||
log.Printf("reboot via API received, rebooting...")
|
||||
rebootCmd = unix.LINUX_REBOOT_CMD_RESTART
|
||||
}
|
||||
}()
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (task *API) container(platform platform.Platform, data *userdata.UserData) (err error) {
|
||||
if _, _, err = start(data); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func start(data *userdata.UserData) (api *reg.Registrator, server *grpc.Server, err error) {
|
||||
api = reg.NewRegistrator(data)
|
||||
server = factory.NewServer(api)
|
||||
listener, err := factory.NewListener(factory.Network("unix"), factory.SocketPath(constants.InitSocketPath))
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
go func() {
|
||||
// nolint: errcheck
|
||||
server.Serve(listener)
|
||||
}()
|
||||
|
||||
return api, server, nil
|
||||
}
|
@ -2,7 +2,7 @@
|
||||
* 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 proc_test
|
||||
package api_test
|
||||
|
||||
import "testing"
|
||||
|
@ -2,7 +2,7 @@
|
||||
* 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 main
|
||||
package api
|
||||
|
||||
import (
|
||||
"log"
|
59
internal/app/machined/internal/phase/install/install.go
Normal file
59
internal/app/machined/internal/phase/install/install.go
Normal file
@ -0,0 +1,59 @@
|
||||
/* 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 (
|
||||
"log"
|
||||
|
||||
"github.com/talos-systems/talos/internal/app/machined/internal/mount"
|
||||
"github.com/talos-systems/talos/internal/app/machined/internal/phase"
|
||||
"github.com/talos-systems/talos/internal/app/machined/internal/platform"
|
||||
"github.com/talos-systems/talos/internal/app/machined/internal/runtime"
|
||||
"github.com/talos-systems/talos/pkg/userdata"
|
||||
)
|
||||
|
||||
// Install represents the Install task.
|
||||
type Install struct{}
|
||||
|
||||
// NewInstallTask initializes and returns an Install task.
|
||||
func NewInstallTask() phase.Task {
|
||||
return &Install{}
|
||||
}
|
||||
|
||||
// RuntimeFunc returns the runtime function.
|
||||
func (task *Install) RuntimeFunc(mode runtime.Mode) phase.RuntimeFunc {
|
||||
switch mode {
|
||||
case runtime.Standard:
|
||||
return task.runtime
|
||||
default:
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
func (task *Install) runtime(platform platform.Platform, data *userdata.UserData) (err error) {
|
||||
// Perform any tasks required by a particular platform.
|
||||
log.Printf("performing platform specific tasks")
|
||||
if err = platform.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 = platform.Install(data); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
14
internal/app/machined/internal/phase/install/install_test.go
Normal file
14
internal/app/machined/internal/phase/install/install_test.go
Normal file
@ -0,0 +1,14 @@
|
||||
/* 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_test
|
||||
|
||||
import "testing"
|
||||
|
||||
func TestEmpty(t *testing.T) {
|
||||
// added for accurate coverage estimation
|
||||
//
|
||||
// please remove it once any unit-test is added
|
||||
// for this package
|
||||
}
|
39
internal/app/machined/internal/phase/network/network.go
Normal file
39
internal/app/machined/internal/phase/network/network.go
Normal file
@ -0,0 +1,39 @@
|
||||
/* 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 network
|
||||
|
||||
import (
|
||||
"github.com/talos-systems/talos/internal/app/machined/internal/phase"
|
||||
"github.com/talos-systems/talos/internal/app/machined/internal/platform"
|
||||
"github.com/talos-systems/talos/internal/app/machined/internal/runtime"
|
||||
"github.com/talos-systems/talos/internal/pkg/network"
|
||||
"github.com/talos-systems/talos/pkg/userdata"
|
||||
)
|
||||
|
||||
// UserDefinedNetwork represents the UserDefinedNetwork task.
|
||||
type UserDefinedNetwork struct{}
|
||||
|
||||
// NewUserDefinedNetworkTask initializes and returns an UserDefinedNetwork task.
|
||||
func NewUserDefinedNetworkTask() phase.Task {
|
||||
return &UserDefinedNetwork{}
|
||||
}
|
||||
|
||||
// RuntimeFunc returns the runtime function.
|
||||
func (task *UserDefinedNetwork) RuntimeFunc(mode runtime.Mode) phase.RuntimeFunc {
|
||||
switch mode {
|
||||
case runtime.Standard:
|
||||
return task.runtime
|
||||
default:
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
func (task *UserDefinedNetwork) runtime(platform platform.Platform, data *userdata.UserData) (err error) {
|
||||
if err = network.SetupNetwork(data); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
14
internal/app/machined/internal/phase/network/network_test.go
Normal file
14
internal/app/machined/internal/phase/network/network_test.go
Normal file
@ -0,0 +1,14 @@
|
||||
/* 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 network_test
|
||||
|
||||
import "testing"
|
||||
|
||||
func TestEmpty(t *testing.T) {
|
||||
// added for accurate coverage estimation
|
||||
//
|
||||
// please remove it once any unit-test is added
|
||||
// for this package
|
||||
}
|
111
internal/app/machined/internal/phase/phase.go
Normal file
111
internal/app/machined/internal/phase/phase.go
Normal file
@ -0,0 +1,111 @@
|
||||
/* 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 phase
|
||||
|
||||
import (
|
||||
"log"
|
||||
"sync"
|
||||
|
||||
"github.com/hashicorp/go-multierror"
|
||||
"github.com/pkg/errors"
|
||||
"github.com/talos-systems/talos/internal/app/machined/internal/platform"
|
||||
"github.com/talos-systems/talos/internal/app/machined/internal/platform/container"
|
||||
"github.com/talos-systems/talos/internal/app/machined/internal/runtime"
|
||||
"github.com/talos-systems/talos/internal/pkg/kmsg"
|
||||
"github.com/talos-systems/talos/pkg/userdata"
|
||||
)
|
||||
|
||||
// Runner represents a management layer for phases.
|
||||
type Runner struct {
|
||||
platform platform.Platform
|
||||
phases []*Phase
|
||||
mode runtime.Mode
|
||||
data *userdata.UserData
|
||||
}
|
||||
|
||||
// NewRunner initializes and returns a Runner.
|
||||
func NewRunner(data *userdata.UserData) (*Runner, error) {
|
||||
platform, err := platform.NewPlatform()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
mode := runtime.Standard
|
||||
switch platform.(type) {
|
||||
case *container.Container:
|
||||
mode = runtime.Container
|
||||
default:
|
||||
// Setup logging to /dev/kmsg.
|
||||
if _, err = kmsg.Setup("[talos]"); err != nil {
|
||||
return nil, errors.Errorf("failed to setup logging to /dev/kmsg: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
return &Runner{
|
||||
platform: platform,
|
||||
mode: mode,
|
||||
data: data,
|
||||
}, nil
|
||||
}
|
||||
|
||||
// Run executes all phases known to a Runner.
|
||||
func (r *Runner) Run() error {
|
||||
for _, phase := range r.phases {
|
||||
var (
|
||||
result *multierror.Error
|
||||
wg sync.WaitGroup
|
||||
)
|
||||
wg.Add(len(phase.tasks))
|
||||
log.Printf("[phase]: %s", phase.name)
|
||||
go func(p *Phase) {
|
||||
for _, task := range p.tasks {
|
||||
defer wg.Done()
|
||||
var f RuntimeFunc
|
||||
if f = task.RuntimeFunc(r.mode); f == nil {
|
||||
// A task is not defined for this runtime mode.
|
||||
continue
|
||||
}
|
||||
if err := f(r.platform, r.data); err != nil {
|
||||
result = multierror.Append(result, err)
|
||||
}
|
||||
}
|
||||
}(phase)
|
||||
wg.Wait()
|
||||
if result != nil {
|
||||
return result.ErrorOrNil()
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// Add adds a phase to a Runner.
|
||||
func (r *Runner) Add(phase ...*Phase) {
|
||||
r.phases = append(r.phases, phase...)
|
||||
}
|
||||
|
||||
// Phase represents a phase in the boot process.
|
||||
type Phase struct {
|
||||
name string
|
||||
tasks []Task
|
||||
}
|
||||
|
||||
// NewPhase initializes and returns a Phase.
|
||||
func NewPhase(name string, tasks ...Task) *Phase {
|
||||
tasks = append([]Task{}, tasks...)
|
||||
return &Phase{
|
||||
name: name,
|
||||
tasks: tasks,
|
||||
}
|
||||
}
|
||||
|
||||
// RuntimeFunc defines the function that a task must return. The function
|
||||
// envelopes the task logic for a given runtim mode.
|
||||
type RuntimeFunc func(platform.Platform, *userdata.UserData) error
|
||||
|
||||
// Task represents a task within a Phase.
|
||||
type Task interface {
|
||||
RuntimeFunc(runtime.Mode) RuntimeFunc
|
||||
}
|
@ -74,11 +74,11 @@ func Hosts() (err error) {
|
||||
return
|
||||
}
|
||||
|
||||
if err = ioutil.WriteFile("/run/hosts", writer.Bytes(), 0644); err != nil {
|
||||
if err = ioutil.WriteFile("/run/system/etc/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 {
|
||||
if err = unix.Mount("/run/system/etc/hosts", "/etc/hosts", "", unix.MS_BIND, ""); err != nil {
|
||||
return errors.Wrap(err, "failed to create bind mount for /etc/hosts")
|
||||
}
|
||||
|
||||
@ -88,7 +88,7 @@ func Hosts() (err error) {
|
||||
// ResolvConf copies the resolv.conf generated in the early boot to the new
|
||||
// root.
|
||||
func ResolvConf() (err error) {
|
||||
target := "/run/resolv.conf"
|
||||
target := "/run/system/etc/resolv.conf"
|
||||
var f *os.File
|
||||
if f, err = os.OpenFile(target, os.O_WRONLY|os.O_CREATE, 0644); err != nil {
|
||||
return err
|
||||
@ -96,7 +96,7 @@ func ResolvConf() (err error) {
|
||||
// nolint: errcheck
|
||||
defer f.Close()
|
||||
|
||||
if err = unix.Mount("/run/resolv.conf", "/etc/resolv.conf", "", unix.MS_BIND, ""); err != nil {
|
||||
if err = unix.Mount("/run/system/etc/resolv.conf", "/etc/resolv.conf", "", unix.MS_BIND, ""); err != nil {
|
||||
return errors.Wrap(err, "failed to create bind mount for /etc/resolv.conf")
|
||||
}
|
||||
|
||||
@ -134,11 +134,11 @@ func OSRelease() (err error) {
|
||||
return
|
||||
}
|
||||
|
||||
if err = ioutil.WriteFile("/run/os-release", writer.Bytes(), 0644); err != nil {
|
||||
return fmt.Errorf("write /run/os-release: %v", err)
|
||||
if err = ioutil.WriteFile("/run/system/etc/os-release", writer.Bytes(), 0644); err != nil {
|
||||
return fmt.Errorf("write /run/system/etc/os-release: %v", err)
|
||||
}
|
||||
|
||||
if err = unix.Mount("/run/os-release", "/etc/os-release", "", unix.MS_BIND, ""); err != nil {
|
||||
if err = unix.Mount("/run/system/etc/os-release", "/etc/os-release", "", unix.MS_BIND, ""); err != nil {
|
||||
return errors.Wrap(err, "failed to create bind mount for /etc/os-release")
|
||||
}
|
||||
|
40
internal/app/machined/internal/phase/rootfs/mount_cgroups.go
Normal file
40
internal/app/machined/internal/phase/rootfs/mount_cgroups.go
Normal file
@ -0,0 +1,40 @@
|
||||
/* 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 rootfs
|
||||
|
||||
import (
|
||||
"github.com/pkg/errors"
|
||||
"github.com/talos-systems/talos/internal/app/machined/internal/mount/cgroups"
|
||||
"github.com/talos-systems/talos/internal/app/machined/internal/phase"
|
||||
"github.com/talos-systems/talos/internal/app/machined/internal/platform"
|
||||
"github.com/talos-systems/talos/internal/app/machined/internal/runtime"
|
||||
"github.com/talos-systems/talos/pkg/userdata"
|
||||
)
|
||||
|
||||
// MountCgroups represents the MountCgroups task.
|
||||
type MountCgroups struct{}
|
||||
|
||||
// NewMountCgroupsTask initializes and returns an MountCgroups task.
|
||||
func NewMountCgroupsTask() phase.Task {
|
||||
return &MountCgroups{}
|
||||
}
|
||||
|
||||
// RuntimeFunc returns the runtime function.
|
||||
func (task *MountCgroups) RuntimeFunc(mode runtime.Mode) phase.RuntimeFunc {
|
||||
switch mode {
|
||||
case runtime.Standard:
|
||||
return task.runtime
|
||||
default:
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
func (task *MountCgroups) runtime(platform platform.Platform, data *userdata.UserData) (err error) {
|
||||
if err = cgroups.Mount(); err != nil {
|
||||
return errors.Wrap(err, "error mounting cgroups")
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
@ -0,0 +1,95 @@
|
||||
/* 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 rootfs
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
"github.com/talos-systems/talos/internal/app/machined/internal/phase"
|
||||
"github.com/talos-systems/talos/internal/app/machined/internal/platform"
|
||||
"github.com/talos-systems/talos/internal/app/machined/internal/runtime"
|
||||
"github.com/talos-systems/talos/pkg/userdata"
|
||||
|
||||
"golang.org/x/sys/unix"
|
||||
)
|
||||
|
||||
const (
|
||||
// SystemVarPath is the path to write runtime system related files and
|
||||
// directories.
|
||||
SystemVarPath = "/var/system"
|
||||
)
|
||||
|
||||
// MountOverlay represents the MountOverlay task.
|
||||
type MountOverlay struct{}
|
||||
|
||||
// NewMountOverlayTask initializes and returns an MountOverlay task.
|
||||
func NewMountOverlayTask() phase.Task {
|
||||
return &MountOverlay{}
|
||||
}
|
||||
|
||||
// RuntimeFunc returns the runtime function.
|
||||
func (task *MountOverlay) RuntimeFunc(mode runtime.Mode) phase.RuntimeFunc {
|
||||
switch mode {
|
||||
case runtime.Standard:
|
||||
return task.standard
|
||||
case runtime.Container:
|
||||
return task.container
|
||||
default:
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
func (task *MountOverlay) standard(platform platform.Platform, data *userdata.UserData) (err error) {
|
||||
overlays := []string{
|
||||
"/etc/kubernetes",
|
||||
"/etc/cni",
|
||||
"/usr/libexec/kubernetes",
|
||||
"/usr/etc/udev",
|
||||
"/opt",
|
||||
}
|
||||
// Create all overlay mounts.
|
||||
for _, o := range overlays {
|
||||
if err = overlay(o); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (task *MountOverlay) container(platform platform.Platform, data *userdata.UserData) (err error) {
|
||||
targets := []string{"/", "/var/lib/kubelet", "/etc/cni"}
|
||||
for _, t := range targets {
|
||||
if err = unix.Mount("", t, "", unix.MS_SHARED, ""); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func overlay(path string) error {
|
||||
parts := strings.Split(path, "/")
|
||||
prefix := strings.Join(parts[1:], "-")
|
||||
diff := fmt.Sprintf(filepath.Join(SystemVarPath, "%s-diff"), prefix)
|
||||
workdir := fmt.Sprintf(filepath.Join(SystemVarPath, "%s-workdir"), prefix)
|
||||
|
||||
for _, s := range []string{diff, workdir} {
|
||||
if err := os.MkdirAll(s, 0700); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
opts := fmt.Sprintf("lowerdir=%s,upperdir=%s,workdir=%s", path, diff, workdir)
|
||||
if err := unix.Mount("overlay", path, "overlay", 0, opts); err != nil {
|
||||
return errors.Errorf("error creating overlay mount to %s: %v", path, err)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
@ -0,0 +1,45 @@
|
||||
/* 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 rootfs
|
||||
|
||||
import (
|
||||
"github.com/talos-systems/talos/internal/app/machined/internal/phase"
|
||||
"github.com/talos-systems/talos/internal/app/machined/internal/phase/rootfs/etc"
|
||||
"github.com/talos-systems/talos/internal/app/machined/internal/platform"
|
||||
"github.com/talos-systems/talos/internal/app/machined/internal/runtime"
|
||||
"github.com/talos-systems/talos/pkg/userdata"
|
||||
)
|
||||
|
||||
// NetworkConfiguration represents the NetworkConfiguration task.
|
||||
type NetworkConfiguration struct{}
|
||||
|
||||
// NewNetworkConfigurationTask initializes and returns an NetworkConfiguration task.
|
||||
func NewNetworkConfigurationTask() phase.Task {
|
||||
return &NetworkConfiguration{}
|
||||
}
|
||||
|
||||
// RuntimeFunc returns the runtime function.
|
||||
func (task *NetworkConfiguration) RuntimeFunc(mode runtime.Mode) phase.RuntimeFunc {
|
||||
switch mode {
|
||||
case runtime.Standard:
|
||||
return task.runtime
|
||||
default:
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
func (task *NetworkConfiguration) runtime(platform platform.Platform, data *userdata.UserData) (err error) {
|
||||
// Create /etc/hosts.
|
||||
if err = etc.Hosts(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Create /etc/resolv.conf.
|
||||
if err = etc.ResolvConf(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
31
internal/app/machined/internal/phase/rootfs/os_release.go
Normal file
31
internal/app/machined/internal/phase/rootfs/os_release.go
Normal file
@ -0,0 +1,31 @@
|
||||
/* 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 rootfs
|
||||
|
||||
import (
|
||||
"github.com/talos-systems/talos/internal/app/machined/internal/phase"
|
||||
"github.com/talos-systems/talos/internal/app/machined/internal/phase/rootfs/etc"
|
||||
"github.com/talos-systems/talos/internal/app/machined/internal/platform"
|
||||
"github.com/talos-systems/talos/internal/app/machined/internal/runtime"
|
||||
"github.com/talos-systems/talos/pkg/userdata"
|
||||
)
|
||||
|
||||
// OSRelease represents the OSRelease task.
|
||||
type OSRelease struct{}
|
||||
|
||||
// NewOSReleaseTask initializes and returns an OSRelease task.
|
||||
func NewOSReleaseTask() phase.Task {
|
||||
return &OSRelease{}
|
||||
}
|
||||
|
||||
// RuntimeFunc returns the runtime function.
|
||||
func (task *OSRelease) RuntimeFunc(mode runtime.Mode) phase.RuntimeFunc {
|
||||
return task.runtime
|
||||
}
|
||||
|
||||
func (task *OSRelease) runtime(platform platform.Platform, data *userdata.UserData) (err error) {
|
||||
// Create /etc/os-release.
|
||||
return etc.OSRelease()
|
||||
}
|
@ -0,0 +1,31 @@
|
||||
/* 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 rootfs
|
||||
|
||||
import (
|
||||
"os"
|
||||
|
||||
"github.com/talos-systems/talos/internal/app/machined/internal/phase"
|
||||
"github.com/talos-systems/talos/internal/app/machined/internal/platform"
|
||||
"github.com/talos-systems/talos/internal/app/machined/internal/runtime"
|
||||
"github.com/talos-systems/talos/pkg/userdata"
|
||||
)
|
||||
|
||||
// SystemDirectory represents the SystemDirectory task.
|
||||
type SystemDirectory struct{}
|
||||
|
||||
// NewSystemDirectoryTask initializes and returns an SystemDirectory task.
|
||||
func NewSystemDirectoryTask() phase.Task {
|
||||
return &SystemDirectory{}
|
||||
}
|
||||
|
||||
// RuntimeFunc returns the runtime function.
|
||||
func (task *SystemDirectory) RuntimeFunc(mode runtime.Mode) phase.RuntimeFunc {
|
||||
return task.runtime
|
||||
}
|
||||
|
||||
func (task *SystemDirectory) runtime(platform platform.Platform, data *userdata.UserData) (err error) {
|
||||
return os.MkdirAll("/run/system/etc", os.ModeDir)
|
||||
}
|
@ -0,0 +1,37 @@
|
||||
/* 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 rootfs
|
||||
|
||||
import (
|
||||
"os"
|
||||
|
||||
"github.com/talos-systems/talos/internal/app/machined/internal/phase"
|
||||
"github.com/talos-systems/talos/internal/app/machined/internal/platform"
|
||||
"github.com/talos-systems/talos/internal/app/machined/internal/runtime"
|
||||
"github.com/talos-systems/talos/pkg/userdata"
|
||||
)
|
||||
|
||||
// VarDirectories represents the VarDirectories task.
|
||||
type VarDirectories struct{}
|
||||
|
||||
// NewVarDirectoriesTask initializes and returns an VarDirectories task.
|
||||
func NewVarDirectoriesTask() phase.Task {
|
||||
return &VarDirectories{}
|
||||
}
|
||||
|
||||
// RuntimeFunc returns the runtime function.
|
||||
func (task *VarDirectories) RuntimeFunc(mode runtime.Mode) phase.RuntimeFunc {
|
||||
return task.runtime
|
||||
}
|
||||
|
||||
func (task *VarDirectories) runtime(platform platform.Platform, data *userdata.UserData) (err error) {
|
||||
for _, p := range []string{"/var/log", "/var/lib/kubelet", "/var/log/pods"} {
|
||||
if err = os.MkdirAll(p, 0700); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
42
internal/app/machined/internal/phase/security/security.go
Normal file
42
internal/app/machined/internal/phase/security/security.go
Normal file
@ -0,0 +1,42 @@
|
||||
/* 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 security
|
||||
|
||||
import (
|
||||
"github.com/talos-systems/talos/internal/app/machined/internal/phase"
|
||||
"github.com/talos-systems/talos/internal/app/machined/internal/platform"
|
||||
"github.com/talos-systems/talos/internal/app/machined/internal/runtime"
|
||||
"github.com/talos-systems/talos/internal/pkg/security/kspp"
|
||||
"github.com/talos-systems/talos/pkg/userdata"
|
||||
)
|
||||
|
||||
// Security represents the Security task.
|
||||
type Security struct{}
|
||||
|
||||
// NewSecurityTask initializes and returns an Security task.
|
||||
func NewSecurityTask() phase.Task {
|
||||
return &Security{}
|
||||
}
|
||||
|
||||
// RuntimeFunc returns the runtime function.
|
||||
func (task *Security) RuntimeFunc(mode runtime.Mode) phase.RuntimeFunc {
|
||||
switch mode {
|
||||
case runtime.Standard:
|
||||
return task.runtime
|
||||
default:
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
func (task *Security) runtime(platform platform.Platform, data *userdata.UserData) (err error) {
|
||||
if err = kspp.EnforceKSPPKernelParameters(); err != nil {
|
||||
return err
|
||||
}
|
||||
if err = kspp.EnforceKSPPSysctls(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
@ -0,0 +1,14 @@
|
||||
/* 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 security_test
|
||||
|
||||
import "testing"
|
||||
|
||||
func TestEmpty(t *testing.T) {
|
||||
// added for accurate coverage estimation
|
||||
//
|
||||
// please remove it once any unit-test is added
|
||||
// for this package
|
||||
}
|
63
internal/app/machined/internal/phase/services/services.go
Normal file
63
internal/app/machined/internal/phase/services/services.go
Normal file
@ -0,0 +1,63 @@
|
||||
/* 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 services
|
||||
|
||||
import (
|
||||
"github.com/talos-systems/talos/internal/app/machined/internal/phase"
|
||||
"github.com/talos-systems/talos/internal/app/machined/internal/platform"
|
||||
"github.com/talos-systems/talos/internal/app/machined/internal/runtime"
|
||||
"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/pkg/userdata"
|
||||
)
|
||||
|
||||
// Services represents the Services task.
|
||||
type Services struct{}
|
||||
|
||||
// NewServicesTask initializes and returns an Services task.
|
||||
func NewServicesTask() phase.Task {
|
||||
return &Services{}
|
||||
}
|
||||
|
||||
// RuntimeFunc returns the runtime function.
|
||||
func (task *Services) RuntimeFunc(mode runtime.Mode) phase.RuntimeFunc {
|
||||
return task.runtime
|
||||
}
|
||||
|
||||
func (task *Services) runtime(platform platform.Platform, data *userdata.UserData) (err error) {
|
||||
go startSystemServices(data)
|
||||
go startKubernetesServices(data)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func startSystemServices(data *userdata.UserData) {
|
||||
svcs := system.Services(data)
|
||||
// Start the services common to all nodes.
|
||||
svcs.Start(
|
||||
&services.Networkd{},
|
||||
&services.Containerd{},
|
||||
&services.Udevd{},
|
||||
&services.UdevdTrigger{},
|
||||
&services.OSD{},
|
||||
&services.NTPd{},
|
||||
)
|
||||
// Start the services common to all master nodes.
|
||||
if data.Services.Kubeadm.IsControlPlane() {
|
||||
svcs.Start(
|
||||
&services.Trustd{},
|
||||
&services.Proxyd{},
|
||||
)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
func startKubernetesServices(data *userdata.UserData) {
|
||||
svcs := system.Services(data)
|
||||
svcs.Start(
|
||||
&services.Kubelet{},
|
||||
&services.Kubeadm{},
|
||||
)
|
||||
}
|
@ -0,0 +1,14 @@
|
||||
/* 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 services_test
|
||||
|
||||
import "testing"
|
||||
|
||||
func TestEmpty(t *testing.T) {
|
||||
// added for accurate coverage estimation
|
||||
//
|
||||
// please remove it once any unit-test is added
|
||||
// for this package
|
||||
}
|
30
internal/app/machined/internal/phase/sysctls/sysctls.go
Normal file
30
internal/app/machined/internal/phase/sysctls/sysctls.go
Normal file
@ -0,0 +1,30 @@
|
||||
/* 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 sysctls
|
||||
|
||||
import (
|
||||
"github.com/talos-systems/talos/internal/app/machined/internal/phase"
|
||||
"github.com/talos-systems/talos/internal/app/machined/internal/platform"
|
||||
"github.com/talos-systems/talos/internal/app/machined/internal/runtime"
|
||||
"github.com/talos-systems/talos/internal/pkg/proc"
|
||||
"github.com/talos-systems/talos/pkg/userdata"
|
||||
)
|
||||
|
||||
// Sysctls represents the Sysctls task.
|
||||
type Sysctls struct{}
|
||||
|
||||
// NewSysctlsTask initializes and returns an UserData task.
|
||||
func NewSysctlsTask() phase.Task {
|
||||
return &Sysctls{}
|
||||
}
|
||||
|
||||
// RuntimeFunc returns the runtime function.
|
||||
func (task *Sysctls) RuntimeFunc(mode runtime.Mode) phase.RuntimeFunc {
|
||||
return task.runtime
|
||||
}
|
||||
|
||||
func (task *Sysctls) runtime(platform platform.Platform, data *userdata.UserData) (err error) {
|
||||
return proc.WriteSystemProperty(&proc.SystemProperty{Key: "net.ipv4.ip_forward", Value: "1"})
|
||||
}
|
14
internal/app/machined/internal/phase/sysctls/sysctls_test.go
Normal file
14
internal/app/machined/internal/phase/sysctls/sysctls_test.go
Normal file
@ -0,0 +1,14 @@
|
||||
/* 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 sysctls_test
|
||||
|
||||
import "testing"
|
||||
|
||||
func TestEmpty(t *testing.T) {
|
||||
// added for accurate coverage estimation
|
||||
//
|
||||
// please remove it once any unit-test is added
|
||||
// for this package
|
||||
}
|
@ -0,0 +1,35 @@
|
||||
/* 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 userdata
|
||||
|
||||
import (
|
||||
"github.com/talos-systems/talos/internal/app/machined/internal/mount"
|
||||
"github.com/talos-systems/talos/internal/app/machined/internal/phase"
|
||||
"github.com/talos-systems/talos/internal/app/machined/internal/platform"
|
||||
"github.com/talos-systems/talos/internal/app/machined/internal/runtime"
|
||||
"github.com/talos-systems/talos/pkg/userdata"
|
||||
)
|
||||
|
||||
// ExtraDevices represents the ExtraDevices task.
|
||||
type ExtraDevices struct{}
|
||||
|
||||
// NewExtraDevicesTask initializes and returns an UserData task.
|
||||
func NewExtraDevicesTask() phase.Task {
|
||||
return &ExtraDevices{}
|
||||
}
|
||||
|
||||
// RuntimeFunc returns the runtime function.
|
||||
func (task *ExtraDevices) RuntimeFunc(mode runtime.Mode) phase.RuntimeFunc {
|
||||
return task.runtime
|
||||
}
|
||||
|
||||
func (task *ExtraDevices) runtime(platform platform.Platform, data *userdata.UserData) (err error) {
|
||||
// Mount the extra devices.
|
||||
if err = mount.ExtraDevices(data); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
@ -0,0 +1,39 @@
|
||||
/* 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 userdata
|
||||
|
||||
import (
|
||||
"log"
|
||||
"os"
|
||||
|
||||
"github.com/talos-systems/talos/internal/app/machined/internal/phase"
|
||||
"github.com/talos-systems/talos/internal/app/machined/internal/platform"
|
||||
"github.com/talos-systems/talos/internal/app/machined/internal/runtime"
|
||||
"github.com/talos-systems/talos/pkg/userdata"
|
||||
)
|
||||
|
||||
// ExtraEnvVars represents the ExtraEnvVars task.
|
||||
type ExtraEnvVars struct{}
|
||||
|
||||
// NewExtraEnvVarsTask initializes and returns an UserData task.
|
||||
func NewExtraEnvVarsTask() phase.Task {
|
||||
return &ExtraEnvVars{}
|
||||
}
|
||||
|
||||
// RuntimeFunc returns the runtime function.
|
||||
func (task *ExtraEnvVars) RuntimeFunc(mode runtime.Mode) phase.RuntimeFunc {
|
||||
return task.runtime
|
||||
}
|
||||
|
||||
func (task *ExtraEnvVars) runtime(platform platform.Platform, data *userdata.UserData) (err error) {
|
||||
// Set the requested environment variables.
|
||||
for key, val := range data.Env {
|
||||
if err = os.Setenv(key, val); err != nil {
|
||||
log.Printf("WARNING failed to set enivronment variable: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
46
internal/app/machined/internal/phase/userdata/extra_files.go
Normal file
46
internal/app/machined/internal/phase/userdata/extra_files.go
Normal file
@ -0,0 +1,46 @@
|
||||
/* 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 userdata
|
||||
|
||||
import (
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"path/filepath"
|
||||
|
||||
"github.com/hashicorp/go-multierror"
|
||||
"github.com/talos-systems/talos/internal/app/machined/internal/phase"
|
||||
"github.com/talos-systems/talos/internal/app/machined/internal/platform"
|
||||
"github.com/talos-systems/talos/internal/app/machined/internal/runtime"
|
||||
"github.com/talos-systems/talos/pkg/userdata"
|
||||
)
|
||||
|
||||
// ExtraFiles represents the ExtraFiles task.
|
||||
type ExtraFiles struct{}
|
||||
|
||||
// NewExtraFilesTask initializes and returns an UserData task.
|
||||
func NewExtraFilesTask() phase.Task {
|
||||
return &ExtraFiles{}
|
||||
}
|
||||
|
||||
// RuntimeFunc returns the runtime function.
|
||||
func (task *ExtraFiles) RuntimeFunc(mode runtime.Mode) phase.RuntimeFunc {
|
||||
return task.runtime
|
||||
}
|
||||
|
||||
func (task *ExtraFiles) runtime(platform platform.Platform, data *userdata.UserData) (err error) {
|
||||
var result *multierror.Error
|
||||
|
||||
for _, f := range data.Files {
|
||||
p := filepath.Join("/var", f.Path)
|
||||
if err = os.MkdirAll(filepath.Dir(p), os.ModeDir); err != nil {
|
||||
result = multierror.Append(result, err)
|
||||
}
|
||||
if err = ioutil.WriteFile(p, []byte(f.Contents), f.Permissions); err != nil {
|
||||
result = multierror.Append(result, err)
|
||||
}
|
||||
}
|
||||
|
||||
return result.ErrorOrNil()
|
||||
}
|
61
internal/app/machined/internal/phase/userdata/pki.go
Normal file
61
internal/app/machined/internal/phase/userdata/pki.go
Normal file
@ -0,0 +1,61 @@
|
||||
/* 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 userdata
|
||||
|
||||
import (
|
||||
"log"
|
||||
"time"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
"github.com/talos-systems/talos/internal/app/machined/internal/phase"
|
||||
"github.com/talos-systems/talos/internal/app/machined/internal/platform"
|
||||
"github.com/talos-systems/talos/internal/app/machined/internal/runtime"
|
||||
"github.com/talos-systems/talos/internal/pkg/constants"
|
||||
"github.com/talos-systems/talos/internal/pkg/grpc/gen"
|
||||
"github.com/talos-systems/talos/pkg/crypto/x509"
|
||||
"github.com/talos-systems/talos/pkg/userdata"
|
||||
)
|
||||
|
||||
// PKI represents the PKI task.
|
||||
type PKI struct{}
|
||||
|
||||
// NewPKITask initializes and returns an UserData task.
|
||||
func NewPKITask() phase.Task {
|
||||
return &PKI{}
|
||||
}
|
||||
|
||||
// RuntimeFunc returns the runtime function.
|
||||
func (task *PKI) RuntimeFunc(mode runtime.Mode) phase.RuntimeFunc {
|
||||
return task.runtime
|
||||
}
|
||||
|
||||
func (task *PKI) runtime(platform platform.Platform, data *userdata.UserData) (err error) {
|
||||
if data.Services.Kubeadm.IsControlPlane() {
|
||||
log.Println("generating PKI locally")
|
||||
var csr *x509.CertificateSigningRequest
|
||||
if csr, err = data.NewIdentityCSR(); err != nil {
|
||||
return err
|
||||
}
|
||||
var crt *x509.Certificate
|
||||
crt, err = x509.NewCertificateFromCSRBytes(data.Security.OS.CA.Crt, data.Security.OS.CA.Key, csr.X509CertificateRequestPEM, x509.NotAfter(time.Now().Add(time.Duration(8760)*time.Hour)))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
data.Security.OS.Identity.Crt = crt.X509CertificatePEM
|
||||
return nil
|
||||
}
|
||||
|
||||
log.Println("generating PKI from trustd")
|
||||
var generator *gen.Generator
|
||||
generator, err = gen.NewGenerator(data, constants.TrustdPort)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "failed to create trustd client")
|
||||
}
|
||||
if err = generator.Identity(data); err != nil {
|
||||
return errors.Wrap(err, "failed to generate identity")
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
@ -0,0 +1,53 @@
|
||||
/* 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 userdata
|
||||
|
||||
import (
|
||||
"io/ioutil"
|
||||
"log"
|
||||
"os"
|
||||
|
||||
"github.com/talos-systems/talos/internal/app/machined/internal/phase"
|
||||
"github.com/talos-systems/talos/internal/app/machined/internal/platform"
|
||||
"github.com/talos-systems/talos/internal/app/machined/internal/runtime"
|
||||
"github.com/talos-systems/talos/internal/pkg/constants"
|
||||
"github.com/talos-systems/talos/pkg/userdata"
|
||||
"gopkg.in/yaml.v2"
|
||||
)
|
||||
|
||||
// SaveUserData represents the SaveUserData task.
|
||||
type SaveUserData struct{}
|
||||
|
||||
// NewSaveUserDataTask initializes and returns an UserData task.
|
||||
func NewSaveUserDataTask() phase.Task {
|
||||
return &SaveUserData{}
|
||||
}
|
||||
|
||||
// RuntimeFunc returns the runtime function.
|
||||
func (task *SaveUserData) RuntimeFunc(mode runtime.Mode) phase.RuntimeFunc {
|
||||
return task.runtime
|
||||
}
|
||||
|
||||
func (task *SaveUserData) runtime(platform platform.Platform, data *userdata.UserData) (err error) {
|
||||
if _, err = os.Stat(constants.UserDataPath); os.IsNotExist(err) {
|
||||
log.Println("saving userdata to disk")
|
||||
|
||||
var dataBytes []byte
|
||||
dataBytes, err = yaml.Marshal(data)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err = ioutil.WriteFile(constants.UserDataPath, dataBytes, 0400); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
log.Println("refusing to overwrite userdata on disk")
|
||||
|
||||
return nil
|
||||
}
|
73
internal/app/machined/internal/phase/userdata/userdata.go
Normal file
73
internal/app/machined/internal/phase/userdata/userdata.go
Normal file
@ -0,0 +1,73 @@
|
||||
/* 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 userdata
|
||||
|
||||
import (
|
||||
"github.com/talos-systems/talos/internal/app/machined/internal/phase"
|
||||
"github.com/talos-systems/talos/internal/app/machined/internal/platform"
|
||||
"github.com/talos-systems/talos/internal/app/machined/internal/runtime"
|
||||
"github.com/talos-systems/talos/internal/pkg/network"
|
||||
"github.com/talos-systems/talos/pkg/userdata"
|
||||
|
||||
kubeadmapi "k8s.io/kubernetes/cmd/kubeadm/app/apis/kubeadm"
|
||||
)
|
||||
|
||||
// UserData represents the UserData task.
|
||||
type UserData struct{}
|
||||
|
||||
// NewUserDataTask initializes and returns an UserData task.
|
||||
func NewUserDataTask() phase.Task {
|
||||
return &UserData{}
|
||||
}
|
||||
|
||||
// RuntimeFunc returns the runtime function.
|
||||
func (task *UserData) RuntimeFunc(mode runtime.Mode) phase.RuntimeFunc {
|
||||
switch mode {
|
||||
case runtime.Standard:
|
||||
return task.standard
|
||||
case runtime.Container:
|
||||
return task.container
|
||||
default:
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
func (task *UserData) standard(platform platform.Platform, data *userdata.UserData) (err error) {
|
||||
// Setup basic networking for the purposes of downloading the userdata.
|
||||
if err = network.InitNetwork(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
var d *userdata.UserData
|
||||
d, err = platform.UserData()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
*data = *d
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (task *UserData) container(platform platform.Platform, data *userdata.UserData) (err error) {
|
||||
var d *userdata.UserData
|
||||
d, err = platform.UserData()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
*data = *d
|
||||
|
||||
data.Services.Kubeadm.IgnorePreflightErrors = []string{"FileContent--proc-sys-net-bridge-bridge-nf-call-iptables", "Swap", "SystemVerification"}
|
||||
initConfiguration, ok := data.Services.Kubeadm.Configuration.(*kubeadmapi.InitConfiguration)
|
||||
if ok {
|
||||
initConfiguration.ClusterConfiguration.ComponentConfigs.Kubelet.FailSwapOn = false
|
||||
// See https://github.com/kubernetes/kubernetes/issues/58610#issuecomment-359552443
|
||||
max := int32(0)
|
||||
maxPerCore := int32(0)
|
||||
initConfiguration.ClusterConfiguration.ComponentConfigs.KubeProxy.Conntrack.Max = &max
|
||||
initConfiguration.ClusterConfiguration.ComponentConfigs.KubeProxy.Conntrack.MaxPerCore = &maxPerCore
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
@ -0,0 +1,14 @@
|
||||
/* 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 userdata_test
|
||||
|
||||
import "testing"
|
||||
|
||||
func TestEmpty(t *testing.T) {
|
||||
// added for accurate coverage estimation
|
||||
//
|
||||
// please remove it once any unit-test is added
|
||||
// for this package
|
||||
}
|
@ -0,0 +1,51 @@
|
||||
/* 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 container
|
||||
|
||||
import (
|
||||
"encoding/base64"
|
||||
"os"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
"github.com/talos-systems/talos/pkg/userdata"
|
||||
|
||||
"gopkg.in/yaml.v2"
|
||||
)
|
||||
|
||||
// Container is a platform for installing Talos via an Container image.
|
||||
type Container struct{}
|
||||
|
||||
// Name implements the platform.Platform interface.
|
||||
func (c *Container) Name() string {
|
||||
return "Container"
|
||||
}
|
||||
|
||||
// UserData implements the platform.Platform interface.
|
||||
func (c *Container) UserData() (data *userdata.UserData, err error) {
|
||||
s, ok := os.LookupEnv("USERDATA")
|
||||
if !ok {
|
||||
return nil, errors.New("missing USERDATA environment variable")
|
||||
}
|
||||
var decoded []byte
|
||||
if decoded, err = base64.StdEncoding.DecodeString(s); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
data = &userdata.UserData{}
|
||||
if err = yaml.Unmarshal(decoded, data); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return data, nil
|
||||
}
|
||||
|
||||
// Prepare implements the platform.Platform interface.
|
||||
func (c *Container) Prepare(data *userdata.UserData) (err error) {
|
||||
return nil
|
||||
}
|
||||
|
||||
// Install implements the platform.Platform interface.
|
||||
func (c *Container) Install(data *userdata.UserData) error {
|
||||
return nil
|
||||
}
|
@ -5,6 +5,8 @@
|
||||
package platform
|
||||
|
||||
import (
|
||||
"os"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
"github.com/talos-systems/talos/internal/app/machined/internal/platform/baremetal"
|
||||
"github.com/talos-systems/talos/internal/app/machined/internal/platform/cloud/aws"
|
||||
@ -12,6 +14,7 @@ import (
|
||||
"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/container"
|
||||
"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"
|
||||
@ -27,19 +30,31 @@ type Platform interface {
|
||||
}
|
||||
|
||||
// NewPlatform is a helper func for discovering the current platform.
|
||||
//
|
||||
// nolint: gocyclo
|
||||
func NewPlatform() (p Platform, err error) {
|
||||
var platform *string
|
||||
if platform = kernel.Cmdline().Get(constants.KernelParamPlatform).First(); platform == nil {
|
||||
return nil, errors.Errorf("kernel parameter %s was not found", constants.KernelParamPlatform)
|
||||
var platform string
|
||||
if p := kernel.Cmdline().Get(constants.KernelParamPlatform).First(); p != nil {
|
||||
platform = *p
|
||||
}
|
||||
|
||||
switch *platform {
|
||||
if p, ok := os.LookupEnv("PLATFORM"); ok {
|
||||
platform = p
|
||||
}
|
||||
|
||||
if platform == "" {
|
||||
return nil, errors.New("failed to determine platform")
|
||||
}
|
||||
|
||||
switch platform {
|
||||
case "aws":
|
||||
p = &aws.AWS{}
|
||||
case "azure":
|
||||
p = &azure.Azure{}
|
||||
case "bare-metal":
|
||||
p = &baremetal.BareMetal{}
|
||||
case "container":
|
||||
p = &container.Container{}
|
||||
case "googlecloud":
|
||||
p = &googlecloud.GoogleCloud{}
|
||||
case "iso":
|
||||
@ -49,7 +64,7 @@ func NewPlatform() (p Platform, err error) {
|
||||
case "vmware":
|
||||
p = &vmware.VMware{}
|
||||
default:
|
||||
return nil, errors.Errorf("platform not supported: %s", *platform)
|
||||
return nil, errors.Errorf("platform not supported: %s", platform)
|
||||
}
|
||||
|
||||
return p, nil
|
||||
|
20
internal/app/machined/internal/runtime/runtime.go
Normal file
20
internal/app/machined/internal/runtime/runtime.go
Normal file
@ -0,0 +1,20 @@
|
||||
/* 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 runtime
|
||||
|
||||
// Mode is a runtime mode.
|
||||
type Mode int
|
||||
|
||||
const (
|
||||
// Standard represents a runtime mode.
|
||||
Standard Mode = iota
|
||||
// Container represents a runtime mode.
|
||||
Container
|
||||
)
|
||||
|
||||
// String returns the string representation of a Mode.
|
||||
func (m Mode) String() string {
|
||||
return [...]string{"Standard", "Container"}[m]
|
||||
}
|
@ -5,379 +5,95 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"encoding/base64"
|
||||
"flag"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"log"
|
||||
"os"
|
||||
"os/signal"
|
||||
"strings"
|
||||
"syscall"
|
||||
"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/app/machined/internal/phase"
|
||||
apiptask "github.com/talos-systems/talos/internal/app/machined/internal/phase/api"
|
||||
"github.com/talos-systems/talos/internal/app/machined/internal/phase/install"
|
||||
"github.com/talos-systems/talos/internal/app/machined/internal/phase/network"
|
||||
"github.com/talos-systems/talos/internal/app/machined/internal/phase/rootfs"
|
||||
"github.com/talos-systems/talos/internal/app/machined/internal/phase/security"
|
||||
"github.com/talos-systems/talos/internal/app/machined/internal/phase/services"
|
||||
"github.com/talos-systems/talos/internal/app/machined/internal/phase/sysctls"
|
||||
userdatatask "github.com/talos-systems/talos/internal/app/machined/internal/phase/userdata"
|
||||
"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"
|
||||
|
||||
"golang.org/x/sys/unix"
|
||||
|
||||
kubeadmapi "k8s.io/kubernetes/cmd/kubeadm/app/apis/kubeadm"
|
||||
)
|
||||
|
||||
var (
|
||||
inContainer *bool
|
||||
rebootFlag = unix.LINUX_REBOOT_CMD_RESTART
|
||||
userdataArg *string
|
||||
)
|
||||
|
||||
func init() {
|
||||
inContainer = flag.Bool("in-container", false, "run Talos in a container")
|
||||
userdataArg = flag.String("userdata", "", "the base64 encoded userdata")
|
||||
flag.Parse()
|
||||
}
|
||||
|
||||
func kmsg(prefix string) (*os.File, error) {
|
||||
out, err := os.OpenFile("/dev/kmsg", os.O_RDWR|unix.O_CLOEXEC|unix.O_NONBLOCK|unix.O_NOCTTY, 0666)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "failed to open /dev/kmsg")
|
||||
}
|
||||
log.SetOutput(out)
|
||||
log.SetPrefix(prefix + " ")
|
||||
log.SetFlags(0)
|
||||
|
||||
return out, nil
|
||||
}
|
||||
|
||||
func container() (err error) {
|
||||
log.Println("preparing container based deploy")
|
||||
|
||||
log.Println("remounting volumes as shared mounts")
|
||||
targets := []string{"/", "/var/lib/kubelet", "/etc/cni"}
|
||||
for _, t := range targets {
|
||||
if err = unix.Mount("", t, "", unix.MS_SHARED, ""); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
if *userdataArg != "" {
|
||||
log.Printf("writing the user data: %s\n", constants.UserDataPath)
|
||||
var decoded []byte
|
||||
if decoded, err = base64.StdEncoding.DecodeString(*userdataArg); err != nil {
|
||||
return err
|
||||
}
|
||||
if err = ioutil.WriteFile(constants.UserDataPath, decoded, 0400); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
var data *userdata.UserData
|
||||
if data, err = userdata.Open(constants.UserDataPath); err != nil {
|
||||
func run() (err error) {
|
||||
if err = startup.RandSeed(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Workarounds for running in a container.
|
||||
|
||||
data.Services.Kubeadm.IgnorePreflightErrors = []string{"FileContent--proc-sys-net-bridge-bridge-nf-call-iptables", "Swap", "SystemVerification"}
|
||||
initConfiguration, ok := data.Services.Kubeadm.Configuration.(*kubeadmapi.InitConfiguration)
|
||||
if ok {
|
||||
initConfiguration.ClusterConfiguration.ComponentConfigs.Kubelet.FailSwapOn = false
|
||||
// See https://github.com/kubernetes/kubernetes/issues/58610#issuecomment-359552443
|
||||
max := int32(0)
|
||||
maxPerCore := int32(0)
|
||||
initConfiguration.ClusterConfiguration.ComponentConfigs.KubeProxy.Conntrack.Max = &max
|
||||
initConfiguration.ClusterConfiguration.ComponentConfigs.KubeProxy.Conntrack.MaxPerCore = &maxPerCore
|
||||
if err = os.Setenv("PATH", constants.PATH); err != nil {
|
||||
return errors.New("error setting PATH")
|
||||
}
|
||||
|
||||
log.Println("preparing the root filesystem")
|
||||
if err = rootfs.Prepare("", true, data); err != nil {
|
||||
data := &userdata.UserData{}
|
||||
phaserunner, err := phase.NewRunner(data)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
phaserunner.Add(
|
||||
phase.NewPhase(
|
||||
"system requirements",
|
||||
security.NewSecurityTask(),
|
||||
rootfs.NewSystemDirectoryTask(),
|
||||
rootfs.NewMountCgroupsTask(),
|
||||
sysctls.NewSysctlsTask(),
|
||||
),
|
||||
phase.NewPhase(
|
||||
"basic system configuration",
|
||||
rootfs.NewNetworkConfigurationTask(),
|
||||
rootfs.NewOSReleaseTask(),
|
||||
),
|
||||
phase.NewPhase(
|
||||
"userdata",
|
||||
userdatatask.NewUserDataTask(),
|
||||
),
|
||||
phase.NewPhase(
|
||||
"mount extra devices",
|
||||
userdatatask.NewExtraDevicesTask(),
|
||||
),
|
||||
phase.NewPhase(
|
||||
"user requests",
|
||||
userdatatask.NewPKITask(),
|
||||
network.NewUserDefinedNetworkTask(),
|
||||
userdatatask.NewExtraEnvVarsTask(),
|
||||
userdatatask.NewExtraFilesTask(),
|
||||
),
|
||||
phase.NewPhase(
|
||||
"installation",
|
||||
install.NewInstallTask(),
|
||||
rootfs.NewMountOverlayTask(),
|
||||
),
|
||||
phase.NewPhase(
|
||||
"setup /var",
|
||||
rootfs.NewVarDirectoriesTask(),
|
||||
),
|
||||
phase.NewPhase(
|
||||
"save userdata",
|
||||
userdatatask.NewSaveUserDataTask(),
|
||||
),
|
||||
phase.NewPhase(
|
||||
"service setup",
|
||||
apiptask.NewAPITask(),
|
||||
services.NewServicesTask(),
|
||||
),
|
||||
)
|
||||
|
||||
if err = phaserunner.Run(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func createOverlay(path string) error {
|
||||
log.Printf("mounting overlay for %s\n", path)
|
||||
|
||||
parts := strings.Split(path, "/")
|
||||
prefix := strings.Join(parts[1:], "-")
|
||||
diff := fmt.Sprintf("/var/%s-diff", prefix)
|
||||
workdir := fmt.Sprintf("/var/%s-workdir", prefix)
|
||||
|
||||
for _, s := range []string{diff, workdir} {
|
||||
if err := os.MkdirAll(s, 0700); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
opts := fmt.Sprintf("lowerdir=%s,upperdir=%s,workdir=%s", path, diff, workdir)
|
||||
if err := unix.Mount("overlay", path, "overlay", 0, opts); err != nil {
|
||||
return errors.Errorf("error creating overlay mount to %s: %v", path, err)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// 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
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for _, p := range []string{"/var/log", "/var/lib/kubelet", "/var/log/pods"} {
|
||||
if err = os.MkdirAll(p, 0700); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
// Read the user data.
|
||||
log.Printf("reading the user data: %s\n", constants.UserDataPath)
|
||||
var data *userdata.UserData
|
||||
if data, err = userdata.Open(constants.UserDataPath); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Mount the extra partitions.
|
||||
log.Printf("mounting the extra partitions")
|
||||
if err = mount.ExtraDevices(data); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Write any user specified files to disk.
|
||||
log.Println("writing the files specified in the user data to disk")
|
||||
if err = data.WriteFiles(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Set the requested environment variables.
|
||||
log.Println("setting environment variables")
|
||||
for key, val := range data.Env {
|
||||
if err = os.Setenv(key, val); err != nil {
|
||||
log.Printf("WARNING failed to set enivronment variable: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
poweroffCh, err := listenForPowerButton()
|
||||
if err != nil {
|
||||
log.Printf("WARNING: power off events will be ignored: %+v", err)
|
||||
}
|
||||
|
||||
termCh := make(chan os.Signal, 1)
|
||||
signal.Notify(termCh, syscall.SIGTERM)
|
||||
|
||||
// Get a handle to the system services API.
|
||||
svcs := system.Services(data)
|
||||
defer svcs.Shutdown()
|
||||
|
||||
// Instantiate internal init API
|
||||
api := reg.NewRegistrator(data)
|
||||
server := factory.NewServer(api)
|
||||
listener, err := factory.NewListener(
|
||||
factory.Network("unix"),
|
||||
factory.SocketPath(constants.InitSocketPath),
|
||||
)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
defer server.Stop()
|
||||
|
||||
go func() {
|
||||
// nolint: errcheck
|
||||
server.Serve(listener)
|
||||
}()
|
||||
|
||||
startSystemServices(data)
|
||||
startKubernetesServices(data)
|
||||
|
||||
select {
|
||||
case <-api.ShutdownCh:
|
||||
log.Printf("poweroff via API received")
|
||||
// poweroff, proceed to shutdown but mark as poweroff
|
||||
rebootFlag = unix.LINUX_REBOOT_CMD_POWER_OFF
|
||||
case <-poweroffCh:
|
||||
log.Printf("poweroff via ACPI")
|
||||
// poweroff, proceed to shutdown but mark as poweroff
|
||||
rebootFlag = unix.LINUX_REBOOT_CMD_POWER_OFF
|
||||
case <-termCh:
|
||||
log.Printf("SIGTERM received, rebooting...")
|
||||
case <-api.RebootCh:
|
||||
log.Printf("reboot via API received, rebooting...")
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func startSystemServices(data *userdata.UserData) {
|
||||
svcs := system.Services(data)
|
||||
|
||||
log.Println("starting system services")
|
||||
// Start the services common to all nodes.
|
||||
svcs.Start(
|
||||
&services.Networkd{},
|
||||
&services.Containerd{},
|
||||
&services.Udevd{},
|
||||
&services.UdevdTrigger{},
|
||||
&services.OSD{},
|
||||
&services.NTPd{},
|
||||
)
|
||||
// Start the services common to all master nodes.
|
||||
if data.Services.Kubeadm.IsControlPlane() {
|
||||
svcs.Start(
|
||||
&services.Trustd{},
|
||||
&services.Proxyd{},
|
||||
)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
func startKubernetesServices(data *userdata.UserData) {
|
||||
svcs := system.Services(data)
|
||||
|
||||
log.Println("starting kubernetes services")
|
||||
svcs.Start(
|
||||
&services.Kubelet{},
|
||||
&services.Kubeadm{},
|
||||
)
|
||||
}
|
||||
|
||||
func sync() {
|
||||
syncdone := make(chan struct{})
|
||||
|
||||
go func() {
|
||||
defer close(syncdone)
|
||||
unix.Sync()
|
||||
}()
|
||||
|
||||
log.Printf("waiting for sync...")
|
||||
|
||||
for i := 29; i >= 0; i-- {
|
||||
select {
|
||||
case <-syncdone:
|
||||
log.Printf("sync done")
|
||||
return
|
||||
case <-time.After(time.Second):
|
||||
}
|
||||
if i != 0 {
|
||||
log.Printf("waiting %d more seconds for sync to finish", i)
|
||||
}
|
||||
}
|
||||
|
||||
log.Printf("sync hasn't completed in time, aborting...")
|
||||
}
|
||||
|
||||
func reboot() {
|
||||
// See http://man7.org/linux/man-pages/man2/reboot.2.html.
|
||||
sync()
|
||||
|
||||
// nolint: errcheck
|
||||
unix.Reboot(rebootFlag)
|
||||
|
||||
if *inContainer {
|
||||
return
|
||||
}
|
||||
|
||||
select {}
|
||||
}
|
||||
|
||||
func recovery() {
|
||||
if r := recover(); r != nil {
|
||||
log.Printf("recovered from: %+v\n", r)
|
||||
@ -401,26 +117,12 @@ func main() {
|
||||
// services are gracefully shutdown.
|
||||
|
||||
// on any return from init.main(), initiate host reboot or shutdown
|
||||
defer reboot()
|
||||
// handle any panics in the main goroutine, and proceed to reboot() above
|
||||
defer recovery()
|
||||
|
||||
if err := startup.RandSeed(); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
// TODO(andrewrynhard): Remove this and be explicit.
|
||||
if err := os.Setenv("PATH", constants.PATH); err != nil {
|
||||
panic(errors.New("error setting PATH"))
|
||||
}
|
||||
|
||||
if *inContainer {
|
||||
if err := container(); err != nil {
|
||||
panic(errors.Wrap(err, "failed to prepare container based deploy"))
|
||||
}
|
||||
}
|
||||
|
||||
if err := root(); err != nil {
|
||||
if err := run(); err != nil {
|
||||
panic(errors.Wrap(err, "boot failed"))
|
||||
}
|
||||
|
||||
select {}
|
||||
}
|
||||
|
@ -17,6 +17,7 @@ import (
|
||||
specs "github.com/opencontainers/runtime-spec/specs-go"
|
||||
"github.com/pkg/errors"
|
||||
|
||||
"github.com/talos-systems/talos/internal/app/machined/internal/cni"
|
||||
"github.com/talos-systems/talos/internal/app/machined/pkg/system"
|
||||
"github.com/talos-systems/talos/internal/app/machined/pkg/system/conditions"
|
||||
"github.com/talos-systems/talos/internal/app/machined/pkg/system/health"
|
||||
@ -24,7 +25,6 @@ import (
|
||||
"github.com/talos-systems/talos/internal/app/machined/pkg/system/runner/containerd"
|
||||
"github.com/talos-systems/talos/internal/app/machined/pkg/system/runner/restart"
|
||||
"github.com/talos-systems/talos/internal/pkg/constants"
|
||||
"github.com/talos-systems/talos/internal/pkg/rootfs/cni"
|
||||
"github.com/talos-systems/talos/pkg/userdata"
|
||||
)
|
||||
|
||||
|
@ -9,6 +9,7 @@ import (
|
||||
"context"
|
||||
"fmt"
|
||||
"net"
|
||||
"path/filepath"
|
||||
|
||||
containerdapi "github.com/containerd/containerd"
|
||||
"github.com/containerd/containerd/oci"
|
||||
@ -74,7 +75,7 @@ func (o *OSD) Runner(data *userdata.UserData) (runner.Runner, error) {
|
||||
{Type: "bind", Destination: "/etc/kubernetes", Source: "/etc/kubernetes", Options: []string{"bind", "rw"}},
|
||||
{Type: "bind", Destination: "/etc/ssl", Source: "/etc/ssl", Options: []string{"bind", "ro"}},
|
||||
{Type: "bind", Destination: "/var/log", Source: "/var/log", Options: []string{"rbind", "rw"}},
|
||||
{Type: "bind", Destination: "/var/lib/init", Source: "/var/lib/init", Options: []string{"rbind", "rw"}},
|
||||
{Type: "bind", Destination: filepath.Dir(constants.InitSocketPath), Source: filepath.Dir(constants.InitSocketPath), Options: []string{"rbind", "rw"}},
|
||||
}
|
||||
|
||||
env := []string{}
|
||||
|
@ -143,7 +143,7 @@ const (
|
||||
TalosConfigEnvVar = "TALOSCONFIG"
|
||||
|
||||
// InitSocketPath is the path to file socket of init API
|
||||
InitSocketPath = "/var/lib/init/init.sock"
|
||||
InitSocketPath = "/run/system/init/init.sock"
|
||||
|
||||
// KernelAsset defines a well known name for our kernel filename
|
||||
KernelAsset = "vmlinuz"
|
||||
|
27
internal/pkg/kmsg/kmsg.go
Normal file
27
internal/pkg/kmsg/kmsg.go
Normal file
@ -0,0 +1,27 @@
|
||||
/* 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 kmsg
|
||||
|
||||
import (
|
||||
"log"
|
||||
"os"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
"golang.org/x/sys/unix"
|
||||
)
|
||||
|
||||
// Setup configures the log package to write to the kernel ring buffer via
|
||||
// /dev/kmsg.
|
||||
func Setup(prefix string) (*os.File, error) {
|
||||
out, err := os.OpenFile("/dev/kmsg", os.O_RDWR|unix.O_CLOEXEC|unix.O_NONBLOCK|unix.O_NOCTTY, 0666)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "failed to open /dev/kmsg")
|
||||
}
|
||||
log.SetOutput(out)
|
||||
log.SetPrefix(prefix + " ")
|
||||
log.SetFlags(0)
|
||||
|
||||
return out, nil
|
||||
}
|
14
internal/pkg/kmsg/kmsg_test.go
Normal file
14
internal/pkg/kmsg/kmsg_test.go
Normal file
@ -0,0 +1,14 @@
|
||||
/* 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 kmsg_test
|
||||
|
||||
import "testing"
|
||||
|
||||
func TestEmpty(t *testing.T) {
|
||||
// added for accurate coverage estimation
|
||||
//
|
||||
// please remove it once any unit-test is added
|
||||
// for this package
|
||||
}
|
@ -6,12 +6,26 @@ package proc
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"path"
|
||||
"strings"
|
||||
|
||||
"code.cloudfoundry.org/bytefmt"
|
||||
"github.com/prometheus/procfs"
|
||||
)
|
||||
|
||||
// SystemProperty represents a kernel system property.
|
||||
type SystemProperty struct {
|
||||
Key string
|
||||
Value string
|
||||
}
|
||||
|
||||
// WriteSystemProperty writes a value to a key under /proc/sys.
|
||||
func WriteSystemProperty(prop *SystemProperty) error {
|
||||
keyPath := path.Join("/proc/sys", strings.Replace(prop.Key, ".", "/", -1))
|
||||
return ioutil.WriteFile(keyPath, []byte(prop.Value), 0644)
|
||||
}
|
||||
|
||||
// ProcessList contains all of the process stats we want
|
||||
// to display via top
|
||||
type ProcessList struct {
|
||||
|
@ -1,23 +0,0 @@
|
||||
/* 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 proc
|
||||
|
||||
import (
|
||||
"io/ioutil"
|
||||
"path"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// SystemProperty represents a kernel system property.
|
||||
type SystemProperty struct {
|
||||
Key string
|
||||
Value string
|
||||
}
|
||||
|
||||
// WriteSystemProperty writes a value to a key under /proc/sys.
|
||||
func WriteSystemProperty(prop *SystemProperty) error {
|
||||
keyPath := path.Join("/proc/sys", strings.Replace(prop.Key, ".", "/", -1))
|
||||
return ioutil.WriteFile(keyPath, []byte(prop.Value), 0644)
|
||||
}
|
@ -1,138 +0,0 @@
|
||||
/* 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 rootfs
|
||||
|
||||
import (
|
||||
"io/ioutil"
|
||||
"log"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"time"
|
||||
|
||||
"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/proc"
|
||||
"github.com/talos-systems/talos/pkg/crypto/x509"
|
||||
"github.com/talos-systems/talos/pkg/userdata"
|
||||
yaml "gopkg.in/yaml.v2"
|
||||
)
|
||||
|
||||
// Prepare creates the files required by the installed binaries and libraries.
|
||||
// nolint: gocyclo
|
||||
func Prepare(s string, inContainer bool, data *userdata.UserData) (err error) {
|
||||
if !inContainer {
|
||||
// Enable IP forwarding.
|
||||
if err = proc.WriteSystemProperty(&proc.SystemProperty{Key: "net.ipv4.ip_forward", Value: "1"}); err != nil {
|
||||
return
|
||||
}
|
||||
// Kernel Self Protection Project recommended settings.
|
||||
if err = kernelHardening(); err != nil {
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
// Generate the identity certificate.
|
||||
if err = generatePKI(data); err != nil {
|
||||
return
|
||||
}
|
||||
// Save the user data to disk.
|
||||
if _, err = os.Stat(filepath.Join(s, constants.UserDataPath)); os.IsNotExist(err) || inContainer {
|
||||
log.Println("saving userdata to disk")
|
||||
var dataBytes []byte
|
||||
dataBytes, err = yaml.Marshal(data)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if err = ioutil.WriteFile(filepath.Join(s, constants.UserDataPath), dataBytes, 0400); err != nil {
|
||||
return err
|
||||
}
|
||||
} else {
|
||||
log.Println("using existing userdata on disk")
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
log.Printf("encountered error reading userdata: %v", err)
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func generatePKI(data *userdata.UserData) (err error) {
|
||||
log.Println("generating node identity PKI")
|
||||
if data.Services.Kubeadm.IsControlPlane() {
|
||||
log.Println("generating PKI locally")
|
||||
var csr *x509.CertificateSigningRequest
|
||||
if csr, err = data.NewIdentityCSR(); err != nil {
|
||||
return err
|
||||
}
|
||||
var crt *x509.Certificate
|
||||
crt, err = x509.NewCertificateFromCSRBytes(data.Security.OS.CA.Crt, data.Security.OS.CA.Key, csr.X509CertificateRequestPEM, x509.NotAfter(time.Now().Add(time.Duration(8760)*time.Hour)))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
data.Security.OS.Identity.Crt = crt.X509CertificatePEM
|
||||
return nil
|
||||
}
|
||||
|
||||
log.Println("generating PKI from trustd")
|
||||
var generator *gen.Generator
|
||||
generator, err = gen.NewGenerator(data, constants.TrustdPort)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "failed to create trustd client")
|
||||
}
|
||||
if err = generator.Identity(data); err != nil {
|
||||
return errors.Wrap(err, "failed to generate identity")
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func kernelHardening() (err error) {
|
||||
props := []*proc.SystemProperty{
|
||||
{
|
||||
Key: "kernel.kptr_restrict",
|
||||
Value: "1",
|
||||
},
|
||||
{
|
||||
Key: "kernel.dmesg_restrict",
|
||||
Value: "1",
|
||||
},
|
||||
{
|
||||
Key: "kernel.perf_event_paranoid",
|
||||
Value: "3",
|
||||
},
|
||||
// We can skip this sysctl because CONFIG_KEXEC is not set.
|
||||
// {
|
||||
// Key: "kernel.kexec_load_disabled",
|
||||
// Value: "1",
|
||||
// },
|
||||
{
|
||||
Key: "kernel.yama.ptrace_scope",
|
||||
Value: "1",
|
||||
},
|
||||
{
|
||||
Key: "user.max_user_namespaces",
|
||||
Value: "0",
|
||||
},
|
||||
{
|
||||
Key: "kernel.unprivileged_bpf_disabled",
|
||||
Value: "1",
|
||||
},
|
||||
{
|
||||
Key: "net.core.bpf_jit_harden",
|
||||
Value: "2",
|
||||
},
|
||||
}
|
||||
|
||||
for _, prop := range props {
|
||||
if err = proc.WriteSystemProperty(prop); err != nil {
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
@ -8,6 +8,7 @@ import (
|
||||
"github.com/hashicorp/go-multierror"
|
||||
"github.com/pkg/errors"
|
||||
"github.com/talos-systems/talos/internal/pkg/kernel"
|
||||
"github.com/talos-systems/talos/internal/pkg/proc"
|
||||
)
|
||||
|
||||
var (
|
||||
@ -40,3 +41,51 @@ func EnforceKSPPKernelParameters() error {
|
||||
|
||||
return result.ErrorOrNil()
|
||||
}
|
||||
|
||||
// EnforceKSPPSysctls verifies that all required KSPP kernel sysctls are set
|
||||
// with the right value.
|
||||
func EnforceKSPPSysctls() (err error) {
|
||||
props := []*proc.SystemProperty{
|
||||
{
|
||||
Key: "kernel.kptr_restrict",
|
||||
Value: "1",
|
||||
},
|
||||
{
|
||||
Key: "kernel.dmesg_restrict",
|
||||
Value: "1",
|
||||
},
|
||||
{
|
||||
Key: "kernel.perf_event_paranoid",
|
||||
Value: "3",
|
||||
},
|
||||
// We can skip this sysctl because CONFIG_KEXEC is not set.
|
||||
// {
|
||||
// Key: "kernel.kexec_load_disabled",
|
||||
// Value: "1",
|
||||
// },
|
||||
{
|
||||
Key: "kernel.yama.ptrace_scope",
|
||||
Value: "1",
|
||||
},
|
||||
{
|
||||
Key: "user.max_user_namespaces",
|
||||
Value: "0",
|
||||
},
|
||||
{
|
||||
Key: "kernel.unprivileged_bpf_disabled",
|
||||
Value: "1",
|
||||
},
|
||||
{
|
||||
Key: "net.core.bpf_jit_harden",
|
||||
Value: "2",
|
||||
},
|
||||
}
|
||||
|
||||
for _, prop := range props {
|
||||
if err = proc.WriteSystemProperty(prop); err != nil {
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
@ -144,9 +144,6 @@ func Reset() (err error) {
|
||||
"--force",
|
||||
)
|
||||
|
||||
cmd.Stdout = os.Stdout
|
||||
cmd.Stderr = os.Stderr
|
||||
|
||||
return cmd.Run()
|
||||
}
|
||||
|
||||
|
@ -11,7 +11,6 @@ import (
|
||||
"io/ioutil"
|
||||
stdlibnet "net"
|
||||
"os"
|
||||
"path"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
@ -89,22 +88,6 @@ type File struct {
|
||||
Path string `yaml:"path"`
|
||||
}
|
||||
|
||||
// WriteFiles writes the requested files to disk.
|
||||
func (data *UserData) WriteFiles() (err error) {
|
||||
for _, f := range data.Files {
|
||||
// TODO isnt there a const for the data mountpoint
|
||||
p := path.Join("/var", f.Path)
|
||||
if err = os.MkdirAll(path.Dir(p), os.ModeDir); err != nil {
|
||||
return
|
||||
}
|
||||
if err = ioutil.WriteFile(p, []byte(f.Contents), f.Permissions); err != nil {
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// NewIdentityCSR creates a new CSR for the node's identity certificate.
|
||||
func (data *UserData) NewIdentityCSR() (csr *x509.CertificateSigningRequest, err error) {
|
||||
var key *x509.Key
|
||||
|
Loading…
x
Reference in New Issue
Block a user