hap 0.0.2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (55) hide show
  1. checksums.yaml +7 -0
  2. data/.DS_Store +0 -0
  3. data/.gitignore +17 -0
  4. data/.ruby-gemset +1 -0
  5. data/.ruby-version +1 -0
  6. data/Gemfile +4 -0
  7. data/LICENSE.txt +22 -0
  8. data/README.md +73 -0
  9. data/Rakefile +34 -0
  10. data/bin/hap +7 -0
  11. data/env.rb +14 -0
  12. data/hap.gemspec +30 -0
  13. data/lib/hap.rb +65 -0
  14. data/lib/hap/app.rb +66 -0
  15. data/lib/hap/cli.rb +111 -0
  16. data/lib/hap/constants.rb +23 -0
  17. data/lib/hap/generators.rb +15 -0
  18. data/lib/hap/generators/endpoint.rb +43 -0
  19. data/lib/hap/generators/gemfile.rb +28 -0
  20. data/lib/hap/generators/haproxy.rb +56 -0
  21. data/lib/hap/generators/install.rb +52 -0
  22. data/lib/hap/generators/procfile.rb +39 -0
  23. data/lib/hap/generators/templates/app/.ruby-gemset +1 -0
  24. data/lib/hap/generators/templates/app/.ruby-version +1 -0
  25. data/lib/hap/generators/templates/app/Gemfile +8 -0
  26. data/lib/hap/generators/templates/app/Rakefile +0 -0
  27. data/lib/hap/generators/templates/app/env.rb +10 -0
  28. data/lib/hap/generators/templates/app/server.rb +2 -0
  29. data/lib/hap/generators/templates/config/backend/Gemfile.erb +5 -0
  30. data/lib/hap/generators/templates/config/backend/Procfile.erb +3 -0
  31. data/lib/hap/generators/templates/config/frontend/Procfile.erb +8 -0
  32. data/lib/hap/generators/templates/config/frontend/haproxy.cfg.erb +41 -0
  33. data/lib/hap/generators/templates/endpoint.erb +12 -0
  34. data/lib/hap/helpers.rb +23 -0
  35. data/lib/hap/helpers/endpoint.rb +92 -0
  36. data/lib/hap/helpers/git.rb +41 -0
  37. data/lib/hap/helpers/heroku.rb +63 -0
  38. data/lib/hap/helpers/user_input.rb +29 -0
  39. data/lib/hap/version.rb +3 -0
  40. data/lib/kernel.rb +6 -0
  41. data/spec/cli_spec.rb +36 -0
  42. data/spec/fixtures/backend/Procfile +2 -0
  43. data/spec/fixtures/backend/Procfile.production +2 -0
  44. data/spec/fixtures/frontend/Procfile +3 -0
  45. data/spec/fixtures/frontend/Procfile.production +1 -0
  46. data/spec/fixtures/frontend/haproxy.cfg +31 -0
  47. data/spec/fixtures/frontend/haproxy.cfg.production +31 -0
  48. data/spec/fixtures/my_end_point.rb +7 -0
  49. data/spec/fixtures/namespace_my_end_point.rb +11 -0
  50. data/spec/generators/endpoint_spec.rb +29 -0
  51. data/spec/generators/haproxy_spec.rb +29 -0
  52. data/spec/generators/install_spec.rb +30 -0
  53. data/spec/generators/procfile_spec.rb +41 -0
  54. data/spec/support/minitest_helper.rb +18 -0
  55. metadata +225 -0
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 0bd84f54373818e6ba80184570c1a09b97acd82c
4
+ data.tar.gz: 0fe55b6a035aede51d26deb6be94812b2e4cfd82
5
+ SHA512:
6
+ metadata.gz: c2485b9dddba790b5ca17bdb727de1690c527ee39911c4de5b13df7b4c7e59944f49dff0129b8bd76ffb1bd83e165c35774cf17941814df7368c3f5c3caf0122
7
+ data.tar.gz: 9834d429146c3752eeffba291ba8c2edd0045c25f7c27ec315f3a7723cbd15f4fa401250fa594ded05261b9079aa140a58980ea6a7b2cdb619abc8e334a7ab11
Binary file
@@ -0,0 +1,17 @@
1
+ *.gem
2
+ *.rbc
3
+ .bundle
4
+ .config
5
+ .yardoc
6
+ Gemfile.lock
7
+ InstalledFiles
8
+ _yardoc
9
+ coverage
10
+ doc/
11
+ lib/bundler/man
12
+ pkg
13
+ rdoc
14
+ spec/reports
15
+ test/tmp
16
+ test/version_tmp
17
+ tmp
@@ -0,0 +1 @@
1
+ hap
@@ -0,0 +1 @@
1
+ ruby-2.0.0-p0
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in hap.gemspec
4
+ gemspec
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2013 lemmycaution
2
+
3
+ MIT License
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining
6
+ a copy of this software and associated documentation files (the
7
+ "Software"), to deal in the Software without restriction, including
8
+ without limitation the rights to use, copy, modify, merge, publish,
9
+ distribute, sublicense, and/or sell copies of the Software, and to
10
+ permit persons to whom the Software is furnished to do so, subject to
11
+ the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be
14
+ included in all copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
@@ -0,0 +1,73 @@
1
+ # Hap
2
+
3
+ An Interface to help creating multi-server high scalable APIs on Heroku!
4
+
5
+ Hap is a CLI and a bit much more to manage `App per Resource` APIs powered by Goliath and HaProxy
6
+
7
+ ## Installation
8
+
9
+ Add this line to your application's Gemfile:
10
+
11
+ gem 'hap'
12
+
13
+ And then execute:
14
+
15
+ $ bundle
16
+
17
+ Or install it yourself as:
18
+
19
+ $ gem install hap
20
+
21
+ ## Usage
22
+
23
+ Beware!, before start, this gem has not been fully tested on various platforms and i'm using it with ruby 2.0 on mac os x, but designed to work on heroku, so it works on heroku :)
24
+
25
+ Go and create you firt hap app by running
26
+
27
+ $ hap new my_intergalactic_api [--bundle] [--remote]
28
+
29
+ Ok, get in the directory
30
+
31
+ $ cd my_intergalactic_api
32
+
33
+ Then create the very first endpoint of this little api
34
+
35
+ $ hap endpoint showmeok
36
+
37
+ Run it locally, then head to localhost:5000/showmeok (!wow!)
38
+
39
+ $ hap server
40
+
41
+ Well, to deploy this tiny api you need a heroku account and api key, if you have already, run;
42
+ but first, if you are using multiple heroku accounts deploy may fail, but are you usin heroku:accounts
43
+ then run
44
+
45
+ $ hap account YourAccountName
46
+
47
+ well, we'r ready now, go live, hurray!
48
+
49
+ $ hap deploy
50
+
51
+ Viola! Your highly scalable, haproxy powered multi-app (not dyno!) api deployed!
52
+
53
+ If you missed the address of you api, you can find all data about heroku apps under deploy directory.
54
+
55
+ Good luck
56
+
57
+ Drop me a line if you liked or interested in this, @onuruyar at twitter.
58
+
59
+ ps: Thanks https://github.com/kiafaldorius/ for his buildpack, it rocks!
60
+
61
+ ## Todo
62
+
63
+ write more tests
64
+ write documentation
65
+ it can be sexier than this!
66
+
67
+ ## Contributing
68
+
69
+ 1. Fork it
70
+ 2. Create your feature branch (`git checkout -b my-new-feature`)
71
+ 3. Commit your changes (`git commit -am 'Add some feature'`)
72
+ 4. Push to the branch (`git push origin my-new-feature`)
73
+ 5. Create new Pull Request
@@ -0,0 +1,34 @@
1
+ require "./env"
2
+
3
+ $stderr.sync = true
4
+
5
+ require "bundler/gem_tasks"
6
+
7
+ # Bundling
8
+ require 'bundler'
9
+ Bundler.setup
10
+ Bundler.require
11
+
12
+ # Test Task
13
+ task :test, [:path] do |t, args|
14
+
15
+ # set environment
16
+ ENV["RACK_ENV"] = "test"
17
+ ENV['HEROKU_API_KEY']='TEST_API_KEY'
18
+ ENV['HEROKU_ACCOUNT']='fluxproject'
19
+ ENV['GEM_ROOT'] = File.dirname(File.expand_path(__FILE__))
20
+
21
+ require 'hap'
22
+
23
+ # include support files
24
+ Dir.glob('spec/support/*.rb') { |f| require f }
25
+
26
+ # Run them all or only one
27
+ if ARGV.length < 2
28
+ Dir.glob('spec/**/*_spec.rb') { |f| require f }
29
+ else
30
+ require "#{ARGV[1]}_spec.rb"
31
+ end
32
+ end
33
+
34
+ task :default => ["test"]
data/bin/hap ADDED
@@ -0,0 +1,7 @@
1
+ #!/usr/bin/ruby
2
+ require File.join(File.dirname(__FILE__), '..', 'env')
3
+
4
+ # Bundling
5
+ require 'thor'
6
+ require 'hap'
7
+ Hap::CLI.start
data/env.rb ADDED
@@ -0,0 +1,14 @@
1
+ $:.unshift File.dirname( __FILE__)
2
+
3
+ # real time stdout
4
+ $stdout.sync = true
5
+ # $stderr.sync = true
6
+
7
+ # ENV vars
8
+ if File.exists?(".env")
9
+ Hash[File.read(".env").
10
+ gsub("\n\n","\n").
11
+ split("\n").
12
+ compact.map{|v| v.split("=")}].
13
+ each { |k,v| ENV[k] = v }
14
+ end
@@ -0,0 +1,30 @@
1
+ # coding: utf-8
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'hap/version'
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = "hap"
8
+ spec.version = Hap::VERSION
9
+ spec.authors = ["lemmycaution"]
10
+ spec.email = ["fluxproject@gmail.com"]
11
+ spec.description = %q{An Interface to help creating multi-server high scalable APIs on heroku}
12
+ spec.summary = %q{Hap is a CLI and a bit much more to manage `App per Resource` APIs based on Goliath and HaProxy}
13
+ spec.homepage = "http://github.com/lemmycaution/hap"
14
+ spec.license = "MIT"
15
+
16
+ spec.files = `git ls-files`.split($/)
17
+ spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
18
+ spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
19
+ spec.require_paths = ["lib"]
20
+
21
+ spec.add_development_dependency "bundler", "~> 1.3"
22
+ spec.add_development_dependency "rake"
23
+
24
+ spec.add_development_dependency "minitest"
25
+ spec.add_dependency "thor"
26
+ spec.add_dependency "activesupport"
27
+ spec.add_dependency "heroku-api"
28
+ spec.add_dependency "heroku"
29
+ spec.add_dependency "oj"
30
+ end
@@ -0,0 +1,65 @@
1
+ require "kernel"
2
+ require 'pathname'
3
+ require "active_support/inflector"
4
+ require "active_support/string_inquirer"
5
+ require "active_support/concern"
6
+ require "active_support/dependencies/autoload"
7
+
8
+ module Hap
9
+
10
+ extend ActiveSupport::Autoload
11
+
12
+ eager_autoload do
13
+ autoload :App
14
+ autoload :CLI
15
+ autoload :Constants
16
+ autoload :Generators
17
+ autoload :Helpers
18
+ autoload :Version
19
+ end
20
+
21
+ include Constants
22
+
23
+ class << self
24
+
25
+ def env
26
+ @env ||= ActiveSupport::StringInquirer.new(ENV['RACK_ENV'] ||= "development")
27
+ end
28
+
29
+ def env=(environment)
30
+ @env = ActiveSupport::StringInquirer.new(environment)
31
+ end
32
+
33
+ def app_root
34
+ @app_root ||= find_root_with_flag('server.rb', Dir.pwd)
35
+ end
36
+
37
+ def app_root= app_root
38
+ @app_root = app_root
39
+ end
40
+
41
+ def in_app_dir?
42
+ File.exists?("#{Hap.app_root}/server.rb")
43
+ end
44
+
45
+ private
46
+
47
+ # i steal this from rails
48
+ def find_root_with_flag(flag, default=nil)
49
+ root_path = self.class.called_from[0]
50
+
51
+ while root_path && File.directory?(root_path) && !File.exist?("#{root_path}/#{flag}")
52
+ parent = File.dirname(root_path)
53
+ root_path = parent != root_path && parent
54
+ end
55
+
56
+ root = File.exist?("#{root_path}/#{flag}") ? root_path : default
57
+ raise "Could not find root path for #{self}" unless root
58
+
59
+ RbConfig::CONFIG['host_os'] =~ /mswin|mingw/ ?
60
+ Pathname.new(root).expand_path : Pathname.new(root).realpath
61
+ end
62
+
63
+ end
64
+
65
+ end
@@ -0,0 +1,66 @@
1
+ require 'oj'
2
+ require 'heroku-api'
3
+
4
+ module Hap
5
+ class App
6
+
7
+ @data = {}
8
+
9
+ attr_accessor :name, :file, :data
10
+
11
+ def initialize name
12
+ @name = name
13
+ @file = "#{Hap.app_root}/#{Hap::DEPLOYMENT_DIR}/#{name}/#{Hap::APP_DATA_FILE}"
14
+ @data = Oj.load(File.read(@file)) if exists?
15
+ end
16
+
17
+ def exists?
18
+ @exists ||= File.exists?(@file)
19
+ end
20
+
21
+ def frontend?
22
+ @name == Hap::FRONT_END
23
+ end
24
+
25
+ def data
26
+ @data["domain_name"] = {"domain" => "TEST"} if Hap.env.test?
27
+ @data
28
+ end
29
+
30
+ def create!(api_key = nil)
31
+ return self if exists?
32
+ self.api_key = api_key
33
+ @data = heroku.post_app(name: nil).body
34
+ add_buildpack if frontend?
35
+ self
36
+ end
37
+
38
+ def destroy!(api_key = nil)
39
+ return unless exists?
40
+ self.api_key = api_key
41
+ heroku.delete_app @data["name"] rescue nil
42
+ end
43
+
44
+ def api_key= api_key
45
+ @api_key = api_key unless api_key.nil?
46
+ end
47
+
48
+ def missing_method(method,*args,&block)
49
+ return @data.send(method, *args, &block) if @data.respond_to?(method)
50
+ super(method,*args,&block)
51
+ end
52
+
53
+ private
54
+
55
+ def heroku
56
+ @heroku ||= ::Heroku::API.new(api_key: @api_key, :mock => Hap.env.test?)
57
+ end
58
+
59
+ def add_buildpack
60
+ heroku.put_config_vars @data["name"], {
61
+ "BUILDPACK_URL" => Hap::BUILDPACK_URL
62
+ }
63
+ end
64
+
65
+ end
66
+ end
@@ -0,0 +1,111 @@
1
+ module Hap
2
+
3
+ class CLI < Thor
4
+
5
+ include Hap::Helpers
6
+
7
+ def self.source_root
8
+ Hap.app_root
9
+ end
10
+
11
+ unless Hap.in_app_dir?
12
+
13
+ desc "new [PATH]", "Creates new Hap App"
14
+ def new(*args)
15
+ Hap::Generators::Install.start args
16
+ end
17
+
18
+ else
19
+
20
+ desc "endpoint [NAME]", "Creates new endpoint"
21
+ def endpoint(*args)
22
+ Hap::Generators::Endpoint.start args
23
+ end
24
+
25
+ desc "create [APP]", "Creates Heroku app"
26
+ def create(*args)
27
+ create_app *args
28
+ end
29
+
30
+ desc "delete [APP]", "Deletes Heroku app"
31
+ def delete(app, *args)
32
+ delete_app app
33
+ end
34
+
35
+ desc "delete_all", "Deletes All Heroku apps"
36
+ def delete_all(*args)
37
+ delete_app Hap::FRONT_END
38
+ endpoints.each do |endpoint|
39
+ delete_app endpoint[:path]
40
+ end
41
+ end
42
+
43
+ desc "account [HEROKU_ACCOUNT]", "Sets default heroku account if heroku:accounts plugin available"
44
+ def account(account)
45
+ if has_accounts_plugin?
46
+
47
+ set_env_var "HEROKU_ACCOUNT", account
48
+
49
+ if File.exists? Hap::DEPLOYED_FRONTEND
50
+ inside Hap::DEPLOYED_FRONTEND do
51
+ run "heroku accounts:set #{account}"
52
+ end
53
+ end
54
+
55
+ endpoints.each do |endpoint|
56
+ next unless deployed? endpoint
57
+ inside deploy_dir(endpoint) do
58
+ run "heroku accounts:set #{account}"
59
+ end
60
+ end
61
+
62
+ end
63
+ end
64
+
65
+ desc "server", "Starts Hap server"
66
+ def server(*args)
67
+ Hap::Generators::Haproxy.start args
68
+ Hap::Generators::Procfile.start args
69
+ system "foreman start -f #{Hap::RUNTIME_DIR}/#{Hap::FRONT_END}/Procfile -d ."
70
+ end
71
+
72
+ desc "deploy", "Deploys to heroku"
73
+ def deploy(*args)
74
+ old_env = Hap.env
75
+ Hap.env = "production"
76
+
77
+ # Deploy Frontend
78
+ create_app Hap::FRONT_END
79
+
80
+ Hap::Generators::Procfile.start [Hap::FRONT_END, "production"]
81
+ Hap::Generators::Haproxy.start ["production"]
82
+ bundle_and_git Hap::FRONT_END
83
+
84
+ # Deploy Backend
85
+ endpoints.each do |endpoint|
86
+
87
+ create_app endpoint[:path]
88
+
89
+ Hap::Generators::Procfile.start [endpoint[:path], "production"]
90
+ Hap::Generators::Gemfile.start [endpoint[:path], "production"]
91
+
92
+ copy_file endpoint[:file], deploy_dir(endpoint)
93
+
94
+ bundle_and_git endpoint[:path]
95
+
96
+ end
97
+
98
+ Hap.env = old_env
99
+ end
100
+
101
+ end
102
+
103
+ private
104
+
105
+ def env
106
+ Hap.env
107
+ end
108
+
109
+ end
110
+
111
+ end