From: Paulo Vital <pvital(a)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(a)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(a)/nginx/conf.d'
if self.installed:
- self.nginx_conf_dir = '@sysconfdir(a)/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