Coverage for ocp_resources/storage_class.py: 0%

59 statements  

« prev     ^ index     » next       coverage.py v7.6.10, created at 2025-01-30 10:48 +0200

1# -*- coding: utf-8 -*- 

2from kubernetes.dynamic.exceptions import ResourceNotFoundError 

3 

4from ocp_resources.resource import MissingRequiredArgumentError, Resource 

5from ocp_resources.storage_profile import StorageProfile 

6 

7 

8class StorageClass(Resource): 

9 """ 

10 StorageClass object. 

11 """ 

12 

13 api_group = Resource.ApiGroup.STORAGE_K8S_IO 

14 

15 class Types: 

16 """ 

17 These are names of StorageClass instances when you run `oc get sc` 

18 

19 API: 

20 https://kubernetes.io/docs/concepts/storage/storage-classes/ 

21 """ 

22 

23 LOCAL_BLOCK = "local-block" 

24 HOSTPATH = "hostpath-provisioner" 

25 CEPH_RBD = "ocs-storagecluster-ceph-rbd" 

26 NFS = "nfs" 

27 HOSTPATH_CSI = "hostpath-csi" 

28 

29 class Provisioner: 

30 HOSTPATH = "kubevirt.io/hostpath-provisioner" 

31 NO_PROVISIONER = "kubernetes.io/no-provisioner" 

32 CEPH_RBD = "openshift-storage.rbd.csi.ceph.com" 

33 HOSTPATH_CSI = "kubevirt.io.hostpath-provisioner" 

34 

35 class VolumeBindingMode: 

36 """ 

37 VolumeBindingMode indicates how PersistentVolumeClaims should be provisioned and bound. 

38 When unset, Immediate is used. 

39 When "Immediate", if you want to use the "node aware" hostpath-provisioner, 

40 ProvisionOnNode annotations should be introduced to PVC. 

41 Or in order to be able to use the hpp without specifying the node on the PVC, 

42 since CNV-2.2, hpp supports for "WaitForFirstConsumer". 

43 """ 

44 

45 # TODO: Rename to Uppercase 

46 Immediate = "Immediate" 

47 WaitForFirstConsumer = "WaitForFirstConsumer" 

48 

49 class Annotations: 

50 IS_DEFAULT_CLASS = f"{Resource.ApiGroup.STORAGECLASS_KUBERNETES_IO}/is-default-class" 

51 IS_DEFAULT_VIRT_CLASS = f"{Resource.ApiGroup.STORAGECLASS_KUBEVIRT_IO}/is-default-virt-class" 

52 

53 class ReclaimPolicy: 

54 DELETE = "Delete" 

55 RETAIN = "Retain" 

56 

57 def __init__( 

58 self, 

59 provisioner=None, 

60 reclaim_policy=None, 

61 volume_binding_mode=None, 

62 allow_volume_expansion=None, 

63 parameters=None, 

64 allowed_topologies=None, 

65 mount_options=None, 

66 **kwargs, 

67 ): 

68 """ 

69 StorageClass object 

70 

71 Args: 

72 provisioner (str): The provisioner of the storage class 

73 reclaim_policy (str): Can be either "Delete" or "Retain" 

74 volume_binding_mode (str): When volume binding and dynamic provisioning should occur 

75 allow_volume_expansion (bool): True for allowing the volume expansion 

76 parameters (dict): Describe volumes belonging to the storage class. 

77 allowed_topologies (list): Restrict provisioning to specific topologies 

78 mount_options (list): PV's that are dynamically created by the SC will have the mount options 

79 """ 

80 super().__init__( 

81 **kwargs, 

82 ) 

83 

84 self.provisioner = provisioner 

85 self.reclaim_policy = reclaim_policy 

86 self.volume_binding_mode = volume_binding_mode 

87 self.allow_volume_expansion = allow_volume_expansion 

88 self.parameters = parameters 

89 self.allowed_topologies = allowed_topologies 

90 self.mount_options = mount_options 

91 

92 def to_dict(self) -> None: 

93 super().to_dict() 

94 if not self.kind_dict and not self.yaml_file: 

95 if not self.provisioner: 

96 raise MissingRequiredArgumentError(argument="provisioner") 

97 self.res.update({"provisioner": self.provisioner}) 

98 if self.reclaim_policy: 

99 self.res.update({"reclaimPolicy": self.reclaim_policy}) 

100 if self.volume_binding_mode: 

101 self.res.update({"volumeBindingMode": self.volume_binding_mode}) 

102 if self.allow_volume_expansion: 

103 self.res.update({"allowVolumeExpansion": self.allow_volume_expansion}) 

104 if self.parameters: 

105 self.res.update({"parameters": self.parameters}) 

106 if self.allowed_topologies: 

107 self.res.update({"allowedTopologies": self.allowed_topologies}) 

108 if self.mount_options: 

109 self.res.update({"mountOptions": self.mount_options}) 

110 

111 @property 

112 def storage_profile(self): 

113 try: 

114 return StorageProfile( 

115 client=self.client, 

116 name=self.name, 

117 ) 

118 except ResourceNotFoundError: 

119 self.logger.error(f" storageProfile is not found for {self.name} storageClass") 

120 raise