]> git.proxmox.com Git - ceph.git/blob - ceph/src/pybind/mgr/dashboard/controllers/host.py
import 15.2.4
[ceph.git] / ceph / src / pybind / mgr / dashboard / controllers / host.py
1 # -*- coding: utf-8 -*-
2 from __future__ import absolute_import
3 import copy
4
5 from typing import List
6
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
11 from .. import mgr
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
17
18
19 def host_task(name, metadata, wait_for=10.0):
20 return Task("host/{}".format(name), metadata, wait_for)
21
22
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.
26
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
31 :return list of dict
32 """
33 hosts = copy.deepcopy(ceph_hosts)
34 orch_hosts_map = {
35 host.hostname: {
36 'labels': host.labels
37 }
38 for host in orch_hosts
39 }
40
41 # Hosts in both Ceph and Orchestrator
42 for host in hosts:
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)
48
49 # Hosts only in Orchestrator
50 orch_hosts_only = [
51 dict(hostname=hostname,
52 ceph_version='',
53 labels=orch_hosts_map[hostname]['labels'],
54 services=[],
55 sources={
56 'ceph': False,
57 'orchestrator': True
58 }) for hostname in orch_hosts_map
59 ]
60 hosts.extend(orch_hosts_only)
61 return hosts
62
63
64 def get_hosts(from_ceph=True, from_orchestrator=True):
65 """
66 Get hosts from various sources.
67 """
68 ceph_hosts = []
69 if from_ceph:
70 ceph_hosts = [
71 merge_dicts(server, {
72 'labels': [],
73 'sources': {
74 'ceph': True,
75 'orchestrator': False
76 }
77 }) for server in mgr.list_servers()
78 ]
79 if from_orchestrator:
80 orch = OrchClient.instance()
81 if orch.available():
82 return merge_hosts_by_hostname(ceph_hosts, orch.hosts.list())
83 return ceph_hosts
84
85
86 @ApiController('/host', Scope.HOSTS)
87 class Host(RESTController):
88 def list(self, sources=None):
89 if sources is None:
90 return get_hosts()
91 _sources = sources.split(',')
92 from_ceph = 'ceph' in _sources
93 from_orchestrator = 'orchestrator' in _sources
94 return get_hosts(from_ceph, from_orchestrator)
95
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)
103
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)
111
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
114
115 :param orch_client: Orchestrator client
116 :param add: True for adding host operation, False for removing host
117 :raise DashboardException
118 """
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(
129 hostname),
130 component='orchestrator')
131
132 @RESTController.Resource('GET')
133 def devices(self, hostname):
134 # (str) -> List
135 return CephService.get_devices_by_host(hostname)
136
137 @RESTController.Resource('GET')
138 def smart(self, hostname):
139 # type: (str) -> dict
140 return CephService.get_smart_data_by_host(hostname)
141
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]