Files
cloudpods/pkg/util/nodeid/nodeid.go
2019-03-29 14:47:48 +08:00

205 lines
4.1 KiB
Go

// Copyright 2019 Yunion
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package nodeid
import (
"bufio"
"bytes"
"crypto/md5"
"encoding/hex"
"fmt"
"io/ioutil"
"os"
"os/exec"
"reflect"
"regexp"
"runtime"
"sort"
"strconv"
"strings"
"yunion.io/x/log"
)
func execCmd(cmd *exec.Cmd) (string, error) {
var out bytes.Buffer
cmd.Stdout = &out
err := cmd.Run()
if err != nil {
return "", err
}
return out.String(), nil
}
func stringToLines(s string) (lines []string, err error) {
scanner := bufio.NewScanner(strings.NewReader(s))
for scanner.Scan() {
lines = append(lines, scanner.Text())
}
err = scanner.Err()
return
}
func getLinuxMacAddress() (string, error) {
path := "/sys/class/net/"
fs, e := ioutil.ReadDir(path)
if e != nil {
return "", e
}
macs := []string{}
for _, f := range fs {
link, e := os.Readlink(path + f.Name())
// 过滤掉虚拟网卡
if e != nil || !strings.Contains(link, "/pci") {
continue
}
u, e := ioutil.ReadFile(path + f.Name() + "/address")
if e == nil {
us := strings.TrimSpace(string(u))
isNew := true
for _, mac := range macs {
if us == "00:00:00:00:00:00" || us == mac {
isNew = false
}
}
if isNew {
macs = append(macs, us)
}
}
}
sort.SliceStable(macs, func(i, j int) bool {
return macs[i] < macs[j]
})
if len(macs) < 1 {
return "", fmt.Errorf("no available mac")
}
log.Debugf("macs info %s", macs)
mac := strings.Replace(macs[0], ":", "", -1)
if len(mac) != 12 {
return "", fmt.Errorf("mac length error")
}
return mac, nil
}
func getLinuxCpuInfo() (string, error) {
u, e := ioutil.ReadFile("/proc/cpuinfo")
if e != nil {
return "", e
}
lines, e := stringToLines(string(u))
filted := []string{}
for _, line := range lines {
l := strings.TrimSpace(line)
if strings.Contains(l, "cache size") || strings.Contains(l, "processor") {
v := strings.Split(l, ":")[1]
vn := strings.Replace(v, " ", "", -1)
isNew := true
for _, fl := range filted {
if fl == vn {
isNew = false
}
}
if isNew {
filted = append(filted, vn)
}
}
}
re := regexp.MustCompile(`([0-9]+)?.*`)
sort.SliceStable(filted, func(i, j int) bool {
a := re.FindStringSubmatch(filted[i])[1]
b := re.FindStringSubmatch(filted[j])[1]
if a == "" {
if b == "" {
return filted[i] < filted[j]
} else if strings.HasPrefix(b, "0") {
return false
} else {
return true
}
} else {
if b == "" {
if strings.HasPrefix(a, "0") {
return true
} else {
return false
}
} else {
if a == b {
return len(filted[i]) < len(filted[j])
} else {
ia, _ := strconv.Atoi(a)
ib, _ := strconv.Atoi(b)
return ia < ib
}
}
}
})
if len(filted) == 0 {
return "", fmt.Errorf("no available cpu info")
}
log.Debugf("cpu info %s", filted)
h := md5.New()
h.Write([]byte(strings.Join(filted, "\n") + "\n"))
cpumd5 := hex.EncodeToString(h.Sum(nil))
return cpumd5, nil
}
func getLinux() ([]string, error) {
ret := []string{}
funcs := make([]interface{}, 0)
funcs = append(funcs, getLinuxMacAddress)
funcs = append(funcs, getLinuxCpuInfo)
for _, f := range funcs {
fi := reflect.ValueOf(f)
s := fi.Call(nil)
if e := s[1].Interface(); e == nil {
ret = append(ret, s[0].Interface().(string))
}
}
return ret, nil
}
func GetNodeId() ([]byte, error) {
var f func() ([]string, error)
if runtime.GOOS == "linux" {
f = getLinux
} else {
return nil, fmt.Errorf("Unsupported OS")
}
ret, e := f()
if e != nil || len(ret) < 2 {
log.Debugf("service info %s", ret)
return nil, fmt.Errorf("Fail to generate Node ID")
}
sn := md5.Sum([]byte(ret[0] + ret[1]))
return sn[0:], nil
}