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.
@@ -0,0 +1,19 @@
1
+ require 'redis'
2
+
3
+ # docker links support
4
+ unless ENV['REDIS_PORT_6379_TCP_ADDR'].nil?
5
+ ENV['REDIS_HOST'] = ENV['REDIS_PORT_6379_TCP_ADDR']
6
+ ENV['REDIS_PORT'] = ENV['REDIS_PORT_6379_TCP_PORT']
7
+ ENV.delete('REDIS_PASS')
8
+ end
9
+
10
+ ENV['REDIS_HOST'] = 'localhost' unless ENV['REDIS_HOST']
11
+ ENV['REDIS_PORT'] = '6379' unless ENV['REDIS_PORT']
12
+ ENV['REDIS_PASS'] = nil unless ENV['REDIS_PASS']
13
+ ENV['REDIS_DB'] = '0' unless ENV['REDIS_DB']
14
+
15
+ $redis = Redis.new(:host => ENV['REDIS_HOST'],
16
+ :port => ENV['REDIS_PORT'].to_i,
17
+ :password => ENV['REDIS_PASS'],
18
+ :db => ENV['REDIS_DB'].to_i)
19
+
@@ -1,63 +1,38 @@
1
- module RehashHelpers
2
- def rehash()
3
- @layout = {}
4
- @roles = []
5
- $redis.keys('app:*').each do |app|
6
- role = $redis.hget(app,'role')
7
- unless role == 'nil'
8
- @roles << role
1
+ module Gaptool
2
+ module EC2
3
+ def self.rehash()
4
+ servers.each do |inst|
5
+ rmserver inst
9
6
  end
10
- end
11
- $redis.keys('host:*').each do |key|
12
- @roles << key.gsub('host:','').gsub(/:.*:i-.*/,'')
13
- end
14
- @roles.uniq!
15
- @roles.each do |role|
16
- apps = []
17
- $redis.keys('app:*').each do |app|
18
- if $redis.hget(app,'role') == role
19
- apps << app.gsub('app:','')
20
- end
21
- end
22
- @layout[role] = apps
23
- end
24
-
25
- $redis.keys("host:*").each do |rediskey|
26
- $redis.del rediskey
27
- end
28
-
29
- $redis.keys("instance:*").each do |rediskey|
30
- $redis.del rediskey
31
- end
32
-
33
- @zones = $redis.hgetall('amis').keys
34
- @zones.each do |zone|
35
- @ec2 = AWS::EC2.new(:access_key_id => $redis.hget('config', 'aws_id'), :secret_access_key => $redis.hget('config', 'aws_secret'), :ec2_endpoint => "ec2.#{zone}.amazonaws.com")
36
- @instances = []
37
- @ec2.instances.each do |instance|
38
- if instance.tags['gaptool'] == 'yes' && instance.status == :running
39
- @instances << instance
7
+ layout = roles()
8
+ puts layout
9
+ zones.each do |zone|
10
+ @ec2 = AWS::EC2.new(:access_key_id => $redis.hget('config', 'aws_id'),
11
+ :secret_access_key => $redis.hget('config', 'aws_secret'),
12
+ :ec2_endpoint => "ec2.#{zone}.amazonaws.com")
13
+ ilist = []
14
+ @ec2.instances.each do |instance|
15
+ if instance.tags['gaptool'] == 'yes' && instance.status == :running
16
+ ilist << instance
17
+ end
40
18
  end
