gaptool-server 0.6.4 → 0.6.6
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/Rakefile +2 -0
- data/VERSION +1 -1
- data/bin/gaptool_migrate_security_groups +18 -0
- data/lib/app.rb +11 -5
- data/lib/exceptions.rb +0 -4
- data/lib/helpers/data.rb +17 -3
- data/lib/helpers/ec2.rb +61 -7
- data/lib/helpers/rehash.rb +44 -1
- data/lib/routes.rb +29 -4
- data/tasks/ec2.rb +44 -0
- data/tasks/role.rb +9 -0
- data/tasks/server.rb +9 -0
- data/test/api_test.rb +37 -7
- data/test/data_test.rb +23 -7
- data/test/test_helper.rb +2 -1
- metadata +20 -4
- data/bin/gaptool_server_migrate_0.5-0.6 +0 -113
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 6323ce0f24d59f15f894675c6cf76724f5b8ace1
|
4
|
+
data.tar.gz: 4af7e863c6b3527d54ff458fa29cdaebf09583eb
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 8bb6202e2fc26965a53acad59625830ea198cd7c930414d005b4977291a49c1a79823e5a29ad00c8c97ed68f0a979ab047f93d5933203455f199138d29f7a1b0
|
7
|
+
data.tar.gz: 97cdc9abf27d57332ef261dac8b7919bd732102362d6b5a79bf70b26df9870ab4e1c8911edfe8c2c59a3cf050036f1a9f77477a355988f6f82a2cc82f25fcc31
|
data/Rakefile
CHANGED
@@ -4,10 +4,12 @@ Dir.chdir(File.dirname(__FILE__))
|
|
4
4
|
require 'shellwords'
|
5
5
|
require 'rspec/core/rake_task'
|
6
6
|
require_relative 'lib/helpers/redis'
|
7
|
+
require_relative 'lib/helpers/ec2'
|
7
8
|
require_relative 'lib/helpers/init'
|
8
9
|
require_relative 'lib/helpers/rehash'
|
9
10
|
|
10
11
|
DH = Gaptool::Data
|
12
|
+
EC2 = Gaptool::EC2
|
11
13
|
$stdout.sync = true
|
12
14
|
|
13
15
|
def sys(cmd)
|
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
0.6.
|
1
|
+
0.6.6
|
@@ -0,0 +1,18 @@
|
|
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
|
data/lib/app.rb
CHANGED
@@ -9,14 +9,16 @@ require 'openssl'
|
|
9
9
|
require 'net/ssh'
|
10
10
|
require 'peach'
|
11
11
|
require 'airbrake'
|
12
|
+
require 'logger'
|
12
13
|
require_relative 'exceptions'
|
13
14
|
|
14
15
|
class GaptoolServer < Sinatra::Application
|
15
16
|
helpers Sinatra::JSON
|
17
|
+
use Airbrake::Sinatra
|
16
18
|
|
17
19
|
def error_response msg=''
|
18
|
-
message = "#{env['sinatra.error'].message}"
|
19
|
-
message = "#{msg}
|
20
|
+
message = env['sinatra_error'].nil? ? "" : " #{env['sinatra.error'].message}"
|
21
|
+
message = "#{msg}#{message}" unless msg.empty?
|
20
22
|
json result: 'error', message: message
|
21
23
|
end
|
22
24
|
|
@@ -30,6 +32,10 @@ class GaptoolServer < Sinatra::Application
|
|
30
32
|
error_response
|
31
33
|
end
|
32
34
|
|
35
|
+
def unauthenticated
|
36
|
+
halt(401, error_response("Unauthenticated"))
|
37
|
+
end
|
38
|
+
|
33
39
|
error do
|
34
40
|
status 500
|
35
41
|
error_response
|
@@ -39,8 +45,8 @@ class GaptoolServer < Sinatra::Application
|
|
39
45
|
unless ENV['AIRBRAKE_API_KEY'].nil?
|
40
46
|
Airbrake.configure do |cfg|
|
41
47
|
cfg.api_key = ENV['AIRBRAKE_API_KEY']
|
48
|
+
cfg.logger = Logger.new(STDOUT)
|
42
49
|
end
|
43
|
-
use Airbrake::Sinatra
|
44
50
|
end
|
45
51
|
disable :sessions
|
46
52
|
enable :dump_errors
|
@@ -50,8 +56,8 @@ class GaptoolServer < Sinatra::Application
|
|
50
56
|
before do
|
51
57
|
if request.path_info != '/ping' && ENV['GAPTOOL_DISABLE_AUTH'].nil?
|
52
58
|
user = Gaptool::Data.user(env['HTTP_X_GAPTOOL_USER'])
|
53
|
-
|
54
|
-
|
59
|
+
return unauthenticated if user.nil?
|
60
|
+
return unauthenticated unless user[:key] == env['HTTP_X_GAPTOOL_KEY']
|
55
61
|
end
|
56
62
|
end
|
57
63
|
|
data/lib/exceptions.rb
CHANGED
data/lib/helpers/data.rb
CHANGED
@@ -49,6 +49,11 @@ module Gaptool
|
|
49
49
|
$redis.hset("instance:#{instance}", attr, value)
|
50
50
|
end
|
51
51
|
|
52
|
+
def self.set_server_data_attributes(instance, attrs)
|
53
|
+
return if attrs.values.any? {|v| v.nil? || (v.is_a?(String) && v.empty?) || !!v == v}
|
54
|
+
$redis.hmset("instance:#{instance}", *attrs.flatten)
|
55
|
+
end
|
56
|
+
|
52
57
|
def self.save_server_data(instance, data)
|
53
58
|
|
54
59
|
unless data['chef_runlist'].nil?
|
@@ -151,8 +156,9 @@ module Gaptool
|
|
151
156
|
rs['chef_runlist'] = default_runlist
|
152
157
|
end
|
153
158
|
|
154
|
-
rs['apps'] = apps_in_role(rs['role'])
|
155
159
|
rs.delete_if {|k,v| v.nil? || (!!v != v && v.empty?)}
|
160
|
+
rs['apps'] = apps_in_role(rs['role'])
|
161
|
+
rs
|
156
162
|
end
|
157
163
|
|
158
164
|
def self.save_role_data(role, data)
|
@@ -161,6 +167,10 @@ module Gaptool
|
|
161
167
|
amis = data.delete("amis") || {}
|
162
168
|
overwrite_hash("role:#{role}:amis", amis)
|
163
169
|
end
|
170
|
+
if data['sg']
|
171
|
+
sgs = data.delete("sg") || {}
|
172
|
+
overwrite_hash("role:#{role}:sg", sgs)
|
173
|
+
end
|
164
174
|
if data['apps']
|
165
175
|
apps = data.delete("apps") || []
|
166
176
|
apps.each {|a| add_app(a, role)}
|
@@ -173,14 +183,18 @@ module Gaptool
|
|
173
183
|
res = $redis.hgetall("role:#{role}")
|
174
184
|
res['apps'] = apps_in_role(role)
|
175
185
|
res['amis'] = $redis.hgetall("role:#{role}:amis")
|
186
|
+
res['sg'] = $redis.hgetall("role:#{role}:sg")
|
176
187
|
res
|
177
188
|
end
|
178
189
|
|
179
190
|
def self.get_ami_for_role(role, region=nil)
|
180
|
-
|
181
191
|
$redis.hget("role:#{role}:amis", region) || $redis.hget("amis", region)
|
182
192
|
end
|
183
193
|
|
194
|
+
def self.get_sg_for_role(role, environment)
|
195
|
+
$redis.hget("role:#{role}:sg", environment) || "#{role}-#{environment}"
|
196
|
+
end
|
197
|
+
|
184
198
|
def self.get_runlist_for_role(role)
|
185
199
|
rl = $redis.hget("role:#{role}", "chef_runlist")
|
186
200
|
return nil if rl.nil?
|
@@ -257,7 +271,7 @@ module Gaptool
|
|
257
271
|
end
|
258
272
|
|
259
273
|
def self.stringify_apps(rs)
|
260
|
-
|
274
|
+
if !rs.nil? && !rs['apps'].nil?
|
261
275
|
rs['apps'] = rs['apps'].to_json
|
262
276
|
end
|
263
277
|
rs
|
data/lib/helpers/ec2.rb
CHANGED
@@ -1,9 +1,12 @@
|
|
1
1
|
require 'aws-sdk'
|
2
2
|
require 'securerandom'
|
3
|
+
require 'logger'
|
4
|
+
require 'airbrake'
|
3
5
|
|
4
6
|
# encoding: utf-8
|
5
7
|
module Gaptool
|
6
8
|
module EC2
|
9
|
+
@@logger = Logger.new(STDERR)
|
7
10
|
|
8
11
|
def self.configure_ec2 zone
|
9
12
|
return if ENV['DRYRUN']
|
@@ -45,28 +48,79 @@ module Gaptool
|
|
45
48
|
return sg.id
|
46
49
|
end
|
47
50
|
|
48
|
-
def self.create_ec2_instance(ec2opts, data)
|
51
|
+
def self.create_ec2_instance(ec2opts, data, retries=3, sleeptime=0.5)
|
49
52
|
if ENV['DRYRUN']
|
50
53
|
id = "i-test#{SecureRandom.hex(2)}"
|
51
54
|
return {id: id,
|
52
55
|
hostname: "test-#{id}.#{data[:zone].chop}.compute.amazonaws.com",
|
56
|
+
instance: nil,
|
53
57
|
launch_time: Time.now.to_s}
|
54
58
|
end
|
55
59
|
configure_ec2 data[:zone].chop
|
56
60
|
ec2 = AWS::EC2.new
|
57
61
|
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
62
|
+
i = 0
|
63
|
+
begin
|
64
|
+
instance = ec2.instances.create(ec2opts)
|
65
|
+
@@logger.debug("Spawned instance #{instance.id}")
|
66
|
+
rescue => e
|
67
|
+
i += 1
|
68
|
+
raise if i > retries
|
69
|
+
@@logger.error("Error while creating instance: #{e}: sleeping #{sleeptime}s and retrying (#{i}/#{retries})")
|
70
|
+
sleep sleeptime
|
71
|
+
retry
|
72
|
+
end
|
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
|
+
i = 0
|
82
|
+
begin
|
83
|
+
hostname = instance.public_dns_name
|
84
|
+
rescue => e
|
85
|
+
i += 1
|
86
|
+
if i > retries
|
87
|
+
@@logger.error("Could not get hostname for instance #{instance} after #{retries} retries, setting to nil")
|
88
|
+
hostname = nil
|
89
|
+
Airbrake.notify_or_ignore(
|
90
|
+
e,
|
91
|
+
error_class: "EC2 public dns fail",
|
92
|
+
parameters: {instance: instance[:id], role: data['role'], environment: data['environment'], hostname: nil}
|
93
|
+
)
|
94
|
+
else
|
95
|
+
@@logger.error("Error getting hostname for instance: #{e}: sleeping #{sleeptime}s and retrying (#{i}/#{retries})")
|
96
|
+
sleep sleeptime
|
97
|
+
retry
|
98
|
+
end
|
99
|
+
end
|
63
100
|
{
|
64
101
|
id: instance.id,
|
65
|
-
|
102
|
+
instance: instance,
|
103
|
+
hostname: hostname,
|
66
104
|
launch_time: launch_time
|
67
105
|
}
|
68
106
|
end
|
69
107
|
|
108
|
+
def self.tag_ec2_instance(instance, key, value, retries=5, sleeptime=0.5)
|
109
|
+
return true if ENV['DRYRUN']
|
110
|
+
i = 0
|
111
|
+
begin
|
112
|
+
instance.add_tag(key, value: value)
|
113
|
+
@@logger.debug("Added tag #{key}=#{value} to #{instance.id}")
|
114
|
+
true
|
115
|
+
rescue => e
|
116
|
+
i += 1
|
117
|
+
raise if i > retries
|
118
|
+
@@logger.error("Error adding tag #{key} to #{instance.id}: #{e}: sleeping #{sleeptime}s and retrying (#{i}/#{retries})")
|
119
|
+
sleep sleeptime
|
120
|
+
retry
|
121
|
+
end
|
122
|
+
end
|
123
|
+
|
70
124
|
def self.terminate_ec2_instance(zone, id)
|
71
125
|
return if ENV['DRYRUN']
|
72
126
|
configure_ec2 zone
|
data/lib/helpers/rehash.rb
CHANGED
@@ -1,5 +1,6 @@
|
|
1
1
|
require_relative "ec2"
|
2
2
|
require_relative "data"
|
3
|
+
require "logger"
|
3
4
|
|
4
5
|
module Gaptool
|
5
6
|
module EC2
|
@@ -27,12 +28,54 @@ module Gaptool
|
|
27
28
|
"hostname" => instance.public_dns_name,
|
28
29
|
"launch_time" => instance.launch_time.to_s,
|
29
30
|
"apps" => roles[role].to_s,
|
30
|
-
"instance"=> instance.instance_id
|
31
|
+
"instance"=> instance.instance_id,
|
32
|
+
"security_group" => instance.security_groups[0].name
|
31
33
|
}
|
32
34
|
Gaptool::Data::addserver(iid, data, nil)
|
33
35
|
end
|
34
36
|
end
|
35
37
|
return {"action" => "complete"}
|
36
38
|
end
|
39
|
+
|
40
|
+
def self.rehash_property(property)
|
41
|
+
Gaptool::Data::servers.each do |id|
|
42
|
+
rehash_property_for_instance(property, id)
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
def self.rehash_properties_for_instance(instance_id)
|
47
|
+
res = {}
|
48
|
+
%w[hostname itype security_group].each do |property|
|
49
|
+
res[property] = self.rehash_property_for_instance(property, instance_id, false)
|
50
|
+
end
|
51
|
+
Gaptool::set_server_data_attributes(instance_id, res)
|
52
|
+
end
|
53
|
+
|
54
|
+
def self.rehash_property_for_instance(property, instance_id, save=true)
|
55
|
+
logger = Logger.new(STDOUT)
|
56
|
+
data = Gaptool::Data.get_server_data(instance_id)
|
57
|
+
return false if data.nil? || data['zone'].nil? || data['zone'].empty?
|
58
|
+
Gaptool::EC2::configure_ec2 data['zone'].chop
|
59
|
+
ec2 = AWS::EC2.new(region: data['zone'].chop)
|
60
|
+
logger.info("Updating #{property} for #{instance_id} in zone #{data['zone'].chop}")
|
61
|
+
instance = ec2.instances[instance_id]
|
62
|
+
return false if instance.nil?
|
63
|
+
case property
|
64
|
+
when "hostname"
|
65
|
+
value = instance.public_dns_name
|
66
|
+
when "itype"
|
67
|
+
value = instance.instance_type
|
68
|
+
when "security_group"
|
69
|
+
value = instance.security_groups[0].name
|
70
|
+
else
|
71
|
+
return false
|
72
|
+
end
|
73
|
+
if save
|
74
|
+
logger.info("Setting #{property} to #{value} for #{instance_id}")
|
75
|
+
Gaptool::Data.set_server_data_attr(instance_id, property, value)
|
76
|
+
else
|
77
|
+
value
|
78
|
+
end
|
79
|
+
end
|
37
80
|
end
|
38
81
|
end
|
data/lib/routes.rb
CHANGED
@@ -2,6 +2,7 @@
|
|
2
2
|
require 'securerandom'
|
3
3
|
require 'set'
|
4
4
|
require_relative 'exceptions'
|
5
|
+
|
5
6
|
class GaptoolServer < Sinatra::Application
|
6
7
|
|
7
8
|
def require_parameters(required_keys, data)
|
@@ -27,8 +28,8 @@ class GaptoolServer < Sinatra::Application
|
|
27
28
|
JSON.parse(request.body.read))
|
28
29
|
|
29
30
|
secret = SecureRandom.hex(12)
|
30
|
-
security_group = data['security_group'] || Gaptool::Data::
|
31
|
-
sgid = Gaptool::EC2::get_or_create_securitygroup(data['role'], data['environment'], data['zone'], security_group)
|
31
|
+
data['security_group'] = data['security_group'] || Gaptool::Data::get_sg_for_role(data['role'], data['environment'])
|
32
|
+
sgid = Gaptool::EC2::get_or_create_securitygroup(data['role'], data['environment'], data['zone'], data['security_group'])
|
32
33
|
image_id = data['ami'] || Gaptool::Data::get_ami_for_role(data['role'], data['zone'].chop)
|
33
34
|
data['terminable'] = data['terminable'].nil? ? true : !!data['terminable']
|
34
35
|
data['secret'] = secret
|
@@ -47,8 +48,26 @@ class GaptoolServer < Sinatra::Application
|
|
47
48
|
zone: data['zone']
|
48
49
|
}
|
49
50
|
)
|
51
|
+
|
52
|
+
# Tag instance
|
53
|
+
role = data['role']
|
54
|
+
env = data['environment']
|
55
|
+
name = "#{role}-#{env}-#{instance[:id]}"
|
56
|
+
{'Name' => name, 'gaptool' => 'yes', 'role' => role, 'environment' => env}.each do |tag, value|
|
57
|
+
begin
|
58
|
+
Gaptool::EC2::tag_ec2_instance(instance[:instance], tag, value)
|
59
|
+
rescue => e
|
60
|
+
logger.error("Error while tagging: #{e}. Skipping tag")
|
61
|
+
Airbrake.notify_or_ignore(
|
62
|
+
e,
|
63
|
+
error_class: "EC2 Tag failed",
|
64
|
+
parameters: {instance: instance[:id], name: name, role: role, environment: env}
|
65
|
+
)
|
66
|
+
end
|
67
|
+
end
|
68
|
+
|
50
69
|
# Add host tag
|
51
|
-
data.merge(instance.reject { |k, v|
|
70
|
+
data.merge(instance.reject { |k, v| [:id, :instance].include?(k) })
|
52
71
|
Gaptool::Data::addserver(instance[:id], data, secret)
|
53
72
|
json({instance: instance[:id],
|
54
73
|
ami: image_id,
|
@@ -139,7 +158,13 @@ class GaptoolServer < Sinatra::Application
|
|
139
158
|
end
|
140
159
|
|
141
160
|
get '/instance/:id' do
|
142
|
-
|
161
|
+
rs = Gaptool::Data::get_server_data(params[:id])
|
162
|
+
if rs.nil?
|
163
|
+
status 404
|
164
|
+
error_response "instance with id '#{params[:id]}' not found"
|
165
|
+
else
|
166
|
+
json Gaptool::Data::stringify_apps(rs)
|
167
|
+
end
|
143
168
|
end
|
144
169
|
|
145
170
|
get '/hosts/:role/:environment' do
|
data/tasks/ec2.rb
ADDED
@@ -0,0 +1,44 @@
|
|
1
|
+
namespace :ec2 do
|
2
|
+
desc "Rehash instances"
|
3
|
+
task :rehash do |t|
|
4
|
+
EC2.rehash
|
5
|
+
end
|
6
|
+
|
7
|
+
desc "Rehash single attribute of all instances"
|
8
|
+
task :rehash_attr_all, [:property] do |t, args|
|
9
|
+
if args[:property].nil?
|
10
|
+
puts "Missing property"
|
11
|
+
return 1
|
12
|
+
end
|
13
|
+
EC2.rehash_property(args[:property])
|
14
|
+
end
|
15
|
+
|
16
|
+
desc "Rehash ec2 attributes for a single instance"
|
17
|
+
task :rehash_attrs_for, [:instance] do |t, args|
|
18
|
+
if args[:instance].nil?
|
19
|
+
puts "Missing instance"
|
20
|
+
return 1
|
21
|
+
end
|
22
|
+
res = EC2.rehash_properties_for_instance(args[:instance])
|
23
|
+
return 1 unless res
|
24
|
+
end
|
25
|
+
|
26
|
+
desc "Rehash a single property for an instance"
|
27
|
+
task :rehash_attr_for, [:instance, :property] do |t, args|
|
28
|
+
if args[:instance].nil?
|
29
|
+
puts "Missing instance"
|
30
|
+
return 1
|
31
|
+
end
|
32
|
+
if args[:property].nil?
|
33
|
+
puts "Missing property"
|
34
|
+
return 1
|
35
|
+
end
|
36
|
+
res = EC2.rehash_property_for_instance(args[:property], args[:instance])
|
37
|
+
if res
|
38
|
+
puts "#{property} for instance #{instance} set to '#{res}'"
|
39
|
+
else
|
40
|
+
return 1
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
end
|
data/tasks/role.rb
ADDED
@@ -0,0 +1,9 @@
|
|
1
|
+
namespace :role do
|
2
|
+
desc "Set security group for a role"
|
3
|
+
task :set_sg, [:role, :environment, :security_group] do |t, args|
|
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])
|
6
|
+
role['sg'].merge!(args[:environment] => args[:security_group])
|
7
|
+
DH.save_role_data(args[:role], role)
|
8
|
+
end
|
9
|
+
end
|
data/tasks/server.rb
CHANGED
@@ -8,4 +8,13 @@ namespace :server do
|
|
8
8
|
DH.set_server_data_attr args[:instance], 'terminable', (args[:value] == "true" ? "true" : "false")
|
9
9
|
puts DH.get_server_data args[:instance]
|
10
10
|
end
|
11
|
+
|
12
|
+
desc "Remove a server from the gaptool database (no actions on AWS)"
|
13
|
+
task :rm, [:instance] do |t, args|
|
14
|
+
if args[:instance].nil?
|
15
|
+
puts "You must select an instance"
|
16
|
+
return 1
|
17
|
+
end
|
18
|
+
DH.rmserver(args[:instance])
|
19
|
+
end
|
11
20
|
end
|
data/test/api_test.rb
CHANGED
@@ -79,6 +79,23 @@ describe "Test API" do
|
|
79
79
|
expect(resp['chef_runlist']).to eq(['recipe[other]'])
|
80
80
|
end
|
81
81
|
|
82
|
+
it "should get the security group from the role" do
|
83
|
+
DH.save_role_data(host_data['role'], "sg" => {host_data['environment'] => "mysg-in-role"})
|
84
|
+
id = add_and_register_server(host_data.reject{|k,v| k == 'security_group'})['instance']
|
85
|
+
get "/host/testrole/testenv/#{id}"
|
86
|
+
resp = JSON.parse(last_response.body)
|
87
|
+
expect(resp.keys).to include("security_group")
|
88
|
+
expect(resp['security_group']).to eq("mysg-in-role")
|
89
|
+
end
|
90
|
+
|
91
|
+
it "should get the default security group" do
|
92
|
+
id = add_and_register_server(host_data.reject{|k,v| k == 'security_group'})['instance']
|
93
|
+
get "/host/testrole/testenv/#{id}"
|
94
|
+
resp = JSON.parse(last_response.body)
|
95
|
+
expect(resp.keys).to include("security_group")
|
96
|
+
expect(resp['security_group']).to eq("#{host_data['role']}-#{host_data['environment']}")
|
97
|
+
end
|
98
|
+
|
82
99
|
it "should remove default runlist" do
|
83
100
|
id = add_and_register_server(host_data.merge("chef_runlist"=> ['recipe[init]']))['instance']
|
84
101
|
get "/host/testrole/testenv/#{id}"
|
@@ -93,7 +110,6 @@ describe "Test API" do
|
|
93
110
|
resp = JSON.parse(last_response.body)
|
94
111
|
expect(resp.keys).not_to include("chef_runlist")
|
95
112
|
expect(resp['chef_runlist']).to be(nil)
|
96
|
-
|
97
113
|
end
|
98
114
|
|
99
115
|
it "should get the ami from the role" do
|
@@ -188,7 +204,8 @@ describe "Test API" do
|
|
188
204
|
id = add_and_register_server()['instance']
|
189
205
|
get '/hosts'
|
190
206
|
expect(last_response.status).to eq(200)
|
191
|
-
exp_data = host_data.reject{|k,v| k == 'terminable'}.merge('chef_runlist' => expanded_runlist
|
207
|
+
exp_data = host_data.reject{|k,v| k == 'terminable'}.merge('chef_runlist' => expanded_runlist,
|
208
|
+
'apps'=> [])
|
192
209
|
exp_data['instance'] = id
|
193
210
|
expect(JSON.parse(last_response.body)).to eq([exp_data])
|
194
211
|
end
|
@@ -200,9 +217,11 @@ describe "Test API" do
|
|
200
217
|
expect(last_response.status).to eq(200)
|
201
218
|
exp_data = [
|
202
219
|
host_data.reject{|k,v| k == 'terminable'}.merge({'instance' => id1,
|
203
|
-
'chef_runlist' => expanded_runlist
|
220
|
+
'chef_runlist' => expanded_runlist,
|
221
|
+
'apps' => []}),
|
204
222
|
host_data.reject{|k,v| k == 'terminable'}.merge({'instance' => id2,
|
205
|
-
'chef_runlist' => expanded_runlist
|
223
|
+
'chef_runlist' => expanded_runlist,
|
224
|
+
'apps' => []})
|
206
225
|
].to_set
|
207
226
|
expect(JSON.parse(last_response.body).to_set).to eq(exp_data)
|
208
227
|
end
|
@@ -215,7 +234,8 @@ describe "Test API" do
|
|
215
234
|
get '/hosts/otherrole'
|
216
235
|
expect(last_response.status).to eq(200)
|
217
236
|
exp_data = [other.reject{|k,v| k == 'terminable'}.merge({'instance'=> id1,
|
218
|
-
'chef_runlist' => expanded_runlist
|
237
|
+
'chef_runlist' => expanded_runlist,
|
238
|
+
'apps' => []})]
|
219
239
|
expect(JSON.parse(last_response.body)).to eq(exp_data)
|
220
240
|
end
|
221
241
|
|
@@ -226,11 +246,21 @@ describe "Test API" do
|
|
226
246
|
expect(last_response.status).to eq(200)
|
227
247
|
exp_data = host_data.reject{|k,v| k == 'terminable'}.merge({
|
228
248
|
'instance'=> id,
|
229
|
-
'chef_runlist' => expanded_runlist
|
249
|
+
'chef_runlist' => expanded_runlist,
|
250
|
+
'apps' => "[]"})
|
230
251
|
expect(JSON.parse(last_response.body)).to eq(exp_data)
|
231
252
|
end
|
232
253
|
end
|
233
254
|
|
255
|
+
it "should not find an host by id" do
|
256
|
+
add_and_register_server()['instance']
|
257
|
+
get '/instance/other'
|
258
|
+
expect(last_response.status).to eq(404)
|
259
|
+
expect(JSON.parse(last_response.body)).to eq(
|
260
|
+
{"result" => "error",
|
261
|
+
"message" => "instance with id 'other' not found"})
|
262
|
+
end
|
263
|
+
|
234
264
|
it "should find all hosts by environment and role" do
|
235
265
|
id1 = add_and_register_server()['instance']
|
236
266
|
id2 = add_and_register_server()['instance']
|
@@ -238,7 +268,7 @@ describe "Test API" do
|
|
238
268
|
id4 = add_and_register_server(host_data.merge({'role' => 'otherrole'}))['instance']
|
239
269
|
get '/hosts/testrole/testenv'
|
240
270
|
expect(last_response.status).to eq(200)
|
241
|
-
d = host_data.reject{|k,v| k == 'terminable'}.merge('chef_runlist' => expanded_runlist)
|
271
|
+
d = host_data.reject{|k,v| k == 'terminable'}.merge('chef_runlist' => expanded_runlist, 'apps'=> '[]')
|
242
272
|
exp_data = [
|
243
273
|
d.merge({'instance' => id1}),
|
244
274
|
d.merge({'instance' => id2})
|
data/test/data_test.rb
CHANGED
@@ -36,7 +36,8 @@ describe "data helpers" do
|
|
36
36
|
'chef_repo' => 'myrepo',
|
37
37
|
'chef_branch' => 'master',
|
38
38
|
'registered' => 'false',
|
39
|
-
'secret' => 'secret'
|
39
|
+
'secret' => 'secret',
|
40
|
+
'apps' => []
|
40
41
|
}))
|
41
42
|
end
|
42
43
|
|
@@ -46,7 +47,8 @@ describe "data helpers" do
|
|
46
47
|
expect(server).to eq(data.merge({
|
47
48
|
'instance' => instid,
|
48
49
|
'chef_repo' => 'myrepo',
|
49
|
-
'chef_branch' => 'master'
|
50
|
+
'chef_branch' => 'master',
|
51
|
+
'apps' => []
|
50
52
|
}))
|
51
53
|
end
|
52
54
|
|
@@ -61,7 +63,8 @@ describe "data helpers" do
|
|
61
63
|
expect(server).to eq(data.merge({
|
62
64
|
'instance' => instid,
|
63
65
|
'chef_repo' => 'myrepo',
|
64
|
-
'chef_branch' => 'master'
|
66
|
+
'chef_branch' => 'master',
|
67
|
+
'apps' => []
|
65
68
|
}))
|
66
69
|
end
|
67
70
|
|
@@ -94,7 +97,8 @@ describe "data helpers" do
|
|
94
97
|
'instance' => instid,
|
95
98
|
'chef_repo' => 'myrepo',
|
96
99
|
'chef_branch' => 'master',
|
97
|
-
'initkey' => 'FAKEKEY'
|
100
|
+
'initkey' => 'FAKEKEY',
|
101
|
+
'apps' => []
|
98
102
|
}))
|
99
103
|
end
|
100
104
|
|
@@ -104,12 +108,14 @@ describe "data helpers" do
|
|
104
108
|
role = DH.get_role_data("role")
|
105
109
|
expect(role).to eq({"chef_runlist"=> ["recipe[myrecipe]"].to_json,
|
106
110
|
"apps" => [],
|
107
|
-
"amis" => {}
|
111
|
+
"amis" => {},
|
112
|
+
"sg" => {}})
|
108
113
|
server = DH.get_server_data(instid)
|
109
114
|
expect(server).to eq(data.merge("instance" => instid,
|
110
115
|
"chef_runlist" => ["recipe[myrecipe]"],
|
111
116
|
"chef_repo" => "myrepo",
|
112
|
-
"chef_branch" => "master"
|
117
|
+
"chef_branch" => "master",
|
118
|
+
"apps" => [] ))
|
113
119
|
end
|
114
120
|
|
115
121
|
it "shoud get the ami for a node from the role" do
|
@@ -118,6 +124,16 @@ describe "data helpers" do
|
|
118
124
|
role = DH.get_role_data("role")
|
119
125
|
expect(role).to eq({'ami' => 'ami-1234567',
|
120
126
|
"apps" => [],
|
121
|
-
"amis" => {}
|
127
|
+
"amis" => {},
|
128
|
+
"sg" => {}})
|
129
|
+
end
|
130
|
+
|
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")
|
134
|
+
expect(role).to eq({'ami' => 'ami-1234567',
|
135
|
+
"apps" => [],
|
136
|
+
"amis" => {},
|
137
|
+
"sg" => {"test" => "my_role"}})
|
122
138
|
end
|
123
139
|
end
|
data/test/test_helper.rb
CHANGED
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.6.
|
4
|
+
version: 0.6.6
|
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:
|
13
|
+
date: 2015-01-22 00:00:00.000000000 Z
|
14
14
|
dependencies:
|
15
15
|
- !ruby/object:Gem::Dependency
|
16
16
|
name: sinatra
|
@@ -166,6 +166,20 @@ dependencies:
|
|
166
166
|
- - "~>"
|
167
167
|
- !ruby/object:Gem::Version
|
168
168
|
version: '1.5'
|
169
|
+
- !ruby/object:Gem::Dependency
|
170
|
+
name: json
|
171
|
+
requirement: !ruby/object:Gem::Requirement
|
172
|
+
requirements:
|
173
|
+
- - "~>"
|
174
|
+
- !ruby/object:Gem::Version
|
175
|
+
version: '1.8'
|
176
|
+
type: :runtime
|
177
|
+
prerelease: false
|
178
|
+
version_requirements: !ruby/object:Gem::Requirement
|
179
|
+
requirements:
|
180
|
+
- - "~>"
|
181
|
+
- !ruby/object:Gem::Version
|
182
|
+
version: '1.8'
|
169
183
|
- !ruby/object:Gem::Dependency
|
170
184
|
name: rspec
|
171
185
|
requirement: !ruby/object:Gem::Requirement
|
@@ -227,7 +241,7 @@ email: ops@gild.com
|
|
227
241
|
executables:
|
228
242
|
- gaptool-server
|
229
243
|
- gaptool-shell
|
230
|
-
-
|
244
|
+
- gaptool_migrate_security_groups
|
231
245
|
extensions: []
|
232
246
|
extra_rdoc_files:
|
233
247
|
- LICENSE.txt
|
@@ -241,7 +255,7 @@ files:
|
|
241
255
|
- VERSION
|
242
256
|
- bin/gaptool-server
|
243
257
|
- bin/gaptool-shell
|
244
|
-
- bin/
|
258
|
+
- bin/gaptool_migrate_security_groups
|
245
259
|
- config.ru
|
246
260
|
- lib/app.rb
|
247
261
|
- lib/exceptions.rb
|
@@ -255,7 +269,9 @@ files:
|
|
255
269
|
- tasks/app.rb
|
256
270
|
- tasks/config.rb
|
257
271
|
- tasks/docker.rb
|
272
|
+
- tasks/ec2.rb
|
258
273
|
- tasks/gem.rb
|
274
|
+
- tasks/role.rb
|
259
275
|
- tasks/server.rb
|
260
276
|
- tasks/user.rb
|
261
277
|
- test/api_test.rb
|
@@ -1,113 +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
|
-
puts "Removing cruft"
|
13
|
-
# First, remove cruft. Like all servers created but never registered, etc
|
14
|
-
['instance:*', '_*', 'apikey:*', 'service:*', 'running', 'ec2*',
|
15
|
-
'failover', 'capacity', 'sg:*'].each do |pattern|
|
16
|
-
$redis.redis.keys(pattern).each do |key|
|
17
|
-
$redis.redis.del key
|
18
|
-
end
|
19
|
-
end
|
20
|
-
|
21
|
-
puts "Migrating roles..."
|
22
|
-
$redis.redis.keys('role:*').each do |key|
|
23
|
-
puts " - #{key}"
|
24
|
-
data = $redis.redis.hgetall(key)
|
25
|
-
role = key.sub('role:', '')
|
26
|
-
unless data['ami'].nil?
|
27
|
-
# We didn't have per-regin ami in roles, so
|
28
|
-
# default to us-west-2
|
29
|
-
data['amis'] = {'us-west-2' => data['ami']}
|
30
|
-
role.delete('ami')
|
31
|
-
end
|
32
|
-
DH.save_role_data(role, data)
|
33
|
-
end
|
34
|
-
|
35
|
-
puts "Migrating ami info to role..."
|
36
|
-
$redis.redis.keys('amis:*').each do |key|
|
37
|
-
role = key.sub("amis:", '')
|
38
|
-
puts " - #{key}"
|
39
|
-
amis = $redis.redis.hgetall(key)
|
40
|
-
roledata = DH.get_role_data(role)
|
41
|
-
roledata['amis'] = amis.merge(roledata['amis'] || {})
|
42
|
-
DH.save_role_data(role, roledata)
|
43
|
-
$redis.redis.del(key)
|
44
|
-
end
|
45
|
-
|
46
|
-
puts "Migrating apps..."
|
47
|
-
$redis.redis.keys('app:*').each do |key|
|
48
|
-
puts " - #{key}"
|
49
|
-
appname = key.sub('app:', '')
|
50
|
-
role = $redis.redis.hget(key, "role")
|
51
|
-
if role.nil? || appname.nil?
|
52
|
-
puts "Missing info for app: #{appname} role: #{role}"
|
53
|
-
end
|
54
|
-
$redis.redis.del(key)
|
55
|
-
DH.add_app(appname, role) unless role.nil?
|
56
|
-
end
|
57
|
-
|
58
|
-
puts "Migrating instances..."
|
59
|
-
$redis.redis.keys('host:*').each do |key|
|
60
|
-
puts " - #{key}"
|
61
|
-
pfx, role, env, iid = key.split(':')
|
62
|
-
data = $redis.redis.hgetall(key)
|
63
|
-
data['role'] = role
|
64
|
-
data['environment'] = env
|
65
|
-
unless data['chef_runlist'].nil?
|
66
|
-
data['chef_runlist'] = JSON.parse data['chef_runlist']
|
67
|
-
end
|
68
|
-
DH.addserver(iid, data, nil)
|
69
|
-
$redis.redis.del(key)
|
70
|
-
# remove stale keys from hsh
|
71
|
-
$redis.hdel "instance:#{iid}", ["capacity", "mirror", "secret", 'instance']
|
72
|
-
end
|
73
|
-
|
74
|
-
puts "Removing unneeded info from instance data..."
|
75
|
-
$redis.smembers('instances').each do |inst|
|
76
|
-
$redis.hdel "instance:#{inst}", ["capacity", "mirror", "secret", "instance"]
|
77
|
-
if $redis.hget("instance:#{inst}", 'chef_runlist') == "recipe[init]"
|
78
|
-
$redis.hdel "instance:#{inst}", "chef_runlist"
|
79
|
-
end
|
80
|
-
term = $redis.hget("instance:#{inst}", "terminate")
|
81
|
-
unless term.nil?
|
82
|
-
unless term == 'true'
|
83
|
-
$redis.hset("instance:#{inst}", "terminable", term)
|
84
|
-
end
|
85
|
-
$redis.hdel("instance:#{inst}", "terminate")
|
86
|
-
end
|
87
|
-
end
|
88
|
-
|
89
|
-
puts "Rename old config keys"
|
90
|
-
$redis.redis.rename('config', 'gt:config')
|
91
|
-
$redis.hset('config', 'chef_repo', $redis.hget('config', 'chefrepo'))
|
92
|
-
$redis.hset('config', 'chef_branch', $redis.hget('config', 'chefbranch'))
|
93
|
-
|
94
|
-
puts "Removing old config keys"
|
95
|
-
['remoteredis:host', 'remoteredis:port', 'aws_id', 'aws_secret',
|
96
|
-
'chefrepo', 'chefbranch'].each do |key|
|
97
|
-
$redis.hdel 'config', key
|
98
|
-
end
|
99
|
-
|
100
|
-
unless ARGV[0].nil?
|
101
|
-
puts "Updating GT_URL to #{ARGV[0]}"
|
102
|
-
$redis.hset('config', 'url', ARGV[0])
|
103
|
-
end
|
104
|
-
|
105
|
-
puts "Namespace remaining keys"
|
106
|
-
['users', 'amis'].each { |k| $redis.redis.rename(k, "gt:#{k}")}
|
107
|
-
|
108
|
-
puts "Removing out-of-namespace keys"
|
109
|
-
$redis.redis.keys('*').select { |k| !k.start_with? ('gt:')}.each do |k|
|
110
|
-
$redis.redis.del(k)
|
111
|
-
end
|
112
|
-
|
113
|
-
$redis.save
|