1 # -*- coding: utf-8 -*-
2 from __future__
import absolute_import
5 from typing
import List
7 from mgr_util
import merge_dicts
8 from orchestrator
import HostSpec
9 from . import ApiController
, RESTController
, Task
10 from .orchestrator
import raise_if_no_orchestrator
12 from ..exceptions
import DashboardException
13 from ..security
import Scope
14 from ..services
.orchestrator
import OrchClient
15 from ..services
.ceph_service
import CephService
16 from ..services
.exception
import handle_orchestrator_error
19 def host_task(name
, metadata
, wait_for
=10.0):
20 return Task("host/{}".format(name
), metadata
, wait_for
)
23 def merge_hosts_by_hostname(ceph_hosts
, orch_hosts
):
24 # type: (List[dict], List[HostSpec]) -> List[dict]
25 """Merge Ceph hosts with orchestrator hosts by hostnames.
27 :param ceph_hosts: hosts returned from mgr
28 :type ceph_hosts: list of dict
29 :param orch_hosts: hosts returned from ochestrator
30 :type orch_hosts: list of HostSpec
33 _ceph_hosts
= copy
.deepcopy(ceph_hosts
)
34 orch_hostnames
= {host
.hostname
for host
in orch_hosts
}
36 # hosts in both Ceph and Orchestrator
37 for ceph_host
in _ceph_hosts
:
38 if ceph_host
['hostname'] in orch_hostnames
:
39 ceph_host
['sources']['orchestrator'] = True
40 orch_hostnames
.remove(ceph_host
['hostname'])
42 # Hosts only in Orchestrator
43 orch_sources
= {'ceph': False, 'orchestrator': True}
44 _orch_hosts
= [dict(hostname
=hostname
, ceph_version
='', services
=[], sources
=orch_sources
)
45 for hostname
in orch_hostnames
]
46 _ceph_hosts
.extend(_orch_hosts
)
50 def get_hosts(from_ceph
=True, from_orchestrator
=True):
51 """get hosts from various sources"""
54 ceph_hosts
= [merge_dicts(server
, {'sources': {'ceph': True, 'orchestrator': False}})
55 for server
in mgr
.list_servers()]
57 orch
= OrchClient
.instance()
59 return merge_hosts_by_hostname(ceph_hosts
, orch
.hosts
.list())
63 @ApiController('/host', Scope
.HOSTS
)
64 class Host(RESTController
):
66 def list(self
, sources
=None):
69 _sources
= sources
.split(',')
70 from_ceph
= 'ceph' in _sources
71 from_orchestrator
= 'orchestrator' in _sources
72 return get_hosts(from_ceph
, from_orchestrator
)
74 @raise_if_no_orchestrator
75 @handle_orchestrator_error('host')
76 @host_task('create', {'hostname': '{hostname}'})
77 def create(self
, hostname
):
78 orch_client
= OrchClient
.instance()
79 self
._check
_orchestrator
_host
_op
(orch_client
, hostname
, True)
80 orch_client
.hosts
.add(hostname
)
82 @raise_if_no_orchestrator
83 @handle_orchestrator_error('host')
84 @host_task('delete', {'hostname': '{hostname}'})
85 def delete(self
, hostname
):
86 orch_client
= OrchClient
.instance()
87 self
._check
_orchestrator
_host
_op
(orch_client
, hostname
, False)
88 orch_client
.hosts
.remove(hostname
)
90 def _check_orchestrator_host_op(self
, orch_client
, hostname
, add_host
=True):
91 """Check if we can adding or removing a host with orchestrator
93 :param orch_client: Orchestrator client
94 :param add: True for adding host operation, False for removing host
95 :raise DashboardException
97 host
= orch_client
.hosts
.get(hostname
)
99 raise DashboardException(
100 code
='orchestrator_add_existed_host',
101 msg
='{} is already in orchestrator'.format(hostname
),
102 component
='orchestrator')
103 if not add_host
and not host
:
104 raise DashboardException(
105 code
='orchestrator_remove_nonexistent_host',
106 msg
='Remove a non-existent host {} from orchestrator'.format(
108 component
='orchestrator')
110 @RESTController.Resource('GET')
111 def devices(self
, hostname
):
113 return CephService
.get_devices_by_host(hostname
)
115 @RESTController.Resource('GET')
116 def smart(self
, hostname
):
117 # type: (str) -> dict
118 return CephService
.get_smart_data_by_host(hostname
)
120 @RESTController.Resource('GET')
121 @raise_if_no_orchestrator
122 def daemons(self
, hostname
: str) -> List
[dict]:
123 orch
= OrchClient
.instance()
124 daemons
= orch
.services
.list_daemons(None, hostname
)
125 return [d
.to_json() for d
in daemons
]