gaptool-server 0.5.19 → 0.6.0.beta1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/Gemfile +3 -0
- data/Rakefile +43 -0
- data/VERSION +1 -1
- data/bin/gaptool-server +7 -29
- data/bin/gaptool-shell +12 -0
- data/bin/gaptool_server_migrate_0.5-0.6 +96 -0
- data/config.ru +3 -12
- data/lib/app.rb +27 -10
- data/lib/exceptions.rb +35 -0
- data/lib/helpers/data.rb +257 -0
- data/lib/helpers/ec2.rb +80 -0
- data/lib/helpers/init.rb +2 -4
- data/lib/helpers/redis.rb +19 -0
- data/lib/helpers/rehash.rb +31 -56
- data/lib/routes.rb +172 -0
- data/lib/views/init.erb +6 -8
- data/tasks/app.rb +28 -0
- data/tasks/docker.rb +84 -0
- data/tasks/gem.rb +27 -0
- data/tasks/user.rb +32 -0
- data/test/api_test.rb +256 -0
- data/test/base_test.rb +16 -0
- data/test/data_test.rb +118 -0
- data/test/test_helper.rb +25 -0
- metadata +127 -14
- data/lib/helpers/gaptool-base.rb +0 -38
- data/lib/public/css/common.css +0 -4
- data/lib/routes/init.rb +0 -3
- data/lib/routes/main.rb +0 -206
- data/lib/routes/rehash.rb +0 -6
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: f07c5a5a5853295749abfb9e33430dd54ad1678b
|
4
|
+
data.tar.gz: 1b6082b74ddbe7bcd38efaa24a73b75ecc58f2e5
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 9e86ef3243630f8e5633721d7c69c29471b887285c3156bc6984118f843aa9aff5ebd13bc9d92fedd2c0896500ca9944fff58a3849ab369fd04dd0e15b9c9051
|
7
|
+
data.tar.gz: 44d38d87ccfc61820177391152663335f6a2f2c30ba8d268852ca7d7b2810001e248f5090069482e2c158d031bb07beffb4543858c4eedca4f986450ac39904a
|
data/Gemfile
ADDED
data/Rakefile
ADDED
@@ -0,0 +1,43 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
Dir.chdir(File.dirname(__FILE__))
|
3
|
+
|
4
|
+
require 'shellwords'
|
5
|
+
require 'rspec/core/rake_task'
|
6
|
+
require_relative 'lib/helpers/redis'
|
7
|
+
require_relative 'lib/helpers/init'
|
8
|
+
|
9
|
+
DH = Gaptool::Data
|
10
|
+
$stdout.sync = true
|
11
|
+
|
12
|
+
def sys(cmd)
|
13
|
+
IO.popen(cmd) do |f|
|
14
|
+
until f.eof?
|
15
|
+
puts f.gets
|
16
|
+
end
|
17
|
+
end
|
18
|
+
$?.to_i
|
19
|
+
end
|
20
|
+
|
21
|
+
Dir.glob('tasks/*.rb').each { |r| load r}
|
22
|
+
|
23
|
+
desc "Start the shell"
|
24
|
+
task :shell do
|
25
|
+
exec "racksh #{Shellwords.join(ARGV[1..-1])}"
|
26
|
+
end
|
27
|
+
task :sh => :shell
|
28
|
+
|
29
|
+
desc "Start the HTTP server"
|
30
|
+
task :server do
|
31
|
+
exec "unicorn #{Shellwords.join(ARGV[1..-1])}"
|
32
|
+
end
|
33
|
+
|
34
|
+
task :help do
|
35
|
+
puts "Available tasks"
|
36
|
+
exec "rake -T"
|
37
|
+
end
|
38
|
+
|
39
|
+
RSpec::Core::RakeTask.new :test do |task|
|
40
|
+
task.pattern = Dir['test/*_test.rb']
|
41
|
+
end
|
42
|
+
|
43
|
+
task :default => :help
|
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
0.
|
1
|
+
0.6.0.beta1
|
data/bin/gaptool-server
CHANGED
@@ -1,33 +1,11 @@
|
|
1
1
|
#!/usr/bin/env ruby
|
2
2
|
require 'rubygems'
|
3
|
-
require 'thin'
|
4
|
-
#require 'gaptool-server/app.rb'
|
5
3
|
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
# Default options values
|
13
|
-
@options = {
|
14
|
-
:chdir => File.expand_path('..', File.dirname(__FILE__)),
|
15
|
-
:environment => ENV['RACK_ENV'] || 'development',
|
16
|
-
:address => '0.0.0.0',
|
17
|
-
:port => Server::DEFAULT_PORT,
|
18
|
-
:timeout => Server::DEFAULT_TIMEOUT,
|
19
|
-
:log => 'log/thin.log',
|
20
|
-
:pid => 'tmp/pids/thin.pid',
|
21
|
-
:max_conns => Server::DEFAULT_MAXIMUM_CONNECTIONS,
|
22
|
-
:max_persistent_conns => Server::DEFAULT_MAXIMUM_PERSISTENT_CONNECTIONS,
|
23
|
-
:require => [],
|
24
|
-
:wait => Controllers::Cluster::DEFAULT_WAIT_TIME
|
25
|
-
}
|
26
|
-
|
27
|
-
parse!
|
28
|
-
end
|
29
|
-
end
|
4
|
+
begin
|
5
|
+
require 'gaptool-server'
|
6
|
+
root = Gem.loaded_specs['gaptool-server'].full_gem_path
|
7
|
+
rescue LoadError
|
8
|
+
root = File.realpath(File.join(File.dirname(__FILE__), ".."))
|
30
9
|
end
|
31
|
-
|
32
|
-
|
33
|
-
Thin::GaptoolRunner.new(ARGV).run!
|
10
|
+
Dir.chdir(root)
|
11
|
+
exec "unicorn #{ARGV.join(" ")}"
|
data/bin/gaptool-shell
ADDED
@@ -0,0 +1,12 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
require 'rubygems'
|
3
|
+
|
4
|
+
begin
|
5
|
+
require 'gaptool-server'
|
6
|
+
root = Gem.loaded_specs['gaptool-server'].full_gem_path
|
7
|
+
rescue LoadError
|
8
|
+
root = File.realpath(File.join(File.dirname(__FILE__), ".."))
|
9
|
+
end
|
10
|
+
Dir.chdir(root)
|
11
|
+
|
12
|
+
exec "racksh #{ARGV.join(" ")}"
|
@@ -0,0 +1,96 @@
|
|
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.keys(pattern).each do |key|
|
17
|
+
$redis.del key
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
puts "Migrating roles..."
|
22
|
+
$redis.keys('role:*').each do |key|
|
23
|
+
puts " - #{key}"
|
24
|
+
data = $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.keys('amis:*').each do |key|
|
37
|
+
role = key.sub("amis:", '')
|
38
|
+
puts " - #{key}"
|
39
|
+
amis = $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.del(key)
|
44
|
+
end
|
45
|
+
|
46
|
+
puts "Migrating apps..."
|
47
|
+
$redis.keys('app:*').each do |key|
|
48
|
+
puts " - #{key}"
|
49
|
+
appname = key.sub('app:', '')
|
50
|
+
role = $redis.hget(key, "role")
|
51
|
+
if role.nil? || appname.nil?
|
52
|
+
puts "Missing info for app: #{appname} role: #{role}"
|
53
|
+
end
|
54
|
+
$redis.del(key)
|
55
|
+
DH.add_app(appname, role) unless role.nil?
|
56
|
+
end
|
57
|
+
|
58
|
+
puts "Migrating instances..."
|
59
|
+
$redis.keys('host:*').each do |key|
|
60
|
+
puts " - #{key}"
|
61
|
+
pfx, role, env, iid = key.split(':')
|
62
|
+
data = $redis.hgetall(key)
|
63
|
+
data['role'] = role
|
64
|
+
data['environment'] = env
|
65
|
+
DH.addserver(iid, data, nil)
|
66
|
+
$redis.del(key)
|
67
|
+
# remove stale keys from hsh
|
68
|
+
$redis.hdel "instance:#{iid}", ["capacity", "mirror", "secret", 'instance']
|
69
|
+
end
|
70
|
+
|
71
|
+
puts "Removing unneeded info from instance data..."
|
72
|
+
$redis.smembers('instances').each do |inst|
|
73
|
+
$redis.hdel "instance:#{inst}", ["capacity", "mirror", "secret", "instance"]
|
74
|
+
if $redis.hget("instance:#{inst}", 'chef_runlist') == "recipe[init]"
|
75
|
+
$redis.hdel "instance:#{inst}", "chef_runlist"
|
76
|
+
end
|
77
|
+
term = $redis.hget("instance:#{inst}", "terminate")
|
78
|
+
unless term.nil?
|
79
|
+
unless term == 'true'
|
80
|
+
$redis.hset("instance:#{inst}", "terminable", term)
|
81
|
+
end
|
82
|
+
$redis.hdel("instance:#{inst}", "terminate")
|
83
|
+
end
|
84
|
+
end
|
85
|
+
|
86
|
+
puts "Rename old config keys"
|
87
|
+
$redis.hset('config', 'chef_repo', $redis.hget('config', 'chefrepo'))
|
88
|
+
$redis.hset('config', 'chef_branch', $redis.hget('config', 'chefbranch'))
|
89
|
+
|
90
|
+
puts "Removing old config keys"
|
91
|
+
['remoteredis:host', 'remoteredis:port', 'aws_id', 'aws_secret',
|
92
|
+
'chefrepo', 'chefbranch'].each do |key|
|
93
|
+
$redis.hdel 'config', key
|
94
|
+
end
|
95
|
+
|
96
|
+
$redis.save
|
data/config.ru
CHANGED
@@ -1,19 +1,10 @@
|
|
1
1
|
#!/usr/bin/env ruby
|
2
2
|
|
3
|
-
|
4
|
-
|
5
|
-
ENV['REDIS_HOST'] = 'localhost' unless ENV['REDIS_HOST']
|
6
|
-
ENV['REDIS_PORT'] = '6379' unless ENV['REDIS_PORT']
|
7
|
-
ENV['REDIS_PASS'] = nil unless ENV['REDIS_PASS']
|
8
|
-
ENV['REDIS_DB'] = '0' unless ENV['REDIS_DB']
|
9
|
-
$redis = Redis.new(:host => ENV['REDIS_HOST'],
|
10
|
-
:port => ENV['REDIS_PORT'],
|
11
|
-
:password => ENV['REDIS_PASS'],
|
12
|
-
:db => ENV['REDIS_DB'])
|
3
|
+
ENV['DRYRUN'] = nil unless ENV['DRYRUN'] == 'true'
|
13
4
|
|
14
5
|
libpath = File.expand_path(File.join(File.dirname(__FILE__), "lib"))
|
15
6
|
$:.unshift(libpath)
|
7
|
+
require "#{libpath}/helpers/redis"
|
16
8
|
require "#{libpath}/app.rb"
|
17
9
|
|
18
|
-
|
19
|
-
run instance
|
10
|
+
run GaptoolServer
|
data/lib/app.rb
CHANGED
@@ -1,5 +1,6 @@
|
|
1
1
|
# encoding: utf-8
|
2
2
|
require 'sinatra'
|
3
|
+
require 'sinatra/json'
|
3
4
|
require 'json'
|
4
5
|
require 'yaml'
|
5
6
|
require 'erb'
|
@@ -8,11 +9,30 @@ require 'openssl'
|
|
8
9
|
require 'net/ssh'
|
9
10
|
require 'peach'
|
10
11
|
require 'airbrake'
|
12
|
+
require_relative 'exceptions'
|
11
13
|
|
12
14
|
class GaptoolServer < Sinatra::Application
|
15
|
+
helpers Sinatra::JSON
|
16
|
+
|
17
|
+
def error_response msg=''
|
18
|
+
message = "#{env['sinatra.error'].message}"
|
19
|
+
message = "#{msg} #{message}" unless msg.empty?
|
20
|
+
json result: 'error', message: message
|
21
|
+
end
|
22
|
+
|
23
|
+
error JSON::ParserError do
|
24
|
+
status 400
|
25
|
+
error_response "Invalid data."
|
26
|
+
end
|
27
|
+
|
28
|
+
error HTTPError do
|
29
|
+
status env['sinatra.error'].code
|
30
|
+
error_response
|
31
|
+
end
|
13
32
|
|
14
33
|
error do
|
15
|
-
|
34
|
+
status 500
|
35
|
+
error_response
|
16
36
|
end
|
17
37
|
|
18
38
|
configure do
|
@@ -24,20 +44,17 @@ class GaptoolServer < Sinatra::Application
|
|
24
44
|
end
|
25
45
|
disable :sessions
|
26
46
|
enable :dump_errors
|
47
|
+
disable :show_exceptions
|
27
48
|
end
|
28
49
|
|
29
50
|
before do
|
30
|
-
if request.path_info != '/ping'
|
31
|
-
|
32
|
-
|
51
|
+
if request.path_info != '/ping' && ENV['GAPTOOL_DISABLE_AUTH'].nil?
|
52
|
+
user = Gaptool::Data.user(env['HTTP_X_GAPTOOL_USER'])
|
53
|
+
raise Unauthenticated if user.nil?
|
54
|
+
raise Unauthenticated unless user[:key] == env['HTTP_X_GAPTOOL_KEY']
|
33
55
|
end
|
34
56
|
end
|
35
|
-
|
36
|
-
helpers do
|
37
|
-
include Rack::Utils
|
38
|
-
alias_method :h, :escape_html
|
39
|
-
end
|
40
57
|
end
|
41
58
|
|
42
59
|
require_relative 'helpers/init'
|
43
|
-
require_relative 'routes
|
60
|
+
require_relative 'routes'
|
data/lib/exceptions.rb
ADDED
@@ -0,0 +1,35 @@
|
|
1
|
+
class HTTPError < StandardError
|
2
|
+
@code = 500
|
3
|
+
|
4
|
+
def self.code
|
5
|
+
@code
|
6
|
+
end
|
7
|
+
|
8
|
+
def code
|
9
|
+
self.class.code
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
13
|
+
class ClientError < HTTPError
|
14
|
+
@code = 400
|
15
|
+
end
|
16
|
+
|
17
|
+
class BadRequest < ClientError
|
18
|
+
@code = 400
|
19
|
+
end
|
20
|
+
|
21
|
+
class Unauthenticated < ClientError
|
22
|
+
@code = 401
|
23
|
+
end
|
24
|
+
|
25
|
+
class Forbidden < ClientError
|
26
|
+
@code = 403
|
27
|
+
end
|
28
|
+
|
29
|
+
class NotFound < ClientError
|
30
|
+
@code = 404
|
31
|
+
end
|
32
|
+
|
33
|
+
class Conflict < ClientError
|
34
|
+
@code = 409
|
35
|
+
end
|
data/lib/helpers/data.rb
ADDED
@@ -0,0 +1,257 @@
|
|
1
|
+
require 'json'
|
2
|
+
require 'securerandom'
|
3
|
+
|
4
|
+
module Gaptool
|
5
|
+
module Data
|
6
|
+
|
7
|
+
def self.init_recipe
|
8
|
+
'recipe[init]'
|
9
|
+
end
|
10
|
+
|
11
|
+
def self.default_runlist
|
12
|
+
[init_recipe]
|
13
|
+
end
|
14
|
+
|
15
|
+
def self.addserver(instance, data, secret)
|
16
|
+
role = data['role']
|
17
|
+
environment = data['environment']
|
18
|
+
if role.nil? || environment.nil?
|
19
|
+
raise ArgumentError, "Missing role or environment"
|
20
|
+
end
|
21
|
+
|
22
|
+
if instance.nil? || instance.empty?
|
23
|
+
raise ArgumentError, "Missing instance"
|
24
|
+
end
|
25
|
+
|
26
|
+
$redis.sadd("instances", instance)
|
27
|
+
$redis.sadd("role:#{role}:instances", instance)
|
28
|
+
$redis.sadd("environment:#{environment}:instances", instance)
|
29
|
+
unless secret.nil?
|
30
|
+
data['registered'] = false
|
31
|
+
$redis.sadd('instances:unregistered', instance)
|
32
|
+
$redis.set("instances:secrets:#{data['role']}:#{data['environment']}:#{secret}", instance)
|
33
|
+
data['secret'] = secret
|
34
|
+
end
|
35
|
+
save_server_data instance, data
|
36
|
+
end
|
37
|
+
|
38
|
+
def self.overwrite_hash(key, data)
|
39
|
+
if !key.nil? && !data.nil? && !data.empty?
|
40
|
+
$redis.multi do
|
41
|
+
$redis.del(key)
|
42
|
+
$redis.hmset(key, *data.select{ |k,v| !v.nil? && ((v.is_a?(String) && !v.empty?) || !!v == v)}.flatten)
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
def self.save_server_data(instance, data)
|
48
|
+
|
49
|
+
unless data['chef_runlist'].nil?
|
50
|
+
data['chef_runlist'] = [*data['chef_runlist']]
|
51
|
+
unless data['chef_runlist'].include? init_recipe
|
52
|
+
data['chef_runlist'].unshift(init_recipe)
|
53
|
+
end
|
54
|
+
|
55
|
+
if data['chef_runlist'] == default_runlist
|
56
|
+
data.delete('chef_runlist')
|
57
|
+
else
|
58
|
+
data['chef_runlist'] = data['chef_runlist'].to_json
|
59
|
+
end
|
60
|
+
end
|
61
|
+
overwrite_hash("instance:#{instance}", data)
|
62
|
+
end
|
63
|
+
|
64
|
+
def self.register_server(role, environment, secret)
|
65
|
+
key = "instances:secrets:#{role}:#{environment}:#{secret}"
|
66
|
+
instance = nil
|
67
|
+
$redis.watch(key) do
|
68
|
+
instance = $redis.get(key)
|
69
|
+
if !instance.nil? && !instance.empty?
|
70
|
+
$redis.multi do |m|
|
71
|
+
m.hdel("instance:#{instance}", "secret")
|
72
|
+
m.hdel("instance:#{instance}", "registered")
|
73
|
+
m.srem('instances:unregistered', instance)
|
74
|
+
m.del(key)
|
75
|
+
end
|
76
|
+
else
|
77
|
+
$redis.unwatch
|
78
|
+
instance = nil
|
79
|
+
end
|
80
|
+
end
|
81
|
+
instance
|
82
|
+
end
|
83
|
+
|
84
|
+
def self.rmserver(instance)
|
85
|
+
data = get_server_data instance
|
86
|
+
return if data.nil?
|
87
|
+
$redis.multi do |m|
|
88
|
+
m.srem("instances", instance)
|
89
|
+
m.srem("role:#{data['role']}:instances", instance)
|
90
|
+
m.srem("environment:#{data['environment']}:instances", instance)
|
91
|
+
m.del("instance:#{instance}")
|
92
|
+
end
|
93
|
+
instance
|
94
|
+
end
|
95
|
+
|
96
|
+
def self.get_config(key)
|
97
|
+
$redis.hget('config', key)
|
98
|
+
end
|
99
|
+
|
100
|
+
def self.set_config(key, value)
|
101
|
+
$redis.hset('config', key, value)
|
102
|
+
end
|
103
|
+
|
104
|
+
def self.get_server_data(instance, opts={})
|
105
|
+
rs = $redis.hgetall("instance:#{instance}")
|
106
|
+
return nil if rs.nil? || rs.empty?
|
107
|
+
rs['instance'] = instance
|
108
|
+
if !rs['chef_runlist'].nil? && !rs['chef_runlist'].empty?
|
109
|
+
rs['chef_runlist'] = JSON.parse rs['chef_runlist']
|
110
|
+
else
|
111
|
+
rs['chef_runlist'] = get_runlist_for_role rs['role']
|
112
|
+
end
|
113
|
+
|
114
|
+
%w(chef_repo chef_branch).each do |v|
|
115
|
+
if rs[v].nil? || rs[v].empty?
|
116
|
+
rs[v] = get_config(v)
|
117
|
+
end
|
118
|
+
end
|
119
|
+
|
120
|
+
if opts[:initkey]
|
121
|
+
rs['initkey'] = get_config('initkey')
|
122
|
+
end
|
123
|
+
|
124
|
+
if !rs['terminable'].nil? && rs['terminable'] == "false"
|
125
|
+
rs['terminable'] = false
|
126
|
+
else
|
127
|
+
rs.delete('terminable')
|
128
|
+
end
|
129
|
+
|
130
|
+
if opts[:force_runlist] && rs['chef_runlist'].nil?
|
131
|
+
rs['chef_runlist'] = default_runlist
|
132
|
+
end
|
133
|
+
|
134
|
+
rs['apps'] = apps_in_role(rs['role'])
|
135
|
+
rs.delete_if {|k,v| v.nil? || (!!v != v && v.empty?)}
|
136
|
+
end
|
137
|
+
|
138
|
+
def self.save_role_data(role, data)
|
139
|
+
return if role.nil? || data.nil?
|
140
|
+
if data['amis']
|
141
|
+
amis = data.delete("amis") || {}
|
142
|
+
overwrite_hash("role:#{role}:amis", amis)
|
143
|
+
end
|
144
|
+
if data['apps']
|
145
|
+
apps = data.delete("apps") || []
|
146
|
+
apps.each {|a| add_app(a, role)}
|
147
|
+
end
|
148
|
+
overwrite_hash("role:#{role}", data)
|
149
|
+
$redis.sadd("roles", role)
|
150
|
+
end
|
151
|
+
|
152
|
+
def self.get_role_data(role)
|
153
|
+
res = $redis.hgetall("role:#{role}")
|
154
|
+
res['apps'] = apps_in_role(role)
|
155
|
+
res['amis'] = $redis.hgetall("role:#{role}:amis")
|
156
|
+
res
|
157
|
+
end
|
158
|
+
|
159
|
+
def self.get_ami_for_role(role, region=nil)
|
160
|
+
|
161
|
+
$redis.hget("role:#{role}:amis", region) || $redis.hget("amis", region)
|
162
|
+
end
|
163
|
+
|
164
|
+
def self.get_runlist_for_role(role)
|
165
|
+
rl = $redis.hget("role:#{role}", "chef_runlist")
|
166
|
+
return nil if rl.nil?
|
167
|
+
rl = JSON.parse rl
|
168
|
+
return nil if rl == default_runlist
|
169
|
+
rl
|
170
|
+
end
|
171
|
+
|
172
|
+
def self.set_amis(amis)
|
173
|
+
overwrite_hash("amis", amis)
|
174
|
+
end
|
175
|
+
|
176
|
+
def self.zones
|
177
|
+
$redis.hgetall('amis').keys
|
178
|
+
end
|
179
|
+
|
180
|
+
def self.servers_in_role(role)
|
181
|
+
$redis.smembers("role:#{role}:instances")
|
182
|
+
end
|
183
|
+
|
184
|
+
def self.servers_in_env(env)
|
185
|
+
$redis.smembers("environment:#{env}:instances")
|
186
|
+
end
|
187
|
+
|
188
|
+
def self.servers_in_role_env(role, env)
|
189
|
+
$redis.sinter("role:#{role}:instances", "environment:#{env}:instances")
|
190
|
+
end
|
191
|
+
|
192
|
+
def self.servers
|
193
|
+
$redis.smembers("instances")
|
194
|
+
end
|
195
|
+
|
196
|
+
def self.roles
|
197
|
+
Hash[$redis.smembers("roles").map {|r| [r, get_role_data(r)] }]
|
198
|
+
end
|
199
|
+
|
200
|
+
def self.add_app(name, role)
|
201
|
+
return if name.nil? || role.nil?
|
202
|
+
$redis.multi do
|
203
|
+
$redis.sadd("apps", name)
|
204
|
+
$redis.sadd("role:#{role}:apps", name)
|
205
|
+
$redis.set("app:#{name}", role)
|
206
|
+
end
|
207
|
+
end
|
208
|
+
|
209
|
+
def self.remove_app(name)
|
210
|
+
return if name.nil?
|
211
|
+
key = "app:#{name}"
|
212
|
+
$redis.watch(key) do
|
213
|
+
role = $redis.get(key)
|
214
|
+
if !role.nil?
|
215
|
+
$redis.multi do |m|
|
216
|
+
m.del(key)
|
217
|
+
m.srem("apps", name)
|
218
|
+
m.srem("role:#{role}")
|
219
|
+
end
|
220
|
+
else
|
221
|
+
$redis.unwatch
|
222
|
+
end
|
223
|
+
end
|
224
|
+
end
|
225
|
+
|
226
|
+
def self.get_app_data(app)
|
227
|
+
{"role" => $redis.get("app:#{app}")}
|
228
|
+
end
|
229
|
+
|
230
|
+
def self.apps
|
231
|
+
$redis.smembers("apps")
|
232
|
+
end
|
233
|
+
|
234
|
+
def self.apps_in_role(role)
|
235
|
+
$redis.smembers("role:#{role}:apps")
|
236
|
+
end
|
237
|
+
|
238
|
+
def self.useradd(user, key=nil)
|
239
|
+
key = SecureRandom.hex(64) unless key
|
240
|
+
$redis.hset('users', user, key)
|
241
|
+
{username: user, key: key}
|
242
|
+
end
|
243
|
+
|
244
|
+
def self.userdel(user)
|
245
|
+
$redis.hdel('users', user)
|
246
|
+
end
|
247
|
+
|
248
|
+
def self.users
|
249
|
+
$redis.hgetall('users')
|
250
|
+
end
|
251
|
+
|
252
|
+
def self.user(user)
|
253
|
+
userdesc = {username: user, key: $redis.hget('users', user)}
|
254
|
+
return userdesc[:key].nil? ? nil : userdesc
|
255
|
+
end
|
256
|
+
end
|
257
|
+
end
|
data/lib/helpers/ec2.rb
ADDED
@@ -0,0 +1,80 @@
|
|
1
|
+
require 'securerandom'
|
2
|
+
|
3
|
+
# encoding: utf-8
|
4
|
+
module Gaptool
|
5
|
+
module EC2
|
6
|
+
|
7
|
+
def self.configure_ec2 zone
|
8
|
+
return if ENV['DRYRUN']
|
9
|
+
id = ENV['AWS_ACCESS_KEY_ID']
|
10
|
+
secret = ENV['AWS_SECRET_ACCESS_KEY']
|
11
|
+
AWS.config(access_key_id: id, secret_access_key: secret,
|
12
|
+
ec2_endpoint: "ec2.#{zone}.amazonaws.com")
|
13
|
+
end
|
14
|
+
|
15
|
+
def self.putkey(host)
|
16
|
+
return "FAKEKEY", "FAKEPUB" if ENV['DRYRUN']
|
17
|
+
key = OpenSSL::PKey::RSA.new 2048
|
18
|
+
pubkey = "#{key.ssh_type} #{[key.to_blob].pack('m0')} GAPTOOL_GENERATED_KEY"
|
19
|
+
ENV['SSH_AUTH_SOCK'] = ''
|
20
|
+
Net::SSH.start(host, 'admin',
|
21
|
+
:key_data => [$redis.hget('config', 'gaptoolkey')],
|
22
|
+
:config => false, :keys_only => true,
|
23
|
+
:paranoid => false) do |ssh|
|
24
|
+
ssh.exec! "grep -v GAPTOOL_GENERATED_KEY ~/.ssh/authorized_keys > /tmp/pubkeys"
|
25
|
+
ssh.exec! "echo #{pubkey} >> /tmp/pubkeys"
|
26
|
+
ssh.exec! "mv /tmp/pubkeys ~/.ssh/authorized_keys"
|
27
|
+
end
|
28
|
+
return key.to_pem, pubkey
|
29
|
+
end
|
30
|
+
|
31
|
+
def self.get_or_create_securitygroup(role, environment, zone, groupname=nil)
|
32
|
+
return "sg-test#{SecureRandom.hex(2)}" if ENV['DRYRUN']
|
33
|
+
configure_ec2 zone.chop
|
34
|
+
ec2 = AWS::EC2.new
|
35
|
+
groupname = groupname || "#{role}-#{environment}"
|
36
|
+
ec2.security_groups.each do |group|
|
37
|
+
if group.name == groupname
|
38
|
+
return group.id
|
39
|
+
end
|
40
|
+
end
|
41
|
+
internet = ['0.0.0.0/0']
|
42
|
+
sg = ec2.security_groups.create(groupname)
|
43
|
+
sg.authorize_ingress :tcp, 22, *internet
|
44
|
+
return sg.id
|
45
|
+
end
|
46
|
+
|
47
|
+
def self.create_ec2_instance(ec2opts, data)
|
48
|
+
return "i-test#{SecureRandom.hex(2)}" if ENV['DRYRUN']
|
49
|
+
configure_ec2 data['zone'].chop
|
50
|
+
ec2 = AWS::EC2.new
|
51
|
+
|
52
|
+
instance = ec2.instances.create(opts)
|
53
|
+
instance.add_tag('Name', value: "#{data[:role]}-#{data[:env]}-#{instance.id}")
|
54
|
+
instance.add_tag('gaptool', :value => "yes")
|
55
|
+
instance.id
|
56
|
+
end
|
57
|
+
|
58
|
+
def self.terminate_ec2_instance(zone, id)
|
59
|
+
return if ENV['DRYRUN']
|
60
|
+
configure_ec2 zone
|
61
|
+
ec2 = AWS::EC2.new
|
62
|
+
instance = ec2.instances[id]
|
63
|
+
instance.terminate
|
64
|
+
end
|
65
|
+
|
66
|
+
def self.get_ec2_instance_data(zone, id)
|
67
|
+
if ENV['DRYRUN']
|
68
|
+
return {
|
69
|
+
hostname: 'fake.hostname.gild.com'
|
70
|
+
}
|
71
|
+
end
|
72
|
+
configure_ec2 zone
|
73
|
+
ec2 = AWS::EC2.new
|
74
|
+
instance = ec2.instances[id]
|
75
|
+
return {
|
76
|
+
dns_name: instance.dns_name
|
77
|
+
}
|
78
|
+
end
|
79
|
+
end
|
80
|
+
end
|
data/lib/helpers/init.rb
CHANGED