From df1ecbda2cc2a32ec34f16d26f23d07453156641 Mon Sep 17 00:00:00 2001 From: Gregory Thiemonge Date: Thu, 9 Jul 2020 14:25:39 +0200 Subject: [PATCH] Deny the creation of L7Policies for HTTPS/TCP/UDP listeners L7Policies are not compatible with non-TERMINATED_HTTPS/HTTP listeners (i.e HTTPS/TCP/UDP listeners). The Amphora driver should deny those invalid combinations. Story: 2007911 Task: 40314 Change-Id: I0f1cac05ebea12a300feffb22fdfe546cf802b87 (cherry picked from commit 45b0a507a150721389833e33789b4cfdbc1a9590) (cherry picked from commit 4248e98acbfa76ef1ab6d35ffbf0abf5b61e0a33) --- .../api/drivers/amphora_driver/v1/driver.py | 13 ++++++++++++ .../api/drivers/amphora_driver/v2/driver.py | 13 ++++++++++++ .../drivers/amphora_driver/v1/test_driver.py | 20 ++++++++++++++++++- .../drivers/amphora_driver/v2/test_driver.py | 20 ++++++++++++++++++- ...ocols-for-l7policies-83d678171f13136a.yaml | 7 +++++++ 5 files changed, 71 insertions(+), 2 deletions(-) create mode 100644 releasenotes/notes/validate-protocols-for-l7policies-83d678171f13136a.yaml diff --git a/octavia/api/drivers/amphora_driver/v1/driver.py b/octavia/api/drivers/amphora_driver/v1/driver.py index 8485cc4cae..cd157166d2 100644 --- a/octavia/api/drivers/amphora_driver/v1/driver.py +++ b/octavia/api/drivers/amphora_driver/v1/driver.py @@ -55,6 +55,11 @@ AMPHORA_SUPPORTED_PROTOCOLS = [ lib_consts.PROTOCOL_SCTP, ] +VALID_L7POLICY_LISTENER_PROTOCOLS = [ + lib_consts.PROTOCOL_HTTP, + lib_consts.PROTOCOL_TERMINATED_HTTPS +] + class AmphoraProviderDriver(driver_base.ProviderDriver): def __init__(self): @@ -339,6 +344,14 @@ class AmphoraProviderDriver(driver_base.ProviderDriver): # L7 Policy def l7policy_create(self, l7policy): + db_listener = self.repositories.listener.get(db_apis.get_session(), + id=l7policy.listener_id) + if db_listener.protocol not in VALID_L7POLICY_LISTENER_PROTOCOLS: + msg = ('%s protocol listeners do not support L7 policies' % ( + db_listener.protocol)) + raise exceptions.UnsupportedOptionError( + user_fault_string=msg, + operator_fault_string=msg) payload = {consts.L7POLICY_ID: l7policy.l7policy_id} self.client.cast({}, 'create_l7policy', **payload) diff --git a/octavia/api/drivers/amphora_driver/v2/driver.py b/octavia/api/drivers/amphora_driver/v2/driver.py index 666a05ba18..aeda78b856 100644 --- a/octavia/api/drivers/amphora_driver/v2/driver.py +++ b/octavia/api/drivers/amphora_driver/v2/driver.py @@ -56,6 +56,11 @@ AMPHORA_SUPPORTED_PROTOCOLS = [ lib_consts.PROTOCOL_SCTP, ] +VALID_L7POLICY_LISTENER_PROTOCOLS = [ + lib_consts.PROTOCOL_HTTP, + lib_consts.PROTOCOL_TERMINATED_HTTPS +] + class AmphoraProviderDriver(driver_base.ProviderDriver): def __init__(self): @@ -362,6 +367,14 @@ class AmphoraProviderDriver(driver_base.ProviderDriver): # L7 Policy def l7policy_create(self, l7policy): + db_listener = self.repositories.listener.get(db_apis.get_session(), + id=l7policy.listener_id) + if db_listener.protocol not in VALID_L7POLICY_LISTENER_PROTOCOLS: + msg = ('%s protocol listeners do not support L7 policies' % ( + db_listener.protocol)) + raise exceptions.UnsupportedOptionError( + user_fault_string=msg, + operator_fault_string=msg) payload = {consts.L7POLICY: l7policy.to_dict()} self.client.cast({}, 'create_l7policy', **payload) diff --git a/octavia/tests/unit/api/drivers/amphora_driver/v1/test_driver.py b/octavia/tests/unit/api/drivers/amphora_driver/v1/test_driver.py index 26b609569a..ef4ceb2ea0 100644 --- a/octavia/tests/unit/api/drivers/amphora_driver/v1/test_driver.py +++ b/octavia/tests/unit/api/drivers/amphora_driver/v1/test_driver.py @@ -619,14 +619,32 @@ class TestAmphoraDriver(base.TestRpc): mock_cast.assert_called_with({}, 'update_health_monitor', **payload) # L7 Policy + @mock.patch('octavia.db.api.get_session') + @mock.patch('octavia.db.repositories.ListenerRepository.get') @mock.patch('oslo_messaging.RPCClient.cast') - def test_l7policy_create(self, mock_cast): + def test_l7policy_create(self, mock_cast, mock_listener_get, mock_session): + mock_listener = mock.MagicMock() + mock_listener.protocol = consts.PROTOCOL_HTTP + mock_listener_get.return_value = mock_listener provider_l7policy = driver_dm.L7Policy( l7policy_id=self.sample_data.l7policy1_id) self.amp_driver.l7policy_create(provider_l7policy) payload = {consts.L7POLICY_ID: self.sample_data.l7policy1_id} mock_cast.assert_called_with({}, 'create_l7policy', **payload) + @mock.patch('octavia.db.api.get_session') + @mock.patch('octavia.db.repositories.ListenerRepository.get') + def test_l7policy_create_invalid_listener_protocol(self, mock_listener_get, + mock_session): + mock_listener = mock.MagicMock() + mock_listener.protocol = consts.PROTOCOL_UDP + mock_listener_get.return_value = mock_listener + provider_l7policy = driver_dm.L7Policy( + l7policy_id=self.sample_data.l7policy1_id) + self.assertRaises(exceptions.UnsupportedOptionError, + self.amp_driver.l7policy_create, + provider_l7policy) + @mock.patch('oslo_messaging.RPCClient.cast') def test_l7policy_delete(self, mock_cast): provider_l7policy = driver_dm.L7Policy( diff --git a/octavia/tests/unit/api/drivers/amphora_driver/v2/test_driver.py b/octavia/tests/unit/api/drivers/amphora_driver/v2/test_driver.py index 47e41fa213..410911ef7a 100644 --- a/octavia/tests/unit/api/drivers/amphora_driver/v2/test_driver.py +++ b/octavia/tests/unit/api/drivers/amphora_driver/v2/test_driver.py @@ -674,14 +674,32 @@ class TestAmphoraDriver(base.TestRpc): mock_cast.assert_called_with({}, 'update_health_monitor', **payload) # L7 Policy + @mock.patch('octavia.db.api.get_session') + @mock.patch('octavia.db.repositories.ListenerRepository.get') @mock.patch('oslo_messaging.RPCClient.cast') - def test_l7policy_create(self, mock_cast): + def test_l7policy_create(self, mock_cast, mock_listener_get, mock_session): + mock_listener = mock.MagicMock() + mock_listener.protocol = consts.PROTOCOL_HTTP + mock_listener_get.return_value = mock_listener provider_l7policy = driver_dm.L7Policy( l7policy_id=self.sample_data.l7policy1_id) self.amp_driver.l7policy_create(provider_l7policy) payload = {consts.L7POLICY: provider_l7policy.to_dict()} mock_cast.assert_called_with({}, 'create_l7policy', **payload) + @mock.patch('octavia.db.api.get_session') + @mock.patch('octavia.db.repositories.ListenerRepository.get') + def test_l7policy_create_invalid_listener_protocol(self, mock_listener_get, + mock_session): + mock_listener = mock.MagicMock() + mock_listener.protocol = consts.PROTOCOL_UDP + mock_listener_get.return_value = mock_listener + provider_l7policy = driver_dm.L7Policy( + l7policy_id=self.sample_data.l7policy1_id) + self.assertRaises(exceptions.UnsupportedOptionError, + self.amp_driver.l7policy_create, + provider_l7policy) + @mock.patch('oslo_messaging.RPCClient.cast') def test_l7policy_delete(self, mock_cast): provider_l7policy = driver_dm.L7Policy( diff --git a/releasenotes/notes/validate-protocols-for-l7policies-83d678171f13136a.yaml b/releasenotes/notes/validate-protocols-for-l7policies-83d678171f13136a.yaml new file mode 100644 index 0000000000..114daaa3df --- /dev/null +++ b/releasenotes/notes/validate-protocols-for-l7policies-83d678171f13136a.yaml @@ -0,0 +1,7 @@ +--- +fixes: + - | + Validate that the creation of L7 policies is compatible with the protocol + of the listener in the Amphora driver. L7 policies are allowed for + Terminated HTTPS or HTTP protocol listeners, but not for HTTPS, TCP or UDP + protocols listeners.