Coverage for ocp_resources/pod.py: 34%

170 statements  

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

1# Generated using https://github.com/RedHatQE/openshift-python-wrapper/blob/main/scripts/resource/README.md 

2 

3import json 

4 

5from typing import Any, Dict, List, Optional 

6 

7import kubernetes 

8from timeout_sampler import TimeoutWatch 

9 

10from ocp_resources.utils.constants import TIMEOUT_5SEC 

11from ocp_resources.exceptions import ExecOnPodError 

12from ocp_resources.node import Node 

13 

14from ocp_resources.resource import NamespacedResource, MissingRequiredArgumentError 

15 

16 

17class Pod(NamespacedResource): 

18 """ 

19 Pod is a collection of containers that can run on a host. This resource is created by clients and scheduled onto hosts. 

20 """ 

21 

22 api_version: str = NamespacedResource.ApiVersion.V1 

23 

24 def __init__( 

25 self, 

26 active_deadline_seconds: Optional[int] = None, 

27 affinity: Optional[Dict[str, Any]] = None, 

28 automount_service_account_token: Optional[bool] = None, 

29 containers: Optional[List[Any]] = None, 

30 dns_config: Optional[Dict[str, Any]] = None, 

31 dns_policy: Optional[str] = "", 

32 enable_service_links: Optional[bool] = None, 

33 ephemeral_containers: Optional[List[Any]] = None, 

34 host_aliases: Optional[List[Any]] = None, 

35 host_ipc: Optional[bool] = None, 

36 host_network: Optional[bool] = None, 

37 host_pid: Optional[bool] = None, 

38 host_users: Optional[bool] = None, 

39 hostname: Optional[str] = "", 

40 image_pull_secrets: Optional[List[Any]] = None, 

41 init_containers: Optional[List[Any]] = None, 

42 node_name: Optional[str] = "", 

43 node_selector: Optional[Dict[str, Any]] = None, 

44 os: Optional[Dict[str, Any]] = None, 

45 overhead: Optional[Dict[str, Any]] = None, 

46 preemption_policy: Optional[str] = "", 

47 priority: Optional[int] = None, 

48 priority_class_name: Optional[str] = "", 

49 readiness_gates: Optional[List[Any]] = None, 

50 resource_claims: Optional[List[Any]] = None, 

51 restart_policy: Optional[str] = "", 

52 runtime_class_name: Optional[str] = "", 

53 scheduler_name: Optional[str] = "", 

54 scheduling_gates: Optional[List[Any]] = None, 

55 security_context: Optional[Dict[str, Any]] = None, 

56 service_account: Optional[str] = "", 

57 service_account_name: Optional[str] = "", 

58 set_hostname_as_fqdn: Optional[bool] = None, 

59 share_process_namespace: Optional[bool] = None, 

60 subdomain: Optional[str] = "", 

61 termination_grace_period_seconds: Optional[int] = None, 

62 tolerations: Optional[List[Any]] = None, 

63 topology_spread_constraints: Optional[List[Any]] = None, 

64 volumes: Optional[List[Any]] = None, 

65 **kwargs: Any, 

66 ) -> None: 

