-
Notifications
You must be signed in to change notification settings - Fork 88
/
alloc.go
127 lines (107 loc) · 2.76 KB
/
alloc.go
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
// Copyright 2018 Drone.IO Inc
// Use of this source code is governed by the Polyform License
// that can be found in the LICENSE file.
package engine
import (
"context"
"sync"
"time"
"github.com/drone/autoscaler"
"github.com/drone/autoscaler/engine/certs"
"github.com/drone/autoscaler/logger"
"github.com/drone/autoscaler/metrics"
)
type allocator struct {
wg sync.WaitGroup
servers autoscaler.ServerStore
provider autoscaler.Provider
metrics metrics.Collector
}
func (a *allocator) Allocate(ctx context.Context) error {
logger := logger.FromContext(ctx)
servers, err := a.servers.ListState(ctx, autoscaler.StatePending)
if err != nil {
return err
}
for _, server := range servers {
server.State = autoscaler.StateCreating
err = a.servers.Update(ctx, server)
if err != nil {
logger.WithError(err).
WithField("server", server.Name).
WithField("state", "creating").
Errorln("failed to update server state")
return err
}
a.wg.Add(1)
go func(server *autoscaler.Server) {
a.allocate(ctx, server)
a.wg.Done()
}(server)
}
return nil
}
func (a *allocator) allocate(ctx context.Context, server *autoscaler.Server) error {
logger := logger.FromContext(ctx)
defer func() {
if err := recover(); err != nil {
logger.WithError(err.(error)).
WithField("server", server.Name).
Errorln("unexpected panic")
}
}()
ca, err := certs.GenerateCA()
if err != nil {
return err
}
cert, err := certs.GenerateCert(server.Name, ca)
if err != nil {
return err
}
ctx, cancel := context.WithTimeout(ctx, time.Hour)
defer cancel()
opts := autoscaler.InstanceCreateOpts{
Name: server.Name,
CAKey: ca.Key,
CACert: ca.Cert,
TLSKey: cert.Key,
TLSCert: cert.Cert,
}
start := time.Now()
instance, err := a.provider.Create(ctx, opts)
if err != nil {
a.metrics.IncrServerCreateError()
logger.WithError(err).
WithField("server", server.Name).
Errorln("failed to provision server")
server.Error = err.Error()
server.State = autoscaler.StateError
} else {
a.metrics.TrackServerCreateTime(start)
logger.WithField("server", server.Name).
Debugln("provisioned server")
server.State = autoscaler.StateCreated
}
if instance != nil {
server.ID = instance.ID
server.Address = instance.Address
server.Image = instance.Image
server.Provider = instance.Provider
server.Region = instance.Region
server.Size = instance.Size
server.CACert = opts.CACert
server.CAKey = opts.CAKey
server.TLSCert = opts.TLSCert
server.TLSKey = opts.TLSKey
server.Started = time.Now().Unix()
}
err = a.servers.Update(ctx, server)
if err != nil {
a.metrics.IncrServerCreateError()
logger.WithError(err).
WithField("server", server.Name).
Errorln("failed to update server state")
return err
}
return nil
}