apache-config-generator 0.1

Sign up to get free protection for your applications and to get access to all the features.
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
+