67 """ 

68 Args: 

69 active_deadline_seconds (int): Optional duration in seconds the pod may be active on the node 

70 relative to StartTime before the system will actively try to mark 

71 it failed and kill associated containers. Value must be a positive 

72 integer. 

73 

74 affinity (Dict[str, Any]): Affinity is a group of affinity scheduling rules. 

75 

76 automount_service_account_token (bool): AutomountServiceAccountToken indicates whether a service account token 

77 should be automatically mounted. 

78 

79 containers (List[Any]): List of containers belonging to the pod. Containers cannot currently 

80 be added or removed. There must be at least one container in a 

81 Pod. Cannot be updated. 

82 

83 dns_config (Dict[str, Any]): PodDNSConfig defines the DNS parameters of a pod in addition to those 

84 generated from DNSPolicy. 

85 

86 dns_policy (str): Set DNS policy for the pod. Defaults to "ClusterFirst". Valid values 

87 are 'ClusterFirstWithHostNet', 'ClusterFirst', 'Default' or 

88 'None'. DNS parameters given in DNSConfig will be merged with the 

89 policy selected with DNSPolicy. To have DNS options set along with 

90 hostNetwork, you have to specify DNS policy explicitly to 

91 'ClusterFirstWithHostNet'. Possible enum values: - 

92 `"ClusterFirst"` indicates that the pod should use cluster DNS 

93 first unless hostNetwork is true, if it is available, then fall 

94 back on the default (as determined by kubelet) DNS settings. - 

95 `"ClusterFirstWithHostNet"` indicates that the pod should use 

96 cluster DNS first, if it is available, then fall back on the 

97 default (as determined by kubelet) DNS settings. - `"Default"` 

98 indicates that the pod should use the default (as determined by 

99 kubelet) DNS settings. - `"None"` indicates that the pod should 

100 use empty DNS settings. DNS parameters such as nameservers and 

101 search paths should be defined via DNSConfig. 

102 

103 enable_service_links (bool): EnableServiceLinks indicates whether information about services should 

104 be injected into pod's environment variables, matching the syntax 

105 of Docker links. Optional: Defaults to true. 

106 

107 ephemeral_containers (List[Any]): List of ephemeral containers run in this pod. Ephemeral containers may 

108 be run in an existing pod to perform user-initiated actions such 

109 as debugging. This list cannot be specified when creating a pod, 

110 and it cannot be modified by updating the pod spec. In order to 

111 add an ephemeral container to an existing pod, use the pod's 

112 ephemeralcontainers subresource. 

113 

114 host_aliases (List[Any]): HostAliases is an optional list of hosts and IPs that will be injected 

115 into the pod's hosts file if specified. 

116 

117 host_ipc (bool): Use the host's ipc namespace. Optional: Default to false. 

118 

119 host_network (bool): Host networking requested for this pod. Use the host's network 

120 namespace. If this option is set, the ports that will be used must 

121 be specified. Default to false. 

122 

123 host_pid (bool): Use the host's pid namespace. Optional: Default to false. 

124 

125 host_users (bool): Use the host's user namespace. Optional: Default to true. If set to 

126 true or not present, the pod will be run in the host user 

127 namespace, useful for when the pod needs a feature only available 

128 to the host user namespace, such as loading a kernel module with 

129 CAP_SYS_MODULE. When set to false, a new userns is created for the 

130 pod. Setting false is useful for mitigating container breakout 

131 vulnerabilities even allowing users to run their containers as 

132 root without actually having root privileges on the host. This 

133 field is alpha-level and is only honored by servers that enable 

134 the UserNamespacesSupport feature. 

135 

136 hostname (str): Specifies the hostname of the Pod If not specified, the pod's hostname 

137 will be set to a system-defined value. 

138 

139 image_pull_secrets (List[Any]): ImagePullSecrets is an optional list of references to secrets in the 

140 same namespace to use for pulling any of the images used by this 

141 PodSpec. If specified, these secrets will be passed to individual 

142 puller implementations for them to use. More info: 

143 https://kubernetes.io/docs/concepts/containers/images#specifying- 

144 imagepullsecrets-on-a-pod 

145 

146 init_containers (List[Any]): List of initialization containers belonging to the pod. Init 

147 containers are executed in order prior to containers being 

148 started. If any init container fails, the pod is considered to 

149 have failed and is handled according to its restartPolicy. The 

150 name for an init container or normal container must be unique 

151 among all containers. Init containers may not have Lifecycle 

152 actions, Readiness probes, Liveness probes, or Startup probes. The 

153 resourceRequirements of an init container are taken into account 

154 during scheduling by finding the highest request/limit for each 

155 resource type, and then using the max of of that value or the sum 

156 of the normal containers. Limits are applied to init containers in 

157 a similar fashion. Init containers cannot currently be added or 

158 removed. Cannot be updated. More info: 

159 https://kubernetes.io/docs/concepts/workloads/pods/init- 

160 containers/ 

161 

162 node_name (str): NodeName is a request to schedule this pod onto a specific node. If it 

163 is non-empty, the scheduler simply schedules this pod onto that 

164 node, assuming that it fits resource requirements. 

165 

166 node_selector (Dict[str, Any]): NodeSelector is a selector which must be true for the pod to fit on a 

167 node. Selector which must match a node's labels for the pod to be 

168 scheduled on that node. More info: 

169 https://kubernetes.io/docs/concepts/configuration/assign-pod-node/ 

170 

171 os (Dict[str, Any]): PodOS defines the OS parameters of a pod. 

172 

173 overhead (Dict[str, Any]): Overhead represents the resource overhead associated with running a 

174 pod for a given RuntimeClass. This field will be autopopulated at 

175 admission time by the RuntimeClass admission controller. If the 

176 RuntimeClass admission controller is enabled, overhead must not be 

177 set in Pod create requests. The RuntimeClass admission controller 

178 will reject Pod create requests which have the overhead already 

179 set. If RuntimeClass is configured and selected in the PodSpec, 

180 Overhead will be set to the value defined in the corresponding 

181 RuntimeClass, otherwise it will remain unset and treated as zero. 

182 More info: https://git.k8s.io/enhancements/keps/sig-node/688-pod- 

183 overhead/README.md 

184 

185 preemption_policy (str): PreemptionPolicy is the Policy for preempting pods with lower 

186 priority. One of Never, PreemptLowerPriority. Defaults to 

187 PreemptLowerPriority if unset. Possible enum values: - `"Never"` 

188 means that pod never preempts other pods with lower priority. - 

189 `"PreemptLowerPriority"` means that pod can preempt other pods 

190 with lower priority. 

191 

192 priority (int): The priority value. Various system components use this field to find 

193 the priority of the pod. When Priority Admission Controller is 

194 enabled, it prevents users from setting this field. The admission 

195 controller populates this field from PriorityClassName. The higher 

196 the value, the higher the priority. 

197 

198 priority_class_name (str): If specified, indicates the pod's priority. "system-node-critical" and 

199 "system-cluster-critical" are two special keywords which indicate 

200 the highest priorities with the former being the highest priority. 

201 Any other name must be defined by creating a PriorityClass object 

202 with that name. If not specified, the pod priority will be default 

203 or zero if there is no default. 

204 

205 readiness_gates (List[Any]): If specified, all readiness gates will be evaluated for pod readiness. 

206 A pod is ready when all its containers are ready AND all 

207 conditions specified in the readiness gates have status equal to 

208 "True" More info: https://git.k8s.io/enhancements/keps/sig- 

209 network/580-pod-readiness-gates 

210 

211 resource_claims (List[Any]): ResourceClaims defines which ResourceClaims must be allocated and 

212 reserved before the Pod is allowed to start. The resources will be 

213 made available to those containers which consume them by name. 

214 This is an alpha field and requires enabling the 

215 DynamicResourceAllocation feature gate. This field is immutable. 

216 

217 restart_policy (str): Restart policy for all containers within the pod. One of Always, 

218 OnFailure, Never. In some contexts, only a subset of those values 

219 may be permitted. Default to Always. More info: 

220 https://kubernetes.io/docs/concepts/workloads/pods/pod- 

221 lifecycle/#restart-policy Possible enum values: - `"Always"` - 

222 `"Never"` - `"OnFailure"` 

223 

224 runtime_class_name (str): RuntimeClassName refers to a RuntimeClass object in the node.k8s.io 

225 group, which should be used to run this pod. If no RuntimeClass 

226 resource matches the named class, the pod will not be run. If 

227 unset or empty, the "legacy" RuntimeClass will be used, which is 

228 an implicit class with an empty definition that uses the default 

229 runtime handler. More info: 

230 https://git.k8s.io/enhancements/keps/sig-node/585-runtime-class 

231 

232 scheduler_name (str): If specified, the pod will be dispatched by specified scheduler. If 

233 not specified, the pod will be dispatched by default scheduler. 

234 

235 scheduling_gates (List[Any]): SchedulingGates is an opaque list of values that if specified will 

236 block scheduling the pod. If schedulingGates is not empty, the pod 

237 will stay in the SchedulingGated state and the scheduler will not 

238 attempt to schedule the pod. SchedulingGates can only be set at 

239 pod creation time, and be removed only afterwards. 

240 

241 security_context (Dict[str, Any]): PodSecurityContext holds pod-level security attributes and common 

242 container settings. Some fields are also present in 

243 container.securityContext. Field values of 

244 container.securityContext take precedence over field values of 

245 PodSecurityContext. 

246 

247 service_account (str): DeprecatedServiceAccount is a deprecated alias for ServiceAccountName. 

248 Deprecated: Use serviceAccountName instead. 

249 

250 service_account_name (str): ServiceAccountName is the name of the ServiceAccount to use to run 

251 this pod. More info: https://kubernetes.io/docs/tasks/configure- 

252 pod-container/configure-service-account/ 

253 

254 set_hostname_as_fqdn (bool): If true the pod's hostname will be configured as the pod's FQDN, 

255 rather than the leaf name (the default). In Linux containers, this 

256 means setting the FQDN in the hostname field of the kernel (the 

257 nodename field of struct utsname). In Windows containers, this 

258 means setting the registry value of hostname for the registry key 

259 HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\Tcpip\Paramet 

260 ers to FQDN. If a pod does not have FQDN, this has no effect. 

261 Default to false. 

262 

263 share_process_namespace (bool): Share a single process namespace between all of the containers in a 

264 pod. When this is set containers will be able to view and signal 

265 processes from other containers in the same pod, and the first 

266 process in each container will not be assigned PID 1. HostPID and 

267 ShareProcessNamespace cannot both be set. Optional: Default to 

268 false. 

269 

270 subdomain (str): If specified, the fully qualified Pod hostname will be 

271 "<hostname>.<subdomain>.<pod namespace>.svc.<cluster domain>". If 

272 not specified, the pod will not have a domainname at all. 

273 

274 termination_grace_period_seconds (int): Optional duration in seconds the pod needs to terminate gracefully. 

275 May be decreased in delete request. Value must be non-negative 

276 integer. The value zero indicates stop immediately via the kill 

277 signal (no opportunity to shut down). If this value is nil, the 

278 default grace period will be used instead. The grace period is the 

279 duration in seconds after the processes running in the pod are 

280 sent a termination signal and the time when the processes are 

281 forcibly halted with a kill signal. Set this value longer than the 

282 expected cleanup time for your process. Defaults to 30 seconds. 

283 

284 tolerations (List[Any]): If specified, the pod's tolerations. 

285 

286 topology_spread_constraints (List[Any]): TopologySpreadConstraints describes how a group of pods ought to 

287 spread across topology domains. Scheduler will schedule pods in a 

288 way which abides by the constraints. All topologySpreadConstraints 

289 are ANDed. 

290 

291 volumes (List[Any]): List of volumes that can be mounted by containers belonging to the 

292 pod. More info: 

293 https://kubernetes.io/docs/concepts/storage/volumes 

294 

295 """ 

