158 lines
2.9 KiB
Go
158 lines
2.9 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")
|
||
|
}
|
||
|
|
||
|
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, "/dev/storage/"+volume.Name)...)
|
||
|
}
|