Coverage for ocp_resources/virtual_machine_import.py: 0%

143 statements  

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

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

2 

3 

4from ocp_resources.utils.constants import PROTOCOL_ERROR_EXCEPTION_DICT, TIMEOUT_4MINUTES 

5from ocp_resources.resource import NamespacedResource 

6from timeout_sampler import TimeoutExpiredError, TimeoutSampler 

7from ocp_resources.virtual_machine import VirtualMachine 

8 

9 

10def _map_mappings(mappings): 

11 mappings_list = [] 

12 for mapping in mappings: 

13 mapping_dict = {"target": {"name": mapping.target_name}} 

14 if mapping.target_namespace: 

15 mapping_dict["target"]["namespace"] = mapping.target_namespace 

16 if mapping.target_type: 

17 mapping_dict["type"] = mapping.target_type 

18 if mapping.source_id: 

19 mapping_dict.setdefault("source", {})["id"] = mapping.source_id 

20 if mapping.source_name: 

21 mapping_dict.setdefault("source", {})["name"] = mapping.source_name 

22 if mapping.target_access_modes: 

23 mapping_dict["accessMode"] = mapping.target_access_modes 

24 if mapping.target_volume_mode: 

25 mapping_dict["volumeMode"] = mapping.target_volume_mode 

26 mappings_list.append(mapping_dict) 

27 return mappings_list 

28 

29 

30class VirtualMachineImport(NamespacedResource): 

31 """ 

32 Virtual Machine Import object, inherited from NamespacedResource. 

33 """ 

34 

35 api_group = NamespacedResource.ApiGroup.V2V_KUBEVIRT_IO 

36 

37 class Condition(NamespacedResource.Condition): 

38 SUCCEEDED = "Succeeded" 

39 VALID = "Valid" 

40 MAPPING_RULES_VERIFIED = "MappingRulesVerified" 

41 PROCESSING = "Processing" 

42 

43 class ValidConditionReason: 

44 """ 

45 Valid condition reason object 

46 """ 

47 

48 VALIDATION_COMPLETED = "ValidationCompleted" 

49 SECRET_NOT_FOUND = "SecretNotFound" # pragma: allowlist secret 

50 RESOURCE_MAPPING_NOT_FOUND = "ResourceMappingNotFound" 

51 UNINITIALIZED_PROVIDER = "UninitializedProvider" 

52 SOURCE_VM_NOT_FOUND = "SourceVMNotFound" 

53 INCOMPLETE_MAPPING_RULES = "IncompleteMappingRules" 

54 

55 class MappingRulesConditionReason: 

56 """ 

57 Mapping rules verified condition reason object 

58 """ 

59 

60 MAPPING_COMPLETED = "MappingRulesVerificationCompleted" 

61 MAPPING_FAILED = "MappingRulesVerificationFailed" 

62 MAPPING_REPORTED_WARNINGS = "MappingRulesVerificationReportedWarnings" 

63 

64 class ProcessingConditionReason: 

65 """ 

66 Processing condition reason object 

67 """ 

68 

69 CREATING_TARGET_VM = "CreatingTargetVM" 

70 COPYING_DISKS = "CopyingDisks" 

71 COMPLETED = "ProcessingCompleted" 

72 FAILED = "ProcessingFailed" 

73 

74 class SucceededConditionReason: 

75 """ 

76 Succeeced cond reason object 

77 """ 

78 

79 VALIDATION_FAILED = "ValidationFailed" 

80 VM_CREATION_FAILED = "VMCreationFailed" 

81 DATAVOLUME_CREATION_FAILED = "DataVolumeCreationFailed" 

82 VIRTUAL_MACHINE_READY = "VirtualMachineReady" 

83 VIRTUAL_MACHINE_RUNNING = "VirtualMachineRunning" 

84 VMTEMPLATE_MATCHING_FAILED = "VMTemplateMatchingFailed" 

85 

86 def __init__( 

87 self, 

88 name=None, 

89 namespace=None, 

90 provider_credentials_secret_name=None, 

91 provider_type=None, 

92 provider_credentials_secret_namespace=None, 

93 client=None, 

94 teardown=True, 

95 vm_id=None, 

96 vm_name=None, 

97 cluster_id=None, 

98 cluster_name=None, 

99 target_vm_name=None, 

100 start_vm=False, 

101 provider_mappings=None, 

102 resource_mapping_name=None, 

103 resource_mapping_namespace=None, 

104 warm=False, 

105 finalize_date=None, 

106 yaml_file=None, 

107 delete_timeout=TIMEOUT_4MINUTES, 

108 **kwargs, 

109 ): 

110 super().__init__( 

111 name=name, 

112 namespace=namespace, 

113 client=client, 

114 teardown=teardown, 

115 yaml_file=yaml_file, 

116 delete_timeout=delete_timeout, 

117 **kwargs, 

118 ) 

119 self.vm_id = vm_id 

120 self.vm_name = vm_name 

121 self.cluster_id = cluster_id 

122 self.cluster_name = cluster_name 

123 self.target_vm_name = target_vm_name 

124 self.start_vm = start_vm 

125 self.provider_credentials_secret_name = provider_credentials_secret_name 

126 self.provider_credentials_secret_namespace = provider_credentials_secret_namespace 

127 self.provider_mappings = provider_mappings 

128 self.resource_mapping_name = resource_mapping_name 

129 self.resource_mapping_namespace = resource_mapping_namespace 

130 self.provider_type = provider_type 

131 self.warm = warm 

