]> git.apps.os.sepia.ceph.com Git - ceph.git/commitdiff
mgr/cephadm: Fix dashboard gateway configuration when using IPV6 40355/head
authorJuan Miguel Olmo Martínez <jolmomar@redhat.com>
Wed, 24 Mar 2021 14:30:38 +0000 (15:30 +0100)
committerSage Weil <sage@newdream.net>
Thu, 25 Mar 2021 12:42:06 +0000 (07:42 -0500)
Fixes: https://tracker.ceph.com/issues/49957
Signed-off-by: Juan Miguel Olmo Martínez <jolmomar@redhat.com>
(cherry picked from commit 1b18f4f9cb28708b544c62b3d07f9e1b4c701e41)

src/pybind/mgr/cephadm/services/iscsi.py
src/pybind/mgr/cephadm/tests/test_services.py

index c4e0762d2744365017496922cd5051915e570de3..7737a637422ff89a0a3377674b2b1769879509f7 100644 (file)
@@ -2,6 +2,7 @@ import errno
 import json
 import logging
 from typing import List, cast, Optional
+from ipaddress import ip_address, IPv6Address
 
 from mgr_module import HandleCommandResult
 from ceph.deployment.service_spec import IscsiServiceSpec
@@ -95,6 +96,9 @@ class IscsiService(CephService):
                     logger.warning('No ServiceSpec found for %s', dd)
                     continue
                 ip = utils.resolve_ip(dd.hostname)
+                # IPv6 URL encoding requires square brackets enclosing the ip
+                if type(ip_address(ip)) is IPv6Address:
+                    ip = f'[{ip}]'
                 protocol = "http"
                 if spec.api_secure and spec.ssl_cert and spec.ssl_key:
                     protocol = "https"
index e52a26729962463f7ae7595996842c438b150483..46dfbab4d973fc0c14f3052cee4de744a7bdf101 100644 (file)
@@ -1,6 +1,6 @@
 import pytest
 
-from unittest.mock import MagicMock, call
+from unittest.mock import MagicMock, call, patch
 
 from cephadm.services.cephadmservice import MonService, MgrService, MdsService, RgwService, \
     RbdMirrorService, CrashService, CephadmDaemonDeploySpec
@@ -13,6 +13,7 @@ from cephadm.services.exporter import CephadmExporter
 from ceph.deployment.service_spec import IscsiServiceSpec
 
 from orchestrator import OrchestratorError
+from orchestrator._interface import DaemonDescription
 
 
 class FakeMgr:
@@ -84,40 +85,6 @@ class TestCephadmService:
         }
         return cephadm_services
 
-    def test_iscsi_client_caps(self):
-        mgr = FakeMgr()
-        iscsi_service = self._get_services(mgr)['iscsi']
-
-        iscsi_spec = IscsiServiceSpec(service_type='iscsi', service_id="a")
-        iscsi_spec.daemon_type = "iscsi"
-        iscsi_spec.daemon_id = "a"
-        iscsi_spec.spec = MagicMock()
-        iscsi_spec.spec.daemon_type = "iscsi"
-        iscsi_spec.spec.ssl_cert = ''
-
-        mgr.spec_store = MagicMock()
-        mgr.spec_store.__getitem__.return_value = iscsi_spec
-
-        iscsi_daemon_spec = CephadmDaemonDeploySpec(
-            host='host', daemon_id='a', service_name=iscsi_spec.service_name())
-
-        iscsi_service.prepare_create(iscsi_daemon_spec)
-
-        expected_caps = ['mon',
-                         'profile rbd, allow command "osd blocklist", allow command "config-key get" with "key" prefix "iscsi/"',
-                         'mgr', 'allow command "service status"',
-                         'osd', 'allow rwx']
-
-        expected_call = call({'prefix': 'auth get-or-create',
-                              'entity': 'client.iscsi.a',
-                              'caps': expected_caps})
-        expected_call2 = call({'prefix': 'auth caps',
-                               'entity': 'client.iscsi.a',
-                               'caps': expected_caps})
-
-        assert expected_call in mgr.mon_command.mock_calls
-        assert expected_call2 in mgr.mon_command.mock_calls
-
     def test_get_auth_entity(self):
         mgr = FakeMgr()
         cephadm_services = self._get_services(mgr)
