1
0
mirror of https://github.com/rancher/os.git synced 2025-05-28 17:44:20 +00:00
os/cmd/control/bootstrap.go
2018-12-11 13:52:08 +08:00

190 lines
4.3 KiB
Go

package control
import (
"fmt"
"io/ioutil"
"os"
"os/exec"
"path/filepath"
"strings"
"time"
"github.com/rancher/os/config"
"github.com/rancher/os/pkg/log"
"github.com/rancher/os/pkg/util"
)
func BootstrapMain() {
log.InitLogger()
log.Debugf("bootstrapAction")
if err := UdevSettle(); err != nil {
log.Errorf("Failed to run udev settle: %v", err)
}
log.Debugf("bootstrapAction: loadingConfig")
cfg := config.LoadConfig()
log.Debugf("bootstrapAction: Rngd(%v)", cfg.Rancher.State.Rngd)
if cfg.Rancher.State.Rngd {
if err := runRngd(); err != nil {
log.Errorf("Failed to run rngd: %v", err)
}
}
log.Debugf("bootstrapAction: MdadmScan(%v)", cfg.Rancher.State.MdadmScan)
if cfg.Rancher.State.MdadmScan {
if err := mdadmScan(); err != nil {
log.Errorf("Failed to run mdadm scan: %v", err)
}
}
log.Debugf("bootstrapAction: cryptsetup(%v)", cfg.Rancher.State.Cryptsetup)
if cfg.Rancher.State.Cryptsetup {
if err := cryptsetup(); err != nil {
log.Errorf("Failed to run cryptsetup: %v", err)
}
}
log.Debugf("bootstrapAction: LvmScan(%v)", cfg.Rancher.State.LvmScan)
if cfg.Rancher.State.LvmScan {
if err := vgchange(); err != nil {
log.Errorf("Failed to run vgchange: %v", err)
}
}
stateScript := cfg.Rancher.State.Script
log.Debugf("bootstrapAction: stateScript(%v)", stateScript)
if stateScript != "" {
if err := runStateScript(stateScript); err != nil {
log.Errorf("Failed to run state script: %v", err)
}
}
log.Debugf("bootstrapAction: RunCommandSequence(%v)", cfg.Bootcmd)
err := util.RunCommandSequence(cfg.Bootcmd)
if err != nil {
log.Error(err)
}
if cfg.Rancher.State.Dev != "" && cfg.Rancher.State.Wait {
waitForRoot(cfg)
}
if len(cfg.Rancher.State.Autoformat) > 0 {
log.Infof("bootstrap container: Autoformat(%v) as %s", cfg.Rancher.State.Autoformat, "ext4")
if err := autoformat(cfg.Rancher.State.Autoformat); err != nil {
log.Errorf("Failed to run autoformat: %v", err)
}
}
log.Debugf("bootstrapAction: udev settle2")
if err := UdevSettle(); err != nil {
log.Errorf("Failed to run udev settle: %v", err)
}
}
func mdadmScan() error {
cmd := exec.Command("mdadm", "--assemble", "--scan")
cmd.Stdout = os.Stdout
cmd.Stderr = os.Stderr
return cmd.Run()
}
func vgchange() error {
cmd := exec.Command("vgchange", "--activate", "ay")
cmd.Stdout = os.Stdout
cmd.Stderr = os.Stderr
return cmd.Run()
}
func cryptsetup() error {
devices, err := util.BlkidType("crypto_LUKS")
if err != nil {
return err
}
for _, cryptdevice := range devices {
fdRead, err := os.Open("/dev/console")
if err != nil {
return err
}
defer fdRead.Close()
fdWrite, err := os.OpenFile("/dev/console", os.O_WRONLY|os.O_APPEND, 0)
if err != nil {
return err
}
defer fdWrite.Close()
cmd := exec.Command("cryptsetup", "luksOpen", cryptdevice, fmt.Sprintf("luks-%s", filepath.Base(cryptdevice)))
cmd.Stdout = fdWrite
cmd.Stderr = fdWrite
cmd.Stdin = fdRead
if err := cmd.Run(); err != nil {
log.Errorf("Failed to run cryptsetup for %s: %v", cryptdevice, err)
}
}
return nil
}
func runRngd() error {
// use /dev/urandom as random number input for rngd
// this is a really bad idea
// since I am simple filling the kernel entropy pool with entropy coming from the kernel itself!
// but this does not need to consider the user's hw rngd drivers.
cmd := exec.Command("rngd", "-r", "/dev/urandom", "-q")
cmd.Stdout = os.Stdout
cmd.Stderr = os.Stderr
return cmd.Run()
}
func runStateScript(script string) error {
f, err := ioutil.TempFile("", "")
if err != nil {
return err
}
if _, err := f.WriteString(script); err != nil {
return err
}
if err := f.Chmod(os.ModePerm); err != nil {
return err
}
if err := f.Close(); err != nil {
return err
}
return util.RunScript(f.Name())
}
func waitForRoot(cfg *config.CloudConfig) {
var dev string
for i := 0; i < 30; i++ {
dev = util.ResolveDevice(cfg.Rancher.State.Dev)
if dev != "" {
break
}
time.Sleep(time.Millisecond * 1000)
}
if dev == "" {
return
}
for i := 0; i < 30; i++ {
if _, err := os.Stat(dev); err == nil {
break
}
time.Sleep(time.Millisecond * 1000)
}
}
func autoformat(autoformatDevices []string) error {
cmd := exec.Command("/usr/sbin/auto-format.sh")
cmd.Stdout = os.Stdout
cmd.Stderr = os.Stderr
cmd.Env = []string{
"AUTOFORMAT=" + strings.Join(autoformatDevices, " "),
}
return cmd.Run()
}