]> git.proxmox.com Git - ceph.git/blob - ceph/src/pybind/mgr/dashboard/controllers/host.py
import 15.2.0 Octopus source
[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 _ceph_hosts = copy.deepcopy(ceph_hosts)
34 orch_hostnames = {host.hostname for host in orch_hosts}
35
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'])
41
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)
47 return _ceph_hosts
48
49
50 def get_hosts(from_ceph=True, from_orchestrator=True):
51 """get hosts from various sources"""
52 ceph_hosts = []
53 if from_ceph:
54 ceph_hosts = [merge_dicts(server, {'sources': {'ceph': True, 'orchestrator': False}})
55 for server in mgr.list_servers()]
56 if from_orchestrator:
57 orch = OrchClient.instance()
58 if orch.available():
59 return merge_hosts_by_hostname(ceph_hosts, orch.hosts.list())
60 return ceph_hosts
61
62
63 @ApiController('/host', Scope.HOSTS)
64 class Host(RESTController):
65
66 def list(self, sources=None):
67 if sources is None:
68 return get_hosts()
69 _sources = sources.split(',')
70 from_ceph = 'ceph' in _sources
71 from_orchestrator = 'orchestrator' in _sources
72 return get_hosts(from_ceph, from_orchestrator)
73
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)
81
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)
89
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
92
93 :param orch_client: Orchestrator client
94 :param add: True for adding host operation, False for removing host
95 :raise DashboardException
96 """
97 host = orch_client.hosts.get(hostname)
98 if add_host and host:
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(
107 hostname),
108 component='orchestrator')
109
110 @RESTController.Resource('GET')
111 def devices(self, hostname):
112 # (str) -> List
113 return CephService.get_devices_by_host(hostname)
114
115 @RESTController.Resource('GET')
116 def smart(self, hostname):
117 # type: (str) -> dict
118 return CephService.get_smart_data_by_host(hostname)
119
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]