codecraftai-restclient-nutanix 1.2.0__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.
- ccai/restclient/nutanix/__init__.py +12 -0
- ccai/restclient/nutanix/apigroups/__init__.py +0 -0
- ccai/restclient/nutanix/apigroups/clustersgroup.py +125 -0
- ccai/restclient/nutanix/apigroups/groupsupport.py +161 -0
- ccai/restclient/nutanix/apigroups/imagesgroup.py +117 -0
- ccai/restclient/nutanix/apigroups/networkgroups.py +307 -0
- ccai/restclient/nutanix/apigroups/projectsgroup.py +160 -0
- ccai/restclient/nutanix/apigroups/snapshotsgroup.py +128 -0
- ccai/restclient/nutanix/apigroups/tasksgroup.py +63 -0
- ccai/restclient/nutanix/apigroups/vmsgroup.py +445 -0
- ccai/restclient/nutanix/apigroups/volumegroupsgroup.py +121 -0
- ccai/restclient/nutanix/aspectsnutanix.py +106 -0
- ccai/restclient/nutanix/exceptions/__init__.py +0 -0
- ccai/restclient/nutanix/exceptions/nutanixexceptions.py +26 -0
- ccai/restclient/nutanix/model/__init__.py +0 -0
- ccai/restclient/nutanix/model/nutanixcategory.py +66 -0
- ccai/restclient/nutanix/model/nutanixcluster.py +65 -0
- ccai/restclient/nutanix/model/nutanixhost.py +68 -0
- ccai/restclient/nutanix/model/nutaniximage.py +80 -0
- ccai/restclient/nutanix/model/nutanixproject.py +68 -0
- ccai/restclient/nutanix/model/nutanixsecuritypolicy.py +68 -0
- ccai/restclient/nutanix/model/nutanixsnapshot.py +80 -0
- ccai/restclient/nutanix/model/nutanixstoragecontainer.py +76 -0
- ccai/restclient/nutanix/model/nutanixsubnet.py +94 -0
- ccai/restclient/nutanix/model/nutanixtaskhandle.py +198 -0
- ccai/restclient/nutanix/model/nutanixtaskstatus.py +136 -0
- ccai/restclient/nutanix/model/nutanixvm.py +120 -0
- ccai/restclient/nutanix/model/nutanixvolumegroup.py +71 -0
- ccai/restclient/nutanix/model/nutanixvpc.py +68 -0
- ccai/restclient/nutanix/nutanixclient.py +612 -0
- ccai/restclient/nutanix/py.typed +0 -0
- ccai/restclient/nutanix/specs/__init__.py +0 -0
- ccai/restclient/nutanix/specs/nutanixspecs.py +350 -0
- codecraftai_restclient_nutanix-1.2.0.dist-info/METADATA +84 -0
- codecraftai_restclient_nutanix-1.2.0.dist-info/RECORD +37 -0
- codecraftai_restclient_nutanix-1.2.0.dist-info/WHEEL +4 -0
- codecraftai_restclient_nutanix-1.2.0.dist-info/licenses/LICENSE.md +204 -0
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
"""
|
|
2
|
+
.. module:: nutanix
|
|
3
|
+
:platform: Darwin, Linux, Unix, Windows
|
|
4
|
+
:synopsis: The ``ccai.restclient.nutanix`` package — the typed,
|
|
5
|
+
aspect-driven Nutanix Prism REST client.
|
|
6
|
+
|
|
7
|
+
.. moduleauthor:: Myron Walker <myron.walker@gmail.com>
|
|
8
|
+
"""
|
|
9
|
+
|
|
10
|
+
__author__ = "Myron Walker"
|
|
11
|
+
__copyright__ = "Copyright 2026, Code Craft AI LLC"
|
|
12
|
+
__credits__ = []
|
|
File without changes
|
|
@@ -0,0 +1,125 @@
|
|
|
1
|
+
"""
|
|
2
|
+
.. module:: clustersgroup
|
|
3
|
+
:platform: Darwin, Linux, Unix, Windows
|
|
4
|
+
:synopsis: Module that contains the :class:`ClustersGroup` and
|
|
5
|
+
:class:`HostsGroup` api groups exposing the Prism Central
|
|
6
|
+
cluster and host enumeration endpoints.
|
|
7
|
+
|
|
8
|
+
.. moduleauthor:: Myron Walker <myron.walker@gmail.com>
|
|
9
|
+
"""
|
|
10
|
+
|
|
11
|
+
__author__ = "Myron Walker"
|
|
12
|
+
__copyright__ = "Copyright 2026, Code Craft AI LLC"
|
|
13
|
+
__credits__ = []
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
from typing import Any, Dict, List
|
|
17
|
+
|
|
18
|
+
from ccai.restclient.base.restapigroup import RestApiGroup
|
|
19
|
+
|
|
20
|
+
from ccai.restclient.nutanix.aspectsnutanix import (
|
|
21
|
+
AspectsNutanix, DEFAULT_NUTANIX_ASPECTS
|
|
22
|
+
)
|
|
23
|
+
from ccai.restclient.nutanix.apigroups.groupsupport import iter_list_entities
|
|
24
|
+
from ccai.restclient.nutanix.model.nutanixcluster import NutanixCluster
|
|
25
|
+
from ccai.restclient.nutanix.model.nutanixhost import NutanixHost
|
|
26
|
+
from ccai.restclient.nutanix.model.nutanixstoragecontainer import (
|
|
27
|
+
NutanixStorageContainer
|
|
28
|
+
)
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
class ClustersGroup(RestApiGroup):
|
|
32
|
+
"""
|
|
33
|
+
:class:`ClustersGroup` exposes the Prism Central cluster and
|
|
34
|
+
storage-container enumeration endpoints.
|
|
35
|
+
"""
|
|
36
|
+
|
|
37
|
+
def list(self, *,
|
|
38
|
+
aspects: AspectsNutanix = DEFAULT_NUTANIX_ASPECTS
|
|
39
|
+
) -> List[NutanixCluster]:
|
|
40
|
+
"""
|
|
41
|
+
Enumerate every cluster managed by Prism Central.
|
|
42
|
+
|
|
43
|
+
:param aspects: Behaviour control for the call.
|
|
44
|
+
|
|
45
|
+
:returns: A list of :class:`NutanixCluster` records.
|
|
46
|
+
"""
|
|
47
|
+
client = self.client
|
|
48
|
+
|
|
49
|
+
def _fetch_page(offset: int, length: int) -> Dict[str, Any]:
|
|
50
|
+
page = client.post_list(entity="clusters", offset=offset,
|
|
51
|
+
length=length, action="list clusters",
|
|
52
|
+
aspects=aspects)
|
|
53
|
+
return page
|
|
54
|
+
|
|
55
|
+
entities = iter_list_entities(fetch_page=_fetch_page, aspects=aspects)
|
|
56
|
+
rtnval: List[NutanixCluster] = []
|
|
57
|
+
for entity in entities:
|
|
58
|
+
rtnval.append(NutanixCluster.from_dict(entity))
|
|
59
|
+
return rtnval
|
|
60
|
+
|
|
61
|
+
def list_storage_containers(self, *,
|
|
62
|
+
aspects: AspectsNutanix = DEFAULT_NUTANIX_ASPECTS
|
|
63
|
+
) -> List[NutanixStorageContainer]:
|
|
64
|
+
"""
|
|
65
|
+
Enumerate every storage container known to Prism Central.
|
|
66
|
+
|
|
67
|
+
:param aspects: Behaviour control for the call.
|
|
68
|
+
|
|
69
|
+
:returns: A list of :class:`NutanixStorageContainer` records.
|
|
70
|
+
"""
|
|
71
|
+
client = self.client
|
|
72
|
+
|
|
73
|
+
def _fetch_page(offset: int, length: int) -> Dict[str, Any]:
|
|
74
|
+
page = client.post_list(entity="storage_containers",
|
|
75
|
+
offset=offset, length=length,
|
|
76
|
+
action="list storage containers",
|
|
77
|
+
aspects=aspects)
|
|
78
|
+
return page
|
|
79
|
+
|
|
80
|
+
entities = iter_list_entities(fetch_page=_fetch_page, aspects=aspects)
|
|
81
|
+
rtnval: List[NutanixStorageContainer] = []
|
|
82
|
+
for entity in entities:
|
|
83
|
+
rtnval.append(NutanixStorageContainer.from_dict(entity))
|
|
84
|
+
return rtnval
|
|
85
|
+
|
|
86
|
+
|
|
87
|
+
class HostsGroup(RestApiGroup):
|
|
88
|
+
"""
|
|
89
|
+
:class:`HostsGroup` exposes the Prism Central host enumeration
|
|
90
|
+
endpoint.
|
|
91
|
+
"""
|
|
92
|
+
|
|
93
|
+
def list(self, *, cluster_uuid: str,
|
|
94
|
+
aspects: AspectsNutanix = DEFAULT_NUTANIX_ASPECTS
|
|
95
|
+
) -> List[NutanixHost]:
|
|
96
|
+
"""
|
|
97
|
+
Enumerate the hosts belonging to a cluster.
|
|
98
|
+
|
|
99
|
+
:param cluster_uuid: The cluster uuid to filter hosts by.
|
|
100
|
+
:param aspects: Behaviour control for the call.
|
|
101
|
+
|
|
102
|
+
:returns: A list of :class:`NutanixHost` records.
|
|
103
|
+
"""
|
|
104
|
+
client = self.client
|
|
105
|
+
|
|
106
|
+
def _fetch_page(offset: int, length: int) -> Dict[str, Any]:
|
|
107
|
+
page = client.post_list(entity="hosts", offset=offset,
|
|
108
|
+
length=length, action="list hosts",
|
|
109
|
+
aspects=aspects)
|
|
110
|
+
return page
|
|
111
|
+
|
|
112
|
+
entities = iter_list_entities(fetch_page=_fetch_page, aspects=aspects)
|
|
113
|
+
rtnval: List[NutanixHost] = []
|
|
114
|
+
for entity in entities:
|
|
115
|
+
host = NutanixHost.from_dict(entity)
|
|
116
|
+
status = entity.get("status", {})
|
|
117
|
+
cluster_ref = status.get("cluster_reference", {})
|
|
118
|
+
host_cluster = cluster_ref.get("uuid", None)
|
|
119
|
+
if cluster_uuid is None or len(cluster_uuid) == 0:
|
|
120
|
+
rtnval.append(host)
|
|
121
|
+
elif host_cluster == cluster_uuid:
|
|
122
|
+
rtnval.append(host)
|
|
123
|
+
elif host_cluster is None:
|
|
124
|
+
rtnval.append(host)
|
|
125
|
+
return rtnval
|
|
@@ -0,0 +1,161 @@
|
|
|
1
|
+
"""
|
|
2
|
+
.. module:: groupsupport
|
|
3
|
+
:platform: Darwin, Linux, Unix, Windows
|
|
4
|
+
:synopsis: Module that contains shared helpers used by the Nutanix
|
|
5
|
+
Prism Central api-group classes.
|
|
6
|
+
|
|
7
|
+
.. moduleauthor:: Myron Walker <myron.walker@gmail.com>
|
|
8
|
+
"""
|
|
9
|
+
|
|
10
|
+
__author__ = "Myron Walker"
|
|
11
|
+
__copyright__ = "Copyright 2026, Code Craft AI LLC"
|
|
12
|
+
__credits__ = []
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
import os
|
|
16
|
+
|
|
17
|
+
from typing import Any, Callable, Dict, List
|
|
18
|
+
from urllib.parse import quote
|
|
19
|
+
|
|
20
|
+
from requests import Response
|
|
21
|
+
|
|
22
|
+
from ccai.errors.exceptions import SemanticError
|
|
23
|
+
|
|
24
|
+
from ccai.restclient.nutanix.aspectsnutanix import AspectsNutanix
|
|
25
|
+
from ccai.restclient.nutanix.exceptions.nutanixexceptions import (
|
|
26
|
+
NutanixAuthenticationError
|
|
27
|
+
)
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
def encode_segment(*, segment: str) -> str:
|
|
31
|
+
"""
|
|
32
|
+
Percent-encode a single URL path segment.
|
|
33
|
+
|
|
34
|
+
Empty or ``None`` identifiers are rejected — a missing identifier
|
|
35
|
+
is an API-misuse condition, not a runtime error.
|
|
36
|
+
|
|
37
|
+
:param segment: The raw path segment.
|
|
38
|
+
|
|
39
|
+
:returns: The percent-encoded segment.
|
|
40
|
+
|
|
41
|
+
:raises: :class:`SemanticError` when the segment is empty/None.
|
|
42
|
+
"""
|
|
43
|
+
if segment is None:
|
|
44
|
+
raise SemanticError("URL path segment must not be None.")
|
|
45
|
+
if len(segment) == 0:
|
|
46
|
+
raise SemanticError("URL path segment must not be empty.")
|
|
47
|
+
|
|
48
|
+
rtnval = quote(segment, safe="")
|
|
49
|
+
return rtnval
|
|
50
|
+
|
|
51
|
+
|
|
52
|
+
def compose_leaf(*, base: str, parts: List[str]) -> str:
|
|
53
|
+
"""
|
|
54
|
+
Compose a Prism Central API leaf from a base prefix and per-segment
|
|
55
|
+
identifiers. Each identifier is percent-encoded independently.
|
|
56
|
+
|
|
57
|
+
:param base: The base leaf (e.g. ``/api/nutanix/v3/vms``).
|
|
58
|
+
:param parts: Trailing path identifiers (uuids, action names).
|
|
59
|
+
|
|
60
|
+
:returns: The composed leaf path beginning with ``/``.
|
|
61
|
+
|
|
62
|
+
:raises: :class:`SemanticError` when ``parts`` carries an empty
|
|
63
|
+
identifier.
|
|
64
|
+
"""
|
|
65
|
+
if base is None or len(base) == 0:
|
|
66
|
+
raise SemanticError("compose_leaf requires a non-empty base.")
|
|
67
|
+
|
|
68
|
+
leaf = base
|
|
69
|
+
if parts is not None:
|
|
70
|
+
for part in parts:
|
|
71
|
+
encoded = encode_segment(segment=part)
|
|
72
|
+
leaf = leaf + "/" + encoded
|
|
73
|
+
|
|
74
|
+
rtnval = leaf
|
|
75
|
+
return rtnval
|
|
76
|
+
|
|
77
|
+
|
|
78
|
+
def raise_for_status(*, response: Response, action: str) -> None:
|
|
79
|
+
"""
|
|
80
|
+
Raise a descriptive error for a non-2xx Prism Central response.
|
|
81
|
+
|
|
82
|
+
HTTP 401 / 403 are reclassified into
|
|
83
|
+
:class:`NutanixAuthenticationError`; every other non-2xx becomes a
|
|
84
|
+
:class:`SemanticError`.
|
|
85
|
+
|
|
86
|
+
:param response: The :class:`Response` to inspect.
|
|
87
|
+
:param action: A short description of the attempted action.
|
|
88
|
+
|
|
89
|
+
:returns: ``None``.
|
|
90
|
+
|
|
91
|
+
:raises: :class:`NutanixAuthenticationError`,
|
|
92
|
+
:class:`SemanticError`.
|
|
93
|
+
"""
|
|
94
|
+
status = response.status_code
|
|
95
|
+
if 200 <= status < 300:
|
|
96
|
+
return
|
|
97
|
+
|
|
98
|
+
if status in (401, 403):
|
|
99
|
+
err_msg_lines = ["Nutanix Prism Central rejected the credential."]
|
|
100
|
+
err_msg_lines.append("ACTION: {}".format(action))
|
|
101
|
+
err_msg_lines.append("STATUS: {}".format(status))
|
|
102
|
+
err_msg_lines.append("RESPONSE:")
|
|
103
|
+
err_msg_lines.append(response.text)
|
|
104
|
+
err_msg = os.linesep.join(err_msg_lines)
|
|
105
|
+
raise NutanixAuthenticationError(err_msg)
|
|
106
|
+
|
|
107
|
+
err_msg_lines = ["Nutanix Prism Central API call failed: {}.".format(
|
|
108
|
+
action
|
|
109
|
+
)]
|
|
110
|
+
err_msg_lines.append("STATUS: {}".format(status))
|
|
111
|
+
err_msg_lines.append("RESPONSE:")
|
|
112
|
+
err_msg_lines.append(response.text)
|
|
113
|
+
err_msg = os.linesep.join(err_msg_lines)
|
|
114
|
+
raise SemanticError(err_msg)
|
|
115
|
+
|
|
116
|
+
|
|
117
|
+
def iter_list_entities(*, fetch_page: Callable[[int, int], Dict[str, Any]],
|
|
118
|
+
aspects: AspectsNutanix) -> List[Dict[str, Any]]:
|
|
119
|
+
"""
|
|
120
|
+
Walk a Prism Central ``*/list`` endpoint, following the offset
|
|
121
|
+
cursor until every entity has been collected.
|
|
122
|
+
|
|
123
|
+
Prism v3 ``*/list`` endpoints accept an offset/length body and
|
|
124
|
+
return ``{"metadata": {"total_matches": N, "offset": O, ...},
|
|
125
|
+
"entities": [...]}``. This helper pages by offset using the page
|
|
126
|
+
length from ``aspects`` until the collected count reaches
|
|
127
|
+
``total_matches`` (or a page returns no entities).
|
|
128
|
+
|
|
129
|
+
:param fetch_page: Callable accepting ``(offset, length)`` and
|
|
130
|
+
returning the parsed page dict.
|
|
131
|
+
:param aspects: Behaviour control supplying the page length.
|
|
132
|
+
|
|
133
|
+
:returns: A list of raw entity dicts in traversal order.
|
|
134
|
+
"""
|
|
135
|
+
page_length = aspects.page_length
|
|
136
|
+
if page_length <= 0:
|
|
137
|
+
raise SemanticError("AspectsNutanix.page_length must be > 0.")
|
|
138
|
+
|
|
139
|
+
collected: List[Dict[str, Any]] = []
|
|
140
|
+
offset = 0
|
|
141
|
+
while True:
|
|
142
|
+
page = fetch_page(offset, page_length)
|
|
143
|
+
|
|
144
|
+
entities = page.get("entities", None)
|
|
145
|
+
if entities is None:
|
|
146
|
+
entities = []
|
|
147
|
+
for entity in entities:
|
|
148
|
+
collected.append(entity)
|
|
149
|
+
|
|
150
|
+
page_metadata = page.get("metadata", {})
|
|
151
|
+
total_matches = page_metadata.get("total_matches", None)
|
|
152
|
+
|
|
153
|
+
if len(entities) == 0:
|
|
154
|
+
break
|
|
155
|
+
if total_matches is not None and len(collected) >= total_matches:
|
|
156
|
+
break
|
|
157
|
+
|
|
158
|
+
offset = offset + page_length
|
|
159
|
+
|
|
160
|
+
rtnval = collected
|
|
161
|
+
return rtnval
|
|
@@ -0,0 +1,117 @@
|
|
|
1
|
+
"""
|
|
2
|
+
.. module:: imagesgroup
|
|
3
|
+
:platform: Darwin, Linux, Unix, Windows
|
|
4
|
+
:synopsis: Module that contains the :class:`ImagesGroup` api group
|
|
5
|
+
for the Prism Central image catalog.
|
|
6
|
+
|
|
7
|
+
.. moduleauthor:: Myron Walker <myron.walker@gmail.com>
|
|
8
|
+
"""
|
|
9
|
+
|
|
10
|
+
__author__ = "Myron Walker"
|
|
11
|
+
__copyright__ = "Copyright 2026, Code Craft AI LLC"
|
|
12
|
+
__credits__ = []
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
from typing import Any, Dict, List, Optional
|
|
16
|
+
|
|
17
|
+
from ccai.restclient.base.restapigroup import RestApiGroup
|
|
18
|
+
|
|
19
|
+
from ccai.restclient.nutanix.aspectsnutanix import (
|
|
20
|
+
AspectsNutanix, DEFAULT_NUTANIX_ASPECTS
|
|
21
|
+
)
|
|
22
|
+
from ccai.restclient.nutanix.apigroups.groupsupport import iter_list_entities
|
|
23
|
+
from ccai.restclient.nutanix.model.nutaniximage import NutanixImage
|
|
24
|
+
from ccai.restclient.nutanix.model.nutanixtaskhandle import NutanixTaskHandle
|
|
25
|
+
from ccai.restclient.nutanix.specs.nutanixspecs import ImageSpec
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
class ImagesGroup(RestApiGroup):
|
|
29
|
+
"""
|
|
30
|
+
:class:`ImagesGroup` exposes the Prism Central image-catalog
|
|
31
|
+
endpoints — upload, list (paged), and idempotent delete.
|
|
32
|
+
"""
|
|
33
|
+
|
|
34
|
+
def list(self, *,
|
|
35
|
+
aspects: AspectsNutanix = DEFAULT_NUTANIX_ASPECTS
|
|
36
|
+
) -> List[NutanixImage]:
|
|
37
|
+
"""
|
|
38
|
+
Enumerate every image in the Prism Central catalog.
|
|
39
|
+
|
|
40
|
+
:param aspects: Behaviour control for the call.
|
|
41
|
+
|
|
42
|
+
:returns: A list of :class:`NutanixImage` records.
|
|
43
|
+
"""
|
|
44
|
+
client = self.client
|
|
45
|
+
|
|
46
|
+
def _fetch_page(offset: int, length: int) -> Dict[str, Any]:
|
|
47
|
+
page = client.post_list(entity="images", offset=offset,
|
|
48
|
+
length=length, action="list images",
|
|
49
|
+
aspects=aspects)
|
|
50
|
+
return page
|
|
51
|
+
|
|
52
|
+
entities = iter_list_entities(fetch_page=_fetch_page, aspects=aspects)
|
|
53
|
+
rtnval: List[NutanixImage] = []
|
|
54
|
+
for entity in entities:
|
|
55
|
+
rtnval.append(NutanixImage.from_dict(entity))
|
|
56
|
+
return rtnval
|
|
57
|
+
|
|
58
|
+
def find_by_name(self, *, name: str,
|
|
59
|
+
aspects: AspectsNutanix = DEFAULT_NUTANIX_ASPECTS
|
|
60
|
+
) -> Optional[NutanixImage]:
|
|
61
|
+
"""
|
|
62
|
+
Return the image with the given name, or ``None``.
|
|
63
|
+
|
|
64
|
+
:param name: The image name to match.
|
|
65
|
+
:param aspects: Behaviour control for the call.
|
|
66
|
+
|
|
67
|
+
:returns: A :class:`NutanixImage` or ``None``.
|
|
68
|
+
"""
|
|
69
|
+
for image in self.list(aspects=aspects):
|
|
70
|
+
if image.name == name:
|
|
71
|
+
rtnval: Optional[NutanixImage] = image
|
|
72
|
+
return rtnval
|
|
73
|
+
rtnval = None
|
|
74
|
+
return rtnval
|
|
75
|
+
|
|
76
|
+
def upload(self, *, spec: ImageSpec,
|
|
77
|
+
aspects: AspectsNutanix = DEFAULT_NUTANIX_ASPECTS
|
|
78
|
+
) -> NutanixTaskHandle:
|
|
79
|
+
"""
|
|
80
|
+
Upload (register) an image from an intent spec.
|
|
81
|
+
|
|
82
|
+
Read-before-create: when an image of the same name already
|
|
83
|
+
exists, an already-completed task handle wrapping its uuid is
|
|
84
|
+
returned.
|
|
85
|
+
|
|
86
|
+
:param spec: The :class:`ImageSpec` intent spec.
|
|
87
|
+
:param aspects: Behaviour control for the call.
|
|
88
|
+
|
|
89
|
+
:returns: A :class:`NutanixTaskHandle`.
|
|
90
|
+
"""
|
|
91
|
+
existing = self.find_by_name(name=spec.name, aspects=aspects)
|
|
92
|
+
client = self.client
|
|
93
|
+
if existing is not None:
|
|
94
|
+
rtnval = client.completed_handle_for_entity(
|
|
95
|
+
entity_uuid=existing.uuid
|
|
96
|
+
)
|
|
97
|
+
return rtnval
|
|
98
|
+
|
|
99
|
+
payload = spec.to_payload()
|
|
100
|
+
rtnval = client.post_intent(entity="images", payload=payload,
|
|
101
|
+
action="upload image", aspects=aspects)
|
|
102
|
+
return rtnval
|
|
103
|
+
|
|
104
|
+
def delete(self, *, image_uuid: str,
|
|
105
|
+
aspects: AspectsNutanix = DEFAULT_NUTANIX_ASPECTS
|
|
106
|
+
) -> None:
|
|
107
|
+
"""
|
|
108
|
+
Delete an image by uuid; an unknown uuid is a no-op.
|
|
109
|
+
|
|
110
|
+
:param image_uuid: The image uuid.
|
|
111
|
+
:param aspects: Behaviour control for the call.
|
|
112
|
+
|
|
113
|
+
:returns: ``None``.
|
|
114
|
+
"""
|
|
115
|
+
self.client.delete_intent(entity="images", entity_uuid=image_uuid,
|
|
116
|
+
action="delete image", aspects=aspects)
|
|
117
|
+
return
|