apache-config-generator 0.1

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.
data/CHANGELOG ADDED
@@ -0,0 +1 @@
1
+ v0.1. Initial release, support for many of the Apache config basics.
data/Manifest ADDED
@@ -0,0 +1,20 @@
1
+ CHANGELOG
2
+ Manifest
3
+ README.md
4
+ Rakefile
5
+ bin/apache-configurator
6
+ lib/apache.rb
7
+ lib/apache/config.rb
8
+ lib/apache/directory.rb
9
+ lib/apache/logging.rb
10
+ lib/apache/master.rb
11
+ lib/apache/modules.rb
12
+ lib/apache/mpm_prefork.rb
13
+ lib/apache/performance.rb
14
+ lib/apache/permissions.rb
15
+ lib/apache/quoteize.rb
16
+ lib/apache/rake/create.rb
17
+ lib/apache/rewrites.rb
18
+ lib/apache/ssl.rb
19
+ skel/Rakefile
20
+ skel/config.yml
data/README.md ADDED
@@ -0,0 +1,33 @@
1
+ # Apache Config Generator
2
+
3
+ Programmatically construct your Apache configuration using a powerful DSL built in Ruby.
4
+
5
+ ## Installation
6
+
7
+ `gem install apache-config-generator`
8
+
9
+ ## Usage
10
+
11
+ Run `apache-configurator <directory>` to create a new directory to hold your config files.
12
+ A Rakefile and config.yml file will also be generated.
13
+
14
+ ## Building a config file
15
+
16
+ Configs center around the Apache::Config.build method:
17
+
18
+ Apache::Config.build('sites-available/my-site.conf') do
19
+ server_name 'my-cool-website.cool.wow'
20
+ document_root '/var/www/my-cool-website'
21
+
22
+ directory '/' do
23
+ options :follow_sym_links, :indexes
24
+ allow_from_all
25
+ end
26
+
27
+ location_match %r{^/secret} do
28
+ deny_from_all
29
+
30
+ basic_authentication "My secret", '/etc/apache2/users/global.users', :user => :john
31
+ satisfy :any
32
+ end
33
+ end
data/Rakefile ADDED
@@ -0,0 +1,39 @@
1
+ $LOAD_PATH << 'lib'
2
+
3
+ require 'apache'
4
+ require 'spec/rake/spectask'
5
+ require 'sdoc'
6
+ require 'sdoc_helpers/markdown'
7
+ require 'echoe'
8
+
9
+ namespace :apache do
10
+ desc "Generate the configs"
11
+ task :generate, :path do |t, args|
12
+ Dir[File.join(args[:path], '**', '*.rb')].each do |file|
13
+ require file
14
+ end
15
+ end
16
+ end
17
+
18
+ Echoe.new('apache-config-generator') do |p|
19
+ p.author = "John Bintz"
20
+ p.summary = "A Ruby DSL for programmatically generating Apache configs"
21
+ p.ignore_pattern = [ 'spec/**/*', 'test/**/*', 'docs/**/*' ]
22
+ p.executable_pattern = [ 'bin/**/*' ]
23
+ end
24
+
25
+ namespace :spec do
26
+ desc "Run RCov tests"
27
+ Spec::Rake::SpecTask.new('rcov') do |t|
28
+ t.spec_files = FileList['spec/*.rb']
29
+ t.rcov = true
30
+ t.rcov_opts = ['--exclude', 'spec', '--exclude', 'gems']
31
+ t.spec_opts = ['-b']
32
+ end
33
+ end
34
+
35
+ Rake::RDocTask.new do |rdoc|
36
+ rdoc.template = 'direct'
37
+ rdoc.rdoc_files.add('lib')
38
+ rdoc.rdoc_dir = 'docs'
39
+ end
@@ -0,0 +1,32 @@
1
+ # -*- encoding: utf-8 -*-
2
+
3
+ Gem::Specification.new do |s|
4
+ s.name = %q{apache-config-generator}
5
+ s.version = "0.1"
6
+
7
+ s.required_rubygems_version = Gem::Requirement.new(">= 1.2") if s.respond_to? :required_rubygems_version=
8
+ s.authors = ["John Bintz"]
9
+ s.date = %q{2010-05-10}
10
+ s.default_executable = %q{apache-configurator}
11
+ s.description = %q{A Ruby DSL for programmatically generating Apache configs}
12
+ s.email = %q{}
13
+ s.executables = ["apache-configurator"]
14
+ s.extra_rdoc_files = ["CHANGELOG", "README.md", "bin/apache-configurator", "lib/apache.rb", "lib/apache/config.rb", "lib/apache/directory.rb", "lib/apache/logging.rb", "lib/apache/master.rb", "lib/apache/modules.rb", "lib/apache/mpm_prefork.rb", "lib/apache/performance.rb", "lib/apache/permissions.rb", "lib/apache/quoteize.rb", "lib/apache/rake/create.rb", "lib/apache/rewrites.rb", "lib/apache/ssl.rb"]
15
+ s.files = ["CHANGELOG", "Manifest", "README.md", "Rakefile", "bin/apache-configurator", "lib/apache.rb", "lib/apache/config.rb", "lib/apache/directory.rb", "lib/apache/logging.rb", "lib/apache/master.rb", "lib/apache/modules.rb", "lib/apache/mpm_prefork.rb", "lib/apache/performance.rb", "lib/apache/permissions.rb", "lib/apache/quoteize.rb", "lib/apache/rake/create.rb", "lib/apache/rewrites.rb", "lib/apache/ssl.rb", "skel/Rakefile", "skel/config.yml", "apache-config-generator.gemspec"]
16
+ s.homepage = %q{}
17
+ s.rdoc_options = ["--line-numbers", "--inline-source", "--title", "Apache-config-generator", "--main", "README.md"]
18
+ s.require_paths = ["lib"]
19
+ s.rubyforge_project = %q{apache-config-generator}
20
+ s.rubygems_version = %q{1.3.6}
21
+ s.summary = %q{A Ruby DSL for programmatically generating Apache configs}
22
+
23
+ if s.respond_to? :specification_version then
24
+ current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION
25
+ s.specification_version = 3
26
+
27
+ if Gem::Version.new(Gem::RubyGemsVersion) >= Gem::Version.new('1.2.0') then
28
+ else
29
+ end
30
+ else
31
+ end
32
+ end
@@ -0,0 +1,12 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require 'fileutils'
4
+
5
+ if File.directory? ARGV[0]
6
+ puts "You can't overwrite an existing directory."
7
+ exit 1
8
+ end
9
+
10
+ FileUtils.cp_r File.expand_path(File.join(File.dirname(__FILE__), '..', 'skel')), ARGV[0]
11
+ FileUtils.mkdir_p File.join(ARGV[0], 'source')
12
+ FileUtils.mkdir_p File.join(ARGV[0], 'conf.d')
data/lib/apache.rb ADDED
@@ -0,0 +1 @@
1
+ require 'apache/config'
@@ -0,0 +1,248 @@
1
+ require 'fileutils'
2
+
3
+ Dir[File.join(File.dirname(__FILE__), '*.rb')].each { |f| require f }
4
+
5
+ module Apache
6
+ # The core class of Apache Config Generator.
7
+ #
8
+ # Configuration is built by calling either build or build_if:
9
+ #
10
+ # Ex: Build a config file regardless of current environment:
11
+ #
12
+ # Apache::Config.build('my-config.conf') do
13
+ # document_root '/my/document/root'
14
+ # ...
15
+ # end
16
+ #
17
+ # Ex: Build a config file only if you're in the development environment:
18
+ #
19
+ # Apache::Config.build_if('my-config.conf', :development) do
20
+ # document_root '/my/document/root'
21
+ # ...
22
+ # end
23
+ #
24
+ # By default, methods called within the block are NerdCapsed to match the Apache config directive format:
25
+ #
26
+ # document_root #=> DocumentRoot
27
+ # options #=> Options
28
+ # allow_override #=> AllowOverride
29
+ #
30
+ # Parameters passed into the methods are quoted if they're Strings or Integers, and not quoted if they're Symbols:
31
+ #
32
+ # document_root '/my/document/root' #=> DocumentRoot "/my/document/root"
33
+ # document_root '/my/document/root'.to_sym #=> DocumentRoot /my/document/root
34
+ # accept_path_info :off #=> AcceptPathInfo off
35
+ #
36
+ # Suffixing the method name with an exclamation point turns off quoting for all parameters:
37
+ #
38
+ # document_root! '/my/document/root' #=> DocumentRoot /my/document/root
39
+ #
40
+ # Block-level directives work the same as the top-level build method:
41
+ #
42
+ # directory '/my/site' do
43
+ # allow_from_all
44
+ # satisfy :any
45
+ # end
46
+ #
47
+ # Directives that require a regular expression take a Regexp:
48
+ #
49
+ # location_match %r{^/my/site} do
50
+ # set_env 'this_is_my_site', 'yes'
51
+ # end
52
+
53
+ class Config
54
+ class << self
55
+ attr_accessor :line_indent, :rotate_logs_path
56
+
57
+ include Apache::Master
58
+ include Apache::Quoteize
59
+ include Apache::Permissions
60
+ include Apache::Directories
61
+ include Apache::Logging
62
+ include Apache::Performance
63
+ include Apache::Rewrites
64
+ include Apache::MPM
65
+
66
+ # Build the provided configuration only if the current environment matches one of the conditions
67
+ def build_if(target, *conditions, &block)
68
+ build(target, &block) if conditions.include? APACHE_ENV
69
+ end
70
+
71
+ # Build the provided configuration
72
+ def build(target = nil, &block)
73
+ reset!
74
+
75
+ self.instance_eval(&block)
76
+
77
+ if target
78
+ FileUtils.mkdir_p File.split(target).first
79
+ File.open(target, 'w') { |f| f.puts [ "# Generated by apache-config-generator #{Time.now.to_s}", @config ].flatten * "\n" }
80
+ end
81
+
82
+ @config
83
+ end
84
+
85
+ # Reset the current settings
86
+ def reset!
87
+ @config = []
88
+ @line_indent = 0
89
+ end
90
+
91
+ # Indent the string by the current @line_indent level
92
+ def indent(string_or_array)
93
+ case string_or_array
94
+ when Array
95
+ string_or_array.collect { |s| indent(s) }
96
+ else
97
+ " " * (@line_indent * 2) + string_or_array.to_s
98
+ end
99
+ end
100
+
101
+ # Add the string to the current config
102
+ def <<(string)
103
+ @config << indent(string)
104
+ end
105
+
106
+ # Append the array to the current config
107
+ def +(other)
108
+ @config += other
109
+ end
110
+
111
+ # Get the config
112
+ def to_a
113
+ @config
114
+ end
115
+
116
+ # Apachify a string
117
+ #
118
+ # Split the provided name on underscores and capitalize the individual parts
119
+ # Certain character strings are capitalized to match Apache directive names:
120
+ # * Cgi => CGI
121
+ # * Ssl => SSL
122
+ # * Ldap => LDAP
123
+ def apachify(name)
124
+ case name
125
+ when String, Symbol
126
+ name.to_s.split("_").collect(&:capitalize).join.gsub('Ssl', 'SSL').gsub('Cgi', 'CGI').gsub('Ldap', 'LDAP').gsub('Url', 'URL')
127
+ when Array
128
+ name.collect { |n| apachify(n) }
129
+ end
130
+ end
131
+
132
+ # Handle options that aren't specially handled
133
+ #
134
+ # Method names are NerdCapsed and paramters are quoted, unless the method ends with !
135
+ def method_missing(method, *args)
136
+ if method.to_s[-1..-1] == "!"
137
+ method = method.to_s[0..-2].to_sym
138
+ else
139
+ args = *quoteize(*args)
140
+ end
141
+
142
+ self << [ apachify(method), *args ].compact * ' '
143
+ end
144
+
145
+ # Handle creating block methods
146
+ #
147
+ # Methods created this way are:
148
+ # * virtual_host
149
+ # * location
150
+ # * files
151
+ def block_methods(*methods)
152
+ methods.each do |method|
153
+ self.class.class_eval <<-EOT
154
+ def #{method}(*name, &block)
155
+ blockify(apachify("#{method}"), name, &block)
156
+ end
157
+ EOT
158
+ end
159
+ end
160
+
161
+ # If the given module is loaded, process the directives within.
162
+ #
163
+ # The provided module name is converted into Apache module name format:
164
+ # if_module(:php5) do #=> <IfModule mod_php5>
165
+ def if_module(mod, &block)
166
+ blockify(apachify('if_module'), "#{mod}_module".to_sym, &block)
167
+ end
168
+
169
+ # Create a directory block, checking to see if the source directory exists.
170
+ def directory(dir, &block)
171
+ directory? dir
172
+ blockify(apachify('directory'), dir, &block)
173
+ end
174
+
175
+ # Create a LocationMatch block with the provided Regexp:
176
+ # location_match %r{^/my/location/[a-z0-9]+\.html} do #=> <LocationMatch "^/my/location/[a-z0-9]+\.html">
177
+ def location_match(regexp, &block)
178
+ blockify(apachify('location_match'), regexp.source, &block)
179
+ end
180
+
181
+ # Create a FilesMatch block with the provied Regexp:
182
+ # files_match %r{\.html$} do #=> FilesMatch "\.html$">
183
+ def files_match(regexp, &block)
184
+ blockify(apachify('files_match'), regexp.source, &block)
185
+ end
186
+
187
+ # Only execute the provided block if APACHE_ENV matches one of the provided enviroment symbols:
188
+ # if_environment(:production) do
189
+ def if_environment(*env, &block)
190
+ self.instance_eval(&block) if env.include?(APACHE_ENV)
191
+ end
192
+
193
+ # Blockify the second parameter of a block
194
+ #
195
+ # The name is processed differently based on input object type:
196
+ # * String - the name is quoteized
197
+ # * Array - all of the array members are quoteized
198
+ # * Symbol - the name is to_s
199
+ def blockify_name(name)
200
+ case name
201
+ when String
202
+ quoteize(name).first
203
+ when Array
204
+ (quoteize(*name) * " ")
205
+ when Symbol
206
+ name.to_s
207
+ end
208
+ end
209
+
210
+ # Handle the blockification of a provided block
211
+ def blockify(tag_name, name, &block)
212
+ self << ""
213
+ self << "<#{[ tag_name, blockify_name(name) ].compact * ' '}>"
214
+ @line_indent += 1
215
+ self.instance_eval(&block)
216
+ @line_indent -= 1
217
+ self << "</#{tag_name}>"
218
+ self << ""
219
+ end
220
+
221
+ # Build a string that invokes Apache's rotatelogs command
222
+ def rotatelogs(path, time)
223
+ begin
224
+ time = time.to_i
225
+ rescue
226
+ raise "Time should be an integer: #{path} #{time}"
227
+ end
228
+
229
+ "|#{@rotate_logs_path} #{path} #{time}"
230
+ end
231
+
232
+ private
233
+ def writable?(path)
234
+ puts "[warn] #{path} may not be writable!" if !File.directory? File.split(path).first
235
+ end
236
+
237
+ def directory?(path)
238
+ puts "[warn] #{path} does not exist!" if !File.directory? path
239
+ end
240
+
241
+ def exist?(path)
242
+ puts "[warn] #{path} does not exist!" if !File.exist?(path)
243
+ end
244
+ end
245
+
246
+ block_methods :virtual_host, :location, :files
247
+ end
248
+ end
@@ -0,0 +1,25 @@
1
+ module Apache
2
+ # Methods to handle directory settings
3
+ module Directories
4
+ # Create an Options directive
5
+ #
6
+ # The options passed into this method are Apachified:
7
+ # options :exec_cgi, :follow_sym_links #=> Options ExecCGI FollowSymLinks
8
+ def options(*opt)
9
+ create_options_list('Options', *opt)
10
+ end
11
+
12
+ # Create an IndexOptions directive
13
+ #
14
+ # The options passed into this method are Apachified:
15
+ # index_options :fancy_indexing, :suppress_description #=> IndexOptions FancyIndexing SuppressDescription
16
+ def index_options(*opt)
17
+ create_options_list('IndexOptions', *opt)
18
+ end
19
+
20
+ private
21
+ def create_options_list(tag, *opt)
22
+ self << "#{tag} #{apachify(opt) * " "}"
23
+ end
24
+ end
25
+ end
@@ -0,0 +1,45 @@
1
+ module Apache
2
+ # Methods to handle logging configuration are defined here.
3
+ #
4
+ # For each of the four main log types (Custom, Error, Script, and Rewrite), the following two methods are created:
5
+ #
6
+ # * (type)_log: A non-rotated log file
7
+ # * rotate_(type)_log: A rotated log file
8
+ #
9
+ # Non-rotated logs work as such:
10
+ # custom_log "/path/to/log/file.log", :common #=> CustomLog "/path/to/log/file.log" common
11
+ #
12
+ # Rotated logs work as such:
13
+ # rotate_custom_log "/path/to/log/file-%Y%m%d.log", 86400, :common
14
+ # #=> CustomLog "|/path/to/rotatelogs /path/to/log/file-%Y%m%d.jpg 86400" common
15
+ #
16
+ # Both variations check to make sure the log file diretory exists during generation.
17
+ # The rotate_ variations need @rotate_logs_path set to work.
18
+ module Logging
19
+ [ :custom, :error, :script, :rewrite ].each do |type|
20
+ class_eval <<-EOT
21
+ def #{type}_log(*opts)
22
+ handle_log '#{type.to_s.capitalize}Log', opts.first, quoteize(opts.first), opts[1..-1]
23
+ end
24
+
25
+ def rotate_#{type}_log(*opts)
26
+ handle_log '#{type.to_s.capitalize}Log', opts.first, quoteize(rotatelogs(*opts[0..1])), opts[2..-1]
27
+ end
28
+ EOT
29
+ end
30
+
31
+ def combined_log_format(name = 'combined')
32
+ log_format '%h %l %u %t \"%r\" %>s %b \"%{Referer}i\" \"%{User-Agent}i\"', name.to_sym
33
+ end
34
+
35
+ def common_log_format(name = 'common')
36
+ log_format '%h %l %u %t \"%r\" %>s %b', name.to_sym
37
+ end
38
+
39
+ private
40
+ def handle_log(tag, path, real_path, *opts)
41
+ writable? path
42
+ self << "#{tag} #{[real_path, opts].flatten * " "}"
43
+ end
44
+ end
45
+ end
@@ -0,0 +1,105 @@
1
+ module Apache
2
+ # Options that aren't specific to a particular purpose go here. Once enough like methods for a
3
+ # particular purpose exist, break them out into a separate module.
4
+ module Master
5
+ # Build a module list.
6
+ # Wraps around Modules.build
7
+ def modules(*modules, &block)
8
+ @config += Modules.build(*modules, &block)
9
+ end
10
+
11
+ # Add a User/Group block
12
+ # runner('www', 'www-data') #=>
13
+ # User www
14
+ # Group www-data
15
+ def runner(user, group = nil)
16
+ user! user
17
+ group! group if group
18
+ end
19
+
20
+ # Enable Passenger on this server
21
+ #
22
+ # This assumes that Passenger was installed via the gem. This may or may not work for you, but it works for me.
23
+ def passenger(ruby_root, ruby_version, passenger_version)
24
+ load_module 'passenger_module', "#{ruby_root}/lib/ruby/gems/#{ruby_version}/gems/passenger-#{passenger_version}/ext/apache2/mod_passenger.so"
25
+ passenger_root "#{ruby_root}/lib/ruby/gems/#{ruby_version}/gems/passenger-#{passenger_version}"
26
+ passenger_ruby "#{ruby_root}/bin/ruby"
27
+ end
28
+
29
+ # Enable gzip compression server-wide on pretty much everything that can be gzip compressed
30
+ def enable_gzip!
31
+ directory '/' do
32
+ add_output_filter_by_type! :DEFLATE, 'text/html', 'text/plain', 'text/css', 'text/javascript', 'application/javascript'
33
+ browser_match! '^Mozilla/4', "gzip-only-text/html"
34
+ browser_match! '^Mozilla/4\.0[678]', "no-gzip"
35
+ browser_match! '\bMSIE', '!no-gzip', '!gzip-only-text/html'
36
+ end
37
+ end
38
+
39
+ # Set the TCP timeout. Defined here to get around various other timeout methods.
40
+ def timeout(t)
41
+ self << "Timeout #{t}"
42
+ end
43
+
44
+ # Add a comment to the Apache config. Can pass in either a String or Array of comment lines.
45
+ def comment(c)
46
+ out = [ '' ]
47
+ case c
48
+ when String
49
+ out += c.split("\n")
50
+ when Array
51
+ out += c
52
+ end
53
+ out << ''
54
+ self + out.collect { |line| "# #{line.strip}".strip }
55
+ end
56
+
57
+ # Create a ScriptAlias, checking to make sure the filesystem path exists.
58
+ def script_alias(uri, path)
59
+ directory? path
60
+ self << %{ScriptAlias #{quoteize(uri, path) * ' '}}
61
+ end
62
+
63
+ alias :script_alias! :script_alias
64
+
65
+ # Add a MIME type, potentially also adding handlers and encodings
66
+ # add_type! 'text/html', '.shtml', :handler => 'server-parsed'
67
+ # add_type! 'text/html', '.gz', :encoding => 'gzip'
68
+ def add_type!(mime, extension, options = {})
69
+ self << "AddType #{mime} #{extension}"
70
+ options.each do |type, value|
71
+ self << "Add#{type.to_s.capitalize} #{value} #{extension}"
72
+ end
73
+ end
74
+
75
+ # Include other config files or directories.
76
+ # Used to get around reserved Ruby keyword.
77
+ def apache_include(*opts)
78
+ self << "Include #{opts * " "}"
79
+ end
80
+
81
+ # Alias a URL to a directory in the filesystem.
82
+ # Used to get around reserved Ruby keyword.
83
+ def apache_alias(*opts)
84
+ self << "Alias #{quoteize(*opts) * " "}"
85
+ end
86
+
87
+ # Set multiple headers to be delivered for a particular section
88
+ # set_header 'Content-type' => 'application/octet-stream',
89
+ # 'Content-disposition' => [ 'attachment', 'env=only-for-downloads' ] #=>
90
+ # Header set "Content-type" "application/octet-stream"
91
+ # Header set "Content-dispoaition" "attachment" env=only-for-downloads
92
+ def set_header(hash)
93
+ hash.each do |key, value|
94
+ output = "Header set #{quoteize(key)}"
95
+ case value
96
+ when String, Symbol
97
+ output += " #{quoteize(value)}"
98
+ when Array
99
+ output += " #{quoteize(value.first)} #{value.last}"
100
+ end
101
+ self << output
102
+ end
103
+ end
104
+ end
105
+ end
@@ -0,0 +1,44 @@
1
+ require 'apache/quoteize'
2
+
3
+ module Apache
4
+ # Create lists of modules to load in the Apache 2.2 style (with LoadModule only)
5
+ class Modules
6
+ class << self
7
+ include Apache::Quoteize
8
+
9
+ attr_accessor :modules
10
+
11
+ # Reset the list of modules to output
12
+ def reset!
13
+ @modules = []
14
+ end
15
+
16
+ # Build a block of LoadModule commands
17
+ #
18
+ # Apache::Modules.build(:expires, :headers) do
19
+ # funky "/path/to/funky/module.so"
20
+ # end
21
+ #
22
+ # becomes:
23
+ #
24
+ # LoadModule "expires_module" "modules/mod_expires.so"
25
+ # LoadModule "headers_module" "modules/mod_headers.so"
26
+ # LoadModule "funky_module" "/path/to/funky/module.so"
27
+ def build(*modules, &block)
28
+ reset!
29
+
30
+ modules.each { |m| self.send(m) }
31
+ self.instance_eval(&block) if block
32
+
33
+ [ '' ] + @modules + [ '' ]
34
+ end
35
+
36
+ # The method name becomes the module core name
37
+ def method_missing(method, *args)
38
+ module_name = "#{method}_module"
39
+ module_path = args[0] || "modules/mod_#{method}.so"
40
+ @modules << [ 'LoadModule', *quoteize(module_name, module_path) ] * " "
41
+ end
42
+ end
43
+ end
44
+ end
@@ -0,0 +1,59 @@
1
+ module Apache
2
+ module MPM
3
+ # Set up the Prefork MPM
4
+ #
5
+ # prefork_config do
6
+ # start 5
7
+ # spares 5, 20
8
+ # limit 100
9
+ # clients 100
10
+ # max_requests 1000
11
+ # end
12
+ #
13
+ # becomes:
14
+ #
15
+ # StartServers 5
16
+ # MinSpareServers 5
17
+ # MaxSpareServers 20
18
+ # ServerLimit 100
19
+ # MaxClients 100
20
+ # MaxRequestsPerChild 1000
21
+ #
22
+ def prefork_config(&block)
23
+ self + Apache::MPM::Prefork.build(&block)
24
+ end
25
+
26
+ # Builder for Prefork MPM
27
+ # See Apache::MPM::prefork_config for usage.
28
+ class Prefork
29
+ class << self
30
+ def build(&block)
31
+ @config = ['', '# Prefork config', '']
32
+
33
+ self.instance_eval(&block)
34
+
35
+ @config
36
+ end
37
+
38
+ def method_missing(method, *opts)
39
+ if which = {
40
+ :start => 'StartServers',
41
+ :spares => [ 'MinSpareServers', 'MaxSpareServers' ],
42
+ :limit => 'ServerLimit',
43
+ :clients => 'MaxClients',
44
+ :max_requests => 'MaxRequestsPerChild'
45
+ }[method]
46
+ case which
47
+ when String
48
+ @config << "#{which} #{opts * " "}"
49
+ when Array
50
+ which.each do |w|
51
+ @config << "#{w} #{opts.shift}"
52
+ end
53
+ end
54
+ end
55
+ end
56
+ end
57
+ end
58
+ end
59
+ end
@@ -0,0 +1,22 @@
1
+ module Apache
2
+ # Options to adjust server performance beyond MPM settings
3
+ module Performance
4
+ # Activate KeepAlive, optionally tweaking max requests and timeout
5
+ #
6
+ # activate_keepalive :requests => 100, :timeout => 5 #=>
7
+ # KeepAlive on
8
+ # MaxKeepAliveRequests 100
9
+ # KeepAliveTimeout 5
10
+ def activate_keepalive(options)
11
+ self << "KeepAlive On"
12
+ options.each do |option, value|
13
+ case option
14
+ when :requests
15
+ self << "MaxKeepAliveRequests #{value}"
16
+ when :timeout
17
+ self << "KeepAliveTimeout #{value}"
18
+ end
19
+ end
20
+ end
21
+ end
22
+ end
@@ -0,0 +1,91 @@
1
+ module Apache
2
+ # Configure server access permissions
3
+ module Permissions
4
+ # Shortcut for denying all access to a block
5
+ def deny_from_all
6
+ order :deny, :allow
7
+ deny :from_all
8
+ end
9
+
10
+ alias :deny_from_all! :deny_from_all
11
+
12
+ # Shortcut for allowing all access to a block
13
+ def allow_from_all
14
+ order :allow, :deny
15
+ allow :from_all
16
+ end
17
+
18
+ alias :allow_from_all! :allow_from_all
19
+
20
+ # Define IP block restrictions
21
+ #
22
+ # allow_from '127.0.0.1' #=> Allow from "127.0.0.1"
23
+ def allow_from(*where)
24
+ self << "Allow from #{quoteize(*where) * " "}"
25
+ end
26
+
27
+ # Specify default access order
28
+ #
29
+ # order :allow, :deny #=> Order allow,deny
30
+ def order(*args)
31
+ self << "Order #{args * ','}"
32
+ end
33
+
34
+ alias :order! :order
35
+
36
+ # Set up default restrictive permissions
37
+ def default_restrictive!
38
+ directory '/' do
39
+ options :follow_sym_links
40
+ allow_override :none
41
+ deny_from_all
42
+ end
43
+ end
44
+
45
+ # Block all .ht* files
46
+ def no_htfiles!
47
+ files_match %{^\.ht} do
48
+ deny_from_all
49
+ satisfy :all
50
+ end
51
+ end
52
+
53
+ # Set up basic authentication
54
+ #
55
+ # Check to make sure the defined users_file exists
56
+ #
57
+ # basic_authentication "My secret", '/my.users', 'valid-user' => true
58
+ # basic_authentication "My other secret", '/my.users', :user => [ :john ]
59
+ def basic_authentication(zone, users_file, requires = {})
60
+ exist? users_file
61
+ auth_type :basic
62
+ auth_name zone
63
+ auth_user_file users_file
64
+ requires.each do |type, values|
65
+ apache_require type, *values
66
+ end
67
+ end
68
+
69
+ alias :basic_authentication! :basic_authentication
70
+
71
+ # Set up LDAP authentication
72
+ def ldap_authentication(zone, url, requires = {})
73
+ auth_type :basic
74
+ auth_name zone
75
+ auth_basic_provider :ldap
76
+ authz_ldap_authoritative :on
77
+ auth_ldap_url url
78
+ requires.each do |type, values|
79
+ apache_require type, *values
80
+ end
81
+ end
82
+
83
+ alias :ldap_authentication! :ldap_authentication
84
+
85
+ # Create an Apache require directive.
86
+ # Used to get around Ruby reserved word.
87
+ def apache_require(*opts)
88
+ self << "Require #{opts * " "}"
89
+ end
90
+ end
91
+ end
@@ -0,0 +1,16 @@
1
+ module Apache
2
+ # Add quotes around parameters as needed
3
+ module Quoteize
4
+ # Add quotes around most parameters, and don't add quotes around Symbols
5
+ def quoteize(*args)
6
+ args.collect do |arg|
7
+ case arg
8
+ when Symbol
9
+ arg.to_s.gsub('_', ' ')
10
+ else
11
+ %{"#{arg}"}
12
+ end
13
+ end
14
+ end
15
+ end
16
+ end
@@ -0,0 +1,26 @@
1
+ require 'fileutils'
2
+ require 'apache/config'
3
+ require 'apache/rake/create'
4
+ require 'yaml'
5
+
6
+ namespace :apache do
7
+ desc "Create all defined configs for the specified environment"
8
+ task :create, :environment do |t, args|
9
+ APACHE_ENV = (args[:environment] || 'production').to_sym
10
+
11
+ CONFIG = Hash[YAML.load_file('config.yml').collect { |k,v| [ k.to_sym, v ] }]
12
+
13
+ CONFIG[:source_path] = File.expand_path(CONFIG[:source])
14
+ CONFIG[:dest_path] = File.expand_path(CONFIG[:destination])
15
+
16
+ Apache::Config.rotate_logs_path = CONFIG[:rotate_logs_path]
17
+
18
+ FileUtils.mkdir_p CONFIG[:dest_path]
19
+ Dir.chdir CONFIG[:dest_path]
20
+
21
+ Dir[File.join(CONFIG[:source_path], '**', '*.rb')].each do |file|
22
+ puts file
23
+ require file
24
+ end
25
+ end
26
+ end
@@ -0,0 +1,297 @@
1
+ module Apache
2
+ # Handle the creation of RewriteRules, RewriteConds, Redirects, and RedirectMatches
3
+ module Rewrites
4
+ # Enable the rewrite engine, optionally setting the logging level
5
+ #
6
+ # enable_rewrite_engine :log_level => 1 #=>
7
+ # RewriteEngine on
8
+ # RewriteLogLevel 1
9
+ def enable_rewrite_engine(options)
10
+ self << ''
11
+ rewrite_engine! :on
12
+ options.each do |option, value|
13
+ case option
14
+ when :log_level
15
+ rewrite_log_level! value
16
+ end
17
+ end
18
+ self << ''
19
+ end
20
+
21
+ # Pass the block to RewriteManager.build
22
+ def rewrites(&block)
23
+ self + indent(RewriteManager.build(&block))
24
+ self << ''
25
+ end
26
+
27
+ # Create a permanent Redirect
28
+ #
29
+ # r301 '/here', '/there' #=> Redirect permanent "/here" "/there"
30
+ def r301(*opt)
31
+ self << "Redirect permanent #{quoteize(*opt) * " "}"
32
+ end
33
+ end
34
+
35
+ # Handle the creation of Rewritable things
36
+ class RewriteManager
37
+ class << self
38
+ attr_accessor :rewrites
39
+
40
+ # Reset the current list of rewrites
41
+ def reset!
42
+ @rewrites = []
43
+ end
44
+
45
+ # Build rewritable things from the provided block
46
+ def build(&block)
47
+ reset!
48
+
49
+ self.instance_eval(&block)
50
+
51
+ @rewrites.collect(&:to_a).flatten
52
+ end
53
+
54
+ # Commit the latest rewritable thing to the list of rewrites
55
+ def commit!
56
+ @rewrites << @rewrite
57
+ @rewrite = nil
58
+ end
59
+
60
+ # Ensure that there's a RewriteRule to be worked with
61
+ def ensure_rewrite!
62
+ @rewrite = RewriteRule.new if !@rewrite
63
+ end
64
+
65
+ # Create a RewriteRule with the given options
66
+ #
67
+ # rewrite %r{/here(.*)}, '/there$1', :last => true #=>
68
+ # RewriteRule "/here(.*)" "/there$1" [L]
69
+ def rewrite(*opts)
70
+ ensure_rewrite!
71
+ @rewrite.rule(*opts)
72
+ commit!
73
+ end
74
+
75
+ alias :rule :rewrite
76
+
77
+ # Create a RewriteCond with the given options
78
+ #
79
+ # cond "%{REQUEST_FILENAME}", "^/here" #=>
80
+ # RewriteCond "%{REQUEST_FILENAME}", "^/here"
81
+ def cond(*opts)
82
+ ensure_rewrite!
83
+ @rewrite.cond(*opts)
84
+ end
85
+
86
+ # Create a permanent RedirectMatch
87
+ #
88
+ # r301 %r{/here(.*)}, "/there$1" #=>
89
+ # RedirectMatch permanent "/here(.*)" "/there$1"
90
+ def r301(*opts)
91
+ redirect = RedirectMatchPermanent.new
92
+ redirect.rule(*opts)
93
+
94
+ @rewrites << redirect
95
+ end
96
+
97
+ # Test the rewritable things defined in this block
98
+ def rewrite_test(from, to, opts = {})
99
+ orig_from = from.dup
100
+ @rewrites.each do |r|
101
+ from = r.test(from, opts)
102
+ end
103
+
104
+ if from != to
105
+ puts "[warn] #{orig_from} >> #{to} failed!"
106
+ puts "[warn] Result: #{from}"
107
+ end
108
+ end
109
+ end
110
+ end
111
+
112
+ # Common methods for testing rewritable things that use regular expressions
113
+ module RegularExpressionMatcher
114
+ # Test this rewritable thing
115
+ def test(from, opts = {})
116
+ from = from.gsub(@from, @to.gsub(/\$([0-9])/) { |m| '\\' + $1 })
117
+ replace_placeholders(from, opts)
118
+ end
119
+
120
+ # Replace the placeholders in this rewritable thing
121
+ def replace_placeholders(s, opts)
122
+ opts.each do |opt, value|
123
+ case value
124
+ when String
125
+ s = s.gsub('%{' + opt.to_s.upcase + '}', value)
126
+ end
127
+ end
128
+ s
129
+ end
130
+ end
131
+
132
+ # A matchable thing to be extended
133
+ class MatchableThing
134
+ include Apache::Quoteize
135
+
136
+ # The Apache directive tag for this thing
137
+ def tag; raise 'Override this method'; end
138
+
139
+ def initialize
140
+ @from = nil
141
+ @to = nil
142
+ end
143
+
144
+ def rule(from, to)
145
+ @from = from
146
+ @to = to
147
+ end
148
+
149
+ def to_s
150
+ "#{tag} #{[quoteize(@from), quoteize(@to)].compact.flatten * " "}"
151
+ end
152
+
153
+ def to_a
154
+ [ to_s ]
155
+ end
156
+ end
157
+
158
+ # A RewriteRule definition
159
+ class RewriteRule < MatchableThing
160
+ include RegularExpressionMatcher
161
+
162
+ def tag; 'RewriteRule'; end
163
+
164
+ def initialize
165
+ super
166
+ @conditions = []
167
+ @options = nil
168
+ end
169
+
170
+ # Define the rule, passing in additional options
171
+ #
172
+ # rule %r{^/here}, '/there', { :last => true, :preserve_query_string => true }
173
+ def rule(from, to,options = {})
174
+ super(from, to)
175
+
176
+ raise "from must be a Regexp" if !from.kind_of?(Regexp)
177
+
178
+ options = options.collect do |key, value|
179
+ case key
180
+ when :last
181
+ 'L'
182
+ when :preserve_query_string
183
+ 'QSA'
184
+ end
185
+ end.sort
186
+
187
+ @options = !options.empty? ? "[#{options * ','}]" : nil
188
+ end
189
+
190
+ # Add a RewriteCondition to this RewriteRule
191
+ def cond(from, to, *opts)
192
+ rewrite_cond = RewriteCondition.new
193
+ rewrite_cond.cond(from, to, *opts)
194
+
195
+ @conditions << rewrite_cond
196
+ end
197
+
198
+ def to_s
199
+ "#{tag} #{[quoteize(@from.source), quoteize(@to), @options].compact.flatten * " "}"
200
+ end
201
+
202
+ def to_a
203
+ [ @conditions.collect(&:to_s), super ].flatten
204
+ end
205
+
206
+ # Test this RewriteRule, ensuring the RewriteConds also match
207
+ def test(from, opts = {})
208
+ ok = true
209
+ @conditions.each do |c|
210
+ ok = false if !c.test(from, opts)
211
+ end
212
+
213
+ if ok
214
+ super(from, opts)
215
+ else
216
+ replace_placeholders(from, opts)
217
+ end
218
+ end
219
+ end
220
+
221
+ # A permanent RedirectMatch
222
+ class RedirectMatchPermanent < MatchableThing
223
+ include RegularExpressionMatcher
224
+
225
+ def tag; 'RedirectMatch permanent'; end
226
+
227
+ def rule(from, to)
228
+ super(from, to)
229
+
230
+ raise "from must be a Regexp" if !from.kind_of?(Regexp)
231
+ end
232
+
233
+ def to_s
234
+ "#{tag} #{[quoteize(@from.source), quoteize(@to)].compact.flatten * " "}"
235
+ end
236
+ end
237
+
238
+ # A RewriteCond
239
+ class RewriteCondition < MatchableThing
240
+ include RegularExpressionMatcher
241
+
242
+ def tag; 'RewriteCond'; end
243
+
244
+ # Define a RewriteCond
245
+ #
246
+ # rule "%{REQUEST_FILENAME}", "^/here", :case_insensitive #=>
247
+ # RewriteCond "%{REQUEST_FILENAME}" "^/here" [NC]
248
+ def rule(from, to, *opts)
249
+ super(from, to)
250
+
251
+ options = opts.collect do |opt|
252
+ case opt
253
+ when :or
254
+ 'OR'
255
+ when :case_insensitive
256
+ 'NC'
257
+ when :no_vary
258
+ 'NV'
259
+ end
260
+ end
261
+
262
+ @options = (!options.empty?) ? "[#{options * ','}]" : nil
263
+ end
264
+
265
+ alias :cond :rule
266
+
267
+ def initialize
268
+ super
269
+ @options = nil
270
+ end
271
+
272
+ def to_s
273
+ "#{tag} #{[quoteize(@from), quoteize(@to), @options].compact.flatten * " "}"
274
+ end
275
+
276
+ # Test this RewriteCond
277
+ def test(from, opts = {})
278
+ super(from, opts)
279
+ source = replace_placeholders(@from, opts)
280
+
281
+ result = false
282
+ case @to[0..0]
283
+ when '!'
284
+ result = !source[Regexp.new(@to[1..-1])]
285
+ when '-'
286
+ case @to
287
+ when '-f'
288
+ result = opts[:files].include? source if opts[:files]
289
+ end
290
+ else
291
+ result = source[Regexp.new(@to)]
292
+ end
293
+
294
+ result
295
+ end
296
+ end
297
+ end
data/lib/apache/ssl.rb ADDED
File without changes
data/skel/Rakefile ADDED
@@ -0,0 +1,3 @@
1
+ require 'rubygems'
2
+
3
+ require 'apache/rake/create'
data/skel/config.yml ADDED
@@ -0,0 +1,3 @@
1
+ source: "source"
2
+ destination: "conf.d"
3
+ rotate_logs_path: '/path/to/apache/bin/rotatelogs'
metadata ADDED
@@ -0,0 +1,102 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: apache-config-generator
3
+ version: !ruby/object:Gem::Version
4
+ prerelease: false
5
+ segments:
6
+ - 0
7
+ - 1
8
+ version: "0.1"
9
+ platform: ruby
10
+ authors:
11
+ - John Bintz
12
+ autorequire:
13
+ bindir: bin
14
+ cert_chain: []
15
+
16
+ date: 2010-05-10 00:00:00 -04:00
17
+ default_executable:
18
+ dependencies: []
19
+
20
+ description: A Ruby DSL for programmatically generating Apache configs
21
+ email: ""
22
+ executables:
23
+ - apache-configurator
24
+ extensions: []
25
+
26
+ extra_rdoc_files:
27
+ - CHANGELOG
28
+ - README.md
29
+ - bin/apache-configurator
30
+ - lib/apache.rb
31
+ - lib/apache/config.rb
32
+ - lib/apache/directory.rb
33
+ - lib/apache/logging.rb
34
+ - lib/apache/master.rb
35
+ - lib/apache/modules.rb
36
+ - lib/apache/mpm_prefork.rb
37
+ - lib/apache/performance.rb
38
+ - lib/apache/permissions.rb
39
+ - lib/apache/quoteize.rb
40
+ - lib/apache/rake/create.rb
41
+ - lib/apache/rewrites.rb
42
+ - lib/apache/ssl.rb
43
+ files:
44
+ - CHANGELOG
45
+ - Manifest
46
+ - README.md
47
+ - Rakefile
48
+ - bin/apache-configurator
49
+ - lib/apache.rb
50
+ - lib/apache/config.rb
51
+ - lib/apache/directory.rb
52
+ - lib/apache/logging.rb
53
+ - lib/apache/master.rb
54
+ - lib/apache/modules.rb
55
+ - lib/apache/mpm_prefork.rb
56
+ - lib/apache/performance.rb
57
+ - lib/apache/permissions.rb
58
+ - lib/apache/quoteize.rb
59
+ - lib/apache/rake/create.rb
60
+ - lib/apache/rewrites.rb
61
+ - lib/apache/ssl.rb
62
+ - skel/Rakefile
63
+ - skel/config.yml
64
+ - apache-config-generator.gemspec
65
+ has_rdoc: true
66
+ homepage: ""
67
+ licenses: []
68
+
69
+ post_install_message:
70
+ rdoc_options:
71
+ - --line-numbers
72
+ - --inline-source
73
+ - --title
74
+ - Apache-config-generator
75
+ - --main
76
+ - README.md
77
+ require_paths:
78
+ - lib
79
+ required_ruby_version: !ruby/object:Gem::Requirement
80
+ requirements:
81
+ - - ">="
82
+ - !ruby/object:Gem::Version
83
+ segments:
84
+ - 0
85
+ version: "0"
86
+ required_rubygems_version: !ruby/object:Gem::Requirement
87
+ requirements:
88
+ - - ">="
89
+ - !ruby/object:Gem::Version
90
+ segments:
91
+ - 1
92
+ - 2
93
+ version: "1.2"
94
+ requirements: []
95
+
96
+ rubyforge_project: apache-config-generator
97
+ rubygems_version: 1.3.6
98
+ signing_key:
99
+ specification_version: 3
100
+ summary: A Ruby DSL for programmatically generating Apache configs
101
+ test_files: []
102
+