@@ -158,3 +125,95 @@ class TestCephadmService:
                 cephadm_services[daemon_type].get_auth_entity("id1", "host")
                 cephadm_services[daemon_type].get_auth_entity("id1", "")
                 cephadm_services[daemon_type].get_auth_entity("id1")
+
+
+class TestISCSIService:
+
+    mgr = FakeMgr()
+    iscsi_service = IscsiService(mgr)
+
+    iscsi_spec = IscsiServiceSpec(service_type='iscsi', service_id="a")
+    iscsi_spec.daemon_type = "iscsi"
+    iscsi_spec.daemon_id = "a"
+    iscsi_spec.spec = MagicMock()
+    iscsi_spec.spec.daemon_type = "iscsi"
+    iscsi_spec.spec.ssl_cert = ''
+    iscsi_spec.api_user = "user"
+    iscsi_spec.api_password = "password"
+    iscsi_spec.api_port = 5000
+    iscsi_spec.api_secure = False
+    iscsi_spec.ssl_cert = "cert"
+    iscsi_spec.ssl_key = "key"
+
+    mgr.spec_store = MagicMock()
+    mgr.spec_store.all_specs.get.return_value = iscsi_spec
+
+    def test_iscsi_client_caps(self):
+
+        iscsi_daemon_spec = CephadmDaemonDeploySpec(
+            host='host', daemon_id='a', service_name=self.iscsi_spec.service_name())
+
+        self.iscsi_service.prepare_create(iscsi_daemon_spec)
+
+        expected_caps = ['mon',
+                         'profile rbd, allow command "osd blocklist", allow command "config-key get" with "key" prefix "iscsi/"',
+                         'mgr', 'allow command "service status"',
+                         'osd', 'allow rwx']
+
+        expected_call = call({'prefix': 'auth get-or-create',
+                              'entity': 'client.iscsi.a',
+                              'caps': expected_caps})
+        expected_call2 = call({'prefix': 'auth caps',
+                               'entity': 'client.iscsi.a',
+                               'caps': expected_caps})
+
+        assert expected_call in self.mgr.mon_command.mock_calls
+        assert expected_call2 in self.mgr.mon_command.mock_calls
+
+    @patch('cephadm.utils.resolve_ip')
+    def test_iscsi_dashboard_config(self, mock_resolve_ip):
+
+        self.mgr.check_mon_command = MagicMock()
+        self.mgr.check_mon_command.return_value = ('', '{"gateways": {}}', '')
+
+        # Case 1: use IPV4 address
+        id1 = DaemonDescription(daemon_type='iscsi', hostname="testhost1",
+                                daemon_id="a", ip='192.168.1.1')
+        daemon_list = [id1]
+        mock_resolve_ip.return_value = '192.168.1.1'
+
+        self.iscsi_service.config_dashboard(daemon_list)
+
+        dashboard_expected_call = call({'prefix': 'dashboard iscsi-gateway-add',
+                                        'name': 'testhost1'},
+                                       'http://user:password@192.168.1.1:5000')
+
+        assert dashboard_expected_call in self.mgr.check_mon_command.mock_calls
+
+        # Case 2: use IPV6 address
+        self.mgr.check_mon_command.reset_mock()
+
+        id1 = DaemonDescription(daemon_type='iscsi', hostname="testhost1",
+                                daemon_id="a", ip='FEDC:BA98:7654:3210:FEDC:BA98:7654:3210')
+        mock_resolve_ip.return_value = 'FEDC:BA98:7654:3210:FEDC:BA98:7654:3210'
+
+        self.iscsi_service.config_dashboard(daemon_list)
+
+        dashboard_expected_call = call({'prefix': 'dashboard iscsi-gateway-add',
+                                        'name': 'testhost1'},
+                                       'http://user:password@[FEDC:BA98:7654:3210:FEDC:BA98:7654:3210]:5000')
+
+        assert dashboard_expected_call in self.mgr.check_mon_command.mock_calls
+
+        # Case 3: IPV6 Address . Secure protocol
+        self.mgr.check_mon_command.reset_mock()
+
+        self.iscsi_spec.api_secure = True
+
+        self.iscsi_service.config_dashboard(daemon_list)
+
+        dashboard_expected_call = call({'prefix': 'dashboard iscsi-gateway-add',
+                                        'name': 'testhost1'},
+                                       'https://user:password@[FEDC:BA98:7654:3210:FEDC:BA98:7654:3210]:5000')
+
+        assert dashboard_expected_call in self.mgr.check_mon_command.mock_calls