hap 0.0.2

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.
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,23 @@
1
+ module Hap
2
+ module Constants
3
+
4
+ DEPLOYMENT_DIR = "tmp/deploy"
5
+ RUNTIME_DIR = "tmp/server"
6
+ ENDPOINTS_DIR = "app/endpoints"
7
+ CONFIG_DIR = "config"
8
+
9
+ FRONT_END = "frontend"
10
+ BACK_END = "backend"
11
+ BUILDPACK_URL = 'https://github.com/kiafaldorius/haproxy-buildpack'
12
+
13
+ HAPROXY_BACKEND_SERVER_OPTIONS = 'inter 5000 fastinter 1000 fall 1 weight 50'
14
+ DEFAULT_PROCESS_TYPE = "web"
15
+
16
+ DEVELOPMENT_HOST = "localhost"
17
+ DEFAULT_TCP_PORT = 80
18
+
19
+ DEPLOYED_FRONTEND = "#{DEPLOYMENT_DIR}/#{FRONT_END}"
20
+ APP_DATA_FILE = "heroku.json"
21
+ REMOTE_REPO_NAME = "heroku"
22
+ end
23
+ end
@@ -0,0 +1,15 @@
1
+ module Hap
2
+ module Generators
3
+
4
+ extend ActiveSupport::Autoload
5
+
6
+ eager_autoload do
7
+ autoload :Endpoint
8
+ autoload :Gemfile
9
+ autoload :Haproxy
10
+ autoload :Install
11
+ autoload :Procfile
12
+ end
13
+
14
+ end
15
+ end
@@ -0,0 +1,43 @@
1
+ module Hap
2
+ module Generators
3
+ class Endpoint < Thor::Group
4
+
5
+ include Hap::Helpers
6
+
7
+ argument :name, required: true
8
+ class_option :remote, default: false
9
+
10
+ def self.source_root
11
+ File.dirname(__FILE__)
12
+ end
13
+
14
+ def copy_endpoint_template
15
+ template("templates/endpoint.erb", "#{Hap.app_root}/#{Hap::ENDPOINTS_DIR}/#{name}.rb")
16
+ end
17
+
18
+ def create_config_file
19
+ create_file "#{Hap.app_root}/#{Hap::CONFIG_DIR}/#{name}.rb", ""
20
+ end
21
+
22
+ def create_remote_app
23
+ create_app name if options[:remote]
24
+ end
25
+
26
+ private
27
+
28
+ def modules
29
+ @modules ||= name.split("/").tap{|a| a.pop }
30
+ end
31
+
32
+ def has_module?
33
+ @has_module ||= name.include?("/")
34
+ end
35
+
36
+ def class_name
37
+ @class_name ||= name.split("/").last
38
+ end
39
+
40
+ end
41
+
42
+ end
43
+ end
@@ -0,0 +1,28 @@
1
+ module Hap
2
+ module Generators
3
+ class Gemfile < Thor::Group
4
+
5
+ include Hap::Helpers
6
+
7
+ argument :app, required: true
8
+ argument :env, default: Hap.env
9
+ class_option :force, default: true
10
+
11
+ def self.source_root
12
+ File.dirname(__FILE__)
13
+ end
14
+
15
+ def create_cfg_file
16
+ template "templates/config/#{Hap::BACK_END}/Gemfile.erb", target_file
17
+ end
18
+
19
+ protected
20
+
21
+ def target_file
22
+ @target_file ||= "#{Hap.app_root}/#{Hap::DEPLOYMENT_DIR}/#{app}/Gemfile"
23
+ end
24
+
25
+ end
26
+
27
+ end
28
+ end
@@ -0,0 +1,56 @@
1
+ module Hap
2
+ module Generators
3
+ class Haproxy < Thor::Group
4
+
5
+ include Hap::Helpers
6
+
7
+ argument :env, default: Hap.env
8
+ class_option :force, default: true
9
+
10
+ def self.source_root
11
+ File.dirname(__FILE__)
12
+ end
13
+
14
+ def create_cfg_file
15
+ template "templates/config/#{Hap::FRONT_END}/haproxy.cfg.erb", target_file
16
+ end
17
+
18
+ def fix_port
19
+ gsub_file target_file, "$PORT", "5000" unless to.production?
20
+ end
21
+
22
+ def convert_to_profile
23
+ if to.production?
24
+ copy_file target_file, target_file.gsub( File.basename(target_file), "haproxy.cfg" )
25
+ prepend_file target_file do
26
+ "#!/bin/bash\n"
27
+ "cat > haproxy.cfg <<EOF\n"
28
+ end
29
+ append_file target_file do
30
+ "\nEOF"
31
+ end
32
+ end
33
+ end
34
+
35
+ protected
36
+
37
+ def stats_admin
38
+ @stats_admin ||= ENV['STATS_ADMIN'] ||= "admin"
39
+ end
40
+
41
+ def stats_password
42
+ @stats_password ||= ENV['STATS_PASSWORD'] ||= "password"
43
+ end
44
+
45
+ def target_file
46
+ @target_file ||= "#{Hap.app_root}/#{target}/#{Hap::FRONT_END}/#{filename}"
47
+ end
48
+
49
+ def filename
50
+ @filename ||= to.production? ? ".profile" : "haproxy.cfg"
51
+ end
52
+
53
+ end
54
+
55
+ end
56
+ end
@@ -0,0 +1,52 @@
1
+ module Hap
2
+ module Generators
3
+ class Install < Thor::Group
4
+
5
+ include Hap::Helpers
6
+
7
+ argument :path, required: true
8
+ class_option :bundle, default: false
9
+ class_option :remote, default: false
10
+
11
+ def self.source_root
12
+ File.dirname(__FILE__)
13
+ end
14
+
15
+ def create_app_directory_structure
16
+ directory("templates/app", path)
17
+ empty_directory "#{app_path}/#{Hap::DEPLOYMENT_DIR}"
18
+ empty_directory "#{app_path}/#{Hap::RUNTIME_DIR}"
19
+ empty_directory "#{app_path}/app/endpoints"
20
+ empty_directory "#{app_path}/config"
21
+ Hap.app_root = app_path
22
+ end
23
+
24
+ def install_bundle
25
+ return unless options[:bundle]
26
+ inside(app_path) do
27
+ Bundler.with_clean_env do
28
+ run "bundle install", capture: true
29
+ end
30
+ end
31
+ end
32
+
33
+ def init_git
34
+ inside(app_path) do
35
+ git_init
36
+ end
37
+ end
38
+
39
+ def create_remote_app
40
+ create_app Hap::FRONT_END if options[:remote]
41
+ end
42
+
43
+ private
44
+
45
+ def app_path
46
+ "#{Dir.pwd}/#{path}"
47
+ end
48
+
49
+ end
50
+
51
+ end
52
+ end
@@ -0,0 +1,39 @@
1
+ module Hap
2
+ module Generators
3
+ class Procfile < Thor::Group
4
+
5
+ include Hap::Helpers
6
+
7
+ argument :app, default: Hap::FRONT_END
8
+ argument :env, default: Hap.env
9
+ class_option :force, default: true
10
+
11
+ def self.source_root
12
+ File.dirname(__FILE__)
13
+ end
14
+
15
+ def create_procfile
16
+ template "templates/config/#{type}/Procfile.erb",
17
+ "#{Hap.app_root}/#{target}/#{app}/Procfile"
18
+ end
19
+
20
+ private
21
+
22
+ def type
23
+ app == Hap::FRONT_END ? Hap::FRONT_END : Hap::BACK_END
24
+ end
25
+
26
+ def haproxy
27
+ to.production? ? "./haproxy -f haproxy.cfg" :
28
+ "haproxy -f #{Hap::RUNTIME_DIR}/#{Hap::FRONT_END}/haproxy.cfg -d -V"
29
+ end
30
+
31
+ def backend
32
+ path = app.is_a?(String) ? app : app.name
33
+ endpoints(true).select{|e| e[:path] == path }[0]
34
+ end
35
+
36
+ end
37
+
38
+ end
39
+ end
@@ -0,0 +1 @@
1
+ ruby-2.0.0-p0
@@ -0,0 +1,8 @@
1
+ ruby '2.0.0'
2
+
3
+ source 'https://rubygems.org'
4
+
5
+ gem 'hap', path: "/Users/onuruyar/Sites/hap/gem"
6
+
7
+ gem 'goliath'
8
+ gem 'foreman'
@@ -0,0 +1,10 @@
1
+ $:.unshift File.dirname( __FILE__)
2
+
3
+ # real time stdout
4
+ $stdout.sync = true
5
+ $stderr.sync = true
6
+
7
+ # Bundling
8
+ require 'bundler'
9
+ Bundler.setup
10
+ Bundler.require
@@ -0,0 +1,2 @@
1
+ require './env'
2
+ require ARGV[0]
@@ -0,0 +1,5 @@
1
+ ruby '2.0.0'
2
+
3
+ source 'https://rubygems.org'
4
+
5
+ gem 'goliath'
@@ -0,0 +1,3 @@
1
+ <% backend[:servers].each_with_index do |server, index| %>
2
+ <%= server[:type] %>: bundle exec ruby <%= backend[:file] %> -p $PORT
3
+ <% end %>
@@ -0,0 +1,8 @@
1
+ web: <%= haproxy %>
2
+ <% unless to.production? %>
3
+ <% endpoints(true).each do |endpoint| %>
4
+ <% endpoint[:servers].each_with_index do |server, index| %>
5
+ srv_<%= endpoint[:name] %>_<%= index %>: bundle exec ruby <%= endpoint[:file] %> -p <%= server[:port] %>
6
+ <% end %>
7
+ <% end %>
8
+ <% end %>
@@ -0,0 +1,41 @@
1
+ global
2
+ pidfile /var/run/haproxy.pid
3
+ log 127.0.0.1 local0 info
4
+ user root
5
+
6
+ defaults
7
+ mode http
8
+
9
+ clitimeout 600000 # maximum inactivity time on the client side
10
+ srvtimeout 600000 # maximum inactivity time on the server side
11
+ timeout connect 8000 # maximum time to wait for a connection attempt to a server to succeed
12
+
13
+ stats enable
14
+ stats auth <%= stats_admin %>:<%= stats_password %>
15
+ stats uri /monitor
16
+ stats refresh 5s
17
+ retries 5
18
+ option httpchk GET /status
19
+ option redispatch
20
+ option httpclose
21
+ option abortonclose
22
+ option forwardfor
23
+
24
+ balance roundrobin # each server is used in turns, according to assigned weight
25
+
26
+ frontend http
27
+ bind :$PORT
28
+ monitor-uri /haproxy # end point to monitor HAProxy status (returns 200)
29
+
30
+ <% endpoints(true).each do |endpoint| %>
31
+ acl acl_<%= endpoint[:name] %> path_reg ^/<%= endpoint[:path] %>/?
32
+ use_backend backend_<%= endpoint[:name] %> if acl_<%= endpoint[:name] %>
33
+ <% end %>
34
+
35
+ <% endpoints(true).each do |endpoint| %>
36
+ backend backend_<%= endpoint[:name] %>
37
+ reqirep ^Host: Host:\ <%= endpoint[:host] %>
38
+ <% endpoint[:servers].each_with_index do |server, index| %>
39
+ server srv_<%= endpoint[:name] %>_<%= index %> <%= server[:address] %>:<%= server[:port] %> <%= server[:options] %>
40
+ <% end %>
41
+ <% end %>
@@ -0,0 +1,12 @@
1
+ require 'goliath'
2
+ <% if has_module? %><% modules.each do |module_name| %>
3
+ module <%= module_name.classify %>
4
+ <% end %><% end %>
5
+ class <%= class_name.classify %> < Goliath::API
6
+ def response(env)
7
+ [200,{},"OK"]
8
+ end
9
+ end
10
+ <% if has_module? %><% modules.each do |mname| %>
11
+ end
12
+ <% end %><% end %>
@@ -0,0 +1,23 @@
1
+ module Hap
2
+ module Helpers
3
+
4
+ extend ActiveSupport::Concern
5
+ extend ActiveSupport::Autoload
6
+
7
+ eager_autoload do
8
+ autoload :Endpoint
9
+ autoload :Git
10
+ autoload :Heroku
11
+ autoload :UserInput
12
+ end
13
+
14
+ included do
15
+ include Heroku
16
+ include UserInput
17
+ include Git
18
+ include Endpoint
19
+ include Thor::Actions
20
+ end
21
+
22
+ end
23
+ end
@@ -0,0 +1,92 @@
1
+ module Hap
2
+ module Helpers
3
+ module Endpoint
4
+
5
+ protected
6
+
7
+ def endpoints(with_servers = false)
8
+ @endpoints ||= begin
9
+ Array.new.tap{ |endpoints|
10
+ Dir.glob("#{Hap::ENDPOINTS_DIR}/**/*.rb").each_with_index do |file,index|
11
+ return unless File.file? file
12
+
13
+ path = file.gsub(/#{Hap::ENDPOINTS_DIR}|\.rb/,"")[1..-1]
14
+ name = path.parameterize.underscore
15
+ servers = []
16
+ host = nil
17
+
18
+ if with_servers
19
+ servers = [{
20
+ address: address(path), port: port(name, index),
21
+ options: Hap::HAPROXY_BACKEND_SERVER_OPTIONS,
22
+ type: Hap::DEFAULT_PROCESS_TYPE
23
+ }]
24
+ host = get_host(path)
25
+ end
26
+
27
+ endpoints << {file: file, path: path, name: name, host: host, servers: servers}
28
+ end
29
+ }
30
+ end
31
+ end
32
+
33
+ def deployed? endpoint
34
+ App.new(endpoint[:path]).exists?
35
+ end
36
+
37
+ def deploy_dir endpoint
38
+ "#{Hap::DEPLOYMENT_DIR}/#{endpoint[:path]}/#{Hap::ENDPOINTS_DIR}/#{File.basename(endpoint[:file])}"
39
+ end
40
+
41
+ private
42
+
43
+ def to
44
+ @to ||= ActiveSupport::StringInquirer.new(env)
45
+ end
46
+
47
+ def target
48
+ @target ||= to.production? ? Hap::DEPLOYMENT_DIR : Hap::RUNTIME_DIR
49
+ end
50
+
51
+ def get_host path
52
+ to.production? ? address(path) : Hap::DEVELOPMENT_HOST
53
+ end
54
+
55
+ def address path
56
+
57
+ if to.production?
58
+
59
+ app = App.new(path)
60
+
61
+ app = create_app path unless app.exists?
62
+
63
+ raise Thor::Error, "App could not found" unless app.exists?
64
+
65
+ app.data["domain_name"]["domain"]
66
+
67
+ else
68
+ "0.0.0.0"
69
+
70
+ end
71
+
72
+ end
73
+
74
+ def port name, index
75
+ to.production? ? Hap::DEFAULT_TCP_PORT : next_port(name,index).to_s
76
+ end
77
+
78
+ def next_port name, index
79
+ if ports[name]
80
+ ports[name] += 1
81
+ else
82
+ ports[name] = ((index +1) * 1000) + 5000
83
+ end
84
+ end
85
+
86
+ def ports
87
+ @ports ||= {}
88
+ end
89
+
90
+ end
91
+ end
92
+ end