github.com/kardianos/nomad@v0.1.3-0.20151022182107-b13df73ee850/nomad/structs/funcs.go (about) 1 package structs 2 3 import ( 4 crand "crypto/rand" 5 "fmt" 6 "math" 7 ) 8 9 // RemoveAllocs is used to remove any allocs with the given IDs 10 // from the list of allocations 11 func RemoveAllocs(alloc []*Allocation, remove []*Allocation) []*Allocation { 12 // Convert remove into a set 13 removeSet := make(map[string]struct{}) 14 for _, remove := range remove { 15 removeSet[remove.ID] = struct{}{} 16 } 17 18 n := len(alloc) 19 for i := 0; i < n; i++ { 20 if _, ok := removeSet[alloc[i].ID]; ok { 21 alloc[i], alloc[n-1] = alloc[n-1], nil 22 i-- 23 n-- 24 } 25 } 26 27 alloc = alloc[:n] 28 return alloc 29 } 30 31 // FilterTerminalAllocs filters out all allocations in a terminal state 32 func FilterTerminalAllocs(allocs []*Allocation) []*Allocation { 33 n := len(allocs) 34 for i := 0; i < n; i++ { 35 if allocs[i].TerminalStatus() { 36 allocs[i], allocs[n-1] = allocs[n-1], nil 37 i-- 38 n-- 39 } 40 } 41 return allocs[:n] 42 } 43 44 // AllocsFit checks if a given set of allocations will fit on a node. 45 // The netIdx can optionally be provided if its already been computed. 46 // If the netIdx is provided, it is assumed that the client has already 47 // ensured there are no collisions. 48 func AllocsFit(node *Node, allocs []*Allocation, netIdx *NetworkIndex) (bool, string, *Resources, error) { 49 // Compute the utilization from zero 50 used := new(Resources) 51 52 // Add the reserved resources of the node 53 if node.Reserved != nil { 54 if err := used.Add(node.Reserved); err != nil { 55 return false, "", nil, err 56 } 57 } 58 59 // For each alloc, add the resources 60 for _, alloc := range allocs { 61 if err := used.Add(alloc.Resources); err != nil { 62 return false, "", nil, err 63 } 64 } 65 66 // Check that the node resources are a super set of those 67 // that are being allocated 68 if superset, dimension := node.Resources.Superset(used); !superset { 69 return false, dimension, used, nil 70 } 71 72 // Create the network index if missing 73 if netIdx == nil { 74 netIdx = NewNetworkIndex() 75 if netIdx.SetNode(node) || netIdx.AddAllocs(allocs) { 76 return false, "reserved port collision", used, nil 77 } 78 } 79 80 // Check if the network is overcommitted 81 if netIdx.Overcommitted() { 82 return false, "bandwidth exceeded", used, nil 83 } 84 85 // Allocations fit! 86 return true, "", used, nil 87 } 88 89 // ScoreFit is used to score the fit based on the Google work published here: 90 // http://www.columbia.edu/~cs2035/courses/ieor4405.S13/datacenter_scheduling.ppt 91 // This is equivalent to their BestFit v3 92 func ScoreFit(node *Node, util *Resources) float64 { 93 // Determine the node availability 94 nodeCpu := float64(node.Resources.CPU) 95 if node.Reserved != nil { 96 nodeCpu -= float64(node.Reserved.CPU) 97 } 98 nodeMem := float64(node.Resources.MemoryMB) 99 if node.Reserved != nil { 100 nodeMem -= float64(node.Reserved.MemoryMB) 101 } 102 103 // Compute the free percentage 104 freePctCpu := 1 - (float64(util.CPU) / nodeCpu) 105 freePctRam := 1 - (float64(util.MemoryMB) / nodeMem) 106 107 // Total will be "maximized" the smaller the value is. 108 // At 100% utilization, the total is 2, while at 0% util it is 20. 109 total := math.Pow(10, freePctCpu) + math.Pow(10, freePctRam) 110 111 // Invert so that the "maximized" total represents a high-value 112 // score. Because the floor is 20, we simply use that as an anchor. 113 // This means at a perfect fit, we return 18 as the score. 114 score := 20.0 - total 115 116 // Bound the score, just in case 117 // If the score is over 18, that means we've overfit the node. 118 if score > 18.0 { 119 score = 18.0 120 } else if score < 0 { 121 score = 0 122 } 123 return score 124 } 125 126 // GenerateUUID is used to generate a random UUID 127 func GenerateUUID() string { 128 buf := make([]byte, 16) 129 if _, err := crand.Read(buf); err != nil { 130 panic(fmt.Errorf("failed to read random bytes: %v", err)) 131 } 132 133 return fmt.Sprintf("%08x-%04x-%04x-%04x-%12x", 134 buf[0:4], 135 buf[4:6], 136 buf[6:8], 137 buf[8:10], 138 buf[10:16]) 139 }