Skip to content

Commit ff8a807

Browse files
Enhance StorageConsumer cr and class (#11621)
* Enhance StorageConsumer cr and class * if version deco added Signed-off-by: Daniel Osypenko <dosypenk@redhat.com>
1 parent 837e269 commit ff8a807

File tree

2 files changed

+251
-1
lines changed

2 files changed

+251
-1
lines changed

ocs_ci/ocs/resources/storageconsumer.py

Lines changed: 215 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
from ocs_ci.framework import config
88
from ocs_ci.ocs import constants, ocp
99
from ocs_ci.ocs.resources.ocs import OCS
10+
from ocs_ci.ocs.version import if_version
1011
from ocs_ci.utility.utils import exec_cmd
1112

1213
log = logging.getLogger(__name__)
@@ -19,6 +20,18 @@ class StorageConsumer:
1920

2021
def __init__(self, consumer_name, consumer_context=None):
2122
"""
23+
Starting from ODF 4.19 (Converged) this CR has optional Spec fields:
24+
StorageQuotaInGiB int
25+
StorageClasses []
26+
VolumeSnapshotClasses []
27+
VolumeGroupSnapshotClasses []
28+
29+
Starting from ODF 4.19 (Converged) this CR has optional Status fields:
30+
Client ClientStatus
31+
RadosNamespace RadosNamespaceStatus
32+
CephFsSubVolumeGroup SubVolumeGroupStatus
33+
CephCsiClientProfiles [] ClientProfileStatus
34+
2235
Args:
2336
consumer_name (string): name of the StorageConsumer resource
2437
consumer_context (int): index of cluster context. This is needed for
@@ -120,3 +133,205 @@ def get_heartbeat_cronjob(self):
120133
if job["metadata"]["name"].endswith("status-reporter")
121134
][0]
122135
return cronjob
136+
137+
@if_version(">4.18")
138+
def get_client_status(self):
139+
"""
140+
Get client status from storageconsumer resource and apply patch.
141+
142+
Returns:
143+
dict: client status
144+
145+
"""
146+
with config.RunWithConfigContext(self.consumer_context):
147+
return self.ocp.get(resource_name=self.name).get("status").get("client")
148+
149+
@if_version(">4.18")
150+
def get_rados_namespace_status(self):
151+
"""
152+
Get rados namespace status from storageconsumer resource and apply patch.
153+
154+
Returns:
155+
dict: rados namespace status
156+
157+
"""
158+
with config.RunWithConfigContext(self.consumer_context):
159+
return (
160+
self.ocp.get(resource_name=self.name)
161+
.get("status")
162+
.get("radosNamespace")
163+
)
164+
165+
@if_version(">4.18")
166+
def get_cephfs_subvolume_group_status(self):
167+
"""
168+
Get cephfs subvolume group status from storageconsumer resource and apply patch.
169+
170+
Returns:
171+
dict: cephfs subvolume group status
172+
173+
"""
174+
with config.RunWithConfigContext(self.consumer_context):
175+
return (
176+
self.ocp.get(resource_name=self.name)
177+
.get("status")
178+
.get("cephFsSubVolumeGroup")
179+
)
180+
181+
@if_version(">4.18")
182+
def get_ceph_csi_client_profiles(self):
183+
"""
184+
Get ceph csi client profiles from storageconsumer resource and apply patch.
185+
186+
Returns:
187+
dict: ceph csi client profiles
188+
189+
"""
190+
with config.RunWithConfigContext(self.consumer_context):
191+
return (
192+
self.ocp.get(resource_name=self.name)
193+
.get("status")
194+
.get("cephCsiClientProfiles")
195+
)
196+
197+
def get_storage_quota_in_gib(self):
198+
"""
199+
Get storage quota in GiB from storageconsumer resource.
200+
201+
Returns:
202+
int: storage quota in GiB
203+
204+
"""
205+
with config.RunWithConfigContext(self.consumer_context):
206+
return (
207+
self.ocp.get(resource_name=self.name)
208+
.get("spec")
209+
.get("storageQuotaInGiB")
210+
)
211+
212+
@if_version(">4.18")
213+
def get_storage_classes(self):
214+
"""
215+
Get storage classes from storageconsumer resource and apply patch.
216+
217+
Returns:
218+
list: storage classes
219+
220+
"""
221+
with config.RunWithConfigContext(self.consumer_context):
222+
return (
223+
self.ocp.get(resource_name=self.name).get("spec").get("storageClasses")
224+
)
225+
226+
def set_storage_quota_in_gib(self, quota):
227+
"""
228+
Update storage quota in GiB in storageconsumer resource and apply patch.
229+
230+
Args:
231+
quota (int): storage quota in GiB
232+
233+
"""
234+
with config.RunWithConfigContext(self.consumer_context):
235+
patch_param = f'{{"spec": {{"storageQuotaInGiB": {quota}}}}}'
236+
self.ocp.patch(resource_name=self.name, params=patch_param)
237+
238+
@if_version(">4.18")
239+
def add_custom_storage_class(self, storage_class):
240+
"""
241+
Add storage class to storageconsumer resource and apply patch.
242+
243+
Args:
244+
storage_class (string): storage class
245+
246+
"""
247+
with config.RunWithConfigContext(self.consumer_context):
248+
patch_param = f'{{"spec": {{"storageClasses": ["{storage_class}"]}}}}'
249+
self.ocp.patch(resource_name=self.name, params=patch_param)
250+
251+
@if_version(">4.18")
252+
def remove_custom_storage_class(self, storage_class):
253+
"""
254+
Remove storage class from storageconsumer resource and apply patch.
255+
256+
Args:
257+
storage_class (string): storage class
258+
259+
"""
260+
with config.RunWithConfigContext(self.consumer_context):
261+
current_storage_classes = (
262+
self.ocp.get(resource_name=self.name).get("spec").get("storageClasses")
263+
)
264+
if storage_class in current_storage_classes:
265+
current_storage_classes.remove(storage_class)
266+
patch_param = (
267+
f'{{"spec": {{"storageClasses": {current_storage_classes}}}}}'
268+
)
269+
self.ocp.patch(resource_name=self.name, params=patch_param)
270+
271+
@if_version(">4.18")
272+
def add_custom_volume_snapshot_class(self, snapshot_class):
273+
"""
274+
Add volume snapshot class to storageconsumer resource and apply patch.
275+
276+
Args:
277+
snapshot_class (string): volume snapshot class
278+
279+
"""
280+
with config.RunWithConfigContext(self.consumer_context):
281+
patch_param = (
282+
f'{{"spec": {{"volumeSnapshotClasses": ["{snapshot_class}"]}}}}'
283+
)
284+
self.ocp.patch(resource_name=self.name, params=patch_param)
285+
286+
@if_version(">4.18")
287+
def remove_custom_volume_snapshot_class(self, snapshot_class):
288+
"""
289+
Remove volume snapshot class from storageconsumer resource and apply patch.
290+
291+
Args:
292+
snapshot_class (string): volume snapshot class
293+
294+
"""
295+
with config.RunWithConfigContext(self.consumer_context):
296+
current_snapshot_classes = (
297+
self.ocp.get(resource_name=self.name)
298+
.get("spec")
299+
.get("volumeSnapshotClasses")
300+
)
301+
if snapshot_class in current_snapshot_classes:
302+
current_snapshot_classes.remove(snapshot_class)
303+
patch_param = f'{{"spec": {{"volumeSnapshotClasses": {current_snapshot_classes}}}}}'
304+
self.ocp.patch(resource_name=self.name, params=patch_param)
305+
306+
@if_version(">4.18")
307+
def add_custom_volume_group_snapshot_class(self, group_snapshot_class):
308+
"""
309+
Add volume group snapshot class to storageconsumer resource and apply patch.
310+
311+
Args:
312+
group_snapshot_class (string): volume group snapshot class
313+
314+
"""
315+
with config.RunWithConfigContext(self.consumer_context):
316+
patch_param = f'{{"spec": {{"volumeGroupSnapshotClasses": ["{group_snapshot_class}"]}}}}'
317+
self.ocp.patch(resource_name=self.name, params=patch_param)
318+
319+
@if_version(">4.18")
320+
def remove_custom_volume_group_snapshot_class(self, group_snapshot_class):
321+
"""
322+
Remove volume group snapshot class from storageconsumer resource and apply patch.
323+
324+
Args:
325+
group_snapshot_class (string): volume group snapshot class
326+
327+
"""
328+
with config.RunWithConfigContext(self.consumer_context):
329+
current_group_snapshot_classes = (
330+
self.ocp.get(resource_name=self.name)
331+
.get("spec")
332+
.get("volumeGroupSnapshotClasses")
333+
)
334+
if group_snapshot_class in current_group_snapshot_classes:
335+
current_group_snapshot_classes.remove(group_snapshot_class)
336+
patch_param = f'{{"spec": {{"volumeGroupSnapshotClasses": {current_group_snapshot_classes}}}}}'
337+
self.ocp.patch(resource_name=self.name, params=patch_param)

ocs_ci/ocs/version.py

Lines changed: 36 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,14 +22,15 @@
2222
import pprint
2323
import re
2424
import sys
25+
from functools import wraps
2526

2627
from ocs_ci import framework
2728
from ocs_ci.framework import config
2829
from ocs_ci.ocs import constants, node, ocp
2930
from ocs_ci.ocs.ocp import OCP
3031
from ocs_ci.ocs.exceptions import CommandFailed
3132
from ocs_ci.utility import utils
32-
33+
from ocs_ci.utility.utils import skipif_ocs_version
3334

3435
logger = logging.getLogger(__name__)
3536

@@ -275,3 +276,37 @@ def main():
275276
return
276277

277278
report_ocs_version(cluster_version, image_dict, file_obj=sys.stdout)
279+
280+
281+
def if_version(expressions):
282+
"""
283+
Decorator to skip the function if the OCS version does not match the required version
284+
285+
! Important note: This decorator is silently skipping the function
286+
if the OCS version does not match the required version. Only warning message will be added to the log.
287+
If the test should fail when wrapped function was skipped, use this decorator in combination with pytest 'assert'.
288+
289+
Args:
290+
expressions (str OR list): condition for which we need to check, eg:
291+
A single expression string '>=4.2' OR
292+
A list of expressions like ['<4.3', '>4.2'], ['<=4.3', '>=4.2']
293+
294+
Returns:
295+
result of executing the function if the OCS version matches the required version
296+
297+
"""
298+
299+
def decorator(func):
300+
@wraps(func)
301+
def wrapper(*args, **kwargs):
302+
if skipif_ocs_version(expressions):
303+
return func(*args, **kwargs)
304+
else:
305+
logger.warning(
306+
f"Skipping {func.__name__} because the OCS version "
307+
f"does not match the required version {expressions}"
308+
)
309+
310+
return wrapper
311+
312+
return decorator

0 commit comments

Comments
 (0)