openshift-python-wrapper 4.11.61__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (132) hide show
  1. ocp_resources/__init__.py +0 -0
  2. ocp_resources/api_service.py +9 -0
  3. ocp_resources/backup.py +52 -0
  4. ocp_resources/benchmark.py +92 -0
  5. ocp_resources/catalog_source.py +63 -0
  6. ocp_resources/catalog_source_config.py +86 -0
  7. ocp_resources/cdi.py +13 -0
  8. ocp_resources/cdi_config.py +52 -0
  9. ocp_resources/chaos_engine.py +30 -0
  10. ocp_resources/chaos_result.py +11 -0
  11. ocp_resources/cluster_operator.py +5 -0
  12. ocp_resources/cluster_role.py +70 -0
  13. ocp_resources/cluster_role_binding.py +36 -0
  14. ocp_resources/cluster_service_version.py +8 -0
  15. ocp_resources/cluster_version.py +5 -0
  16. ocp_resources/configmap.py +37 -0
  17. ocp_resources/console_cli_download.py +9 -0
  18. ocp_resources/console_plugin.py +9 -0
  19. ocp_resources/console_quick_start.py +9 -0
  20. ocp_resources/constants.py +26 -0
  21. ocp_resources/csidriver.py +9 -0
  22. ocp_resources/custom_resource_definition.py +5 -0
  23. ocp_resources/daemonset.py +61 -0
  24. ocp_resources/data_import_cron.py +100 -0
  25. ocp_resources/data_source.py +59 -0
  26. ocp_resources/datavolume.py +275 -0
  27. ocp_resources/deployment.py +65 -0
  28. ocp_resources/destination_rule.py +11 -0
  29. ocp_resources/event.py +114 -0
  30. ocp_resources/forklift_controller.py +10 -0
  31. ocp_resources/gateway.py +11 -0
  32. ocp_resources/hook.py +52 -0
  33. ocp_resources/host.py +64 -0
  34. ocp_resources/hostpath_provisioner.py +50 -0
  35. ocp_resources/hyperconverged.py +43 -0
  36. ocp_resources/image.py +9 -0
  37. ocp_resources/image_content_source_policy.py +9 -0
  38. ocp_resources/image_stream.py +48 -0
  39. ocp_resources/imagestreamtag.py +9 -0
  40. ocp_resources/infrastructure.py +18 -0
  41. ocp_resources/installplan.py +8 -0
  42. ocp_resources/job.py +65 -0
  43. ocp_resources/kube_descheduler.py +65 -0
  44. ocp_resources/kubevirt.py +5 -0
  45. ocp_resources/kubevirt_common_templates_bundle.py +5 -0
  46. ocp_resources/kubevirt_metrics_aggregation.py +5 -0
  47. ocp_resources/kubevirt_node_labeller_bundle.py +5 -0
  48. ocp_resources/kubevirt_template_validaotr.py +5 -0
  49. ocp_resources/logger.py +76 -0
  50. ocp_resources/machine.py +50 -0
  51. ocp_resources/machine_config.py +5 -0
  52. ocp_resources/machine_config_pool.py +9 -0
  53. ocp_resources/machine_health_check.py +76 -0
  54. ocp_resources/machine_set.py +189 -0
  55. ocp_resources/migration.py +63 -0
  56. ocp_resources/migration_policy.py +66 -0
  57. ocp_resources/mtv.py +171 -0
  58. ocp_resources/mutating_webhook_config.py +9 -0
  59. ocp_resources/namespace.py +40 -0
  60. ocp_resources/network.py +5 -0
  61. ocp_resources/network_addons_config.py +9 -0
  62. ocp_resources/network_attachment_definition.py +24 -0
  63. ocp_resources/network_map.py +64 -0
  64. ocp_resources/network_policy.py +9 -0
  65. ocp_resources/nmstate.py +9 -0
  66. ocp_resources/node.py +41 -0
  67. ocp_resources/node_health_check.py +10 -0
  68. ocp_resources/node_maintenance.py +40 -0
  69. ocp_resources/node_network_configuration_enactment.py +20 -0
  70. ocp_resources/node_network_configuration_policy.py +472 -0
  71. ocp_resources/node_network_state.py +121 -0
  72. ocp_resources/oauth.py +9 -0
  73. ocp_resources/operator_condition.py +5 -0
  74. ocp_resources/operator_group.py +37 -0
  75. ocp_resources/operator_hub.py +5 -0
  76. ocp_resources/operator_source.py +50 -0
  77. ocp_resources/package_manifest.py +5 -0
  78. ocp_resources/peer_authentication.py +18 -0
  79. ocp_resources/persistent_volume.py +27 -0
  80. ocp_resources/persistent_volume_claim.py +103 -0
  81. ocp_resources/plan.py +143 -0
  82. ocp_resources/pod.py +175 -0
  83. ocp_resources/pod_disruption_budget.py +53 -0
  84. ocp_resources/priority_class.py +48 -0
  85. ocp_resources/project.py +60 -0
  86. ocp_resources/prometheus.py +9 -0
  87. ocp_resources/prometheus_rule.py +9 -0
  88. ocp_resources/provider.py +59 -0
  89. ocp_resources/replicaset.py +11 -0
  90. ocp_resources/resource.py +1383 -0
  91. ocp_resources/restore.py +52 -0
  92. ocp_resources/role.py +11 -0
  93. ocp_resources/role_binding.py +67 -0
  94. ocp_resources/route.py +76 -0
  95. ocp_resources/secret.py +75 -0
  96. ocp_resources/security_context_constraints.py +9 -0
  97. ocp_resources/service.py +16 -0
  98. ocp_resources/service_account.py +9 -0
  99. ocp_resources/service_mesh_control_plane.py +11 -0
  100. ocp_resources/service_mesh_member_roll.py +14 -0
  101. ocp_resources/service_monitor.py +9 -0
  102. ocp_resources/sriov_network.py +54 -0
  103. ocp_resources/sriov_network_node_policy.py +67 -0
  104. ocp_resources/sriov_network_node_state.py +44 -0
  105. ocp_resources/ssp.py +9 -0
  106. ocp_resources/storage_class.py +47 -0
  107. ocp_resources/storage_map.py +67 -0
  108. ocp_resources/storage_profile.py +7 -0
  109. ocp_resources/subscription.py +66 -0
  110. ocp_resources/tekton_tasks.py +9 -0
  111. ocp_resources/template.py +74 -0
  112. ocp_resources/upload_token_request.py +39 -0
  113. ocp_resources/utils.py +278 -0
  114. ocp_resources/validating_webhook_config.py +9 -0
  115. ocp_resources/virtual_machine.py +177 -0
  116. ocp_resources/virtual_machine_Instance_replica_set.py +9 -0
  117. ocp_resources/virtual_machine_cluster_flavor.py +5 -0
  118. ocp_resources/virtual_machine_flavor.py +5 -0
  119. ocp_resources/virtual_machine_import.py +307 -0
  120. ocp_resources/virtual_machine_instance.py +322 -0
  121. ocp_resources/virtual_machine_instance_migration.py +36 -0
  122. ocp_resources/virtual_machine_instance_preset.py +9 -0
  123. ocp_resources/virtual_machine_restore.py +99 -0
  124. ocp_resources/virtual_machine_snapshot.py +96 -0
  125. ocp_resources/virtual_service.py +11 -0
  126. ocp_resources/vm_import_config.py +9 -0
  127. ocp_resources/volume_snapshot.py +9 -0
  128. ocp_resources/volume_snapshot_class.py +9 -0
  129. openshift_python_wrapper-4.11.61.dist-info/LICENSE +201 -0
  130. openshift_python_wrapper-4.11.61.dist-info/METADATA +188 -0
  131. openshift_python_wrapper-4.11.61.dist-info/RECORD +132 -0
  132. openshift_python_wrapper-4.11.61.dist-info/WHEEL +4 -0
