gaptool-server 0.6.6 → 0.7.0
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 +4 -4
- data/Rakefile +1 -1
- data/VERSION +1 -1
- data/bin/gaptool-server +1 -1
- data/bin/gaptool_server_migrate_0.6-0.7 +35 -0
- data/lib/helpers/data.rb +23 -16
- data/lib/helpers/ec2.rb +42 -9
- data/lib/helpers/rehash.rb +4 -2
- data/lib/routes.rb +47 -12
- data/tasks/app.rb +24 -7
- data/tasks/docker.rb +6 -6
- data/tasks/ec2.rb +6 -0
- data/tasks/role.rb +1 -1
- data/test/api_test.rb +113 -6
- data/test/data_test.rb +9 -9
- metadata +22 -8
- data/bin/gaptool_migrate_security_groups +0 -18
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA1:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 9bdd9381a7a9adcc78aed7919ba4cdc36c718f93
|
|
4
|
+
data.tar.gz: 9d716274f9ab9c02a9c0c62e27d011d6b381029c
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 07863c41b56f69c29b9915deb3db26aa03a89965c48a63cf71196a0545646d2ea994e61d03b789011382bdb23da37d157e055e9ac20358a052be250f9aa37531
|
|
7
|
+
data.tar.gz: 2e3f46dc0f16ff83aab782e97a50b938c83f7b736c7a7fa38e30bb9d74755bbd6662a9b101a17766a28af9b25d5064214d1dd6b67aa516becdffcfdc3a2c6380
|
data/Rakefile
CHANGED
|
@@ -32,7 +32,7 @@ unless File.exists?('/.dockerenv')
|
|
|
32
32
|
|
|
33
33
|
desc "Start the HTTP server"
|
|
34
34
|
task :server do
|
|
35
|
-
exec "
|
|
35
|
+
exec "puma -p 3000 --preload -t 8:32 -w 3 #{Shellwords.join(ARGV[1..-1])}"
|
|
36
36
|
end
|
|
37
37
|
|
|
38
38
|
desc "Bump the version"
|
data/VERSION
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
0.
|
|
1
|
+
0.7.0
|
data/bin/gaptool-server
CHANGED
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
#!/usr/bin/env ruby
|
|
2
|
+
#
|
|
3
|
+
# Convert all apps for new data format
|
|
4
|
+
|
|
5
|
+
libpath = File.expand_path(File.join(File.dirname(__FILE__), "..", "lib"))
|
|
6
|
+
$:.unshift(libpath)
|
|
7
|
+
require "#{libpath}/helpers/redis"
|
|
8
|
+
require "#{libpath}/helpers/data"
|
|
9
|
+
DH = Gaptool::Data
|
|
10
|
+
|
|
11
|
+
# - $redis.sadd("role:#{role}:apps", name)
|
|
12
|
+
# - $redis.set("app:#{name}", role)
|
|
13
|
+
# + $redis.sadd("apps:#{environment}", name)
|
|
14
|
+
# + $redis.sadd("role:#{role}:#{environment}:apps", name)
|
|
15
|
+
# + $redis.hset("app:#{name}", environment, role)
|
|
16
|
+
# - role = $redis.get(key)
|
|
17
|
+
# + roles = $redis.hgetall(key)
|
|
18
|
+
# - role = $redis.get("app:#{app}")
|
|
19
|
+
# + return $redis.hgetall("app:#{app}")
|
|
20
|
+
# - $redis.smembers("role:#{role}:apps")
|
|
21
|
+
# + $redis.smembers("apps:#{environment}")
|
|
22
|
+
# + $redis.smembers("role:#{role}:#{environment}:apps")
|
|
23
|
+
|
|
24
|
+
puts 'Removing role:*:apps'
|
|
25
|
+
$redis.keys("role:*:apps").each {|k| $redis.del(k)}
|
|
26
|
+
puts "Migrating apps"
|
|
27
|
+
$redis.keys("app:*").each do |key|
|
|
28
|
+
app = key.sub(/app:/, "")
|
|
29
|
+
puts " * app: #{app} (#{key})"
|
|
30
|
+
role = $redis.get(key)
|
|
31
|
+
$redis.del("app:#{app}")
|
|
32
|
+
%w(staging production).each do |env|
|
|
33
|
+
DH.add_app(app, role, env)
|
|
34
|
+
end
|
|
35
|
+
end
|
data/lib/helpers/data.rb
CHANGED
|
@@ -39,7 +39,7 @@ module Gaptool
|
|
|
39
39
|
if !key.nil? && !data.nil? && !data.empty?
|
|
40
40
|
$redis.multi do
|
|
41
41
|
$redis.del(key)
|
|
42
|
-
$redis.hmset(key, *data.select{ |k,v| !v.nil? && ((v.is_a?(String) && !v.empty?) || !!v == v)}.flatten)
|
|
42
|
+
$redis.hmset(key, *data.select{ |k,v| !v.nil? && ((v.is_a?(String) && !v.empty?) || (v.is_a?(Integer)) || !!v == v)}.flatten)
|
|
43
43
|
end
|
|
44
44
|
end
|
|
45
45
|
end
|
|
@@ -152,12 +152,17 @@ module Gaptool
|
|
|
152
152
|
rs.delete('terminable')
|
|
153
153
|
end
|
|
154
154
|
|
|
155
|
+
if !rs['hidden'].nil? && rs['hidden'] == "true"
|
|
156
|
+
rs['hidden'] = true
|
|
157
|
+
end
|
|
158
|
+
|
|
155
159
|
if opts[:force_runlist] && rs['chef_runlist'].nil?
|
|
156
160
|
rs['chef_runlist'] = default_runlist
|
|
157
161
|
end
|
|
158
162
|
|
|
159
163
|
rs.delete_if {|k,v| v.nil? || (!!v != v && v.empty?)}
|
|
160
|
-
rs['
|
|
164
|
+
rs['launch_time'] = rs['launch_time'].to_i if rs['launch_time']
|
|
165
|
+
rs['apps'] = apps_in_role(rs['role'], rs['environment'])
|
|
161
166
|
rs
|
|
162
167
|
end
|
|
163
168
|
|
|
@@ -172,16 +177,16 @@ module Gaptool
|
|
|
172
177
|
overwrite_hash("role:#{role}:sg", sgs)
|
|
173
178
|
end
|
|
174
179
|
if data['apps']
|
|
175
|
-
apps = data.delete("apps")
|
|
176
|
-
apps.each {|
|
|
180
|
+
apps = data.delete("apps")
|
|
181
|
+
apps.each {|env, app| add_app(app, role, env)}
|
|
177
182
|
end
|
|
178
183
|
overwrite_hash("role:#{role}", data)
|
|
179
184
|
$redis.sadd("roles", role)
|
|
180
185
|
end
|
|
181
186
|
|
|
182
|
-
def self.get_role_data(role)
|
|
187
|
+
def self.get_role_data(role, environment=nil)
|
|
183
188
|
res = $redis.hgetall("role:#{role}")
|
|
184
|
-
res['apps'] = apps_in_role(role)
|
|
189
|
+
res['apps'] = environment ? apps_in_role(role, environment) : []
|
|
185
190
|
res['amis'] = $redis.hgetall("role:#{role}:amis")
|
|
186
191
|
res['sg'] = $redis.hgetall("role:#{role}:sg")
|
|
187
192
|
res
|
|
@@ -231,12 +236,13 @@ module Gaptool
|
|
|
231
236
|
Hash[$redis.smembers("roles").map {|r| [r, get_role_data(r)] }]
|
|
232
237
|
end
|
|
233
238
|
|
|
234
|
-
def self.add_app(name, role)
|
|
239
|
+
def self.add_app(name, role, environment)
|
|
235
240
|
return if name.nil? || role.nil?
|
|
236
241
|
$redis.multi do
|
|
237
242
|
$redis.sadd("apps", name)
|
|
238
|
-
$redis.sadd("
|
|
239
|
-
$redis.
|
|
243
|
+
$redis.sadd("apps:#{environment}", name)
|
|
244
|
+
$redis.sadd("role:#{role}:#{environment}:apps", name)
|
|
245
|
+
$redis.hset("app:#{name}", environment, role)
|
|
240
246
|
end
|
|
241
247
|
end
|
|
242
248
|
|
|
@@ -244,12 +250,14 @@ module Gaptool
|
|
|
244
250
|
return if name.nil?
|
|
245
251
|
key = "app:#{name}"
|
|
246
252
|
$redis.watch(key) do
|
|
247
|
-
|
|
248
|
-
if !
|
|
253
|
+
roles = $redis.hgetall(key)
|
|
254
|
+
if !roles.nil?
|
|
249
255
|
$redis.multi do |m|
|
|
250
256
|
m.del(key)
|
|
251
257
|
m.srem("apps", name)
|
|
252
|
-
|
|
258
|
+
roles.each do |env, role|
|
|
259
|
+
m.srem("role:#{role}:#{env}:apps", name)
|
|
260
|
+
end
|
|
253
261
|
end
|
|
254
262
|
else
|
|
255
263
|
$redis.unwatch
|
|
@@ -258,16 +266,15 @@ module Gaptool
|
|
|
258
266
|
end
|
|
259
267
|
|
|
260
268
|
def self.get_app_data(app)
|
|
261
|
-
|
|
262
|
-
return {"role" => role } unless role.nil?
|
|
269
|
+
return $redis.hgetall("app:#{app}")
|
|
263
270
|
end
|
|
264
271
|
|
|
265
272
|
def self.apps
|
|
266
273
|
$redis.smembers("apps")
|
|
267
274
|
end
|
|
268
275
|
|
|
269
|
-
def self.apps_in_role(role)
|
|
270
|
-
$redis.smembers("role:#{role}:apps")
|
|
276
|
+
def self.apps_in_role(role, environment)
|
|
277
|
+
$redis.smembers("role:#{role}:#{environment}:apps")
|
|
271
278
|
end
|
|
272
279
|
|
|
273
280
|
def self.stringify_apps(rs)
|
data/lib/helpers/ec2.rb
CHANGED
|
@@ -54,7 +54,7 @@ module Gaptool
|
|
|
54
54
|
return {id: id,
|
|
55
55
|
hostname: "test-#{id}.#{data[:zone].chop}.compute.amazonaws.com",
|
|
56
56
|
instance: nil,
|
|
57
|
-
launch_time: Time.now.
|
|
57
|
+
launch_time: Time.now.to_i}
|
|
58
58
|
end
|
|
59
59
|
configure_ec2 data[:zone].chop
|
|
60
60
|
ec2 = AWS::EC2.new
|
|
@@ -71,13 +71,6 @@ module Gaptool
|
|
|
71
71
|
retry
|
|
72
72
|
end
|
|
73
73
|
|
|
74
|
-
begin
|
|
75
|
-
launch_time = instance.launch_time.to_s
|
|
76
|
-
launch_time = launch_time.empty? ? Time.now.to_s : launch_time
|
|
77
|
-
rescue
|
|
78
|
-
launch_time = Time.now.to_s
|
|
79
|
-
end
|
|
80
|
-
|
|
81
74
|
i = 0
|
|
82
75
|
begin
|
|
83
76
|
hostname = instance.public_dns_name
|
|
@@ -89,7 +82,7 @@ module Gaptool
|
|
|
89
82
|
Airbrake.notify_or_ignore(
|
|
90
83
|
e,
|
|
91
84
|
error_class: "EC2 public dns fail",
|
|
92
|
-
parameters: {instance: instance
|
|
85
|
+
parameters: {instance: instance.id, role: data['role'], environment: data['environment'], hostname: nil}
|
|
93
86
|
)
|
|
94
87
|
else
|
|
95
88
|
@@logger.error("Error getting hostname for instance: #{e}: sleeping #{sleeptime}s and retrying (#{i}/#{retries})")
|
|
@@ -97,6 +90,31 @@ module Gaptool
|
|
|
97
90
|
retry
|
|
98
91
|
end
|
|
99
92
|
end
|
|
93
|
+
|
|
94
|
+
i = 0
|
|
95
|
+
begin
|
|
96
|
+
launch_time = instance.launch_time.to_i
|
|
97
|
+
raise unless launch_time.is_a? Integer
|
|
98
|
+
|
|
99
|
+
rescue => e
|
|
100
|
+
i += 1
|
|
101
|
+
if i > retries
|
|
102
|
+
@@logger.error("Cloud not get launch time for instance #{instance} after #{retries} retries. Setting to now()")
|
|
103
|
+
launch_time = Time.now.to_i
|
|
104
|
+
Airbrake.notify_or_ignore(
|
|
105
|
+
e,
|
|
106
|
+
error_class: "EC2 get launch_time fail",
|
|
107
|
+
parameters: {instance: instance.id, role: data['role'], environment: data['environment'], hostname: nil}
|
|
108
|
+
)
|
|
109
|
+
else
|
|
110
|
+
@@logger.error("Error getting launch_time for instance: #{e}: sleeping #{sleeptime}s and retrying (#{i}/#{retries})")
|
|
111
|
+
sleep sleeptime
|
|
112
|
+
retry
|
|
113
|
+
end
|
|
114
|
+
end
|
|
115
|
+
|
|
116
|
+
@@logger.info {"Instance #{instance.id} launch_time: #{launch_time} #{instance.launch_time}"}
|
|
117
|
+
|
|
100
118
|
{
|
|
101
119
|
id: instance.id,
|
|
102
120
|
instance: instance,
|
|
@@ -142,5 +160,20 @@ module Gaptool
|
|
|
142
160
|
hostname: instance.dns_name
|
|
143
161
|
}
|
|
144
162
|
end
|
|
163
|
+
|
|
164
|
+
def self.retag()
|
|
165
|
+
logger = Logger.new(STDOUT)
|
|
166
|
+
Gaptool::Data::servers.each do |id|
|
|
167
|
+
data = Gaptool::Data.get_server_data(id)
|
|
168
|
+
next if data.nil? || data['zone'].nil? || data['zone'].empty?
|
|
169
|
+
Gaptool::EC2::configure_ec2 data['zone'].chop
|
|
170
|
+
ec2 = AWS::EC2.new(region: data['zone'].chop)
|
|
171
|
+
instance = ec2.instances[id]
|
|
172
|
+
next if instance.tags.role && instance.tags.environment
|
|
173
|
+
logger.info("Retagging instance #{id} in zone #{data['zone'].chop}")
|
|
174
|
+
instance.tags.role = data['role']
|
|
175
|
+
instance.tags.environment = data['environment']
|
|
176
|
+
end
|
|
177
|
+
end
|
|
145
178
|
end
|
|
146
179
|
end
|
data/lib/helpers/rehash.rb
CHANGED
|
@@ -48,7 +48,7 @@ module Gaptool
|
|
|
48
48
|
%w[hostname itype security_group].each do |property|
|
|
49
49
|
res[property] = self.rehash_property_for_instance(property, instance_id, false)
|
|
50
50
|
end
|
|
51
|
-
Gaptool::set_server_data_attributes(instance_id, res)
|
|
51
|
+
Gaptool::Data::set_server_data_attributes(instance_id, res)
|
|
52
52
|
end
|
|
53
53
|
|
|
54
54
|
def self.rehash_property_for_instance(property, instance_id, save=true)
|
|
@@ -67,11 +67,13 @@ module Gaptool
|
|
|
67
67
|
value = instance.instance_type
|
|
68
68
|
when "security_group"
|
|
69
69
|
value = instance.security_groups[0].name
|
|
70
|
+
when "launch_time"
|
|
71
|
+
value = instance.launch_time.to_i
|
|
70
72
|
else
|
|
71
73
|
return false
|
|
72
74
|
end
|
|
75
|
+
logger.info("Setting #{property} to #{value} for #{instance_id}")
|
|
73
76
|
if save
|
|
74
|
-
logger.info("Setting #{property} to #{value} for #{instance_id}")
|
|
75
77
|
Gaptool::Data.set_server_data_attr(instance_id, property, value)
|
|
76
78
|
else
|
|
77
79
|
value
|
data/lib/routes.rb
CHANGED
|
@@ -67,7 +67,7 @@ class GaptoolServer < Sinatra::Application
|
|
|
67
67
|
end
|
|
68
68
|
|
|
69
69
|
# Add host tag
|
|
70
|
-
data.merge(instance.reject { |k, v| [:id, :instance].include?(k) })
|
|
70
|
+
data.merge!(Hash[instance.reject { |k, v| [:id, :instance].include?(k) }.map {|k, v| [k.to_s, v]}])
|
|
71
71
|
Gaptool::Data::addserver(instance[:id], data, secret)
|
|
72
72
|
json({instance: instance[:id],
|
|
73
73
|
ami: image_id,
|
|
@@ -136,24 +136,37 @@ class GaptoolServer < Sinatra::Application
|
|
|
136
136
|
end
|
|
137
137
|
|
|
138
138
|
get '/hosts' do
|
|
139
|
-
|
|
139
|
+
filter = !!params['hidden'] ? Proc.new {|s| !s['registered']} : Proc.new { |s| !s['registered'] && !s['hidden'] == true}
|
|
140
|
+
json(Gaptool::Data::servers.map do |inst|
|
|
140
141
|
Gaptool::Data::get_server_data inst
|
|
141
|
-
end.select
|
|
142
|
-
json servers
|
|
142
|
+
end.select(&filter))
|
|
143
143
|
end
|
|
144
144
|
|
|
145
145
|
get '/apps' do
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
146
|
+
json(Hash[Gaptool::Data.apps.map {|a| ["app:#{a}", Gaptool::Data::get_app_data(a)]}])
|
|
147
|
+
end
|
|
148
|
+
|
|
149
|
+
get '/app/:app/:environment/hosts' do
|
|
150
|
+
app_data = Gaptool::Data::get_app_data(params[:app])
|
|
151
|
+
unless app_data
|
|
152
|
+
status 404
|
|
153
|
+
error_response "app '#{params[:apps]}' not found"
|
|
149
154
|
end
|
|
150
|
-
|
|
155
|
+
|
|
156
|
+
role = app_data[params[:environment]]
|
|
157
|
+
list = Gaptool::Data::servers_in_role_env role, params[:environment]
|
|
158
|
+
filter = !!params['hidden'] ? Proc.new {|s| false } : Proc.new { |s| s['hidden']}
|
|
159
|
+
json(list.map do |inst|
|
|
160
|
+
data = Gaptool::Data::get_server_data(inst)
|
|
161
|
+
Gaptool::Data::stringify_apps(data)
|
|
162
|
+
end.delete_if(&filter))
|
|
151
163
|
end
|
|
152
164
|
|
|
153
165
|
get '/hosts/:role' do
|
|
166
|
+
filter = !!params['hidden'] ? Proc.new {|s| !s['registered']} : Proc.new { |s| !s['registered'] && !s['hidden'] == true}
|
|
154
167
|
servers = Gaptool::Data::servers_in_role(params[:role]).map do |inst|
|
|
155
|
-
Gaptool::Data::get_server_data
|
|
156
|
-
end.select
|
|
168
|
+
Gaptool::Data::get_server_data(inst)
|
|
169
|
+
end.select(&filter)
|
|
157
170
|
json servers
|
|
158
171
|
end
|
|
159
172
|
|
|
@@ -167,15 +180,37 @@ class GaptoolServer < Sinatra::Application
|
|
|
167
180
|
end
|
|
168
181
|
end
|
|
169
182
|
|
|
183
|
+
patch '/instance/:id' do
|
|
184
|
+
rs = Gaptool::Data::get_server_data(params[:id])
|
|
185
|
+
if rs.nil?
|
|
186
|
+
status 404
|
|
187
|
+
error_response "instance with id '#{params[:id]}' not found"
|
|
188
|
+
else
|
|
189
|
+
data = JSON.parse(request.body.read)
|
|
190
|
+
if !data['hidden'].nil?
|
|
191
|
+
hidden = !!data['hidden']
|
|
192
|
+
rs["hidden"] = hidden if hidden == true
|
|
193
|
+
rs.delete("hidden") if hidden == false
|
|
194
|
+
end
|
|
195
|
+
if !data['terminable'].nil?
|
|
196
|
+
rs["terminable"] = !!data['terminable']
|
|
197
|
+
end
|
|
198
|
+
Gaptool::Data::save_server_data params[:id], rs
|
|
199
|
+
json Gaptool::Data::stringify_apps(rs)
|
|
200
|
+
end
|
|
201
|
+
end
|
|
202
|
+
|
|
170
203
|
get '/hosts/:role/:environment' do
|
|
171
204
|
if params[:role] == 'ALL'
|
|
172
205
|
list = Gaptool::Data::servers_in_env params[:environment]
|
|
173
206
|
else
|
|
174
207
|
list = Gaptool::Data::servers_in_role_env params[:role], params[:environment]
|
|
175
208
|
end
|
|
209
|
+
filter = !!params['hidden'] ? Proc.new {|s| false } : Proc.new { |s| s['hidden']}
|
|
176
210
|
servers = list.map do |inst|
|
|
177
|
-
Gaptool::Data::
|
|
178
|
-
|
|
211
|
+
data = Gaptool::Data::get_server_data(inst)
|
|
212
|
+
Gaptool::Data::stringify_apps(data)
|
|
213
|
+
end.delete_if(&filter)
|
|
179
214
|
|
|
180
215
|
json servers
|
|
181
216
|
end
|
data/tasks/app.rb
CHANGED
|
@@ -1,14 +1,20 @@
|
|
|
1
1
|
namespace :app do
|
|
2
2
|
desc "Add an application"
|
|
3
|
-
task :add, [:app, :role] do |t, args|
|
|
4
|
-
|
|
3
|
+
task :add, [:app, :role, :environment] do |t, args|
|
|
4
|
+
[:app, :role, :environment].each do |arg|
|
|
5
|
+
abort("Missing parameter #{arg}") if args[arg].nil? || args[arg].empty?
|
|
6
|
+
end
|
|
5
7
|
ex = DH.get_app_data(args[:app])
|
|
6
8
|
unless ex.nil?
|
|
7
|
-
puts "Updating application #{args[:app]}
|
|
9
|
+
puts "Updating application #{args[:app]} (#{args[:environment]}) to #{args[:role]}"
|
|
8
10
|
DH.remove_app(args[:app])
|
|
11
|
+
ex.delete(args[:environment])
|
|
12
|
+
end
|
|
13
|
+
DH.add_app(args[:app], args[:role], args[:environment])
|
|
14
|
+
ex.each do |env, role|
|
|
15
|
+
DH.add_app(args[:app], role, env)
|
|
9
16
|
end
|
|
10
|
-
|
|
11
|
-
puts "Added app #{args[:app]} in role #{args[:role]}"
|
|
17
|
+
puts "Added app #{args[:app]}, role #{args[:role]}, environment: #{args[:environment]}"
|
|
12
18
|
end
|
|
13
19
|
|
|
14
20
|
desc "Remove an application"
|
|
@@ -25,9 +31,20 @@ namespace :app do
|
|
|
25
31
|
if info.nil? || info.empty?
|
|
26
32
|
puts "No such app #{args[:app]}"
|
|
27
33
|
else
|
|
28
|
-
puts " * #{
|
|
34
|
+
puts " * #{app} #{info.map {|k,v| "#{k}: #{v}"}.join(", ")}"
|
|
29
35
|
end
|
|
36
|
+
end
|
|
30
37
|
|
|
38
|
+
desc "Copy all apps for a role to a new env"
|
|
39
|
+
task :newenv, [:role, :oldenv, :newenv, :newrole] do |t, args|
|
|
40
|
+
[:role, :oldenv, :newenv].each do |k|
|
|
41
|
+
abort "Missing parameter #{k}" if args[k].nil?
|
|
42
|
+
end
|
|
43
|
+
newrole = args[:newrole] || args[:role]
|
|
44
|
+
DH.apps_in_role(args[:role], args[:oldenv]).each do |app|
|
|
45
|
+
puts " * app: #{app} to role #{newrole} (#{args[:newenv]})"
|
|
46
|
+
DH.add_app(app, newrole, args[:newenv])
|
|
47
|
+
end
|
|
31
48
|
end
|
|
32
49
|
end
|
|
33
50
|
|
|
@@ -36,6 +53,6 @@ task :app do
|
|
|
36
53
|
puts "Apps:"
|
|
37
54
|
DH.apps.each do |app|
|
|
38
55
|
info = DH.get_app_data(app)
|
|
39
|
-
puts " * #{app}
|
|
56
|
+
puts " * #{app} #{info.map {|k,v| "#{k}: #{v}"}.join(", ")}"
|
|
40
57
|
end
|
|
41
58
|
end
|
data/tasks/docker.rb
CHANGED
|
@@ -23,17 +23,17 @@ unless File.exists?('/.dockerenv')
|
|
|
23
23
|
|
|
24
24
|
desc "Run tests w/ docker"
|
|
25
25
|
task :test => :build do
|
|
26
|
-
sys(%w(
|
|
26
|
+
sys(%w(docker-compose run --rm gaptool rake test))
|
|
27
27
|
end
|
|
28
28
|
|
|
29
29
|
desc "Stop docker containers"
|
|
30
30
|
task :stop do
|
|
31
|
-
sys(%w(
|
|
31
|
+
sys(%w(docker-compose stop))
|
|
32
32
|
end
|
|
33
33
|
|
|
34
34
|
desc "Start docker containers"
|
|
35
35
|
task :start do
|
|
36
|
-
sys(%w(
|
|
36
|
+
sys(%w(docker-compose start))
|
|
37
37
|
end
|
|
38
38
|
|
|
39
39
|
desc "Restart docker containers"
|
|
@@ -41,19 +41,19 @@ unless File.exists?('/.dockerenv')
|
|
|
41
41
|
|
|
42
42
|
desc "Stop and remove docker containers (alias 'rm')"
|
|
43
43
|
task :remove => :stop do
|
|
44
|
-
sys(%w(
|
|
44
|
+
sys(%w(docker-compose rm --force))
|
|
45
45
|
end
|
|
46
46
|
|
|
47
47
|
task :rm => :remove
|
|
48
48
|
|
|
49
49
|
desc "Recreate docker containers without building"
|
|
50
50
|
task :recreate do
|
|
51
|
-
sys(%w(
|
|
51
|
+
sys(%w(docker-compose up -d))
|
|
52
52
|
end
|
|
53
53
|
|
|
54
54
|
desc "Run a command in the docker container"
|
|
55
55
|
task :run do
|
|
56
|
-
exit sys(%W(
|
|
56
|
+
exit sys(%W(docker-compose run --rm gaptool #{ARGV[1..-1].shelljoin}))
|
|
57
57
|
end
|
|
58
58
|
end
|
|
59
59
|
|
data/tasks/ec2.rb
CHANGED
data/tasks/role.rb
CHANGED
|
@@ -2,7 +2,7 @@ namespace :role do
|
|
|
2
2
|
desc "Set security group for a role"
|
|
3
3
|
task :set_sg, [:role, :environment, :security_group] do |t, args|
|
|
4
4
|
abort("Missing parameters") if args[:role].nil? || args[:environment].nil? || args[:role].empty? || args[:environment].empty? || args[:security_group].nil? || args[:security_group].empty?
|
|
5
|
-
role = DH.get_role_data(args[:role])
|
|
5
|
+
role = DH.get_role_data(args[:role], args[:environment])
|
|
6
6
|
role['sg'].merge!(args[:environment] => args[:security_group])
|
|
7
7
|
DH.save_role_data(args[:role], role)
|
|
8
8
|
end
|
data/test/api_test.rb
CHANGED
|
@@ -16,6 +16,7 @@ describe "Test API" do
|
|
|
16
16
|
header 'X_GAPTOOL_KEY', 'test'
|
|
17
17
|
$redis.flushall
|
|
18
18
|
DH.useradd('test', 'test')
|
|
19
|
+
$time = Time.now
|
|
19
20
|
end
|
|
20
21
|
|
|
21
22
|
def add_and_register_server data=nil
|
|
@@ -45,7 +46,8 @@ describe "Test API" do
|
|
|
45
46
|
'terminable' => true,
|
|
46
47
|
'zone' => 'my-zone-1a',
|
|
47
48
|
'itype' => 'm1.type',
|
|
48
|
-
"hostname" => 'fake.hostname.gild.com'
|
|
49
|
+
"hostname" => 'fake.hostname.gild.com',
|
|
50
|
+
"launch_time" => $time.to_i
|
|
49
51
|
}
|
|
50
52
|
end
|
|
51
53
|
|
|
@@ -67,7 +69,8 @@ describe "Test API" do
|
|
|
67
69
|
it "should create a instance" do
|
|
68
70
|
post '/init', host_data.to_json
|
|
69
71
|
expect(last_response.status).to eq(200)
|
|
70
|
-
expect(JSON.parse(last_response.body).keys).to eq(["instance", "ami", "role", "hostname", "launch_time",
|
|
72
|
+
expect(JSON.parse(last_response.body).keys).to eq(["instance", "ami", "role", "hostname", "launch_time",
|
|
73
|
+
"environment", "secret", "terminable", "security_group"])
|
|
71
74
|
end
|
|
72
75
|
|
|
73
76
|
it "should get the runlist from the role" do
|
|
@@ -96,6 +99,86 @@ describe "Test API" do
|
|
|
96
99
|
expect(resp['security_group']).to eq("#{host_data['role']}-#{host_data['environment']}")
|
|
97
100
|
end
|
|
98
101
|
|
|
102
|
+
it "should set instance unterminable" do
|
|
103
|
+
id = add_and_register_server()['instance']
|
|
104
|
+
|
|
105
|
+
get "/instance/#{id}"
|
|
106
|
+
expect(last_response.status).to eq(200)
|
|
107
|
+
resp = JSON.parse(last_response.body)
|
|
108
|
+
expect(resp.keys).not_to include("terminable")
|
|
109
|
+
|
|
110
|
+
patch "/instance/#{id}", {terminable: false}.to_json
|
|
111
|
+
expect(last_response.status).to eq(200)
|
|
112
|
+
resp = JSON.parse(last_response.body)
|
|
113
|
+
expect(resp['terminable']).to eq(false)
|
|
114
|
+
|
|
115
|
+
get "/instance/#{id}"
|
|
116
|
+
expect(last_response.status).to eq(200)
|
|
117
|
+
resp = JSON.parse(last_response.body)
|
|
118
|
+
expect(resp['terminable']).to eq(false)
|
|
119
|
+
|
|
120
|
+
post '/terminate', {'id' => id}.to_json
|
|
121
|
+
expect(last_response.status).to eq(409)
|
|
122
|
+
|
|
123
|
+
patch "/instance/#{id}", {terminable: true}.to_json
|
|
124
|
+
expect(last_response.status).to eq(200)
|
|
125
|
+
resp = JSON.parse(last_response.body)
|
|
126
|
+
expect(resp['terminable']).to eq(true)
|
|
127
|
+
|
|
128
|
+
post '/terminate', {'id' => id}.to_json
|
|
129
|
+
expect(last_response.status).to eq(200)
|
|
130
|
+
end
|
|
131
|
+
|
|
132
|
+
it "should set an instance as hidden" do
|
|
133
|
+
id = add_and_register_server()['instance']
|
|
134
|
+
|
|
135
|
+
get "/instance/#{id}"
|
|
136
|
+
expect(last_response.status).to eq(200)
|
|
137
|
+
resp = JSON.parse(last_response.body)
|
|
138
|
+
expect(resp.keys).not_to include("hidden")
|
|
139
|
+
|
|
140
|
+
patch "/instance/#{id}", {hidden: false}.to_json
|
|
141
|
+
expect(last_response.status).to eq(200)
|
|
142
|
+
resp = JSON.parse(last_response.body)
|
|
143
|
+
expect(resp.keys).not_to include("hidden")
|
|
144
|
+
|
|
145
|
+
get "/instance/#{id}"
|
|
146
|
+
expect(last_response.status).to eq(200)
|
|
147
|
+
resp = JSON.parse(last_response.body)
|
|
148
|
+
expect(resp.keys).not_to include("hidden")
|
|
149
|
+
|
|
150
|
+
patch "/instance/#{id}", {hidden: true}.to_json
|
|
151
|
+
expect(last_response.status).to eq(200)
|
|
152
|
+
resp = JSON.parse(last_response.body)
|
|
153
|
+
expect(resp['hidden']).to eq(true)
|
|
154
|
+
|
|
155
|
+
get "/instance/#{id}"
|
|
156
|
+
expect(last_response.status).to eq(200)
|
|
157
|
+
resp = JSON.parse(last_response.body)
|
|
158
|
+
expect(resp['hidden']).to eq(true)
|
|
159
|
+
|
|
160
|
+
get "/host/#{host_data['role']}/#{host_data['environment']}/#{id}"
|
|
161
|
+
expect(last_response.status).to eq(200)
|
|
162
|
+
resp = JSON.parse(last_response.body)
|
|
163
|
+
expect(resp['hidden']).to eq(true)
|
|
164
|
+
|
|
165
|
+
get "/hosts"
|
|
166
|
+
expect(last_response.status).to eq(200)
|
|
167
|
+
expect(JSON.parse(last_response.body)).to eq([])
|
|
168
|
+
|
|
169
|
+
get "/hosts/#{host_data['role']}"
|
|
170
|
+
expect(last_response.status).to eq(200)
|
|
171
|
+
expect(JSON.parse(last_response.body)).to eq([])
|
|
172
|
+
|
|
173
|
+
get "/hosts/#{host_data['role']}/#{host_data['environment']}"
|
|
174
|
+
expect(last_response.status).to eq(200)
|
|
175
|
+
expect(JSON.parse(last_response.body)).to eq([])
|
|
176
|
+
|
|
177
|
+
get "/hosts/ALL/#{host_data['environment']}"
|
|
178
|
+
expect(last_response.status).to eq(200)
|
|
179
|
+
expect(JSON.parse(last_response.body)).to eq([])
|
|
180
|
+
end
|
|
181
|
+
|
|
99
182
|
it "should remove default runlist" do
|
|
100
183
|
id = add_and_register_server(host_data.merge("chef_runlist"=> ['recipe[init]']))['instance']
|
|
101
184
|
get "/host/testrole/testenv/#{id}"
|
|
@@ -226,6 +309,30 @@ describe "Test API" do
|
|
|
226
309
|
expect(JSON.parse(last_response.body).to_set).to eq(exp_data)
|
|
227
310
|
end
|
|
228
311
|
|
|
312
|
+
it "should find one hidden host" do
|
|
313
|
+
id1 = add_and_register_server()['instance']
|
|
314
|
+
id2 = add_and_register_server()['instance']
|
|
315
|
+
patch "/instance/#{id1}", {hidden: true}.to_json
|
|
316
|
+
%W(/hosts /hosts/#{host_data['role']} /hosts/#{host_data['role']}/#{host_data['environment']} /hosts/ALL/#{host_data['environment']}).each do |url|
|
|
317
|
+
get url
|
|
318
|
+
expect(last_response.status).to eq(200)
|
|
319
|
+
res = JSON.parse(last_response.body).map{|x| x.delete('apps'); x}.to_set
|
|
320
|
+
exp_data = [host_data.reject{|k,v| k == 'terminable'}.merge({'instance' => id2,
|
|
321
|
+
'chef_runlist' => expanded_runlist})].to_set
|
|
322
|
+
expect(res).to eq(exp_data)
|
|
323
|
+
get url, {hidden: true}
|
|
324
|
+
expect(last_response.status).to eq(200)
|
|
325
|
+
exp_data = [
|
|
326
|
+
host_data.reject{|k,v| k == 'terminable'}.merge({'instance' => id1,
|
|
327
|
+
'chef_runlist' => expanded_runlist,
|
|
328
|
+
'hidden' => true}),
|
|
329
|
+
host_data.reject{|k,v| k == 'terminable'}.merge({'instance' => id2,
|
|
330
|
+
'chef_runlist' => expanded_runlist})
|
|
331
|
+
].to_set
|
|
332
|
+
expect(JSON.parse(last_response.body).map{|x| x.delete('apps'); x}.to_set).to eq(exp_data)
|
|
333
|
+
end
|
|
334
|
+
end
|
|
335
|
+
|
|
229
336
|
it "should find an host by role" do
|
|
230
337
|
other = host_data.merge({'role' => 'otherrole'})
|
|
231
338
|
id1 = add_and_register_server(other)['instance']
|
|
@@ -295,10 +402,10 @@ describe "Test API" do
|
|
|
295
402
|
end
|
|
296
403
|
|
|
297
404
|
it "should return the list of apps" do
|
|
298
|
-
DH.add_app("firstapp", "testrole")
|
|
299
|
-
DH.add_app("secondapp", "testrole")
|
|
300
|
-
apps_list = {"app:firstapp" => {"
|
|
301
|
-
"app:secondapp" =>{"
|
|
405
|
+
DH.add_app("firstapp", "testrole", "testenv")
|
|
406
|
+
DH.add_app("secondapp", "testrole", "testenv")
|
|
407
|
+
apps_list = {"app:firstapp" => {"testenv" => "testrole"},
|
|
408
|
+
"app:secondapp" => {"testenv" => "testrole"}}
|
|
302
409
|
get "/apps"
|
|
303
410
|
expect(last_response.status).to eq(200)
|
|
304
411
|
expect(JSON.parse(last_response.body)).to eq(apps_list)
|
data/test/data_test.rb
CHANGED
|
@@ -105,7 +105,7 @@ describe "data helpers" do
|
|
|
105
105
|
it "should get the runlist for a node from the role" do
|
|
106
106
|
DH.save_role_data("role", chef_runlist: ["recipe[myrecipe]"].to_json)
|
|
107
107
|
DH.addserver(instid, data, nil)
|
|
108
|
-
role = DH.get_role_data("role")
|
|
108
|
+
role = DH.get_role_data("role", "testenv")
|
|
109
109
|
expect(role).to eq({"chef_runlist"=> ["recipe[myrecipe]"].to_json,
|
|
110
110
|
"apps" => [],
|
|
111
111
|
"amis" => {},
|
|
@@ -121,19 +121,19 @@ describe "data helpers" do
|
|
|
121
121
|
it "shoud get the ami for a node from the role" do
|
|
122
122
|
DH.save_role_data("role", ami: 'ami-1234567')
|
|
123
123
|
DH.addserver(instid, data, nil)
|
|
124
|
-
role = DH.get_role_data("role")
|
|
124
|
+
role = DH.get_role_data("role", "testenv")
|
|
125
125
|
expect(role).to eq({'ami' => 'ami-1234567',
|
|
126
126
|
"apps" => [],
|
|
127
127
|
"amis" => {},
|
|
128
128
|
"sg" => {}})
|
|
129
129
|
end
|
|
130
130
|
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
131
|
+
it "shoud get the sg for a node from the role" do
|
|
132
|
+
DH.save_role_data("role", ami: 'ami-1234567', "sg" => {"test" => "my_role"})
|
|
133
|
+
role = DH.get_role_data("role", "testenv")
|
|
134
|
+
expect(role).to eq({'ami' => 'ami-1234567',
|
|
135
|
+
"apps" => [],
|
|
136
|
+
"amis" => {},
|
|
137
|
+
"sg" => {"test" => "my_role"}})
|
|
138
138
|
end
|
|
139
139
|
end
|
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: gaptool-server
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.
|
|
4
|
+
version: 0.7.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Matt Bailey
|
|
@@ -10,7 +10,7 @@ authors:
|
|
|
10
10
|
autorequire:
|
|
11
11
|
bindir: bin
|
|
12
12
|
cert_chain: []
|
|
13
|
-
date: 2015-
|
|
13
|
+
date: 2015-05-31 00:00:00.000000000 Z
|
|
14
14
|
dependencies:
|
|
15
15
|
- !ruby/object:Gem::Dependency
|
|
16
16
|
name: sinatra
|
|
@@ -41,19 +41,19 @@ dependencies:
|
|
|
41
41
|
- !ruby/object:Gem::Version
|
|
42
42
|
version: '1.4'
|
|
43
43
|
- !ruby/object:Gem::Dependency
|
|
44
|
-
name:
|
|
44
|
+
name: puma
|
|
45
45
|
requirement: !ruby/object:Gem::Requirement
|
|
46
46
|
requirements:
|
|
47
47
|
- - "~>"
|
|
48
48
|
- !ruby/object:Gem::Version
|
|
49
|
-
version:
|
|
49
|
+
version: 2.11.1
|
|
50
50
|
type: :runtime
|
|
51
51
|
prerelease: false
|
|
52
52
|
version_requirements: !ruby/object:Gem::Requirement
|
|
53
53
|
requirements:
|
|
54
54
|
- - "~>"
|
|
55
55
|
- !ruby/object:Gem::Version
|
|
56
|
-
version:
|
|
56
|
+
version: 2.11.1
|
|
57
57
|
- !ruby/object:Gem::Dependency
|
|
58
58
|
name: redis
|
|
59
59
|
requirement: !ruby/object:Gem::Requirement
|
|
@@ -180,6 +180,20 @@ dependencies:
|
|
|
180
180
|
- - "~>"
|
|
181
181
|
- !ruby/object:Gem::Version
|
|
182
182
|
version: '1.8'
|
|
183
|
+
- !ruby/object:Gem::Dependency
|
|
184
|
+
name: rake
|
|
185
|
+
requirement: !ruby/object:Gem::Requirement
|
|
186
|
+
requirements:
|
|
187
|
+
- - "~>"
|
|
188
|
+
- !ruby/object:Gem::Version
|
|
189
|
+
version: '10'
|
|
190
|
+
type: :runtime
|
|
191
|
+
prerelease: false
|
|
192
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
193
|
+
requirements:
|
|
194
|
+
- - "~>"
|
|
195
|
+
- !ruby/object:Gem::Version
|
|
196
|
+
version: '10'
|
|
183
197
|
- !ruby/object:Gem::Dependency
|
|
184
198
|
name: rspec
|
|
185
199
|
requirement: !ruby/object:Gem::Requirement
|
|
@@ -241,7 +255,7 @@ email: ops@gild.com
|
|
|
241
255
|
executables:
|
|
242
256
|
- gaptool-server
|
|
243
257
|
- gaptool-shell
|
|
244
|
-
-
|
|
258
|
+
- gaptool_server_migrate_0.6-0.7
|
|
245
259
|
extensions: []
|
|
246
260
|
extra_rdoc_files:
|
|
247
261
|
- LICENSE.txt
|
|
@@ -255,7 +269,7 @@ files:
|
|
|
255
269
|
- VERSION
|
|
256
270
|
- bin/gaptool-server
|
|
257
271
|
- bin/gaptool-shell
|
|
258
|
-
- bin/
|
|
272
|
+
- bin/gaptool_server_migrate_0.6-0.7
|
|
259
273
|
- config.ru
|
|
260
274
|
- lib/app.rb
|
|
261
275
|
- lib/exceptions.rb
|
|
@@ -298,7 +312,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
|
298
312
|
version: '0'
|
|
299
313
|
requirements: []
|
|
300
314
|
rubyforge_project:
|
|
301
|
-
rubygems_version: 2.
|
|
315
|
+
rubygems_version: 2.2.2
|
|
302
316
|
signing_key:
|
|
303
317
|
specification_version: 4
|
|
304
318
|
summary: gaptool-server for managing cloud resources
|
|
@@ -1,18 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env ruby
|
|
2
|
-
#
|
|
3
|
-
# convert the old data model for the gaptool server
|
|
4
|
-
# to the new struct
|
|
5
|
-
|
|
6
|
-
libpath = File.expand_path(File.join(File.dirname(__FILE__), "..", "lib"))
|
|
7
|
-
$:.unshift(libpath)
|
|
8
|
-
require "#{libpath}/helpers/redis"
|
|
9
|
-
require "#{libpath}/helpers/data"
|
|
10
|
-
DH = Gaptool::Data
|
|
11
|
-
|
|
12
|
-
$redis.keys("role:*").each do |k|
|
|
13
|
-
next if k.end_with?('instances') || k.end_with?('apps') || k.end_with?('amis')
|
|
14
|
-
puts "Migrating #{k}"
|
|
15
|
-
sgroup = $redis.hget(k, "security_group")
|
|
16
|
-
$redis.hset("#{k}:sg", "production", sgroup)
|
|
17
|
-
$redis.del(k)
|
|
18
|
-
end
|