manageheroku 0.0.3 → 0.0.4
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +51 -2
- data/lib/manageheroku/app.rb +14 -0
- data/lib/manageheroku/conf.rb +5 -0
- data/lib/manageheroku/heroku.rb +53 -21
- data/lib/manageheroku/version.rb +1 -1
- data/lib/manageheroku.rb +1 -0
- data/test/conf_test.rb +6 -0
- data/test/heroku_test.rb +20 -1
- data/test/sample_conf.yml +8 -0
- metadata +4 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: a2b7e0c6e489cca7b8565cae44c9a3c3149d2a9d
|
4
|
+
data.tar.gz: f2cd5ab4739b3854ff62b4a30b7bbb503a4b10fe
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 283d3963c2f5244d3c567d8c5cc24048a8125996dcfcd60f6e34bb97fa8e25d6366b47ceb68058edd9619182a2632026744fef7b47fc7c610ba04d6108a9f363
|
7
|
+
data.tar.gz: 4473152d94246b52b250d23185f5af453f720bab81f8f340e5507a8e6f0bb88860722149ff2eb493932750afe3c932b87fdec76bb4c05d0cd4e9ba620c46803d
|
data/README.md
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
# Manageheroku
|
2
2
|
|
3
|
-
Manage Heroku App Formations
|
3
|
+
Manage Heroku App Formations and Apps with YML config files. Allows you to version control important application attributes, and manage configuration for different environments and scenarios.
|
4
4
|
|
5
5
|
## Installation
|
6
6
|
|
@@ -18,7 +18,56 @@ Or install it yourself as:
|
|
18
18
|
|
19
19
|
## Usage
|
20
20
|
|
21
|
-
|
21
|
+
Typical usage is to automate scaling any number of services through config files. For example:
|
22
|
+
|
23
|
+
oauth-token: <%= ENV["HEROKU_OAUTH_TOKEN"] %>
|
24
|
+
apps:
|
25
|
+
- name: "commerce-app-staging"
|
26
|
+
maintenance: false
|
27
|
+
- name: "pricing-service-staging"
|
28
|
+
maintenance: false
|
29
|
+
- name: "messaging-service-staging"
|
30
|
+
maintenance: false
|
31
|
+
formations:
|
32
|
+
- name: "commerce-app-staging"
|
33
|
+
procs:
|
34
|
+
- process: "web"
|
35
|
+
quantity: 4
|
36
|
+
size: "standard-2X"
|
37
|
+
- process: "resque"
|
38
|
+
quantity: 1
|
39
|
+
- name: "pricing-service-staging"
|
40
|
+
procs:
|
41
|
+
- process: "web"
|
42
|
+
quantity: 2
|
43
|
+
- process: "resque"
|
44
|
+
quantity: 1
|
45
|
+
- name: "messaging-service-staging"
|
46
|
+
procs:
|
47
|
+
- process: "web"
|
48
|
+
quantity: 2
|
49
|
+
- process: "resque"
|
50
|
+
quantity: 1
|
51
|
+
|
52
|
+
This config file is for an imaginary ecommerce application that is composed of a website, a pricing service and a messaging service. Using manageheroku allows you to apply this configuration to the dyno formation of each application listed in the config file. For example:
|
53
|
+
|
54
|
+
config_file = File.join(Rails.root, 'script', 'config', "black_friday_conf.yml")
|
55
|
+
heroku = Manageheroku::Heroku.new(config_file)
|
56
|
+
heroku.update!
|
57
|
+
|
58
|
+
Your application can programmatically run code like that to scale your applications based on a schedule or whatever your needs are. Currently your dyno formation sizes and quantities are the only things updatable. You can find a list of dyno types in heroku docs https://devcenter.heroku.com/articles/dyno-types
|
59
|
+
|
60
|
+
### Apps
|
61
|
+
|
62
|
+
The apps section of the config file allows you to configure attributes of a list of apps. Configurable attributes are maintenance mode and build stack. See https://devcenter.heroku.com/articles/platform-api-reference#app-update
|
63
|
+
|
64
|
+
### Formations
|
65
|
+
|
66
|
+
The formations section of the config file allows you to configure dyno formations for a list of apps. See https://devcenter.heroku.com/articles/platform-api-reference#formation-batch-update for details.
|
67
|
+
|
68
|
+
### Real World Usage
|
69
|
+
|
70
|
+
We have manageheroku config files for shutting down and starting up all of our internal environments: development, staging and performance. Then with cron (or resque scheduler) all these environments shut down at 8pm and start back up at 8am, so we're not paying for loads of resources that aren't being used. We also use manageheroku config files for storing various interesting configurations of the application for our performance testing environments.
|
22
71
|
|
23
72
|
## Contributing
|
24
73
|
|
data/lib/manageheroku/conf.rb
CHANGED
@@ -15,5 +15,10 @@ module Manageheroku
|
|
15
15
|
formation_objects = @conf_data["formations"]
|
16
16
|
formation_objects.map{|formation_object| Manageheroku::Formation.new(formation_object["name"], formation_object["procs"]) }
|
17
17
|
end
|
18
|
+
|
19
|
+
def apps
|
20
|
+
app_objects = @conf_data["apps"]
|
21
|
+
app_objects.map{|app_object| Manageheroku::App.new(app_object["name"], app_object)}
|
22
|
+
end
|
18
23
|
end
|
19
24
|
end
|
data/lib/manageheroku/heroku.rb
CHANGED
@@ -2,42 +2,74 @@ module Manageheroku
|
|
2
2
|
class Heroku
|
3
3
|
|
4
4
|
attr_reader :errors
|
5
|
+
attr_accessor :verbose
|
6
|
+
|
5
7
|
def initialize(conf_file, api_object=nil)
|
6
8
|
@conf = Manageheroku::Conf.new(conf_file)
|
7
9
|
@formations = @conf.formations
|
10
|
+
@apps = @conf.apps
|
8
11
|
@heroku = api_object || PlatformAPI.connect_oauth(@conf.oauth_token)
|
9
12
|
@errors = []
|
13
|
+
@verbose = false
|
10
14
|
end
|
11
15
|
|
12
16
|
def update!
|
17
|
+
update_apps!
|
18
|
+
update_formations!
|
19
|
+
end
|
20
|
+
|
21
|
+
private
|
22
|
+
|
23
|
+
def update_apps!
|
24
|
+
@apps.each do |app|
|
25
|
+
begin
|
26
|
+
response = @heroku.app.update(*app.update_params)
|
27
|
+
log_info("Updating App #{app.name}:", response) if @verbose
|
28
|
+
rescue StandardError => e
|
29
|
+
log_errors e
|
30
|
+
raise e
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
def update_formations!
|
13
36
|
@formations.each do |formation|
|
14
37
|
begin
|
15
|
-
@heroku.formation.batch_update(*formation.update_params)
|
38
|
+
response = @heroku.formation.batch_update(*formation.update_params)
|
39
|
+
log_info("Updating Formation for #{formation.name}:", response) if @verbose
|
16
40
|
rescue StandardError => e
|
17
|
-
|
18
|
-
# errors with a response have good information that you miss in stacktrace form
|
19
|
-
status = e.response.status
|
20
|
-
status_line = e.response.status_line
|
21
|
-
response_body_id = nil
|
22
|
-
response_body_message = nil
|
23
|
-
begin
|
24
|
-
body_hash = JSON.parse(e.response.body)
|
25
|
-
response_body_id = body_hash["id"]
|
26
|
-
response_body_message = body_hash["message"]
|
27
|
-
rescue
|
28
|
-
response_body_message = e.response.body
|
29
|
-
end
|
30
|
-
error_string = <<-OUTPUT
|
31
|
-
Status: #{[status, status_line].join(";")}
|
32
|
-
Body: #{[response_body_id, response_body_message].join(";")}
|
33
|
-
OUTPUT
|
34
|
-
@errors << error_string
|
35
|
-
puts error_string #Heroku logs stdout
|
36
|
-
end
|
41
|
+
log_errors e
|
37
42
|
raise e
|
38
43
|
end
|
39
44
|
end
|
40
45
|
end
|
41
46
|
|
47
|
+
def log_info(*log_lines)
|
48
|
+
log_lines.each{ |line| puts line }
|
49
|
+
end
|
50
|
+
|
51
|
+
def log_errors(e)
|
52
|
+
if e.respond_to?(:response)
|
53
|
+
# errors with a response have good information that you miss in stacktrace form
|
54
|
+
status = e.response.status
|
55
|
+
status_line = e.response.status_line
|
56
|
+
response_body_id = nil
|
57
|
+
response_body_message = nil
|
58
|
+
begin
|
59
|
+
body_hash = JSON.parse(e.response.body)
|
60
|
+
response_body_id = body_hash["id"]
|
61
|
+
response_body_message = body_hash["message"]
|
62
|
+
rescue
|
63
|
+
response_body_message = e.response.body
|
64
|
+
end
|
65
|
+
error_string = <<-OUTPUT
|
66
|
+
Status: #{[status, status_line].join(";")}
|
67
|
+
Body: #{[response_body_id, response_body_message].join(";")}
|
68
|
+
OUTPUT
|
69
|
+
@errors << error_string
|
70
|
+
puts error_string #Heroku logs stdout
|
71
|
+
end
|
72
|
+
end
|
73
|
+
|
42
74
|
end
|
43
75
|
end
|
data/lib/manageheroku/version.rb
CHANGED
data/lib/manageheroku.rb
CHANGED
data/test/conf_test.rb
CHANGED
@@ -13,6 +13,12 @@ class ConfTest < MiniTest::Test
|
|
13
13
|
conf.formations.last.name.must_equal "myapp-performance"
|
14
14
|
end
|
15
15
|
|
16
|
+
it "must update all the apps" do
|
17
|
+
conf = Manageheroku::Conf.new(File.join(File.dirname(__FILE__), 'sample_conf.yml'))
|
18
|
+
conf.apps.first.name.must_equal "myapp-development"
|
19
|
+
conf.apps.last.name.must_equal "myapp-staging"
|
20
|
+
end
|
21
|
+
|
16
22
|
it "supports ERB magic in the config file" do
|
17
23
|
ENV["TEST_VAL"] = "erb_is_great"
|
18
24
|
conf = Manageheroku::Conf.new(File.join(File.dirname(__FILE__), 'sample_conf.yml'))
|
data/test/heroku_test.rb
CHANGED
@@ -3,8 +3,9 @@ require File.join(File.dirname(__FILE__), 'test_helper')
|
|
3
3
|
class HerokuTest < MiniTest::Test
|
4
4
|
describe "heroku" do
|
5
5
|
# it "really works" do
|
6
|
-
# conf_file_path = File.join(File.dirname(__FILE__), '
|
6
|
+
# conf_file_path = File.join(File.dirname(__FILE__), 'shutdown_development_conf.yml')
|
7
7
|
# heroku = Manageheroku::Heroku.new(conf_file_path)
|
8
|
+
# heroku.verbose = true
|
8
9
|
# heroku.update!
|
9
10
|
# end
|
10
11
|
#
|
@@ -34,6 +35,10 @@ class HerokuTest < MiniTest::Test
|
|
34
35
|
FormationStub.new
|
35
36
|
end
|
36
37
|
|
38
|
+
def app
|
39
|
+
AppStub.new
|
40
|
+
end
|
41
|
+
|
37
42
|
class FormationStub
|
38
43
|
def batch_update(*params)
|
39
44
|
response_params = {body: {"id"=>"Invalid params", "message"=>"Cannot update the same process twice"}.to_json,
|
@@ -42,6 +47,11 @@ class HerokuTest < MiniTest::Test
|
|
42
47
|
raise Excon::Errors::UnprocessableEntity.new("Oh ye gods!", nil, Excon::Response.new(response_params))
|
43
48
|
end
|
44
49
|
end
|
50
|
+
|
51
|
+
class AppStub
|
52
|
+
def update(*params)
|
53
|
+
end
|
54
|
+
end
|
45
55
|
end
|
46
56
|
|
47
57
|
class ApiStubDegenerateCase
|
@@ -49,12 +59,21 @@ class HerokuTest < MiniTest::Test
|
|
49
59
|
FormationStub.new
|
50
60
|
end
|
51
61
|
|
62
|
+
def app
|
63
|
+
AppStub.new
|
64
|
+
end
|
65
|
+
|
52
66
|
class FormationStub
|
53
67
|
def batch_update(*params)
|
54
68
|
response_params = { status: "503" }
|
55
69
|
raise Excon::Errors::ServiceUnavailable.new("Et tu Heroku?", nil, Excon::Response.new(response_params))
|
56
70
|
end
|
57
71
|
end
|
72
|
+
|
73
|
+
class AppStub
|
74
|
+
def update(*params)
|
75
|
+
end
|
76
|
+
end
|
58
77
|
end
|
59
78
|
|
60
79
|
end
|
data/test/sample_conf.yml
CHANGED
@@ -1,4 +1,11 @@
|
|
1
1
|
oauth-token: <%= ENV["TEST_VAL"] || "the-magic-oauth-token" %>
|
2
|
+
|
3
|
+
apps:
|
4
|
+
- name: "myapp-development"
|
5
|
+
maintenance: true
|
6
|
+
- name: "myapp-staging"
|
7
|
+
maintenance: true
|
8
|
+
|
2
9
|
formations:
|
3
10
|
- name: "myapp-development"
|
4
11
|
procs:
|
@@ -16,5 +23,6 @@ formations:
|
|
16
23
|
procs:
|
17
24
|
- process: "web"
|
18
25
|
quantity: 0
|
26
|
+
size: "2X"
|
19
27
|
- process: "resque-low"
|
20
28
|
quantity: 0
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: manageheroku
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0.
|
4
|
+
version: 0.0.4
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Josh Cronemeyer
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2016-
|
11
|
+
date: 2016-08-12 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: platform-api
|
@@ -65,6 +65,7 @@ files:
|
|
65
65
|
- README.md
|
66
66
|
- Rakefile
|
67
67
|
- lib/manageheroku.rb
|
68
|
+
- lib/manageheroku/app.rb
|
68
69
|
- lib/manageheroku/conf.rb
|
69
70
|
- lib/manageheroku/formation.rb
|
70
71
|
- lib/manageheroku/heroku.rb
|
@@ -94,7 +95,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
94
95
|
version: '0'
|
95
96
|
requirements: []
|
96
97
|
rubyforge_project:
|
97
|
-
rubygems_version: 2.
|
98
|
+
rubygems_version: 2.5.1
|
98
99
|
signing_key:
|
99
100
|
specification_version: 4
|
100
101
|
summary: Manage Heroku Apps from config files
|