296 super().__init__(**kwargs) 

297 

298 self.active_deadline_seconds = active_deadline_seconds 

299 self.affinity = affinity 

300 self.automount_service_account_token = automount_service_account_token 

301 self.containers = containers 

302 self.dns_config = dns_config 

303 self.dns_policy = dns_policy 

304 self.enable_service_links = enable_service_links 

305 self.ephemeral_containers = ephemeral_containers 

306 self.host_aliases = host_aliases 

307 self.host_ipc = host_ipc 

308 self.host_network = host_network 

309 self.host_pid = host_pid 

310 self.host_users = host_users 

311 self.hostname = hostname 

312 self.image_pull_secrets = image_pull_secrets 

313 self.init_containers = init_containers 

314 self.node_name = node_name 

315 self.node_selector = node_selector 

316 self.os = os 

317 self.overhead = overhead 

318 self.preemption_policy = preemption_policy 

319 self.priority = priority 

320 self.priority_class_name = priority_class_name 

321 self.readiness_gates = readiness_gates 

322 self.resource_claims = resource_claims 

323 self.restart_policy = restart_policy 

324 self.runtime_class_name = runtime_class_name 

325 self.scheduler_name = scheduler_name 

326 self.scheduling_gates = scheduling_gates 

327 self.security_context = security_context 

