Repository: sapcc/octavia-f5-provider-driver

Issue:
Support of Default profiles for listener
Support configuration of default profiles for listeners:
- HTTP
- HTTP Compression
- Fast L4
- TCP
- UDP
- Multiplex (OneConnect)

Discussion:

Patch:
diff --git a/octavia_f5/common/config.py b/octavia_f5/common/config.py
index b78c9c8..9a1eb4a 100644
--- a/octavia_f5/common/config.py
+++ b/octavia_f5/common/config.py
@@ -58,9 +58,21 @@ f5_agent_opts = [
                choices=[constants.SERVICE_L4,
                         constants.SERVICE_TCP],
                help=_("Service type used for TCP listener")),
+    cfg.StrOpt('profile_http', default=None,
+               help=_("Path to default HTTP profile"
+                      "(e.g. custom_http)")),
+    cfg.StrOpt('profile_http_compression', default=None,
+               help=_("Path to default http compression profile"
+                      " profile (e.g. custom_http_compression)")),
     cfg.StrOpt('profile_l4', default=None,
-               help=_("Path to default l4 acceleration profile"
-                      "(e.g. /Common/custom_fastl4)")),
+               help=_("Path to default L4 acceleration profile"
+                      "(e.g. custom_fastl4)")),
+    cfg.StrOpt('profile_tcp', default=None,
+               help=_("Path to default TCP profile"
+                      "(e.g. custom_tcp)")),
+    cfg.StrOpt('profile_udp', default=None,
+               help=_("Path to default UDP profile"
+                      "(e.g. custom_udp)")),
     cfg.StrOpt('profile_multiplex', default=None,
                help=_("Path to default multiplex (oneconnect) acceleration"
                       " profile (e.g. /Common/custom_oneconnect)")),
diff --git a/octavia_f5/common/constants.py b/octavia_f5/common/constants.py
index 6496baa..6796259 100644
--- a/octavia_f5/common/constants.py
+++ b/octavia_f5/common/constants.py
@@ -52,6 +52,8 @@ SERVICE_L4 = 'Service_L4'
 SERVICE_GENERIC = 'Service_Generic'
 SUPPORTED_SERVICES = (SERVICE_TCP, SERVICE_UDP, SERVICE_HTTP,
                       SERVICE_HTTPS, SERVICE_L4, SERVICE_GENERIC)
+SERVICE_TCP_TYPES = (SERVICE_TCP, SERVICE_GENERIC, SERVICE_HTTP, SERVICE_HTTPS)
+SERVICE_HTTP_TYPES = (SERVICE_HTTP, SERVICE_HTTPS)
 
 SEGMENT = 'segment'
 VIF_TYPE = 'f5'
diff --git a/octavia_f5/restclient/as3classes.py b/octavia_f5/restclient/as3classes.py
index 0752cd4..304f6f8 100644
--- a/octavia_f5/restclient/as3classes.py
+++ b/octavia_f5/restclient/as3classes.py
@@ -180,10 +180,12 @@ class Monitor(BaseDescription):
 
 
 class BigIP(BaseDescription):
-    def __init__(self, bigip):
+    def __init__(self, bigip, _common=True):
         super(BigIP, self).__init__(locals())
 
         self.require('bigip')
+        if _common:
+            setattr(self, 'bigip', '/Common/{}'.format(bigip))
 
 
 class Service_Generic_profileTCP(BaseDescription):
diff --git a/octavia_f5/restclient/as3objects/service.py b/octavia_f5/restclient/as3objects/service.py
index 7034cd8..d3977ff 100644
--- a/octavia_f5/restclient/as3objects/service.py
+++ b/octavia_f5/restclient/as3objects/service.py
@@ -53,10 +53,7 @@ def get_esd_entities(servicetype, esd):
     service_args = {}
     irules = esd.get('lbaas_irule', None)
     if irules:
