Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
Allow custom configs with LBaaS
This fix takes care of haproxy parsing and
validation changes on vrouter agent. Removing
extra white spaces

Closes-Bug: #1475393
Change-Id: I822e27792f78168a178d555db5703fa1e73d0cc9
  • Loading branch information
Varun Lodaya authored and Varun Lodaya committed Sep 3, 2015
1 parent cd74710 commit cfbd9b8
Show file tree
Hide file tree
Showing 3 changed files with 162 additions and 8 deletions.
1 change: 1 addition & 0 deletions src/vnsw/opencontrail-vrouter-netns/SConscript
Expand Up @@ -18,6 +18,7 @@ sources = [
'opencontrail_vrouter_netns/vrouter_netns.py',
'opencontrail_vrouter_netns/haproxy_config.py',
'opencontrail_vrouter_netns/haproxy_process.py',
'opencontrail_vrouter_netns/haproxy_validator.py',
'opencontrail_vrouter_netns/vrouter_docker.py',
'opencontrail_vrouter_netns/daemon_start.py',
'opencontrail_vrouter_netns/daemon_stop.py',
Expand Down
@@ -1,6 +1,16 @@
import json
import os

def validate_custom_attributes(config, section):
return {}

try:
from haproxy_validator import validate_custom_attributes as validator
from haproxy_validator import custom_attributes_dict
except ImportError:
validator = validate_custom_attributes
custom_attributes_dict = {}

PROTO_TCP = 'TCP'
PROTO_HTTP = 'HTTP'
PROTO_HTTPS = 'HTTPS'
Expand Down Expand Up @@ -45,6 +55,15 @@ def build_config(conf_file):
return filename

def _set_global_config(config, sock_path):
global_custom_attributes = validator(config, 'global')
maxconn = global_custom_attributes.pop('maxconn', None) \
if 'maxconn' in global_custom_attributes else 65000
ssl_ciphers = global_custom_attributes.pop('ssl_ciphers', None) \
if 'ssl_ciphers' in global_custom_attributes else \
'ECDH+AESGCM:DH+AESGCM:ECDH+AES256:DH+AES256:' \
'ECDH+AES128:DH+AES:ECDH+3DES:DH+3DES:RSA+AESGCM:' \
'RSA+AES:RSA+3DES:!aNULL:!MD5:!DSS'

conf = [
'global',
'daemon',
Expand All @@ -53,30 +72,45 @@ def _set_global_config(config, sock_path):
'log /dev/log local0',
'log /dev/log local1 notice',
'tune.ssl.default-dh-param 2048',
'ssl-default-bind-ciphers ECDH+AESGCM:' \
'DH+AESGCM:ECDH+AES256:DH+AES256:ECDH+AES128:' \
'DH+AES:ECDH+3DES:DH+3DES:RSA+AESGCM:RSA+AES:' \
'RSA+3DES:!aNULL:!MD5:!DSS',
'ssl-default-bind-ciphers %s' % ssl_ciphers,
'ulimit-n 200000',
'maxconn 65000'
'maxconn %d' % maxconn
]
conf.append('stats socket %s mode 0666 level user' % sock_path)
for key, value in global_custom_attributes.iteritems():
cmd = custom_attributes_dict['global'][key]['cmd']
conf.append(cmd % value)

return ("\n\t".join(conf))

def _set_defaults(config):
default_custom_attributes = validator(config, 'default')
client_timeout = default_custom_attributes.pop('client_timeout', None) \
if 'client_timeout' in default_custom_attributes else 300000
server_timeout = default_custom_attributes.pop('server_timeout', None) \
if 'server_timeout' in default_custom_attributes else 300000
connect_timeout = default_custom_attributes.pop('connect_timeout', None) \
if 'connect_timeout' in default_custom_attributes else 5000

conf = [
'defaults',
'log global',
'retries 3',
'option redispatch',
'timeout connect 5000',
'timeout client 300000',
'timeout server 300000',
'timeout connect %d' % connect_timeout,
'timeout client %d' % client_timeout,
'timeout server %d' % server_timeout,
]

for key, value in default_custom_attributes.iteritems():
cmd = custom_attributes_dict['default'][key]['cmd']
conf.append(cmd % value)

return ("\n\t".join(conf))

def _set_frontend(config):
port = config['vip']['port']
vip_custom_attributes = validator(config, 'vip')
ssl = ''
if config['vip']['protocol'] == PROTO_HTTPS:
ssl = 'ssl crt %s no-sslv3' % config['ssl-crt']
Expand All @@ -92,9 +126,15 @@ def _set_frontend(config):
if config['vip']['protocol'] == PROTO_HTTP or \
config['vip']['protocol'] == PROTO_HTTPS:
conf.append('option forwardfor')

for key, value in vip_custom_attributes.iteritems():
cmd = custom_attributes_dict['vip'][key]['cmd']
conf.append(cmd % value)

return ("\n\t".join(conf))

def _set_backend(config):
pool_custom_attributes = validator(config, 'pool')
conf = [
'backend %s' % config['pool']['id'],
'mode %s' % PROTO_MAP[config['pool']['protocol']],
Expand All @@ -103,6 +143,10 @@ def _set_backend(config):
if config['pool']['protocol'] == PROTO_HTTP:
conf.append('option forwardfor')

for key, value in pool_custom_attributes.iteritems():
cmd = custom_attributes_dict['pool'][key]['cmd']
conf.append(cmd % value)

server_suffix, monitor_conf = _set_health_monitor(config)
conf.extend(monitor_conf)
session_conf = _set_session_persistence(config)
Expand All @@ -117,6 +161,10 @@ def _set_backend(config):
server += ' cookie %d' % config['members'].index(member)
conf.append(server)

for key, value in pool_custom_attributes.iteritems():
cmd = custom_attributes_dict['pool'][key]['cmd']
conf.append(cmd % value)

return ("\n\t".join(conf))

def _set_health_monitor(config):
Expand Down
@@ -0,0 +1,105 @@
custom_attributes_dict = {
'global': {
'max_conn': {
'type': int,
'limits': [1, 65535],
'cmd': 'maxconn %d'
},
'max_conn_rate': {
'type': int,
'limits': [1, 65535],
'cmd': 'maxconnrate %d'
},
'max_sess_rate': {
'type': int,
'limits': [1, 65535],
'cmd': 'maxsessrate %d'
},
'max_ssl_conn': {
'type': int,
'limits': [1, 65535],
'cmd': 'maxsslconn %d'
},
'max_ssl_rate': {
'type': int,
'limits': [1, 65535],
'cmd': 'maxsslrate %d'
},
'ssl_ciphers': {
'type': str,
'limits': [1, 100],
'cmd': 'ssl-default-bind-ciphers %s'
},
'tune_http_max_header': {
'type': int,
'limits': [1, 128],
'cmd': 'tune.http.maxhdr %d'
},
'tune_ssl_max_record': {
'type': int,
'limits': [1, 16384],
'cmd': 'tune.ssl.maxrecord %d'
}
},
'default': {
'server_timeout': {
'type': int,
'limits': [1, 5000000],
'cmd': 'timeout server %d'
},
'client_timeout': {
'type': int,
'limits': [1, 5000000],
'cmd': 'timeout client %d'
},
'connect_timeout': {
'type': int,
'limits': [1, 5000000],
'cmd': 'timeout connect %d'
}
},
'vip': {
'http_server_close': {
'type': bool,
'limits': ['True', 'False'],
'cmd': '%soption http-server-close'
},
'rate_limit_sessions': {
'type': int,
'limits': [1, 65535],
'cmd': 'rate-limit sessions %d'
}
},
'pool': {},
}

def validate_custom_attributes(config, section):
section_dict = {}
if 'custom-attributes' in config and section in custom_attributes_dict:
custom_attributes = config['custom-attributes']
for key, value in custom_attributes.iteritems():
if key in custom_attributes_dict[section]:
#Sanitize the value
try:
type_attr = custom_attributes_dict[section][key]['type']
limits = custom_attributes_dict[section][key]['limits']
if type_attr == int:
value = type_attr(value)
if value in range(limits[0], limits[1]):
section_dict.update({key:value})
elif type_attr == str:
if len(value) in range(limits[0], limits[1]):
section_dict.update({key:value})
elif type_attr == bool:
if value in limits:
if value == 'True':
value = ''
elif value == 'False':
value = 'no '
section_dict.update({key:value})
except Exception as e:
print "Skipping key: %s, value: %s due to validation failure" \
% (key, value)
continue

return section_dict

0 comments on commit cfbd9b8

Please sign in to comment.