328 self.service_account = service_account 

329 self.service_account_name = service_account_name 

330 self.set_hostname_as_fqdn = set_hostname_as_fqdn 

331 self.share_process_namespace = share_process_namespace 

332 self.subdomain = subdomain 

333 self.termination_grace_period_seconds = termination_grace_period_seconds 

334 self.tolerations = tolerations 

335 self.topology_spread_constraints = topology_spread_constraints 

336 self.volumes = volumes 

337 

338 def to_dict(self) -> None: 

339 super().to_dict() 

340 

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

342 if not self.containers: 

343 raise MissingRequiredArgumentError(argument="self.containers") 

344 

345 self.res["spec"] = {} 

346 _spec = self.res["spec"] 

347 

348 _spec["containers"] = self.containers 

349 

350 if self.active_deadline_seconds: 

351 _spec["activeDeadlineSeconds"] = self.active_deadline_seconds 

352 

353 if self.affinity: 

354 _spec["affinity"] = self.affinity 

355 

356 if self.automount_service_account_token is not None: 

357 _spec["automountServiceAccountToken"] = self.automount_service_account_token 

358 

359 if self.dns_config: 

360 _spec["dnsConfig"] = self.dns_config 

361 

362 if self.dns_policy: 

363 _spec["dnsPolicy"] = self.dns_policy 