-        service_args['iRules'] = [
-            as3.BigIP('/Common/' + rule) for
-            rule in irules
-        ]
+        service_args['iRules'] = [as3.BigIP(rule) for rule in irules]
 
     # client / server tcp profiles
     if servicetype in [const.SERVICE_HTTP, const.SERVICE_HTTPS,
@@ -66,11 +63,11 @@ def get_esd_entities(servicetype, esd):
         if stcp and ctcp:
             # Server and Clientside profile defined
             service_args['profileTCP'] = as3.Service_Generic_profileTCP(
-                ingress=as3.BigIP('/Common/' + ctcp),
-                egress=as3.BigIP('/Common/' + stcp)
+                ingress=as3.BigIP(ctcp),
+                egress=as3.BigIP(stcp)
             )
         elif ctcp:
-            service_args['profileTCP'] = as3.BigIP('/Common/' + ctcp)
+            service_args['profileTCP'] = as3.BigIP(ctcp)
         else:
             service_args['profileTCP'] = 'normal'
 
@@ -78,14 +75,12 @@ def get_esd_entities(servicetype, esd):
         # OneConnect (Multiplex) Profile
         oneconnect = esd.get('lbaas_one_connect', None)
         if oneconnect:
-            service_args['profileMultiplex'] = as3.BigIP(
-                '/Common/' + oneconnect)
+            service_args['profileMultiplex'] = as3.BigIP(oneconnect)
 
         # HTTP Compression Profile
         compression = esd.get('lbaas_http_compression', None)
         if compression:
-            service_args['profileHTTPCompression'] = as3.BigIP(
-                '/Common/' + compression)
+            service_args['profileHTTPCompression'] = as3.BigIP(compression)
 
     return service_args
 
@@ -124,7 +119,7 @@ def get_service(listener, cert_manager, esd_repository):
         service_args['_servicetype'] = const.SERVICE_HTTP
     # HTTPS (non-terminated)
     elif listener.protocol == const.PROTOCOL_HTTPS:
-        service_args['_servicetype'] = const.SERVICE_GENERIC
+        service_args['_servicetype'] = CONF.f5_agent.tcp_service_type
     # Proxy
     elif listener.protocol == const.PROTOCOL_PROXY:
         service_args['_servicetype'] = const.SERVICE_HTTP
@@ -154,10 +149,18 @@ def get_service(listener, cert_manager, esd_repository):
         ))
         entities.extend([(cert['id'], cert['as3']) for cert in certificates])
 
-    # add profile
-    if CONF.f5_agent.profile_l4:
+    # add default profiles to supported listeners
+    if CONF.f5_agent.profile_http and service_args['_servicetype'] in const.SERVICE_HTTP_TYPES:
+        service_args['profileHTTP'] = as3.BigIP(CONF.f5_agent.profile_http)
+    if CONF.f5_agent.profile_http_compression and service_args['_servicetype'] in const.SERVICE_HTTP_TYPES:
+        service_args['profileHTTPCompression'] = as3.BigIP(CONF.f5_agent.profile_http_compression)
+    if CONF.f5_agent.profile_l4 and service_args['_servicetype'] == const.SERVICE_L4:
         service_args['profileL4'] = as3.BigIP(CONF.f5_agent.profile_l4)
-    if CONF.f5_agent.profile_multiplex:
+    if CONF.f5_agent.profile_tcp and service_args['_servicetype'] in const.SERVICE_TCP_TYPES:
+        service_args['profileTCP'] = as3.BigIP(CONF.f5_agent.profile_tcp)
+    if CONF.f5_agent.profile_udp and service_args['_servicetype'] == const.SERVICE_UDP:
+        service_args['profileUDP'] = as3.BigIP(CONF.f5_agent.profile_udp)
+    if CONF.f5_agent.profile_multiplex and service_args['_servicetype'] in const.SERVICE_HTTP_TYPES:
         service_args['profileMultiplex'] = as3.BigIP(CONF.f5_agent.profile_multiplex)
 
     if listener.connection_limit > 0:


Test patch:
diff --git a/octavia_f5/tests/unit/restclient/test_as3classes.py b/octavia_f5/tests/unit/restclient/test_as3classes.py
index ed0e339..a78b746 100644
--- a/octavia_f5/tests/unit/restclient/test_as3classes.py
+++ b/octavia_f5/tests/unit/restclient/test_as3classes.py
@@ -189,9 +189,13 @@ class TestAS3Classes(base.TestCase):
     def test_bigip(self):
         # creation
         bigip = {'bigip': 'test_bigip'}
-        bigip_obj = as3classes.BigIP(bigip['bigip'])
+        bigip_obj = as3classes.BigIP(bigip['bigip'], _common=False)
         self.assertEqual(bigip, bigip_obj.to_dict())
 
+        bigip_common = {'bigip': '/Common/test_bigip'}
+        bigip_obj = as3classes.BigIP(bigip['bigip'])
+        self.assertEqual(bigip_common, bigip_obj.to_dict())
+
     def test_servicegenericprofile_tcp(self):
         sgptcp = {'ingress': 'test_ingress',
                   'egress': 'test_egress'}