1+ from __future__ import annotations
2+
13from ocp_resources .utils .constants import (
24 TIMEOUT_1MINUTE ,
35 TIMEOUT_2MINUTES ,
1012from timeout_sampler import TimeoutExpiredError , TimeoutSampler
1113from warnings import warn
1214
15+ from typing import Any , TYPE_CHECKING
16+
17+ if TYPE_CHECKING :
18+ from ocp_resources .secret import Secret
19+
1320
1421class DataVolume (NamespacedResource ):
1522 """
@@ -70,69 +77,58 @@ class Status(Resource.Condition.Status):
7077
7178 def __init__ (
7279 self ,
73- name = None ,
74- namespace = None ,
75- source = None ,
76- size = None ,
77- storage_class = None ,
78- url = None ,
79- content_type = ContentType .KUBEVIRT ,
80- access_modes = None ,
81- cert_configmap = None ,
82- secret = None ,
83- client = None ,
84- volume_mode = None ,
85- hostpath_node = None ,
86- source_pvc = None ,
87- source_namespace = None ,
88- multus_annotation = None ,
89- bind_immediate_annotation = None ,
90- preallocation = None ,
91- teardown = True ,
92- yaml_file = None ,
93- delete_timeout = TIMEOUT_4MINUTES ,
94- api_name = "pvc" ,
95- delete_after_completion = None ,
96- ** kwargs ,
97- ):
80+ source : str | None = None ,
81+ source_dict : dict [str , Any ] | None = None ,
82+ size : str | None = None ,
83+ storage_class : str | None = None ,
84+ url : str | None = None ,
85+ content_type : str | None = None ,
86+ access_modes : str | None = None ,
87+ volume_mode : str | None = None ,
88+ cert_configmap : str | None = None ,
89+ secret : Secret | None = None ,
90+ hostpath_node : str | None = None ,
91+ source_pvc : str | None = None ,
92+ source_namespace : str | None = None ,
93+ source_ref : dict [str , Any ] | None = None ,
94+ multus_annotation : str | None = None ,
95+ bind_immediate_annotation : bool | None = None ,
96+ preallocation : bool | None = None ,
97+ api_name : str | None = "pvc" ,
98+ checkpoints : list [Any ] | None = None ,
99+ final_checkpoint : bool | None = None ,
100+ priority_class_name : str | None = None ,
101+ ** kwargs : Any ,
102+ ) -> None :
98103 """
99104 DataVolume object
100105
101106 Args:
102- name (str): DataVolume name.
103- namespace (str): DataVolume namespace.
104- source (str): source of DV - upload/http/pvc/registry.
105- size (str): DataVolume size - format size+size unit, for example: "5Gi".
107+ source (str, default: None): source of DV - upload/http/pvc/registry/blank.
108+ source_dict (dict[str, Any], default: None): DataVolume.source dictionary.
109+ size (str, default: None): DataVolume size - format size+size unit, for example: "5Gi".
106110 storage_class (str, default: None): storage class name for DataVolume.
107111 url (str, default: None): url for importing DV, when source is http/registry.
108- content_type (str, default: "kubevirt"): DataVolume content type.
109- access_modes (str, default: None): DataVolume access mode.
112+ content_type (str, default: None): DataVolume content type (e.g., "kubevirt", "archive").
113+ access_modes (str, default: None): DataVolume access mode (e.g., "ReadWriteOnce", "ReadWriteMany").
114+ volume_mode (str, default: None): DataVolume volume mode (e.g., "Filesystem", "Block").
110115 cert_configmap (str, default: None): name of config map for TLS certificates.
111116 secret (Secret, default: None): to be set as secretRef.
112- client (DynamicClient): DynamicClient to use.
113- volume_mode (str, default: None): DataVolume volume mode.
114117 hostpath_node (str, default: None): Node name to provision the DV on.
115118 source_pvc (str, default: None): PVC name for when cloning the DV.
116119 source_namespace (str, default: None): PVC namespace for when cloning the DV.
120+ source_ref (dict[str, Any], default: None): SourceRef is an indirect reference to the source of data for the
121+ requested DataVolume. Currently only "DataSource" is supported. Fields: kind (str), name (str), namespace (str)
117122 multus_annotation (str, default: None): network nad name.
118- bind_immediate_annotation (bool, default: None): when WaitForFirstConsumer is set in StorageClass and DV
119- should be bound immediately.
123+ bind_immediate_annotation (bool, default: None): when WaitForFirstConsumer is set in StorageClass and DV
124+ should be bound immediately.
120125 preallocation (bool, default: None): preallocate disk space.
121- teardown (bool, default: True): Indicates if this resource would need to be deleted.
122- yaml_file (yaml, default: None): yaml file for the resource.
123- delete_timeout (int, default: 4 minutes): timeout associated with delete action.
124- api_name (str, default: "pvc"): api used for DV, pvc/storage
125- delete_after_completion (str, default: None): annotation for garbage collector - "true"/"false"
126+ api_name (str, default: "pvc"): api used for DV (e.g., "storage", "pvc").
127+ checkpoints (list[Any], default: None): list of DataVolumeCheckpoints for snapshot operations.
128+ final_checkpoint (bool, default: None): indicates whether the current DataVolumeCheckpoint is the final one.
129+ priority_class_name (str, default: None): priority class name for the DataVolume pod.
126130 """
127- super ().__init__ (
128- name = name ,
129- namespace = namespace ,
130- client = client ,
131- teardown = teardown ,
132- yaml_file = yaml_file ,
133- delete_timeout = delete_timeout ,
134- ** kwargs ,
135- )
131+ super ().__init__ (** kwargs )
136132 self .source = source
137133 self .url = url
138134 self .cert_configmap = cert_configmap
@@ -145,62 +141,98 @@ def __init__(
145141 self .hostpath_node = hostpath_node
146142 self .source_pvc = source_pvc
147143 self .source_namespace = source_namespace
144+ self .source_dict = source_dict
145+ self .source_ref = source_ref
148146 self .multus_annotation = multus_annotation
149147 self .bind_immediate_annotation = bind_immediate_annotation
150148 self .preallocation = preallocation
151149 self .api_name = api_name
152- self .delete_after_completion = delete_after_completion
150+ self .checkpoints = checkpoints
151+ self .final_checkpoint = final_checkpoint
152+ self .priority_class_name = priority_class_name
153153
154154 def to_dict (self ) -> None :
155155 super ().to_dict ()
156156 if not self .kind_dict and not self .yaml_file :
157- self .res .update ({
158- "spec" : {
159- "source" : {self .source : {"url" : self .url }},
160- self .api_name : {
161- "resources" : {"requests" : {"storage" : self .size }},
162- },
163- }
164- })
165- if self .access_modes :
166- self .res ["spec" ][self .api_name ]["accessModes" ] = [self .access_modes ]
167- if self .content_type :
168- self .res ["spec" ]["contentType" ] = self .content_type
169- if self .storage_class :
170- self .res ["spec" ][self .api_name ]["storageClassName" ] = self .storage_class
171- if self .secret :
172- self .res ["spec" ]["source" ][self .source ]["secretRef" ] = self .secret .name
173- if self .volume_mode :
174- self .res ["spec" ][self .api_name ]["volumeMode" ] = self .volume_mode
175- if self .source == "http" or "registry" :
176- self .res ["spec" ]["source" ][self .source ]["url" ] = self .url
177- if self .cert_configmap :
178- self .res ["spec" ]["source" ][self .source ]["certConfigMap" ] = self .cert_configmap
179- if self .source == "upload" or self .source == "blank" :
180- self .res ["spec" ]["source" ][self .source ] = {}
157+ self .res ["spec" ] = {}
158+ _spec = self .res ["spec" ]
159+
160+ if self .checkpoints is not None :
161+ _spec ["checkpoints" ] = self .checkpoints
162+
163+ if self .content_type is not None :
164+ _spec ["contentType" ] = self .content_type
165+
166+ if self .final_checkpoint is not None :
167+ _spec ["finalCheckpoint" ] = self .final_checkpoint
168+
169+ if self .preallocation is not None :
170+ _spec ["preallocation" ] = self .preallocation
171+
172+ if self .priority_class_name is not None :
173+ _spec ["priorityClassName" ] = self .priority_class_name
174+
175+ # Set api_name spec fields (pvc/storage)
176+ if self .api_name is not None :
177+ _spec [self .api_name ] = {}
178+
179+ if self .access_modes is not None :
180+ _spec [self .api_name ]["accessModes" ] = [self .access_modes ]
181+
182+ if self .volume_mode is not None :
183+ _spec [self .api_name ]["volumeMode" ] = self .volume_mode
184+
185+ if self .storage_class is not None :
186+ _spec [self .api_name ]["storageClassName" ] = self .storage_class
187+
188+ if self .size is not None :
189+ _spec [self .api_name ]["resources" ] = {"requests" : {"storage" : self .size }}
190+
191+ # Handle source configuration
192+ if self .source_dict is not None :
193+ _spec ["source" ] = self .source_dict
194+ elif self .source is not None :
195+ warn (
196+ "source is deprecated and will be removed in the next version. Use source_dict instead." ,
197+ DeprecationWarning ,
198+ stacklevel = 2 ,
199+ )
200+
201+ _spec ["source" ] = {}
202+ source_spec = _spec ["source" ]
203+
204+ if self .source in ["http" , "registry" ]:
205+ source_spec [self .source ] = {"url" : self .url }
206+ elif self .source in ["upload" , "blank" ]:
207+ source_spec [self .source ] = {}
208+ elif self .source == "pvc" :
209+ source_spec [self .source ] = {
210+ "name" : self .source_pvc ,
211+ "namespace" : self .source_namespace or self .namespace ,
212+ }
213+
214+ if self .secret is not None :
215+ source_spec [self .source ]["secretRef" ] = self .secret .name
216+ if self .cert_configmap is not None :
217+ source_spec [self .source ]["certConfigMap" ] = self .cert_configmap
218+
219+ if self .source_ref is not None :
220+ _spec ["sourceRef" ] = self .source_ref
221+
181222 if self .hostpath_node :
182223 self .res ["metadata" ].setdefault ("annotations" , {}).update ({
183224 f"{ NamespacedResource .ApiGroup .KUBEVIRT_IO } /provisionOnNode" : (self .hostpath_node )
184225 })
226+
185227 if self .multus_annotation :
186228 self .res ["metadata" ].setdefault ("annotations" , {}).update ({
187229 f"{ NamespacedResource .ApiGroup .K8S_V1_CNI_CNCF_IO } /networks" : (self .multus_annotation )
188230 })
231+
189232 if self .bind_immediate_annotation :
190233 self .res ["metadata" ].setdefault ("annotations" , {}).update ({
191234 f"{ self .api_group } /storage.bind.immediate.requested" : "true"
192235 })
193- if self .source == "pvc" :
194- self .res ["spec" ]["source" ]["pvc" ] = {
195- "name" : self .source_pvc or "dv-source" ,
196- "namespace" : self .source_namespace or self .namespace ,
197- }
198- if self .preallocation is not None :
199- self .res ["spec" ]["preallocation" ] = self .preallocation
200- if self .delete_after_completion :
201- self .res ["metadata" ].setdefault ("annotations" , {}).update ({
202- f"{ self .api_group } /storage.deleteAfterCompletion" : (self .delete_after_completion )
203- })
204236
205237 def wait_deleted (self , timeout = TIMEOUT_4MINUTES ):
206238 """
0 commit comments