Example #1
0
func (f *CPUFingerprint) Fingerprint(cfg *config.Config, node *structs.Node) (bool, error) {
	if err := stats.Init(); err != nil {
		return false, fmt.Errorf("Unable to obtain CPU information: %v", err)
	}

	modelName := stats.CPUModelName()
	if modelName != "" {
		node.Attributes["cpu.modelname"] = modelName
	}

	mhz := stats.CPUMHzPerCore()
	node.Attributes["cpu.frequency"] = fmt.Sprintf("%.0f", mhz)
	f.logger.Printf("[DEBUG] fingerprint.cpu: frequency: %.0f MHz", mhz)

	numCores := stats.CPUNumCores()
	node.Attributes["cpu.numcores"] = fmt.Sprintf("%d", numCores)
	f.logger.Printf("[DEBUG] fingerprint.cpu: core count: %d", numCores)

	tt := stats.TotalTicksAvailable()
	node.Attributes["cpu.totalcompute"] = fmt.Sprintf("%.0f", tt)

	if node.Resources == nil {
		node.Resources = &structs.Resources{}
	}

	node.Resources.CPU = int(tt)

	return true, nil
}
Example #2
0
func (f *NetworkFingerprint) Fingerprint(cfg *config.Config, node *structs.Node) (bool, error) {
	// newNetwork is populated and addded to the Nodes resources
	newNetwork := &structs.NetworkResource{}

	// eth0 is the default device for Linux, and en0 is default for OS X
	defaultDevice := "eth0"
	if "darwin" == runtime.GOOS {
		defaultDevice = "en0"
	}

	newNetwork.Device = defaultDevice

	if ip := f.ifConfig(defaultDevice); ip != "" {
		node.Attributes["network.ip-address"] = ip
		newNetwork.IP = ip
		newNetwork.CIDR = newNetwork.IP + "/32"
	}

	if throughput := f.linkSpeed(defaultDevice); throughput > 0 {
		newNetwork.MBits = throughput
	}

	if node.Resources == nil {
		node.Resources = &structs.Resources{}
	}

	node.Resources.Networks = append(node.Resources.Networks, newNetwork)

	// return true, because we have a network connection
	return true, nil
}
Example #3
0
func (f *StorageFingerprint) Fingerprint(cfg *config.Config, node *structs.Node) (bool, error) {

	// Initialize these to empty defaults
	node.Attributes["unique.storage.volume"] = ""
	node.Attributes["unique.storage.bytestotal"] = ""
	node.Attributes["unique.storage.bytesfree"] = ""
	if node.Resources == nil {
		node.Resources = &structs.Resources{}
	}

	// Guard against unset AllocDir
	storageDir := cfg.AllocDir
	if storageDir == "" {
		var err error
		storageDir, err = os.Getwd()
		if err != nil {
			return false, fmt.Errorf("unable to get CWD from filesystem: %s", err)
		}
	}

	volume, total, free, err := f.diskFree(storageDir)
	if err != nil {
		return false, fmt.Errorf("failed to determine disk space for %s: %v", storageDir, err)
	}

	node.Attributes["unique.storage.volume"] = volume
	node.Attributes["unique.storage.bytestotal"] = strconv.FormatUint(total, 10)
	node.Attributes["unique.storage.bytesfree"] = strconv.FormatUint(free, 10)

	node.Resources.DiskMB = int(free / bytesPerMegabyte)

	return true, nil
}
Example #4
0
func (f *CPUFingerprint) Fingerprint(cfg *config.Config, node *structs.Node) (bool, error) {
	cpuInfo, err := cpu.Info()
	if err != nil {
		f.logger.Println("[WARN] Error reading CPU information:", err)
		return false, err
	}

	var numCores int32
	var mhz float64
	var modelName string

	// Assume all CPUs found have same Model. Log if not.
	// If CPUInfo() returns nil above, this loop is still safe
	for _, c := range cpuInfo {
		numCores += c.Cores
		mhz += c.Mhz

		if modelName != "" && modelName != c.ModelName {
			f.logger.Println("[WARN] Found different model names in the same CPU information. Recording last found")
		}
		modelName = c.ModelName
	}
	// Get average CPU frequency
	mhz /= float64(len(cpuInfo))

	if mhz > 0 {
		node.Attributes["cpu.frequency"] = fmt.Sprintf("%.6f", mhz)
		f.logger.Printf("[DEBUG] fingerprint.cpu: frequency: %02.1fMHz", mhz)
	}

	if numCores <= 0 {
		const defaultCPUCoreCount = 1
		f.logger.Printf("[DEBUG] fingerprint.cpu: unable to find core count, defaulting to %d", defaultCPUCoreCount)
		numCores = defaultCPUCoreCount
	}

	if numCores > 0 {
		node.Attributes["cpu.numcores"] = fmt.Sprintf("%d", numCores)
		f.logger.Printf("[DEBUG] fingerprint.cpu: core count: %d", numCores)
	}

	if mhz > 0 && numCores > 0 {
		tc := float64(numCores) * mhz
		node.Attributes["cpu.totalcompute"] = fmt.Sprintf("%.6f", tc)

		if node.Resources == nil {
			node.Resources = &structs.Resources{}
		}

		node.Resources.CPU = int(tc)
	}

	if modelName != "" {
		node.Attributes["cpu.modelname"] = modelName
	}

	return true, nil
}
Example #5
0
func (f *NetworkFingerprint) Fingerprint(cfg *config.Config, node *structs.Node) (bool, error) {
	// newNetwork is populated and addded to the Nodes resources
	newNetwork := &structs.NetworkResource{}
	defaultDevice := ""
	ip := ""

	// 1. Use user-defined network device
	// 2. Use first interface found in the system for non-dev mode. (dev mode uses lo by default.)
	if cfg.NetworkInterface != "" {
		defaultDevice = cfg.NetworkInterface
		ip = f.ipAddress(defaultDevice)
	} else {

		intfs, err := net.Interfaces()
		if err != nil {
			return false, err
		}

		for _, i := range intfs {
			if (i.Flags&net.FlagUp != 0) && (i.Flags&(net.FlagLoopback|net.FlagPointToPoint) == 0) {
				if ip = f.ipAddress(i.Name); ip != "" {
					defaultDevice = i.Name
					break
				}
			}
		}
	}

	if (defaultDevice != "") && (ip != "") {
		newNetwork.Device = defaultDevice
		node.Attributes["network.ip-address"] = ip
		newNetwork.IP = ip
		newNetwork.CIDR = newNetwork.IP + "/32"
	} else {
		return false, fmt.Errorf("Unable to find any network interface which has IP address")
	}

	if throughput := f.linkSpeed(defaultDevice); throughput > 0 {
		newNetwork.MBits = throughput
	} else {
		f.logger.Printf("[DEBUG] fingerprint.network: Unable to read link speed; setting to default %v", cfg.NetworkSpeed)
		newNetwork.MBits = cfg.NetworkSpeed
	}

	if node.Resources == nil {
		node.Resources = &structs.Resources{}
	}

	node.Resources.Networks = append(node.Resources.Networks, newNetwork)

	// return true, because we have a network connection
	return true, nil
}
Example #6
0
func (f *NetworkFingerprint) Fingerprint(cfg *config.Config, node *structs.Node) (bool, error) {
	// newNetwork is populated and addded to the Nodes resources
	newNetwork := &structs.NetworkResource{}
	var ip string

	intf, err := f.findInterface(cfg.NetworkInterface)
	switch {
	case err != nil:
		return false, fmt.Errorf("Error while detecting network interface during fingerprinting: %v", err)
	case intf == nil:
		// No interface could be found
		return false, nil
	}

	if ip, err = f.ipAddress(intf); err != nil {
		return false, fmt.Errorf("Unable to find IP address of interface: %s, err: %v", intf.Name, err)
	}

	newNetwork.Device = intf.Name
	node.Attributes["unique.network.ip-address"] = ip
	newNetwork.IP = ip
	newNetwork.CIDR = newNetwork.IP + "/32"

	f.logger.Printf("[DEBUG] fingerprint.network: Detected interface %v with IP %v during fingerprinting", intf.Name, ip)

	throughput := f.linkSpeed(intf.Name)
	if cfg.NetworkSpeed != 0 {
		newNetwork.MBits = cfg.NetworkSpeed
		f.logger.Printf("[DEBUG] fingerprint.network: setting link speed to user configured speed: %d", newNetwork.MBits)
	} else if throughput != 0 {
		newNetwork.MBits = throughput
		f.logger.Printf("[DEBUG] fingerprint.network: link speed for %v set to %v", intf.Name, newNetwork.MBits)
	} else {
		newNetwork.MBits = defaultNetworkSpeed
		f.logger.Printf("[DEBUG] fingerprint.network: link speed could not be detected and no speed specified by user. Defaulting to %d", defaultNetworkSpeed)
	}

	if node.Resources == nil {
		node.Resources = &structs.Resources{}
	}

	node.Resources.Networks = append(node.Resources.Networks, newNetwork)

	// return true, because we have a network connection
	return true, nil
}
Example #7
0
func (f *MemoryFingerprint) Fingerprint(cfg *config.Config, node *structs.Node) (bool, error) {
	memInfo, err := mem.VirtualMemory()
	if err != nil {
		f.logger.Printf("[WARN] Error reading memory information: %s", err)
		return false, err
	}

	if memInfo.Total > 0 {
		node.Attributes["memory.totalbytes"] = fmt.Sprintf("%d", memInfo.Total)

		if node.Resources == nil {
			node.Resources = &structs.Resources{}
		}
		node.Resources.MemoryMB = int(memInfo.Total / 1024 / 1024)
	}

	return true, nil
}
Example #8
0
func (f *NetworkFingerprint) Fingerprint(cfg *config.Config, node *structs.Node) (bool, error) {
	// newNetwork is populated and addded to the Nodes resources
	newNetwork := &structs.NetworkResource{}
	var ip string

	intf, err := f.findInterface(cfg.NetworkInterface)
	if err != nil {
		return false, fmt.Errorf("Error while detecting network interface during fingerprinting: %v", err)
	}

	// No interface could be found
	if intf == nil {
		return false, nil
	}

	if ip, err = f.ipAddress(intf); err != nil {
		return false, fmt.Errorf("Unable to find IP address of interface: %s, err: %v", intf.Name, err)
	}

	newNetwork.Device = intf.Name
	node.Attributes["network.ip-address"] = ip
	newNetwork.IP = ip
	newNetwork.CIDR = newNetwork.IP + "/32"

	f.logger.Printf("[DEBUG] fingerprint.network: Detected interface %v  with IP %v during fingerprinting", intf.Name, ip)

	if throughput := f.linkSpeed(intf.Name); throughput > 0 {
		newNetwork.MBits = throughput
	} else {
		f.logger.Printf("[DEBUG] fingerprint.network: Unable to read link speed; setting to default %v", cfg.NetworkSpeed)
		newNetwork.MBits = cfg.NetworkSpeed
	}

	if node.Resources == nil {
		node.Resources = &structs.Resources{}
	}

	node.Resources.Networks = append(node.Resources.Networks, newNetwork)

	// return true, because we have a network connection
	return true, nil
}
Example #9
0
func (f *NetworkFingerprint) Fingerprint(cfg *config.Config, node *structs.Node) (bool, error) {
	// newNetwork is populated and addded to the Nodes resources
	newNetwork := &structs.NetworkResource{}

	// eth0 is the default device for Linux, and en0 is default for OS X
	defaultDevice := "eth0"
	if "darwin" == runtime.GOOS {
		defaultDevice = "en0"
	}
	// User-defined override for the default interface
	if cfg.NetworkInterface != "" {
		defaultDevice = cfg.NetworkInterface
	}

	newNetwork.Device = defaultDevice

	if ip := f.ipAddress(defaultDevice); ip != "" {
		node.Attributes["network.ip-address"] = ip
		newNetwork.IP = ip
		newNetwork.CIDR = newNetwork.IP + "/32"
	} else {
		return false, fmt.Errorf("Unable to determine IP on network interface %v", defaultDevice)
	}

	if throughput := f.linkSpeed(defaultDevice); throughput > 0 {
		newNetwork.MBits = throughput
	} else {
		f.logger.Printf("[DEBUG] fingerprint.network: Unable to read link speed; setting to default %v", cfg.NetworkSpeed)
		newNetwork.MBits = cfg.NetworkSpeed
	}

	if node.Resources == nil {
		node.Resources = &structs.Resources{}
	}

	node.Resources.Networks = append(node.Resources.Networks, newNetwork)

	// return true, because we have a network connection
	return true, nil
}
Example #10
0
func (f *StorageFingerprint) Fingerprint(cfg *config.Config, node *structs.Node) (bool, error) {

	// Initialize these to empty defaults
	node.Attributes["storage.volume"] = ""
	node.Attributes["storage.bytestotal"] = ""
	node.Attributes["storage.bytesfree"] = ""
	if node.Resources == nil {
		node.Resources = &structs.Resources{}
	}

	// Guard against unset AllocDir
	storageDir := cfg.AllocDir
	if storageDir == "" {
		var err error
		storageDir, err = os.Getwd()
		if err != nil {
			return false, fmt.Errorf("Unable to get CWD from filesystem: %s", err)
		}
	}

	if runtime.GOOS == "windows" {
		path, err := filepath.Abs(storageDir)
		if err != nil {
			return false, fmt.Errorf("Failed to detect volume for storage directory %s: %s", storageDir, err)
		}
		volume := filepath.VolumeName(path)
		node.Attributes["storage.volume"] = volume
		out, err := exec.Command("fsutil", "volume", "diskfree", volume).Output()
		if err != nil {
			return false, fmt.Errorf("Failed to inspect free space from volume %s: %s", volume, err)
		}
		outstring := string(out)

		totalMatches := reWindowsTotalSpace.FindStringSubmatch(outstring)
		if len(totalMatches) == 2 {
			node.Attributes["storage.bytestotal"] = totalMatches[1]
			total, err := strconv.ParseInt(totalMatches[1], 10, 64)
			if err != nil {
				return false, fmt.Errorf("Failed to parse storage.bytestotal in bytes: %s", err)
			}
			// Convert from bytes to to MB
			node.Resources.DiskMB = int(total / 1024 / 1024)
		} else {
			return false, fmt.Errorf("Failed to parse output from fsutil")
		}

		freeMatches := reWindowsFreeSpace.FindStringSubmatch(outstring)
		if len(freeMatches) == 2 {
			node.Attributes["storage.bytesfree"] = freeMatches[1]
			_, err := strconv.ParseInt(freeMatches[1], 10, 64)
			if err != nil {
				return false, fmt.Errorf("Failed to parse storage.bytesfree in bytes: %s", err)
			}

		} else {
			return false, fmt.Errorf("Failed to parse output from fsutil")
		}
	} else {
		path, err := filepath.Abs(storageDir)
		if err != nil {
			return false, fmt.Errorf("Failed to determine absolute path for %s", storageDir)
		}

		// Use -k to standardize the output values between darwin and linux
		mountOutput, err := exec.Command("df", "-k", path).Output()
		if err != nil {
			return false, fmt.Errorf("Failed to determine mount point for %s", path)
		}
		// Output looks something like:
		//	Filesystem 1024-blocks      Used Available Capacity   iused    ifree %iused  Mounted on
		//	/dev/disk1   487385240 423722532  63406708    87% 105994631 15851677   87%   /
		//	[0] volume [1] capacity [2] SKIP  [3] free
		lines := strings.Split(string(mountOutput), "\n")
		if len(lines) < 2 {
			return false, fmt.Errorf("Failed to parse `df` output; expected at least 2 lines")
		}
		fields := strings.Fields(lines[1])
		if len(fields) < 4 {
			return false, fmt.Errorf("Failed to parse `df` output; expected at least 4 columns")
		}
		node.Attributes["storage.volume"] = fields[0]

		total, err := strconv.ParseInt(fields[1], 10, 64)
		if err != nil {
			return false, fmt.Errorf("Failed to parse storage.bytestotal size in kilobytes")
		}
		node.Attributes["storage.bytestotal"] = strconv.FormatInt(total*1024, 10)

		free, err := strconv.ParseInt(fields[3], 10, 64)
		if err != nil {
			return false, fmt.Errorf("Failed to parse storage.bytesfree size in kilobytes")
		}
		// Convert from KB to MB
		node.Resources.DiskMB = int(free / 1024)
		// Convert from KB to bytes
		node.Attributes["storage.bytesfree"] = strconv.FormatInt(free*1024, 10)
	}

	return true, nil
}
Example #11
0
func (f *EnvAWSFingerprint) Fingerprint(cfg *config.Config, node *structs.Node) (bool, error) {
	if !isAWS() {
		return false, nil
	}

	// newNetwork is populated and addded to the Nodes resources
	newNetwork := &structs.NetworkResource{
		Device: "eth0",
	}

	if node.Links == nil {
		node.Links = make(map[string]string)
	}
	metadataURL := os.Getenv("AWS_ENV_URL")
	if metadataURL == "" {
		metadataURL = DEFAULT_AWS_URL
	}

	// assume 2 seconds is enough time for inside AWS network
	client := &http.Client{
		Timeout:   2 * time.Second,
		Transport: cleanhttp.DefaultTransport(),
	}

	keys := []string{
		"ami-id",
		"hostname",
		"instance-id",
		"instance-type",
		"local-hostname",
		"local-ipv4",
		"public-hostname",
		"public-ipv4",
		"placement/availability-zone",
	}
	for _, k := range keys {
		res, err := client.Get(metadataURL + k)
		if err != nil {
			// if it's a URL error, assume we're not in an AWS environment
			// TODO: better way to detect AWS? Check xen virtualization?
			if _, ok := err.(*url.Error); ok {
				return false, nil
			}
			// not sure what other errors it would return
			return false, err
		}
		resp, err := ioutil.ReadAll(res.Body)
		res.Body.Close()
		if err != nil {
			f.logger.Printf("[ERR]: fingerprint.env_aws: Error reading response body for AWS %s", k)
		}

		// assume we want blank entries
		key := strings.Replace(k, "/", ".", -1)
		node.Attributes["platform.aws."+key] = strings.Trim(string(resp), "\n")
	}

	// copy over network specific information
	if node.Attributes["platform.aws.local-ipv4"] != "" {
		node.Attributes["network.ip-address"] = node.Attributes["platform.aws.local-ipv4"]
		newNetwork.IP = node.Attributes["platform.aws.local-ipv4"]
		newNetwork.CIDR = newNetwork.IP + "/32"
	}

	// find LinkSpeed from lookup
	if throughput := f.linkSpeed(); throughput > 0 {
		newNetwork.MBits = throughput
	}

	if node.Resources == nil {
		node.Resources = &structs.Resources{}
	}
	node.Resources.Networks = append(node.Resources.Networks, newNetwork)

	// populate Node Network Resources

	// populate Links
	node.Links["aws.ec2"] = node.Attributes["platform.aws.placement.availability-zone"] + "." + node.Attributes["platform.aws.instance-id"]

	return true, nil
}
Example #12
0
func (f *EnvAWSFingerprint) Fingerprint(cfg *config.Config, node *structs.Node) (bool, error) {
	if !f.isAWS() {
		return false, nil
	}

	// newNetwork is populated and addded to the Nodes resources
	newNetwork := &structs.NetworkResource{
		Device: "eth0",
	}

	if node.Links == nil {
		node.Links = make(map[string]string)
	}
	metadataURL := os.Getenv("AWS_ENV_URL")
	if metadataURL == "" {
		metadataURL = DEFAULT_AWS_URL
	}

	// assume 2 seconds is enough time for inside AWS network
	client := &http.Client{
		Timeout:   2 * time.Second,
		Transport: cleanhttp.DefaultTransport(),
	}

	// Keys and whether they should be namespaced as unique. Any key whose value
	// uniquely identifies a node, such as ip, should be marked as unique. When
	// marked as unique, the key isn't included in the computed node class.
	keys := map[string]bool{
		"ami-id":                      true,
		"hostname":                    true,
		"instance-id":                 true,
		"instance-type":               false,
		"local-hostname":              true,
		"local-ipv4":                  true,
		"public-hostname":             true,
		"public-ipv4":                 true,
		"placement/availability-zone": false,
	}
	for k, unique := range keys {
		res, err := client.Get(metadataURL + k)
		if res.StatusCode != http.StatusOK {
			f.logger.Printf("[WARN]: fingerprint.env_aws: Could not read value for attribute %q", k)
			continue
		}
		if err != nil {
			// if it's a URL error, assume we're not in an AWS environment
			// TODO: better way to detect AWS? Check xen virtualization?
			if _, ok := err.(*url.Error); ok {
				return false, nil
			}
			// not sure what other errors it would return
			return false, err
		}
		resp, err := ioutil.ReadAll(res.Body)
		res.Body.Close()
		if err != nil {
			f.logger.Printf("[ERR]: fingerprint.env_aws: Error reading response body for AWS %s", k)
		}

		// assume we want blank entries
		key := "platform.aws." + strings.Replace(k, "/", ".", -1)
		if unique {
			key = structs.UniqueNamespace(key)
		}

		node.Attributes[key] = strings.Trim(string(resp), "\n")
	}

	// copy over network specific information
	if val := node.Attributes["unique.platform.aws.local-ipv4"]; val != "" {
		node.Attributes["unique.network.ip-address"] = val
		newNetwork.IP = val
		newNetwork.CIDR = newNetwork.IP + "/32"
	}

	// find LinkSpeed from lookup
	throughput := f.linkSpeed()
	if cfg.NetworkSpeed != 0 {
		throughput = cfg.NetworkSpeed
	} else if throughput == 0 {
		// Failed to determine speed. Check if the network fingerprint got it
		found := false
		if node.Resources != nil && len(node.Resources.Networks) > 0 {
			for _, n := range node.Resources.Networks {
				if n.IP == newNetwork.IP {
					throughput = n.MBits
					found = true
					break
				}
			}
		}

		// Nothing detected so default
		if !found {
			throughput = defaultNetworkSpeed
		}
	}

	// populate Node Network Resources
	if node.Resources == nil {
		node.Resources = &structs.Resources{}
	}
	newNetwork.MBits = throughput
	node.Resources.Networks = []*structs.NetworkResource{newNetwork}

	// populate Links
	node.Links["aws.ec2"] = fmt.Sprintf("%s.%s",
		node.Attributes["platform.aws.placement.availability-zone"],
		node.Attributes["unique.platform.aws.instance-id"])

	return true, nil
}