364 

365 if self.enable_service_links is not None: 

366 _spec["enableServiceLinks"] = self.enable_service_links 

367 

368 if self.ephemeral_containers: 

369 _spec["ephemeralContainers"] = self.ephemeral_containers 

370 

371 if self.host_aliases: 

372 _spec["hostAliases"] = self.host_aliases 

373 

374 if self.host_ipc is not None: 

375 _spec["hostIPC"] = self.host_ipc 

376 

377 if self.host_network is not None: 

378 _spec["hostNetwork"] = self.host_network 

379 

380 if self.host_pid is not None: 

381 _spec["hostPID"] = self.host_pid 

382 

383 if self.host_users is not None: 

384 _spec["hostUsers"] = self.host_users 

385 

386 if self.hostname: 

387 _spec["hostname"] = self.hostname 

388 

389 if self.image_pull_secrets: 

390 _spec["imagePullSecrets"] = self.image_pull_secrets 

391 

392 if self.init_containers: 

393 _spec["initContainers"] = self.init_containers 

394 

395 if self.node_name: 

396 _spec["nodeName"] = self.node_name 

397 

398 if self.node_selector: 

399 _spec["nodeSelector"] = self.node_selector 

400 

401 if self.os: 

402 _spec["os"] = self.os 

403 

404 if self.overhead: 

405 _spec["overhead"] = self.overhead 

406 

407 if self.preemption_policy: 

408 _spec["preemptionPolicy"] = self.preemption_policy 

409 

410 if self.priority: 

411 _spec["priority"] = self.priority 

412 

413 if self.priority_class_name: 

414 _spec["priorityClassName"] = self.priority_class_name 

415 

416 if self.readiness_gates: 

417 _spec["readinessGates"] = self.readiness_gates 

418 

419 if self.resource_claims: 

420 _spec["resourceClaims"] = self.resource_claims 

421 

422 if self.restart_policy: 

423 _spec["restartPolicy"] = self.restart_policy 

424 

425 if self.runtime_class_name: 

426 _spec["runtimeClassName"] = self.runtime_class_name 

427 

428 if self.scheduler_name: 

429 _spec["schedulerName"] = self.scheduler_name 

430 

431 if self.scheduling_gates: 

432 _spec["schedulingGates"] = self.scheduling_gates 

433 

434 if self.security_context: 

435 _spec["securityContext"] = self.security_context 

436 

437 if self.service_account: 

438 _spec["serviceAccount"] = self.service_account 

439 

440 if self.service_account_name: 

441 _spec["serviceAccountName"] = self.service_account_name 

442 

443 if self.set_hostname_as_fqdn is not None: 

444 _spec["setHostnameAsFQDN"] = self.set_hostname_as_fqdn 

