@@ -0,0 +1,2 @@ |
||
1 |
+https://github.com/cantino/heroku-selectable-procfile.git |
|
2 |
+https://github.com/heroku/heroku-buildpack-ruby.git |
@@ -74,12 +74,9 @@ gem 'hipchat', '~> 1.2.0' |
||
74 | 74 |
gem 'xmpp4r', '~> 0.5.6' |
75 | 75 |
gem 'feed-normalizer' |
76 | 76 |
gem 'slack-notifier', '~> 0.5.0' |
77 |
- |
|
78 | 77 |
gem 'therubyracer', '~> 0.12.1' |
79 |
- |
|
80 | 78 |
gem 'mqtt' |
81 | 79 |
|
82 |
- |
|
83 | 80 |
group :development do |
84 | 81 |
gem 'binding_of_caller' |
85 | 82 |
gem 'better_errors' |
@@ -103,3 +100,17 @@ group :production do |
||
103 | 100 |
gem 'dotenv-deployment' |
104 | 101 |
gem 'rack' |
105 | 102 |
end |
103 |
+ |
|
104 |
+# This hack needs some explanation. When on Heroku, use the pg, unicorn, and rails12factor gems. |
|
105 |
+# When not on Heroku, we still want our Gemfile.lock to include these gems, so we scope them to |
|
106 |
+# an unsupported platform. |
|
107 |
+if ENV['ON_HEROKU'] || ENV['HEROKU_POSTGRESQL_ROSE_URL'] || File.read(File.join(File.dirname(__FILE__), 'Procfile')) =~ /intended for Heroku/ |
|
108 |
+ gem 'pg' |
|
109 |
+ gem 'unicorn' |
|
110 |
+ gem 'rails_12factor' |
|
111 |
+else |
|
112 |
+ gem 'pg', platform: :ruby_18 |
|
113 |
+ gem 'unicorn', platform: :ruby_18 |
|
114 |
+ gem 'rails_12factor', platform: :ruby_18 |
|
115 |
+end |
|
116 |
+ |
@@ -165,6 +165,7 @@ GEM |
||
165 | 165 |
kaminari (0.16.1) |
166 | 166 |
actionpack (>= 3.0.0) |
167 | 167 |
activesupport (>= 3.0.0) |
168 |
+ kgio (2.9.2) |
|
168 | 169 |
kramdown (1.3.3) |
169 | 170 |
launchy (2.4.2) |
170 | 171 |
addressable (~> 2.3) |
@@ -196,6 +197,7 @@ GEM |
||
196 | 197 |
multi_xml (~> 0.5) |
197 | 198 |
rack (~> 1.2) |
198 | 199 |
orm_adapter (0.5.0) |
200 |
+ pg (0.17.1) |
|
199 | 201 |
polyglot (0.3.5) |
200 | 202 |
protected_attributes (1.0.8) |
201 | 203 |
activemodel (>= 4.0.1, < 5.0) |
@@ -218,11 +220,17 @@ GEM |
||
218 | 220 |
bundler (>= 1.3.0, < 2.0) |
219 | 221 |
railties (= 4.1.4) |
220 | 222 |
sprockets-rails (~> 2.0) |
223 |
+ rails_12factor (0.0.2) |
|
224 |
+ rails_serve_static_assets |
|
225 |
+ rails_stdout_logging |
|
226 |
+ rails_serve_static_assets (0.0.2) |
|
227 |
+ rails_stdout_logging (0.0.3) |
|
221 | 228 |
railties (4.1.4) |
222 | 229 |
actionpack (= 4.1.4) |
223 | 230 |
activesupport (= 4.1.4) |
224 | 231 |
rake (>= 0.8.7) |
225 | 232 |
thor (>= 0.18.1, < 2.0) |
233 |
+ raindrops (0.13.0) |
|
226 | 234 |
rake (10.3.2) |
227 | 235 |
ref (1.0.5) |
228 | 236 |
rest-client (1.6.7) |
@@ -322,6 +330,10 @@ GEM |
||
322 | 330 |
uglifier (2.5.1) |
323 | 331 |
execjs (>= 0.3.0) |
324 | 332 |
json (>= 1.8.0) |
333 |
+ unicorn (4.8.3) |
|
334 |
+ kgio (~> 2.6) |
|
335 |
+ rack |
|
336 |
+ raindrops (~> 0.7) |
|
325 | 337 |
uuid (2.3.7) |
326 | 338 |
macaddr (~> 1.0) |
327 | 339 |
uuidtools (2.1.4) |
@@ -380,11 +392,13 @@ DEPENDENCIES |
||
380 | 392 |
mqtt |
381 | 393 |
mysql2 (~> 0.3.16) |
382 | 394 |
nokogiri (~> 1.6.1) |
395 |
+ pg |
|
383 | 396 |
protected_attributes (~> 1.0.8) |
384 | 397 |
pry |
385 | 398 |
quiet_assets |
386 | 399 |
rack |
387 | 400 |
rails (= 4.1.4) |
401 |
+ rails_12factor |
|
388 | 402 |
rr |
389 | 403 |
rspec (~> 2.14) |
390 | 404 |
rspec-rails (~> 2.14) |
@@ -401,6 +415,7 @@ DEPENDENCIES |
||
401 | 415 |
typhoeus (~> 0.6.3) |
402 | 416 |
tzinfo-data |
403 | 417 |
uglifier (>= 1.3.0) |
418 |
+ unicorn |
|
404 | 419 |
vcr |
405 | 420 |
webmock (~> 1.17.4) |
406 | 421 |
weibo_2 (~> 0.1.4) |
@@ -6,8 +6,8 @@ jobs: bundle exec rails runner bin/threaded.rb |
||
6 | 6 |
# web: bundle exec unicorn -c config/unicorn/production.rb |
7 | 7 |
# jobs: bundle exec rails runner bin/threaded.rb |
8 | 8 |
|
9 |
-# Old version with seperate processes (use this if you have issues with the threaded version) |
|
10 |
-#web: bundle exec rails server |
|
11 |
-#schedule: bundle exec rails runner bin/schedule.rb |
|
12 |
-#twitter: bundle exec rails runner bin/twitter_stream.rb |
|
13 |
-#dj: bundle exec script/delayed_job run |
|
9 |
+# Old version with separate processes (use this if you have issues with the threaded version) |
|
10 |
+# web: bundle exec rails server |
|
11 |
+# schedule: bundle exec rails runner bin/schedule.rb |
|
12 |
+# twitter: bundle exec rails runner bin/twitter_stream.rb |
|
13 |
+# dj: bundle exec script/delayed_job run |
@@ -38,7 +38,7 @@ module Agents |
||
38 | 38 |
'expected_receive_period_in_days' => "2", |
39 | 39 |
'group_by_path' => "filter", |
40 | 40 |
'value_path' => "count", |
41 |
- 'message' => "A peak was found" |
|
41 |
+ 'message' => "A peak of {{count}} was found in {{filter}}" |
|
42 | 42 |
} |
43 | 43 |
end |
44 | 44 |
|
@@ -0,0 +1,160 @@ |
||
1 |
+#!/usr/bin/env ruby |
|
2 |
+require 'open3' |
|
3 |
+require 'io/console' |
|
4 |
+ |
|
5 |
+unless `which heroku` =~ /heroku/ |
|
6 |
+ puts "It looks like the heroku command line tool hasn't been installed yet. Please install" |
|
7 |
+ puts "the Heroku Toolbelt from https://toolbelt.heroku.com, run 'heroku auth:login', and then" |
|
8 |
+ puts "run this script again." |
|
9 |
+ exit 1 |
|
10 |
+end |
|
11 |
+ |
|
12 |
+def capture(cmd, opts = {}) |
|
13 |
+ o, s = Open3.capture2e(cmd, opts) |
|
14 |
+ o.strip |
|
15 |
+end |
|
16 |
+ |
|
17 |
+def ask(question, opts = {}) |
|
18 |
+ print question + " " |
|
19 |
+ STDOUT.flush |
|
20 |
+ (opts[:noecho] ? STDIN.noecho(&:gets) : gets).strip |
|
21 |
+end |
|
22 |
+ |
|
23 |
+def nag(question, opts = {}) |
|
24 |
+ answer = '' |
|
25 |
+ while answer.length == 0 |
|
26 |
+ answer = ask(question, opts) |
|
27 |
+ end |
|
28 |
+ answer |
|
29 |
+end |
|
30 |
+ |
|
31 |
+def yes?(question) |
|
32 |
+ ask(question + " (y/n)") =~ /^y/i |
|
33 |
+end |
|
34 |
+ |
|
35 |
+def grab_heroku_config! |
|
36 |
+ config_data = capture("heroku config -s") |
|
37 |
+ $config = {} |
|
38 |
+ if config_data !~ /has no config vars/ |
|
39 |
+ config_data.split("\n").map do |line| |
|
40 |
+ next if line =~ /^\s*(#|$)/ # skip comments and empty lines |
|
41 |
+ first_equal_sign = line.index('=') |
|
42 |
+ $config[line.slice(0, first_equal_sign)] = line.slice(first_equal_sign + 1, line.length) |
|
43 |
+ end |
|
44 |
+ end |
|
45 |
+end |
|
46 |
+ |
|
47 |
+def set_value(key, value, options = {}) |
|
48 |
+ if $config[key].nil? || $config[key] == '' || ($config[key] != value && options[:force] != false) |
|
49 |
+ puts "Setting #{key} to #{value}" unless options[:silent] |
|
50 |
+ puts capture("heroku config:set #{key}=#{value}") |
|
51 |
+ end |
|
52 |
+end |
|
53 |
+ |
|
54 |
+unless File.exists?(File.expand_path("~/.netrc")) && File.read(File.expand_path("~/.netrc")) =~ /heroku/ |
|
55 |
+ puts "It looks like you need to log in to Heroku. Please run 'heroku auth:login' before continuing." |
|
56 |
+ exit 1 |
|
57 |
+end |
|
58 |
+ |
|
59 |
+puts "Welcome #{`heroku auth:whoami`.strip}! It looks like you're logged into Heroku." |
|
60 |
+puts |
|
61 |
+ |
|
62 |
+info = capture("heroku info") |
|
63 |
+if info =~ /No app specified/i |
|
64 |
+ puts "It looks like you don't have a Heroku app set up yet for this repo." |
|
65 |
+ puts "You can either exit now and run 'heroku create', or I can do it for you." |
|
66 |
+ if yes?("Would you like me to create a Heroku app for you now in this repo?") |
|
67 |
+ puts `heroku create` |
|
68 |
+ info = capture("heroku info") |
|
69 |
+ else |
|
70 |
+ puts "Okay, exiting so you can do it." |
|
71 |
+ exit 0 |
|
72 |
+ end |
|
73 |
+end |
|
74 |
+ |
|
75 |
+app_name = info.scan(/http:\/\/([\w\d-]+)\.herokuapp\.com/).flatten.first |
|
76 |
+ |
|
77 |
+unless yes?("Your Heroku app name is #{app_name}. Is this correct?") |
|
78 |
+ puts "Well, then I'm not sure what to do here, sorry." |
|
79 |
+ exit 1 |
|
80 |
+end |
|
81 |
+ |
|
82 |
+grab_heroku_config! |
|
83 |
+ |
|
84 |
+if $config.length > 0 |
|
85 |
+ puts |
|
86 |
+ puts "Your current Heroku config:" |
|
87 |
+ $config.each do |key, value| |
|
88 |
+ puts ' ' + key + ' ' * (25 - [key.length, 25].min) + '= ' + value |
|
89 |
+ end |
|
90 |
+end |
|
91 |
+ |
|
92 |
+unless $config['APP_SECRET_TOKEN'] |
|
93 |
+ puts "Setting up APP_SECRET_TOKEN..." |
|
94 |
+ puts capture("heroku config:set APP_SECRET_TOKEN=`rake secret`") |
|
95 |
+end |
|
96 |
+ |
|
97 |
+set_value 'BUILDPACK_URL', "https://github.com/ddollar/heroku-buildpack-multi.git" |
|
98 |
+set_value 'PROCFILE_PATH', "deployment/heroku/Procfile.heroku", force: false |
|
99 |
+set_value 'ON_HEROKU', "true" |
|
100 |
+set_value 'FORCE_SSL', "true" |
|
101 |
+set_value 'DOMAIN', "#{app_name}.herokuapp.com", force: false |
|
102 |
+ |
|
103 |
+unless $config['INVITATION_CODE'] |
|
104 |
+ puts "You need to set an invitation code for your Huginn instance. If you plan to share this instance, you will" |
|
105 |
+ puts "tell this code to anyone who you'd like to invite. If you won't share it, then just set this to something" |
|
106 |
+ puts "that people will not guess." |
|
107 |
+ |
|
108 |
+ invitation_code = nag("What code would you like to use?") |
|
109 |
+ set_value 'INVITATION_CODE', invitation_code |
|
110 |
+end |
|
111 |
+ |
|
112 |
+unless $config['SMTP_DOMAIN'] && $config['SMTP_USER_NAME'] && $config['SMTP_PASSWORD'] && $config['SMTP_SERVER'] && $config['EMAIL_FROM_ADDRESS'] |
|
113 |
+ puts "Okay, let's setup outgoing email settings. The simplest solution is to use the free sendgrid Heroku addon." |
|
114 |
+ puts "If you'd like to use your own server, or your Gmail account, please see .env.example and set" |
|
115 |
+ puts "SMTP_DOMAIN, SMTP_USER_NAME, SMTP_PASSWORD, and SMTP_SERVER with 'heroku config:set'." |
|
116 |
+ if yes?("Should I enable the free sendgrid addon?") |
|
117 |
+ puts capture("heroku addons:add sendgrid") |
|
118 |
+ |
|
119 |
+ set_value 'SMTP_SERVER', "smtp.sendgrid.net", silent: true |
|
120 |
+ set_value 'SMTP_DOMAIN', "heroku.com", silent: true |
|
121 |
+ |
|
122 |
+ grab_heroku_config! |
|
123 |
+ set_value 'SMTP_USER_NAME', $config['SENDGRID_USERNAME'], silent: true |
|
124 |
+ set_value 'SMTP_PASSWORD', $config['SENDGRID_PASSWORD'], silent: true |
|
125 |
+ else |
|
126 |
+ puts "Okay, you'll need to set SMTP_DOMAIN, SMTP_USER_NAME, SMTP_PASSWORD, and SMTP_SERVER with 'heroku config:set' manually." |
|
127 |
+ end |
|
128 |
+ |
|
129 |
+ unless $config['EMAIL_FROM_ADDRESS'] |
|
130 |
+ email = nag("What email address would you like email to appear to be sent from?") |
|
131 |
+ set_value 'EMAIL_FROM_ADDRESS', email |
|
132 |
+ end |
|
133 |
+end |
|
134 |
+ |
|
135 |
+branch = capture("git rev-parse --abbrev-ref HEAD") |
|
136 |
+if yes?("Should I push your current branch (#{branch}) to heroku?") |
|
137 |
+ puts "This may take a moment..." |
|
138 |
+ puts capture("git push heroku #{branch}:master -f") |
|
139 |
+ |
|
140 |
+ puts "Running database migrations..." |
|
141 |
+ puts capture("heroku run rake db:migrate") |
|
142 |
+ |
|
143 |
+ puts |
|
144 |
+ puts |
|
145 |
+ puts "I can make an admin user on your new Huginn instance and setup some example Agents." |
|
146 |
+ if yes?("Should I create a new admin user and some example Agents?") |
|
147 |
+ seed_email = nag "Okay, what is your email address?" |
|
148 |
+ seed_username = nag "And what username would you like to login as?" |
|
149 |
+ seed_password = nag "Finally, what password would you like to use?", noecho: true |
|
150 |
+ puts "\nJust a moment..." |
|
151 |
+ |
|
152 |
+ capture("heroku run rake db:seed SEED_EMAIL=#{seed_email} SEED_USERNAME=#{seed_username} SEED_PASSWORD=#{seed_password}") |
|
153 |
+ puts |
|
154 |
+ puts |
|
155 |
+ puts "Okay, you should be all set! Visit https://#{app_name}.herokuapp.com and login as '#{seed_username}' with your password." |
|
156 |
+ end |
|
157 |
+end |
|
158 |
+ |
|
159 |
+puts |
|
160 |
+puts "Done!" |
@@ -5,5 +5,5 @@ Delayed::Worker.read_ahead = 5 |
||
5 | 5 |
Delayed::Worker.default_priority = 10 |
6 | 6 |
Delayed::Worker.delay_jobs = !Rails.env.test? |
7 | 7 |
|
8 |
-Delayed::Worker.logger = Logger.new(Rails.root.join('log', 'delayed_job.log')) |
|
9 |
-Delayed::Worker.logger.level = Logger::DEBUG |
|
8 |
+# Delayed::Worker.logger = Logger.new(Rails.root.join('log', 'delayed_job.log')) |
|
9 |
+# Delayed::Worker.logger.level = Logger::DEBUG |
@@ -1,10 +1,10 @@ |
||
1 | 1 |
# This file should contain all the record creation needed to seed the database with its default values. |
2 | 2 |
# The data can then be loaded with the rake db:seed (or created alongside the db with db:setup). |
3 | 3 |
|
4 |
-user = User.find_or_initialize_by(:email => "admin@example.com") |
|
5 |
-user.username = "admin" |
|
6 |
-user.password = "password" |
|
7 |
-user.password_confirmation = "password" |
|
4 |
+user = User.find_or_initialize_by(:email => ENV['SEED_EMAIL'] || "admin@example.com") |
|
5 |
+user.username = ENV['SEED_USERNAME'] || "admin" |
|
6 |
+user.password = ENV['SEED_PASSWORD'] || "password" |
|
7 |
+user.password_confirmation = ENV['SEED_PASSWORD'] || "password" |
|
8 | 8 |
user.invitation_code = User::INVITATION_CODES.first |
9 | 9 |
user.admin = true |
10 | 10 |
user.save! |
@@ -0,0 +1,4 @@ |
||
1 |
+# This Procfile is intended for Heroku, and is detected by the Gemfile. DO NOT REMOVE THIS LINE! |
|
2 |
+ |
|
3 |
+# deployment/heroku/unicorn.rb is a special Unicorn config file that also spawns workers. |
|
4 |
+web: bundle exec unicorn -p $PORT -c ./deployment/heroku/unicorn.rb |
@@ -0,0 +1,51 @@ |
||
1 |
+require "net/http" |
|
2 |
+ |
|
3 |
+worker_processes Integer(ENV["WEB_CONCURRENCY"] || 2) |
|
4 |
+timeout 15 |
|
5 |
+preload_app true |
|
6 |
+ |
|
7 |
+# Note that this will only work correctly when running Heroku with ONE web worker. |
|
8 |
+# If you want to run more than one, use the standard Huginn Procfile instead, with separate web and job entries. |
|
9 |
+# You'll need to set the Heroku config variable PROCFILE_PATH to 'Procfile'. |
|
10 |
+Thread.new do |
|
11 |
+ worker_pid = nil |
|
12 |
+ while true |
|
13 |
+ if worker_pid.nil? |
|
14 |
+ worker_pid = spawn("bundle exec rails runner bin/threaded.rb") |
|
15 |
+ puts "New threaded worker PID: #{worker_pid}" |
|
16 |
+ end |
|
17 |
+ |
|
18 |
+ sleep 45 |
|
19 |
+ |
|
20 |
+ if ENV['DOMAIN'] |
|
21 |
+ force_ssl = ENV['FORCE_SSL'].present? && ENV['FORCE_SSL'] == 'true' |
|
22 |
+ Net::HTTP.get_response(URI((force_ssl ? "https://" : "http://") + ENV['DOMAIN'])) |
|
23 |
+ end |
|
24 |
+ |
|
25 |
+ begin |
|
26 |
+ Process.getpgid worker_pid |
|
27 |
+ rescue Errno::ESRCH |
|
28 |
+ # No longer running |
|
29 |
+ worker_pid = nil |
|
30 |
+ end |
|
31 |
+ end |
|
32 |
+end |
|
33 |
+ |
|
34 |
+before_fork do |server, worker| |
|
35 |
+ Signal.trap 'TERM' do |
|
36 |
+ puts 'Unicorn master intercepting TERM and sending myself QUIT instead' |
|
37 |
+ Process.kill 'QUIT', Process.pid |
|
38 |
+ end |
|
39 |
+ |
|
40 |
+ defined?(ActiveRecord::Base) and |
|
41 |
+ ActiveRecord::Base.connection.disconnect! |
|
42 |
+end |
|
43 |
+ |
|
44 |
+after_fork do |server, worker| |
|
45 |
+ Signal.trap 'TERM' do |
|
46 |
+ puts 'Unicorn worker intercepting TERM and doing nothing. Wait for master to send QUIT' |
|
47 |
+ end |
|
48 |
+ |
|
49 |
+ defined?(ActiveRecord::Base) and |
|
50 |
+ ActiveRecord::Base.establish_connection |
|
51 |
+end |