Node resources on client

This commit is contained in:
Alex Dadgar
2018-09-29 17:23:41 -07:00
parent 95d9286ad1
commit b310a54aa6
11 changed files with 245 additions and 23 deletions

View File

@@ -446,6 +446,7 @@ type Node struct {
Attributes map[string]string
Resources *Resources
Reserved *Resources
NodeResources *NodeResources
Links map[string]string
Meta map[string]string
NodeClass string
@@ -461,6 +462,25 @@ type Node struct {
ModifyIndex uint64
}
type NodeResources struct {
Cpu NodeCpuResources
Memory NodeMemoryResources
Disk NodeDiskResources
Networks []*NetworkResource
}
type NodeCpuResources struct {
TotalShares uint64
}
type NodeMemoryResources struct {
MemoryMB uint64
}
type NodeDiskResources struct {
DiskMB uint64
}
// DrainStrategy describes a Node's drain behavior.
type DrainStrategy struct {
// DrainSpec is the user declared drain specification

View File

@@ -938,6 +938,9 @@ func (c *Client) setupNode() error {
if node.Meta == nil {
node.Meta = make(map[string]string)
}
if node.NodeResources == nil {
node.NodeResources = &structs.NodeResources{}
}
if node.Resources == nil {
node.Resources = &structs.Resources{}
}
@@ -1042,11 +1045,17 @@ func (c *Client) updateNodeFromFingerprint(response *cstructs.FingerprintRespons
}
}
// COMPAT(0.10): Remove in 0.10
if response.Resources != nil && !resourcesAreEqual(c.config.Node.Resources, response.Resources) {
nodeHasChanged = true
c.config.Node.Resources.Merge(response.Resources)
}
if response.NodeResources != nil && !c.config.Node.NodeResources.Equals(response.NodeResources) {
nodeHasChanged = true
c.config.Node.NodeResources.Merge(response.NodeResources)
}
if nodeHasChanged {
c.updateNodeLocked()
}

View File

@@ -24,9 +24,16 @@ func NewCPUFingerprint(logger *log.Logger) Fingerprint {
func (f *CPUFingerprint) Fingerprint(req *cstructs.FingerprintRequest, resp *cstructs.FingerprintResponse) error {
cfg := req.Config
setResourcesCPU := func(totalCompute int) {
// COMPAT(0.10): Remove in 0.10
resp.Resources = &structs.Resources{
CPU: totalCompute,
}
resp.NodeResources = &structs.NodeResources{
Cpu: structs.NodeCpuResources{
TotalShares: uint64(totalCompute),
},
}
}
if err := stats.Init(); err != nil {

View File

@@ -45,9 +45,14 @@ func TestCPUFingerprint(t *testing.T) {
t.Fatalf("Missing CPU Total Compute")
}
// COMPAT(0.10): Remove in 0.10
if response.Resources == nil || response.Resources.CPU == 0 {
t.Fatalf("Expected to find CPU Resources")
}
if response.NodeResources == nil || response.NodeResources.Cpu.TotalShares == 0 {
t.Fatalf("Expected to find CPU Resources")
}
}
// TestCPUFingerprint_OverrideCompute asserts that setting cpu_total_compute in
@@ -91,8 +96,12 @@ func TestCPUFingerprint_OverrideCompute(t *testing.T) {
t.Fatalf("err: %v", err)
}
// COMPAT(0.10): Remove in 0.10
if response.Resources.CPU != cfg.CpuCompute {
t.Fatalf("expected override cpu of %d but found %d", cfg.CpuCompute, response.Resources.CPU)
}
if response.NodeResources.Cpu.TotalShares != uint64(cfg.CpuCompute) {
t.Fatalf("expected override cpu of %d but found %d", cfg.CpuCompute, response.NodeResources.Cpu.TotalShares)
}
}
}

View File

@@ -43,9 +43,17 @@ func (f *MemoryFingerprint) Fingerprint(req *cstructs.FingerprintRequest, resp *
if totalMemory > 0 {
resp.AddAttribute("memory.totalbytes", fmt.Sprintf("%d", totalMemory))
// COMPAT(0.10): Remove in 0.10
resp.Resources = &structs.Resources{
MemoryMB: totalMemory / bytesInMB,
}
resp.NodeResources = &structs.NodeResources{
Memory: structs.NodeMemoryResources{
MemoryMB: uint64(totalMemory / bytesInMB),
},
}
}
return nil

View File

@@ -29,9 +29,15 @@ func TestMemoryFingerprint(t *testing.T) {
if response.Resources == nil {
t.Fatalf("response resources should not be nil")
}
// COMPAT(0.10): Remove in 0.10
if response.Resources.MemoryMB == 0 {
t.Fatalf("Expected node.Resources.MemoryMB to be non-zero")
}
if response.NodeResources.Memory.MemoryMB == 0 {
t.Fatalf("Expected node.Resources.MemoryMB to be non-zero")
}
}
func TestMemoryFingerprint_Override(t *testing.T) {
@@ -52,4 +58,5 @@ func TestMemoryFingerprint_Override(t *testing.T) {
require := require.New(t)
require.NotNil(response.Resources)
require.Equal(response.Resources.MemoryMB, memoryMB)
require.EqualValues(response.NodeResources.Memory.MemoryMB, memoryMB)
}

View File

@@ -95,9 +95,15 @@ func (f *NetworkFingerprint) Fingerprint(req *cstructs.FingerprintRequest, resp
return err
}
// COMPAT(0.10): Remove in 0.10
resp.Resources = &structs.Resources{
Networks: nwResources,
}
resp.NodeResources = &structs.NodeResources{
Networks: nwResources,
}
for _, nwResource := range nwResources {
f.logger.Printf("[DEBUG] fingerprint.network: Detected interface %v with IP: %v", intf.Name, nwResource.IP)
}

View File

@@ -47,9 +47,15 @@ func (f *StorageFingerprint) Fingerprint(req *cstructs.FingerprintRequest, resp
resp.AddAttribute("unique.storage.bytesfree", strconv.FormatUint(free, 10))
// set the disk size for the response
// COMPAT(0.10): Remove in 0.10
resp.Resources = &structs.Resources{
DiskMB: int(free / bytesPerMegabyte),
}
resp.NodeResources = &structs.NodeResources{
Disk: structs.NodeDiskResources{
DiskMB: uint64(free / bytesPerMegabyte),
},
}
resp.Detected = true
return nil

View File

@@ -37,10 +37,15 @@ func TestStorageFingerprint(t *testing.T) {
t.Fatalf("unique.storage.bytesfree %d is larger than unique.storage.bytestotal %d", free, total)
}
// COMPAT(0.10): Remove in 0.10
if response.Resources == nil {
t.Fatalf("Node Resources was nil")
}
if response.Resources.DiskMB == 0 {
t.Errorf("Expected node.Resources.DiskMB to be non-zero")
}
if response.NodeResources == nil || response.NodeResources.Disk.DiskMB == 0 {
t.Errorf("Expected node.Resources.DiskMB to be non-zero")
}
}

View File

@@ -354,9 +354,10 @@ type FingerprintRequest struct {
// FingerprintResponse is the response which a fingerprinter annotates with the
// results of the fingerprint method
type FingerprintResponse struct {
Attributes map[string]string
Links map[string]string
Resources *structs.Resources
Attributes map[string]string
Links map[string]string
Resources *structs.Resources
NodeResources *structs.NodeResources
// Detected is a boolean indicating whether the fingerprinter detected
// if the resource was available

View File

@@ -1425,6 +1425,9 @@ type Node struct {
// "docker.runtime=1.8.3"
Attributes map[string]string
// NodeResources captures the available resources on the client.
NodeResources *NodeResources
// Resources is the available resources on the client.
// For example 'cpu=2' 'memory=2048'
Resources *Resources
@@ -1609,26 +1612,6 @@ type NodeListStub struct {
ModifyIndex uint64
}
// Networks defined for a task on the Resources struct.
type Networks []*NetworkResource
// Port assignment and IP for the given label or empty values.
func (ns Networks) Port(label string) (string, int) {
for _, n := range ns {
for _, p := range n.ReservedPorts {
if p.Label == label {
return n.IP, p.Value
}
}
for _, p := range n.DynamicPorts {
if p.Label == label {
return n.IP, p.Value
}
}
}
return "", 0
}
// Resources is used to define the resources available
// on a client
type Resources struct {
@@ -1927,6 +1910,167 @@ func (n *NetworkResource) PortLabels() map[string]int {
return labelValues
}
// Networks defined for a task on the Resources struct.
type Networks []*NetworkResource
// Port assignment and IP for the given label or empty values.
func (ns Networks) Port(label string) (string, int) {
for _, n := range ns {
for _, p := range n.ReservedPorts {
if p.Label == label {
return n.IP, p.Value
}
}
for _, p := range n.DynamicPorts {
if p.Label == label {
return n.IP, p.Value
}
}
}
return "", 0
}
type NodeResources struct {
Cpu NodeCpuResources
Memory NodeMemoryResources
Disk NodeDiskResources
Networks Networks
}
func (n *NodeResources) Merge(o *NodeResources) {
if o == nil {
return
}
n.Cpu.Merge(&o.Cpu)
n.Memory.Merge(&o.Memory)
n.Disk.Merge(&o.Disk)
if len(o.Networks) != 0 {
n.Networks = o.Networks
}
}
func (n *NodeResources) Equals(o *NodeResources) bool {
if o == nil && n == nil {
return true
} else if o == nil {
return false
} else if n == nil {
return false
}
if !n.Cpu.Equals(&o.Cpu) {
return false
}
if !n.Memory.Equals(&o.Memory) {
return false
}
if !n.Disk.Equals(&o.Disk) {
return false
}
if len(n.Networks) != len(o.Networks) {
return false
}
for i, n := range n.Networks {
if !n.Equals(o.Networks[i]) {
return false
}
}
return true
}
type NodeCpuResources struct {
TotalShares uint64
}
func (n *NodeCpuResources) Merge(o *NodeCpuResources) {
if o == nil {
return
}
if o.TotalShares != 0 {
n.TotalShares = o.TotalShares
}
}
func (n *NodeCpuResources) Equals(o *NodeCpuResources) bool {
if o == nil && n == nil {
return true
} else if o == nil {
return false
} else if n == nil {
return false
}
if n.TotalShares != o.TotalShares {
return false
}
return true
}
type NodeMemoryResources struct {
MemoryMB uint64
}
func (n *NodeMemoryResources) Merge(o *NodeMemoryResources) {
if o == nil {
return
}
if o.MemoryMB != 0 {
n.MemoryMB = o.MemoryMB
}
}
func (n *NodeMemoryResources) Equals(o *NodeMemoryResources) bool {
if o == nil && n == nil {
return true
} else if o == nil {
return false
} else if n == nil {
return false
}
if n.MemoryMB != o.MemoryMB {
return false
}
return true
}
type NodeDiskResources struct {
DiskMB uint64
}
func (n *NodeDiskResources) Merge(o *NodeDiskResources) {
if o == nil {
return
}
if o.DiskMB != 0 {
n.DiskMB = o.DiskMB
}
}
func (n *NodeDiskResources) Equals(o *NodeDiskResources) bool {
if o == nil && n == nil {
return true
} else if o == nil {
return false
} else if n == nil {
return false
}
if n.DiskMB != o.DiskMB {
return false
}
return true
}
const (
// JobTypeNomad is reserved for internal system tasks and is
// always handled by the CoreScheduler.