132 self.finalize_date = finalize_date 

133 

134 @property 

135 def vm(self): 

136 return VirtualMachine( 

137 name=self.target_vm_name, 

138 namespace=self.namespace, 

139 client=self.client, 

140 ) 

141 

142 def to_dict(self) -> None: 

143 super().to_dict() 

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

145 spec = self.res.setdefault("spec", {}) 

146 

147 secret = spec.setdefault("providerCredentialsSecret", {}) 

148 secret["name"] = self.provider_credentials_secret_name 

149 

150 if self.provider_credentials_secret_namespace: 

151 secret["namespace"] = self.provider_credentials_secret_namespace 

152 

153 if self.resource_mapping_name: 

154 spec.setdefault("resourceMapping", {})["name"] = self.resource_mapping_name 

155 if self.resource_mapping_namespace: 

156 spec.setdefault("resourceMapping", {})["namespace"] = self.resource_mapping_namespace 

157 

158 if self.target_vm_name: 

159 spec["targetVmName"] = self.target_vm_name 

160 

161 if self.start_vm is not None: 

162 spec["startVm"] = self.start_vm 

163 

164 if self.warm: 

165 spec["warm"] = self.warm 

166 if self.finalize_date: 

167 spec["finalizeDate"] = self.finalize_date.strftime(format="%Y-%m-%dT%H:%M:%SZ") 

168 

169 provider_source = spec.setdefault("source", {}).setdefault(self.provider_type, {}) 

170 vm = provider_source.setdefault("vm", {}) 

171 if self.vm_id: 

172 vm["id"] = self.vm_id 

173 if self.vm_name: 

174 vm["name"] = self.vm_name 

175 

176 if self.cluster_id: 

177 vm.setdefault("cluster", {})["id"] = self.cluster_id 

178 if self.cluster_name: 

179 vm.setdefault("cluster", {})["name"] = self.cluster_name 

180 

181 if self.provider_mappings: 

182 if self.provider_mappings.disk_mappings: 

183 mappings = _map_mappings(mappings=self.provider_mappings.disk_mappings) 

184 provider_source.setdefault("mappings", {}).setdefault("diskMappings", mappings) 

185 

186 if self.provider_mappings.network_mappings: 

187 mappings = _map_mappings(mappings=self.provider_mappings.network_mappings) 

188 provider_source.setdefault("mappings", {}).setdefault("networkMappings", mappings) 

189 

190 if self.provider_mappings.storage_mappings: 

191 mappings = _map_mappings(mappings=self.provider_mappings.storage_mappings) 

192 provider_source.setdefault("mappings", {}).setdefault("storageMappings", mappings) 

193 

194 def wait( 

195 self, 

196 timeout=600, 

197 cond_reason=SucceededConditionReason.VIRTUAL_MACHINE_READY, 

198 cond_status=Condition.Status.TRUE, 

199 cond_type=Condition.SUCCEEDED, 

200 ): 

201 self.logger.info(f"Wait for {self.kind} {self.name} {cond_reason} condition to be {cond_status}") 

202 samples = TimeoutSampler( 

203 wait_timeout=timeout, 

204 sleep=1, 

205 exceptions_dict=PROTOCOL_ERROR_EXCEPTION_DICT, 

206 func=self.api.get, 

207 field_selector=f"metadata.name=={self.name}", 

208 namespace=self.namespace, 

209 ) 

210 last_condition = None 

211 try: 

212 for sample in samples: 

213 if sample.items: 

214 sample_status = sample.items[0].status 

215 if sample_status: 

216 current_conditions = sample_status.conditions 

217 for cond in current_conditions: 

218 last_condition = cond 

219 if cond.type == cond_type and cond.status == cond_status and cond.reason == cond_reason: 

220 msg = ( 

221 f"Status of {self.kind} {self.name} {cond.type} is " 

222 f"{cond.status} ({cond.reason}: {cond.message})" 

223 ) 

224 self.logger.info(msg) 

225 return 

226 except TimeoutExpiredError: 

227 raise TimeoutExpiredError( 

228 f"Last condition of {self.kind} {self.name} {last_condition.type} was" 

229 f" {last_condition.status} ({last_condition.reason}:" 

230 f" {last_condition.message})" 

231 ) 

232 

233 

234class ResourceMapping(NamespacedResource): 

235 """ 

236 ResourceMapping object. 

237 """ 

238 

239 api_group = NamespacedResource.ApiGroup.V2V_KUBEVIRT_IO 

240 

241 def __init__( 

242 self, 

243 name=None, 

244 namespace=None, 

245 mapping=None, 

246 client=None, 

247 teardown=True, 

248 yaml_file=None, 

249 **kwargs, 

250 ): 

251 super().__init__( 

252 name=name, 

253 namespace=namespace, 

254 client=client, 

255 teardown=teardown, 

256 yaml_file=yaml_file, 

257 **kwargs, 

258 ) 

259 self.mapping = mapping 

260 

261 def to_dict(self) -> None: 

262 super().to_dict() 

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

264 for provider, mapping in self.mapping.items(): 

265 res_provider_section = self.res.setdefault("spec", {}).setdefault(provider, {}) 

266 if mapping.network_mappings is not None: 

267 res_provider_section.setdefault( 

268 "networkMappings", 

269 _map_mappings(mappings=mapping.network_mappings), 

270 ) 

271 if mapping.storage_mappings is not None: 

272 res_provider_section.setdefault( 

273 "storageMappings", 

274 _map_mappings(mappings=mapping.storage_mappings), 

275 )