1 # -*- coding: utf-8 -*-
2 from __future__
import absolute_import
7 from . import ApiController
, Endpoint
, ReadPermission
, UpdatePermission
8 from . import RESTController
, Task
10 from ..exceptions
import DashboardException
11 from ..security
import Scope
12 from ..services
.exception
import handle_orchestrator_error
13 from ..services
.orchestrator
import OrchClient
14 from ..tools
import TaskManager
, wraps
17 def get_device_osd_map():
18 """Get mappings from inventory devices to OSD IDs.
20 :return: Returns a dictionary containing mappings. Note one device might
21 shared between multiple OSDs.
35 for osd_id
, osd_metadata
in mgr
.get('osd_metadata').items():
36 hostname
= osd_metadata
.get('hostname')
37 devices
= osd_metadata
.get('devices')
38 if not hostname
or not devices
:
40 if hostname
not in result
:
42 # for OSD contains multiple devices, devices is in `sda,sdb`
43 for device
in devices
.split(','):
44 if device
not in result
[hostname
]:
45 result
[hostname
][device
] = [int(osd_id
)]
47 result
[hostname
][device
].append(int(osd_id
))
51 def orchestrator_task(name
, metadata
, wait_for
=2.0):
52 return Task("orchestrator/{}".format(name
), metadata
, wait_for
)
55 def raise_if_no_orchestrator(method
):
57 def inner(self
, *args
, **kwargs
):
58 orch
= OrchClient
.instance()
59 if not orch
.available():
60 raise DashboardException(code
='orchestrator_status_unavailable',
61 msg
='Orchestrator is unavailable',
62 component
='orchestrator',
64 return method(self
, *args
, **kwargs
)
68 @ApiController('/orchestrator')
69 class Orchestrator(RESTController
):
74 return OrchClient
.instance().status()
76 @Endpoint(method
='POST')
78 @raise_if_no_orchestrator
79 @handle_orchestrator_error('osd')
80 @orchestrator_task('identify_device', ['{hostname}', '{device}'])
81 def identify_device(self
, hostname
, device
, duration
):
82 # type: (str, str, int) -> None
84 Identify a device by switching on the device light for N seconds.
85 :param hostname: The hostname of the device to process.
86 :param device: The device identifier to process, e.g. ``/dev/dm-0`` or
87 ``ABC1234DEF567-1R1234_ABC8DE0Q``.
88 :param duration: The duration in seconds how long the LED should flash.
90 orch
= OrchClient
.instance()
91 TaskManager
.current_task().set_progress(0)
92 orch
.blink_device_light(hostname
, device
, 'ident', True)
93 for i
in range(int(duration
)):
94 percentage
= int(round(i
/ float(duration
) * 100))
95 TaskManager
.current_task().set_progress(percentage
)
97 orch
.blink_device_light(hostname
, device
, 'ident', False)
98 TaskManager
.current_task().set_progress(100)
101 @ApiController('/orchestrator/inventory', Scope
.HOSTS
)
102 class OrchestratorInventory(RESTController
):
104 @raise_if_no_orchestrator
105 def list(self
, hostname
=None):
106 orch
= OrchClient
.instance()
107 hosts
= [hostname
] if hostname
else None
108 inventory_hosts
= [host
.to_json() for host
in orch
.inventory
.list(hosts
)]
109 device_osd_map
= get_device_osd_map()
110 for inventory_host
in inventory_hosts
:
111 host_osds
= device_osd_map
.get(inventory_host
['name'])
112 for device
in inventory_host
['devices']:
114 dev_name
= os
.path
.basename(device
['path'])
115 device
['osd_ids'] = sorted(host_osds
.get(dev_name
, []))
117 device
['osd_ids'] = []
118 return inventory_hosts