From: Tom Clegg Date: Thu, 2 Jun 2022 18:39:18 +0000 (-0400) Subject: Merge branch '15370-loopback-dispatchcloud' X-Git-Tag: 2.5.0~142 X-Git-Url: https://git.arvados.org/arvados.git/commitdiff_plain/86660414472d4ff0d8267f9845a753497bd41692?hp=-c Merge branch '15370-loopback-dispatchcloud' closes #15370 Arvados-DCO-1.1-Signed-off-by: Tom Clegg --- 86660414472d4ff0d8267f9845a753497bd41692 diff --combined lib/config/load.go index a547d14069,acc54cf92d..fbd01488a0 --- a/lib/config/load.go +++ b/lib/config/load.go @@@ -16,6 -16,7 +16,7 @@@ import "io/ioutil" "os" "regexp" + "runtime" "strconv" "strings" "time" @@@ -25,6 -26,7 +26,7 @@@ "github.com/imdario/mergo" "github.com/prometheus/client_golang/prometheus" "github.com/sirupsen/logrus" + "golang.org/x/sys/unix" ) //go:embed config.default.yml @@@ -297,7 -299,10 +299,10 @@@ func (ldr *Loader) Load() (*arvados.Con ldr.loadOldKeepBalanceConfig, ) } - loadFuncs = append(loadFuncs, ldr.setImplicitStorageClasses) + loadFuncs = append(loadFuncs, + ldr.setImplicitStorageClasses, + ldr.setLoopbackInstanceType, + ) for _, f := range loadFuncs { err = f(&cfg) if err != nil { @@@ -362,7 -367,7 +367,7 @@@ func (ldr *Loader) checkClusterID(label if emptyStringOk && clusterID == "" { return nil } else if !acceptableClusterIDRe.MatchString(clusterID) { - return fmt.Errorf("%s: cluster ID should be 5 alphanumeric characters", label) + return fmt.Errorf("%s: cluster ID should be 5 lowercase alphanumeric characters", label) } return nil } @@@ -415,6 -420,67 +420,67 @@@ func (ldr *Loader) checkEnum(label, val return fmt.Errorf("%s: unacceptable value %q: must be one of %q", label, value, accepted) } + func (ldr *Loader) setLoopbackInstanceType(cfg *arvados.Config) error { + for id, cc := range cfg.Clusters { + if !cc.Containers.CloudVMs.Enable || cc.Containers.CloudVMs.Driver != "loopback" { + continue + } + if len(cc.InstanceTypes) == 1 { + continue + } + if len(cc.InstanceTypes) > 1 { + return fmt.Errorf("Clusters.%s.InstanceTypes: cannot use multiple InstanceTypes with loopback driver", id) + } + // No InstanceTypes configured. Fill in implicit + // default. + hostram, err := getHostRAM() + if err != nil { + return err + } + scratch, err := getFilesystemSize(os.TempDir()) + if err != nil { + return err + } + cc.InstanceTypes = arvados.InstanceTypeMap{"localhost": { + Name: "localhost", + ProviderType: "localhost", + VCPUs: runtime.NumCPU(), + RAM: hostram, + Scratch: scratch, + IncludedScratch: scratch, + }} + cfg.Clusters[id] = cc + } + return nil + } + + func getFilesystemSize(path string) (arvados.ByteSize, error) { + var stat unix.Statfs_t + err := unix.Statfs(path, &stat) + if err != nil { + return 0, err + } + return arvados.ByteSize(stat.Blocks * uint64(stat.Bsize)), nil + } + + var reMemTotal = regexp.MustCompile(`(^|\n)MemTotal: *(\d+) kB\n`) + + func getHostRAM() (arvados.ByteSize, error) { + buf, err := os.ReadFile("/proc/meminfo") + if err != nil { + return 0, err + } + m := reMemTotal.FindSubmatch(buf) + if m == nil { + return 0, errors.New("error parsing /proc/meminfo: no MemTotal") + } + kb, err := strconv.ParseInt(string(m[2]), 10, 64) + if err != nil { + return 0, fmt.Errorf("error parsing /proc/meminfo: %q: %w", m[2], err) + } + return arvados.ByteSize(kb) * 1024, nil + } + func (ldr *Loader) setImplicitStorageClasses(cfg *arvados.Config) error { cluster: for id, cc := range cfg.Clusters { diff --combined lib/config/load_test.go index fd2921bd45,fb9792632c..a19400c191 --- a/lib/config/load_test.go +++ b/lib/config/load_test.go @@@ -13,6 -13,7 +13,7 @@@ import "os/exec" "reflect" "regexp" + "runtime" "strings" "testing" "time" @@@ -406,7 -407,7 +407,7 @@@ Clusters if v != nil { c.Logf("%#v", v.Clusters) } - c.Check(err, check.ErrorMatches, `.*cluster ID should be 5 alphanumeric characters.*`) + c.Check(err, check.ErrorMatches, `.*cluster ID should be 5 lowercase alphanumeric characters.*`) } } @@@ -601,6 -602,55 +602,55 @@@ func (s *LoadSuite) TestListKeys(c *che } } + func (s *LoadSuite) TestLoopbackInstanceTypes(c *check.C) { + ldr := testLoader(c, ` + Clusters: + z1111: + Containers: + CloudVMs: + Enable: true + Driver: loopback + InstanceTypes: + a: {} + b: {} + `, nil) + cfg, err := ldr.Load() + c.Check(err, check.ErrorMatches, `Clusters\.z1111\.InstanceTypes: cannot use multiple InstanceTypes with loopback driver`) + + ldr = testLoader(c, ` + Clusters: + z1111: + Containers: + CloudVMs: + Enable: true + Driver: loopback + `, nil) + cfg, err = ldr.Load() + c.Assert(err, check.IsNil) + cc, err := cfg.GetCluster("") + c.Assert(err, check.IsNil) + c.Check(cc.InstanceTypes, check.HasLen, 1) + c.Check(cc.InstanceTypes["localhost"].VCPUs, check.Equals, runtime.NumCPU()) + + ldr = testLoader(c, ` + Clusters: + z1111: + Containers: + CloudVMs: + Enable: true + Driver: loopback + InstanceTypes: + a: + VCPUs: 9 + `, nil) + cfg, err = ldr.Load() + c.Assert(err, check.IsNil) + cc, err = cfg.GetCluster("") + c.Assert(err, check.IsNil) + c.Check(cc.InstanceTypes, check.HasLen, 1) + c.Check(cc.InstanceTypes["a"].VCPUs, check.Equals, 9) + } + func (s *LoadSuite) TestWarnUnusedLocalKeep(c *check.C) { var logbuf bytes.Buffer _, err := testLoader(c, ` @@@ -849,3 -899,16 +899,16 @@@ arvados_config_source_timestamp_seconds `) } } + + func (s *LoadSuite) TestGetHostRAM(c *check.C) { + hostram, err := getHostRAM() + c.Check(err, check.IsNil) + c.Logf("getHostRAM() == %v", hostram) + } + + func (s *LoadSuite) TestGetFilesystemSize(c *check.C) { + path := c.MkDir() + size, err := getFilesystemSize(path) + c.Check(err, check.IsNil) + c.Logf("getFilesystemSize(%q) == %v", path, size) + }