[PATCH V4] [Wok] Use system's nginx proxy service.

From: Paulo Vital <pvital@linux.vnet.ibm.com> This patch works on Fedora 23 and 24, RHEL 7.2, Ubuntu 16.04, Debian 8.5 and OpenSUSE 42.1 It's recommended to follow the current steps reported in Troubleshooting wiki page of Wok: https://github.com/kimchi-project/wok/blob/master/docs/troubleshooting.md V4: - Use values of session timeout from configuration to set proxy timeout - remove un-necessary method to check if Wok is installed V3: - removed unnecessary semanage command. V2: - fixed PEP8 errors V1: This patch removes the code that executes a dedicated nginx proxy, making Wok to use the system's nginx service. This is a requirement to make Wok acceptable in community repositories. It also make sure that a Wok executed from path different than installed (from a cloned and builded source code, for example) will create a symbolic link in system's nginx config dir to the running configuration file. This patch solves part of issue #25 Paulo Vital (1): Use system's nginx proxy service. src/nginx/wok.conf.in | 95 +++++++++++++++++++++------------------------------ src/wok/config.py.in | 3 +- src/wok/i18n.py | 2 ++ src/wok/proxy.py | 28 ++++++++------- src/wok/server.py | 6 +--- 5 files changed, 60 insertions(+), 74 deletions(-) -- 2.7.4

