gaptool-server 0.5.19 → 0.6.0.beta1
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/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