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
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
|
package main
import (
"errors"
"fmt"
"io/ioutil"
"math/rand"
"net/http"
"time"
"github.com/google/uuid"
"go.wit.com/lib/gui/shell"
pb "go.wit.com/lib/protobuf/virtbuf"
"go.wit.com/log"
)
// attempts to create a new virtual machine
func create(w http.ResponseWriter, r *http.Request) error {
msg, err := ioutil.ReadAll(r.Body) // Read the body as []byte
if err != nil {
fmt.Fprintln(w, "ReadAll() error =", err)
return err
}
var d *pb.Droplet
d = new(pb.Droplet)
if err := d.UnmarshalJSON(msg); err != nil {
return err
}
log.Info("Got msg:", string(msg))
log.Info("hostname =", d.Hostname)
name := d.Hostname
tmpd := findDroplet(name)
if tmpd != nil {
result := "create error: Droplet " + name + " is already defined"
fmt.Fprintln(w, result)
return errors.New(result)
}
if d.Uuid == "" {
u := uuid.New()
d.Uuid = u.String()
}
if len(d.Networks) == 0 {
var newNet *pb.Network
newNet = new(pb.Network)
newNet.Mac = getNewMac()
d.Networks = append(d.Networks, newNet)
// d.AddDefaultNetwork(mac)
}
me.cluster.Droplets = append(me.cluster.Droplets, d)
result, err := startDroplet(d)
if err != nil {
fmt.Fprintln(w, result)
fmt.Fprintln(w, "startDroplet(d) failed:", err)
return err
}
fmt.Fprintln(w, result)
fmt.Fprintln(w, "START=OK")
return nil
}
// for now, because sometimes this should write to stdout and
// sometimes to http socket, it returns a string
func startDroplet(d *pb.Droplet) (string, error) {
var result string
name := d.Hostname
// validate the droplet
if err := ValidateDroplet(d); err != nil {
result = "ValidateDroplet() failed droplet " + d.Hostname
return result, err
}
// is the droplet already on?
if d.CurrentState == pb.DropletState_ON {
result = "EVENT start droplet " + d.Hostname + " is already ON"
return result, errors.New(result)
}
// how long has the cluster been stable?
// wait until it is stable. use this to throttle droplet starts
dur := time.Since(me.unstable)
result = fmt.Sprintln("should start droplet", name, "here. grid stable for:", shell.FormatDuration(dur))
if dur < me.unstableTimeout {
tmp := shell.FormatDuration(me.unstableTimeout)
result += "grid is still too unstable (unstable timeout = " + tmp + ")"
return result, errors.New("grid is still unstable")
}
// make the list of hypervisors that are active and can start new droplets
var pool []*HyperT
for _, h := range me.hypers {
// this droplet is set to use this and only this hypervisor
if d.ForceHypervisor == h.pb.Hostname {
ok, b := h.start(d)
if ok {
return result + b, nil
}
return result + b, errors.New("start " + name + " on hypervisor " + h.pb.Hostname)
}
// skip hypervisors marked inactive
if h.pb.Active != true {
result += fmt.Sprintln("hypervisor is inactive:", name, "for", h.pb.Hostname, h.pb.Active)
continue
}
// the config file says this droplet should run on this hypervisor
// attempt to start the droplet here. use this even if the hypervisor is inactive?
if d.PreferredHypervisor == h.pb.Hostname {
ok, b := h.start(d)
if ok {
return result + b, nil
}
return result + b, errors.New("start " + name + " on hypervisor " + h.pb.Hostname)
}
result += fmt.Sprintln("hypervisor ready:", name, "for", h.pb.Hostname, h.pb.Active)
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]
// update/resend the search directories to the hypervisor
result += fmt.Sprintln("h.sendDirs() HERE")
result += fmt.Sprintln("h.sendDirs() HERE")
h.sendDirs()
ok, output := h.start(d)
if ok {
return result + output, nil
}
return result + output, errors.New("start " + name + " on hypervisor " + h.pb.Hostname)
}
|