On Jul 21 11:11AM, Aline Manera wrote:
On 07/18/2016 06:59 PM, pvital(a)linux.vnet.ibm.com wrote:
> 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 | 6 +++-
> src/wok/i18n.py | 2 ++
> src/wok/proxy.py | 28 ++++++++-------
> src/wok/server.py | 6 +---
> 5 files changed, 63 insertions(+), 74 deletions(-)
>
> diff --git a/src/nginx/wok.conf.in b/src/nginx/wok.conf.in
> index cb05e4d..823d94d 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;
> +# Timeout set to 10 minutes to avoid the 504 Gateway Timeout
> +# when Wok is processing a request.
The session timeout is configurable in the wok config file so you should not
assume 10 minutes.
You will need to get the timeout value and do the right count to set the
nginx config file.
Interesting!!! The current code has this values hardcoded.
I'll change this.
> +proxy_connect_timeout 600;
> +proxy_send_timeout 600;
> +proxy_read_timeout 600;
> +send_timeout 600;
> -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..d0bca9b 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'
> @@ -119,6 +120,9 @@ class Paths(object):
> def get_template_path(self, resource):
> return os.path.join(self.ui_dir, 'pages/%s.tmpl' % resource)
> + def is_wok_installed(self):
> + return self.installed
> +
In other part of the code, we are accessing self.installed directly! Any
special reason to create this new function?
Seems like too Java huh
Really? I'm going to check better, but I guess the only code I saw was
inside the same class or method.
> paths = Paths()
>
> 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..cf978ad 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.is_wok_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):
--
Paulo Ricardo Paz Vital
Linux Technology Center, IBM Systems
http://www.ibm.com/linux/ltc/