41
- end
42
- @instances.each do |instance|
43
- @name = instance.tags['Name'].split('-')
44
- @rediskey = "host:#{@name[0]}:#{@name[1]}:i-#{@name.last}"
45
- @host = {
46
- "zone"=> instance.availability_zone,
47
- "itype"=> instance.instance_type,
48
- "role"=> @name.first,
49
- "environment"=> @name[1],
50
- "secret"=>"NA",
51
- "capacity"=>"6",
52
- "hostname"=> instance.public_dns_name,
53
- "apps" => @layout[@name[0]].to_s,
54
- "instance"=> instance.instance_id
55
- }
56
- @host.keys.each do |key|
57
- $redis.hset(@rediskey, key, @host[key])
19
+ ilist.each do |instance|
20
+ puts " - #{instance.tags['Name']}"
21
+ role, environment, iid = instance.tags['Name'].split('-')
22
+ data = {
23
+ "zone"=> instance.availability_zone,
24
+ "itype"=> instance.instance_type,
25
+ "role"=> role,
26
+ "environment"=> environment,
27
+ "hostname"=> instance.public_dns_name,
28
+ "apps" => layout[role].to_s,
29
+ "instance"=> instance.instance_id
30
+ }
31
+ puts data
32
+ addserver(data['instance'], data, nil)
58
33
  end
59
34
  end
35
+ return {"action" => "complete"}
60
36
  end
61
- return {"action" => "complete"}
62
37
  end
63
38
  end
