SUGGESTION - ssl-load-extra-files - private key name resolution
Hi, I posted this on the discourse haproxy forum and was asked to post it here for better visibility : We recently switched to haproxy 2.2.2 and we encountered a problem with the flexibility of ssl-load-extra-files. The way we handle certs is as follows: Public key name is : fqdn.pem Private key name is : fqdn.key Which resulted in No Private Key found in '/etc/pki/tls/certs/fqdn.pem' or /etc/pki/tls/certs/fqdn.pem.key I think it would be interesting if that directive was a little smarter in the way it deals with file extensions and also tried to strip the extension from the filename to see if the .key file exists with the same name. Not sure how that would affect performance for HaProxy startup, but for the moment, we either need to completely revamp the way we deploy certs, or create a symlink for the key file, to .pem.key in the same directory if we want to use this feature. SSL-LOAD-EXTRA-FILES is an excellent feature we’ve been waiting for as it simplifies our cert deployment, but in its current form It’s not really usable for us. Thank you. -- Marc-Antoine Leclercq
Re: Using sockets from Lua
Great, no more segfault ! Tx a lot ;) On Tue, 25 Aug 2015 18:28:31 +0200, Willy Tarreau w...@1wt.eu wrote : On Tue, Aug 25, 2015 at 05:27:59PM +0200, Thierry FOURNIER wrote: Hello, Thank you for the bug repport. It is fixed in the current developpment version. You must compile from sources or wait for the next dev release. Actually, the function txn.close() causes a segfault, it will be fixed in a few time. I just merged your temporary fix, Thierry, so the segfault is supposed to be gone. CCing Marc-Antoine and Cyril on this. In the mean time, guys, please don't add code after txn.close(), as it more or less expects to be final. In all your examples it was already fine, but if we manage to enforce it to be final, you'll get less surprizes later :-) Thanks, Willy -- Marc-Antoine
Re: ocsp
Hi, i did tests you want. see below for answers. On Mon, 20 Jul 2015 17:42:03 +0200, Lukas Tribus luky...@hotmail.com wrote : Hi Lukas, frontend cluster:443 bind 1.2.3.4:443 ssl strict-sni crt /home/provisionning/0.pem crt /home/provisionning/cluster.d default_backend cluster capture request header Host len 255 Can you confirm there is no SSL intercepting device in front of the webserver, like hardware firewalls/UTM and whatnot? yes Could you try with just a single certificate (single crt config pointing to a single certificate file, not a directory)? yes it works fine with crt pointing to a signe certificate file. Can you make the openssl tests from the server, connecting locally without any intermediate devices? i did and results are the same. Regards, Thanks, Lukas -- Marc-Antoine
Re: segfault in src/buffer.c
Hi Thierry, using lua file and cfg file i provided in my two first mails and lastest source, you should get segault when doing : # curl http://127.0.0.1 -H X-debug-me: yes Regards, On Tue, 18 Aug 2015 12:33:40 +0200, Thierry t...@thierry.1s.fr wrote : Hi, How can I reproduce the segfault ? Thierry On Mon, 17 Aug 2015 15:00:25 +0200 Marc-Antoine marc-antoine.b...@ovh.net wrote: Hi, Cyril, as you said, if removed txn:close() from the lua script, I don't get segfault anymore. I noticed that if I removed default_backend line from frontend declaration, segfault does not happen even with txn:close() in lua script : frontend fe:80 bind 127.0.0.1:80 acl debugme req.hdr_cnt(X-debug-me) ge 1 http-request lua mirror if debugme #default_backend be Regards, On Sat, 15 Aug 2015 23:56:57 +0200, Cyril Bonté cyril.bo...@free.fr wrote : Hi Marc-Antoine, Le 12/08/2015 19:01, Marc-Antoine a écrit : I forgot lua file content : # cat mylua.lua -- a simple mirror web server -- it generates a response whose body contains the requests headers function mirror(txn) (...) txn:close() end This is the call which produce a segfault later, combined with the haproxy configuration. I give more details below. Marc-Antoine marc-antoine.b...@ovh.net wrote : (...) defaults modehttp (...) frontend fe:80 bind 127.0.0.1:80 acl debugme req.hdr_cnt(X-debug-me) ge 1 http-request lua mirror if debugme default_backend be It looks that currently, mode http doesn't allow a call to txn:close(). To extend the issue, txn:close() won't work for a proxy in HTTP mode for both : http-request lua tcp-request content lua This is due to the stream processing which still execute some request analyzers even if the lua code sends a response and asks to close the transaction. I haven't looked at the code enough yet, but maybe we should try to find a way to notify haproxy to stop the processing once txn:close() is called. This also explains some other segfaults reported in the past : http://comments.gmane.org/gmane.comp.web.haproxy/21136 -- Marc-Antoine -- Marc-Antoine
Re: segfault in src/buffer.c
Hi, Cyril, as you said, if removed txn:close() from the lua script, I don't get segfault anymore. I noticed that if I removed default_backend line from frontend declaration, segfault does not happen even with txn:close() in lua script : frontend fe:80 bind 127.0.0.1:80 acl debugme req.hdr_cnt(X-debug-me) ge 1 http-request lua mirror if debugme #default_backend be Regards, On Sat, 15 Aug 2015 23:56:57 +0200, Cyril Bonté cyril.bo...@free.fr wrote : Hi Marc-Antoine, Le 12/08/2015 19:01, Marc-Antoine a écrit : I forgot lua file content : # cat mylua.lua -- a simple mirror web server -- it generates a response whose body contains the requests headers function mirror(txn) (...) txn:close() end This is the call which produce a segfault later, combined with the haproxy configuration. I give more details below. Marc-Antoine marc-antoine.b...@ovh.net wrote : (...) defaults modehttp (...) frontend fe:80 bind 127.0.0.1:80 acl debugme req.hdr_cnt(X-debug-me) ge 1 http-request lua mirror if debugme default_backend be It looks that currently, mode http doesn't allow a call to txn:close(). To extend the issue, txn:close() won't work for a proxy in HTTP mode for both : http-request lua tcp-request content lua This is due to the stream processing which still execute some request analyzers even if the lua code sends a response and asks to close the transaction. I haven't looked at the code enough yet, but maybe we should try to find a way to notify haproxy to stop the processing once txn:close() is called. This also explains some other segfaults reported in the past : http://comments.gmane.org/gmane.comp.web.haproxy/21136 -- Marc-Antoine
ECC certificate
Hi all, i'm trying to use an ECC certificate under haproxy without success : * haproxy -vv HA-Proxy version 1.5.8 2014/10/31 Copyright 2000-2014 Willy Tarreau w...@1wt.eu Build options : TARGET = linux2628 CPU = generic CC = gcc CFLAGS = -g -O2 -fstack-protector --param=ssp-buffer-size=4 -Wformat -Werror=format-security -D_FORTIFY_SOURCE=2 OPTIONS = USE_ZLIB=1 USE_OPENSSL=1 USE_PCRE=1 Default settings : maxconn = 2000, bufsize = 16384, maxrewrite = 8192, maxpollevents = 200 Encrypted password support via crypt(3): yes Built with zlib version : 1.2.7 Compression algorithms supported : identity, deflate, gzip Built with OpenSSL version : OpenSSL 1.0.1e 11 Feb 2013 Running on OpenSSL version : OpenSSL 1.0.1e 11 Feb 2013 OpenSSL library supports TLS extensions : yes OpenSSL library supports SNI : yes OpenSSL library supports prefer-server-ciphers : yes Built with PCRE version : 8.30 2012-02-04 PCRE library supports JIT : no (USE_PCRE_JIT not set) Built with transparent proxy support using: IP_TRANSPARENT IPV6_TRANSPARENT IP_FREEBIND Available polling systems : epoll : pref=300, test result OK poll : pref=200, test result OK select : pref=150, test result OK Total: 3 (3 usable), will use epoll. * conf : global ssl-default-bind-ciphers kEECDH+aRSA+AES:kRSA+AES:+AES256:!kEDH:!LOW:!EXP:!MD5:!RC4:!aNULL:!eNULL ssl-default-bind-options no-sslv3 frontend cluster2:443 bind 1.2.3.4:443 ssl strict-sni crt /home/provisionning/0.pem crt /home/provisionning/cluster2.d default_backend cluster2 any idea ? -- Marc-Antoine
Re: ECC certificate
Hi, it jus added kEECDH+aECDSA+AES in front on my cipher list and it works fine ! tx Regards, On Wed, 12 Aug 2015 11:33:15 +0200, Robin Geuze rob...@transip.nl wrote : ECC certs don't work with your keychain since it only contains RSA based ciphers and not ecdsa based ones. Baptiste wrote on 8/12/2015 11:29: On Wed, Aug 12, 2015 at 11:22 AM, Marc-Antoine marc-antoine.b...@ovh.net wrote: Hi all, i'm trying to use an ECC certificate under haproxy without success : * haproxy -vv HA-Proxy version 1.5.8 2014/10/31 Copyright 2000-2014 Willy Tarreau w...@1wt.eu Build options : TARGET = linux2628 CPU = generic CC = gcc CFLAGS = -g -O2 -fstack-protector --param=ssp-buffer-size=4 -Wformat -Werror=format-security -D_FORTIFY_SOURCE=2 OPTIONS = USE_ZLIB=1 USE_OPENSSL=1 USE_PCRE=1 Default settings : maxconn = 2000, bufsize = 16384, maxrewrite = 8192, maxpollevents = 200 Encrypted password support via crypt(3): yes Built with zlib version : 1.2.7 Compression algorithms supported : identity, deflate, gzip Built with OpenSSL version : OpenSSL 1.0.1e 11 Feb 2013 Running on OpenSSL version : OpenSSL 1.0.1e 11 Feb 2013 OpenSSL library supports TLS extensions : yes OpenSSL library supports SNI : yes OpenSSL library supports prefer-server-ciphers : yes Built with PCRE version : 8.30 2012-02-04 PCRE library supports JIT : no (USE_PCRE_JIT not set) Built with transparent proxy support using: IP_TRANSPARENT IPV6_TRANSPARENT IP_FREEBIND Available polling systems : epoll : pref=300, test result OK poll : pref=200, test result OK select : pref=150, test result OK Total: 3 (3 usable), will use epoll. * conf : global ssl-default-bind-ciphers kEECDH+aRSA+AES:kRSA+AES:+AES256:!kEDH:!LOW:!EXP:!MD5:!RC4:!aNULL:!eNULL ssl-default-bind-options no-sslv3 frontend cluster2:443 bind 1.2.3.4:443 ssl strict-sni crt /home/provisionning/0.pem crt /home/provisionning/cluster2.d default_backend cluster2 any idea ? -- Marc-Antoine Hi, Might be related to your Openssl version :/ Baptiste -- Marc-Antoine
[SPAM] segfault in src/buffer.c
### HTTP ### frontend fe:80 bind 127.0.0.1:80 acl debugme req.hdr_cnt(X-debug-me) ge 1 http-request lua mirror if debugme default_backend be frontend fe:443 bind 127.0.0.1:443 ssl crt /etc/ssl/private default_backend be backend be server s1 127.0.0.2 server s2 127.0.0.3 server s3 127.0.0.4 Regards, -- Marc-Antoine
Re: [SPAM] segfault in src/buffer.c
I forgot lua file content : # cat mylua.lua -- a simple mirror web server -- it generates a response whose body contains the requests headers function mirror(txn) local buffer = local response = local mydate = txn.sc:http_date(txn.f:date()) buffer = buffer .. You sent the following headers\r\n buffer = buffer .. ===\r\n buffer = buffer .. txn.req:dup() buffer = buffer .. ===\r\n response = response .. HTTP/1.0 200 OK\r\n response = response .. Server: haproxy-lua/mirror\r\n response = response .. Content-Type: text/html\r\n response = response .. Date: .. mydate .. \r\n response = response .. Content-Length: .. buffer:len() .. \r\n response = response .. Connection: close\r\n response = response .. \r\n response = response .. buffer txn.res:send(response) txn:close() end On Wed, 12 Aug 2015 18:57:50 +0200, Marc-Antoine marc-antoine.b...@ovh.net wrote : Hi, i try to test lua in haproxy and i got segfault while doing curl request : # curl http://127.0.0.1 -H X-debug-me: yes curl: (52) Empty reply from server --- # gdb ./haproxy GNU gdb (GDB) 7.4.1-debian Copyright (C) 2012 Free Software Foundation, Inc. License GPLv3+: GNU GPL version 3 or later http://gnu.org/licenses/gpl.html This is free software: you are free to change and redistribute it. There is NO WARRANTY, to the extent permitted by law. Type show copying and show warranty for details. This GDB was configured as x86_64-linux-gnu. For bug reporting instructions, please see: http://www.gnu.org/software/gdb/bugs/... Reading symbols from /root/haproxy/haproxy...done. (gdb) run -f /etc/haproxy/haproxy.cfg -db Starting program: /root/haproxy/haproxy -f /etc/haproxy/haproxy.cfg -db Program received signal SIGSEGV, Segmentation fault. __memmove_ssse3 () at ../sysdeps/x86_64/multiarch/memcpy-ssse3.S:2976 2976../sysdeps/x86_64/multiarch/memcpy-ssse3.S: Aucun fichier ou dossier de ce type. (gdb) bt #0 __memmove_ssse3 () at ../sysdeps/x86_64/multiarch/memcpy-ssse3.S:2976 #1 0x004130a9 in buffer_insert_line2 (b=0x7e53b0, pos=0x7e541c \r\n, str=0x782850 , len=20) at src/buffer.c:126 #2 0x00468c99 in http_header_add_tail2 (msg=0x7cd5a0, hdr_idx=0x7cd540, text=0x782850 , len=20) at src/proto_http.c:507 #3 0x00472ebb in http_process_request (s=0x7cd1e0, req=0x7cd1f0, an_bit=512) at src/proto_http.c:4596 #4 0x004b7202 in process_stream (t=0x7d4cb0) at src/stream.c:1741 #5 0x004196c4 in process_runnable_tasks () at src/task.c:238 #6 0x0040c148 in run_poll_loop () at src/haproxy.c:1515 #7 0x0040cca2 in main (argc=4, argv=0x7fffe6f8) at src/haproxy.c:1874 --- # ./haproxy -vv HA-Proxy version 1.6-dev3-03d0e4-59 2015/08/11 Copyright 2000-2015 Willy Tarreau wi...@haproxy.org Build options : TARGET = linux2628 CPU = generic CC = gcc CFLAGS = -O0 OPTIONS = USE_ZLIB=1 USE_OPENSSL=1 USE_PCRE=1 Default settings : maxconn = 2000, bufsize = 16384, maxrewrite = 8192, maxpollevents = 200 Encrypted password support via crypt(3): yes Built with zlib version : 1.2.7 Compression algorithms supported : identity(identity), deflate(deflate), raw-deflate(deflate), gzip(gzip) Built with OpenSSL version : OpenSSL 1.0.1e 11 Feb 2013 Running on OpenSSL version : OpenSSL 1.0.1e 11 Feb 2013 OpenSSL library supports TLS extensions : yes OpenSSL library supports SNI : yes OpenSSL library supports prefer-server-ciphers : yes Built with PCRE version : 8.30 2012-02-04 PCRE library supports JIT : no (USE_PCRE_JIT not set) Built with Lua version : Lua 5.3.1 Built with transparent proxy support using: IP_TRANSPARENT IPV6_TRANSPARENT IP_FREEBIND Available polling systems : epoll : pref=300, test result OK poll : pref=200, test result OK select : pref=150, test result OK Total: 3 (3 usable), will use epoll. --- global log /dev/loglocal0 chroot /var/lib/haproxy stats socket /run/haproxy/admin.sock mode 660 level admin stats timeout 30s user haproxy group haproxy daemon nbproc 1 # Default SSL material locations ca-base /etc/ssl/certs crt-base /etc/ssl/private # Default ciphers to use on SSL-enabled listening sockets. # For more information, see ciphers(1SSL). ssl-default-bind-ciphers kEECDH+aECDSA+AES:kEECDH+aRSA+AES:kRSA+AES:+AES256:RC4-SHA:!kEDH:!LOW:!EXP:!MD5:!aNULL:!eNULL ssl-default-bind-options no-sslv3 lua-load /root/haproxy/mylua.lua defaults log global modehttp option httplog option log-health-checks option log-separate-errors
Re: ocsp
Hi, On Mon, 20 Jul 2015 11:50:50 +0200, Marc-Antoine marc-antoine.b...@ovh.net wrote : Hi Lukas, frontend cluster:443 bind 1.2.3.4:443 ssl strict-sni crt /home/provisionning/0.pem crt /home/provisionning/cluster.d default_backend cluster capture request header Host len 255 using this conf i made some tests. here is /home/provisionning content case and result : --- 1) ./0.pem.ocsp ./0.pem ./0.pem.issuer ./cluster.d/8640.pem.ocsp ./cluster.d/8640.pem.issuer ./cluster.d/8485.pem.ocsp ./cluster.d/8485.pem.issuer ./cluster.d/8485.pem ./cluster.d/8640.pem = ocsp stapling is working for all certs 2) ./0.pem.ocsp ./0.pem ./0.pem.issuer ./cluster.d/8485.pem.ocsp ./cluster.d/8485.pem.issuer ./cluster.d/8485.pem ./cluster.d/8640.pem = ocsp stapling is working for 0 and 8485 certs and broken for 8640 cert 3) ./0.pem.ocsp ./0.pem ./0.pem.issuer ./cluster.d/8640.pem.ocsp ./cluster.d/8640.pem.issuer ./cluster.d/8485.pem ./cluster.d/8640.pem = ocsp stapling is working 0 and 8640 certs and broken for 8485 cert 4) ./0.pem ./cluster.d/8640.pem.ocsp ./cluster.d/8640.pem.issuer ./cluster.d/8485.pem.ocsp ./cluster.d/8485.pem.issuer ./cluster.d/8485.pem ./cluster.d/8640.pem = ocsp stapling is broken for all certs --- is that a normal behavior ? i think ocsp stapling should work for 8485 and 8640 certs in case 4. Regards, --- HA-Proxy version 1.5.8 2014/10/31 Copyright 2000-2014 Willy Tarreau w...@1wt.eu Build options : TARGET = linux2628 CPU = generic CC = gcc CFLAGS = -g -O2 -fstack-protector --param=ssp-buffer-size=4 -Wformat -Werror=format-security -D_FORTIFY_SOURCE=2 OPTIONS = USE_ZLIB=1 USE_OPENSSL=1 USE_PCRE=1 Default settings : maxconn = 2000, bufsize = 16384, maxrewrite = 8192, maxpollevents = 200 Encrypted password support via crypt(3): yes Built with zlib version : 1.2.7 Compression algorithms supported : identity, deflate, gzip Built with OpenSSL version : OpenSSL 1.0.1e 11 Feb 2013 Running on OpenSSL version : OpenSSL 1.0.1e 11 Feb 2013 OpenSSL library supports TLS extensions : yes OpenSSL library supports SNI : yes OpenSSL library supports prefer-server-ciphers : yes Built with PCRE version : 8.30 2012-02-04 PCRE library supports JIT : no (USE_PCRE_JIT not set) Built with transparent proxy support using: IP_TRANSPARENT IPV6_TRANSPARENT IP_FREEBIND Available polling systems : epoll : pref=300, test result OK poll : pref=200, test result OK select : pref=150, test result OK Total: 3 (3 usable), will use epoll. --- If ocsp file is too old or empty for example, i got warning. Regards, On Fri, 17 Jul 2015 21:50:34 +0200, Lukas Tribus luky...@hotmail.com wrote : Hi Marc, Hi all, I have some problem making ocsp stapling working. here is what i did : I have 8150.pem with chain, cert and key in it. I have 8150.pem.ocsp that seems ok : # openssl ocsp -respin 8150.pem.ocsp -text -CAfile alphassl256.chain OCSP Response Data: OCSP Response Status: successful (0x0) Response Type: Basic OCSP Response Version: 1 (0x0) Responder Id: 9F10D9EDA5260B71A677124526751E17DC85A62F Produced At: Jul 9 09:47:04 2015 GMT Responses: Certificate ID: Hash Algorithm: sha1 Issuer Name Hash: 84D56BF8098BD307B766D8E1EBAD6596AA6B6761 Issuer Key Hash: F5CDD53C0850F96A4F3AB797DA5683E669D268F7 Serial Number: 11216784E7CA1813F3AD922B60EAF6428EE0 Cert Status: good This Update: Jul 9 09:47:04 2015 GMT Next Update: Jul 9 21:47:04 2015 GMT No error/warn at haproxy launching but not sure haproxy is loading .ocsp file because no notice in log. But nothing in tlsextdebug : echo Q | openssl s_client -connect www.beluc.fr:443 -servername www.beluc.fr -tlsextdebug -status -CApath /etc/ssl/certs [...] OCSP response: no response sent [...] Do you see smth wrong ? What can i do in order to debug? Can you provide the output of haproxy -vv please and a config snippet (the frontend ssl configuration)? Do you see a warning if 8150.pem.ocsp contains garbage when you restart haproxy? Regards, Lukas -- Marc-Antoine
Re: ocsp
Hi Lukas, I used only one pem file per frontend instead of pem directory : frontend cluster1:443 bind 1.2.3.4:443 ssl crt /home/provisionning/cluster1.d/8640.pem default_backend cluster1 Regards, On Mon, 20 Jul 2015 20:18:10 +0200, Lukas Tribus luky...@hotmail.com wrote : Hi Lukas, I made a mistake in my previous email : it works locally AND remotely ! What fixed the problem? This may be useful for others as well. Lukas -- Marc-Antoine
Re: ocsp
Hi Lukas, I made a mistake in my previous email : it works locally AND remotely ! Regards, On Mon, 20 Jul 2015 19:04:24 +0200, Lukas Tribus luky...@hotmail.com wrote : Hi Marc, Hi Lukas, great intuition :) --- CONNECTED(0003) TLS server extension server name (id=0), len=0 TLS server extension renegotiation info (id=65281), len=1 0001 - SPACES/NULS TLS server extension EC point formats (id=11), len=4 - 03 00 01 02 TLS server extension session ticket (id=35), len=0 TLS server extension status request (id=5), len=0 TLS server extension heartbeat (id=15), len=1 - 01 . depth=2 C = BE, O = GlobalSign nv-sa, OU = Root CA, CN = GlobalSign Root CA verify return:1 depth=1 C = BE, O = GlobalSign nv-sa, CN = AlphaSSL CA - SHA256 - G2 verify return:1 depth=0 OU = Domain Control Validated, CN = *.makeprestashop.com verify return:1 OCSP response: == OCSP Response Data: OCSP Response Status: successful (0x0) Response Type: Basic OCSP Response Version: 1 (0x0) Responder Id: 9F10D9EDA5260B71A677124526751E17DC85A62F Produced At: Jul 20 16:42:53 2015 GMT Responses: Certificate ID: Hash Algorithm: sha1 Issuer Name Hash: 84D56BF8098BD307B766D8E1EBAD6596AA6B6761 Issuer Key Hash: F5CDD53C0850F96A4F3AB797DA5683E669D268F7 Serial Number: 11210839AC1CC2D1DC09BA07A33700E3E681 Cert Status: good This Update: Jul 20 16:42:53 2015 GMT Next Update: Jul 21 04:42:53 2015 GMT [...] --- It works locally or remotely ! Not sure I understand. Does that mean it works locally, but not remotely? Regards, Lukas -- Marc-Antoine
Re: ocsp
Hi, nobody knows plz ? On Thu, 9 Jul 2015 13:06:59 +0200, Marc-Antoine marc-antoine.b...@ovh.net wrote : Hi all, I have some problem making ocsp stapling working. here is what i did : I have 8150.pem with chain, cert and key in it. I have 8150.pem.ocsp that seems ok : # openssl ocsp -respin 8150.pem.ocsp -text -CAfile alphassl256.chain OCSP Response Data: OCSP Response Status: successful (0x0) Response Type: Basic OCSP Response Version: 1 (0x0) Responder Id: 9F10D9EDA5260B71A677124526751E17DC85A62F Produced At: Jul 9 09:47:04 2015 GMT Responses: Certificate ID: Hash Algorithm: sha1 Issuer Name Hash: 84D56BF8098BD307B766D8E1EBAD6596AA6B6761 Issuer Key Hash: F5CDD53C0850F96A4F3AB797DA5683E669D268F7 Serial Number: 11216784E7CA1813F3AD922B60EAF6428EE0 Cert Status: good This Update: Jul 9 09:47:04 2015 GMT Next Update: Jul 9 21:47:04 2015 GMT No error/warn at haproxy launching but not sure haproxy is loading .ocsp file because no notice in log. But nothing in tlsextdebug : echo Q | openssl s_client -connect www.beluc.fr:443 -servername www.beluc.fr -tlsextdebug -status -CApath /etc/ssl/certs [...] OCSP response: no response sent [...] Do you see smth wrong ? What can i do in order to debug ? Regards, -- Marc-Antoine
ocsp
Hi all, I have some problem making ocsp stapling working. here is what i did : I have 8150.pem with chain, cert and key in it. I have 8150.pem.ocsp that seems ok : # openssl ocsp -respin 8150.pem.ocsp -text -CAfile alphassl256.chain OCSP Response Data: OCSP Response Status: successful (0x0) Response Type: Basic OCSP Response Version: 1 (0x0) Responder Id: 9F10D9EDA5260B71A677124526751E17DC85A62F Produced At: Jul 9 09:47:04 2015 GMT Responses: Certificate ID: Hash Algorithm: sha1 Issuer Name Hash: 84D56BF8098BD307B766D8E1EBAD6596AA6B6761 Issuer Key Hash: F5CDD53C0850F96A4F3AB797DA5683E669D268F7 Serial Number: 11216784E7CA1813F3AD922B60EAF6428EE0 Cert Status: good This Update: Jul 9 09:47:04 2015 GMT Next Update: Jul 9 21:47:04 2015 GMT No error/warn at haproxy launching but not sure haproxy is loading .ocsp file because no notice in log. But nothing in tlsextdebug : echo Q | openssl s_client -connect www.beluc.fr:443 -servername www.beluc.fr -tlsextdebug -status -CApath /etc/ssl/certs [...] OCSP response: no response sent [...] Do you see smth wrong ? What can i do in order to debug ? Regards, -- Marc-Antoine
Re: [ANNOUNCE] haproxy-1.5.14
Hi, just to let you know changelog is missing 1.5.14 infos ;) great job by the way ! On Fri, 3 Jul 2015 17:55:56 +0200, Willy Tarreau w...@1wt.eu wrote : Changelog: http://www.haproxy.org/download/1.5/src/CHANGELOG -- Marc-Antoine
Re: Which signal causes HAProxy to reload its config
On 25 March 2015 at 12:25, jeff saremi jeffsar...@hotmail.com wrote: I have to do manually what -sf is supposed to be doing since it's either not working or not supported and removed. I know what that does is send a signal to the pid stored by the haproxy process. I'd like to do that myself. Just need to know the signal name. thanks jeff Haproxy doesn't reload its config. -sf is there so that the new haproxy you're spawning tells the old one to stop accepting new connections and exit once the current one are closed. You do not send a signal to the running haproxy process (well, you do, but not only), you *replace* it. What you may be looking for, though, is haproxy-systemd-wrapper, which does all this automatically when it receives SIGUSR2 or SIGHUP. Regards, Marc-Antoine
Re: [PATCH] Also accept SIGHUP/SIGTERM in systemd-wrapper
On 11 September 2014 07:44, Willy Tarreau w...@1wt.eu wrote: On Wed, Sep 10, 2014 at 10:38:55PM -0700, Matt Robenolt wrote: Awesome, thanks. :) Is it possible to also get this applied into the 1.5 branch since this is low risk and doesn???t break any backwards compatibility and whatnot? I've just backported it as well. 1.5 was still missing Conrad Hoffman's improved signal handling, but now both patches have been merged. Willy Iirc, the reason why I did not use SIGHUP for the reload (which I'd have preferred too) is that haproxy itself uses SIGHUP, and if I used it in the wrapper, it became a noop for haproxy. Maybe I did something wrong and with the actual state of it it works fine now, but did you check that haproxy still handles it properly?
Re: [PATCH 0/3] systemd wrapper improvements
Hi, On Thursday, April 17, 2014, Apollon Oikonomopoulos apoi...@debian.org wrote: Hi, The following patches improve the systemd wrapper in a couple of ways: - The systemd wrapper itself is now re-executed on SIGUSR2, allowing a new version of both HAProxy and the wrapper to be gracefully loaded. - We use standard error for message logging, which seems to get more reliably to systemd's journal than stdout. - We also use systemd's support for prefixing messages with the log level to differentiate between message severity. - Finally, we propagate the exit status of HAProxy to systemd, instead of always returning success. Regards, Apollon Apollon Oikonomopoulos (3): MINOR: systemd wrapper: re-execute on SIGUSR2 MINOR: systemd wrapper: improve logging MINOR: systemd wrapper: propagate exit status src/haproxy-systemd-wrapper.c | 69 ++- 1 file changed, 49 insertions(+), 20 deletions(-) -- 1.9.1 Looks good to me. Any comments, Will? Regards, Marc-Antoine
Re: haproxy-systemd-wrapper spawning multiple processes
Hi, On 16 February 2014 01:51, Ryan O'Hara roh...@redhat.com wrote: I started tinkering with haproxy-systemd-wrapper recently and noticed that I get two haproxy processes when I start: # systemctl start haproxy # systemctl status haproxy haproxy.service - HAProxy Load Balancer Loaded: loaded (/usr/lib/systemd/system/haproxy.service; disabled) Active: active (running) since Sat 2014-02-15 10:39:20 CST; 1s ago Main PID: 10065 (haproxy-systemd) CGroup: /system.slice/haproxy.service ├─10065 /usr/sbin/haproxy-systemd-wrapper -f /etc/haproxy/haproxy.cfg -p /run/haproxy ├─10066 /usr/sbin/haproxy -f /etc/haproxy/haproxy.cfg -p /run/haproxy.pid -Ds └─10067 /usr/sbin/haproxy -f /etc/haproxy/haproxy.cfg -p /run/haproxy.pid -Ds That doesn't seem right. A quick look the haproxy processes shows an interesting parent/child relationship: # ps -C haproxy -o pid,ppid PID PPID 10066 10065 10067 10066 Can someone explain what is going on here? I'm using 1.5-dev22 and the systemd service file from the source. Here is how haproxy works (correct me if I'm wrong, it's not all that fresh in my mind): - the main haproxy process is started - it forks as many child processes as asked in its configuration file - it goes away letting only the worker child processes First thing I did was to make it wait for the worker child processes instead of leaving, that's what -Ds is for. This is in order to avoid the double fork which would happen because of what I'll describe just below. Here is how haproxy reloads its configuration: - A new haproxy is spawned with the pids of the old workers - The new haproxy tells the old workers not to listen anymore, and to exit when they have finished dealing with their current requests - The new haproxy spawns its own workers and starts listening - The old haproxy quits eventually when it has dealt with all pending requests systemd doesn't like this behavious at all as the main process completely goes away, replaced by a brand new one, just for a *reload*. The easiest way to get it working without having to rework the core behaviour of haproxy was to put a wrapper around it, which spawns haproxy, listens to a signal which systemd emits on reload, and which spawns a new haproxy when this signal is received. This way, the main process never changes ans systemd can reload gracefully. This is why you get haproxy-systemd-wrapper - main haproxy process - haproxy worker. haproxy-systemd-wrapper waits for the main haproxy process to exit to avoir zombies. The main haproxy process exits when all its workers are done. Thanks. Ryan Hope that helps and sounds right. Marc-Antoine
Re: haproxy-systemd-wrapper spawning multiple processes
On Sat, 2014-02-15 at 20:04 -0600, Ryan O'Hara wrote: On Sun, Feb 16, 2014 at 10:08:31AM +0900, Marc-Antoine Perennou wrote: This is why you get haproxy-systemd-wrapper - main haproxy process - haproxy worker. haproxy-systemd-wrapper waits for the main haproxy process to exit to avoir zombies. The main haproxy process exits when all its workers are done. It has been while since I dealt with this, but can't you double fork to avoid zombies? Is it a double fork that causes problems for systemd? Double forking would work fine, but the wrapper wouldn't be linked to the worker processes and thus couldn't check whether there has been a problem or not. Without the double fork, if there is a problem, the wrapper will exit and you'll be able to notice it. With the double fork, we would end up with some kind of endless loop instead of a waiting loop, and it would never exit. Thanks. Ryan Hope that helps and sounds right. Marc-Antoine It does help. Thank you. Ryan Regards Marc-Antoine
Re: Three patches to the haproxy-systemd-wrapper
Hello, On Saturday, November 23, 2013, Willy Tarreau wrote: Hello Kristoffer, On Fri, Nov 22, 2013 at 11:21:21AM +0100, Kristoffer Grönlund wrote: Hello, I have packaged haproxy 1.4.24 for openSUSE 13.1 [1], which uses systemd as the init system. At first I tried using a service script originally written for Fedora, but this script didn't handle configuration file reload in a good way. I then found the haproxy-systemd-wrapper committed upstream, which looked like a more viable approach. However, it didn't work for openSUSE mainly because SBINDIR didn't point to the correct directory. There was also an issue with the wrapper not cleaning up when killed by systemd, leaving zombie processes hanging. The attached patches should address both of these issues in a way that should work on any systemd-platform. I also added some logging to the systemd-wrapper so that it's easier to figure out what it does. The patched wrapper seems to work well for me, but any comments/suggestions are welcome. :) In case the patches get stripped, they are also available from my github account [2]. They are applied to a copy of 1.4.24 there, but should apply cleanly to the development tree. Great, thank you! I'll wait for Marc-Antoine to do a quick review since he seems to be the only one here having had his fingers dirty with systemd, then I have no problem merging them. Thanks! Willy I don't have access to a computer to actually test those, but: - the first one looks nice, never felt really confident hard coding SBINDIR and the solution makes sense - nice catch for the second one, didn't think of the sigint when writing it, lgtm - third one is trivial enough not to harm anyone +1 for me Thanks! Marc-Antoine
[PATCH] BUG/MEDIUM: systemd-wrapper: don't leak zombie processes
Formerly, if A was replaced by B, and then B by C before A finished exiting, we didn't wait for B to finish so it ended up as a zombie process. Fix this by waiting randomly every child we spawn. Signed-off-by: Marc-Antoine Perennou marc-anto...@perennou.com --- src/haproxy-systemd-wrapper.c | 10 -- 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/src/haproxy-systemd-wrapper.c b/src/haproxy-systemd-wrapper.c index 5968015..8499b35 100644 --- a/src/haproxy-systemd-wrapper.c +++ b/src/haproxy-systemd-wrapper.c @@ -19,12 +19,11 @@ #include unistd.h #include sys/wait.h -static pid_t pid = 0; static char *pid_file = /run/haproxy.pid; static int main_argc; static char **main_argv; -static pid_t spawn_haproxy(char **pid_strv, int nb_pid) +static void spawn_haproxy(char **pid_strv, int nb_pid) { pid_t pid = fork(); if (!pid) { @@ -45,7 +44,6 @@ static pid_t spawn_haproxy(char **pid_strv, int nb_pid) execv(argv[0], argv); exit(0); } - return pid; } static int read_pids(char ***pid_strv) @@ -77,7 +75,7 @@ static void signal_handler(int signum __attribute__((unused))) char **pid_strv = NULL; int nb_pid = read_pids(pid_strv); - pid = spawn_haproxy(pid_strv, nb_pid); + spawn_haproxy(pid_strv, nb_pid); for (i = 0; i nb_pid; ++i) free(pid_strv[i]); @@ -107,8 +105,8 @@ int main(int argc, char **argv) signal(SIGUSR2, signal_handler); - pid = spawn_haproxy(NULL, 0); - while (-1 != waitpid(pid, NULL, 0) || errno == EINTR); + spawn_haproxy(NULL, 0); + while (-1 != wait(NULL) || errno == EINTR); return EXIT_SUCCESS; } -- 1.8.2
Re: [PATCH v2] BUG/MEDIUM: systemd-wrapper: don't leak zombie processes
Hi, After checking out the man page of waitpid, wait would indeed be sufficient here. I didn't actually know about waitpid(-1) I'll resubmit an updated patch tomorrow! Thanks On 1 April 2013 23:32, Willy Tarreau w...@1wt.eu wrote: Hi Marc-Antoine, On Thu, Mar 14, 2013 at 02:50:56PM +0100, Marc-Antoine Perennou wrote: Formerly, if A was replaced by B, and then B by C before A finished exiting, we didn't wait for B to finish so it ended up as a zombie process. Fix this by queuing all process we spawn for waitpid. I'm a bit puzzled, why is it necessary to keep a queue of all spawned processes ? The system already has one, so we should simply do a wait() or waitpid(-1). Am I missing something ? Willy
[PATCH v2] BUG/MEDIUM: systemd-wrapper: don't leak zombie processes
Formerly, if A was replaced by B, and then B by C before A finished exiting, we didn't wait for B to finish so it ended up as a zombie process. Fix this by queuing all process we spawn for waitpid. Signed-off-by: Marc-Antoine Perennou marc-anto...@perennou.com --- src/haproxy-systemd-wrapper.c | 45 +-- 1 file changed, 43 insertions(+), 2 deletions(-) diff --git a/src/haproxy-systemd-wrapper.c b/src/haproxy-systemd-wrapper.c index 5968015..a3af528 100644 --- a/src/haproxy-systemd-wrapper.c +++ b/src/haproxy-systemd-wrapper.c @@ -24,6 +24,44 @@ static char *pid_file = /run/haproxy.pid; static int main_argc; static char **main_argv; +static struct { + pid_t *queue; + int count; + int size; + int index; + int rindex; +} pids = { + .queue = NULL, + .count = 0, + .size = 8, + .index = 0, + .rindex = 0 +}; + +static void pids_push(pid_t pid) +{ + if (pids.size == pids.count) { + // Double the capacity, write in the new half, rewind reading head + pids.index = pids.size; + pids.rindex = 0; + pids.size *= 2; + pids.queue = realloc(pids.queue, pids.size * sizeof(int)); + } + pids.queue[pids.index++ % pids.size] = pid; + pids.count++; +} + +static bool pids_pop(void) +{ + if (pids.count == 0) + pid = 0; + else { + pids.count--; + pid = pids.queue[pids.rindex++ % pids.size]; + } + return pid != 0; +} + static pid_t spawn_haproxy(char **pid_strv, int nb_pid) { pid_t pid = fork(); @@ -77,7 +115,7 @@ static void signal_handler(int signum __attribute__((unused))) char **pid_strv = NULL; int nb_pid = read_pids(pid_strv); - pid = spawn_haproxy(pid_strv, nb_pid); + pids_push(spawn_haproxy(pid_strv, nb_pid)); for (i = 0; i nb_pid; ++i) free(pid_strv[i]); @@ -107,8 +145,11 @@ int main(int argc, char **argv) signal(SIGUSR2, signal_handler); + pids.queue = malloc(pids.size * sizeof(int)); pid = spawn_haproxy(NULL, 0); - while (-1 != waitpid(pid, NULL, 0) || errno == EINTR); + while ((-1 != waitpid(pid, NULL, 0) pids_pop()) || errno == EINTR); + + free(pids.queue); return EXIT_SUCCESS; } -- 1.8.1.5
[PATCH] MEDIUM: systemd-wrapper: don't leak zombie processes
Formerly, if A was replaced by B, and then B by C before A finished exiting, we didn't wait for B to finish so it ended up as a zombie process. Fix this by queuing all process we spawn for waitpid. Signed-off-by: Marc-Antoine Perennou marc-anto...@perennou.com --- src/haproxy-systemd-wrapper.c | 45 +-- 1 file changed, 43 insertions(+), 2 deletions(-) diff --git a/src/haproxy-systemd-wrapper.c b/src/haproxy-systemd-wrapper.c index 57e8d7d..3c70271 100644 --- a/src/haproxy-systemd-wrapper.c +++ b/src/haproxy-systemd-wrapper.c @@ -24,6 +24,44 @@ static char *pid_file = /run/haproxy.pid; static int main_argc; static char **main_argv; +static struct { + pid_t *queue; + int count; + int size; + int index; + int rindex; +} pids = { + .queue = NULL, + .count = 0, + .size = 8, + .index = 0, + .rindex = 0 +}; + +static void pids_push(pid_t pid) +{ + if (pids.size == pids.count) { + // Double the capacity, write in the new half, rewind reading head + pids.index = pids.size; + pids.rindex = 0; + pids.size *= 2; + pids.queue = realloc(pids.queue, pids.size * sizeof(int)); + } + pids.queue[pids.index++ % pids.size] = pid; + pids.count++; +} + +static bool pids_pop(void) +{ + if (pids.count == 0) + pid = 0; + else { + pids.count--; + pid = pids.queue[pids.rindex++ % pids.size]; + } + return pid != 0; +} + static pid_t spawn_haproxy(char **pid_strv, int nb_pid) { pid_t pid = fork(); @@ -76,7 +114,7 @@ static void signal_handler(int signum __attribute__((unused))) char **pid_strv = NULL; int nb_pid = read_pids(pid_strv); - pid = spawn_haproxy(pid_strv, nb_pid); + pids_push(spawn_haproxy(pid_strv, nb_pid)); for (i = 0; i nb_pid; ++i) free(pid_strv[i]); @@ -106,8 +144,11 @@ int main(int argc, char **argv) signal(SIGUSR2, signal_handler); + pids.queue = malloc(pids.size * sizeof(int)); pid = spawn_haproxy(NULL, 0); - while (-1 != waitpid(pid, NULL, 0) || errno == EINTR); + while ((-1 != waitpid(pid, NULL, 0) || errno == EINTR) pids_pop()); + + free(pids.queue); return EXIT_SUCCESS; } -- 1.8.1.3
Re: [[V2] 3/3] MEDIUM: add systemd service
Hi, On 13 February 2013 08:11, Willy Tarreau w...@1wt.eu wrote: Hi Marc-Antoine, On Tue, Feb 12, 2013 at 10:53:54AM +0100, Marc-Antoine Perennou wrote: +systemd/haproxy.service: contrib/systemd/haproxy.service.in + mkdir -p systemd + sed -e 's:@SBINDIR@:'$(strip $(SBINDIR))':' $ $@ + I'm a bit worried with this one, because it will create a new systemd directory in everyone's sources, which is even not cleaned afterwards. I'd rather keep the usual behaviour we have with whatever lies in the contrib subdir, which consists in considering them as add-ons and leaving them completely in that directory. In my opinion you should create a simple makefile there so that the packager may just run make -C contrib/systemd to build it and have the result in the contrib/systemd directory. Sure, will do diff --git a/contrib/systemd/haproxy.service.in b/contrib/systemd/ haproxy.service.in new file mode 100644 index 000..f925651 --- /dev/null +++ b/contrib/systemd/haproxy.service.in @@ -0,0 +1,11 @@ +[Unit] +Description=HAProxy Load Balancer +After=network.target + +[Service] +ExecStart=@SBINDIR@/haproxy-systemd-wrapper -f /etc/haproxy/haproxy.cfg -p /run/haproxy.pid +ExecReload=/usr/bin/kill -USR2 $MAINPID You should be careful here. On my distro, kill is in /bin, not in /usr/bin. I don't know if it's standard to have it in /usr/bin on distros which involve systemd, but at first glance it might not be very much portable. Oh and BTW my distro seems to be right about it, so please double-check : http://refspecs.linuxfoundation.org/FHS_2.3/fhs-2.3.html Regards, Willy My bad, /bin is actually a symlink to /usr/bin on my system, but you're right it should be /bin, not /usr/bin, will fix it
[[V3] 3/3] MEDIUM: add systemd service
Signed-off-by: Marc-Antoine Perennou marc-anto...@perennou.com --- .gitignore | 1 + contrib/systemd/Makefile | 8 contrib/systemd/haproxy.service.in | 11 +++ 3 files changed, 20 insertions(+) create mode 100644 contrib/systemd/Makefile create mode 100644 contrib/systemd/haproxy.service.in diff --git a/.gitignore b/.gitignore index 5e6f556..ec1545a 100644 --- a/.gitignore +++ b/.gitignore @@ -16,3 +16,4 @@ haproxy-* make-* dlmalloc.c 00*.patch +*.service diff --git a/contrib/systemd/Makefile b/contrib/systemd/Makefile new file mode 100644 index 000..e542c23 --- /dev/null +++ b/contrib/systemd/Makefile @@ -0,0 +1,8 @@ +PREFIX = /usr/local +SBINDIR = $(PREFIX)/sbin + +haproxy.service: haproxy.service.in + sed -e 's:@SBINDIR@:'$(strip $(SBINDIR))':' $ $@ + +clean: + rm -f haproxy.service diff --git a/contrib/systemd/haproxy.service.in b/contrib/systemd/haproxy.service.in new file mode 100644 index 000..1a3d2c0 --- /dev/null +++ b/contrib/systemd/haproxy.service.in @@ -0,0 +1,11 @@ +[Unit] +Description=HAProxy Load Balancer +After=network.target + +[Service] +ExecStart=@SBINDIR@/haproxy-systemd-wrapper -f /etc/haproxy/haproxy.cfg -p /run/haproxy.pid +ExecReload=/bin/kill -USR2 $MAINPID +Restart=always + +[Install] +WantedBy=multi-user.target -- 1.8.1.2
[[V2] 1/3] MEDIUM: New cli option -Ds for systemd compatibility
This patch adds a new option -Ds which is exactly like -D, but instead of forking n times to get n jobs running and then exiting, prefers to wait for all the children it just created. With this done, haproxy becomes more systemd-compliant, without changing anything for other systems. Signed-off-by: Marc-Antoine Perennou marc-anto...@perennou.com --- doc/haproxy-en.txt | 1 + doc/haproxy-fr.txt | 1 + doc/haproxy.1 | 4 include/types/global.h | 1 + src/haproxy.c | 35 +++ 5 files changed, 30 insertions(+), 12 deletions(-) diff --git a/doc/haproxy-en.txt b/doc/haproxy-en.txt index 3d2a2be..4c673d3 100644 --- a/doc/haproxy-en.txt +++ b/doc/haproxy-en.txt @@ -51,6 +51,7 @@ There are only a few command line options : = 'maxconn' in 'listen' or 'default' sections -d starts in foregreound with debugging mode enabled -D starts in daemon mode +-Ds starts in systemd daemon mode -q disable messages on output -V displays messages on output even when -q or 'quiet' are specified. -c only checks config file and exits with code 0 if no error was found, or diff --git a/doc/haproxy-fr.txt b/doc/haproxy-fr.txt index 87bb972..0e36724 100644 --- a/doc/haproxy-fr.txt +++ b/doc/haproxy-fr.txt @@ -53,6 +53,7 @@ Les options de lancement sont peu nombreuses : = 'maxconn' dans les sections 'listen' ou 'default' -d active le mode debug -D passe en daemon +-Ds passe en daemon systemd -q d�sactive l'affichage de messages sur la sortie standard. -V affiche les messages sur la sortie standard, m�me si -q ou 'quiet' sont sp�cifi�s. diff --git a/doc/haproxy.1 b/doc/haproxy.1 index 001de15..48717ad 100644 --- a/doc/haproxy.1 +++ b/doc/haproxy.1 @@ -57,6 +57,10 @@ starting up. Start in daemon mode. .TP +\fB\-Ds\fP +Start in systemd daemon mode, keeping a process in foreground. + +.TP \fB\-q\fP Disable messages on output. diff --git a/include/types/global.h b/include/types/global.h index 133a98d..730cc64 100644 --- a/include/types/global.h +++ b/include/types/global.h @@ -42,6 +42,7 @@ #defineMODE_VERBOSE0x10 #defineMODE_STARTING 0x20 #defineMODE_FOREGROUND 0x40 +#defineMODE_SYSTEMD0x80 /* list of last checks to perform, depending on config options */ #define LSTCHK_CAP_BIND0x0001 /* check that we can bind to any port */ diff --git a/src/haproxy.c b/src/haproxy.c index 4503a01..92e25c2 100644 --- a/src/haproxy.c +++ b/src/haproxy.c @@ -42,6 +42,7 @@ #include signal.h #include stdarg.h #include sys/resource.h +#include sys/wait.h #include time.h #include syslog.h #include grp.h @@ -539,8 +540,11 @@ void init(int argc, char **argv) arg_mode |= MODE_DEBUG; else if (*flag == 'c') arg_mode |= MODE_CHECK; - else if (*flag == 'D') + else if (*flag == 'D') { arg_mode |= MODE_DAEMON; + if (flag[1] == 's') /* -Ds */ + arg_mode |= MODE_SYSTEMD; + } else if (*flag == 'q') arg_mode |= MODE_QUIET; else if (*flag == 's' (flag[1] == 'f' || flag[1] == 't')) { @@ -594,7 +598,7 @@ void init(int argc, char **argv) } global.mode = MODE_STARTING | /* during startup, we want most of the alerts */ - (arg_mode (MODE_DAEMON | MODE_FOREGROUND | MODE_VERBOSE + (arg_mode (MODE_DAEMON | MODE_SYSTEMD | MODE_FOREGROUND | MODE_VERBOSE | MODE_QUIET | MODE_CHECK | MODE_DEBUG)); if (LIST_ISEMPTY(cfg_cfgfiles)) @@ -733,24 +737,24 @@ void init(int argc, char **argv) if (arg_mode (MODE_DEBUG | MODE_FOREGROUND)) { /* command line debug mode inhibits configuration mode */ - global.mode = ~(MODE_DAEMON | MODE_QUIET); + global.mode = ~(MODE_DAEMON | MODE_SYSTEMD | MODE_QUIET); global.mode |= (arg_mode (MODE_DEBUG | MODE_FOREGROUND)); } - if (arg_mode MODE_DAEMON) { + if (arg_mode (MODE_DAEMON | MODE_SYSTEMD)) { /* command line daemon mode inhibits foreground and debug modes mode */ global.mode = ~(MODE_DEBUG | MODE_FOREGROUND); - global.mode |= (arg_mode MODE_DAEMON); + global.mode |= (arg_mode (MODE_DAEMON | MODE_SYSTEMD)); } global.mode |= (arg_mode (MODE_QUIET | MODE_VERBOSE)); - if ((global.mode MODE_DEBUG) (global.mode (MODE_DAEMON | MODE_QUIET))) { - Warning(debug mode incompatible with quiet and daemon. Keeping debug only.\n); - global.mode = ~(MODE_DAEMON | MODE_QUIET); + if ((global.mode MODE_DEBUG
[[V2] 2/3] MEDIUM: add haproxy-systemd-wrapper
Currently, to reload haproxy configuration, you have to use -sf. There is a problem with this way of doing things. First of all, in the systemd world, reload commands should be oneshot ones, which means they should not be the new main process but rather a tool which makes a call to it and then exits. With the current approach, the reload command is the new main command and moreover, it makes the previous one exit. Systemd only tracks the main program, seeing it ending, it assumes it either finished or failed, and kills everything remaining as a grabage collector. We then end up with no haproxy running at all. This patch adds wrapper around haproxy, no changes at all have been made into it, so it's not intrusive and doesn't change anything for other hosts. What this wrapper does is basically launching haproxy as a child, listen to the SIGUSR2 (not to conflict with haproxy itself) signal, and spawing a new haproxy with -sf as a child to relay the first one. Signed-off-by: Marc-Antoine Perennou marc-anto...@perennou.com --- .gitignore| 1 + Makefile | 16 +- src/haproxy-systemd-wrapper.c | 113 ++ 3 files changed, 128 insertions(+), 2 deletions(-) create mode 100644 src/haproxy-systemd-wrapper.c diff --git a/.gitignore b/.gitignore index 5d9576a..5e6f556 100644 --- a/.gitignore +++ b/.gitignore @@ -12,6 +12,7 @@ src/*.o *.log* *.trace* haproxy-* +!src/*.c make-* dlmalloc.c 00*.patch diff --git a/Makefile b/Makefile index f1eed55..ca9e1b2 100644 --- a/Makefile +++ b/Makefile @@ -593,7 +593,7 @@ all: @echo @exit 1 else -all: haproxy +all: haproxy haproxy-systemd-wrapper endif OBJS = src/haproxy.o src/sessionhash.o src/base64.o src/protocol.o \ @@ -618,12 +618,17 @@ ifneq ($(TRACE),) OBJS += src/trace.o endif +WRAPPER_OBJS = src/haproxy-systemd-wrapper.o + # Not used right now LIB_EBTREE = $(EBTREE_DIR)/libebtree.a haproxy: $(OBJS) $(OPTIONS_OBJS) $(EBTREE_OBJS) $(LD) $(LDFLAGS) -o $@ $^ $(LDOPTS) +haproxy-systemd-wrapper: $(WRAPPER_OBJS) + $(LD) $(LDFLAGS) -o $@ $^ $(LDOPTS) + $(LIB_EBTREE): $(EBTREE_OBJS) $(AR) rv $@ $^ @@ -646,6 +651,11 @@ src/haproxy.o: src/haproxy.c -DBUILD_OPTIONS='$(strip $(BUILD_OPTIONS))' \ -c -o $@ $ +src/haproxy-systemd-wrapper.o: src/haproxy-systemd-wrapper.c + $(CC) $(COPTS) \ + -DSBINDIR='$(strip $(SBINDIR))' \ + -c -o $@ $ + src/dlmalloc.o: $(DLMALLOC_SRC) $(CC) $(COPTS) -DDEFAULT_MMAP_THRESHOLD=$(DLMALLOC_THRES) -c -o $@ $ @@ -659,9 +669,10 @@ install-doc: install -m 644 doc/$$x.txt $(DESTDIR)$(DOCDIR) ; \ done -install-bin: haproxy +install-bin: haproxy haproxy-systemd-wrapper install -d $(DESTDIR)$(SBINDIR) install haproxy $(DESTDIR)$(SBINDIR) + install haproxy-systemd-wrapper $(DESTDIR)$(SBINDIR) install: install-bin install-man install-doc @@ -670,6 +681,7 @@ clean: for dir in . src include/* doc ebtree; do rm -f $$dir/*~ $$dir/*.rej $$dir/core; done rm -f haproxy-$(VERSION).tar.gz haproxy-$(VERSION)$(SUBVERS).tar.gz rm -f haproxy-$(VERSION) nohup.out gmon.out + rm -f haproxy-systemd-wrapper tags: find src include \( -name '*.c' -o -name '*.h' \) -print0 | \ diff --git a/src/haproxy-systemd-wrapper.c b/src/haproxy-systemd-wrapper.c new file mode 100644 index 000..57e8d7d --- /dev/null +++ b/src/haproxy-systemd-wrapper.c @@ -0,0 +1,113 @@ +/* + * Wrapper to make haproxy systemd-compliant. + * + * Copyright 2013 Marc-Antoine Perennou marc-anto...@perennou.com + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version + * 2 of the License, or (at your option) any later version. + * + */ + +#include errno.h +#include signal.h +#include stdbool.h +#include stdio.h +#include stdlib.h +#include string.h +#include unistd.h +#include sys/wait.h + +static pid_t pid = 0; +static char *pid_file = /run/haproxy.pid; +static int main_argc; +static char **main_argv; + +static pid_t spawn_haproxy(char **pid_strv, int nb_pid) +{ + pid_t pid = fork(); + if (!pid) { + /* 3 for haproxy -Ds -sf */ + char **argv = calloc(4 + main_argc + nb_pid + 1, sizeof(char *)); + int i; + int argno = 0; + argv[argno++] = SBINDIR/haproxy; + for (i = 0; i main_argc; ++i) + argv[argno++] = main_argv[i]; + argv[argno++] = -Ds; + if (nb_pid 0) { + argv[argno++] = -sf; + for (i = 0; i nb_pid; ++i) + argv[argno++] = pid_strv[i]; + } + argv[argno] = NULL; + execv(argv[0], argv
[[V2] 3/3] MEDIUM: add systemd service
Signed-off-by: Marc-Antoine Perennou marc-anto...@perennou.com --- .gitignore | 1 + Makefile | 8 ++-- contrib/systemd/haproxy.service.in | 11 +++ 3 files changed, 18 insertions(+), 2 deletions(-) create mode 100644 contrib/systemd/haproxy.service.in diff --git a/.gitignore b/.gitignore index 5e6f556..ec1545a 100644 --- a/.gitignore +++ b/.gitignore @@ -16,3 +16,4 @@ haproxy-* make-* dlmalloc.c 00*.patch +*.service diff --git a/Makefile b/Makefile index ca9e1b2..1b81fc7 100644 --- a/Makefile +++ b/Makefile @@ -593,7 +593,7 @@ all: @echo @exit 1 else -all: haproxy haproxy-systemd-wrapper +all: haproxy haproxy-systemd-wrapper systemd/haproxy.service endif OBJS = src/haproxy.o src/sessionhash.o src/base64.o src/protocol.o \ @@ -659,6 +659,10 @@ src/haproxy-systemd-wrapper.o: src/haproxy-systemd-wrapper.c src/dlmalloc.o: $(DLMALLOC_SRC) $(CC) $(COPTS) -DDEFAULT_MMAP_THRESHOLD=$(DLMALLOC_THRES) -c -o $@ $ +systemd/haproxy.service: contrib/systemd/haproxy.service.in + mkdir -p systemd + sed -e 's:@SBINDIR@:'$(strip $(SBINDIR))':' $ $@ + install-man: install -d $(DESTDIR)$(MANDIR)/man1 install -m 644 doc/haproxy.1 $(DESTDIR)$(MANDIR)/man1 @@ -681,7 +685,7 @@ clean: for dir in . src include/* doc ebtree; do rm -f $$dir/*~ $$dir/*.rej $$dir/core; done rm -f haproxy-$(VERSION).tar.gz haproxy-$(VERSION)$(SUBVERS).tar.gz rm -f haproxy-$(VERSION) nohup.out gmon.out - rm -f haproxy-systemd-wrapper + rm -f haproxy-systemd-wrapper systemd/haproxy.service tags: find src include \( -name '*.c' -o -name '*.h' \) -print0 | \ diff --git a/contrib/systemd/haproxy.service.in b/contrib/systemd/haproxy.service.in new file mode 100644 index 000..f925651 --- /dev/null +++ b/contrib/systemd/haproxy.service.in @@ -0,0 +1,11 @@ +[Unit] +Description=HAProxy Load Balancer +After=network.target + +[Service] +ExecStart=@SBINDIR@/haproxy-systemd-wrapper -f /etc/haproxy/haproxy.cfg -p /run/haproxy.pid +ExecReload=/usr/bin/kill -USR2 $MAINPID +Restart=always + +[Install] +WantedBy=multi-user.target -- 1.8.1.2
Re: [PATCH 1/3] MEDIUM: New cli option -Ds for systemd compatibility
On 9 February 2013 09:45, Willy Tarreau w...@1wt.eu wrote: On Fri, Feb 08, 2013 at 03:58:46PM +0100, Marc-Antoine Perennou wrote: @@ -1493,8 +1499,13 @@ int main(int argc, char **argv) px = px-next; } - if (proc == global.nbproc) + if (proc == global.nbproc) { + if (global.mode MODE_SYSTEMD) { + for (proc = 0; proc global.nbproc; proc++) + waitpid(children[proc], NULL, 0); + } exit(0); /* parent must leave */ + } /* if we're NOT in QUIET mode, we should now close the 3 first FDs to ensure * that we can detach from the TTY. We MUST NOT do it in other cases since I think we have an issue here, which should not be too hard to fix. The parent is the one which binds to all the ports, so here it still owns them. This means that a soft restart of a new process will fail until the parent leaves, since it will not release these ports. And the parent will not leave until all of its children have terminated. Or maybe I'm missing something :-/ Also wouldn't it be worth catching EINTR here in the loop ? Otherwise I fear that random signals sent to the process will make the for loop progress to next child eventhough previous ones are not dead. This can easily happen during debugging sessions (ctrl-Z/bg) or when people mistakenly send a SIGHUP to the old process. Willy I just made a simple test, running a webserver serving a big file locally, using haproxy, my wrapper and systemd service. I started a download and during this download, reloaded haproxy. I using nbproc = 2. What happened ? When I started haproxy, I ended up with a wrapper launching a child launching itself two children, we'll call them ha1, ha11 and ha12. Then when I reloaded, the wrapper launched a new child which launched two new children, ha2, ha21 and ha22. ha11 and thus ha1 were still there until the download had finished, ha12 got to zombie state. ha2, ha21 and ha22 successfully have shown up and take all new connections. Once the download has finished, ha11 exited, ha12 too (waitpid making it leave the zombie state) and then ha11, leaving us with only ha2, ha21 and ha22. I think this is the expected behaviour, so there don't seem to be any bug here. For the EINTR stuff, I'm not sure at all, not really familiar with it, so I will give it a look
Re: [PATCH 2/3] MEDIUM: add haproxy-systemd-wrapper
I'll do even simpler, when submitting V2 of this patchset with the EINTR issue, I'll basically forard every arg given to the wrapper to all the children themselves. The tool is not really meant to be used by the user himself though, but rather to be launched by the systemd service. Is SIGUSR2 ok here ? I first did it with SIGUSR1 but then children couldn't bind to this signal on reload, since it was already a USR1 action, so I took the first one not colliding. On 9 February 2013 09:49, Willy Tarreau w...@1wt.eu wrote: On Fri, Feb 08, 2013 at 03:58:47PM +0100, Marc-Antoine Perennou wrote: +static void usage(const char *progname) +{ + fprintf(stderr, Usage: %s [-f cfgfile] [-p pidfile]\n, progname); Here I think it would be worth supporting most of the other command line arguments. For instance, -L is mandatory when session replication is enabled between multiple peers. -C is used by people who have to load many ACLs or certs and want to chdir there to load the files. -c is handy to validate configurations so that they don't have to switch between two different tools and syntaxes. I think we can ignore the various debugging flags now however. Regards, Willy
Re: [PATCH 1/3] MEDIUM: New cli option -Ds for systemd compatibility
On 9 February 2013 11:06, Willy Tarreau w...@1wt.eu wrote: Hi, On Sat, Feb 09, 2013 at 10:44:04AM +0100, Marc-Antoine Perennou wrote: I just made a simple test, running a webserver serving a big file locally, using haproxy, my wrapper and systemd service. I started a download and during this download, reloaded haproxy. I using nbproc = 2. What happened ? When I started haproxy, I ended up with a wrapper launching a child launching itself two children, we'll call them ha1, ha11 and ha12. Then when I reloaded, the wrapper launched a new child which launched two new children, ha2, ha21 and ha22. ha11 and thus ha1 were still there until the download had finished, ha12 got to zombie state. Then if ha1 was still there, I don't understand how it did not prevent the new process from binding to the port. Could you please check ha1 is still bound to the port once the process runs ? That's what I don't understand. ha2, ha21 and ha22 successfully have shown up and take all new connections. Once the download has finished, ha11 exited, ha12 too (waitpid making it leave the zombie state) and then ha11, leaving us with only ha2, ha21 and ha22. I think this is the expected behaviour, so there don't seem to be any bug here. Yes it's the expected behaviour, but I don't understand *why* it works, so it is very possible that we're having a bug somewhere else making this work as a side effect. For the EINTR stuff, I'm not sure at all, not really familiar with it, so I will give it a look Typically I would replace : waitpid(pid, NULL, 0); with while (waitpid(pid, NULL, 0) == -1 errno == EINTR); For instance, when your process receives SIGTTOU/SIGTTIN upon a failed attempt of a new process to start, the old one very likely skips a few children (one per signal). If it can help you, here's how to test for the worst case : - have a running process with a simple configuration bound to one port : listen foo bind :8000 - then have a second configuration which will not work due to a double bind on the same port, and another bind on the first port : listen foo bind :8000 listen fail1 bind :8001 listen fail2 bind :8001 - when the first one is running, try to start the second one. It will fail to bind to :8000, will send a SIGTTOU to process 1 and try again. Then it will fail to bind :8001 without knowing it's not because of #1, so it will wait a bit, believing it's #1 which has not yet released it, and then it will abort, sending SIGTTIN to #1 to inform it that it gives up and that #1 must continue its job as if nothing happened. - process 1 should then just remain unaffected. And restarting #1 with the fail2 listener commented out should work as expected. Best regards, Willy Maybe this can help you understand why it works: Before the download: haproxy 6090 root4u IPv4 53819 0t0 TCP *:http (LISTEN) haproxy 6092 root4u IPv4 53819 0t0 TCP *:http (LISTEN) haproxy 6093 root4u IPv4 53819 0t0 TCP *:http (LISTEN) During the download: haproxy 6090 root4u IPv4 53819 0t0 TCP *:http (LISTEN) haproxy 6092 root4u IPv4 53819 0t0 TCP *:http (LISTEN) haproxy 6093 root1u IPv4 57972 0t0 TCP Lou.local:http-Lou.local:40395 (ESTABLISHED) haproxy 6093 root4u IPv4 53819 0t0 TCP *:http (LISTEN) During the download, after the reload: haproxy 6093 root1u IPv4 57972 0t0 TCP Lou.local:http-Lou.local:40395 (ESTABLISHED) haproxy 6239 root4u IPv4 54622 0t0 TCP *:http (LISTEN) haproxy 6240 root4u IPv4 54622 0t0 TCP *:http (LISTEN) haproxy 6241 root4u IPv4 54622 0t0 TCP *:http (LISTEN) After the download: haproxy 6239 root4u IPv4 54622 0t0 TCP *:http (LISTEN) haproxy 6240 root4u IPv4 54622 0t0 TCP *:http (LISTEN) haproxy 6241 root4u IPv4 54622 0t0 TCP *:http (LISTEN)
[PATCH 2/3] MEDIUM: add haproxy-systemd-wrapper
Signed-off-by: Marc-Antoine Perennou marc-anto...@perennou.com --- .gitignore| 1 + Makefile | 16 +- src/haproxy-systemd-wrapper.c | 122 ++ 3 files changed, 137 insertions(+), 2 deletions(-) create mode 100644 src/haproxy-systemd-wrapper.c diff --git a/.gitignore b/.gitignore index 5d9576a..5e6f556 100644 --- a/.gitignore +++ b/.gitignore @@ -12,6 +12,7 @@ src/*.o *.log* *.trace* haproxy-* +!src/*.c make-* dlmalloc.c 00*.patch diff --git a/Makefile b/Makefile index f1eed55..ca9e1b2 100644 --- a/Makefile +++ b/Makefile @@ -593,7 +593,7 @@ all: @echo @exit 1 else -all: haproxy +all: haproxy haproxy-systemd-wrapper endif OBJS = src/haproxy.o src/sessionhash.o src/base64.o src/protocol.o \ @@ -618,12 +618,17 @@ ifneq ($(TRACE),) OBJS += src/trace.o endif +WRAPPER_OBJS = src/haproxy-systemd-wrapper.o + # Not used right now LIB_EBTREE = $(EBTREE_DIR)/libebtree.a haproxy: $(OBJS) $(OPTIONS_OBJS) $(EBTREE_OBJS) $(LD) $(LDFLAGS) -o $@ $^ $(LDOPTS) +haproxy-systemd-wrapper: $(WRAPPER_OBJS) + $(LD) $(LDFLAGS) -o $@ $^ $(LDOPTS) + $(LIB_EBTREE): $(EBTREE_OBJS) $(AR) rv $@ $^ @@ -646,6 +651,11 @@ src/haproxy.o: src/haproxy.c -DBUILD_OPTIONS='$(strip $(BUILD_OPTIONS))' \ -c -o $@ $ +src/haproxy-systemd-wrapper.o: src/haproxy-systemd-wrapper.c + $(CC) $(COPTS) \ + -DSBINDIR='$(strip $(SBINDIR))' \ + -c -o $@ $ + src/dlmalloc.o: $(DLMALLOC_SRC) $(CC) $(COPTS) -DDEFAULT_MMAP_THRESHOLD=$(DLMALLOC_THRES) -c -o $@ $ @@ -659,9 +669,10 @@ install-doc: install -m 644 doc/$$x.txt $(DESTDIR)$(DOCDIR) ; \ done -install-bin: haproxy +install-bin: haproxy haproxy-systemd-wrapper install -d $(DESTDIR)$(SBINDIR) install haproxy $(DESTDIR)$(SBINDIR) + install haproxy-systemd-wrapper $(DESTDIR)$(SBINDIR) install: install-bin install-man install-doc @@ -670,6 +681,7 @@ clean: for dir in . src include/* doc ebtree; do rm -f $$dir/*~ $$dir/*.rej $$dir/core; done rm -f haproxy-$(VERSION).tar.gz haproxy-$(VERSION)$(SUBVERS).tar.gz rm -f haproxy-$(VERSION) nohup.out gmon.out + rm -f haproxy-systemd-wrapper tags: find src include \( -name '*.c' -o -name '*.h' \) -print0 | \ diff --git a/src/haproxy-systemd-wrapper.c b/src/haproxy-systemd-wrapper.c new file mode 100644 index 000..aa509f6 --- /dev/null +++ b/src/haproxy-systemd-wrapper.c @@ -0,0 +1,122 @@ +/* + * Wrapper to make haproxy systemd-compliant. + * + * Copyright 2013 Marc-Antoine Perennou marc-anto...@perennou.com + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version + * 2 of the License, or (at your option) any later version. + * + */ + +#include limits.h +#include signal.h +#include stdarg.h +#include stdbool.h +#include stdio.h +#include stdlib.h +#include string.h +#include unistd.h +#include sys/wait.h + +#define MAX_ARGS 10 + +static pid_t pid = 0; +static const char *conf_file = /etc/haproxy/haproxy.cfg; +static const char *pid_file = /run/haproxy.pid; + +static pid_t exec_bg(char **pid_strv, int nb_pid, char *arg, ...) +{ + pid_t pid = fork(); + if (!pid) { + char **argv = calloc(MAX_ARGS + nb_pid + 1, sizeof(char *)); + int i; + int argno = 0; + va_list al; + va_start(al, arg); + while (arg argno MAX_ARGS + 1) { + argv[argno++] = arg; + arg = va_arg(al, char *); + } + va_end (al); + for (i = 0; i nb_pid; ++i) + argv[argno++] = pid_strv[i]; + argv[argno] = NULL; + execv(argv[0], argv); + exit(0); + } else return pid; +} + +static int read_pids(char ***pid_strv) +{ + FILE *f = fopen(pid_file, r); + int read = 0, allocated = 8; + char pid_str[10]; + + if (!f) + return 0; + + *pid_strv = malloc(allocated * sizeof(char *)); + while (1 == fscanf(f, %s\n, pid_str)) { + if (read == allocated) { + allocated *= 2; + *pid_strv = realloc(*pid_strv, allocated * sizeof(char *)); + } + (*pid_strv)[read++] = strdup(pid_str); + } + + fclose(f); + + return read; +} + +static void signal_handler(int signum __attribute__((unused))) +{ + int i; + char **pid_strv = NULL; + int nb_pid = read_pids(pid_strv); + + pid = exec_bg(pid_strv, nb_pid, SBINDIR/haproxy, -Ds, -f, conf_file, -p, pid_file, -sf, NULL); + + for (i = 0; i nb_pid; ++i) + free(pid_strv[i]); + free(pid_strv
HAProxy and systemd compatibility
Hi, Currently, to reload haproxy configuration, you have to use -sf. Systemd philosophy is for the daemon not to fork by themselves, but rather let the init process do it for them. My first patch adds a new option -Ds which is exactly like -D, but instead of forking n times to get n jobs running and then exiting, prefers to wait for all the children it just created. With this done, haproxy becomes more systemd-compliant, without changing anything for other systems. Now comes a problem with the -sf way to do things. First of all, in the systemd world, reload commands should be oneshot ones, which means they should not be the new main process but rather a tool which makes a call to it and then exits. With the current approach, the reload command is the new main command and moreover, it makes the previous one exit. Systemd only tracks the main program, seeing it ending, it assumes it either finished or failed, and kills everything remaining as a grabage collector. We then end up with no haproxy running at all. My second patch is a wrapper around haproxy, no changes at all have been made into it, so it's not intrusive and doesn't change anything for other hosts. What this wrapper does is basically launching haproxy as a child, listen to the SIGUSR2 (not to conflict with haproxy itself) signal, and spawing a new haproxy with -sf as a child to relay the first one. The third patch is a logical continuation to the two first ones, providing a systemd service file.
[PATCH 1/3] MEDIUM: New cli option -Ds for systemd compatibility
Signed-off-by: Marc-Antoine Perennou marc-anto...@perennou.com --- doc/haproxy-en.txt | 1 + doc/haproxy-fr.txt | 1 + doc/haproxy.1 | 4 include/types/global.h | 1 + src/haproxy.c | 35 +++ 5 files changed, 30 insertions(+), 12 deletions(-) diff --git a/doc/haproxy-en.txt b/doc/haproxy-en.txt index 3d2a2be..4c673d3 100644 --- a/doc/haproxy-en.txt +++ b/doc/haproxy-en.txt @@ -51,6 +51,7 @@ There are only a few command line options : = 'maxconn' in 'listen' or 'default' sections -d starts in foregreound with debugging mode enabled -D starts in daemon mode +-Ds starts in systemd daemon mode -q disable messages on output -V displays messages on output even when -q or 'quiet' are specified. -c only checks config file and exits with code 0 if no error was found, or diff --git a/doc/haproxy-fr.txt b/doc/haproxy-fr.txt index 87bb972..0e36724 100644 --- a/doc/haproxy-fr.txt +++ b/doc/haproxy-fr.txt @@ -53,6 +53,7 @@ Les options de lancement sont peu nombreuses : = 'maxconn' dans les sections 'listen' ou 'default' -d active le mode debug -D passe en daemon +-Ds passe en daemon systemd -q d�sactive l'affichage de messages sur la sortie standard. -V affiche les messages sur la sortie standard, m�me si -q ou 'quiet' sont sp�cifi�s. diff --git a/doc/haproxy.1 b/doc/haproxy.1 index 001de15..48717ad 100644 --- a/doc/haproxy.1 +++ b/doc/haproxy.1 @@ -57,6 +57,10 @@ starting up. Start in daemon mode. .TP +\fB\-Ds\fP +Start in systemd daemon mode, keeping a process in foreground. + +.TP \fB\-q\fP Disable messages on output. diff --git a/include/types/global.h b/include/types/global.h index 133a98d..730cc64 100644 --- a/include/types/global.h +++ b/include/types/global.h @@ -42,6 +42,7 @@ #defineMODE_VERBOSE0x10 #defineMODE_STARTING 0x20 #defineMODE_FOREGROUND 0x40 +#defineMODE_SYSTEMD0x80 /* list of last checks to perform, depending on config options */ #define LSTCHK_CAP_BIND0x0001 /* check that we can bind to any port */ diff --git a/src/haproxy.c b/src/haproxy.c index 4503a01..75ebd52 100644 --- a/src/haproxy.c +++ b/src/haproxy.c @@ -42,6 +42,7 @@ #include signal.h #include stdarg.h #include sys/resource.h +#include sys/wait.h #include time.h #include syslog.h #include grp.h @@ -539,8 +540,11 @@ void init(int argc, char **argv) arg_mode |= MODE_DEBUG; else if (*flag == 'c') arg_mode |= MODE_CHECK; - else if (*flag == 'D') + else if (*flag == 'D') { arg_mode |= MODE_DAEMON; + if (flag[1] == 's') /* -Ds */ + arg_mode |= MODE_SYSTEMD; + } else if (*flag == 'q') arg_mode |= MODE_QUIET; else if (*flag == 's' (flag[1] == 'f' || flag[1] == 't')) { @@ -594,7 +598,7 @@ void init(int argc, char **argv) } global.mode = MODE_STARTING | /* during startup, we want most of the alerts */ - (arg_mode (MODE_DAEMON | MODE_FOREGROUND | MODE_VERBOSE + (arg_mode (MODE_DAEMON | MODE_SYSTEMD | MODE_FOREGROUND | MODE_VERBOSE | MODE_QUIET | MODE_CHECK | MODE_DEBUG)); if (LIST_ISEMPTY(cfg_cfgfiles)) @@ -733,24 +737,24 @@ void init(int argc, char **argv) if (arg_mode (MODE_DEBUG | MODE_FOREGROUND)) { /* command line debug mode inhibits configuration mode */ - global.mode = ~(MODE_DAEMON | MODE_QUIET); + global.mode = ~(MODE_DAEMON | MODE_SYSTEMD | MODE_QUIET); global.mode |= (arg_mode (MODE_DEBUG | MODE_FOREGROUND)); } - if (arg_mode MODE_DAEMON) { + if (arg_mode (MODE_DAEMON | MODE_SYSTEMD)) { /* command line daemon mode inhibits foreground and debug modes mode */ global.mode = ~(MODE_DEBUG | MODE_FOREGROUND); - global.mode |= (arg_mode MODE_DAEMON); + global.mode |= (arg_mode (MODE_DAEMON | MODE_SYSTEMD)); } global.mode |= (arg_mode (MODE_QUIET | MODE_VERBOSE)); - if ((global.mode MODE_DEBUG) (global.mode (MODE_DAEMON | MODE_QUIET))) { - Warning(debug mode incompatible with quiet and daemon. Keeping debug only.\n); - global.mode = ~(MODE_DAEMON | MODE_QUIET); + if ((global.mode MODE_DEBUG) (global.mode (MODE_DAEMON | MODE_SYSTEMD | MODE_QUIET))) { + Warning(debug mode incompatible with quiet, daemon and systemd. Keeping debug only.\n); + global.mode = ~(MODE_DAEMON | MODE_SYSTEMD | MODE_QUIET); } - if ((global.nbproc 1
[PATCH 3/3] MEDIUM: add systemd service
Signed-off-by: Marc-Antoine Perennou marc-anto...@perennou.com --- .gitignore | 1 + Makefile | 8 ++-- contrib/systemd/haproxy.service.in | 11 +++ 3 files changed, 18 insertions(+), 2 deletions(-) create mode 100644 contrib/systemd/haproxy.service.in diff --git a/.gitignore b/.gitignore index 5e6f556..ec1545a 100644 --- a/.gitignore +++ b/.gitignore @@ -16,3 +16,4 @@ haproxy-* make-* dlmalloc.c 00*.patch +*.service diff --git a/Makefile b/Makefile index ca9e1b2..1b81fc7 100644 --- a/Makefile +++ b/Makefile @@ -593,7 +593,7 @@ all: @echo @exit 1 else -all: haproxy haproxy-systemd-wrapper +all: haproxy haproxy-systemd-wrapper systemd/haproxy.service endif OBJS = src/haproxy.o src/sessionhash.o src/base64.o src/protocol.o \ @@ -659,6 +659,10 @@ src/haproxy-systemd-wrapper.o: src/haproxy-systemd-wrapper.c src/dlmalloc.o: $(DLMALLOC_SRC) $(CC) $(COPTS) -DDEFAULT_MMAP_THRESHOLD=$(DLMALLOC_THRES) -c -o $@ $ +systemd/haproxy.service: contrib/systemd/haproxy.service.in + mkdir -p systemd + sed -e 's:@SBINDIR@:'$(strip $(SBINDIR))':' $ $@ + install-man: install -d $(DESTDIR)$(MANDIR)/man1 install -m 644 doc/haproxy.1 $(DESTDIR)$(MANDIR)/man1 @@ -681,7 +685,7 @@ clean: for dir in . src include/* doc ebtree; do rm -f $$dir/*~ $$dir/*.rej $$dir/core; done rm -f haproxy-$(VERSION).tar.gz haproxy-$(VERSION)$(SUBVERS).tar.gz rm -f haproxy-$(VERSION) nohup.out gmon.out - rm -f haproxy-systemd-wrapper + rm -f haproxy-systemd-wrapper systemd/haproxy.service tags: find src include \( -name '*.c' -o -name '*.h' \) -print0 | \ diff --git a/contrib/systemd/haproxy.service.in b/contrib/systemd/haproxy.service.in new file mode 100644 index 000..f925651 --- /dev/null +++ b/contrib/systemd/haproxy.service.in @@ -0,0 +1,11 @@ +[Unit] +Description=HAProxy Load Balancer +After=network.target + +[Service] +ExecStart=@SBINDIR@/haproxy-systemd-wrapper -f /etc/haproxy/haproxy.cfg -p /run/haproxy.pid +ExecReload=/usr/bin/kill -USR2 $MAINPID +Restart=always + +[Install] +WantedBy=multi-user.target -- 1.8.1.2
Re: -sf/-st not working
It is totally normal that systemd kills the new process as the main one which was the first has exited. This is the expected behaviour. I'm currently patching haproxy to fully support systemd, I'll probably submit my patches by tomorrow (It's fully functionnal here, only needs a little cleaning) On 7 February 2013 16:31, Eugene Istomin e.isto...@edss.ee wrote: ** I think the main problem is in systemd: - from commandline -sf working as expected - from sysvinit -sf working as expected - from systemd -sf only stop process. I try both init.d systemd scripts in systemd-based linux - all results are the same: Loaded: loaded (/lib/systemd/system/haproxy.service; disabled) Active: failed (Result: signal) since Thu, 07 Feb 2013 17:18:43 +0200; 12s ago Process: 28125 ExecReload=/usr/sbin/haproxy -D -f /etc/haproxy/haproxy.cfg -p /var/run/haproxy.pid -sf $MAINPID (code=exited, status=0/SUCCESS) Process: 28118 ExecStart=/usr/sbin/haproxy -D -f /etc/haproxy/haproxy.cfg -p /var/run/haproxy.pid (code=exited, status=0/SUCCESS) Process: 28115 ExecStartPre=/usr/sbin/haproxy -c -q -f /etc/haproxy/haproxy.cfg (code=exited, status=0/SUCCESS) Main PID: 28126 (code=killed, signal=KILL) CGroup: name=systemd:/system/haproxy.service systemd script: [Unit] Description=HAProxy For TCP And HTTP Based Applications After=network.target [Service] Type=forking PIDFile=/var/run/haproxy.pid ExecStartPre=/usr/sbin/haproxy -c -q -f /etc/haproxy/haproxy.cfg ExecStart=/usr/sbin/haproxy -D -f /etc/haproxy/haproxy.cfg -p /var/run/haproxy.pid ExecReload=/usr/sbin/haproxy -D -f /etc/haproxy/haproxy.cfg -p /var/run/haproxy.pid -sf $MAINPID [Install] WantedBy=multi-user.target -- Best regards, Eugene Istomin On Thursday 07 February 2013 14:07:44 Baptiste wrote: You should have a new HAProxy process started using the new configuration and binding the ports... cheers On 2/7/13, Eugene Istomin e.isto...@edss.ee wrote: Thanks for the answer, as written in http://www.mgoff.in/2010/04/18/haproxy-reloading-your-config-with- minimal-service-impact/ The end-result is a reload of the configuration file which is not visible by the customer But in our case it leads to unbinding from all ports and finishing haproxy process. Can this issue related to rpm build options? RPM build log is https://build.opensuse.org/package/rawlog?arch=x86_64package=haproxy-1.5; project=server%3Ahttprepository=openSUSE_12.2 -- Best regards, Eugene Istomin On Thursday 07 February 2013 07:28:17 Willy Tarreau wrote: Hello Eugene, On Wed, Feb 06, 2013 at 08:29:33PM +0200, Eugene Istomin wrote: Hello, We have problem with reload/HUP: if i run #/usr/sbin/haproxy -D -f /etc/haproxy/haproxy.cfg -p /var/run/haproxy.pid -sf $(cat /var/run/haproxy.pid) - haproxy process is shutting down and exit This is the intended behaviour, it unbinds from its ports so that the new process can bind, then waits for all existing connections to terminate and leaves. Isn't it what you're observing ? What would you have expected instead ? Willy
[PATCH] MEDIUM: New cli option -Ds for systemd compatibility
Signed-off-by: Marc-Antoine Perennou marc-anto...@perennou.com --- doc/haproxy-en.txt | 1 + doc/haproxy-fr.txt | 1 + doc/haproxy.1 | 4 include/types/global.h | 1 + src/haproxy.c | 31 +++ 5 files changed, 26 insertions(+), 12 deletions(-) diff --git a/doc/haproxy-en.txt b/doc/haproxy-en.txt index 6a7aa01..e54c714 100644 --- a/doc/haproxy-en.txt +++ b/doc/haproxy-en.txt @@ -51,6 +51,7 @@ There are only a few command line options : = 'maxconn' in 'listen' or 'default' sections -d starts in foregreound with debugging mode enabled -D starts in daemon mode +-Ds starts in systemd daemon mode -q disable messages on output -V displays messages on output even when -q or 'quiet' are specified. -c only checks config file and exits with code 0 if no error was found, or diff --git a/doc/haproxy-fr.txt b/doc/haproxy-fr.txt index 89df8cb..85f4168 100644 --- a/doc/haproxy-fr.txt +++ b/doc/haproxy-fr.txt @@ -53,6 +53,7 @@ Les options de lancement sont peu nombreuses : = 'maxconn' dans les sections 'listen' ou 'default' -d active le mode debug -D passe en daemon +-Ds passe en daemon systemd -q d�sactive l'affichage de messages sur la sortie standard. -V affiche les messages sur la sortie standard, m�me si -q ou 'quiet' sont sp�cifi�s. diff --git a/doc/haproxy.1 b/doc/haproxy.1 index 001de15..48717ad 100644 --- a/doc/haproxy.1 +++ b/doc/haproxy.1 @@ -57,6 +57,10 @@ starting up. Start in daemon mode. .TP +\fB\-Ds\fP +Start in systemd daemon mode, keeping a process in foreground. + +.TP \fB\-q\fP Disable messages on output. diff --git a/include/types/global.h b/include/types/global.h index 28632b7..f6e0eac 100644 --- a/include/types/global.h +++ b/include/types/global.h @@ -42,6 +42,7 @@ #defineMODE_VERBOSE0x10 #defineMODE_STARTING 0x20 #defineMODE_FOREGROUND 0x40 +#defineMODE_SYSTEMD0x80 /* list of last checks to perform, depending on config options */ #define LSTCHK_CAP_BIND0x0001 /* check that we can bind to any port */ diff --git a/src/haproxy.c b/src/haproxy.c index c6933c3..b7430f8 100644 --- a/src/haproxy.c +++ b/src/haproxy.c @@ -42,6 +42,7 @@ #include signal.h #include stdarg.h #include sys/resource.h +#include sys/wait.h #include time.h #include syslog.h @@ -509,8 +510,11 @@ void init(int argc, char **argv) arg_mode |= MODE_DEBUG; else if (*flag == 'c') arg_mode |= MODE_CHECK; - else if (*flag == 'D') + else if (*flag == 'D') { arg_mode |= MODE_DAEMON; + if (flag[1] == 's') /* -Ds */ + arg_mode |= MODE_SYSTEMD; + } else if (*flag == 'q') arg_mode |= MODE_QUIET; else if (*flag == 's' (flag[1] == 'f' || flag[1] == 't')) { @@ -564,7 +568,7 @@ void init(int argc, char **argv) } global.mode = MODE_STARTING | /* during startup, we want most of the alerts */ - (arg_mode (MODE_DAEMON | MODE_FOREGROUND | MODE_VERBOSE + (arg_mode (MODE_DAEMON | MODE_SYSTEMD | MODE_FOREGROUND | MODE_VERBOSE | MODE_QUIET | MODE_CHECK | MODE_DEBUG)); if (LIST_ISEMPTY(cfg_cfgfiles)) @@ -715,24 +719,24 @@ void init(int argc, char **argv) if (arg_mode (MODE_DEBUG | MODE_FOREGROUND)) { /* command line debug mode inhibits configuration mode */ - global.mode = ~(MODE_DAEMON | MODE_QUIET); + global.mode = ~(MODE_DAEMON | MODE_SYSTEMD | MODE_QUIET); global.mode |= (arg_mode (MODE_DEBUG | MODE_FOREGROUND)); } - if (arg_mode MODE_DAEMON) { + if (arg_mode (MODE_DAEMON | MODE_SYSTEMD)) { /* command line daemon mode inhibits foreground and debug modes mode */ global.mode = ~(MODE_DEBUG | MODE_FOREGROUND); - global.mode |= (arg_mode MODE_DAEMON); + global.mode |= (arg_mode (MODE_DAEMON | MODE_SYSTEMD)); } global.mode |= (arg_mode (MODE_QUIET | MODE_VERBOSE)); - if ((global.mode MODE_DEBUG) (global.mode (MODE_DAEMON | MODE_QUIET))) { - Warning(debug mode incompatible with quiet and daemon. Keeping debug only.\n); - global.mode = ~(MODE_DAEMON | MODE_QUIET); + if ((global.mode MODE_DEBUG) (global.mode (MODE_DAEMON | MODE_SYSTEMD | MODE_QUIET))) { + Warning(debug mode incompatible with quiet, daemon and systemd. Keeping debug only.\n); + global.mode = ~(MODE_DAEMON | MODE_SYSTEMD | MODE_QUIET); } - if ((global.nbproc 1) !(global.mode MODE_DAEMON