meroku 0.1.36 → 2.0.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -1,82 +0,0 @@
1
-
2
- module Meroku
3
-
4
- class KeysController < ApplicationController
5
- before_action :set_key, only: [:show, :edit, :update, :destroy]
6
- skip_before_action :verify_authenticity_token, only: [:create]
7
- before_action :authenticate, only: [ :create ]
8
-
9
- ## GET /keys
10
- ## GET /keys.json
11
- #def index
12
- # @keys = Meroku::Key.allxb
13
- # render json: { "data": @keys }
14
- #end
15
-
16
- ## GET /keys/1
17
- ## GET /keys/1.json
18
- #def show
19
- #end
20
- #
21
- ## GET /keys/new
22
- #def new
23
- # @key = Key.new
24
- #end
25
- #
26
- ## GET /keys/1/edit
27
- #def edit
28
- #end
29
- #
30
- # POST /keys
31
- # POST /keys.json
32
- def create
33
- @key = Meroku::Key.new(
34
- key: params["key"],
35
- user_id: @user.id
36
- )
37
- respond_to do |format|
38
- if @key.save
39
- format.json { render json: { data: @key } }
40
- else
41
-
42
- format.json { render json: { :errors => @key.errors }, status: :unprocessable_entity }
43
- end
44
- end
45
- end
46
- #
47
- ## PATCH/PUT /keys/1
48
- ## PATCH/PUT /keys/1.json
49
- #def update
50
- # respond_to do |format|
51
- # if @key.update(key_params)
52
- # format.html { redirect_to @key, notice: 'Key was successfully updated.' }
53
- # format.json { render :show, status: :ok, location: @key }
54
- # else
55
- # format.html { render :edit }
56
- # format.json { render json: @key.errors, status: :unprocessable_entity }
57
- # end
58
- # end
59
- #end
60
- #
61
- ## DELETE /keys/1
62
- ## DELETE /keys/1.json
63
- #def destroy
64
- # @key.destroy
65
- # respond_to do |format|
66
- # format.html { redirect_to keys_url, notice: 'Key was successfully destroyed.' }
67
- # format.json { head :no_content }
68
- # end
69
- #end
70
-
71
- private
72
- # Use callbacks to share common setup or constraints between actions.
73
- def set_key
74
- @key = Key.find(params[:id])
75
- end
76
-
77
- # Never trust parameters from the scary internet, only allow the white list through.
78
- def key_params
79
- params.require(:key).permit(:key, :original_filename, :user_id)
80
- end
81
- end
82
- end
@@ -1,19 +0,0 @@
1
- module Meroku
2
- module Sanitychecks
3
-
4
- def admin_secrets_required
5
- secrets_dir = "#{Dir.home}/crypto/meroku/"
6
- IO.read("#{secrets_dir}/meroku_secrets")
7
- require 'dotenv'
8
- Dotenv.load("#{secrets_dir}/meroku_secrets")
9
- IO.read("#{secrets_dir}/meroku.id_rsa")
10
- #IO.read("#{secrets_dir}/meroku.id_rsa.pub")
11
- #IO.read("#{secrets_dir}/meroku_site_cert.pem")
12
- #IO.read("#{secrets_dir}/meroku_site_chain.pem")
13
- #IO.read("#{secrets_dir}/meroku_site_fullchain.pem")
14
- #IO.read("#{secrets_dir}/meroku_site_privkey.pem")
15
- #IO.read("#{secrets_dir}/meroku_ssh_host_keys.tgz")
16
- end
17
-
18
- end
19
- end
@@ -1,23 +0,0 @@
1
- module Meroku
2
-
3
- class User < Meroku::ApplicationRecord
4
- include Meroku::Util
5
-
6
- # Include default devise modules. Others available are:
7
- # :confirmable, :lockable, :timeoutable and :omniauthable
8
- devise :database_authenticatable, :registerable,
9
- :recoverable, :rememberable, :trackable, :validatable
10
-
11
- has_many :keys
12
-
13
- after_create :add_unix_user
14
- after_create :install_rvm_for_user
15
-
16
- def database_password
17
- encrypted_password[7..20].gsub(/[^0-9a-z ]/i, '')
18
- end
19
-
20
- end
21
-
22
- end
23
-
@@ -1,434 +0,0 @@
1
- module Meroku
2
-
3
- # Methods that doesn't have a proper namespace yet
4
- module Util
5
-
6
- require 'open3'
7
- class Subprocess
8
- def initialize(cmd, &block)
9
- # see: http://stackoverflow.com/a/1162850/83386
10
- Open3.popen3(cmd) do |stdin, stdout, stderr, thread|
11
- stdin.close
12
- # read each stream from a new thread
13
- { :out => stdout, :err => stderr }.each do |key, stream|
14
- Thread.new do
15
- until (line = stream.gets).nil? do
16
- # yield the block depending on the stream
17
- if key == :out
18
- yield line, nil, thread if block_given?
19
- else
20
- yield nil, line, thread if block_given?
21
- end
22
- end
23
- end
24
- end
25
-
26
- thread.join # don't exit until the external process is done
27
- raise "ErrorDuringPopen3" if thread.value != 0
28
- end
29
- end
30
- end
31
-
32
- def additional_env_vars(app_name, dbtype)
33
- require 'rest-client'
34
- resp = RestClient.post 'https://www.meroku.com/meroku/apps/0/additional_env_vars.json', { :"dbtype" => dbtype, authentication: { app_name: app_name, token: cli_token} }
35
- JSON.parse(resp)["data"]
36
- end
37
-
38
- def update_authorized_keys_file
39
- `sudo -i -u u#{self.user_id} sh -c "echo '#{self.key}' | tee /home/u#{self.user_id}/.ssh/authorized_keys"`
40
- end
41
-
42
- def setup_repo
43
- app = Meroku::App.find(self.app_id)
44
- user = Meroku::User.find(self.user_id)
45
- `sudo -i -u u#{user.id} sh -c "mkdir ~/#{app.name}.git"`
46
- `sudo -i -u u#{user.id} sh -c "cd ~/#{app.name}.git && git init --bare"`
47
- end
48
-
49
-
50
- def self.add_unix_users
51
- puts "DB8 #{Meroku::User.all.size} users to add..."
52
- Meroku::User.all.each do |user|
53
- puts "DB8 Adding #{user.id} #{user.email}"
54
- `sudo adduser --disabled-password --gecos "" u#{user.id}`
55
- `sudo usermod -aG meroku u#{user.id}`
56
- #`sudo -i -u u#{user.id} sh -c "mkdir ~/.ssh/"`
57
- #`sudo -i -u u#{user.id} sh -c "touch ~/.ssh/authorized_keys"`
58
- #a = IO.write("/tmp/tmp.txt",user.encrypted_password)
59
- #`sudo -i -u u#{user.id} sh -c "cp /tmp/tmp.txt /home/u1/.encrypted_password"`
60
- #`sudo -i -u u#{user.id} sh -c "cp /tmp/tmp.txt /home/u1/.encrypted_password 2>&1"`
61
- `sudo -i -u u#{user.id} sh -c "git config --global core.hooksPath /opt/githooks"`
62
-
63
- #user.keys.each do |key|
64
- # puts "DB8 Adding key #{key.id} #{key.key[0..9]} ..."
65
- # `sudo -i -u u#{user.id} sh -c "echo '#{key.key}' | tee /home/u#{user.id}/.ssh/authorized_keys"`
66
- #end
67
-
68
- end
69
- end
70
-
71
- # this is a callback called from the User model
72
- def add_unix_user
73
- `sudo adduser --disabled-password --gecos "" u#{self.id}`
74
- `sudo usermod -aG meroku u#{self.id}`
75
- `sudo -i -u u#{self.id} sh -c "mkdir ~/.ssh/"`
76
- `sudo -i -u u#{self.id} sh -c "touch ~/.ssh/authorized_keys"`
77
- Rails.logger.debug "DB8 A"
78
- a = IO.write("/tmp/tmp.txt",self.encrypted_password)
79
- Rails.logger.debug a
80
- Rails.logger.debug `sudo -i -u u#{self.id} sh -c "cp /tmp/tmp.txt /home/u1/.encrypted_password"`
81
- Rails.logger.debug `sudo -i -u u#{self.id} sh -c "cp /tmp/tmp.txt /home/u1/.encrypted_password 2>&1"`
82
- Rails.logger.debug "DB8 A end"
83
- `sudo -i -u u#{self.id} sh -c "git config --global core.hooksPath /opt/githooks"`
84
- end
85
-
86
- # this is a callback called from the Meroku::Collaborator model
87
- def add_mysql_user
88
- user = Meroku::User.find(self.user_id)
89
- `sudo mysql -pbitnami -e 'FLUSH PRIVILEGES; set password for "u#{self.user_id}"@"localhost" = PASSWORD("#{user.database_password}"); FLUSH PRIVILEGES;'`
90
- Rails.logger.debug "DB8 add_mysql_user db password for user id #{user.id} set to #{user.database_password}"
91
- end
92
-
93
- # self is a Meroku::Collaborator
94
- def add_mysql_grants
95
- app = Meroku::App.find(self.app_id)
96
- `sudo mysql -pbitnami -e 'FLUSH PRIVILEGES; GRANT ALL PRIVILEGES ON #{app.name}.* TO "u#{self.user_id}"@"localhost"; FLUSH PRIVILEGES;'`
97
- end
98
-
99
- def create_empty_pg_db
100
- app = Meroku::App.find(self.app_id)
101
- `PGPASSWORD=bitnami psql -U postgres -c "CREATE DATABASE #{app.name};"`
102
- end
103
-
104
- def add_pg_user
105
- user = Meroku::User.find(self.user_id)
106
- `PGPASSWORD=bitnami psql -U postgres -c "CREATE USER u#{self.user_id} WITH PASSWORD '#{user.database_password}';"`
107
- end
108
-
109
- def add_pg_grants
110
- app = Meroku::App.find(self.app_id)
111
- `PGPASSWORD=bitnami psql -U postgres -c "GRANT ALL PRIVILEGES ON DATABASE #{app.name} TO u#{self.user_id};"`
112
- end
113
-
114
- # self is a Meroku::Collaborator
115
- def create_empty_mysql_db
116
- app = Meroku::App.find(self.app_id)
117
- `sudo mysql -pbitnami -e 'CREATE DATABASE #{app.name}'`
118
- end
119
-
120
- # self refers to a Meroku::User
121
- def install_rvm_for_user
122
- `sudo -i -u u#{self.id} /bin/bash -c 'curl -sSL https://get.rvm.io | bash'`
123
- end
124
-
125
-
126
- def self.install_rvm_for_users
127
- puts "DB8 #{Meroku::User.all.size} users to install rvm to..."
128
- Meroku::User.all.each do |user|
129
- puts "DB8 Installing rvm for Adding #{user.id} #{user.email}"
130
- `sudo -i -u u#{user.id} /bin/bash -c 'curl -sSL https://get.rvm.io | bash'`
131
- end
132
- end
133
-
134
- def self.start_apps
135
- puts "DB8 Starting #{Meroku::App.all.size} apps ..."
136
- Meroku::App.all.each do |app|
137
- puts "DB8 Starting app #{app.id} #{app.name}"
138
- app_owner_id = Meroku::App::Collaborator.where(app_id: app.id).first.user_id
139
- `sudo -i -u u#{app_owner_id} /bin/bash -lc 'source /opt/githooks/start_app; start_app "/home/u#{app_owner_id}/#{app.name}.git"'`
140
- end
141
- end
142
-
143
- def public_key_exists?
144
- File.exist?(Dir.home + "/.ssh/id_rsa.pub")
145
- end
146
-
147
- def valid_json?(json)
148
- JSON.parse(json)
149
- return true
150
- rescue JSON::ParserError => e
151
- return false
152
- end
153
-
154
- def cli_logged_in?
155
- if File.exist?("/tmp/meroku.token")
156
- return true
157
- else
158
- puts "Not logged in"
159
- return false
160
- end
161
- end
162
-
163
- def cli_token
164
- `cat /tmp/meroku.token`.chomp
165
- end
166
-
167
- def cli_user_id
168
- user_id = `cat /tmp/meroku.id`
169
- end
170
-
171
- def app_name
172
- git_remote = `git remote get-url meroku`.chomp
173
- git_remote =~ /\@www.meroku.com\:(.*?).git\Z/
174
- $1
175
- end
176
-
177
- def ssh(ip, command)
178
- puts `ssh -tt -o "StrictHostKeyChecking=no" -i ~/crypto/meroku/meroku.id_rsa bitnami@#{ip} '#{command}'`
179
- end
180
-
181
- def ssh2(ip, command)
182
- print "+ #{command} "
183
- Meroku::Util::Subprocess.new "ssh -tt -o StrictHostKeyChecking=no -i ~/crypto/meroku/meroku.id_rsa bitnami@#{ip} '#{command}'" do |stdout, stderr, thread|
184
- print "."
185
- end
186
- print "\n"
187
-
188
- end
189
-
190
- def ssh3(ip, command)
191
- puts "+ #{command} "
192
- Meroku::Util::Subprocess.new "ssh -tt -o StrictHostKeyChecking=no -i ~/crypto/meroku/meroku.id_rsa bitnami@#{ip} '#{command}'" do |stdout, stderr, thread|
193
- print stdout
194
- print stderr
195
- end
196
- print "\n"
197
-
198
- end
199
-
200
- def ec2_client
201
- @ec2_client ||= Aws::EC2::Client.new(
202
- region: 'us-east-1',
203
- access_key_id: ENV['AWS_ACCESS_KEY_ID'],
204
- secret_access_key: ENV['AWS_SECRET_ACCESS_KEY'],
205
- )
206
- end
207
-
208
- def server_being_built
209
- ec2_get_ip_by_instance_id(unused_servers.first)
210
- end
211
-
212
- def ec2_get_ip_by_instance_id(instance_id)
213
- ec2_client.describe_instances(
214
- filters:
215
- [
216
- { name: "instance-id", values: [ instance_id ] }
217
- ]
218
- ).reservations.first.instances.first.public_ip_address
219
- end
220
-
221
- def meroku_servers
222
- ec2_client.describe_instances(
223
- filters:
224
- [
225
- { name: "tag:Name", values: ['meroku'] },
226
- { name: "instance-state-name", values: ['pending', 'running'] }
227
- ]
228
- ).reservations
229
- .map{ |a| a.instances }
230
- .map{ |b|
231
- b.map { |c| c.instance_id }
232
- }
233
- .flatten
234
- end
235
-
236
- # Returns the production servers instance id
237
- def production_servers
238
- ec2_client.describe_instances(
239
- filters:
240
- [
241
- { name: "ip-address", values: [ Meroku::PRODUCTION_IP ] },
242
- { name: "tag:Name", values: ['meroku'] },
243
- { name: "instance-state-name", values: ['pending', 'running'] }
244
- ]
245
- ).map { |x| x.reservations }.flatten.map { |x| x.instances }.flatten.map { |x| x.instance_id }
246
- rescue
247
- []
248
- end
249
-
250
- def unused_servers
251
- meroku_servers - production_servers
252
- end
253
-
254
- def terminate_unused_servers
255
- unused_servers.each do |server|
256
- puts "Terminating #{server}"
257
- ec2_client.terminate_instances({ instance_ids: [ server ] })
258
- sleep 1
259
- end
260
- end
261
-
262
- def ec2_start_instance
263
- resp = ec2_client.run_instances(
264
- {
265
- :image_id => 'ami-52a5dd44', #bitnami 2.4.1
266
- :min_count => 1,
267
- :max_count => 1,
268
- :instance_type => "t2.small",
269
- :key_name => "meroku.id_rsa"
270
- }
271
- )
272
- resp[:instances][0][:instance_id]
273
- end
274
-
275
- def ec2_tag_instance(instance_id)
276
- retries ||= 0
277
- puts "create_tags try ##{ retries }"
278
- ec2_client.create_tags( resources: [ instance_id ], tags: [ { key: 'Name', value: "meroku"}])
279
- rescue
280
- sleep 1
281
- retry if (retries += 1) < 3
282
- end
283
-
284
- def ec2_await_boot(instance_id)
285
- wait_timeout = 60
286
- ec2_client.wait_until(:instance_running, instance_ids:[ instance_id ]) do |w|
287
- w.max_attempts = 10
288
- w.interval = wait_timeout/10
289
- w.before_attempt do |n|
290
- print "#{n}/10 "
291
- end
292
- end
293
- public_ip_address = ec2_client.describe_instances(instance_ids: [instance_id])[0][0].instances[0].public_ip_address
294
- puts public_ip_address
295
- wait_time=40
296
- 10.times do |i|
297
- port_is_open = Socket.tcp(public_ip_address, 22, connect_timeout: 6) { true } rescue false
298
- print "#{i}/10 "
299
- break if port_is_open
300
- sleep 8
301
- end
302
- print "\n"
303
- puts `ssh -o "StrictHostKeyChecking=no" -i ~/crypto/meroku/meroku.id_rsa ubuntu@#{public_ip_address} uptime 2>/dev/null`
304
- end
305
-
306
- def self.shell_exec(command)
307
- require 'open3'
308
- Open3.popen2e(command) do |stdin, stdout_err, wait_thr|
309
- while line = stdout_err.gets
310
- IO.write("/home/bitnami/meroku/rails_app/log/nginx_rebuild.log", line, mode: 'a')
311
- end
312
- exit_status = wait_thr.value
313
- unless exit_status.success?
314
- raise "FAILED !!!"
315
- end
316
- end
317
- end
318
-
319
- def self.nginx_rebuild
320
- IO.write("/home/bitnami/meroku/rails_app/log/nginx_rebuild.log", "ngin_rebuild() started\n")
321
- command = <<-'HEREDOC'
322
- set -ex;
323
- sudo rm -vf /opt/bitnami/nginx/conf/vhosts/*;
324
- sudo rm -vf /opt/bitnami/nginx/keys/clients/*;
325
- HEREDOC
326
- shell_exec(command)
327
- IO.write("/tmp/www.conf", generate_nginx_config("www.meroku.com", "3000", nil) )
328
- IO.write("/tmp/_.conf",nginx_fallback_vhost)
329
-
330
- command = <<-'HEREDOC'
331
- set -ex;
332
- sudo mv -v /tmp/www.conf /opt/bitnami/nginx/conf/vhosts/;
333
- sudo mv -v /tmp/_.conf /opt/bitnami/nginx/conf/vhosts/;
334
- HEREDOC
335
- shell_exec(command)
336
-
337
- Meroku::App.all.each do |app|
338
- port = (3000 + app.id).to_s
339
- domains = "#{app.name}.meroku.com"
340
- domains = "#{app.name}.meroku.com"
341
- domains += " #{app.domains.pluck(:domain).join(" ")}" if app.domains.size > 0
342
- cert = nil
343
- cert = app.name if app.server_crt
344
- IO.write("/tmp/#{app.name}.conf", generate_nginx_config(domains, port, cert) )
345
- shell_exec("sudo mv -v /tmp/#{app.name}.conf /opt/bitnami/nginx/conf/vhosts/")
346
- if app.server_crt
347
- IO.write("/tmp/#{app.name}.crt", app.server_crt )
348
- IO.write("/tmp/#{app.name}.key", app.server_key )
349
- shell_exec "set -ex; sudo mv -v /tmp/#{app.name}.crt /opt/bitnami/nginx/keys/cli\
350
- ents/"
351
- shell_exec "set -ex; sudo mv -v /tmp/#{app.name}.key /opt/bitnami/nginx/keys/cli\
352
- ents/"
353
- end
354
- end
355
- command = <<-'HEREDOC'
356
- set -ex;
357
- sudo /opt/bitnami/nginx/sbin/nginx -s reload;
358
- ls -la /opt/bitnami/nginx/conf/vhosts/;
359
- HEREDOC
360
- shell_exec(command)
361
- IO.write("/home/bitnami/meroku/rails_app/log/nginx_rebuild.log", "ngin_rebuild() ended\n", mode: 'a')
362
- end
363
-
364
-
365
- def self.generate_nginx_config(domains, port, cert)
366
- if cert
367
- server_crt = "/opt/bitnami/nginx/keys/clients/#{cert}.crt"
368
- server_key = "/opt/bitnami/nginx/keys/clients/#{cert}.key"
369
- else
370
- server_crt = "/opt/bitnami/nginx/keys/meroku_site_fullchain.pem"
371
- server_key = "/opt/bitnami/nginx/keys/meroku_site_privkey.pem"
372
- end
373
-
374
- template = nginx_template
375
- template.gsub!('REPLACEMEDOMAINS', domains)
376
- template.gsub!('REPLACEMEPORT', port)
377
- template.gsub!('REPLACEMESERVERCERT', server_crt)
378
- template.gsub!('REPLACEMESERVERKEY', server_key)
379
- template
380
- end
381
-
382
- def self.nginx_template
383
- <<-'HEREDOC'
384
- server {
385
- listen 80;
386
- server_name REPLACEMEDOMAINS;
387
- listen 443 ssl;
388
- ssl_certificate REPLACEMESERVERCERT;
389
- ssl_certificate_key REPLACEMESERVERKEY;
390
-
391
- root /home/u1/onebody/public;
392
-
393
- location ~ ^/assets/ {
394
- expires 1y;
395
- add_header Cache-Control public;
396
-
397
- add_header ETag "";
398
- break;
399
- }
400
-
401
- ssl_session_timeout 5m;
402
- ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
403
- ssl_ciphers 'ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES256-GCM-SHA384:DHE-RSA-AES128-GCM-SHA256:DHE-DSS-AES128-GCM-SHA256:kEDH+AESGCM:ECDHE-RSA-AES128-SHA256:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA:ECDHE-ECDSA-AES128-SHA:ECDHE-RSA-AES256-SHA384:ECDHE-ECDSA-AES256-SHA384:ECDHE-RSA-AES256-SHA:ECDHE-ECDSA-AES256-SHA:DHE-RSA-AES128-SHA256:DHE-RSA-AES128-SHA:DHE-DSS-AES128-SHA256:DHE-RSA-AES256-SHA256:DHE-DSS-AES256-SHA:DHE-RSA-AES256-SHA:AES128-GCM-SHA256:AES256-GCM-SHA384:AES128-SHA256:AES256-SHA256:AES128-SHA:AES256-SHA:AES:CAMELLIA:DES-CBC3-SHA:!aNULL:!eNULL:!EXPORT:!DES:!RC4:!MD5:!PSK:!aECDH:!EDH-DSS-DES-CBC3-SHA:!EDH-RSA-DES-CBC3-SHA:!KRB5-DES-CBC3-SHA';
404
- ssl_prefer_server_ciphers on;
405
-
406
- location / {
407
- proxy_pass http://127.0.0.1:REPLACEMEPORT;
408
- # got from https://github.com/mperham/sidekiq/issues/2560
409
- proxy_set_header Host $http_host;
410
- proxy_set_header X-Real-IP $proxy_protocol_addr;
411
- proxy_set_header X-Forwarded-For $proxy_protocol_addr;
412
- proxy_set_header X-Forwarded-Proto https;
413
-
414
- }
415
- }
416
- HEREDOC
417
- end
418
-
419
- def self.nginx_fallback_vhost
420
- <<-'HEREDOC'
421
- # _.conf
422
- # Default server for clients who do not send correct Host header.
423
- # The underline in the file name makes sure that this file comes first in the dir.
424
- server {
425
- server_name _;
426
- listen *:80 default_server deferred;
427
- return 404;
428
- }
429
- HEREDOC
430
- end
431
-
432
-
433
- end
434
- end