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 hosts
= copy
.deepcopy(ceph_hosts
)
38 for host
in orch_hosts
41 # Hosts in both Ceph and Orchestrator
43 hostname
= host
['hostname']
44 if hostname
in orch_hosts_map
:
45 host
['labels'] = orch_hosts_map
[hostname
]['labels']
46 host
['sources']['orchestrator'] = True
47 orch_hosts_map
.pop(hostname
)
49 # Hosts only in Orchestrator
51 dict(hostname
=hostname
,
53 labels
=orch_hosts_map
[hostname
]['labels'],
58 }) for hostname
in orch_hosts_map
60 hosts
.extend(orch_hosts_only
)
64 def get_hosts(from_ceph
=True, from_orchestrator
=True):
66 Get hosts from various sources.
77 }) for server
in mgr
.list_servers()
80 orch
= OrchClient
.instance()
82 return merge_hosts_by_hostname(ceph_hosts
, orch
.hosts
.list())
86 @ApiController('/host', Scope
.HOSTS
)
87 class Host(RESTController
):
88 def list(self
, sources
=None):
91 _sources
= sources
.split(',')
92 from_ceph
= 'ceph' in _sources
93 from_orchestrator
= 'orchestrator' in _sources
94 return get_hosts(from_ceph
, from_orchestrator
)
96 @raise_if_no_orchestrator
97 @handle_orchestrator_error('host')
98 @host_task('create', {'hostname': '{hostname}'})
99 def create(self
, hostname
):
100 orch_client
= OrchClient
.instance()
101 self
._check
_orchestrator
_host
_op
(orch_client
, hostname
, True)
102 orch_client
.hosts
.add(hostname
)
104 @raise_if_no_orchestrator
105 @handle_orchestrator_error('host')
106 @host_task('delete', {'hostname': '{hostname}'})
107 def delete(self
, hostname
):
108 orch_client
= OrchClient
.instance()
109 self
._check
_orchestrator
_host
_op
(orch_client
, hostname
, False)
110 orch_client
.hosts
.remove(hostname
)
112 def _check_orchestrator_host_op(self
, orch_client
, hostname
, add_host
=True):
113 """Check if we can adding or removing a host with orchestrator
115 :param orch_client: Orchestrator client
116 :param add: True for adding host operation, False for removing host
117 :raise DashboardException
119 host
= orch_client
.hosts
.get(hostname
)
120 if add_host
and host
:
121 raise DashboardException(
122 code
='orchestrator_add_existed_host',
123 msg
='{} is already in orchestrator'.format(hostname
),
124 component
='orchestrator')
125 if not add_host
and not host
:
126 raise DashboardException(
127 code
='orchestrator_remove_nonexistent_host',
128 msg
='Remove a non-existent host {} from orchestrator'.format(
130 component
='orchestrator')
132 @RESTController.Resource('GET')
133 def devices(self
, hostname
):
135 return CephService
.get_devices_by_host(hostname
)
137 @RESTController.Resource('GET')
138 def smart(self
, hostname
):
139 # type: (str) -> dict
140 return CephService
.get_smart_data_by_host(hostname
)
142 @RESTController.Resource('GET')
143 @raise_if_no_orchestrator
144 def daemons(self
, hostname
: str) -> List
[dict]:
145 orch
= OrchClient
.instance()
146 daemons
= orch
.services
.list_daemons(None, hostname
)
147 return [d
.to_json() for d
in daemons
]