apache.rb 7.14 KB
Newer Older
1
2
3
4
5
require 'symbiosis/config_file'
require 'tempfile'

module Symbiosis
  module ConfigFiles
6
    class Apache < Symbiosis::ConfigFile
7
8

      #
9
10
      # Tests the file using Apache and a temporary file.  Returns true if
      # apache2 deems the snippet OK.
11
12
13
14
15
16
17
18
      #
      def ok?
        return false unless File.executable?("/usr/sbin/apache2")

        output = []

        config = self.generate_config(self.template)

19
        tempfile = Tempfile.new(File.basename(self.filename))
20
        tempfile.puts(config)
21
        tempfile.close(false)
22
23
24

        IO.popen( "/usr/sbin/apache2 -C 'UseCanonicalName off' -C 'Include /etc/apache2/mods-enabled/*.load' -C 'Include /etc/apache2/mods-enabled/*.conf' -f #{tempfile.path} -t 2>&1 ") {|io| output = io.readlines }

25
        if "Syntax OK" == output.last.chomp
26
          warn output.collect{|o| "\t"+o}.join.chomp if $VERBOSE
27
28
29
          tempfile.unlink
          return true
        else
30
          warn output.collect{|o| "\t"+o}.join.chomp
31
32
33
34
          File.rename(tempfile.path, tempfile.path+".conf")
          warn "\tTemporary config snippet retained at #{tempfile.path}.conf"
          return false
        end
35
36
37
38
39
      end


      #
      # This checks a site has its config file linked into the sites-enabled
40
41
42
43
      # directory.  If no filename has been specified, it defaults to
      # self.filename with "sites-available" transformed to "sites-enabled".
      #
      # This function returns true if self.filename is symlinked to fn.
44
45
46
      #
      def enabled?(fn = nil)

47
48
        fn = self.filename.sub("sites-available","sites-enabled") if fn.nil?

49
50
51
52
        #
        # Make sure the file exists, and that it is a symlink pointing to our
        # config file
        #
53
54
55
56
57
58
59
60
        if File.symlink?(fn) 
          ln = File.readlink(fn)

          unless ln =~ /^\//
            ln = File.join(File.dirname(fn),ln)
          end

          return File.expand_path(ln) == self.filename
61
62
63
64
65
66
67
68
69
70
71
72
73
74
        end

        #
        # FIXME: should probably check at this point to see if any files point
        # back to the config, or if any file contains the configuration for
        # this domain.
        #

        #
        # Otherwise return false
        #
        false
      end

75
76
77
78
79
80
81
82
83
      #
      # This enables a site by symlinking the self.filename to fn.
      #
      # If fn is not specified, then self.filename is used, with
      # sites-available changed to sites-enabled.
      #
      # If the force flag is set to true, then any file in the way is removed
      # first.
      #
84
85
86
87
88
      def enable(fn = nil, force = false)
        #
        # Take the filename and and replace available with enabled if no
        # filename is given.
        #
89
90
        fn = self.filename.sub("sites-available","sites-enabled") if fn.nil?

91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
        #
        # Do nothing if we're already enabled.
        #
        return if self.enabled?(fn)

        #
        # Clobber any files in the way, if the force flag is set.
        #
        if force and File.exists?(fn)
          File.unlink(fn)
        end

        #
        # If the file is still there after disabling, raise an error
        #
        raise Errno::EEXIST, fn if File.exists?(fn)

        #
        # Symlink away!
        #
        File.symlink(self.filename, fn)
        
        nil
114
115
      end

116
117
118
119
120
121
      #
      # This disables a site whose configuration is contained in fn.  This
      # function makes sure that the site is enabled, before disabling it.
      # 
      # 
      #
122
123
124
125
126
      def disable(fn = nil, force = false)
        #
        # Take the filename and and replace available with enabled if no
        # filename is given.
        #
127
128
        fn = self.filename.sub("sites-available","sites-enabled") if fn.nil?