data/lib/routes.rb ADDED
@@ -0,0 +1,172 @@
1
+ # encoding: utf-8
2
+ require 'securerandom'
3
+ require 'set'
4
+ require_relative 'exceptions'
5
+ class GaptoolServer < Sinatra::Application
6
+
7
+ def require_parameters(required_keys, data)
8
+ data = data.delete_if { |k,v| v.nil? }
9
+ required_keys = [*required_keys].to_set unless required_keys.is_a? Set
10
+ keys = data.keys.to_set
11
+ unless keys >= required_keys
12
+ raise BadRequest, "Missing required_parameters: #{(required_keys - keys).to_a.join(" ")}"
13
+ end
14
+ data
15
+ end
16
+
17
+ get '/' do
18
+ "You must be lost. Read the instructions."
19
+ end
20
+
21
+ get '/ping' do
22
+ "PONG"
23
+ end
24
+
25
+ post '/init' do
26
+ data = require_parameters(%w(role environment zone itype),
27
+ JSON.parse(request.body.read))
28
+
29
+ secret = SecureRandom.hex(12)
30
+ security_group = data['security_group'] || Gaptool::Data::get_role_data(data['role'])["security_group"]
31
+ sgid = Gaptool::EC2::get_or_create_securitygroup(data['role'], data['environment'], data['zone'], security_group)
32
+ image_id = data['ami'] || Gaptool::Data::get_ami_for_role(data['role'], data['zone'].chop)
33
+ data['terminable'] = data['terminable'].nil? ? true : !!data['terminable']
34
+
35
+ id = Gaptool::EC2::create_ec2_instance(
36
+ {
37
+ :image_id => image_id,
38
+ :availability_zone => data['zone'],
39
+ :instance_type => data['itype'],
40
+ :key_name => "gaptool",
41
+ :security_group_ids => sgid,
42
+ :user_data => "#!/bin/bash\ncurl --silent -H 'X-GAPTOOL-USER: #{env['HTTP_X_GAPTOOL_USER']}' -H 'X-GAPTOOL-KEY: #{env['HTTP_X_GAPTOOL_KEY']}' #{$redis.hget('config', 'url')}/register -X PUT --data '#{data.to_json}' | bash"
43
+ }, {
44
+ role: data['role'],
45
+ env: data['environment'],
46
+ zone: data['zone']
47
+ }
48
+ )
49
+ # Add host tag
50
+ Gaptool::Data::addserver(id, data, secret)
51
+ json({instance: id,
52
+ ami: image_id,
53
+ role: data['role'],
54
+ environment: data['environment'],
55
+ secret: secret,
56
+ terminable: data['terminable'],
57
+ security_group: sgid})
58
+ end
59
+
60
+ post '/terminate' do
61
+ data = require_parameters("id",
62
+ JSON.parse(request.body.read))
63
+ host_data = Gaptool::Data::get_server_data data['id']
64
+ raise NotFound, "No such instance: #{data['id']}" if host_data.nil?
65
+ raise Conflict, "Instance #{data['id']} cannot be terminated" if host_data['terminable'] == false
66
+
67
+ Gaptool::EC2::terminate_ec2_instance(data['zone'], data['id'])
68
+ Gaptool::Data::rmserver(data['id'])
69
+ json data['id'] => {'status' => 'terminated'}
70
+ end
71
+
72
+ put '/register' do
73
+ data = JSON.parse request.body.read
74
+ data = require_parameters(%w(role zone environment secret), data)
75
+ instance_id = Gaptool::Data::register_server data['role'], data['environment'], data['secret']
76
+
77
+ raise Forbidden, "Can't register instance: wrong secret or missing role/environment" unless instance_id
78
+
79
+ hostname = Gaptool::EC2::get_ec2_instance_data(data['zone'].chop, instance_id)[:hostname]
80
+ host_data = Gaptool::Data::get_server_data instance_id, initkey: true, force_runlist: true
81
+
82
+ chef_repo = host_data['chef_repo']
83
+ chef_branch = host_data['chef_branch']
84
+ # FIXME: remove init key from redis
85
+ initkey = host_data['init_key']
86
+ run_list = host_data['chef_runlist'].to_json
87
+
88
+ jdata = {
89
+ 'hostname' => hostname,
90
+ 'recipe' => 'init',
91
+ 'number' => instance_id,
92
+ 'instance' => instance_id,
93
+ 'run_list' => run_list,
94
+ 'role' => data['role'],
95
+ 'environment' => data['environment'],
96
+ 'chefrepo' => chef_repo,
97
+ 'chefbranch' => chef_branch,
98
+ 'identity' => initkey,
99
+ 'appuser' => Gaptool::Data::get_config('appuser'),
100
+ 'apps' => host_data['apps']
101
+ }.to_json
102
+
103
+ erb :init, locals: {
104
+ initkey: initkey,
105
+ chef_branch: chef_branch,
106
+ chef_repo: chef_repo,
107
+ json: jdata
108
+ }
109
+ end
110
+
111
+ get '/hosts' do
112
+ servers = Gaptool::Data::servers.map do |inst|
113
+ Gaptool::Data::get_server_data inst
114
+ end
115
+ json servers
116
+ end
117
+
118
+ get '/apps' do
119
+ out = {}
120
+ Gaptool::Data.apps.each do |app|
121
+ out[app] = Gaptool::Data::get_app_data(app)
122
+ end
123
+ json out
124
+ end
125
+
126
+ get '/hosts/:role' do
127
+ servers = Gaptool::Data::servers_in_role(params[:role]).map do |inst|
128
+ Gaptool::Data::get_server_data inst
129
+ end
130
+ json servers
131
+ end
132
+
133
+ get '/instance/:id' do
134
+ json Gaptool::Data::get_server_data(params[:id])
135
+ end
136
+
137
+ get '/hosts/:role/:environment' do
138
+ if params[:role] == 'ALL'
139
+ list = Gaptool::Data::servers_in_env params[:environment]
140
+ else
141
+ list = Gaptool::Data::servers_in_role_env params[:role], params[:environment]
142
+ end
143
+ servers = list.map do |inst|
144
+ Gaptool::Data::get_server_data inst
145
+ end
146
+
147
+ json servers
148
+ end
149
+
150
+ get '/host/:role/:environment/:instance' do
151
+ json Gaptool::Data::get_server_data params[:instance]
152
+ end
153
+
154
+ get '/ssh/:role/:environment/:instance' do
155
+ data = Gaptool::Data::get_server_data params[:instance]
156
+ host = data['hostname']
157
+ key, pubkey = Gaptool::EC2::putkey(host)
158
+ json hostname: host, key: key, pubkey: pubkey
159
+ end
160
+
161
+ get '/version' do
162
+ version = File.read(File.realpath(
163
+ File.join(File.dirname(__FILE__), "..", 'VERSION')
164
+ )).strip
165
+ json server_version: version, api: {v0: "/"}
166
+ end
167
+
168
+ post '/rehash' do
169
+ json Gaptool::Rehash::rehash()
170
+ end
171
+
172
+ end
data/lib/views/init.erb CHANGED
@@ -1,14 +1,12 @@
1
1
  apt-get update
