meroku 0.1.36 → 2.0.0

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.
@@ -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