gaptool-server 0.6.4 → 0.6.6
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 +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
|