-
Notifications
You must be signed in to change notification settings - Fork 24
Expand file tree
/
Copy pathupdate_image_etag.py
More file actions
155 lines (133 loc) · 5.24 KB
/
Copy pathupdate_image_etag.py
File metadata and controls
155 lines (133 loc) · 5.24 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
"""
Use the Nutanix v4 REST APIs to update a Prism Central image
Requires Prism Central 7.5 or later and AOS 7.5 or later
Author: Chris Rasmussen, Senior Technical Marketing Engineer, Nutanix
Date: February 2026
"""
import requests
import urllib3
import getpass
import argparse
import uuid
import json
import sys
from base64 import b64encode
import rich
"""
suppress warnings about insecure connections
please consider the security implications before doing this in a production environment
"""
urllib3.disable_warnings(urllib3.exceptions.InsecureRequestWarning)
"""
setup the command line parameters
for this example only two parameters are required
- the Prism Central IP address or FQDN
- the Prism Central username; the script will prompt for the user's password
so that it never needs to be stored in plain text
"""
parser = argparse.ArgumentParser()
parser.add_argument("pc_ip", help="Prism Central IP address or FQDN")
parser.add_argument("username", help="Prism Central username")
args = parser.parse_args()
# get the cluster password
cluster_password = getpass.getpass(
prompt="Please enter your Prism Central \
password: ",
stream=None,
)
pc_ip = args.pc_ip
username = args.username
# at current release, the latest Nutanix v4 REST API version is 4.2
api_version = "v4.2"
# make sure the user enters a password
if not cluster_password:
while not cluster_password:
print(
"Password cannot be empty. Please enter a password or Ctrl-C/Ctrl-D to exit."
)
cluster_password = getpass.getpass(
prompt="Please enter your Prism Central password: ", stream=None
)
try:
"""
setup the HTTP Basic Authorization header based on the
supplied username and password
"""
encoded_credentials = b64encode(
bytes(f"{username}:{cluster_password}", encoding="ascii")
).decode("ascii")
auth_header = f"Basic {encoded_credentials}"
# setup the URL that will be used for the API request
url = f"https://{pc_ip}:9440/api/vmm/{api_version}/content/images"
"""
setup the request headers
note the use of {auth_header} i.e. the Basic Authorization
credentials we setup earlier
"""
headers = {
"Accept": "application/json",
"Content-Type": "application/json",
"Authorization": f"{auth_header}",
"cache-control": "no-cache",
}
# submit the request
try:
response = requests.request(
"GET", url, headers=headers, verify=False, timeout=10
)
if response.ok:
# show a total count of images found
print(
f'Total images found: {response.json()["metadata"]["totalAvailableResults"]}'
)
else:
print(f"An error occurred while connecting to {pc_ip}.")
"""
the following line can be uncommented to show
detailed error information
"""
print(response.text)
sys.exit()
# images have been found - update the first image in the list
# to begin, we must retrieve that image's details
existing_image_ext_id = response.json()["data"][0]["extId"]
# get the existing image details
url = f"https://{pc_ip}:9440/api/vmm/{api_version}/content/images/{existing_image_ext_id}"
existing_image = requests.get(url, headers=headers, verify=False, timeout=10)
# get the existing image's resource Etag
existing_image_etag = existing_image.headers["Etag"]
# show image details before continuing
print(f"\nImage name: {existing_image.json()['data']['name']}")
print(f"This image will be renamed to \"{existing_image.json()['data']['name']} - Updated\"\n")
# create a new UUID to be used as the value of the Ntnx-Request-Id header
request_id = str(uuid.uuid1())
# create new headers that include the existing image's resource Etag and Ntnx-Request-Id
headers = {
"Accept": "application/json",
"Content-Type": "application/json",
"Authorization": f"{auth_header}",
"cache-control": "no-cache",
"If-Match": existing_image_etag,
"Ntnx-Request-Id": request_id,
}
# create the image update's JSON request payload
update_payload = existing_image.json()["data"]
# alter the image's name
update_payload["name"] = f'{update_payload["name"]} - Updated'
# update the image
url = f"https://{pc_ip}:9440/api/vmm/{api_version}/content/images/{existing_image_ext_id}"
update = requests.put(url, headers=headers, data=json.dumps(update_payload), verify=False, timeout=10)
errors = [ flag for flag in update.json()['metadata']['flags'] if flag['name'].lower() == 'haserror' and flag['value'] == True]
if errors:
print("An error occurred while updating the image. Full response:")
print(update.json() + "\n")
else:
print("Image update successful.\n")
except Exception as ex:
print(
f"An {type(ex).__name__} exception occurred while \
connecting to {pc_ip}.\nArgument: {ex.args}."
)
# catching all exceptions like this should be generally be avoided
except Exception as e:
print(f"{e}")