forked from evergreen-ci/evergreen
/
anser.go
154 lines (126 loc) · 4.01 KB
/
anser.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
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
package migrations
import (
"context"
"time"
"github.com/evergreen-ci/evergreen"
"github.com/evergreen-ci/evergreen/util"
"github.com/mongodb/amboy/pool"
"github.com/mongodb/amboy/queue"
"github.com/mongodb/anser"
"github.com/mongodb/anser/db"
"github.com/mongodb/anser/model"
"github.com/mongodb/grip"
"github.com/pkg/errors"
)
type Options struct {
Limit int
Target int
Workers int
DryRun bool
IDs []string
Period time.Duration
Database string
Session db.Session
}
// Setup configures the migration environment, configuring the backing
// queue and a database session.
func (opts Options) Setup(ctx context.Context) (anser.Environment, error) {
var cancel context.CancelFunc
ctx, cancel = context.WithCancel(ctx)
env := anser.GetEnvironment()
env.RegisterCloser(func() error { cancel(); return nil })
q := queue.NewAdaptiveOrderedLocalQueue(1)
runner, err := pool.NewMovingAverageRateLimitedWorkers(opts.Workers, opts.Target, opts.Period, q)
if err != nil {
return nil, errors.WithStack(err)
}
if err = q.SetRunner(runner); err != nil {
return nil, errors.WithStack(err)
}
if err = q.Start(ctx); err != nil {
return nil, errors.WithStack(err)
}
if err = env.Setup(q, opts.Session); err != nil {
return nil, errors.WithStack(err)
}
return env, nil
}
type migrationGeneratorFactoryOptions struct {
id string
db string
limit int
}
type migrationGeneratorFactory func(anser.Environment, migrationGeneratorFactoryOptions) (anser.Generator, error)
// Application is where the migrations are registered and defined,
// before being handed off to another calling environment for
// execution. See the anser documentation and the
// anser/example_test.go for an example.
func (opts Options) Application(env anser.Environment, evgEnv evergreen.Environment) (*anser.Application, error) {
app := &anser.Application{
Options: model.ApplicationOptions{
Limit: opts.Limit,
DryRun: opts.DryRun,
},
}
githubToken, err := evgEnv.Settings().GetGithubOauthToken()
if err != nil {
return nil, err
}
generatorFactories := map[string]migrationGeneratorFactory{
// Early Migrations, disabled because the generator queries are not properly indexed.
//
// migrationTestResultsLegacyExecution: addExecutionToTasksGenerator,
// migrationTestResultsOldTasks: oldTestResultsGenerator,
// migrationTestResultstasks: testResultsGenerator,
migrationProjectAliasesToCollection: projectAliasesToCollectionGenerator,
migrationGithubHooksToCollection: githubHooksToCollectionGenerator,
migrationZeroDateFix: zeroDateFixGenerator(githubToken),
migrationAdminEventRestructure: adminEventRestructureGenerator,
migrationEventRtypeRestructureAllLogs: eventRTypeMigration,
migrationSetDefaultBranch: setDefaultBranchMigrationGenerator,
migrationAdminMapRestructure: adminMapRestructureGenerator,
migrationSpawnhostExpirationPreference: setSpawnhostPreferenceGenerator,
migrationDistroSecurityGroups: distroSecurityGroupsGenerator,
}
catcher := grip.NewBasicCatcher()
for _, id := range opts.IDs {
if _, ok := generatorFactories[id]; !ok {
catcher.Add(errors.Errorf("no migration defined matching id '%s'", id))
}
}
if catcher.HasErrors() {
return nil, catcher.Resolve()
}
for name, factory := range generatorFactories {
if opts.shouldSkipMigration(name) {
continue
}
args := migrationGeneratorFactoryOptions{
id: name,
db: opts.Database,
limit: opts.Limit,
}
generator, err := factory(env, args)
catcher.Add(err)
if generator != nil {
app.Generators = append(app.Generators, generator)
grip.Debugf("adding generator named: %s", name)
}
}
if catcher.HasErrors() {
return nil, catcher.Resolve()
}
if err := app.Setup(env); err != nil {
return nil, errors.WithStack(err)
}
return app, nil
}
func (opts Options) shouldSkipMigration(id string) bool {
if len(opts.IDs) == 0 {
return false
}
if util.StringSliceContains(opts.IDs, id) {
return false
}
return true
}