1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
|
package main
import (
"fmt"
"math/rand"
"time"
"go.wit.com/lib/gui/shell"
"go.wit.com/log"
)
func (d *DropletT) Start() {
log.Info("a new virtual machine is running")
}
func (h *HyperT) RestartDaemon() {
url := "http://" + h.pb.Hostname + ":2520/kill"
s := shell.Wget(url)
log.Info("EVENT RestartDaemon", url, s)
h.lastpoll = time.Now()
h.killcount += 1
dur := time.Since(h.lastpoll) // Calculate the elapsed time
log.Info("KILLED DAEMON", h.pb.Hostname, shell.FormatDuration(dur), "curl", url)
me.killcount += 1
// mark the cluster as unstable so droplet starts can be throttled
me.unstable = time.Now()
}
var stableTimeout time.Duration = 43 * time.Second
// checks if the cluster is ready and stable
func clusterReady() (bool, string) {
last := time.Since(me.unstable)
if last > stableTimeout {
// the cluster has not been stable for 133 seconds
log.Warn("clusterReady() is stable for ", shell.FormatDuration(stableTimeout), " secs")
return true, fmt.Sprintln("clusterReady() is stable ", shell.FormatDuration(stableTimeout), " secs")
}
log.Warn("clusterReady() is unstable for", shell.FormatDuration(last))
return false, "clusterReady() is unstable for " + shell.FormatDuration(last)
}
func (d *DropletT) dropletReady() (bool, string) {
if d.CurrentState == "ON" {
return false, "EVENT start droplet is already ON"
}
if d.starts > 2 {
// reason := "EVENT start droplet has already been started " + d.starts + " times"
return false, fmt.Sprintln("EVENT start droplet has already been started ", d.starts, " times")
}
return true, ""
}
func (h *HyperT) Start(d *DropletT) (bool, string) {
ready, result := clusterReady()
if !ready {
return false, result
}
ready, result = d.dropletReady()
if !ready {
return false, result
}
url := "http://" + h.pb.Hostname + ":2520/start?start=" + d.pb.Hostname
s := shell.Wget(url)
result = "EVENT start droplet url: " + url + "\n"
result += "EVENT start droplet response: " + s.String()
// increment the counter for a start attempt working
d.starts += 1
// mark the cluster as unstable so droplet starts can be throttled
me.unstable = time.Now()
return true, result
}
func Start(name string) (bool, string) {
var result string
d := findDroplet(name)
if d == nil {
result += "can't start unknown droplet"
return false, result
}
if d.CurrentState == "ON" {
return false, "EVENT start droplet is already ON"
}
dur := time.Since(me.unstable) // how long has the cluster been stable?
result = fmt.Sprintln("should start droplet", name, "here. grid stable for:", shell.FormatDuration(dur))
if dur < 17*time.Second {
result += "grid is still too unstable"
return false, result
}
// make the list of hypervisors that are active and can start new droplets
var pool []*HyperT
for _, h := range me.hypers {
result += fmt.Sprintln("could start droplet on", name, "on", h.pb.Hostname, h.pb.Active)
if d.pb.PreferredHypervisor == h.pb.Hostname {
// the config file says this droplet should run on this hypervisor
a, b := h.Start(d)
return a, result + b
}
if h.pb.Active != true {
continue
}
pool = append(pool, h)
}
// left here as an example of how to actually do random numbers
// it's complete mathematical chaos. Randomness is simple when
// human interaction occurs -- which is exactly what happens most
// of the time. most random shit is bullshit. all you really need
// is exactly this to make sure the random functions work as they
// should. Probably, just use this everywhere in all cases. --jcarr
rand.Seed(time.Now().UnixNano())
a := 0
b := len(pool)
n := a + rand.Intn(b-a)
result += fmt.Sprintln("pool has", len(pool), "members", "rand =", n)
h := pool[n]
startbool, startresult := h.Start(d)
return startbool, result + startresult
}
|