@@ -0,0 +1,66 @@
1
+ from ocp_resources.constants import TIMEOUT_4MINUTES
2
+ from ocp_resources.resource import NamespacedResource
3
+
4
+
5
+ class Subscription(NamespacedResource):
6
+ api_group = NamespacedResource.ApiGroup.OPERATORS_COREOS_COM
7
+
8
+ def __init__(
9
+ self,
10
+ name=None,
11
+ namespace=None,
12
+ client=None,
13
+ source=None,
14
+ source_namespace=None,
15
+ install_plan_approval=None,
16
+ channel=None,
17
+ starting_csv=None,
18
+ node_selector=None,
19
+ tolerations=None,
20
+ teardown=True,
21
+ yaml_file=None,
22
+ delete_timeout=TIMEOUT_4MINUTES,
23
+ **kwargs,
24
+ ):
25
+ super().__init__(
26
+ client=client,
27
+ name=name,
28
+ namespace=namespace,
29
+ teardown=teardown,
30
+ yaml_file=yaml_file,
31
+ delete_timeout=delete_timeout,
32
+ **kwargs,
33
+ )
34
+ self.source = source
35
+ self.source_namespace = source_namespace
36
+ self.channel = channel
37
+ self.install_plan_approval = install_plan_approval
38
+ self.starting_csv = starting_csv
39
+ self.node_selector = node_selector
40
+ self.tolerations = tolerations
41
+
42
+ def to_dict(self):
43
+ super().to_dict()
44
+ if not self.yaml_file:
45
+ self.res.update(
46
+ {
47
+ "spec": {
48
+ "sourceNamespace": self.source_namespace,
49
+ "source": self.source,
50
+ "name": self.name,
51
+ "channel": self.channel,
52
+ "installPlanApproval": self.install_plan_approval,
53
+ "startingCSV": self.starting_csv,
54
+ }
55
+ }
56
+ )
57
+
58
+ if self.node_selector:
59
+ self.res["spec"].setdefault("config", {}).setdefault(
60
+ "nodeSelector", {}
61
+ ).update(self.node_selector)
62
+
63
+ if self.tolerations:
64
+ self.res["spec"].setdefault("config", {}).setdefault(
65
+ "tolerations", []
66
+ ).append(self.tolerations)
@@ -0,0 +1,9 @@
1
+ from ocp_resources.resource import NamespacedResource
2
+
3
+
4
+ class TektonTasks(NamespacedResource):
5
+ """
6
+ TektonTasks object, inherited from NamespacedResource.
7
+ """
8
+
9
+ api_group = NamespacedResource.ApiGroup.TEKTONTASKS_KUBEVIRT_IO
@@ -0,0 +1,74 @@
1
+ import json
2
+
3
+ from ocp_resources.resource import NamespacedResource, Resource
4
+
5
+
6
+ class Template(NamespacedResource):
7
+ api_group = NamespacedResource.ApiGroup.TEMPLATE_OPENSHIFT_IO
8
+ singular_name = "template"
9
+
10
+ class Labels:
11
+ BASE = f"{NamespacedResource.ApiGroup.TEMPLATE_KUBEVIRT_IO}/type=base"
12
+ FLAVOR = "flavor.template.kubevirt.io"
13
+ OS = "os.template.kubevirt.io"
14
+ WORKLOAD = "workload.template.kubevirt.io"
15
+
16
+ class Workload:
17
+ DESKTOP = "desktop"
18
+ HIGHPERFORMANCE = "highperformance"
19
+ SERVER = "server"
20
+ SAPHANA = "saphana"
21
+
22
+ class Flavor:
23
+ LARGE = "large"
24
+ MEDIUM = "medium"
25
+ SMALL = "small"
26
+ TINY = "tiny"
27
+
28
+ class Annotations:
29
+ DEPRECATED = f"{NamespacedResource.ApiGroup.TEMPLATE_KUBEVIRT_IO}/deprecated"
30
+ PROVIDER = f"{NamespacedResource.ApiGroup.TEMPLATE_KUBEVIRT_IO}/provider"
31
+ PROVIDER_SUPPORT_LEVEL = (
32
+ f"{NamespacedResource.ApiGroup.TEMPLATE_KUBEVIRT_IO}/provider-support-level"
33
+ )
34
+ PROVIDER_URL = (
35
+ f"{NamespacedResource.ApiGroup.TEMPLATE_KUBEVIRT_IO}/provider-url"
36
+ )
37
+
38
+ class VMAnnotations:
39
+ OS = f"{Resource.ApiGroup.VM_KUBEVIRT_IO}/os"
40
+ FLAVOR = f"{Resource.ApiGroup.VM_KUBEVIRT_IO}/flavor"
41
+ WORKLOAD = f"{Resource.ApiGroup.VM_KUBEVIRT_IO}/workload"
42
+
43
+ def process(self, client=None, **kwargs):
44
+ client = client or self.client
45
+ instance_dict = self.instance.to_dict()
46
+ params = instance_dict["parameters"]
47
+ # filling the template parameters with given kwargs
48
+ for param in params:
49
+ try:
50
+ param["value"] = kwargs[param["name"]]
51
+ except KeyError:
52
+ continue
53
+ instance_dict["parameters"] = params
54
+ # TODO: remove after fix - https://issues.redhat.com/browse/KNIP-1055 (bug 1753554)
55
+ # For template validator to be used - template namespace needs to be updated
56
+ instance_dict["objects"][0]["metadata"]["labels"][
57
+ "vm.kubevirt.io/template.namespace"
58
+ ] = instance_dict["metadata"]["namespace"]
59
+ instance_json = json.dumps(instance_dict)
60
+ body = json.loads(instance_json)
61
+ response = client.request(
62
+ method="Post",
63
+ path=f"/apis/{self.api_version}/namespaces/openshift/processedtemplates",
64
+ body=body,
65
+ )
66
+ return response.to_dict()["objects"]
67
+
68
+ @staticmethod
69
+ def generate_template_labels(os, workload, flavor):
70
+ return [
71
+ f"{Template.Labels.OS}/{os}",
72
+ f"{Template.Labels.WORKLOAD}/{getattr(Template.Workload, workload.upper())}",
73
+ f"{Template.Labels.FLAVOR}/{getattr(Template.Flavor, flavor.upper())}",
74
+ ]
@@ -0,0 +1,39 @@
1
+ # -*- coding: utf-8 -*-
2
+
3
+ from ocp_resources.constants import TIMEOUT_4MINUTES
4
+ from ocp_resources.resource import NamespacedResource
5
+
6
+
7
+ class UploadTokenRequest(NamespacedResource):
8
+ """
9
+ OpenShift UploadTokenRequest object.
10
+ """
11
+
12
+ api_group = NamespacedResource.ApiGroup.UPLOAD_CDI_KUBEVIRT_IO
13
+
14
+ def __init__(
15
+ self,
16
+ name=None,
17
+ namespace=None,
18
+ client=None,
19
+ pvc_name=None,
20
+ teardown=True,
21
+ yaml_file=None,
22
+ delete_timeout=TIMEOUT_4MINUTES,
23
+ **kwargs,
24
+ ):
25
+ super().__init__(
26
+ name=name,
27
+ namespace=namespace,
28
+ client=client,
29
+ teardown=teardown,
30
+ yaml_file=yaml_file,
31
+ delete_timeout=delete_timeout,
32
+ **kwargs,
33
+ )
34
+ self.pvc_name = pvc_name
35
+
36
+ def to_dict(self):
37
+ super().to_dict()
38
+ if not self.yaml_file:
39
+ self.res.update({"spec": {"pvcName": self.pvc_name}})
ocp_resources/utils.py ADDED
@@ -0,0 +1,278 @@
1
+ import time
2
+
3
+ import yaml
4
+
5
+ from ocp_resources.logger import get_logger
6
+
7
+
8
+ LOGGER = get_logger(name=__name__)
9
+
10
+
11
+ class TimeoutExpiredError(Exception):
12
+ def __init__(self, value):
13
+ super().__init__()
14
+ self.value = value
15
+
16
+ def __str__(self):
17
+ return f"Timed Out: {self.value}"
18
+
19
+
20
+ class TimeoutSampler:
21
+ """
22
+ Samples the function output.
23
+
24
+ This is a generator object that at first yields the output of callable.
25
+ After the yield, it either raises instance of `TimeoutExpiredError` or
26
+ sleeps `sleep` seconds.
27
+
28
+ Yielding the output allows you to handle every value as you wish.
29
+
30
+ exceptions_dict should be in the following format:
31
+ {
32
+ exception0: [exception0_msg0],
33
+ exception1: [
34
+ exception1_msg0,
35
+ exception1_msg1
36
+ ],
37
+ exception2: []
38
+ }
39
+
40
+ If an exception is raised within `func`:
41
+ Example exception inheritance:
42
+ class Exception
43
+ class AExampleError(Exception)
44
+ class BExampleError(AExampleError)
45
+
46
+ The raised exception's class will fall into one of three categories:
47
+ 1. An exception class specifically declared in exceptions_dict
48
+ exceptions_dict: {BExampleError: []}
49
+ raise: BExampleError
50
+ result: continue
51
+
52
+ 2. A child class inherited from an exception class in exceptions_dict
53
+ exceptions_dict: {AExampleError: []}
54
+ raise: BExampleError
55
+ result: continue
56
+
57
+ 3. Everything else, this will always re-raise the exception
58
+ exceptions_dict: {BExampleError: []}
59
+ raise: AExampleError
60
+ result: raise
61
+
62
+ Args:
63
+ wait_timeout (int): Time in seconds to wait for func to return a value equating to True
64
+ sleep (int): Time in seconds between calls to func
65
+ func (Callable): to be wrapped by TimeoutSampler
66
+ exceptions_dict (dict): Exception handling definition
67
+ print_log (bool): Print elapsed time to log
68
+ """
69
+
70
+ def __init__(
71
+ self,
72
+ wait_timeout,
73
+ sleep,
74
+ func,
75
+ exceptions_dict=None,
76
+ print_log=True,
77
+ **func_kwargs,
78
+ ):
79
+ self.wait_timeout = wait_timeout
80
+ self.sleep = sleep
81
+ self.func = func
82
+ self.func_kwargs = func_kwargs
83
+ self.elapsed_time = None
84
+ self.print_log = print_log
85
+
86
+ self.exceptions_dict = exceptions_dict or {Exception: []}
87
+ self._exceptions = tuple(self.exceptions_dict.keys())
88
+
89
+ def _get_func_info(self, _func, type_):
90
+ # If func is partial function.
91
+ if getattr(_func, "func", None):
92
+ return self._get_func_info(_func=_func.func, type_=type_)
93
+
94
+ res = getattr(_func, type_, None)
95
+ if res:
96
+ # If func is lambda function.
97
+ if _func.__name__ == "<lambda>":
98
+ if type_ == "__module__":
99
+ return f"{res}.{_func.__qualname__.split('.')[1]}"
100
+
101
+ elif type_ == "__name__":
102
+ free_vars = _func.__code__.co_freevars
103
+ free_vars = f"{'.'.join(free_vars)}." if free_vars else ""
104
+ return f"lambda: {free_vars}{'.'.join(_func.__code__.co_names)}"
105
+ return res
106
+
107
+ @property
108
+ def _func_log(self):
109
+ """
110
+ Returns:
111
+ string: `func` information to include in log message
112
+ """
113
+ _func_kwargs = f"Kwargs: {self.func_kwargs}" if self.func_kwargs else ""
114
+ _func_module = self._get_func_info(_func=self.func, type_="__module__")
115
+ _func_name = self._get_func_info(_func=self.func, type_="__name__")
116
+ return f"Function: {_func_module}.{_func_name} {_func_kwargs}".strip()
117
+
118
+ def __iter__(self):
119
+ """
120
+ Iterator
121
+
122
+ Yields:
123
+ any: Return value from `func`
124
+ """
125
+ timeout_watch = TimeoutWatch(timeout=self.wait_timeout)
126
+ if self.print_log:
127
+ LOGGER.info(
128
+ f"Waiting for {self.wait_timeout} seconds, retry every {self.sleep} seconds. ({self._func_log})"
129
+ )
130
+
131
+ last_exp = None
132
+ while timeout_watch.remaining_time() > 0:
133
+ try:
134
+ self.elapsed_time = self.wait_timeout - timeout_watch.remaining_time()
135
+ yield self.func(**self.func_kwargs)
136
+ self.elapsed_time = None
137
+
138
+ time.sleep(self.sleep)
139
+
140
+ except self._exceptions as exp:
141
+ last_exp = exp
142
+ last_exp_log = self._get_exception_log(exp=last_exp)
143
+ if self._is_raisable_exception(exp=last_exp):
144
+ LOGGER.error(last_exp_log)
145
+ raise exp
146
+
147
+ self.elapsed_time = None
148
+ time.sleep(self.sleep)
149
+
150
+ finally:
151
+ if self.elapsed_time and self.print_log:
152
+ LOGGER.info(f"Elapsed time: {self.elapsed_time}")
153
+
154
+ raise TimeoutExpiredError(self._get_exception_log(exp=last_exp))
155
+
156
+ @staticmethod
157
+ def _is_exception_matched(exp, exception_messages):
158
+ """
159
+ Args:
160
+ exp (Exception): Exception object raised by `func`
161
+ exception_messages (list): Either an empty list allowing all text,
162
+ or a list of allowed strings to match against the exception text.
163
+
164
+ Returns:
165
+ bool: True if exception text is allowed or no exception text given, False otherwise
166
+ """
167
+ if not exception_messages:
168
+ return True
169
+
170
+ # Prevent match if provided with empty string
171
+ return any(msg and msg in str(exp) for msg in exception_messages)
172
+
173
+ def _is_raisable_exception(self, exp):
174
+ """
175
+ Verify whether exception should be raised during execution of `func`
176
+
177
+ Args:
178
+ exp (Exception): Exception object raised by `func`
179
+
180
+ Returns:
181
+ bool: True if exp should be raised, False otherwise
182
+ """
183
+
184
+ for entry in self.exceptions_dict:
185
+ if isinstance(exp, entry): # Check inheritance for raised exception
186
+ exception_messages = self.exceptions_dict.get(entry)
187
+ if self._is_exception_matched(
188
+ exp=exp, exception_messages=exception_messages
189
+ ):
190
+ return False
191
+
192
+ return True
193
+
194
+ def _get_exception_log(self, exp):
195
+ """
196
+ Args:
197
+ exp (any): Raised exception
198
+
199
+ Returns:
200
+ string: Log message for exception
201
+ """
202
+ exp_name = exp.__class__.__name__ if exp else "N/A"
203
+
204
+ last_exception_log = f"Last exception: {exp_name}: {exp}"
205
+ return f"{self.wait_timeout}\n{self._func_log}\n{last_exception_log}"
206
+
207
+
208
+ class TimeoutWatch:
209
+ """
210
+ A time counter allowing to determine the time remaining since the start
211
+ of a given interval
212
+ """
213
+
214
+ def __init__(self, timeout):
215
+ self.timeout = timeout
216
+ self.start_time = time.time()
217
+
218
+ def remaining_time(self):
219
+ """
220
+ Return the remaining part of timeout since the object was created.
221
+ """
222
+ return self.start_time + self.timeout - time.time()
223
+
224
+
225
+ def skip_existing_resource_creation_teardown(
226
+ resource, export_str, user_exported_args, check_exists=True
227
+ ):
228
+ """
229
+ Args:
230
+ resource (Resource): Resource to match against.
231
+ export_str (str): The user export str. (REUSE_IF_RESOURCE_EXISTS or SKIP_RESOURCE_TEARDOWN)
232
+ user_exported_args (str): Value of export_str. (os.environ.get)
233
+ check_exists (bool): Check if resource exists before return. (applied only for REUSE_IF_RESOURCE_EXISTS)
234
+
235
+ Returns:
236
+ Resource or None: If resource match.
237
+ """
238
+
239
+ def _return_resource(_resource, _check_exists, _msg):
240
+ """
241
+ Return the resource if exists when got _check_exists else return None.
242
+ If _check_exists=False returns the resource.
243
+ """
244
+ if not _check_exists: # In case of SKIP_RESOURCE_TEARDOWN
245
+ return _resource
246
+
247
+ elif _resource.exists: # In case of REUSE_IF_RESOURCE_EXISTS
248
+ LOGGER.warning(_msg)
249
+ return _resource
250
+
251
+ resource.to_dict()
252
+ resource_name = resource.res["metadata"]["name"]
253
+ resource_namespace = resource.res["metadata"].get("namespace")
254
+ skip_create_warn_msg = (
255
+ f"Skip resource {resource.kind} {resource_name} creation, using existing one."
256
+ f" Got {export_str}={user_exported_args}"
257
+ )
258
+ user_args = yaml.safe_load(stream=user_exported_args)
259
+ if resource.kind in user_args:
260
+ _resource_args = user_args[resource.kind]
261
+ if not _resource_args:
262
+ # Match only by kind, user didn't send name and/or namespace.
263
+ return _return_resource(
264
+ _resource=resource,
265
+ _check_exists=check_exists,
266
+ _msg=skip_create_warn_msg,
267
+ )
268
+
269
+ for _name, _namespace in _resource_args.items():
270
+ if resource_name == _name and (
271
+ resource_namespace == _namespace
272
+ or not (resource_namespace and _namespace)
273
+ ):
274
+ return _return_resource(
275
+ _resource=resource,
276
+ _check_exists=check_exists,
277
+ _msg=skip_create_warn_msg,
278
+ )
@@ -0,0 +1,9 @@
1
+ from ocp_resources.resource import Resource
2
+
3
+
4
+ class ValidatingWebhookConfiguration(Resource):
5
+ """
6
+ ValidatingWebhookConfiguration object.
7
+ """
8
+
9
+ api_group = Resource.ApiGroup.ADMISSIONREGISTRATION_K8S_IO
@@ -0,0 +1,177 @@
1
+ # -*- coding: utf-8 -*-
2
+
3
+
4
+ from ocp_resources.constants import (
5
+ DEFAULT_CLUSTER_RETRY_EXCEPTIONS,
6
+ PROTOCOL_ERROR_EXCEPTION_DICT,
7
+ TIMEOUT_4MINUTES,
8
+ )
9
+ from ocp_resources.resource import NamespacedResource
10
+ from ocp_resources.utils import TimeoutSampler
11
+ from ocp_resources.virtual_machine_instance import VirtualMachineInstance
12
+
13
+
14
+ class VirtualMachine(NamespacedResource):
15
+ """
16
+ Virtual Machine object, inherited from Resource.
17
+ Implements actions start / stop / status / wait for VM status / is running
18
+ """
19
+
20
+ api_group = NamespacedResource.ApiGroup.KUBEVIRT_IO
21
+
22
+ class RunStrategy:
23
+ MANUAL = "Manual"
24
+ HALTED = "Halted"
25
+ ALWAYS = "Always"
26
+ RERUNONFAILURE = "RerunOnFailure"
27
+
28
+ class Status(NamespacedResource.Status):
29
+ MIGRATING = "Migrating"
30
+ PAUSED = "Paused"
31
+ PROVISIONING = "Provisioning"
32
+ STARTING = "Starting"
33
+ STOPPED = "Stopped"
34
+ STOPPING = "Stopping"
35
+ WAITING_FOR_VOLUME_BINDING = "WaitingForVolumeBinding"
36
+
37
+ def __init__(
38
+ self,
39
+ name=None,
40
+ namespace=None,
41
+ client=None,
42
+ body=None,
43
+ teardown=True,
44
+ privileged_client=None,
45
+ yaml_file=None,
46
+ delete_timeout=TIMEOUT_4MINUTES,
47
+ **kwargs,
48
+ ):
49
+ super().__init__(
50
+ name=name,
51
+ namespace=namespace,
52
+ client=client,
53
+ teardown=teardown,
54
+ privileged_client=privileged_client,
55
+ yaml_file=yaml_file,
56
+ delete_timeout=delete_timeout,
57
+ **kwargs,
58
+ )
59
+ self.body = body
60
+
61
+ @property
62
+ def _subresource_api_url(self):
63
+ return (
64
+ f"{self.client.configuration.host}/"
65
+ f"apis/subresources.kubevirt.io/{self.api.api_version}/"
66
+ f"namespaces/{self.namespace}/virtualmachines/{self.name}"
67
+ )
68
+
69
+ def api_request(self, method, action, **params):
70
+ return super().api_request(
71
+ method=method, action=action, url=self._subresource_api_url, **params
72
+ )
73
+
74
+ def to_dict(self):
75
+ super().to_dict()
76
+ if not self.yaml_file:
77
+ body_spec = self.body.get("spec") if self.body else None
78
+ self.res["spec"] = body_spec or {"template": {"spec": {}}}
79
+
80
+ def start(self, timeout=TIMEOUT_4MINUTES, wait=False):
81
+ self.api_request(method="PUT", action="start")
82
+ if wait:
83
+ return self.wait_for_ready_status(timeout=timeout, status=True)
84
+
85
+ def restart(self, timeout=TIMEOUT_4MINUTES, wait=False):
86
+ self.api_request(method="PUT", action="restart")
87
+ if wait:
88
+ self.vmi.virt_launcher_pod.wait_deleted()
89
+ return self.vmi.wait_until_running(timeout=timeout, stop_status="dummy")
90
+
91
+ def stop(
92
+ self, timeout=TIMEOUT_4MINUTES, vmi_delete_timeout=TIMEOUT_4MINUTES, wait=False
93
+ ):
94
+ self.api_request(method="PUT", action="stop")
95
+ if wait:
96
+ self.wait_for_ready_status(timeout=timeout, status=None)
97
+ return self.vmi.wait_deleted(timeout=vmi_delete_timeout)
98
+
99
+ def wait_for_ready_status(self, status, timeout=TIMEOUT_4MINUTES, sleep=1):
100
+ """
101
+ Wait for VM resource ready status to be at desire status
102
+
103
+ Args:
104
+ status (any): True for a running VM, None for a stopped VM.
105
+ timeout (int): Time to wait for the resource.
106
+
107
+ Raises:
108
+ TimeoutExpiredError: If timeout reached.
109
+ """
110
+ self.logger.info(
111
+ f"Wait for {self.kind} {self.name} status to be {'ready' if status == True else status}"
112
+ )
113
+ samples = TimeoutSampler(
114
+ wait_timeout=timeout,
115
+ sleep=sleep,
116
+ exceptions_dict={
117
+ **PROTOCOL_ERROR_EXCEPTION_DICT,
118
+ **DEFAULT_CLUSTER_RETRY_EXCEPTIONS,
119
+ },
120
+ func=self.api.get,
121
+ field_selector=f"metadata.name=={self.name}",
122
+ namespace=self.namespace,
123
+ )
124
+ for sample in samples:
125
+ if sample.items and self.ready == status:
126
+ # VM with runStrategy does not have spec.running attribute
127
+ # VM status should be taken from spec.status.ready
128
+ return
129
+
130
+ def get_interfaces(self):
131
+ return self.instance.spec.template.spec.domain.devices.interfaces
132
+
133
+ @property
134
+ def vmi(self):
135
+ """
136
+ Get VMI
137
+
138
+ Returns:
139
+ VirtualMachineInstance: VMI
140
+ """
141
+ return VirtualMachineInstance(
142
+ client=self.client,
143
+ name=self.name,
144
+ namespace=self.namespace,
145
+ privileged_client=self.privileged_client or self.client,
146
+ )
147
+
148
+ @property
149
+ def ready(self):
150
+ """
151
+ Get VM status
152
+
153
+ Returns:
154
+ True if Running else None
155
+ """
156
+ return self.instance.get("status", {}).get("ready")
157
+
158
+ @property
159
+ def printable_status(self):
160
+ """
161
+ Get VM printableStatus
162
+
163
+ Returns:
164
+ VM printableStatus if VM.status.printableStatus else None
165
+ """
166
+ return self.instance.get("status", {}).get("printableStatus")
167
+
168
+ def wait_for_status_none(self, status, timeout=TIMEOUT_4MINUTES):
169
+ self.logger.info(f"Wait for {self.kind} {self.name} status {status} to be None")
170
+ for sample in TimeoutSampler(
171
+ wait_timeout=timeout,
172
+ sleep=1,
173
+ exceptions_dict=PROTOCOL_ERROR_EXCEPTION_DICT,
174
+ func=lambda: self.instance.get("status", {}).get(status),
175
+ ):
176
+ if sample is None:
177
+ return
@@ -0,0 +1,9 @@
1
+ from ocp_resources.resource import NamespacedResource
2
+
3
+
4
+ class VirtualMachineInstanceReplicaSet(NamespacedResource):
5
+ """
6
+ VirtualMachineInstancePreset object.
7
+ """
8
+
9
+ api_group = NamespacedResource.ApiGroup.KUBEVIRT_IO
@@ -0,0 +1,5 @@
1
+ from ocp_resources.resource import Resource
2
+
3
+
4
+ class VirtualMachineClusterFlavor(Resource):
5
+ api_group = Resource.ApiGroup.FLAVOR_KUBEVIRT_IO
@@ -0,0 +1,5 @@
1
+ from ocp_resources.resource import NamespacedResource
2
+
3
+
4
+ class VirtualMachineFlavor(NamespacedResource):
5
+ api_group = NamespacedResource.ApiGroup.FLAVOR_KUBEVIRT_IO