Skip to content

Commit 29be020

Browse files
committed
mgr/rook: Adding support to automatically discover storage classes
Fixes: https://tracker.ceph.com/issues/63038 Fixes: https://tracker.ceph.com/issues/63338 Signed-off-by: Redouane Kachach <[email protected]>
1 parent 478a058 commit 29be020

File tree

2 files changed

+51
-26
lines changed

2 files changed

+51
-26
lines changed

src/pybind/mgr/rook/module.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -130,7 +130,7 @@ def __init__(self, *args: Any, **kwargs: Any) -> None:
130130

131131
self._load_drive_groups()
132132
self._shutdown = threading.Event()
133-
133+
134134
def config_notify(self) -> None:
135135
"""
136136
This method is called whenever one of our config options is changed.
@@ -147,7 +147,7 @@ def config_notify(self) -> None:
147147
assert isinstance(self.drive_group_interval, float)
148148

149149
if self._rook_cluster:
150-
self._rook_cluster.storage_class = self.storage_class
150+
self._rook_cluster.storage_class_name = self.storage_class
151151

152152
def shutdown(self) -> None:
153153
self._shutdown.set()

src/pybind/mgr/rook/rook_cluster.py

Lines changed: 49 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -97,14 +97,15 @@ def wrapper(*args: Any, **kwargs: Any) -> threading.Thread:
9797

9898

9999
class DefaultFetcher():
100-
def __init__(self, storage_class: str, coreV1_api: 'client.CoreV1Api', rook_env: 'RookEnv'):
101-
self.storage_class = storage_class
100+
def __init__(self, storage_class_name: str, coreV1_api: 'client.CoreV1Api', rook_env: 'RookEnv'):
101+
self.storage_class_name = storage_class_name
102102
self.coreV1_api = coreV1_api
103103
self.rook_env = rook_env
104+
self.pvs_in_sc: List[client.V1PersistentVolumeList] = []
104105

105106
def fetch(self) -> None:
106107
self.inventory: KubernetesResource[client.V1PersistentVolumeList] = KubernetesResource(self.coreV1_api.list_persistent_volume)
107-
self.pvs_in_sc = [i for i in self.inventory.items if i.spec.storage_class_name == self.storage_class]
108+
self.pvs_in_sc = [i for i in self.inventory.items if i.spec.storage_class_name == self.storage_class_name]
108109

109110
def convert_size(self, size_str: str) -> int:
110111
units = ("", "Ki", "Mi", "Gi", "Ti", "Pi", "Ei", "", "K", "M", "G", "T", "P", "E")
@@ -149,7 +150,7 @@ def device(self, i: 'client.V1PersistentVolume') -> Tuple[str, Device]:
149150
available = state,
150151
)
151152
return (node, device)
152-
153+
153154

154155
class LSOFetcher(DefaultFetcher):
155156
def __init__(self, storage_class: 'str', coreV1_api: 'client.CoreV1Api', rook_env: 'RookEnv', customObjects_api: 'client.CustomObjectsApi', nodenames: 'Optional[List[str]]' = None):
@@ -372,9 +373,9 @@ def get_item_name(self, item: Any) -> Any:
372373
self.api_func))
373374

374375
class DefaultCreator():
375-
def __init__(self, inventory: 'Dict[str, List[Device]]', coreV1_api: 'client.CoreV1Api', storage_class: 'str'):
376+
def __init__(self, inventory: 'Dict[str, List[Device]]', coreV1_api: 'client.CoreV1Api', storage_class_name: 'str'):
376377
self.coreV1_api = coreV1_api
377-
self.storage_class = storage_class
378+
self.storage_class_name = storage_class_name
378379
self.inventory = inventory
379380

380381
def device_to_device_set(self, drive_group: DriveGroupSpec, d: Device) -> ccl.StorageClassDeviceSetsItem:
@@ -391,7 +392,7 @@ def device_to_device_set(self, drive_group: DriveGroupSpec, d: Device) -> ccl.St
391392
name="data"
392393
),
393394
spec=ccl.Spec(
394-
storageClassName=self.storage_class,
395+
storageClassName=self.storage_class_name,
395396
volumeMode="Block",
396397
accessModes=ccl.CrdObjectList(["ReadWriteOnce"]),
397398
resources={
@@ -700,18 +701,19 @@ def __init__(
700701
storageV1_api: 'client.StorageV1Api',
701702
appsV1_api: 'client.AppsV1Api',
702703
rook_env: 'RookEnv',
703-
storage_class: 'str'
704+
storage_class_name: 'str'
704705
):
705706
self.rook_env = rook_env # type: RookEnv
706707
self.coreV1_api = coreV1_api # client.CoreV1Api
707708
self.batchV1_api = batchV1_api
708709
self.customObjects_api = customObjects_api
709710
self.storageV1_api = storageV1_api # client.StorageV1Api
710711
self.appsV1_api = appsV1_api # client.AppsV1Api
711-
self.storage_class = storage_class # type: str
712+
self.storage_class_name = storage_class_name # type: str
712713

713714
# TODO: replace direct k8s calls with Rook API calls
714-
self.storage_classes : KubernetesResource = KubernetesResource(self.storageV1_api.list_storage_class)
715+
self.available_storage_classes : KubernetesResource = KubernetesResource(self.storageV1_api.list_storage_class)
716+
self.configured_storage_classes = self.list_storage_classes()
715717

716718
self.rook_pods: KubernetesResource[client.V1Pod] = KubernetesResource(self.coreV1_api.list_namespaced_pod,
717719
namespace=self.rook_env.namespace,
@@ -751,34 +753,57 @@ def rook_api_patch(self, path: str, **kwargs: Any) -> Any:
751753
def rook_api_post(self, path: str, **kwargs: Any) -> Any:
752754
return self.rook_api_call("POST", path, **kwargs)
753755

756+
def list_storage_classes(self) -> List[str]:
757+
try:
758+
crd = self.customObjects_api.get_namespaced_custom_object(
759+
group="ceph.rook.io",
760+
version="v1",
761+
namespace=self.rook_env.namespace,
762+
plural="cephclusters",
763+
name=self.rook_env.cluster_name)
764+
765+
sc_devicesets = crd['spec']['storage']['storageClassDeviceSets']
766+
sc_names = [vct['spec']['storageClassName'] for sc in sc_devicesets for vct in sc['volumeClaimTemplates']]
767+
log.info(f"the cluster has the following configured sc: {sc_names}")
768+
return sc_names
769+
except Exception as e:
770+
log.error(f"unable to list storage classes: {e}")
771+
return []
772+
773+
# TODO: remove all the calls to code that uses rook_cluster.storage_class_name
754774
def get_storage_class(self) -> 'client.V1StorageClass':
755-
matching_sc = [i for i in self.storage_classes.items if self.storage_class == i.metadata.name]
775+
matching_sc = [i for i in self.available_storage_classes.items if self.storage_class_name == i.metadata.name]
756776
if len(matching_sc) == 0:
757-
log.error(f"No storage class exists matching configured Rook orchestrator storage class which currently is <{self.storage_class}>. This storage class can be set in ceph config (mgr/rook/storage_class)")
777+
log.error(f"No storage class exists matching configured Rook orchestrator storage class which currently is <{self.storage_class_name}>. This storage class can be set in ceph config (mgr/rook/storage_class)")
758778
raise Exception('No storage class exists matching name provided in ceph config at mgr/rook/storage_class')
759779
return matching_sc[0]
760780

761781
def get_discovered_devices(self, nodenames: Optional[List[str]] = None) -> Dict[str, List[Device]]:
762-
self.fetcher: Optional[DefaultFetcher] = None
782+
discovered_devices: Dict[str, List[Device]] = {}
763783
op_settings = self.coreV1_api.read_namespaced_config_map(name="rook-ceph-operator-config", namespace=self.rook_env.operator_namespace).data
784+
fetcher: Optional[DefaultFetcher] = None
764785
if op_settings.get('ROOK_ENABLE_DISCOVERY_DAEMON', 'false').lower() == 'true':
765-
self.fetcher = PDFetcher(self.coreV1_api, self.rook_env)
786+
fetcher = PDFetcher(self.coreV1_api, self.rook_env)
787+
fetcher.fetch()
788+
discovered_devices = fetcher.devices()
766789
else:
767-
storage_class = self.get_storage_class()
768-
if storage_class.metadata.labels and ('local.storage.openshift.io/owner-name' in storage_class.metadata.labels):
769-
self.fetcher = LSOFetcher(self.storage_class, self.coreV1_api, self.customObjects_api, nodenames)
770-
else:
771-
self.fetcher = DefaultFetcher(self.storage_class, self.coreV1_api, self.rook_env)
790+
active_storage_classes = [sc for sc in self.available_storage_classes.items if sc.metadata.name in self.configured_storage_classes]
791+
for sc in active_storage_classes:
792+
if sc.metadata.labels and ('local.storage.openshift.io/owner-name' in sc.metadata.labels):
793+
fetcher = LSOFetcher(sc.metadata.name, self.coreV1_api, self.customObjects_api, nodenames)
794+
else:
795+
fetcher = DefaultFetcher(sc.metadata.name, self.coreV1_api, self.rook_env)
796+
fetcher.fetch()
797+
discovered_devices.update(fetcher.devices())
772798

773-
self.fetcher.fetch()
774-
return self.fetcher.devices()
799+
return discovered_devices
775800

776801
def get_osds(self) -> List:
777802
osd_pods: KubernetesResource = KubernetesResource(self.coreV1_api.list_namespaced_pod,
778803
namespace=self.rook_env.namespace,
779804
label_selector='app=rook-ceph-osd')
780805
return list(osd_pods.items)
781-
806+
782807
def get_nfs_conf_url(self, nfs_cluster: str, instance: str) -> Optional[str]:
783808
#
784809
# Fetch cephnfs object for "nfs_cluster" and then return a rados://
@@ -1174,9 +1199,9 @@ def add_osds(self, drive_group, matching_hosts):
11741199
storage_class.metadata.labels
11751200
and 'local.storage.openshift.io/owner-name' in storage_class.metadata.labels
11761201
):
1177-
creator = LSOCreator(inventory, self.coreV1_api, self.storage_class)
1202+
creator = LSOCreator(inventory, self.coreV1_api, self.storage_class_name)
11781203
else:
1179-
creator = DefaultCreator(inventory, self.coreV1_api, self.storage_class)
1204+
creator = DefaultCreator(inventory, self.coreV1_api, self.storage_class_name)
11801205
return self._patch(
11811206
ccl.CephCluster,
11821207
'cephclusters',

0 commit comments

Comments
 (0)