445 

446 if self.share_process_namespace is not None: 

447 _spec["shareProcessNamespace"] = self.share_process_namespace 

448 

449 if self.subdomain: 

450 _spec["subdomain"] = self.subdomain 

451 

452 if self.termination_grace_period_seconds: 

453 _spec["terminationGracePeriodSeconds"] = self.termination_grace_period_seconds 

454 

455 if self.tolerations: 

456 _spec["tolerations"] = self.tolerations 

457 

458 if self.topology_spread_constraints: 

459 _spec["topologySpreadConstraints"] = self.topology_spread_constraints 

460 

461 if self.volumes: 

462 _spec["volumes"] = self.volumes 

463 

464 # End of generated code 

465 

466 def execute(self, command: List[str], timeout: int = 60, container: str = "", ignore_rc: bool = False) -> str: 

467 """ 

468 Run command on Pod 

469 

470 Args: 

471 command (list): Command to run. 

472 timeout (int): Time to wait for the command. 

473 container (str): Container name where to exec the command. 

474 ignore_rc (bool): If True ignore error rc from the shell and return out. 

475 

476 Returns: 

477 str: Command output. 

478 

479 Raises: 

480 ExecOnPodError: If the command failed. 

481 """ 

482 error_channel: Dict[Any, Any] = {} 

483 stream_closed_error: str = "stream resp is closed" 

484 self.logger.info(f"Execute {command} on {self.name} ({self.node.name})") 

485 resp = kubernetes.stream.stream( 

486 api_method=self._kube_v1_api.connect_get_namespaced_pod_exec, 

487 name=self.name, 

488 namespace=self.namespace, 

489 command=command, 

490 container=container or self.instance.spec.containers[0].name, 

491 stderr=True, 

492 stdin=False, 

493 stdout=True, 

494 tty=False, 

495 _preload_content=False, 

496 ) 

497 

498 timeout_watch = TimeoutWatch(timeout=timeout) 

499 while resp.is_open(): 

500 resp.run_forever(timeout=2) 

501 try: 

502 error_channel = json.loads(resp.read_channel(kubernetes.stream.ws_client.ERROR_CHANNEL)) 

503 break 

504 except json.decoder.JSONDecodeError: 

505 # Check remaining time, in order to throw exception 

506 # if remaining time reached zero 

507 if timeout_watch.remaining_time() <= 0: 

508 raise ExecOnPodError(command=command, rc=-1, out="", err=stream_closed_error) 

509 

510 rcstring = error_channel.get("status") 

511 if rcstring is None: 

512 raise ExecOnPodError(command=command, rc=-1, out="", err=stream_closed_error) 

513 

514 stdout = resp.read_stdout(timeout=TIMEOUT_5SEC) 

515 stderr = resp.read_stderr(timeout=TIMEOUT_5SEC) 

516 

517 if rcstring == "Success" or ignore_rc: 

518 return stdout 

519 

520 if rcstring == "Failure": 

521 raise ExecOnPodError(command=command, rc=-1, out="", err=error_channel) 

522 

523 returncode = [ 

524 int(cause["message"]) for cause in error_channel["details"]["causes"] if cause["reason"] == "ExitCode" 

525 ][0] 

526 

527 raise ExecOnPodError(command=command, rc=returncode, out=stdout, err=stderr) 

528 

529 def log(self, **kwargs: Any) -> str: 

530 """ 

531 Get Pod logs 

532 

533 Returns: 

534 str: Pod logs. 

535 """ 

536 return self._kube_v1_api.read_namespaced_pod_log(name=self.name, namespace=self.namespace, **kwargs) 

537 

538 @property 

539 def node(self) -> Node: 

540 """ 

541 Get the node name where the Pod is running 

542 

543 Returns: 

544 Node: Node 

545 """ 

546 node_name = self.instance.spec.nodeName 

547 assert node_name, f"Node not found for pod {self.name}" 

548 return Node( 

549 client=self.client, 

550 name=node_name, 

551 ) 

552 

553 @property 

554 def ip(self) -> str: 

555 return self.instance.status.podIP