inits/cmd/dkl-system-init/lvm.go
2019-02-05 09:36:11 +11:00

168 lines
3.0 KiB
Go

package main
import (
"bytes"
"io/ioutil"
"os"
"os/exec"
"path/filepath"
"strings"
"time"
"novit.nc/direktil/pkg/config"
"novit.nc/direktil/pkg/log"
)
const (
pDevName = "DEVNAME="
)
func init() {
go services.WaitPath("/run/lvm/lvmetad.socket")
services.Register(
&CommandService{
Name: "lvmetad",
Restart: StdRestart,
Needs: []string{"service:devfs"},
Command: []string{"lvmetad", "-f"},
PreExec: func() error {
mkdir("/run/lvm", 0700)
mkdir("/run/lock/lvm", 0700)
if !dmInProc() {
run("modprobe", "dm-mod")
}
return nil
},
},
&CommandService{
Name: "lvm",
Needs: []string{"file:/run/lvm/lvmetad.socket"},
Command: []string{"/bin/sh", "-c", `set -ex
/sbin/lvm pvscan
/sbin/lvm vgscan --mknodes
/sbin/lvm vgchange --sysinit -a ly
`},
},
)
}
func isDir(path string) bool {
s, err := os.Stat(path)
if err != nil {
if os.IsNotExist(err) {
return false
}
fatal("failed to query ", path, ": ", err)
}
return s.IsDir()
}
func dmInProc() bool {
for _, f := range []string{"devices", "misc"} {
c, err := ioutil.ReadFile("/proc/" + f)
if err != nil {
fatalf("failed to read %s: %v", f, err)
}
if !bytes.Contains(c, []byte("device-mapper")) {
return false
}
}
return true
}
func setupVG(udevMatch string) {
dev := ""
try := 0
retry:
paths, err := filepath.Glob("/sys/class/block/*")
if err != nil {
fatal("failed to list block devices: ", err)
}
for _, path := range paths {
// ignore loop devices
if strings.HasPrefix("loop", filepath.Base(path)) {
continue
}
// fetch udev informations
out, err := exec.Command("udevadm", "info", "-q", "property", path).CombinedOutput()
if err != nil {
initLog.Taintf(log.Warning, "udev query of %q failed: %v\n%s", path, err, string(out))
continue
}
propertyLines := strings.Split(strings.TrimSpace(string(out)), "\n")
devPath := ""
matches := false
for _, line := range propertyLines {
if strings.HasPrefix(line, pDevName) {
devPath = line[len(pDevName):]
}
if line == udevMatch {
matches = true
}
if devPath != "" && matches {
break
}
}
if devPath != "" && matches {
dev = devPath
break
}
}
if dev == "" {
time.Sleep(1 * time.Second)
try++
if try > 30 {
fatal("storage device not found after 30s, failing.")
}
goto retry
}
initLog.Taint(log.Info, "found storage device at ", dev)
run("pvcreate", dev)
run("vgcreate", "storage", dev)
}
func setupLV(volume config.VolumeDef) {
if volume.Extents != "" {
run("lvcreate", "-l", volume.Extents, "-n", volume.Name, "storage")
} else {
run("lvcreate", "-L", volume.Size, "-n", volume.Name, "storage")
}
// wait the device link
devPath := "/dev/storage/" + volume.Name
for i := 0; i < 300; i++ {
_, err := os.Stat(devPath)
if err == nil {
break
}
time.Sleep(100 * time.Millisecond)
}
args := make([]string, 0)
switch volume.FS {
case "btrfs":
args = append(args, "-f")
case "ext4":
args = append(args, "-F")
}
run("mkfs."+volume.FS, append(args, devPath)...)
}