129
130
131
132
133
134
135
136
137
138
139
140
141
142
        #
        # Remove the file, only if it is a symlink to our filename, or if the
        # force flag is set.
        #
        if self.enabled?(fn) or (File.exists?(fn) and force)
          File.unlink(fn)
        end

        #
        # If the file is still there after disabling, raise an error
        #
        raise Errno::EEXIST, fn if File.exists?(fn)

        nil
143
144
145
      end

      #
146
147
148
      # Returns an array of Symbiosis::IPAddr objects, one for each IP
      # available for this domain, if defined, or the system's primary IPv4 and
      # IPv6 addresses.
149
      #
150
151
152
153
154
155
156
      def available_ips
        if defined? @domain and @domain.is_a?(Symbiosis::Domain)
          @domain.ips
        else
          [Symbiosis::Host.primary_ipv4, Symbiosis::Host.primary_ipv6].compact
        end
      end
157
158

      #
159
      # Return all the IPs as apache-compatible strings for use in templates.
160
161
      #
      def ips
162
        self.available_ips.collect do |ip|
163
164
165
166
167
168
169
170
171
          if ip.ipv6?
            "["+ip.to_s+"]"
          else
            ip.to_s
          end
        end
      end

      #
172
      # Return just the first IP for use in templates.
173
174
      #
      def ip
175
176
        ip = self.available_ips.first
        warn "\tUsing one IP (#{ip}) where the domain has more than one configured!" if self.available_ips.length > 1 and $VERBOSE
177
178
179
180
181
182
183
184
185
186
        if ip.ipv6?
          "["+ip.to_s+"]"
        else
          ip.to_s
        end
      end

      #
      # Return the domain config directory.
      #
187
188
      # If no domain has been defined, nil is returned.
      #
189
      def domain_directory
190
191
192
193
194
        if defined?(@domain) and @domain.is_a?(Symbiosis::Domain) 
          @domain.directory
        else
          nil
        end
195
196
      end

197
198
199
200
201
202
203
204
      #
      #
      # Return a ServerAlias snippet for all server aliases for a domain.
      #
      def server_aliases
        domain.aliases.collect{|a| "ServerAlias #{a}"}.join("\n        ")
      end

205
      #
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
      # Returns the certificate, key, and bundle configuration lines.
      #
      def ssl_config
        ans = []
        if defined?(@domain) and @domain.is_a?(Symbiosis::Domain) 
          unless @domain.ssl_certificate_file and @domain.ssl_key_file
            ans << "SSLCertificateFile #{@domain.ssl_certificate_file}"
            #
            # Add the separate key unless the key is in the certificate. 
            #
            ans << "SSLCertificateKeyFile #{@domain.ssl_key_file}" unless @domain.ssl_certificate_file == @domain.ssl_key_file
            #
            # Add a bundle, if needed.
            #
            ans << "SSLCertificateChainFile #{@domain.ssl_bundle_file}" if @domain.ssl_bundle_file
          end
        elsif File.exists?("/etc/ssl/ssl.crt")
          #
          # TODO: this makes absolutely no checks for the certificate validity
          # etc., unlike the @domain functions above.
          #
          ans << "SSLCertificateFile /etc/ssl/ssl.crt"
          #
          # Add the key and bundle, assuming they exist.
          #
          ans << "SSLCertificateKeyFile /etc/ssl/ssl.key" if File.exists?("/etc/ssl/ssl.key")
          ans << "SSLCertificateChainFile /etc/ssl/ssl.bundle" if File.exists?("/etc/ssl/ssl.bundle")
233
        end
234
235

        ans.join("\n        ")
236
237
238
      end

      #
239
240
241
      # Checks to see if a domain has mandatory ssl.
      #
      # If no domain is set, then this returns false.
242
243
      #
      def mandatory_ssl?
244
245
246
247
248
        if defined?(@domain) and @domain.is_a?(Symbiosis::Domain) 
          @domain.ssl_mandatory?
        else
          false
        end
249
250
      end

251
252
253
254
255
    end
  end
end