vhost_generator 0.2.2 → 0.3.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -94,8 +94,11 @@ class ForemanExportApplication
94
94
  '# Default: web (must have entry of that name in Procfile)',
95
95
  lambda { |value| config.process_type = value }],
96
96
  ['-G', '--generator=GENERATOR',
97
- '# Default: nginx (only supported for now)',
97
+ '# Default: "nginx" (try "apache" too)',
98
98
  lambda { |value| config.generator = value }],
99
+ ['-O', '--generator-options=OPTIONS',
100
+ '# Comma-separated list of key=value',
101
+ lambda { |value| config.generator_options = value }],
99
102
  ['-N', '--dry-run', lambda { |value| config.dry_run = true }],
100
103
  ['-R', '--stop-start-service',
101
104
  '# Starts and stops APP service (may not work everywhere)',
@@ -174,9 +177,14 @@ class ForemanExportApplication
174
177
  Array(Shellwords.escape("#{target}/#{app}") + "-*.conf")
175
178
  commands << %w(sudo bundle exec foreman export) +
176
179
  escape(argv + foreman_flags)
177
- commands << %w(sudo service) + escape(app) + %w(start)
178
- commands << ['echo',
179
- '"Finished, now open your browser and see if all works."']
180
+ message = 'Finished, now '
181
+ if config.service
182
+ commands << %w(sudo service) + escape(app) + %w(start)
183
+ else
184
+ message = "start the #{escape(app)} service, "
185
+ end
186
+ message << "open your browser and see if everything works."
187
+ commands << ['echo', '"' + message + '"']
180
188
  self
181
189
  end
182
190
 
@@ -185,12 +193,14 @@ class ForemanExportApplication
185
193
  attr_reader :config, :argv, :commands
186
194
 
187
195
  def generator_flags(flags=Array.new)
196
+ flags << '-a' << config.app if config.app
188
197
  flags << '-f' << config.static_folder if config.static_folder
189
198
  flags << '-l' << config.server_ports if config.server_ports
190
199
  flags << '-s' << config.server_names if config.server_names
191
200
  flags << '-p' << config.instance_ports if config.instance_ports
192
201
  flags << '-g' << config.generator if config.generator
193
- flags << '-o' << "upstream=#{app}" if config.generator == 'nginx' && app
202
+ flags << '-o' << config.generator_options if config.generator_options
203
+ flags
194
204
  end
195
205
 
196
206
  def foreman_flags(flags=Array.new)
@@ -203,6 +213,7 @@ class ForemanExportApplication
203
213
  flags << '-c' << config.concurrency if config.concurrency
204
214
  flags << '-f' << config.procfile if config.procfile
205
215
  flags << '-d' << config.root if config.root
216
+ flags
206
217
  end
207
218
 
208
219
  def app
@@ -217,8 +228,18 @@ class ForemanExportApplication
217
228
  argv[1] # eg. /etc/init
218
229
  end
219
230
 
231
+ def vhost_dir
232
+ if config.generator == 'nginx'
233
+ '/etc/nginx/sites-enabled'
234
+ elsif config.generator == 'apache'
235
+ '/etc/apache2/sites-enabled'
236
+ else
237
+ raise RuntimeError, "Can't guess vhost_dir for generator=#{config.generator}"
238
+ end
239
+ end
240
+
220
241
  def vhost_config
221
- "/etc/#{service}/sites-enabled/rails-#{app}.conf"
242
+ "#{vhost_dir}/vhost-#{app}.conf"
222
243
  end
223
244
 
224
245
  def escape(args)
@@ -26,7 +26,8 @@ Feature: Wrap "foreman export"
26
26
  -L, --server-ports=PORTS # Default: 80
27
27
  -S, --server-names=NAMES # Default: localhost
28
28
  -K, --foreman-process-type=TYPE # Default: web (must have entry of that name in Procfile)
29
- -G, --generator=GENERATOR # Default: nginx (only supported for now)
29
+ -G, --generator=GENERATOR # Default: "nginx" (try "apache" too)
30
+ -O, --generator-options=OPTIONS # Comma-separated list of key=value
30
31
  -N, --dry-run
31
32
  -R, --stop-start-service # Starts and stops APP service (may not work everywhere)
32
33
 
@@ -39,10 +40,10 @@ Feature: Wrap "foreman export"
39
40
  clock: ....
40
41
  web: bundle exec webserver -p $PORT
41
42
  """
42
- When I run `bundle exec foreman-export-vhost upstart /etc/init -a MYAPP -u MYUSER -p 6000 -c clock=1,web=2 -L 80,81 -S localhost,myapp.com -K web -G nginx -N -R`
43
+ When I run `bundle exec foreman-export-vhost upstart /etc/init -f Procfile -a MYAPP -u MYUSER -p 6000 -c clock=1,web=2 -L 80,81 -S localhost,myapp.com -K web -G nginx -O assets_expire_in=15d -N -R`
43
44
  Then the output should match:
44
45
  """
45
- bundle exec foreman run vhost-generator -f /.*/public -l 80,81 -s localhost,myapp.com -p 6100,6101 -g nginx -o upstream=MYAPP | sudo tee /etc/nginx/sites-enabled/rails-MYAPP.conf
46
+ bundle exec foreman run vhost-generator -a MYAPP -f /.*/public -l 80,81 -s localhost,myapp.com -p 6100,6101 -g nginx -o assets_expire_in\\=15d \| sudo tee /etc/nginx/sites-enabled/vhost-MYAPP.conf
46
47
  """
47
48
  And the output should contain:
48
49
  """
@@ -57,6 +58,6 @@ Feature: Wrap "foreman export"
57
58
  And the output should contain:
58
59
  """
59
60
  sudo service MYAPP start
60
- echo "Finished, now open your browser and see if all works."
61
+ echo "Finished, now open your browser and see if everything works."
61
62
  # Now, try to run this script again without the --dry-run switch!
62
63
  """
@@ -5,11 +5,11 @@ Feature: Output nginx configuration file
5
5
  I want to output a nginx virtualhost configuration.
6
6
 
7
7
  Scenario: using command-line options
8
- When I run `bundle exec vhost-generator -g nginx -o upstream=myupstream -f html -l 80,81 -s localhost,my.server -p 5000,5001,5002 -r /myapp`
8
+ When I run `bundle exec vhost-generator -g nginx -o assets_expire_in=15d -a testapp -f html -l 80,81 -s localhost,my.server -p 5000,5001,5002 -r /myapp`
9
9
  Then the output should match /FILE GENERATED BY.*EDIT AT YOUR OWN RISK/
10
10
  And the output should contain:
11
11
  """
12
- upstream myupstream {
12
+ upstream testapp {
13
13
  server localhost:5000 fail_timeout=0;
14
14
  server localhost:5001 fail_timeout=0;
15
15
  server localhost:5002 fail_timeout=0;
@@ -34,14 +34,14 @@ Feature: Output nginx configuration file
34
34
  proxy_set_header X-Forwarded-Proto $scheme;
35
35
  proxy_set_header Host $http_host;
36
36
  proxy_redirect off;
37
- proxy_pass http://myupstream;
37
+ proxy_pass http://testapp;
38
38
  }
39
39
  """
40
40
  And the output should contain:
41
41
  """
42
42
  location /myapp/assets {
43
43
  gzip_static on; # to serve pre-gzipped version
44
- expires 60d;
44
+ expires 15d;
45
45
  add_header Cache-Control public;
46
46
  }
47
47
  """
@@ -55,7 +55,8 @@ Feature: Output nginx configuration file
55
55
 
56
56
  Scenario: using environment variables
57
57
  When I set env variable "GENERATOR" to "nginx"
58
- And I set env variable "GENERATOR_OPTIONS" to "upstream=myupstream"
58
+ And I set env variable "GENERATOR_OPTIONS" to "assets_expire_in=15d"
59
+ And I set env variable "APPLICATION" to "testapp"
59
60
  And I set env variable "STATIC_FOLDER" to "html"
60
61
  And I set env variable "SERVER_PORTS" to "80,81"
61
62
  And I set env variable "SERVER_NAMES" to "localhost,my.server"
@@ -65,7 +66,7 @@ Feature: Output nginx configuration file
65
66
  Then the output should match /FILE GENERATED BY.*EDIT AT YOUR OWN RISK/
66
67
  And the output should contain:
67
68
  """
68
- upstream myupstream {
69
+ upstream testapp {
69
70
  server localhost:5000 fail_timeout=0;
70
71
  server localhost:5001 fail_timeout=0;
71
72
  server localhost:5002 fail_timeout=0;
@@ -90,14 +91,14 @@ Feature: Output nginx configuration file
90
91
  proxy_set_header X-Forwarded-Proto $scheme;
91
92
  proxy_set_header Host $http_host;
92
93
  proxy_redirect off;
93
- proxy_pass http://myupstream;
94
+ proxy_pass http://testapp;
94
95
  }
95
96
  """
96
97
  And the output should contain:
97
98
  """
98
99
  location /myapp/assets {
99
100
  gzip_static on; # to serve pre-gzipped version
100
- expires 60d;
101
+ expires 15d;
101
102
  add_header Cache-Control public;
102
103
  }
103
104
  """
@@ -8,5 +8,5 @@ Feature: Output program version
8
8
  When I run `bundle exec vhost-generator --version`
9
9
  Then it should pass with:
10
10
  """
11
- vhost-generator, version 0.2.2
11
+ vhost-generator, version 0.3.0
12
12
  """
@@ -33,6 +33,9 @@ module VhostGenerator
33
33
  end
34
34
 
35
35
  def handle_env(env)
36
+ if app = env['APPLICATION']
37
+ config.application = app
38
+ end
36
39
  if path = env['STATIC_FOLDER']
37
40
  config.static_folder = path
38
41
  end
@@ -90,6 +93,9 @@ module VhostGenerator
90
93
 
91
94
  def application_options
92
95
  [
96
+ ['-a', '--application APPLICATION',
97
+ %q{Unique name of your application (e.g. myapp)},
98
+ lambda { |value| config.application = value }],
93
99
  ['-f', '--static-folder STATIC_FOLDER',
94
100
  %q{Path of your application's static folder (e.g. public/)},
95
101
  lambda { |value| config.static_folder = value }],
@@ -0,0 +1,64 @@
1
+ require 'shellwords'
2
+
3
+ Capistrano::Configuration.instance(:must_exist).load do
4
+ namespace :vhost do
5
+ _cset(:vhost_port) { 5000 }
6
+ _cset(:vhost_env) { nil }
7
+ _cset(:vhost_concurrency) { nil }
8
+ _cset(:vhost_procfile) { 'Procfile' }
9
+ _cset(:vhost_server_ports) { '80' }
10
+ _cset(:vhost_server_names) { 'localhost' }
11
+ _cset(:vhost_process) { abort "Please specify the foreman process type, set :vhost_process, 'web' (if you have 'web' in your Procfile)" }
12
+ _cset(:vhost_generator) { abort "Please specify the target web server, set :vhost_generator, 'nginx' (or 'apache')" }
13
+ _cset(:vhost_generator_options) { nil }
14
+
15
+ desc <<-DESC
16
+ Runs the "foreman-export-vhost" command to manage a foreman-enabled \
17
+ application using upstart and generate nginx or apache virtualhost configuration \
18
+ file to serve it to web clients.
19
+
20
+ You can override any of these defaults by setting the variables shown below.
21
+
22
+ set :vhost_port, #{vhost_port.inspect}
23
+ set :vhost_env, #{vhost_env.inspect}
24
+ set :vhost_concurrency, #{vhost_concurrency.inspect}
25
+ set :vhost_procfile, #{vhost_procfile.inspect}
26
+ set :vhost_server_ports, #{vhost_server_ports.inspect}
27
+ set :vhost_server_names, #{vhost_server_names.inspect}
28
+ set :vhost_generator,
29
+ set :vhost_generator_options, #{vhost_generator_options.inspect}
30
+ set :vhost_process
31
+ DESC
32
+ task :export do
33
+ cmdline = "foreman-export-vhost upstart /etc/init -u $USER"
34
+ cmdline << " -a #{application.shellescape}"
35
+ cmdline << " -p #{String(vhost_port).shellescape}"
36
+ cmdline << " -e #{vhost_env.shellescape}" if vhost_env
37
+ cmdline << " -f #{vhost_procfile.shellescape}" if vhost_procfile
38
+ cmdline << " -c #{vhost_concurrency.shellescape}" if vhost_concurrency
39
+ cmdline << " -K #{vhost_process.shellescape}"
40
+ cmdline << " -L #{vhost_server_ports.shellescape}" if vhost_server_ports
41
+ cmdline << " -S #{vhost_server_names.shellescape}" if vhost_server_names
42
+ cmdline << " -G #{vhost_generator.shellescape}" if vhost_generator
43
+ cmdline << " -O #{vhost_generator_options.shellescape}" if vhost_generator_options
44
+ run "cd #{release_path} && #{sudo} RAILS_ENV=#{rails_env} bundle exec #{cmdline}"
45
+ end
46
+
47
+ before 'deploy:create_symlink', 'vhost:export'
48
+ end
49
+
50
+ # Each application is turned into an upstart service by 'foreman export'.
51
+ namespace :deploy do
52
+ task :start do
53
+ run "#{sudo} service #{application.shellescape} start"
54
+ end
55
+
56
+ task :stop do
57
+ run "#{sudo} service #{application.shellescape} stop"
58
+ end
59
+
60
+ task :restart, :roles => :app, :except => { :no_release => true } do
61
+ run "#{sudo} service #{application.shellescape} restart"
62
+ end
63
+ end
64
+ end
@@ -34,7 +34,7 @@ module VhostGenerator
34
34
  args << '-s' << @config.server_names.join(',')
35
35
  args << '-p' << @config.instance_ports.join(',')
36
36
  args << '-r' << @config.relative_root
37
- args << '-g' << 'nginx' # FIXME use @config.generator when real registry
37
+ args << '-g' << @config.generator
38
38
  options = @config.generator_options.collect {|k,v| "#{k}=#{v}" }
39
39
  args << '-o' << options.join(',')
40
40
  args
@@ -9,7 +9,9 @@ module VhostGenerator
9
9
  attr_reader :cfg, :options
10
10
  def initialize(cfg, options={})
11
11
  @cfg = cfg
12
- @options = OpenStruct.new(default_options.merge(options)).freeze
12
+ @options = OpenStruct.new(default_options.merge(options))
13
+ @options.upstream ||= cfg.application
14
+ @options.freeze
13
15
  end
14
16
 
15
17
  def render
@@ -20,7 +22,7 @@ module VhostGenerator
20
22
 
21
23
  def default_options
22
24
  Hash[ 'client_max_body_size' => '4G', 'keepalive_timeout' => '10',
23
- 'assets_expire_in' => '60d', 'upstream' => 'appservers' ].freeze
25
+ 'assets_expire_in' => '60d' ].freeze
24
26
  end
25
27
 
26
28
  private
@@ -1,3 +1,3 @@
1
1
  module VhostGenerator
2
- VERSION = "0.2.2"
2
+ VERSION = "0.3.0"
3
3
  end
@@ -8,14 +8,16 @@ module VhostGenerator
8
8
  # +env+ or +cmdline+ needed to render the configuration template.
9
9
  #
10
10
  class VhostConfiguration
11
- attr_reader :static_folder, :server_ports, :server_names,
11
+ attr_reader :application, :static_folder, :server_ports, :server_names,
12
12
  :instance_ports, :relative_root,
13
13
  :generator, :generator_options
14
14
  attr_accessor :cmdline
15
15
 
16
- def initialize(static_folder='public', server_ports='80',
17
- server_names='localhost', instance_ports='', relative_root='/',
18
- generator='nginx', generator_options='', cmdline=nil)
16
+ def initialize(application='myapp', static_folder='public',
17
+ server_ports='80', server_names='localhost', instance_ports='',
18
+ relative_root='/', generator='nginx', generator_options='',
19
+ cmdline=nil)
20
+ self.application = application
19
21
  self.static_folder = static_folder
20
22
  self.server_ports = server_ports
21
23
  self.server_names = server_names
@@ -26,6 +28,12 @@ module VhostGenerator
26
28
  self.generator_options = generator_options
27
29
  end
28
30
 
31
+ def application=(app)
32
+ app = String(app).strip.gsub(/\s+/, '_') # avoid blanks in app name.
33
+ raise ArgumentError, "application is required" unless app && !app.empty?
34
+ @application = app
35
+ end
36
+
29
37
  def static_folder=(folder)
30
38
  @static_folder = File.expand_path(folder)
31
39
  end
@@ -47,7 +55,8 @@ module VhostGenerator
47
55
  end
48
56
 
49
57
  def generator=(name)
50
- @generator = generator_for(name)
58
+ generator_for(name) # ensure generator exists
59
+ @generator = name
51
60
  end
52
61
 
53
62
  def generator_options=(options)
@@ -59,7 +68,7 @@ module VhostGenerator
59
68
  end
60
69
 
61
70
  def output
62
- self.generator.new(self, self.generator_options).render
71
+ generator_for(self.generator).new(self, self.generator_options).render
63
72
  end
64
73
 
65
74
  protected
@@ -7,6 +7,7 @@ describe VhostGenerator::Application do
7
7
  before { subject.config = config }
8
8
 
9
9
  options = Hash[
10
+ 'application' => 'APPLICATION',
10
11
  'static_folder' => 'STATIC_FOLDER',
11
12
  'server_ports' => 'SERVER_PORTS',
12
13
  'server_names' => 'SERVER_NAMES',
@@ -7,6 +7,7 @@ describe VhostGenerator::Application do
7
7
  before { subject.config = config }
8
8
 
9
9
  options = Hash[
10
+ 'application' => %w(-a --application),
10
11
  'static_folder' => %w(-f --static-folder),
11
12
  'server_ports' => %w(-l --listen),
12
13
  'server_names' => %w(-s --server-name),
@@ -1,6 +1,24 @@
1
1
  require 'vhost_generator/vhost_configuration'
2
2
 
3
3
  describe VhostGenerator::VhostConfiguration do
4
+ describe "#application" do
5
+ it "is 'myapp' by default" do
6
+ expect(subject.application).to eql('myapp')
7
+ end
8
+
9
+ it "is normalized on the fly" do
10
+ expect {
11
+ subject.application = ' my sanitized app '
12
+ }.to change(subject, :application).to('my_sanitized_app')
13
+ end
14
+
15
+ it "is required" do
16
+ expect {
17
+ subject.application = ''
18
+ }.to raise_error(ArgumentError, /required/)
19
+ end
20
+ end
21
+
4
22
  describe "#static_folder" do
5
23
  it "is 'public/' by default" do
6
24
  expect(subject.static_folder).to eql(File.expand_path('public'))
@@ -84,12 +102,12 @@ describe VhostGenerator::VhostConfiguration do
84
102
  expect(subject.generator).to be
85
103
  end
86
104
 
87
- it "is resolved into a generator plugin" do
105
+ it "is set when a generator plugin exists" do
88
106
  generator = double('generator')
89
107
  subject.send(:registry).merge!('test' => generator)
90
108
  expect {
91
109
  subject.generator = 'test'
92
- }.to change(subject, :generator).to generator
110
+ }.to change(subject, :generator).to 'test'
93
111
  end
94
112
 
95
113
  it "complains when trying to set invalid values" do
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: vhost_generator
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.2
4
+ version: 0.3.0
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2012-10-02 00:00:00.000000000 Z
12
+ date: 2012-10-05 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: rake
@@ -100,6 +100,7 @@ files:
100
100
  - features/version.feature
101
101
  - lib/vhost_generator.rb
102
102
  - lib/vhost_generator/application.rb
103
+ - lib/vhost_generator/capistrano.rb
103
104
  - lib/vhost_generator/cmdline_builder.rb
104
105
  - lib/vhost_generator/nginx_generator.rb
105
106
  - lib/vhost_generator/version.rb
@@ -126,7 +127,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
126
127
  version: '0'
127
128
  segments:
128
129
  - 0
129
- hash: 138630257
130
+ hash: 1022995219
130
131
  required_rubygems_version: !ruby/object:Gem::Requirement
131
132
  none: false
132
133
  requirements:
@@ -135,7 +136,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
135
136
  version: '0'
136
137
  segments:
137
138
  - 0
138
- hash: 138630257
139
+ hash: 1022995219
139
140
  requirements: []
140
141
  rubyforge_project:
141
142
  rubygems_version: 1.8.23