mirror of
https://github.com/kemko/nomad.git
synced 2026-01-06 02:15:43 +03:00
Merge pull request #4978 from hashicorp/f-device-tweaks
Display device attributes in `nomad node status -verbose`
This commit is contained in:
@@ -7,6 +7,7 @@ import (
|
||||
"strconv"
|
||||
"time"
|
||||
|
||||
"github.com/hashicorp/nomad/helper"
|
||||
"github.com/hashicorp/nomad/nomad/structs"
|
||||
)
|
||||
|
||||
@@ -673,9 +674,9 @@ func (v *StatValue) String() string {
|
||||
case v.StringVal != nil:
|
||||
return *v.StringVal
|
||||
case v.FloatNumeratorVal != nil:
|
||||
str := strconv.FormatFloat(*v.FloatNumeratorVal, 'f', -1, 64)
|
||||
str := helper.FormatFloat(*v.FloatNumeratorVal, 3)
|
||||
if v.FloatDenominatorVal != nil {
|
||||
str += " / " + strconv.FormatFloat(*v.FloatDenominatorVal, 'f', -1, 64)
|
||||
str += " / " + helper.FormatFloat(*v.FloatDenominatorVal, 3)
|
||||
}
|
||||
|
||||
if v.Unit != "" {
|
||||
@@ -683,7 +684,6 @@ func (v *StatValue) String() string {
|
||||
}
|
||||
return str
|
||||
case v.IntNumeratorVal != nil:
|
||||
|
||||
str := strconv.FormatInt(*v.IntNumeratorVal, 10)
|
||||
if v.IntDenominatorVal != nil {
|
||||
str += " / " + strconv.FormatInt(*v.IntDenominatorVal, 10)
|
||||
|
||||
@@ -1,6 +1,10 @@
|
||||
package api
|
||||
|
||||
import "github.com/hashicorp/nomad/helper"
|
||||
import (
|
||||
"strconv"
|
||||
|
||||
"github.com/hashicorp/nomad/helper"
|
||||
)
|
||||
|
||||
// Resources encapsulates the required resources of
|
||||
// a given task or task group.
|
||||
@@ -122,6 +126,10 @@ type NodeDeviceResource struct {
|
||||
Attributes map[string]*Attribute
|
||||
}
|
||||
|
||||
func (r NodeDeviceResource) ID() string {
|
||||
return r.Vendor + "/" + r.Type + "/" + r.Name
|
||||
}
|
||||
|
||||
// NodeDevice is an instance of a particular device.
|
||||
type NodeDevice struct {
|
||||
// ID is the ID of the device.
|
||||
@@ -143,21 +151,44 @@ type NodeDevice struct {
|
||||
// specifying units
|
||||
type Attribute struct {
|
||||
// Float is the float value for the attribute
|
||||
Float *float64
|
||||
FloatVal *float64 `json:"Float,omitempty"`
|
||||
|
||||
// Int is the int value for the attribute
|
||||
Int *int64
|
||||
IntVal *int64 `json:"Int,omitempty"`
|
||||
|
||||
// String is the string value for the attribute
|
||||
String *string
|
||||
StringVal *string `json:"String,omitempty"`
|
||||
|
||||
// Bool is the bool value for the attribute
|
||||
Bool *bool
|
||||
BoolVal *bool `json:"Bool,omitempty"`
|
||||
|
||||
// Unit is the optional unit for the set int or float value
|
||||
Unit string
|
||||
}
|
||||
|
||||
func (a Attribute) String() string {
|
||||
switch {
|
||||
case a.FloatVal != nil:
|
||||
str := helper.FormatFloat(*a.FloatVal, 3)
|
||||
if a.Unit != "" {
|
||||
str += " " + a.Unit
|
||||
}
|
||||
return str
|
||||
case a.IntVal != nil:
|
||||
str := strconv.FormatInt(*a.IntVal, 10)
|
||||
if a.Unit != "" {
|
||||
str += " " + a.Unit
|
||||
}
|
||||
return str
|
||||
case a.StringVal != nil:
|
||||
return *a.StringVal
|
||||
case a.BoolVal != nil:
|
||||
return strconv.FormatBool(*a.BoolVal)
|
||||
default:
|
||||
return "<unknown>"
|
||||
}
|
||||
}
|
||||
|
||||
// NodeDeviceLocality stores information about the devices hardware locality on
|
||||
// the node.
|
||||
type NodeDeviceLocality struct {
|
||||
|
||||
@@ -109,3 +109,15 @@ func printDeviceStats(ui cli.Ui, deviceGroupStats []*api.DeviceGroupStats) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func getDeviceAttributes(d *api.NodeDeviceResource) []string {
|
||||
attrs := []string{fmt.Sprintf("Device Group|%s", d.ID())}
|
||||
|
||||
for k, v := range d.Attributes {
|
||||
attrs = append(attrs, k+"|"+v.String())
|
||||
}
|
||||
|
||||
sort.Strings(attrs[1:])
|
||||
|
||||
return attrs
|
||||
}
|
||||
@@ -247,3 +247,29 @@ func TestNodeStatusCommand_GetDeviceResources(t *testing.T) {
|
||||
|
||||
assert.Equal(t, expected, formattedDevices)
|
||||
}
|
||||
func TestGetDeviceAttributes(t *testing.T) {
|
||||
d := &api.NodeDeviceResource{
|
||||
Vendor: "Vendor",
|
||||
Type: "Type",
|
||||
Name: "Name",
|
||||
|
||||
Attributes: map[string]*api.Attribute{
|
||||
"utilization": {
|
||||
FloatVal: helper.Float64ToPtr(0.78),
|
||||
Unit: "%",
|
||||
},
|
||||
"filesystem": {
|
||||
StringVal: helper.StringToPtr("ext4"),
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
formattedDevices := getDeviceAttributes(d)
|
||||
expected := []string{
|
||||
"Device Group|Vendor/Type/Name",
|
||||
"filesystem|ext4",
|
||||
"utilization|0.78 %",
|
||||
}
|
||||
|
||||
assert.Equal(t, expected, formattedDevices)
|
||||
}
|
||||
@@ -418,6 +418,7 @@ func (c *NodeStatusCommand) formatNode(client *api.Client, node *api.Node) int {
|
||||
|
||||
if c.verbose {
|
||||
c.formatAttributes(node)
|
||||
c.formatDeviceAttributes(node)
|
||||
c.formatMeta(node)
|
||||
}
|
||||
return 0
|
||||
@@ -528,6 +529,32 @@ func (c *NodeStatusCommand) formatAttributes(node *api.Node) {
|
||||
c.Ui.Output(formatKV(attributes))
|
||||
}
|
||||
|
||||
func (c *NodeStatusCommand) formatDeviceAttributes(node *api.Node) {
|
||||
devices := node.NodeResources.Devices
|
||||
if len(devices) == 0 {
|
||||
return
|
||||
}
|
||||
|
||||
sort.Slice(devices, func(i, j int) bool {
|
||||
return devices[i].ID() < devices[j].ID()
|
||||
})
|
||||
|
||||
first := true
|
||||
for _, d := range devices {
|
||||
if len(d.Attributes) == 0 {
|
||||
continue
|
||||
}
|
||||
|
||||
if first {
|
||||
c.Ui.Output("\nDevice Group Attributes")
|
||||
first = false
|
||||
} else {
|
||||
c.Ui.Output("")
|
||||
}
|
||||
c.Ui.Output(formatKV(getDeviceAttributes(d)))
|
||||
}
|
||||
}
|
||||
|
||||
func (c *NodeStatusCommand) formatMeta(node *api.Node) {
|
||||
// Print the meta
|
||||
keys := make([]string, 0, len(node.Meta))
|
||||
|
||||
@@ -286,7 +286,7 @@ func statsForItem(statsItem *nvml.StatsData, timestamp time.Time) *device.Device
|
||||
}
|
||||
}
|
||||
return &device.DeviceStats{
|
||||
Summary: temperatureStat,
|
||||
Summary: memoryStateStat,
|
||||
Stats: &structs.StatObject{
|
||||
Attributes: map[string]*structs.StatValue{
|
||||
PowerUsageAttr: powerUsageStat,
|
||||
|
||||
@@ -447,9 +447,10 @@ func TestStatsForItem(t *testing.T) {
|
||||
},
|
||||
ExpectedResult: &device.DeviceStats{
|
||||
Summary: &structs.StatValue{
|
||||
Unit: TemperatureUnit,
|
||||
Desc: TemperatureDesc,
|
||||
IntNumeratorVal: helper.Int64ToPtr(1),
|
||||
Unit: MemoryStateUnit,
|
||||
Desc: MemoryStateDesc,
|
||||
IntNumeratorVal: helper.Int64ToPtr(1),
|
||||
IntDenominatorVal: helper.Int64ToPtr(1),
|
||||
},
|
||||
Stats: &structs.StatObject{
|
||||
Attributes: map[string]*structs.StatValue{
|
||||
@@ -541,9 +542,10 @@ func TestStatsForItem(t *testing.T) {
|
||||
},
|
||||
ExpectedResult: &device.DeviceStats{
|
||||
Summary: &structs.StatValue{
|
||||
Unit: TemperatureUnit,
|
||||
Desc: TemperatureDesc,
|
||||
IntNumeratorVal: helper.Int64ToPtr(1),
|
||||
Unit: MemoryStateUnit,
|
||||
Desc: MemoryStateDesc,
|
||||
IntNumeratorVal: helper.Int64ToPtr(1),
|
||||
IntDenominatorVal: helper.Int64ToPtr(1),
|
||||
},
|
||||
Stats: &structs.StatObject{
|
||||
Attributes: map[string]*structs.StatValue{
|
||||
@@ -634,9 +636,10 @@ func TestStatsForItem(t *testing.T) {
|
||||
},
|
||||
ExpectedResult: &device.DeviceStats{
|
||||
Summary: &structs.StatValue{
|
||||
Unit: TemperatureUnit,
|
||||
Desc: TemperatureDesc,
|
||||
IntNumeratorVal: helper.Int64ToPtr(1),
|
||||
Unit: MemoryStateUnit,
|
||||
Desc: MemoryStateDesc,
|
||||
IntNumeratorVal: helper.Int64ToPtr(1),
|
||||
IntDenominatorVal: helper.Int64ToPtr(1),
|
||||
},
|
||||
Stats: &structs.StatObject{
|
||||
Attributes: map[string]*structs.StatValue{
|
||||
@@ -727,9 +730,10 @@ func TestStatsForItem(t *testing.T) {
|
||||
},
|
||||
ExpectedResult: &device.DeviceStats{
|
||||
Summary: &structs.StatValue{
|
||||
Unit: TemperatureUnit,
|
||||
Desc: TemperatureDesc,
|
||||
IntNumeratorVal: helper.Int64ToPtr(1),
|
||||
Unit: MemoryStateUnit,
|
||||
Desc: MemoryStateDesc,
|
||||
IntNumeratorVal: helper.Int64ToPtr(1),
|
||||
IntDenominatorVal: helper.Int64ToPtr(1),
|
||||
},
|
||||
Stats: &structs.StatObject{
|
||||
Attributes: map[string]*structs.StatValue{
|
||||
@@ -821,9 +825,10 @@ func TestStatsForItem(t *testing.T) {
|
||||
},
|
||||
ExpectedResult: &device.DeviceStats{
|
||||
Summary: &structs.StatValue{
|
||||
Unit: TemperatureUnit,
|
||||
Desc: TemperatureDesc,
|
||||
IntNumeratorVal: helper.Int64ToPtr(1),
|
||||
Unit: MemoryStateUnit,
|
||||
Desc: MemoryStateDesc,
|
||||
IntNumeratorVal: helper.Int64ToPtr(1),
|
||||
IntDenominatorVal: helper.Int64ToPtr(1),
|
||||
},
|
||||
Stats: &structs.StatObject{
|
||||
Attributes: map[string]*structs.StatValue{
|
||||
@@ -915,9 +920,10 @@ func TestStatsForItem(t *testing.T) {
|
||||
},
|
||||
ExpectedResult: &device.DeviceStats{
|
||||
Summary: &structs.StatValue{
|
||||
Unit: TemperatureUnit,
|
||||
Desc: TemperatureDesc,
|
||||
IntNumeratorVal: helper.Int64ToPtr(1),
|
||||
Unit: MemoryStateUnit,
|
||||
Desc: MemoryStateDesc,
|
||||
IntNumeratorVal: helper.Int64ToPtr(1),
|
||||
IntDenominatorVal: helper.Int64ToPtr(1),
|
||||
},
|
||||
Stats: &structs.StatObject{
|
||||
Attributes: map[string]*structs.StatValue{
|
||||
@@ -1009,9 +1015,10 @@ func TestStatsForItem(t *testing.T) {
|
||||
},
|
||||
ExpectedResult: &device.DeviceStats{
|
||||
Summary: &structs.StatValue{
|
||||
Unit: TemperatureUnit,
|
||||
Desc: TemperatureDesc,
|
||||
IntNumeratorVal: helper.Int64ToPtr(1),
|
||||
Unit: MemoryStateUnit,
|
||||
Desc: MemoryStateDesc,
|
||||
IntNumeratorVal: helper.Int64ToPtr(1),
|
||||
IntDenominatorVal: helper.Int64ToPtr(1),
|
||||
},
|
||||
Stats: &structs.StatObject{
|
||||
Attributes: map[string]*structs.StatValue{
|
||||
@@ -1103,9 +1110,10 @@ func TestStatsForItem(t *testing.T) {
|
||||
},
|
||||
ExpectedResult: &device.DeviceStats{
|
||||
Summary: &structs.StatValue{
|
||||
Unit: TemperatureUnit,
|
||||
Desc: TemperatureDesc,
|
||||
StringVal: helper.StringToPtr(notAvailable),
|
||||
Unit: MemoryStateUnit,
|
||||
Desc: MemoryStateDesc,
|
||||
IntNumeratorVal: helper.Int64ToPtr(1),
|
||||
IntDenominatorVal: helper.Int64ToPtr(1),
|
||||
},
|
||||
Stats: &structs.StatObject{
|
||||
Attributes: map[string]*structs.StatValue{
|
||||
@@ -1197,9 +1205,9 @@ func TestStatsForItem(t *testing.T) {
|
||||
},
|
||||
ExpectedResult: &device.DeviceStats{
|
||||
Summary: &structs.StatValue{
|
||||
Unit: TemperatureUnit,
|
||||
Desc: TemperatureDesc,
|
||||
IntNumeratorVal: helper.Int64ToPtr(1),
|
||||
Unit: MemoryStateUnit,
|
||||
Desc: MemoryStateDesc,
|
||||
StringVal: helper.StringToPtr(notAvailable),
|
||||
},
|
||||
Stats: &structs.StatObject{
|
||||
Attributes: map[string]*structs.StatValue{
|
||||
@@ -1290,9 +1298,9 @@ func TestStatsForItem(t *testing.T) {
|
||||
},
|
||||
ExpectedResult: &device.DeviceStats{
|
||||
Summary: &structs.StatValue{
|
||||
Unit: TemperatureUnit,
|
||||
Desc: TemperatureDesc,
|
||||
IntNumeratorVal: helper.Int64ToPtr(1),
|
||||
Unit: MemoryStateUnit,
|
||||
Desc: MemoryStateDesc,
|
||||
StringVal: helper.StringToPtr(notAvailable),
|
||||
},
|
||||
Stats: &structs.StatObject{
|
||||
Attributes: map[string]*structs.StatValue{
|
||||
@@ -1383,9 +1391,10 @@ func TestStatsForItem(t *testing.T) {
|
||||
},
|
||||
ExpectedResult: &device.DeviceStats{
|
||||
Summary: &structs.StatValue{
|
||||
Unit: TemperatureUnit,
|
||||
Desc: TemperatureDesc,
|
||||
IntNumeratorVal: helper.Int64ToPtr(1),
|
||||
Unit: MemoryStateUnit,
|
||||
Desc: MemoryStateDesc,
|
||||
IntNumeratorVal: helper.Int64ToPtr(1),
|
||||
IntDenominatorVal: helper.Int64ToPtr(1),
|
||||
},
|
||||
Stats: &structs.StatObject{
|
||||
Attributes: map[string]*structs.StatValue{
|
||||
@@ -1476,9 +1485,10 @@ func TestStatsForItem(t *testing.T) {
|
||||
},
|
||||
ExpectedResult: &device.DeviceStats{
|
||||
Summary: &structs.StatValue{
|
||||
Unit: TemperatureUnit,
|
||||
Desc: TemperatureDesc,
|
||||
IntNumeratorVal: helper.Int64ToPtr(1),
|
||||
Unit: MemoryStateUnit,
|
||||
Desc: MemoryStateDesc,
|
||||
IntNumeratorVal: helper.Int64ToPtr(1),
|
||||
IntDenominatorVal: helper.Int64ToPtr(1),
|
||||
},
|
||||
Stats: &structs.StatObject{
|
||||
Attributes: map[string]*structs.StatValue{
|
||||
@@ -1569,9 +1579,10 @@ func TestStatsForItem(t *testing.T) {
|
||||
},
|
||||
ExpectedResult: &device.DeviceStats{
|
||||
Summary: &structs.StatValue{
|
||||
Unit: TemperatureUnit,
|
||||
Desc: TemperatureDesc,
|
||||
IntNumeratorVal: helper.Int64ToPtr(1),
|
||||
Unit: MemoryStateUnit,
|
||||
Desc: MemoryStateDesc,
|
||||
IntNumeratorVal: helper.Int64ToPtr(1),
|
||||
IntDenominatorVal: helper.Int64ToPtr(1),
|
||||
},
|
||||
Stats: &structs.StatObject{
|
||||
Attributes: map[string]*structs.StatValue{
|
||||
@@ -1663,9 +1674,10 @@ func TestStatsForItem(t *testing.T) {
|
||||
},
|
||||
ExpectedResult: &device.DeviceStats{
|
||||
Summary: &structs.StatValue{
|
||||
Unit: TemperatureUnit,
|
||||
Desc: TemperatureDesc,
|
||||
IntNumeratorVal: helper.Int64ToPtr(1),
|
||||
Unit: MemoryStateUnit,
|
||||
Desc: MemoryStateDesc,
|
||||
IntNumeratorVal: helper.Int64ToPtr(1),
|
||||
IntDenominatorVal: helper.Int64ToPtr(1),
|
||||
},
|
||||
Stats: &structs.StatObject{
|
||||
Attributes: map[string]*structs.StatValue{
|
||||
@@ -1757,9 +1769,10 @@ func TestStatsForItem(t *testing.T) {
|
||||
},
|
||||
ExpectedResult: &device.DeviceStats{
|
||||
Summary: &structs.StatValue{
|
||||
Unit: TemperatureUnit,
|
||||
Desc: TemperatureDesc,
|
||||
IntNumeratorVal: helper.Int64ToPtr(1),
|
||||
Unit: MemoryStateUnit,
|
||||
Desc: MemoryStateDesc,
|
||||
IntNumeratorVal: helper.Int64ToPtr(1),
|
||||
IntDenominatorVal: helper.Int64ToPtr(1),
|
||||
},
|
||||
Stats: &structs.StatObject{
|
||||
Attributes: map[string]*structs.StatValue{
|
||||
@@ -1913,9 +1926,10 @@ func TestStatsForGroup(t *testing.T) {
|
||||
InstanceStats: map[string]*device.DeviceStats{
|
||||
"UUID1": {
|
||||
Summary: &structs.StatValue{
|
||||
Unit: TemperatureUnit,
|
||||
Desc: TemperatureDesc,
|
||||
IntNumeratorVal: helper.Int64ToPtr(1),
|
||||
Unit: MemoryStateUnit,
|
||||
Desc: MemoryStateDesc,
|
||||
IntNumeratorVal: helper.Int64ToPtr(1),
|
||||
IntDenominatorVal: helper.Int64ToPtr(1),
|
||||
},
|
||||
Stats: &structs.StatObject{
|
||||
Attributes: map[string]*structs.StatValue{
|
||||
@@ -1983,9 +1997,10 @@ func TestStatsForGroup(t *testing.T) {
|
||||
},
|
||||
"UUID2": {
|
||||
Summary: &structs.StatValue{
|
||||
Unit: TemperatureUnit,
|
||||
Desc: TemperatureDesc,
|
||||
IntNumeratorVal: helper.Int64ToPtr(2),
|
||||
Unit: MemoryStateUnit,
|
||||
Desc: MemoryStateDesc,
|
||||
IntNumeratorVal: helper.Int64ToPtr(2),
|
||||
IntDenominatorVal: helper.Int64ToPtr(2),
|
||||
},
|
||||
Stats: &structs.StatObject{
|
||||
Attributes: map[string]*structs.StatValue{
|
||||
@@ -2053,9 +2068,10 @@ func TestStatsForGroup(t *testing.T) {
|
||||
},
|
||||
"UUID3": {
|
||||
Summary: &structs.StatValue{
|
||||
Unit: TemperatureUnit,
|
||||
Desc: TemperatureDesc,
|
||||
IntNumeratorVal: helper.Int64ToPtr(3),
|
||||
Unit: MemoryStateUnit,
|
||||
Desc: MemoryStateDesc,
|
||||
IntNumeratorVal: helper.Int64ToPtr(3),
|
||||
IntDenominatorVal: helper.Int64ToPtr(3),
|
||||
},
|
||||
Stats: &structs.StatObject{
|
||||
Attributes: map[string]*structs.StatValue{
|
||||
@@ -2234,9 +2250,10 @@ func TestWriteStatsToChannel(t *testing.T) {
|
||||
InstanceStats: map[string]*device.DeviceStats{
|
||||
"UUID1": {
|
||||
Summary: &structs.StatValue{
|
||||
Unit: TemperatureUnit,
|
||||
Desc: TemperatureDesc,
|
||||
IntNumeratorVal: helper.Int64ToPtr(1),
|
||||
Unit: MemoryStateUnit,
|
||||
Desc: MemoryStateDesc,
|
||||
IntNumeratorVal: helper.Int64ToPtr(1),
|
||||
IntDenominatorVal: helper.Int64ToPtr(1),
|
||||
},
|
||||
Stats: &structs.StatObject{
|
||||
Attributes: map[string]*structs.StatValue{
|
||||
@@ -2311,9 +2328,10 @@ func TestWriteStatsToChannel(t *testing.T) {
|
||||
InstanceStats: map[string]*device.DeviceStats{
|
||||
"UUID2": {
|
||||
Summary: &structs.StatValue{
|
||||
Unit: TemperatureUnit,
|
||||
Desc: TemperatureDesc,
|
||||
IntNumeratorVal: helper.Int64ToPtr(2),
|
||||
Unit: MemoryStateUnit,
|
||||
Desc: MemoryStateDesc,
|
||||
IntNumeratorVal: helper.Int64ToPtr(2),
|
||||
IntDenominatorVal: helper.Int64ToPtr(2),
|
||||
},
|
||||
Stats: &structs.StatObject{
|
||||
Attributes: map[string]*structs.StatValue{
|
||||
@@ -2388,9 +2406,10 @@ func TestWriteStatsToChannel(t *testing.T) {
|
||||
InstanceStats: map[string]*device.DeviceStats{
|
||||
"UUID3": {
|
||||
Summary: &structs.StatValue{
|
||||
Unit: TemperatureUnit,
|
||||
Desc: TemperatureDesc,
|
||||
IntNumeratorVal: helper.Int64ToPtr(3),
|
||||
Unit: MemoryStateUnit,
|
||||
Desc: MemoryStateDesc,
|
||||
IntNumeratorVal: helper.Int64ToPtr(3),
|
||||
IntDenominatorVal: helper.Int64ToPtr(3),
|
||||
},
|
||||
Stats: &structs.StatObject{
|
||||
Attributes: map[string]*structs.StatValue{
|
||||
@@ -2545,9 +2564,10 @@ func TestWriteStatsToChannel(t *testing.T) {
|
||||
InstanceStats: map[string]*device.DeviceStats{
|
||||
"UUID1": {
|
||||
Summary: &structs.StatValue{
|
||||
Unit: TemperatureUnit,
|
||||
Desc: TemperatureDesc,
|
||||
IntNumeratorVal: helper.Int64ToPtr(1),
|
||||
Unit: MemoryStateUnit,
|
||||
Desc: MemoryStateDesc,
|
||||
IntNumeratorVal: helper.Int64ToPtr(1),
|
||||
IntDenominatorVal: helper.Int64ToPtr(1),
|
||||
},
|
||||
Stats: &structs.StatObject{
|
||||
Attributes: map[string]*structs.StatValue{
|
||||
@@ -2622,9 +2642,10 @@ func TestWriteStatsToChannel(t *testing.T) {
|
||||
InstanceStats: map[string]*device.DeviceStats{
|
||||
"UUID3": {
|
||||
Summary: &structs.StatValue{
|
||||
Unit: TemperatureUnit,
|
||||
Desc: TemperatureDesc,
|
||||
IntNumeratorVal: helper.Int64ToPtr(3),
|
||||
Unit: MemoryStateUnit,
|
||||
Desc: MemoryStateDesc,
|
||||
IntNumeratorVal: helper.Int64ToPtr(3),
|
||||
IntDenominatorVal: helper.Int64ToPtr(3),
|
||||
},
|
||||
Stats: &structs.StatObject{
|
||||
Attributes: map[string]*structs.StatValue{
|
||||
@@ -2692,9 +2713,10 @@ func TestWriteStatsToChannel(t *testing.T) {
|
||||
},
|
||||
"UUID2": {
|
||||
Summary: &structs.StatValue{
|
||||
Unit: TemperatureUnit,
|
||||
Desc: TemperatureDesc,
|
||||
IntNumeratorVal: helper.Int64ToPtr(2),
|
||||
Unit: MemoryStateUnit,
|
||||
Desc: MemoryStateDesc,
|
||||
IntNumeratorVal: helper.Int64ToPtr(2),
|
||||
IntDenominatorVal: helper.Int64ToPtr(2),
|
||||
},
|
||||
Stats: &structs.StatObject{
|
||||
Attributes: map[string]*structs.StatValue{
|
||||
@@ -2848,9 +2870,10 @@ func TestWriteStatsToChannel(t *testing.T) {
|
||||
InstanceStats: map[string]*device.DeviceStats{
|
||||
"UUID1": {
|
||||
Summary: &structs.StatValue{
|
||||
Unit: TemperatureUnit,
|
||||
Desc: TemperatureDesc,
|
||||
IntNumeratorVal: helper.Int64ToPtr(1),
|
||||
Unit: MemoryStateUnit,
|
||||
Desc: MemoryStateDesc,
|
||||
IntNumeratorVal: helper.Int64ToPtr(1),
|
||||
IntDenominatorVal: helper.Int64ToPtr(1),
|
||||
},
|
||||
Stats: &structs.StatObject{
|
||||
Attributes: map[string]*structs.StatValue{
|
||||
@@ -2925,9 +2948,10 @@ func TestWriteStatsToChannel(t *testing.T) {
|
||||
InstanceStats: map[string]*device.DeviceStats{
|
||||
"UUID2": {
|
||||
Summary: &structs.StatValue{
|
||||
Unit: TemperatureUnit,
|
||||
Desc: TemperatureDesc,
|
||||
IntNumeratorVal: helper.Int64ToPtr(2),
|
||||
Unit: MemoryStateUnit,
|
||||
Desc: MemoryStateDesc,
|
||||
IntNumeratorVal: helper.Int64ToPtr(2),
|
||||
IntDenominatorVal: helper.Int64ToPtr(2),
|
||||
},
|
||||
Stats: &structs.StatObject{
|
||||
Attributes: map[string]*structs.StatValue{
|
||||
|
||||
@@ -4,6 +4,8 @@ import (
|
||||
"crypto/sha512"
|
||||
"fmt"
|
||||
"regexp"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
multierror "github.com/hashicorp/go-multierror"
|
||||
@@ -344,3 +346,26 @@ func CheckHCLKeys(node ast.Node, valid []string) error {
|
||||
|
||||
return result
|
||||
}
|
||||
|
||||
// FormatFloat converts the floating-point number f to a string,
|
||||
// after rounding it to the passed unit.
|
||||
//
|
||||
// Uses 'f' format (-ddd.dddddd, no exponent), and uses at most
|
||||
// maxPrec digits after the decimal point.
|
||||
func FormatFloat(f float64, maxPrec int) string {
|
||||
v := strconv.FormatFloat(f, 'f', -1, 64)
|
||||
|
||||
idx := strings.LastIndex(v, ".")
|
||||
if idx == -1 {
|
||||
return v
|
||||
}
|
||||
|
||||
sublen := idx + maxPrec + 1
|
||||
if sublen > len(v) {
|
||||
sublen = len(v)
|
||||
}
|
||||
|
||||
return v[:sublen]
|
||||
|
||||
return v
|
||||
}
|
||||
|
||||
@@ -4,6 +4,8 @@ import (
|
||||
"reflect"
|
||||
"sort"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
func TestSliceStringIsSubset(t *testing.T) {
|
||||
@@ -87,3 +89,35 @@ func BenchmarkCleanEnvVar(b *testing.B) {
|
||||
CleanEnvVar(in, replacement)
|
||||
}
|
||||
}
|
||||
|
||||
func TestFormatRoundedFloat(t *testing.T) {
|
||||
cases := []struct {
|
||||
input float64
|
||||
expected string
|
||||
}{
|
||||
{
|
||||
1323,
|
||||
"1323",
|
||||
},
|
||||
{
|
||||
10.321,
|
||||
"10.321",
|
||||
},
|
||||
{
|
||||
100000.31324324,
|
||||
"100000.313",
|
||||
},
|
||||
{
|
||||
100000.3,
|
||||
"100000.3",
|
||||
},
|
||||
{
|
||||
0.7654321,
|
||||
"0.765",
|
||||
},
|
||||
}
|
||||
|
||||
for _, c := range cases {
|
||||
require.Equal(t, c.expected, FormatFloat(c.input, 3))
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user