2
2
  apt-get install -ymq zsh git libssl-dev ruby1.9.1-full build-essential
3
- curl -LO https://www.getchef.com/chef/install.sh
4
- bash install.sh -v <%= @chef_version %>
5
-
3
+ gem install --bindir /usr/local/bin --no-ri --no-rdoc chef
6
4
  cat << 'EOFKEY' > /root/.ssh/id_rsa
7
- <%= @initkey %>
5
+ <%= initkey %>
8
6
  EOFKEY
9
7
  chmod 600 /root/.ssh/id_rsa
10
8
  echo 'StrictHostKeyChecking no' > /root/.ssh/config
11
- git clone -b <%= @chef_branch %> <%= @chef_repo %> /root/ops
12
- echo '<%= @json %>' > /root/init.json
13
- chef-solo -c /root/ops/cookbooks/init.rb -j /root/init.json -E <%= @chef_environment %> && \
14
- (rm /root/.ssh/id_rsa; rm /root/install.sh; userdel -r ubuntu; rm -rf /root/.ssh; rm -rf /root/ops)
9
+ git clone -b <%= chef_branch %> <%= chef_repo %> /root/ops
10
+ echo '<%= json %>' > /root/init.json
11
+ chef-solo -c /root/ops/cookbooks/init.rb -j /root/init.json && \
12
+ (rm /root/.ssh/id_rsa; userdel -r ubuntu; rm -rf /root/.ssh; rm -rf /root/ops)
data/tasks/app.rb ADDED
@@ -0,0 +1,28 @@
1
+ namespace :app do
2
+ desc "Add an application"
3
+ task :add, [:app, :role] do |t, args|
4
+ abort("Missing parameters") if args[:app].nil? || args[:app].empty? || args[:role].nil? || args[:role].empty?
5
+ ex = DH.get_app_data(args[:app])
6
+ unless ex.nil?
7
+ puts "Updating application #{args[:app]}" unless ex.nil?
8
+ DH.remove_app(args[:app])
9
+ end
10
+ DH.add_app(args[:app], args[:role])
11
+ puts "Added app #{args[:app]} in role #{args[:role]}"
12
+ end
13
+
14
+ desc "Remove an application"
15
+ task :delete, [:app] do |t, args|
16
+ DH.remove_app(args[:app])
17
+ puts "Removed app #{args[:app]}"
18
+ end
19
+ end
20
+
21
+ desc "List apps"
22
+ task :app do
23
+ puts "Apps:"
24
+ DH.apps.each do |app|
25
+ info = DH.get_app_data(app)
26
+ puts " * #{app} => #{info["role"]}"
27
+ end
28
+ end
data/tasks/docker.rb ADDED
@@ -0,0 +1,84 @@
1
+ def printimages
2
+ puts %x[docker images | grep '^gild/gaptool']
3
+ end
4
+
5
+ unless File.exists?('/.dockerenv')
6
+ namespace :docker do
7
+ namespace :build do
8
+ task :image do
9
+ sys(%w(./scripts/build_docker_images.sh))
10
+ printimages
11
+ end
12
+
13
+ desc "Build the release image"
14
+ task :release do
15
+ sys(%w(./scripts/build_docker_images.sh -t release))
16
+ printimages
17
+ end
18
+
19
+ task :all => [:image]
20
+ end
21
+
22
+ namespace :push do
23
+ task :release do
24
+ sys(%w(docker push gild/gaptool:release))
25
+ end
26
+
27
+ desc 'Push all tags to the Docker Hub'
28
+ task :all do
29
+ sys(%w(docker push gild/gaptool))
30
+ end
31
+ end
32
+
33
+ desc 'Build the docker image'
34
+ task :build => 'build:image'
35
+
36
+ desc "Push the release image to the Docker Hub"
37
+ task :push => 'push:release'
38
+
39
+ task :up => [:build, :recreate]
40
+
41
+ desc "Run tests w/ docker"
42
+ task :test => :build do
43
+ sys(%w(fig run --rm gaptool rake test))
44
+ end
45
+
46
+ desc "Stop docker containers"
47
+ task :stop do
48
+ sys(%w(fig stop))
49
+ end
50
+
51
+ desc "Start docker containers"
52
+ task :start do
53
+ sys(%w(fig start))
54
+ end
55
+
56
+ desc "Restart docker containers"
57
+ task :restart => [:stop, :start]
58
+
59
+ desc "Stop and remove docker containers (alias 'rm')"
60
+ task :remove => :stop do
61
+ sys(%w(fig rm --force))
62
+ end
63
+
64
+ task :rm => :remove
65
+
66
+ desc "Recreate docker containers without building"
67
+ task :recreate do
68
+ sys(%w(fig up -d))
69
+ end
70
+
71
+ desc "Run a command in the docker container"
72
+ task :run do
73
+ exit sys(%W(fig run --rm gaptool #{ARGV[1..-1].shelljoin}))
74
+ end
75
+
76
+ desc "Run a rake task inside the docker container"
77
+ task :rake do
78
+ exit sys(%W(fig run --rm gaptool rake #{ARGV[1..-1].shelljoin}))
79
+ end
80
+ end
81
+
82
+ desc "Bring up docker containers"
83
+ task :docker => 'docker:up'
84
+ end
data/tasks/gem.rb ADDED
@@ -0,0 +1,27 @@
1
+ namespace :gem do
2
+
3
+ desc "Build the gem"
4
+ task :build => :clean do
5
+ sys(%w(gem build gaptool-server.gemspec))
6
+ end
7
+
8
+ desc "Clean built file"
9
+ task :clean do
10
+ sys(%w(rm -vf *.gem))
11
+ end
12
+
13
+ desc "Bump the version"
14
+ task :bump do
15
+ version = File.read('VERSION').strip
16
+ nver = version.next
17
+ f = File.open('VERSION', 'w')
18
+ f.write(nver)
19
+ f.close
20
+ puts "Bumped #{version} => #{nver}"
21
+ end
22
+
23
+ desc "Push"
24
+ task :push => :build do
25
+ sys(%w(gem push gaptool-server*.gem))
26
+ end
27
+ end
data/tasks/user.rb ADDED
@@ -0,0 +1,32 @@
1
+ namespace :user do
2
+ desc "Add a new user. rake user:create <username>"
3
+ task :create, [:username] do |t, args|
4
+ puts DH.useradd(args[:username])[:key]
5
+ end
6
+
7
+ desc "Rename a user. rake user:rename <oldname> <newname>"
8
+ task :rename, [:oldname, :newname] do |t, args|
9
+ user = DH.user(args[:oldname])
10
+ abort("Unknown user #{args[:oldname]}") if user.nil?
11
+ DH.userdel(user[:username])
12
+ DH.useradd(args[:newname], user[:key])
13
+ puts "User #{args[:oldname]} renamed to #{args[:newname]}"
14
+ end
15
+
16
+ desc "Delete a user. rake user:delete <username>"
17
+ task :delete, [:username] do |t, args|
18
+ DH.userdel(args[:username])
19
+ end
20
+
21
+ desc "Set user key. rake user:setkey <username> <key>"
22
+ task :setkey, [:username, :key] do |t, args|
23
+ user = DH.user(args[:username])
24
+ abort("Unknown user #{args[:username]}") if user.nil?
25
+ puts DH.useradd(args[:username], args[:key])
26
+ end
27
+ end
28
+
29
+ desc "List users"
30
+ task :user do
31
+ puts DH.users.keys.sort.join("\n")
32
+ end