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.
- ocp_resources/__init__.py +0 -0
- ocp_resources/api_service.py +9 -0
- ocp_resources/backup.py +52 -0
- ocp_resources/benchmark.py +92 -0
- ocp_resources/catalog_source.py +63 -0
- ocp_resources/catalog_source_config.py +86 -0
- ocp_resources/cdi.py +13 -0
- ocp_resources/cdi_config.py +52 -0
- ocp_resources/chaos_engine.py +30 -0
- ocp_resources/chaos_result.py +11 -0
- ocp_resources/cluster_operator.py +5 -0
- ocp_resources/cluster_role.py +70 -0
- ocp_resources/cluster_role_binding.py +36 -0
- ocp_resources/cluster_service_version.py +8 -0
- ocp_resources/cluster_version.py +5 -0
- ocp_resources/configmap.py +37 -0
- ocp_resources/console_cli_download.py +9 -0
- ocp_resources/console_plugin.py +9 -0
- ocp_resources/console_quick_start.py +9 -0
- ocp_resources/constants.py +26 -0
- ocp_resources/csidriver.py +9 -0
- ocp_resources/custom_resource_definition.py +5 -0
- ocp_resources/daemonset.py +61 -0
- ocp_resources/data_import_cron.py +100 -0
- ocp_resources/data_source.py +59 -0
- ocp_resources/datavolume.py +275 -0
- ocp_resources/deployment.py +65 -0
- ocp_resources/destination_rule.py +11 -0
- ocp_resources/event.py +114 -0
- ocp_resources/forklift_controller.py +10 -0
- ocp_resources/gateway.py +11 -0
- ocp_resources/hook.py +52 -0
- ocp_resources/host.py +64 -0
- ocp_resources/hostpath_provisioner.py +50 -0
- ocp_resources/hyperconverged.py +43 -0
- ocp_resources/image.py +9 -0
- ocp_resources/image_content_source_policy.py +9 -0
- ocp_resources/image_stream.py +48 -0
- ocp_resources/imagestreamtag.py +9 -0
- ocp_resources/infrastructure.py +18 -0
- ocp_resources/installplan.py +8 -0
- ocp_resources/job.py +65 -0
- ocp_resources/kube_descheduler.py +65 -0
- ocp_resources/kubevirt.py +5 -0
- ocp_resources/kubevirt_common_templates_bundle.py +5 -0
- ocp_resources/kubevirt_metrics_aggregation.py +5 -0
- ocp_resources/kubevirt_node_labeller_bundle.py +5 -0
- ocp_resources/kubevirt_template_validaotr.py +5 -0
- ocp_resources/logger.py +76 -0
- ocp_resources/machine.py +50 -0
- ocp_resources/machine_config.py +5 -0
- ocp_resources/machine_config_pool.py +9 -0
- ocp_resources/machine_health_check.py +76 -0
- ocp_resources/machine_set.py +189 -0
- ocp_resources/migration.py +63 -0
- ocp_resources/migration_policy.py +66 -0
- ocp_resources/mtv.py +171 -0
- ocp_resources/mutating_webhook_config.py +9 -0
- ocp_resources/namespace.py +40 -0
- ocp_resources/network.py +5 -0
- ocp_resources/network_addons_config.py +9 -0
- ocp_resources/network_attachment_definition.py +24 -0
- ocp_resources/network_map.py +64 -0
- ocp_resources/network_policy.py +9 -0
- ocp_resources/nmstate.py +9 -0
- ocp_resources/node.py +41 -0
- ocp_resources/node_health_check.py +10 -0
- ocp_resources/node_maintenance.py +40 -0
- ocp_resources/node_network_configuration_enactment.py +20 -0
- ocp_resources/node_network_configuration_policy.py +472 -0
- ocp_resources/node_network_state.py +121 -0
- ocp_resources/oauth.py +9 -0
- ocp_resources/operator_condition.py +5 -0
- ocp_resources/operator_group.py +37 -0
- ocp_resources/operator_hub.py +5 -0
- ocp_resources/operator_source.py +50 -0
- ocp_resources/package_manifest.py +5 -0
- ocp_resources/peer_authentication.py +18 -0
- ocp_resources/persistent_volume.py +27 -0
- ocp_resources/persistent_volume_claim.py +103 -0
- ocp_resources/plan.py +143 -0
- ocp_resources/pod.py +175 -0
- ocp_resources/pod_disruption_budget.py +53 -0
- ocp_resources/priority_class.py +48 -0
- ocp_resources/project.py +60 -0
- ocp_resources/prometheus.py +9 -0
- ocp_resources/prometheus_rule.py +9 -0
- ocp_resources/provider.py +59 -0
- ocp_resources/replicaset.py +11 -0
- ocp_resources/resource.py +1383 -0
- ocp_resources/restore.py +52 -0
- ocp_resources/role.py +11 -0
- ocp_resources/role_binding.py +67 -0
- ocp_resources/route.py +76 -0
- ocp_resources/secret.py +75 -0
- ocp_resources/security_context_constraints.py +9 -0
- ocp_resources/service.py +16 -0
- ocp_resources/service_account.py +9 -0
- ocp_resources/service_mesh_control_plane.py +11 -0
- ocp_resources/service_mesh_member_roll.py +14 -0
- ocp_resources/service_monitor.py +9 -0
- ocp_resources/sriov_network.py +54 -0
- ocp_resources/sriov_network_node_policy.py +67 -0
- ocp_resources/sriov_network_node_state.py +44 -0
- ocp_resources/ssp.py +9 -0
- ocp_resources/storage_class.py +47 -0
- ocp_resources/storage_map.py +67 -0
- ocp_resources/storage_profile.py +7 -0
- ocp_resources/subscription.py +66 -0
- ocp_resources/tekton_tasks.py +9 -0
- ocp_resources/template.py +74 -0
- ocp_resources/upload_token_request.py +39 -0
- ocp_resources/utils.py +278 -0
- ocp_resources/validating_webhook_config.py +9 -0
- ocp_resources/virtual_machine.py +177 -0
- ocp_resources/virtual_machine_Instance_replica_set.py +9 -0
- ocp_resources/virtual_machine_cluster_flavor.py +5 -0
- ocp_resources/virtual_machine_flavor.py +5 -0
- ocp_resources/virtual_machine_import.py +307 -0
- ocp_resources/virtual_machine_instance.py +322 -0
- ocp_resources/virtual_machine_instance_migration.py +36 -0
- ocp_resources/virtual_machine_instance_preset.py +9 -0
- ocp_resources/virtual_machine_restore.py +99 -0
- ocp_resources/virtual_machine_snapshot.py +96 -0
- ocp_resources/virtual_service.py +11 -0
- ocp_resources/vm_import_config.py +9 -0
- ocp_resources/volume_snapshot.py +9 -0
- ocp_resources/volume_snapshot_class.py +9 -0
- openshift_python_wrapper-4.11.61.dist-info/LICENSE +201 -0
- openshift_python_wrapper-4.11.61.dist-info/METADATA +188 -0
- openshift_python_wrapper-4.11.61.dist-info/RECORD +132 -0
- openshift_python_wrapper-4.11.61.dist-info/WHEEL +4 -0
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
import kubernetes
|
|
2
|
+
|
|
3
|
+
from ocp_resources.constants import PROTOCOL_ERROR_EXCEPTION_DICT, TIMEOUT_4MINUTES
|
|
4
|
+
from ocp_resources.resource import NamespacedResource
|
|
5
|
+
from ocp_resources.utils import TimeoutSampler
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
class DaemonSet(NamespacedResource):
|
|
9
|
+
"""
|
|
10
|
+
DaemonSet object.
|
|
11
|
+
"""
|
|
12
|
+
|
|
13
|
+
api_group = NamespacedResource.ApiGroup.APPS
|
|
14
|
+
|
|
15
|
+
def wait_until_deployed(self, timeout=TIMEOUT_4MINUTES):
|
|
16
|
+
"""
|
|
17
|
+
Wait until all Pods are deployed and ready.
|
|
18
|
+
|
|
19
|
+
Args:
|
|
20
|
+
timeout (int): Time to wait for the Daemonset.
|
|
21
|
+
|
|
22
|
+
Raises:
|
|
23
|
+
TimeoutExpiredError: If not all the pods are deployed.
|
|
24
|
+
"""
|
|
25
|
+
self.logger.info(f"Wait for {self.kind} {self.name} to deploy all desired pods")
|
|
26
|
+
samples = TimeoutSampler(
|
|
27
|
+
wait_timeout=timeout,
|
|
28
|
+
sleep=1,
|
|
29
|
+
exceptions_dict=PROTOCOL_ERROR_EXCEPTION_DICT,
|
|
30
|
+
func=self.api.get,
|
|
31
|
+
field_selector=f"metadata.name=={self.name}",
|
|
32
|
+
namespace=self.namespace,
|
|
33
|
+
)
|
|
34
|
+
for sample in samples:
|
|
35
|
+
if sample.items:
|
|
36
|
+
status = sample.items[0].status
|
|
37
|
+
desired_number_scheduled = status.desiredNumberScheduled
|
|
38
|
+
number_ready = status.numberReady
|
|
39
|
+
if (
|
|
40
|
+
desired_number_scheduled > 0
|
|
41
|
+
and desired_number_scheduled == number_ready
|
|
42
|
+
):
|
|
43
|
+
return
|
|
44
|
+
|
|
45
|
+
def delete(self, wait=False, timeout=TIMEOUT_4MINUTES, body=None):
|
|
46
|
+
"""
|
|
47
|
+
Delete Daemonset
|
|
48
|
+
|
|
49
|
+
Args:
|
|
50
|
+
wait (bool): True to wait for Daemonset to be deleted.
|
|
51
|
+
timeout (int): Time to wait for resource deletion
|
|
52
|
+
body (dict): Content to send for delete()
|
|
53
|
+
|
|
54
|
+
Returns:
|
|
55
|
+
bool: True if delete succeeded, False otherwise.
|
|
56
|
+
"""
|
|
57
|
+
super().delete(
|
|
58
|
+
wait=wait,
|
|
59
|
+
timeout=timeout,
|
|
60
|
+
body=kubernetes.client.V1DeleteOptions(propagation_policy="Foreground"),
|
|
61
|
+
)
|
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
from ocp_resources.constants import TIMEOUT_4MINUTES
|
|
2
|
+
from ocp_resources.resource import NamespacedResource
|
|
3
|
+
|
|
4
|
+
|
|
5
|
+
class DataImportCron(NamespacedResource):
|
|
6
|
+
"""
|
|
7
|
+
DataImportCron object.
|
|
8
|
+
"""
|
|
9
|
+
|
|
10
|
+
api_group = NamespacedResource.ApiGroup.CDI_KUBEVIRT_IO
|
|
11
|
+
|
|
12
|
+
def __init__(
|
|
13
|
+
self,
|
|
14
|
+
name=None,
|
|
15
|
+
namespace=None,
|
|
16
|
+
client=None,
|
|
17
|
+
image_stream=None,
|
|
18
|
+
url=None,
|
|
19
|
+
cert_configmap=None,
|
|
20
|
+
pull_method=None,
|
|
21
|
+
storage_class=None,
|
|
22
|
+
size=None,
|
|
23
|
+
schedule=None,
|
|
24
|
+
garbage_collect=None,
|
|
25
|
+
managed_data_source=None,
|
|
26
|
+
imports_to_keep=None,
|
|
27
|
+
bind_immediate_annotation=None,
|
|
28
|
+
teardown=True,
|
|
29
|
+
privileged_client=None,
|
|
30
|
+
yaml_file=None,
|
|
31
|
+
delete_timeout=TIMEOUT_4MINUTES,
|
|
32
|
+
**kwargs,
|
|
33
|
+
):
|
|
34
|
+
super().__init__(
|
|
35
|
+
name=name,
|
|
36
|
+
namespace=namespace,
|
|
37
|
+
client=client,
|
|
38
|
+
teardown=teardown,
|
|
39
|
+
privileged_client=privileged_client,
|
|
40
|
+
yaml_file=yaml_file,
|
|
41
|
+
delete_timeout=delete_timeout,
|
|
42
|
+
**kwargs,
|
|
43
|
+
)
|
|
44
|
+
self.image_stream = image_stream
|
|
45
|
+
self.url = url
|
|
46
|
+
self.cert_configmap = cert_configmap
|
|
47
|
+
self.pull_method = pull_method
|
|
48
|
+
self.storage_class = storage_class
|
|
49
|
+
self.size = size
|
|
50
|
+
self.schedule = schedule
|
|
51
|
+
self.garbage_collect = garbage_collect
|
|
52
|
+
self.managed_data_source = managed_data_source
|
|
53
|
+
self.imports_to_keep = imports_to_keep
|
|
54
|
+
self.bind_immediate_annotation = bind_immediate_annotation
|
|
55
|
+
|
|
56
|
+
def to_dict(self):
|
|
57
|
+
super().to_dict()
|
|
58
|
+
if not self.yaml_file:
|
|
59
|
+
if self.image_stream and self.url:
|
|
60
|
+
raise ValueError("imageStream and url can not coexist")
|
|
61
|
+
|
|
62
|
+
self.res.update(
|
|
63
|
+
{
|
|
64
|
+
"spec": {
|
|
65
|
+
"template": {
|
|
66
|
+
"spec": {
|
|
67
|
+
"source": {
|
|
68
|
+
"registry": {"pullMethod": self.pull_method}
|
|
69
|
+
},
|
|
70
|
+
"storage": {
|
|
71
|
+
"resources": {"requests": {"storage": self.size}}
|
|
72
|
+
},
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
)
|
|
78
|
+
spec = self.res["spec"]["template"]["spec"]
|
|
79
|
+
if self.bind_immediate_annotation:
|
|
80
|
+
self.res["metadata"].setdefault("annotations", {}).update(
|
|
81
|
+
{
|
|
82
|
+
f"{NamespacedResource.ApiGroup.CDI_KUBEVIRT_IO}/storage.bind.immediate.requested": "true"
|
|
83
|
+
}
|
|
84
|
+
)
|
|
85
|
+
if self.image_stream:
|
|
86
|
+
spec["source"]["registry"]["imageStream"] = self.image_stream
|
|
87
|
+
if self.url:
|
|
88
|
+
spec["source"]["registry"]["url"] = self.url
|
|
89
|
+
if self.cert_configmap:
|
|
90
|
+
spec["source"]["registry"]["certConfigMap"] = self.cert_configmap
|
|
91
|
+
if self.storage_class:
|
|
92
|
+
spec["storage"]["storageClassName"] = self.storage_class
|
|
93
|
+
if self.schedule:
|
|
94
|
+
self.res["spec"]["schedule"] = self.schedule
|
|
95
|
+
if self.garbage_collect:
|
|
96
|
+
self.res["spec"]["garbageCollect"] = self.garbage_collect
|
|
97
|
+
if self.managed_data_source:
|
|
98
|
+
self.res["spec"]["managedDataSource"] = self.managed_data_source
|
|
99
|
+
if self.imports_to_keep:
|
|
100
|
+
self.res["spec"]["importsToKeep"] = self.imports_to_keep
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
from openshift.dynamic.exceptions import ResourceNotFoundError
|
|
2
|
+
|
|
3
|
+
from ocp_resources.constants import TIMEOUT_4MINUTES
|
|
4
|
+
from ocp_resources.persistent_volume_claim import PersistentVolumeClaim
|
|
5
|
+
from ocp_resources.resource import NamespacedResource
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
class DataSource(NamespacedResource):
|
|
9
|
+
api_group = NamespacedResource.ApiGroup.CDI_KUBEVIRT_IO
|
|
10
|
+
|
|
11
|
+
def __init__(
|
|
12
|
+
self,
|
|
13
|
+
name=None,
|
|
14
|
+
namespace=None,
|
|
15
|
+
client=None,
|
|
16
|
+
source=None,
|
|
17
|
+
teardown=True,
|
|
18
|
+
yaml_file=None,
|
|
19
|
+
delete_timeout=TIMEOUT_4MINUTES,
|
|
20
|
+
**kwargs,
|
|
21
|
+
):
|
|
22
|
+
super().__init__(
|
|
23
|
+
name=name,
|
|
24
|
+
namespace=namespace,
|
|
25
|
+
client=client,
|
|
26
|
+
teardown=teardown,
|
|
27
|
+
yaml_file=yaml_file,
|
|
28
|
+
delete_timeout=delete_timeout,
|
|
29
|
+
**kwargs,
|
|
30
|
+
)
|
|
31
|
+
self.source = source
|
|
32
|
+
|
|
33
|
+
def to_dict(self):
|
|
34
|
+
super().to_dict()
|
|
35
|
+
if not self.yaml_file:
|
|
36
|
+
self.res.update(
|
|
37
|
+
{
|
|
38
|
+
"spec": {
|
|
39
|
+
"source": self.source,
|
|
40
|
+
},
|
|
41
|
+
}
|
|
42
|
+
)
|
|
43
|
+
|
|
44
|
+
@property
|
|
45
|
+
def pvc(self):
|
|
46
|
+
data_source_pvc = self.instance.spec.source.pvc
|
|
47
|
+
pvc_name = data_source_pvc.name
|
|
48
|
+
pvc_namespace = data_source_pvc.namespace
|
|
49
|
+
try:
|
|
50
|
+
return PersistentVolumeClaim(
|
|
51
|
+
client=self.client,
|
|
52
|
+
name=pvc_name,
|
|
53
|
+
namespace=pvc_namespace,
|
|
54
|
+
)
|
|
55
|
+
except ResourceNotFoundError:
|
|
56
|
+
self.logger.warning(
|
|
57
|
+
f"dataSource {self.name} is pointing to a non-existing PVC, name: {pvc_name}, "
|
|
58
|
+
f"namespace: {pvc_namespace}"
|
|
59
|
+
)
|
|
@@ -0,0 +1,275 @@
|
|
|
1
|
+
# -*- coding: utf-8 -*-
|
|
2
|
+
|
|
3
|
+
from ocp_resources.constants import TIMEOUT_4MINUTES
|
|
4
|
+
from ocp_resources.persistent_volume_claim import PersistentVolumeClaim
|
|
5
|
+
from ocp_resources.resource import NamespacedResource, Resource
|
|
6
|
+
from ocp_resources.utils import TimeoutExpiredError, TimeoutSampler
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
class DataVolume(NamespacedResource):
|
|
10
|
+
"""
|
|
11
|
+
DataVolume object.
|
|
12
|
+
"""
|
|
13
|
+
|
|
14
|
+
api_group = NamespacedResource.ApiGroup.CDI_KUBEVIRT_IO
|
|
15
|
+
|
|
16
|
+
class Status(NamespacedResource.Status):
|
|
17
|
+
BLANK = "Blank"
|
|
18
|
+
PVC_BOUND = "PVCBound"
|
|
19
|
+
IMPORT_SCHEDULED = "ImportScheduled"
|
|
20
|
+
ClONE_SCHEDULED = "CloneScheduled"
|
|
21
|
+
UPLOAD_SCHEDULED = "UploadScheduled"
|
|
22
|
+
IMPORT_IN_PROGRESS = "ImportInProgress"
|
|
23
|
+
CLONE_IN_PROGRESS = "CloneInProgress"
|
|
24
|
+
UPLOAD_IN_PROGRESS = "UploadInProgress"
|
|
25
|
+
SNAPSHOT_FOR_SMART_CLONE_IN_PROGRESS = "SnapshotForSmartCloneInProgress"
|
|
26
|
+
SMART_CLONE_PVC_IN_PROGRESS = "SmartClonePVCInProgress"
|
|
27
|
+
UPLOAD_READY = "UploadReady"
|
|
28
|
+
UNKNOWN = "Unknown"
|
|
29
|
+
WAIT_FOR_FIRST_CONSUMER = "WaitForFirstConsumer"
|
|
30
|
+
|
|
31
|
+
class AccessMode:
|
|
32
|
+
"""
|
|
33
|
+
AccessMode object.
|
|
34
|
+
"""
|
|
35
|
+
|
|
36
|
+
RWO = "ReadWriteOnce"
|
|
37
|
+
ROX = "ReadOnlyMany"
|
|
38
|
+
RWX = "ReadWriteMany"
|
|
39
|
+
|
|
40
|
+
class ContentType:
|
|
41
|
+
"""
|
|
42
|
+
ContentType object
|
|
43
|
+
"""
|
|
44
|
+
|
|
45
|
+
KUBEVIRT = "kubevirt"
|
|
46
|
+
ARCHIVE = "archive"
|
|
47
|
+
|
|
48
|
+
class VolumeMode:
|
|
49
|
+
"""
|
|
50
|
+
VolumeMode object
|
|
51
|
+
"""
|
|
52
|
+
|
|
53
|
+
BLOCK = "Block"
|
|
54
|
+
FILE = "Filesystem"
|
|
55
|
+
|
|
56
|
+
class Condition:
|
|
57
|
+
class Type:
|
|
58
|
+
READY = "Ready"
|
|
59
|
+
BOUND = "Bound"
|
|
60
|
+
RUNNING = "Running"
|
|
61
|
+
|
|
62
|
+
class Status(Resource.Condition.Status):
|
|
63
|
+
UNKNOWN = "Unknown"
|
|
64
|
+
|
|
65
|
+
def __init__(
|
|
66
|
+
self,
|
|
67
|
+
name=None,
|
|
68
|
+
namespace=None,
|
|
69
|
+
source=None,
|
|
70
|
+
size=None,
|
|
71
|
+
storage_class=None,
|
|
72
|
+
url=None,
|
|
73
|
+
content_type=ContentType.KUBEVIRT,
|
|
74
|
+
access_modes=None,
|
|
75
|
+
cert_configmap=None,
|
|
76
|
+
secret=None,
|
|
77
|
+
client=None,
|
|
78
|
+
volume_mode=None,
|
|
79
|
+
hostpath_node=None,
|
|
80
|
+
source_pvc=None,
|
|
81
|
+
source_namespace=None,
|
|
82
|
+
multus_annotation=None,
|
|
83
|
+
bind_immediate_annotation=None,
|
|
84
|
+
preallocation=None,
|
|
85
|
+
teardown=True,
|
|
86
|
+
privileged_client=None,
|
|
87
|
+
yaml_file=None,
|
|
88
|
+
delete_timeout=TIMEOUT_4MINUTES,
|
|
89
|
+
api_name="pvc",
|
|
90
|
+
**kwargs,
|
|
91
|
+
):
|
|
92
|
+
super().__init__(
|
|
93
|
+
name=name,
|
|
94
|
+
namespace=namespace,
|
|
95
|
+
client=client,
|
|
96
|
+
teardown=teardown,
|
|
97
|
+
privileged_client=privileged_client,
|
|
98
|
+
yaml_file=yaml_file,
|
|
99
|
+
delete_timeout=delete_timeout,
|
|
100
|
+
**kwargs,
|
|
101
|
+
)
|
|
102
|
+
self.source = source
|
|
103
|
+
self.url = url
|
|
104
|
+
self.cert_configmap = cert_configmap
|
|
105
|
+
self.secret = secret
|
|
106
|
+
self.content_type = content_type
|
|
107
|
+
self.size = size
|
|
108
|
+
self.access_modes = access_modes
|
|
109
|
+
self.storage_class = storage_class
|
|
110
|
+
self.volume_mode = volume_mode
|
|
111
|
+
self.hostpath_node = hostpath_node
|
|
112
|
+
self.source_pvc = source_pvc
|
|
113
|
+
self.source_namespace = source_namespace
|
|
114
|
+
self.multus_annotation = multus_annotation
|
|
115
|
+
self.bind_immediate_annotation = bind_immediate_annotation
|
|
116
|
+
self.preallocation = preallocation
|
|
117
|
+
self.api_name = api_name
|
|
118
|
+
|
|
119
|
+
def to_dict(self):
|
|
120
|
+
super().to_dict()
|
|
121
|
+
if not self.yaml_file:
|
|
122
|
+
self.res.update(
|
|
123
|
+
{
|
|
124
|
+
"spec": {
|
|
125
|
+
"source": {self.source: {"url": self.url}},
|
|
126
|
+
self.api_name: {
|
|
127
|
+
"resources": {"requests": {"storage": self.size}},
|
|
128
|
+
},
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
)
|
|
132
|
+
if self.access_modes:
|
|
133
|
+
self.res["spec"][self.api_name]["accessModes"] = [self.access_modes]
|
|
134
|
+
if self.content_type:
|
|
135
|
+
self.res["spec"]["contentType"] = self.content_type
|
|
136
|
+
if self.storage_class:
|
|
137
|
+
self.res["spec"][self.api_name]["storageClassName"] = self.storage_class
|
|
138
|
+
if self.secret:
|
|
139
|
+
self.res["spec"]["source"][self.source]["secretRef"] = self.secret.name
|
|
140
|
+
if self.volume_mode:
|
|
141
|
+
self.res["spec"][self.api_name]["volumeMode"] = self.volume_mode
|
|
142
|
+
if self.source == "http" or "registry":
|
|
143
|
+
self.res["spec"]["source"][self.source]["url"] = self.url
|
|
144
|
+
if self.cert_configmap:
|
|
145
|
+
self.res["spec"]["source"][self.source][
|
|
146
|
+
"certConfigMap"
|
|
147
|
+
] = self.cert_configmap
|
|
148
|
+
if self.source == "upload" or self.source == "blank":
|
|
149
|
+
self.res["spec"]["source"][self.source] = {}
|
|
150
|
+
if self.hostpath_node:
|
|
151
|
+
self.res["metadata"].setdefault("annotations", {}).update(
|
|
152
|
+
{
|
|
153
|
+
f"{NamespacedResource.ApiGroup.KUBEVIRT_IO}/provisionOnNode": self.hostpath_node
|
|
154
|
+
}
|
|
155
|
+
)
|
|
156
|
+
if self.multus_annotation:
|
|
157
|
+
self.res["metadata"].setdefault("annotations", {}).update(
|
|
158
|
+
{
|
|
159
|
+
f"{NamespacedResource.ApiGroup.K8S_V1_CNI_CNCF_IO}/networks": self.multus_annotation
|
|
160
|
+
}
|
|
161
|
+
)
|
|
162
|
+
if self.bind_immediate_annotation:
|
|
163
|
+
self.res["metadata"].setdefault("annotations", {}).update(
|
|
164
|
+
{
|
|
165
|
+
f"{NamespacedResource.ApiGroup.CDI_KUBEVIRT_IO}/storage.bind.immediate.requested": "true"
|
|
166
|
+
}
|
|
167
|
+
)
|
|
168
|
+
if self.source == "pvc":
|
|
169
|
+
self.res["spec"]["source"]["pvc"] = {
|
|
170
|
+
"name": self.source_pvc or "dv-source",
|
|
171
|
+
"namespace": self.source_namespace or self.namespace,
|
|
172
|
+
}
|
|
173
|
+
if self.preallocation is not None:
|
|
174
|
+
self.res["spec"]["preallocation"] = self.preallocation
|
|
175
|
+
|
|
176
|
+
def wait_deleted(self, timeout=TIMEOUT_4MINUTES):
|
|
177
|
+
"""
|
|
178
|
+
Wait until DataVolume and the PVC created by it are deleted
|
|
179
|
+
|
|
180
|
+
Args:
|
|
181
|
+
timeout (int): Time to wait for the DataVolume and PVC to be deleted.
|
|
182
|
+
|
|
183
|
+
Returns:
|
|
184
|
+
bool: True if DataVolume and its PVC are gone, False if timeout reached.
|
|
185
|
+
"""
|
|
186
|
+
super().wait_deleted(timeout=timeout)
|
|
187
|
+
return self.pvc.wait_deleted(timeout=timeout)
|
|
188
|
+
|
|
189
|
+
def wait(self, timeout=600, failure_timeout=120):
|
|
190
|
+
self._check_none_pending_status(failure_timeout=failure_timeout)
|
|
191
|
+
|
|
192
|
+
# If DV's status is not Pending, continue with the flow
|
|
193
|
+
self.wait_for_status(status=self.Status.SUCCEEDED, timeout=timeout)
|
|
194
|
+
self.pvc.wait_for_status(
|
|
195
|
+
status=PersistentVolumeClaim.Status.BOUND, timeout=timeout
|
|
196
|
+
)
|
|
197
|
+
|
|
198
|
+
@property
|
|
199
|
+
def pvc(self):
|
|
200
|
+
return PersistentVolumeClaim(
|
|
201
|
+
client=self.privileged_client or self.client,
|
|
202
|
+
name=self.name,
|
|
203
|
+
namespace=self.namespace,
|
|
204
|
+
)
|
|
205
|
+
|
|
206
|
+
@property
|
|
207
|
+
def scratch_pvc(self):
|
|
208
|
+
return PersistentVolumeClaim(
|
|
209
|
+
name=f"{self.name}-scratch",
|
|
210
|
+
namespace=self.namespace,
|
|
211
|
+
client=self.client,
|
|
212
|
+
)
|
|
213
|
+
|
|
214
|
+
def _check_none_pending_status(self, failure_timeout=120):
|
|
215
|
+
# Avoid waiting for "Succeeded" status if DV's in Pending/None status
|
|
216
|
+
sample = None
|
|
217
|
+
# if garbage collector is enabled, DV will be deleted after success
|
|
218
|
+
try:
|
|
219
|
+
for sample in TimeoutSampler(
|
|
220
|
+
wait_timeout=failure_timeout,
|
|
221
|
+
sleep=10,
|
|
222
|
+
func=lambda: self.exists,
|
|
223
|
+
):
|
|
224
|
+
# If DV status is Pending (or Status is not yet updated) continue to wait, else exit the wait loop
|
|
225
|
+
if sample and (
|
|
226
|
+
not sample.status
|
|
227
|
+
or sample.status.phase
|
|
228
|
+
in [
|
|
229
|
+
self.Status.PENDING,
|
|
230
|
+
None,
|
|
231
|
+
]
|
|
232
|
+
):
|
|
233
|
+
continue
|
|
234
|
+
break
|
|
235
|
+
except TimeoutExpiredError:
|
|
236
|
+
self.logger.error(f"{self.name} status is {sample}")
|
|
237
|
+
raise
|
|
238
|
+
|
|
239
|
+
def wait_for_dv_success(self, timeout=600, failure_timeout=120):
|
|
240
|
+
self.logger.info(f"Wait DV success for {timeout} seconds")
|
|
241
|
+
self._check_none_pending_status(failure_timeout=failure_timeout)
|
|
242
|
+
self.pvc.wait_for_status(
|
|
243
|
+
status=PersistentVolumeClaim.Status.BOUND, timeout=timeout
|
|
244
|
+
)
|
|
245
|
+
# if garbage collector enabled, the DV deleted once succeeded
|
|
246
|
+
try:
|
|
247
|
+
for sample in TimeoutSampler(
|
|
248
|
+
sleep=1,
|
|
249
|
+
wait_timeout=timeout,
|
|
250
|
+
func=lambda: self.exists,
|
|
251
|
+
):
|
|
252
|
+
# DV reach to success if the status is succeeded or if the DV does not exists
|
|
253
|
+
if sample is None or sample.status.phase == self.Status.SUCCEEDED:
|
|
254
|
+
return
|
|
255
|
+
except TimeoutExpiredError:
|
|
256
|
+
self.logger.error(f"Status of {self.kind} {self.name} is {sample}")
|
|
257
|
+
raise
|
|
258
|
+
|
|
259
|
+
def delete(self, wait=False, timeout=TIMEOUT_4MINUTES, body=None):
|
|
260
|
+
"""
|
|
261
|
+
Delete DataVolume
|
|
262
|
+
|
|
263
|
+
Args:
|
|
264
|
+
wait (bool): True to wait for DataVolume and PVC to be deleted.
|
|
265
|
+
timeout (int): Time to wait for resources deletion
|
|
266
|
+
body (dict): Content to send for delete()
|
|
267
|
+
|
|
268
|
+
Returns:
|
|
269
|
+
bool: True if delete succeeded, False otherwise.
|
|
270
|
+
"""
|
|
271
|
+
# if garbage collector is enabled, DV will be deleted after success
|
|
272
|
+
if self.exists:
|
|
273
|
+
return super().delete(wait=wait, timeout=timeout, body=body)
|
|
274
|
+
else:
|
|
275
|
+
return self.pvc.delete(wait=wait, timeout=timeout, body=body)
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
# -*- coding: utf-8 -*-
|
|
2
|
+
from ocp_resources.constants import PROTOCOL_ERROR_EXCEPTION_DICT, TIMEOUT_4MINUTES
|
|
3
|
+
from ocp_resources.resource import NamespacedResource
|
|
4
|
+
from ocp_resources.utils import TimeoutSampler
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
class Deployment(NamespacedResource):
|
|
8
|
+
"""
|
|
9
|
+
OpenShift Deployment object.
|
|
10
|
+
"""
|
|
11
|
+
|
|
12
|
+
api_group = NamespacedResource.ApiGroup.APPS
|
|
13
|
+
|
|
14
|
+
def scale_replicas(self, replica_count=int):
|
|
15
|
+
"""
|
|
16
|
+
Update replicas in deployment.
|
|
17
|
+
|
|
18
|
+
Args:
|
|
19
|
+
replica_count (int): Number of replicas.
|
|
20
|
+
|
|
21
|
+
Returns:
|
|
22
|
+
Deployment is updated successfully
|
|
23
|
+
"""
|
|
24
|
+
super().to_dict()
|
|
25
|
+
self.res.update({"spec": {"replicas": replica_count}})
|
|
26
|
+
|
|
27
|
+
self.logger.info(f"Set deployment replicas: {replica_count}")
|
|
28
|
+
return self.update(resource_dict=self.res)
|
|
29
|
+
|
|
30
|
+
def wait_for_replicas(self, deployed=True, timeout=TIMEOUT_4MINUTES):
|
|
31
|
+
"""
|
|
32
|
+
Wait until all replicas are updated.
|
|
33
|
+
|
|
34
|
+
Args:
|
|
35
|
+
deployed (bool): True for replicas deployed, False for no replicas.
|
|
36
|
+
timeout (int): Time to wait for the deployment.
|
|
37
|
+
|
|
38
|
+
Raises:
|
|
39
|
+
TimeoutExpiredError: If not availableReplicas is equal to replicas.
|
|
40
|
+
"""
|
|
41
|
+
self.logger.info(f"Wait for {self.kind} {self.name} to be deployed: {deployed}")
|
|
42
|
+
samples = TimeoutSampler(
|
|
43
|
+
wait_timeout=timeout,
|
|
44
|
+
sleep=1,
|
|
45
|
+
exceptions_dict=PROTOCOL_ERROR_EXCEPTION_DICT,
|
|
46
|
+
func=lambda: self.instance,
|
|
47
|
+
)
|
|
48
|
+
for sample in samples:
|
|
49
|
+
if sample:
|
|
50
|
+
status = sample.status
|
|
51
|
+
|
|
52
|
+
spec_replicas = sample.spec.replicas
|
|
53
|
+
total_replicas = status.replicas or 0
|
|
54
|
+
updated_replicas = status.updatedReplicas or 0
|
|
55
|
+
available_replicas = status.availableReplicas or 0
|
|
56
|
+
ready_replicas = status.readyReplicas or 0
|
|
57
|
+
|
|
58
|
+
if (
|
|
59
|
+
(deployed and spec_replicas)
|
|
60
|
+
and spec_replicas
|
|
61
|
+
== updated_replicas
|
|
62
|
+
== available_replicas
|
|
63
|
+
== ready_replicas
|
|
64
|
+
) or not (deployed or spec_replicas or total_replicas):
|
|
65
|
+
return
|
ocp_resources/event.py
ADDED
|
@@ -0,0 +1,114 @@
|
|
|
1
|
+
from ocp_resources.logger import get_logger
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
LOGGER = get_logger(name=__name__)
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
class Event:
|
|
8
|
+
"""
|
|
9
|
+
Allow read and remove K8s events.
|
|
10
|
+
"""
|
|
11
|
+
|
|
12
|
+
api_version = "v1"
|
|
13
|
+
|
|
14
|
+
@classmethod
|
|
15
|
+
def get(
|
|
16
|
+
cls,
|
|
17
|
+
dyn_client,
|
|
18
|
+
namespace=None,
|
|
19
|
+
name=None,
|
|
20
|
+
label_selector=None,
|
|
21
|
+
field_selector=None,
|
|
22
|
+
resource_version=None,
|
|
23
|
+
timeout=None,
|
|
24
|
+
):
|
|
25
|
+
"""
|
|
26
|
+
get - retrieves K8s events.
|
|
27
|
+
|
|
28
|
+
Args:
|
|
29
|
+
dyn_client (DynamicClient): K8s client
|
|
30
|
+
namespace (str): event namespace
|
|
31
|
+
name (str): event name
|
|
32
|
+
label_selector (str): filter events by labels; comma separated string of key=value
|
|
33
|
+
field_selector (str): filter events by fields; comma separated string of key=valueevent fields;
|
|
34
|
+
comma separated string of key=value
|
|
35
|
+
resource_version (str): filter events by their resource's version
|
|
36
|
+
timeout (int): timeout in seconds
|
|
37
|
+
|
|
38
|
+
Returns
|
|
39
|
+
list: event objects
|
|
40
|
+
|
|
41
|
+
example: reading all CSV Warning events in namespace "my-namespace", with reason of "AnEventReason"
|
|
42
|
+
for event in Event.get(
|
|
43
|
+
default_client,
|
|
44
|
+
namespace="my-namespace",
|
|
45
|
+
field_selector="involvedObject.kind==ClusterServiceVersion,type==Warning,reason=AnEventReason",
|
|
46
|
+
timeout=10,
|
|
47
|
+
):
|
|
48
|
+
print(event.object)
|
|
49
|
+
"""
|
|
50
|
+
|
|
51
|
+
LOGGER.info("Reading events")
|
|
52
|
+
LOGGER.debug(
|
|
53
|
+
f"get events parameters: namespace={namespace}, name={name}, label_selector={label_selector}, "
|
|
54
|
+
f"field_selector='{field_selector}', resource_version={resource_version}, timeout={timeout}"
|
|
55
|
+
)
|
|
56
|
+
|
|
57
|
+
event_listener = dyn_client.resources.get(
|
|
58
|
+
api_version=cls.api_version, kind=cls.__name__
|
|
59
|
+
)
|
|
60
|
+
yield from event_listener.watch(
|
|
61
|
+
namespace=namespace,
|
|
62
|
+
name=name,
|
|
63
|
+
label_selector=label_selector,
|
|
64
|
+
field_selector=field_selector,
|
|
65
|
+
resource_version=resource_version,
|
|
66
|
+
timeout=timeout,
|
|
67
|
+
)
|
|
68
|
+
|
|
69
|
+
@classmethod
|
|
70
|
+
def delete_events(
|
|
71
|
+
cls,
|
|
72
|
+
dyn_client,
|
|
73
|
+
namespace=None,
|
|
74
|
+
name=None,
|
|
75
|
+
label_selector=None,
|
|
76
|
+
field_selector=None,
|
|
77
|
+
resource_version=None,
|
|
78
|
+
timeout=None,
|
|
79
|
+
):
|
|
80
|
+
"""
|
|
81
|
+
delete_events - delete K8s events. For example, to cleanup events before test, in order to not get old
|
|
82
|
+
events in the test, in order to prevent false positive test.
|
|
83
|
+
|
|
84
|
+
Args:
|
|
85
|
+
dyn_client (DynamicClient): K8s client
|
|
86
|
+
namespace (str): event namespace
|
|
87
|
+
name (str): event name
|
|
88
|
+
label_selector (str): filter events by labels; comma separated string of key=value
|
|
89
|
+
field_selector (str): filter events by fields; comma separated string of key=valueevent fields;
|
|
90
|
+
comma separated string of key=value
|
|
91
|
+
resource_version (str): filter events by their resource's version
|
|
92
|
+
timeout (int): timeout in seconds
|
|
93
|
+
|
|
94
|
+
Returns
|
|
95
|
+
list: event objects
|
|
96
|
+
|
|
97
|
+
example: deleting all the event with a reason of "AnEventReason", from "my-namespace" namespace
|
|
98
|
+
|
|
99
|
+
def delete_events_before_test(default_client):
|
|
100
|
+
Event.delete_events(default_client, namespace=my-namespace, field_selector="reason=AnEventReason")
|
|
101
|
+
"""
|
|
102
|
+
LOGGER.info("Deleting events")
|
|
103
|
+
LOGGER.debug(
|
|
104
|
+
f"delete_events parameters: namespace={namespace}, name={name}, label_selector={label_selector}, "
|
|
105
|
+
f"field_selector='{field_selector}', resource_version={resource_version}, timeout={timeout}"
|
|
106
|
+
)
|
|
107
|
+
dyn_client.resources.get(api_version=cls.api_version, kind=cls.__name__).delete(
|
|
108
|
+
namespace=namespace,
|
|
109
|
+
name=name,
|
|
110
|
+
label_selector=label_selector,
|
|
111
|
+
field_selector=field_selector,
|
|
112
|
+
resource_version=resource_version,
|
|
113
|
+
timeout=timeout,
|
|
114
|
+
)
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
from ocp_resources.mtv import MTV
|
|
2
|
+
from ocp_resources.resource import NamespacedResource
|
|
3
|
+
|
|
4
|
+
|
|
5
|
+
class ForkliftController(NamespacedResource, MTV):
|
|
6
|
+
"""
|
|
7
|
+
Migration Toolkit For Virtualization (MTV) ForkliftController Resource
|
|
8
|
+
"""
|
|
9
|
+
|
|
10
|
+
api_group = NamespacedResource.ApiGroup.FORKLIFT_KONVEYOR_IO
|