Statistics
| Branch: | Tag: | Revision:

root / doc / design-http-server.rst @ fc6075dd

History | View | Annotate | Download (5.4 kB)

1
=========================================
2
Design for replacing Ganeti's HTTP server
3
=========================================
4

    
5
.. contents:: :depth: 4
6

    
7
.. _http-srv-shortcomings:
8

    
9
Current state and shortcomings
10
------------------------------
11

    
12
The :doc:`new design for import/export <design-impexp2>` depends on an
13
HTTP server. Ganeti includes a home-grown HTTP server based on Python's
14
``BaseHTTPServer``. While it served us well so far, it only implements
15
the very basics of the HTTP protocol. It is, for example, not structured
16
well enough to support chunked transfers (:rfc:`2616`, section 3.6.1),
17
which would have some advantages. In addition, it has not been designed
18
for sending large responses.
19

    
20
In the case of the node daemon the HTTP server can not easily be
21
separated from the actual backend code and therefore must run as "root".
22
The RAPI daemon does request parsing in the same process as talking to
23
the master daemon via LUXI.
24

    
25

    
26
Proposed changes
27
----------------
28

    
29
The proposal is to start using a full-fledged HTTP server in Ganeti and
30
to run Ganeti's code as `FastCGI <http://www.fastcgi.com/>`_
31
applications. Reasons:
32

    
33
- Simplify Ganeti's code by delegating the details of HTTP and SSL to
34
  another piece of software
35
- Run HTTP frontend and handler backend as separate processes and users
36
  (esp. useful for node daemon, but also import/export and Remote API)
37
- Allows implementation of :ref:`rpc-feedback`
38

    
39

    
40
Software choice
41
+++++++++++++++
42

    
43
Theoretically any server able of speaking FastCGI to a backend process
44
could be used. However, to keep the number of steps required for setting
45
up a new cluster at roughly the same level, the implementation will be
46
geared for one specific HTTP server at the beginning. Support for other
47
HTTP servers can still be implemented.
48

    
49
After a rough selection of available HTTP servers `lighttpd
50
<http://www.lighttpd.net/>`_ and `nginx <http://www.nginx.org/>`_ were
51
the most likely candidates. Both are `widely used`_ and tested.
52

    
53
.. _widely used: http://news.netcraft.com/archives/2011/01/12/
54
  january-2011-web-server-survey-4.html
55

    
56
Nginx' `original documentation <http://sysoev.ru/nginx/docs/>`_ is in
57
Russian, translations are `available in a Wiki
58
<http://wiki.nginx.org/>`_. Nginx does not support old-style CGI
59
programs.
60

    
61
The author found `lighttpd's documentation
62
<http://redmine.lighttpd.net/wiki/lighttpd>`_ easier to understand and
63
was able to configure a test server quickly. This, together with the
64
support for more technologies, made deciding easier.
65

    
66
With its use as a public-facing web server on a large number of websites
67
(and possibly more behind proxies), lighttpd should be a safe choice.
68
Unlike other webservers, such as the Apache HTTP Server, lighttpd's
69
codebase is of manageable size.
70

    
71
Initially the HTTP server would only be used for import/export
72
transfers, but its use can be expanded to the Remote API and node
73
daemon (see :ref:`rpc-feedback`).
74

    
75
To reduce the attack surface, an option will be provided to configure
76
services (e.g. import/export) to only listen on certain network
77
interfaces.
78

    
79

    
80
.. _rpc-feedback:
81

    
82
RPC feedback
83
++++++++++++
84

    
85
HTTP/1.1 supports chunked transfers (:rfc:`2616`, section 3.6.1). They
86
could be used to provide feedback from node daemons to the master,
87
similar to the feedback from jobs. A good use would be to provide
88
feedback to the user during long-running operations, e.g. downloading an
89
instance's data from another cluster.
90

    
91
.. _requirement: http://www.python.org/dev/peps/pep-0333/
92
  #buffering-and-streaming
93

    
94
WSGI 1.0 (:pep:`333`) includes the following `requirement`_:
95

    
96
  WSGI servers, gateways, and middleware **must not** delay the
97
  transmission of any block; they **must** either fully transmit the
98
  block to the client, or guarantee that they will continue transmission
99
  even while the application is producing its next block
100

    
101
This behaviour was confirmed to work with lighttpd and the
102
:ref:`flup <http-software-req>` library. FastCGI by itself has no such
103
guarantee; webservers with buffering might require artificial padding to
104
force the message to be transmitted.
105

    
106
The node daemon can send JSON-encoded messages back to the master daemon
107
by separating them using a predefined character (see :ref:`LUXI
108
<luxi>`). The final message contains the method's result. pycURL passes
109
each received chunk to the callback set as ``CURLOPT_WRITEFUNCTION``.
110
Once a message is complete, the master daemon can pass it to a callback
111
function inside the job, which then decides on what to do (e.g. forward
112
it as job feedback to the user).
113

    
114
A more detailed design may have to be written before deciding whether to
115
implement RPC feedback.
116

    
117

    
118
.. _http-software-req:
119

    
120
Software requirements
121
+++++++++++++++++++++
122

    
123
- lighttpd 1.4.24 or above built with OpenSSL support (earlier versions
124
  `don't support SSL client certificates
125
  <http://redmine.lighttpd.net/issues/1288>`_)
126
- `flup <http://trac.saddi.com/flup>`_ for FastCGI
127

    
128

    
129
Lighttpd SSL configuration
130
++++++++++++++++++++++++++
131

    
132
.. highlight:: lighttpd
133

    
134
The following sample shows how to configure SSL with client certificates
135
in Lighttpd::
136

    
137
  $SERVER["socket"] == ":443" {
138
    ssl.engine = "enable"
139
    ssl.pemfile = "server.pem"
140
    ssl.ca-file = "ca.pem"
141
    ssl.use-sslv2  = "disable"
142
    ssl.cipher-list = "HIGH:-DES:-3DES:-EXPORT:-ADH"
143
    ssl.verifyclient.activate = "enable"
144
    ssl.verifyclient.enforce = "enable"
145
    ssl.verifyclient.exportcert = "enable"
146
    ssl.verifyclient.username = "SSL_CLIENT_S_DN_CN"
147
  }
148

    
149

    
150
.. vim: set textwidth=72 :
151
.. Local Variables:
152
.. mode: rst
153
.. fill-column: 72
154
.. End: