]> git.apps.os.sepia.ceph.com Git - ceph.git/commitdiff
mgr/dashboard: Fix 500 error while exiting out of maintenance 41856/head
authorNizamudeen A <nia@redhat.com>
Tue, 15 Jun 2021 08:47:58 +0000 (14:17 +0530)
committerNizamudeen A <nia@redhat.com>
Wed, 16 Jun 2021 21:14:46 +0000 (02:44 +0530)
When you add a host in maintenance mode and then exit the maintenance
mode, a 500 server error will popup which will interrupt the whole
exit maintenance process and leave the host in an unknown/offline state.
It happened when I was setting the status of the host through the
HostSpec(). With this change, I am using the enter_maintenance api of
the orch to enable the maintenance.

Fixes: https://tracker.ceph.com/issues/51218
Signed-off-by: Nizamudeen A <nia@redhat.com>
qa/tasks/mgr/dashboard/test_host.py
src/pybind/mgr/dashboard/controllers/host.py
src/pybind/mgr/dashboard/frontend/src/app/ceph/cluster/hosts/host-form/host-form.component.spec.ts
src/pybind/mgr/dashboard/frontend/src/app/shared/api/host.service.ts
src/pybind/mgr/dashboard/openapi.yaml
src/pybind/mgr/dashboard/services/orchestrator.py
src/pybind/mgr/dashboard/tests/test_host.py

index 935e9d71314df64ddc2e71573eb50aca3ccad622..124fff8d1544f9d5b672af75b6115d09f2f3658c 100644 (file)
@@ -146,7 +146,7 @@ class HostControllerTest(DashboardTestCase):
 
 class HostControllerNoOrchestratorTest(DashboardTestCase):
     def test_host_create(self):
-        self._post('/api/host?hostname=foo', version='0.1')
+        self._post('/api/host?hostname=foo', {'status': ''}, version='0.1')
         self.assertStatus(503)
         self.assertError(code='orchestrator_status_unavailable',
                          component='orchestrator')
index d27da0a7aa17f0cd2b8f5d2a9dedec815bf7acf7..fddeb2e5d7f0245c274ba852de2065de973cd12b 100644 (file)
@@ -254,6 +254,18 @@ def get_inventories(hosts: Optional[List[str]] = None,
     return inventory_hosts
 
 
+@allow_empty_body
+def add_host(hostname: str, addr: Optional[str] = None,
+             labels: Optional[List[str]] = None,
+             status: Optional[str] = None):
+    orch_client = OrchClient.instance()
+    host = Host()
+    host.check_orchestrator_host_op(orch_client, hostname)
+    orch_client.hosts.add(hostname, addr, labels)
+    if status == 'maintenance':
+        orch_client.hosts.enter_maintenance(hostname)
+
+
 @ApiController('/host', Scope.HOSTS)
 @ControllerDoc("Get Host Details", "Host")
 class Host(RESTController):
@@ -278,7 +290,7 @@ class Host(RESTController):
                      'hostname': (str, 'Hostname'),
                      'addr': (str, 'Network Address'),
                      'labels': ([str], 'Host Labels'),
-                     'status': (str, 'Status of the Host')
+                     'status': (str, 'Host Status')
                  },
                  responses={200: None, 204: None})
     @RESTController.MethodMap(version='0.1')
@@ -286,10 +298,7 @@ class Host(RESTController):
                addr: Optional[str] = None,
                labels: Optional[List[str]] = None,
                status: Optional[str] = None):  # pragma: no cover - requires realtime env
-        orch_client = OrchClient.instance()
-        self._check_orchestrator_host_op(orch_client, hostname, True)
-        orch_client.hosts.add(hostname, addr, labels, status)
-    create._cp_config = {'tools.json_in.force': False}  # pylint: disable=W0212
+        add_host(hostname, addr, labels, status)
 
     @raise_if_no_orchestrator([OrchFeature.HOST_LIST, OrchFeature.HOST_DELETE])
     @handle_orchestrator_error('host')
@@ -297,10 +306,10 @@ class Host(RESTController):
     @allow_empty_body
     def delete(self, hostname):  # pragma: no cover - requires realtime env
         orch_client = OrchClient.instance()
-        self._check_orchestrator_host_op(orch_client, hostname, False)
+        self.check_orchestrator_host_op(orch_client, hostname, False)
         orch_client.hosts.remove(hostname)
 
-    def _check_orchestrator_host_op(self, orch_client, hostname, add_host=True):  # pragma:no cover
+    def check_orchestrator_host_op(self, orch_client, hostname, add=True):  # pragma:no cover
         """Check if we can adding or removing a host with orchestrator
 
         :param orch_client: Orchestrator client
@@ -308,16 +317,15 @@ class Host(RESTController):
         :raise DashboardException
         """
         host = orch_client.hosts.get(hostname)
-        if add_host and host:
+        if add and host:
             raise DashboardException(
                 code='orchestrator_add_existed_host',
                 msg='{} is already in orchestrator'.format(hostname),
                 component='orchestrator')
-        if not add_host and not host:
+        if not add and not host:
             raise DashboardException(
                 code='orchestrator_remove_nonexistent_host',
-                msg='Remove a non-existent host {} from orchestrator'.format(
-                    hostname),
+                msg='Remove a non-existent host {} from orchestrator'.format(hostname),
                 component='orchestrator')
 
     @RESTController.Resource('GET')
index fad0fa7270fc44b34ecd3c862cc56f56c5055399..dbb834ea8c82cc7fa37ef6b0ac829638e09386db 100644 (file)
@@ -68,7 +68,7 @@ describe('HostFormComponent', () => {
   });
 
   it('should select maintenance mode', () => {
-    component.hostForm.get('maintenance').setValue('maintenance');
+    component.hostForm.get('maintenance').setValue(true);
     fixture.detectChanges();
     component.submit();
     expect(component.status).toBe('maintenance');
index df643afb0ee564677164c2f937310e8a1d6107db..7f8956baa263d1919219e475b87088d05b408384 100644 (file)
@@ -28,7 +28,7 @@ export class HostService {
   create(hostname: string, addr: string, labels: string[], status: string) {
     return this.http.post(
       this.baseURL,
-      { hostname: hostname, addr, labels, status: status },
+      { hostname: hostname, addr: addr, labels: labels, status: status },
       { observe: 'response', headers: { Accept: 'application/vnd.ceph.api.v0.1+json' } }
     );
   }
index 7973832c7328279efefc06657efd50f8d8324b4e..921dadb0471d01011c3647591d0eb1d12aa587d3 100644 (file)
@@ -3251,7 +3251,7 @@ paths:
                     type: string
                   type: array
                 status:
-                  description: Status of the Host
+                  description: Host Status
                   type: string
               required:
               - hostname
index d564c46994080873c6a93b445b37af28d81a50d3..44309a84939173938e9b52bda5fda4b21dd4f18c 100644 (file)
@@ -63,8 +63,8 @@ class HostManger(ResourceManager):
         return hosts[0] if hosts else None
 
     @wait_api_result
-    def add(self, hostname: str, addr: str, labels: List[str], status: str):
-        return self.api.add_host(HostSpec(hostname, addr=addr, labels=labels, status=status))
+    def add(self, hostname: str, addr: str, labels: List[str]):
+        return self.api.add_host(HostSpec(hostname, addr=addr, labels=labels))
 
     @wait_api_result
     def remove(self, hostname: str):
index e7a09a3a7107405239db32904af989375fed9559..6d719a0fc92218052c64f36e9a1927ef5da95932 100644 (file)
@@ -126,6 +126,19 @@ class HostControllerTest(ControllerTestCase):
             self.assertIn('status', self.json_body())
             self.assertIn('addr', self.json_body())
 
+    @mock.patch('dashboard.controllers.host.add_host')
+    def test_add_host(self, mock_add_host):
+        with patch_orch(True):
+            payload = {
+                'hostname': 'node0',
+                'addr': '192.0.2.0',
+                'labels': 'mon',
+                'status': 'maintenance'
+            }
+            self._post(self.URL_HOST, payload, version='0.1')
+            self.assertStatus(201)
+            mock_add_host.assert_called()
+
     def test_set_labels(self):
         mgr.list_servers.return_value = []
         orch_hosts = [