This page is READ-ONLY. It is generated from the old site.
All timestamps are relative to 2013 (when this page is generated).
If you are looking for TeX support, please go to VietTUG.org

chef-api-server as a nginx's back-end

Oh, love will never lie
Added by icy almost 2 years ago  »  Votes: 1/1

Thanks to coderanger on #chef

Keywords: chef, merb, ruby

Update 2011/July/21: The problem doesn't happen with Chef-0.10.2. Please ignore this post if you are using Chef-0.10.2 or higher.

If Chef API server is served as a nginx's back-end, you may get trouble when uploading cookbooks to the server. In the following logs, the debug messages show that knife receives wrong location of server api after its PUT action (see line 8 and line 11):

 1 $ knife cookbook upload chef-client -l debug
 2 DEBUG: Using configuration from /home/pi/.chef/knife.rb
 3 INFO: Saving chef-client
 4 ....
 5 DEBUG: Generated /var/chef-repo/cookbooks/chef-client/metadata.json
 6 DEBUG: Signing the request as pi
 7 DEBUG: Sending HTTP Request via POST to 10.0.0.94:81//sandboxes      # good, knife knows the server's address
 8 INFO: Uploading files                                                # good, knife has just received the response from server
 9 INFO: Uploading /var/chef-repo/cookbooks/chef-client/....
10   (checksum hex = ...) to http://127.0.0.1:4000/sandboxes/....       # bad, the response from server is wrong

The configuration which causes this problem is as below

  1. The Knife is used on another host (it's my laptop!)
  2. Chef api server is started by chef-server -e production -d on the host 10.0.0.94. Chef API will listen on the port 4000 which is inaccessible from my laptop (this is due to firewall).
  3. Nginx is used as a front-end for chef api server, and it is running on the same host as Chef API server. nginx will serve Chef API on the port :81. The configuration is
     1 server {
     2   listen     10.0.0.94:81;
     3   access_log logs/chef-api.acces.log;
     4   error_log  logs/chef-api.error.log;
     5   location   /  {
     6     proxy_pass       http://127.0.0.1:4000;
     7     proxy_redirect   default;
     8   }
     9 }
    
  4. A simple digram may help to explain the configuration
       Knife --> 10.0.0.94:81 (nginx) --> 127.0.0.1:4000 (chef api server)
    

So, the configuration proxy_redirect doesn't work as expected. In the source code of sandboxes.rb, the definition of the method create shows that

1   def create
2     # ...
3     # construct successful response
4     self.status = 201
5     location = absolute_url(:sandbox, :sandbox_id => new_sandbox.guid)
6     headers['Location'] = location
7     # ...
8   end

The function absolute_url is invoked to constructe the response header. This function is defined in Merb core library

 1     def absolute_url(*args)
 2       # FIXME: arrgh, why request.protocol returns http://?
 3       # :// is not part of protocol name
 4       options  = extract_options_from_args!(args) || {}
 5       protocol = options.delete(:protocol)
 6       host     = options.delete(:host)
 7       # ...    
 8       protocol + "://" + host + url(*args)
 9     end

Arrgh, there is still a FIXME :) But it isn't related to our problem. As you can see in the code, the host is detected from :host. I don't know where its value is got in Merb, but nginx can help to overwrite it easily:

 1 server {
 2   listen     10.0.0.94:81;
 3   access_log logs/chef-api.acces.log;
 4   error_log  logs/chef-api.error.log;
 5   location   /  {
 6     proxy_pass       http://127.0.0.1:4000;
 7     proxy_redirect   default;               # This should have worked :(
 8     proxy_set_header Host 10.0.0.94:81;     # This work! This tricks Merb!
 9   }
10 }

This seems to be buggy: The host shouldn't contain the port (:81 here). But I don't care: At least my Chef works :))


Comments