From: Paulo Vital <pvital@linux.vnet.ibm.com> This patch removes the code that executes a dedicated nginx proxy, making Wok to use the system's nginx service. This is a requirement to make Wok acceptable in community repositories. It also make sure that a Wok executed from path different than installed (from a cloned and builded source code, for example) will create a symbolic link in system's nginx config dir to the running configuration file. This patch solves part of issue #25 Signed-off-by: Paulo Vital <pvital@linux.vnet.ibm.com> --- src/nginx/wok.conf.in | 95 +++++++++++++++++++++------------------------------ src/wok/config.py.in | 3 +- src/wok/i18n.py | 2 ++ src/wok/proxy.py | 28 ++++++++------- src/wok/server.py | 6 +--- 5 files changed, 60 insertions(+), 74 deletions(-) diff --git a/src/nginx/wok.conf.in b/src/nginx/wok.conf.in index cb05e4d..512b00b 100644 --- a/src/nginx/wok.conf.in +++ b/src/nginx/wok.conf.in @@ -22,71 +22,54 @@ # This is a template file to be used to generate a nginx # proxy config file at wokd script. -user ${user}; -worker_processes 1; +client_max_body_size ${max_body_size}k; -error_log /var/log/nginx/error.log; +# Set timeout, based on configuration values, to avoid the 504 Gateway Timeout +# when Wok is processing a request. +proxy_connect_timeout ${session_timeout}m; +proxy_send_timeout ${session_timeout}m; +proxy_read_timeout ${session_timeout}m; +send_timeout ${session_timeout}m; -events { - worker_connections 1024; +map $http_upgrade $connection_upgrade { + default upgrade; + '' close; } -http { - log_format main '$remote_addr - $remote_user [$time_local] "$request" ' - '$status $body_bytes_sent "$http_referer" ' - '"$http_user_agent" "$http_x_forwarded_for"'; - - access_log /var/log/nginx/access.log main; - sendfile on; +upstream websocket { + server 127.0.0.1:${websockets_port}; +} - client_max_body_size ${max_body_size}k; +server { + listen ${host_addr}:${proxy_ssl_port} ssl; - # Timeout set to 10 minutes to avoid the 504 Gateway Timeout - # when Wok is processing a request. - proxy_connect_timeout 600; - proxy_send_timeout 600; - proxy_read_timeout 600; - send_timeout 600; + ssl_certificate ${cert_pem}; + ssl_certificate_key ${cert_key}; + ssl_protocols TLSv1.1 TLSv1.2; + ssl_ciphers 'ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES256-GCM-SHA384:DHE-RSA-AES128-GCM-SHA256:DHE-DSS-AES128-GCM-SHA256:kEDH+AESGCM:ECDHE-RSA-AES128-SHA256:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA:ECDHE-ECDSA-AES128-SHA:ECDHE-RSA-AES256-SHA384:ECDHE-ECDSA-AES256-SHA384:ECDHE-RSA-AES256-SHA:ECDHE-ECDSA-AES256-SHA:DHE-RSA-AES128-SHA256:DHE-RSA-AES128-SHA:DHE-DSS-AES128-SHA256:DHE-RSA-AES256-SHA256:DHE-DSS-AES256-SHA:DHE-RSA-AES256-SHA:AES128-GCM-SHA256:AES256-GCM-SHA384:AES128-SHA256:AES256-SHA256:AES128-SHA:AES256-SHA:AES:CAMELLIA:DES-CBC3-SHA:!aNULL:!eNULL:!EXPORT:!DES:!RC4:!MD5:!PSK:!aECDH:!EDH-DSS-DES-CBC3-SHA:!EDH-RSA-DES-CBC3-SHA:!KRB5-DES-CBC3-SHA:@STRENGTH'; + ssl_prefer_server_ciphers on; + ssl_dhparam ${dhparams_pem}; + ssl_session_timeout ${session_timeout}m; - map $http_upgrade $connection_upgrade { - default upgrade; - '' close; - } + add_header Strict-Transport-Security "max-age=31536000; includeSubdomains;"; + add_header X-Frame-Options DENY; + add_header X-Content-Type-Options nosniff; + add_header X-XSS-Protection "1; mode=block"; - upstream websocket { - server 127.0.0.1:${websockets_port}; + location / { + proxy_pass http://127.0.0.1:${cherrypy_port}; + proxy_set_header Host $host; + proxy_set_header X-Real-IP $remote_addr; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + proxy_redirect http://127.0.0.1:${cherrypy_port}/ https://$host:${proxy_ssl_port}/; } - server { - listen ${host_addr}:${proxy_ssl_port} ssl; - - ssl_certificate ${cert_pem}; - ssl_certificate_key ${cert_key}; - ssl_protocols TLSv1.1 TLSv1.2; - ssl_ciphers 'ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES256-GCM-SHA384:DHE-RSA-AES128-GCM-SHA256:DHE-DSS-AES128-GCM-SHA256:kEDH+AESGCM:ECDHE-RSA-AES128-SHA256:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA:ECDHE-ECDSA-AES128-SHA:ECDHE-RSA-AES256-SHA384:ECDHE-ECDSA-AES256-SHA384:ECDHE-RSA-AES256-SHA:ECDHE-ECDSA-AES256-SHA:DHE-RSA-AES128-SHA256:DHE-RSA-AES128-SHA:DHE-DSS-AES128-SHA256:DHE-RSA-AES256-SHA256:DHE-DSS-AES256-SHA:DHE-RSA-AES256-SHA:AES128-GCM-SHA256:AES256-GCM-SHA384:AES128-SHA256:AES256-SHA256:AES128-SHA:AES256-SHA:AES:CAMELLIA:DES-CBC3-SHA:!aNULL:!eNULL:!EXPORT:!DES:!RC4:!MD5:!PSK:!aECDH:!EDH-DSS-DES-CBC3-SHA:!EDH-RSA-DES-CBC3-SHA:!KRB5-DES-CBC3-SHA:@STRENGTH'; - ssl_prefer_server_ciphers on; - ssl_dhparam ${dhparams_pem}; - ssl_session_timeout ${session_timeout}m; - - add_header Strict-Transport-Security "max-age=31536000; includeSubdomains;"; - add_header X-Frame-Options DENY; - add_header X-Content-Type-Options nosniff; - add_header X-XSS-Protection "1; mode=block"; - - location / { - proxy_pass http://127.0.0.1:${cherrypy_port}; - proxy_set_header Host $host; - proxy_set_header X-Real-IP $remote_addr; - proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; - proxy_redirect http://127.0.0.1:${cherrypy_port}/ https://$host:${proxy_ssl_port}/; - } - - location /websockify { - proxy_pass http://websocket; - proxy_http_version 1.1; - proxy_set_header Upgrade $http_upgrade; - proxy_set_header Connection $connection_upgrade; - } + location /websockify { + proxy_pass http://websocket; + proxy_http_version 1.1; + proxy_set_header Upgrade $http_upgrade; + proxy_set_header Connection $connection_upgrade; } - ${http_config} } + +${http_config} diff --git a/src/wok/config.py.in b/src/wok/config.py.in index 1ca6f73..cbe585c 100644 --- a/src/wok/config.py.in +++ b/src/wok/config.py.in @@ -76,9 +76,10 @@ class Paths(object): self.prefix = self.get_prefix() self.installed = (self.prefix == '@pkgdatadir@') self.ui_dir = self.add_prefix('ui') + self.sys_nginx_conf_dir = '@sysconfdir@/nginx/conf.d' if self.installed: - self.nginx_conf_dir = '@sysconfdir@/nginx/conf.d' + self.nginx_conf_dir = self.sys_nginx_conf_dir self.state_dir = '@localstatedir@/lib/wok' self.log_dir = '@localstatedir@/log/wok' self.conf_dir = '@sysconfdir@/wok' diff --git a/src/wok/i18n.py b/src/wok/i18n.py index d6cb17c..33107ee 100644 --- a/src/wok/i18n.py +++ b/src/wok/i18n.py @@ -55,6 +55,8 @@ messages = { "WOKUTILS0004E": _("Invalid data value '%(value)s'"), "WOKUTILS0005E": _("Invalid data unit '%(unit)s'"), + "WOKPROXY0001E": _("Unable to (re)start system's nginx.service. Details: '%(error)s'"), + # These messages (ending with L) are for user log purposes "WOKCOL0001L": _("Request made on collection"), "WOKRES0001L": _("Request made on resource"), diff --git a/src/wok/proxy.py b/src/wok/proxy.py index a74e88a..b68b86e 100644 --- a/src/wok/proxy.py +++ b/src/wok/proxy.py @@ -26,11 +26,12 @@ import os import pwd -import subprocess from string import Template from wok import sslcert from wok.config import paths +from wok.exception import OperationFailed +from wok.utils import run_command HTTP_CONFIG = """ @@ -110,18 +111,21 @@ def _create_proxy_config(options): config_file.write(data) config_file.close() + # If not running from the installed path (from a cloned and builded source + # code), create a symbolic link in system's dir to prevent errors on read + # SSL certifications. + if not paths.installed: + dst = os.path.join(paths.sys_nginx_conf_dir, "wok.conf") + if os.path.isfile(dst) or os.path.islink(dst): + os.remove(dst) + os.symlink(os.path.join(nginx_config_dir, "wok.conf"), dst) + def start_proxy(options): """Start nginx reverse proxy.""" _create_proxy_config(options) - nginx_config_dir = paths.nginx_conf_dir - config_file = "%s/wok.conf" % nginx_config_dir - cmd = ['nginx', '-c', config_file] - subprocess.call(cmd) - - -def terminate_proxy(): - """Stop nginx process.""" - config_file = "%s/wok.conf" % paths.nginx_conf_dir - term_proxy_cmd = ['nginx', '-s', 'stop', '-c', config_file] - subprocess.call(term_proxy_cmd) + # Restart system's nginx service to reload wok configuration + cmd = ['systemctl', 'restart', 'nginx.service'] + output, error, retcode = run_command(cmd, silent=True) + if retcode != 0: + raise OperationFailed('WOKPROXY0001E', {'error': error}) diff --git a/src/wok/server.py b/src/wok/server.py index 8a02596..b1185e3 100644 --- a/src/wok/server.py +++ b/src/wok/server.py @@ -33,7 +33,7 @@ from wok.config import config as configParser from wok.config import paths, PluginConfig, WokConfig from wok.control import sub_nodes from wok.model import model -from wok.proxy import start_proxy, terminate_proxy +from wok.proxy import start_proxy from wok.reqlogger import RequestLogger from wok.root import WokRoot from wok.safewatchedfilehandler import SafeWatchedFileHandler @@ -180,10 +180,6 @@ class Server(object): self.app = cherrypy.tree.mount(WokRoot(model_instance, dev_env), config=self.configObj) self._load_plugins(options) - - # Terminate proxy when cherrypy server is terminated - cherrypy.engine.subscribe('exit', terminate_proxy) - cherrypy.lib.sessions.init() def _load_plugins(self, options): -- 2.7.4
participants (2)
-
Aline Manera
-
pvital@linux.vnet.ibm.com