// detectSeriesAndHardwareCharacteristics detects the OS // series and hardware characteristics of the remote machine // by connecting to the machine and executing a bash script. func detectSeriesAndHardwareCharacteristics(host string) (hc instance.HardwareCharacteristics, series string, err error) { logger.Infof("Detecting series and characteristics on %s", host) cmd := ssh.Command("ubuntu@"+host, []string{"/bin/bash"}, nil) var stdout, stderr bytes.Buffer cmd.Stdout = &stdout cmd.Stderr = &stderr cmd.Stdin = bytes.NewBufferString(detectionScript) if err := cmd.Run(); err != nil { if stderr.Len() != 0 { err = fmt.Errorf("%v (%v)", err, strings.TrimSpace(stderr.String())) } return hc, "", err } lines := strings.Split(stdout.String(), "\n") series = strings.TrimSpace(lines[0]) arch := arch.NormaliseArch(lines[1]) hc.Arch = &arch // HardwareCharacteristics wants memory in megabytes, // meminfo reports it in kilobytes. memkB := strings.Fields(lines[2])[1] // "MemTotal: NNN kB" hc.Mem = new(uint64) *hc.Mem, err = strconv.ParseUint(memkB, 10, 0) *hc.Mem /= 1024 // For each "physical id", count the number of cores. // This way we only count physical cores, not additional // logical cores due to hyperthreading. recorded := make(map[string]bool) var physicalId string hc.CpuCores = new(uint64) for _, line := range lines[3:] { if strings.HasPrefix(line, "physical id") { physicalId = strings.TrimSpace(strings.SplitN(line, ":", 2)[1]) } else if strings.HasPrefix(line, "cpu cores") { var cores uint64 value := strings.TrimSpace(strings.SplitN(line, ":", 2)[1]) if cores, err = strconv.ParseUint(value, 10, 0); err != nil { return hc, "", err } if !recorded[physicalId] { *hc.CpuCores += cores recorded[physicalId] = true } } } if *hc.CpuCores == 0 { // In the case of a single-core, non-HT CPU, we'll see no // "physical id" or "cpu cores" lines. *hc.CpuCores = 1 } // TODO(axw) calculate CpuPower. What algorithm do we use? logger.Infof("series: %s, characteristics: %s", series, hc) return hc, series, nil }
func (s *archSuite) TestNormaliseArch(c *gc.C) { for _, test := range []struct { raw string arch string }{ {"windows", "windows"}, {"amd64", "amd64"}, {"x86_64", "amd64"}, {"386", "i386"}, {"i386", "i386"}, {"i486", "i386"}, {"arm", "armhf"}, {"armv", "armhf"}, {"armv7", "armhf"}, {"aarch64", "arm64"}, {"arm64", "arm64"}, {"ppc64el", "ppc64"}, {"ppc64le", "ppc64"}, } { arch := arch.NormaliseArch(test.raw) c.Check(arch, gc.Equals, test.arch) } }