]> git.proxmox.com Git - ceph.git/blame - ceph/src/python-common/ceph/deployment/drive_selection/selector.py
update source to Ceph Pacific 16.2.2
[ceph.git] / ceph / src / python-common / ceph / deployment / drive_selection / selector.py
CommitLineData
9f95a23c
TL
1import logging
2
3try:
4 from typing import List, Optional
5except ImportError:
6 pass
7
e306af50 8from ..inventory import Device
9f95a23c
TL
9from ..drive_group import DriveGroupSpec, DeviceSelection
10
11from .filter import FilterGenerator
12
13logger = logging.getLogger(__name__)
14
15
16class DriveSelection(object):
17 def __init__(self,
18 spec, # type: DriveGroupSpec
e306af50 19 disks, # type: List[Device]
f91f0fd5 20 existing_daemons=None, # type: Optional[int]
9f95a23c
TL
21 ):
22 self.disks = disks.copy()
23 self.spec = spec
f91f0fd5 24 self.existing_daemons = existing_daemons or 0
9f95a23c 25
f67539c2
TL
26 self._data = self.assign_devices(self.spec.data_devices)
27 self._wal = self.assign_devices(self.spec.wal_devices)
28 self._db = self.assign_devices(self.spec.db_devices)
29 self._journal = self.assign_devices(self.spec.journal_devices)
9f95a23c
TL
30
31 def data_devices(self):
32 # type: () -> List[Device]
33 return self._data
34
35 def wal_devices(self):
36 # type: () -> List[Device]
37 return self._wal
38
39 def db_devices(self):
40 # type: () -> List[Device]
41 return self._db
42
43 def journal_devices(self):
44 # type: () -> List[Device]
45 return self._journal
46
f91f0fd5 47 def _limit_reached(self, device_filter, len_devices,
9f95a23c
TL
48 disk_path):
49 # type: (DeviceSelection, int, str) -> bool
50 """ Check for the <limit> property and apply logic
51
52 If a limit is set in 'device_attrs' we have to stop adding
53 disks at some point.
54
55 If limit is set (>0) and len(devices) >= limit
56
57 :param int len_devices: Length of the already populated device set/list
58 :param str disk_path: The disk identifier (for logging purposes)
59 :return: True/False if the device should be added to the list of devices
60 :rtype: bool
61 """
62 limit = device_filter.limit or 0
63
f91f0fd5 64 if limit > 0 and (len_devices + self.existing_daemons >= limit):
9f95a23c
TL
65 logger.info("Refuse to add {} due to limit policy of <{}>".format(
66 disk_path, limit))
67 return True
68 return False
69
70 @staticmethod
71 def _has_mandatory_idents(disk):
72 # type: (Device) -> bool
73 """ Check for mandatory identification fields
74 """
75 if disk.path:
76 logger.debug("Found matching disk: {}".format(disk.path))
77 return True
78 else:
79 raise Exception(
80 "Disk {} doesn't have a 'path' identifier".format(disk))
81
82 def assign_devices(self, device_filter):
83 # type: (Optional[DeviceSelection]) -> List[Device]
84 """ Assign drives based on used filters
85
86 Do not add disks when:
87
88 1) Filter didn't match
89 2) Disk doesn't have a mandatory identification item (path)
90 3) The set :limit was reached
91
92 After the disk was added we make sure not to re-assign this disk
93 for another defined type[wal/db/journal devices]
94
95 return a sorted(by path) list of devices
96 """
97
98 if not device_filter:
99 logger.debug('device_filter is None')
100 return []
101
102 if not self.spec.data_devices:
103 logger.debug('data_devices is None')
104 return []
105
f67539c2
TL
106 if device_filter.paths:
107 logger.debug('device filter is using explicit paths')
108 return device_filter.paths
109
9f95a23c
TL
110 devices = list() # type: List[Device]
111 for disk in self.disks:
112 logger.debug("Processing disk {}".format(disk.path))
113
9f95a23c
TL
114 if not self._has_mandatory_idents(disk):
115 logger.debug(
116 "Ignoring disk {}. Missing mandatory idents".format(
117 disk.path))
118 continue
119
120 # break on this condition.
121 if self._limit_reached(device_filter, len(devices), disk.path):
122 logger.debug("Ignoring disk {}. Limit reached".format(
123 disk.path))
124 break
125
126 if disk in devices:
127 continue
128
f6b5b4d7
TL
129 if self.spec.filter_logic == 'AND':
130 if not all(m.compare(disk) for m in FilterGenerator(device_filter)):
131 logger.debug(
132 "Ignoring disk {}. Not all filter did match the disk".format(
133 disk.path))
134 continue
135
136 if self.spec.filter_logic == 'OR':
137 if not any(m.compare(disk) for m in FilterGenerator(device_filter)):
138 logger.debug(
139 "Ignoring disk {}. No filter matched the disk".format(
140 disk.path))
141 continue
9f95a23c
TL
142
143 logger.debug('Adding disk {}'.format(disk.path))
144 devices.append(disk)
145
146 # This disk is already taken and must not be re-assigned.
147 for taken_device in devices:
148 if taken_device in self.disks:
149 self.disks.remove(taken_device)
150
151 return sorted([x for x in devices], key=lambda dev: dev.path)