rollo 0.7.0 → 0.8.0.pre.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +5 -5
- data/CODE_OF_CONDUCT.md +1 -1
- data/Gemfile +4 -2
- data/Gemfile.lock +1127 -523
- data/LICENSE.txt +1 -1
- data/Rakefile +134 -10
- data/bin/console +4 -3
- data/lib/rollo.rb +3 -1
- data/lib/rollo/commands.rb +2 -0
- data/lib/rollo/commands/hosts.rb +125 -79
- data/lib/rollo/commands/main.rb +67 -52
- data/lib/rollo/commands/services.rb +92 -57
- data/lib/rollo/model.rb +2 -0
- data/lib/rollo/model/host.rb +4 -2
- data/lib/rollo/model/host_cluster.rb +32 -22
- data/lib/rollo/model/scaling_activity.rb +8 -6
- data/lib/rollo/model/service.rb +28 -19
- data/lib/rollo/model/service_cluster.rb +19 -14
- data/lib/rollo/version.rb +3 -1
- metadata +141 -39
- data/.envrc +0 -5
- data/.gitignore +0 -31
- data/.rspec +0 -3
- data/.ruby-version +0 -1
- data/.travis.yml +0 -5
- data/exe/rollo +0 -5
- data/go +0 -61
- data/rollo.gemspec +0 -37
data/LICENSE.txt
CHANGED
data/Rakefile
CHANGED
@@ -1,24 +1,148 @@
|
|
1
|
-
|
1
|
+
# frozen_string_literal: true
|
2
2
|
|
3
|
-
|
3
|
+
require 'yaml'
|
4
|
+
require 'rake_circle_ci'
|
5
|
+
require 'rake_github'
|
6
|
+
require 'rake_ssh'
|
7
|
+
require 'rake_gpg'
|
8
|
+
require 'securerandom'
|
9
|
+
require 'rspec/core/rake_task'
|
10
|
+
require 'rubocop/rake_task'
|
4
11
|
|
5
|
-
task :
|
12
|
+
task default: %i[
|
13
|
+
library:fix
|
14
|
+
test:unit
|
15
|
+
]
|
16
|
+
|
17
|
+
namespace :encryption do
|
18
|
+
namespace :directory do
|
19
|
+
desc 'Ensure CI secrets directory exists.'
|
20
|
+
task :ensure do
|
21
|
+
FileUtils.mkdir_p('config/secrets/ci')
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
namespace :passphrase do
|
26
|
+
desc 'Generate encryption passphrase used by CI.'
|
27
|
+
task generate: ['directory:ensure'] do
|
28
|
+
File.open('config/secrets/ci/encryption.passphrase', 'w') do |f|
|
29
|
+
f.write(SecureRandom.base64(36))
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
namespace :keys do
|
36
|
+
namespace :deploy do
|
37
|
+
RakeSSH.define_key_tasks(
|
38
|
+
path: 'config/secrets/ci/',
|
39
|
+
comment: 'maintainers@infrablocks.io'
|
40
|
+
)
|
41
|
+
end
|
42
|
+
|
43
|
+
namespace :secrets do
|
44
|
+
namespace :gpg do
|
45
|
+
RakeGPG.define_generate_key_task(
|
46
|
+
output_directory: 'config/secrets/ci',
|
47
|
+
name_prefix: 'gpg',
|
48
|
+
owner_name: 'InfraBlocks Maintainers',
|
49
|
+
owner_email: 'maintainers@infrablocks.io',
|
50
|
+
owner_comment: 'rollo CI Key'
|
51
|
+
)
|
52
|
+
end
|
53
|
+
|
54
|
+
desc 'Generate key used by CI to access secrets.'
|
55
|
+
task generate: [:'gpg:generate']
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
namespace :secrets do
|
60
|
+
desc 'Regenerate all generatable secrets.'
|
61
|
+
task regenerate: %w[
|
62
|
+
encryption:passphrase:generate
|
63
|
+
keys:deploy:generate
|
64
|
+
keys:secrets:generate
|
65
|
+
]
|
66
|
+
end
|
67
|
+
|
68
|
+
RuboCop::RakeTask.new
|
69
|
+
|
70
|
+
namespace :library do
|
71
|
+
desc 'Run all checks of the library'
|
72
|
+
task check: [:rubocop]
|
73
|
+
|
74
|
+
desc 'Attempt to automatically fix issues with the library'
|
75
|
+
task fix: [:'rubocop:auto_correct']
|
76
|
+
end
|
77
|
+
|
78
|
+
namespace :test do
|
79
|
+
RSpec::Core::RakeTask.new(:unit)
|
80
|
+
end
|
81
|
+
|
82
|
+
RakeCircleCI.define_project_tasks(
|
83
|
+
namespace: :circle_ci,
|
84
|
+
project_slug: 'github/infrablocks/rollo'
|
85
|
+
) do |t|
|
86
|
+
circle_ci_config =
|
87
|
+
YAML.load_file('config/secrets/circle_ci/config.yaml')
|
88
|
+
|
89
|
+
t.api_token = circle_ci_config['circle_ci_api_token']
|
90
|
+
t.environment_variables = {
|
91
|
+
ENCRYPTION_PASSPHRASE:
|
92
|
+
File.read('config/secrets/ci/encryption.passphrase')
|
93
|
+
.chomp
|
94
|
+
}
|
95
|
+
t.checkout_keys = []
|
96
|
+
t.ssh_keys = [
|
97
|
+
{
|
98
|
+
hostname: 'github.com',
|
99
|
+
private_key: File.read('config/secrets/ci/ssh.private')
|
100
|
+
}
|
101
|
+
]
|
102
|
+
end
|
103
|
+
|
104
|
+
RakeGithub.define_repository_tasks(
|
105
|
+
namespace: :github,
|
106
|
+
repository: 'infrablocks/rollo'
|
107
|
+
) do |t|
|
108
|
+
github_config =
|
109
|
+
YAML.load_file('config/secrets/github/config.yaml')
|
110
|
+
|
111
|
+
t.access_token = github_config['github_personal_access_token']
|
112
|
+
t.deploy_keys = [
|
113
|
+
{
|
114
|
+
title: 'CircleCI',
|
115
|
+
public_key: File.read('config/secrets/ci/ssh.public')
|
116
|
+
}
|
117
|
+
]
|
118
|
+
end
|
119
|
+
|
120
|
+
namespace :pipeline do
|
121
|
+
desc 'Prepare CircleCI Pipeline'
|
122
|
+
task prepare: %i[
|
123
|
+
circle_ci:project:follow
|
124
|
+
circle_ci:env_vars:ensure
|
125
|
+
circle_ci:checkout_keys:ensure
|
126
|
+
circle_ci:ssh_keys:ensure
|
127
|
+
github:deploy_keys:ensure
|
128
|
+
]
|
129
|
+
end
|
6
130
|
|
7
131
|
namespace :version do
|
8
|
-
desc
|
132
|
+
desc 'Bump version for specified type (pre, major, minor, patch)'
|
9
133
|
task :bump, [:type] do |_, args|
|
10
134
|
bump_version_for(args.type)
|
11
135
|
end
|
12
136
|
end
|
13
137
|
|
14
|
-
desc
|
138
|
+
desc 'Release gem'
|
15
139
|
task :release do
|
16
|
-
sh
|
140
|
+
sh 'gem release --tag --push'
|
17
141
|
end
|
18
142
|
|
19
143
|
def bump_version_for(version_type)
|
20
|
-
sh "gem bump --version #{version_type} "
|
21
|
-
|
22
|
-
|
23
|
-
|
144
|
+
sh "gem bump --version #{version_type} " \
|
145
|
+
'&& bundle install ' \
|
146
|
+
'&& export LAST_MESSAGE="$(git log -1 --pretty=%B)" ' \
|
147
|
+
'&& git commit -a --amend -m "${LAST_MESSAGE} [ci skip]"'
|
24
148
|
end
|
data/bin/console
CHANGED
@@ -1,7 +1,8 @@
|
|
1
1
|
#!/usr/bin/env ruby
|
2
|
+
# frozen_string_literal: true
|
2
3
|
|
3
|
-
require
|
4
|
-
require
|
4
|
+
require 'bundler/setup'
|
5
|
+
require 'rollo'
|
5
6
|
|
6
7
|
# You can add fixtures and/or initialization code here to make experimenting
|
7
8
|
# with your gem easier. You can also use a different console, if you like.
|
@@ -10,5 +11,5 @@ require "rollo"
|
|
10
11
|
# require "pry"
|
11
12
|
# Pry.start
|
12
13
|
|
13
|
-
require
|
14
|
+
require 'irb'
|
14
15
|
IRB.start(__FILE__)
|
data/lib/rollo.rb
CHANGED
data/lib/rollo/commands.rb
CHANGED
data/lib/rollo/commands/hosts.rb
CHANGED
@@ -1,8 +1,11 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require 'thor'
|
2
4
|
require_relative '../model'
|
3
5
|
|
4
6
|
module Rollo
|
5
7
|
module Commands
|
8
|
+
# rubocop:disable Metrics/ClassLength
|
6
9
|
class Hosts < Thor
|
7
10
|
namespace :hosts
|
8
11
|
|
@@ -11,176 +14,219 @@ module Rollo
|
|
11
14
|
end
|
12
15
|
|
13
16
|
desc(
|
14
|
-
|
15
|
-
|
17
|
+
'expand REGION ASG_NAME ECS_CLUSTER_NAME',
|
18
|
+
'Expands the host cluster by one batch.'
|
19
|
+
)
|
16
20
|
method_option(
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
21
|
+
:batch_size,
|
22
|
+
aliases: '-b',
|
23
|
+
type: :numeric,
|
24
|
+
default: 3,
|
25
|
+
desc: 'The number of hosts to add at a time.'
|
26
|
+
)
|
27
|
+
# rubocop:disable Metrics/AbcSize
|
28
|
+
# rubocop:disable Metrics/MethodLength
|
22
29
|
def expand(
|
23
|
-
|
24
|
-
|
30
|
+
region, asg_name, _,
|
31
|
+
host_cluster = nil
|
32
|
+
)
|
25
33
|
batch_size = options[:batch_size]
|
26
34
|
|
27
|
-
host_cluster
|
28
|
-
Rollo::Model::HostCluster.new(asg_name, region)
|
35
|
+
host_cluster ||= Rollo::Model::HostCluster.new(asg_name, region)
|
29
36
|
|
30
37
|
say("Increasing host cluster desired capacity by #{batch_size}...")
|
31
38
|
with_padding do
|
32
39
|
host_cluster.increase_capacity_by(batch_size) do |on|
|
33
40
|
on.prepare do |current, target|
|
34
41
|
say(
|
35
|
-
|
36
|
-
|
42
|
+
"Changing desired capacity from #{current} to " \
|
43
|
+
"#{target}..."
|
44
|
+
)
|
37
45
|
end
|
38
46
|
on.waiting_for_start do |attempt|
|
39
47
|
say(
|
40
|
-
|
41
|
-
|
48
|
+
'Waiting for capacity change to start ' \
|
49
|
+
"(attempt #{attempt})..."
|
50
|
+
)
|
42
51
|
end
|
43
52
|
on.waiting_for_end do |attempt|
|
44
53
|
say(
|
45
|
-
|
46
|
-
|
54
|
+
'Waiting for capacity change to complete ' \
|
55
|
+
"(attempt #{attempt})..."
|
56
|
+
)
|
47
57
|
end
|
48
58
|
on.waiting_for_health do |attempt|
|
49
59
|
say("Waiting for a healthy state (attempt #{attempt})")
|
50
60
|
end
|
51
61
|
end
|
52
62
|
end
|
53
|
-
say
|
63
|
+
say 'Host cluster desired capacity increased, continuing...'
|
54
64
|
end
|
55
65
|
|
66
|
+
# rubocop:enable Metrics/MethodLength
|
67
|
+
# rubocop:enable Metrics/AbcSize
|
68
|
+
|
56
69
|
desc(
|
57
|
-
|
58
|
-
|
70
|
+
'contract REGION ASG_NAME ECS_CLUSTER_NAME',
|
71
|
+
'Contracts the host cluster by one batch'
|
72
|
+
)
|
59
73
|
method_option(
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
74
|
+
:batch_size,
|
75
|
+
aliases: '-b',
|
76
|
+
type: :numeric,
|
77
|
+
default: 3,
|
78
|
+
desc: 'The number of hosts to remove at a time.'
|
79
|
+
)
|
80
|
+
# rubocop:disable Metrics/AbcSize
|
81
|
+
# rubocop:disable Metrics/MethodLength
|
65
82
|
def contract(
|
66
|
-
|
67
|
-
|
83
|
+
region, asg_name, ecs_cluster_name,
|
84
|
+
host_cluster = nil, service_cluster = nil
|
85
|
+
)
|
68
86
|
batch_size = options[:batch_size]
|
69
87
|
|
70
|
-
host_cluster
|
71
|
-
|
72
|
-
|
73
|
-
|
88
|
+
host_cluster ||= Rollo::Model::HostCluster.new(asg_name, region)
|
89
|
+
service_cluster ||= Rollo::Model::ServiceCluster.new(
|
90
|
+
ecs_cluster_name, region
|
91
|
+
)
|
74
92
|
|
75
93
|
say("Decreasing host cluster desired capacity by #{batch_size}...")
|
94
|
+
# rubocop:disable Metrics/BlockLength
|
76
95
|
with_padding do
|
77
96
|
host_cluster.decrease_capacity_by(batch_size) do |on|
|
78
97
|
on.prepare do |current, target|
|
79
98
|
say(
|
80
|
-
|
81
|
-
|
99
|
+
"Changing desired capacity from #{current} to " \
|
100
|
+
"#{target}..."
|
101
|
+
)
|
82
102
|
end
|
83
103
|
on.waiting_for_start do |attempt|
|
84
104
|
say(
|
85
|
-
|
86
|
-
|
105
|
+
'Waiting for capacity change to start ' \
|
106
|
+
"(attempt #{attempt})..."
|
107
|
+
)
|
87
108
|
end
|
88
109
|
on.waiting_for_end do |attempt|
|
89
110
|
say(
|
90
|
-
|
91
|
-
|
111
|
+
'Waiting for capacity change to complete ' \
|
112
|
+
"(attempt #{attempt})..."
|
113
|
+
)
|
92
114
|
end
|
93
115
|
on.waiting_for_health do |attempt|
|
94
116
|
say(
|
95
|
-
|
96
|
-
|
117
|
+
'Waiting for host cluster to reach healthy state ' \
|
118
|
+
"(attempt #{attempt})..."
|
119
|
+
)
|
97
120
|
end
|
98
121
|
end
|
99
|
-
service_cluster.with_replica_services do |
|
100
|
-
|
122
|
+
service_cluster.with_replica_services do |services|
|
123
|
+
services.each_service do |service|
|
101
124
|
service.wait_for_service_health do |on|
|
102
125
|
on.waiting_for_health do |attempt|
|
103
126
|
say(
|
104
|
-
|
105
|
-
|
127
|
+
"Waiting for service #{service.name} to reach a " \
|
128
|
+
"steady state (attempt #{attempt})..."
|
129
|
+
)
|
106
130
|
end
|
107
131
|
end
|
108
132
|
end
|
109
133
|
end
|
110
134
|
end
|
111
|
-
|
135
|
+
# rubocop:enable Metrics/BlockLength
|
136
|
+
say 'Host cluster desired capacity decreased, continuing...'
|
112
137
|
end
|
113
138
|
|
139
|
+
# rubocop:enable Metrics/MethodLength
|
140
|
+
# rubocop:enable Metrics/AbcSize
|
141
|
+
|
114
142
|
desc(
|
115
|
-
|
116
|
-
|
143
|
+
'terminate REGION ASG_NAME ECS_CLUSTER_NAME INSTANCE_IDS*',
|
144
|
+
'Terminates the specified hosts within the cluster.'
|
145
|
+
)
|
117
146
|
method_option(
|
118
|
-
|
119
|
-
|
120
|
-
|
121
|
-
|
122
|
-
|
147
|
+
:batch_size,
|
148
|
+
aliases: '-b',
|
149
|
+
type: :numeric,
|
150
|
+
default: 3,
|
151
|
+
desc: 'The number of hosts to add at a time.'
|
152
|
+
)
|
123
153
|
method_option(
|
124
|
-
|
125
|
-
|
126
|
-
|
127
|
-
|
128
|
-
|
154
|
+
:startup_time,
|
155
|
+
aliases: '-t',
|
156
|
+
type: :numeric,
|
157
|
+
default: 2,
|
158
|
+
desc: 'The number of minutes to wait for services to start up.'
|
159
|
+
)
|
160
|
+
# rubocop:disable Metrics/MethodLength
|
161
|
+
# rubocop:disable Metrics/AbcSize
|
162
|
+
# rubocop:disable Metrics/ParameterLists
|
129
163
|
def terminate(
|
130
|
-
|
131
|
-
|
164
|
+
region, asg_name, ecs_cluster_name, instance_ids,
|
165
|
+
host_cluster = nil, service_cluster = nil
|
166
|
+
)
|
132
167
|
batch_size = options[:batch_size]
|
133
168
|
|
134
169
|
service_start_wait_minutes = options[:startup_time]
|
135
170
|
service_start_wait_seconds = 60 * service_start_wait_minutes
|
136
171
|
|
137
|
-
host_cluster
|
138
|
-
|
139
|
-
|
140
|
-
Rollo::Model::ServiceCluster.new(ecs_cluster_name, region)
|
172
|
+
host_cluster ||= Rollo::Model::HostCluster.new(asg_name, region)
|
173
|
+
service_cluster ||= Rollo::Model::ServiceCluster.new(ecs_cluster_name,
|
174
|
+
region)
|
141
175
|
|
142
|
-
hosts = host_cluster.hosts.select {|h| instance_ids.include?(h.id) }
|
176
|
+
hosts = host_cluster.hosts.select { |h| instance_ids.include?(h.id) }
|
143
177
|
host_batches = hosts.each_slice(batch_size).to_a
|
144
178
|
|
145
179
|
say(
|
146
|
-
|
147
|
-
|
180
|
+
'Terminating old hosts in host cluster in batches of ' \
|
181
|
+
"#{batch_size}..."
|
182
|
+
)
|
183
|
+
# rubocop:disable Metrics/BlockLength
|
148
184
|
with_padding do
|
149
185
|
host_batches.each_with_index do |host_batch, index|
|
150
186
|
say(
|
151
|
-
|
152
|
-
|
153
|
-
|
187
|
+
"Batch #{index + 1} contains hosts: " \
|
188
|
+
"\n\t\t[#{host_batch.map(&:id).join(",\n\t\t ")}]\n" \
|
189
|
+
'Terminating...'
|
190
|
+
)
|
154
191
|
host_batch.each(&:terminate)
|
155
192
|
host_cluster.wait_for_capacity_health do |on|
|
156
193
|
on.waiting_for_health do |attempt|
|
157
194
|
say(
|
158
|
-
|
159
|
-
|
195
|
+
'Waiting for host cluster to reach healthy state ' \
|
196
|
+
"(attempt #{attempt})"
|
197
|
+
)
|
160
198
|
end
|
161
199
|
end
|
162
|
-
service_cluster.with_replica_services do |
|
163
|
-
|
200
|
+
service_cluster.with_replica_services do |services|
|
201
|
+
services.each_service do |service|
|
164
202
|
service.wait_for_service_health do |on|
|
165
203
|
on.waiting_for_health do |attempt|
|
166
204
|
say(
|
167
|
-
|
168
|
-
|
205
|
+
"Waiting for service #{service.name} to reach a " \
|
206
|
+
"steady state (attempt #{attempt})..."
|
207
|
+
)
|
169
208
|
end
|
170
209
|
end
|
171
210
|
end
|
172
211
|
end
|
173
212
|
say(
|
174
|
-
|
175
|
-
|
213
|
+
"Waiting #{service_start_wait_minutes} minute(s) for " \
|
214
|
+
'services to finish starting...'
|
215
|
+
)
|
176
216
|
sleep(service_start_wait_seconds)
|
177
217
|
say(
|
178
|
-
|
179
|
-
|
218
|
+
"Waited #{service_start_wait_minutes} minute(s). " \
|
219
|
+
'Continuing...'
|
220
|
+
)
|
180
221
|
end
|
181
222
|
end
|
182
|
-
|
223
|
+
# rubocop:enable Metrics/BlockLength
|
183
224
|
end
|
225
|
+
# rubocop:enable Metrics/ParameterLists
|
226
|
+
# rubocop:enable Metrics/MethodLength
|
227
|
+
# rubocop:enable Metrics/AbcSize
|
184
228
|
end
|
229
|
+
|
230
|
+
# rubocop:enable Metrics/ClassLength
|
185
231
|
end
|
186
232
|
end
|