Browse Source

Merge "Fix listener deletion in ACTIVE/STANDBY topology" into stable/stein

changes/53/679753/1
Zuul 2 weeks ago
parent
commit
49990fd89f

+ 4
- 1
octavia/amphorae/drivers/haproxy/rest_api_driver.py View File

@@ -299,7 +299,10 @@ class HaproxyAmphoraLoadBalancerDriver(
299 299
     def _combined_config_delete(self, amphora, listener):
300 300
         # Remove the listener from the listener list on the LB before
301 301
         # passing the whole thing over to update (so it'll actually delete)
302
-        listener.load_balancer.listeners.remove(listener)
302
+        # In case of amphorae in ACTIVE_STANDBY topology, ensure that we don't
303
+        # remove an already removed listener.
304
+        if listener in listener.load_balancer.listeners:
305
+            listener.load_balancer.listeners.remove(listener)
303 306
 
304 307
         # Check if there's any certs that we need to delete
305 308
         certs = self._process_tls_certificates(listener)

+ 80
- 0
octavia/tests/unit/amphorae/drivers/haproxy/test_rest_api_driver_1_0.py View File

@@ -522,6 +522,86 @@ class TestHaproxyAmphoraLoadBalancerDriverTest(base.TestCase):
522 522
             API_VERSION].reload_listener.assert_called_once_with(
523 523
             self.amp, sl.load_balancer.id, timeout_dict=None)
524 524
 
525
+    @mock.patch('octavia.amphorae.drivers.haproxy.rest_api_driver.'
526
+                'HaproxyAmphoraLoadBalancerDriver._process_secret')
527
+    @mock.patch('octavia.common.tls_utils.cert_parser.load_certificates_data')
528
+    @mock.patch('octavia.common.tls_utils.cert_parser.get_host_names')
529
+    def test_delete_second_listener_active_standby(self, mock_cert,
530
+                                                   mock_load_crt,
531
+                                                   mock_secret):
532
+        self.driver.clients[
533
+            API_VERSION].delete_listener.__name__ = 'delete_listener'
534
+        sl = sample_configs_combined.sample_listener_tuple(
535
+            tls=True, sni=True, client_ca_cert=True, client_crl_cert=True,
536
+            recursive_nest=True, topology=constants.TOPOLOGY_ACTIVE_STANDBY)
537
+        sl2 = sample_configs_combined.sample_listener_tuple(
538
+            id='sample_listener_id_2',
539
+            topology=constants.TOPOLOGY_ACTIVE_STANDBY)
540
+        sl.load_balancer.listeners.append(sl2)
541
+        mock_cert.return_value = {'cn': sample_certs.X509_CERT_CN}
542
+        mock_secret.side_effect = ['filename.pem', 'crl-filename.pem',
543
+                                   'filename.pem', 'crl-filename.pem']
544
+        sconts = []
545
+        for sni_container in self.sl.sni_containers:
546
+            sconts.append(sni_container.tls_container)
547
+        mock_load_crt.side_effect = [{
548
+            'tls_cert': self.sl.default_tls_container, 'sni_certs': sconts},
549
+            {'tls_cert': None, 'sni_certs': []},
550
+            {'tls_cert': None, 'sni_certs': []},
551
+            {'tls_cert': None, 'sni_certs': []}]
552
+        self.driver.jinja_combo.build_config.side_effect = [
553
+            'fake_config', 'fake_config']
554
+        # Execute driver method
555
+        self.driver.delete(sl)
556
+
557
+        amp1 = sl.load_balancer.amphorae[0]
558
+        amp2 = sl.load_balancer.amphorae[1]
559
+
560
+        # All of the pem files should be removed (using amp1 or amp2)
561
+        dcp_calls_list = [
562
+            [
563
+                mock.call(amp1, sl.load_balancer.id,
564
+                          sl.default_tls_container.id + '.pem'),
565
+                mock.call(amp2, sl.load_balancer.id,
566
+                          sl.default_tls_container.id + '.pem')
567
+            ],
568
+            [
569
+                mock.call(amp1, sl.load_balancer.id, sconts[0].id + '.pem'),
570
+                mock.call(amp2, sl.load_balancer.id, sconts[0].id + '.pem')
571
+            ],
572
+            [
573
+                mock.call(amp1, sl.load_balancer.id, sconts[1].id + '.pem'),
574
+                mock.call(amp2, sl.load_balancer.id, sconts[1].id + '.pem')
575
+            ]
576
+        ]
577
+        mock_calls = (
578
+            self.driver.clients[API_VERSION].delete_cert_pem.mock_calls)
579
+        for dcp_calls in dcp_calls_list:
580
+            # Ensure that at least one call in each pair has been seen
581
+            if (dcp_calls[0] not in mock_calls and
582
+                    dcp_calls[1] not in mock_calls):
583
+                raise Exception("%s not found in %s" % (dcp_calls, mock_calls))
584
+
585
+        # Now just make sure we did an update and not a delete
586
+        self.driver.clients[API_VERSION].delete_listener.assert_not_called()
587
+        upload_config_calls = [
588
+            mock.call(amp1, sl.load_balancer.id, 'fake_config',
589
+                      timeout_dict=None),
590
+            mock.call(amp2, sl.load_balancer.id, 'fake_config',
591
+                      timeout_dict=None)
592
+        ]
593
+        self.driver.clients[API_VERSION].upload_config.assert_has_calls(
594
+            upload_config_calls, any_order=True)
595
+
596
+        # start should be called once per amp
597
+        reload_listener_calls = [
598
+            mock.call(amp1, sl.load_balancer.id, timeout_dict=None),
599
+            mock.call(amp2, sl.load_balancer.id, timeout_dict=None)
600
+        ]
601
+        self.driver.clients[
602
+            API_VERSION].reload_listener.assert_has_calls(
603
+                reload_listener_calls, any_order=True)
604
+
525 605
     @mock.patch('octavia.common.tls_utils.cert_parser.load_certificates_data')
526 606
     def test_delete_last_listener(self, mock_load_crt):
527 607
         self.driver.clients[

Loading…
Cancel
Save