Skip to content

Commit 8d6b184

Browse files
author
William Lam
committed
Updated Marvel VM Create Script
1 parent 815281c commit 8d6b184

File tree

1 file changed

+173
-125
lines changed

1 file changed

+173
-125
lines changed

python/create_random_marvel_vms.py

Lines changed: 173 additions & 125 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
1-
#!/usr/bin/env python
1+
22
# Author: William Lam
33
# Website: www.williamlam.com
44
# Product: VMware vSphere
5-
# Description: vSphere SDK for Python program for creating tiny VMs (1vCPU/128MB) with random names using the Marvel Commics API
5+
# Description: vSphere SDK for Python (pyvmomi) program for creating tiny VMs (1vCPU/128MB) with random names using the Marvel Comics API
66
# Reference: http://www.williamlam.com/2014/02/having-some-fun-with-marvel-comics-api.html
77

88
"""
@@ -11,6 +11,8 @@
1111

1212
from optparse import OptionParser, make_option
1313
from pyVim.connect import SmartConnect, Disconnect
14+
from pyVmomi import vim, VmomiSupport
15+
from requests.packages.urllib3.exceptions import InsecureRequestWarning
1416
from pyVmomi import vmodl
1517
from pyVmomi import vim
1618
from pprint import pprint
@@ -23,156 +25,202 @@
2325
import argparse
2426
import atexit
2527
import sys
28+
import string
29+
import ssl
2630

2731
# Marvel API keys
2832
marvel_public_key = ''
2933
marvel_private_key = ''
3034

3135
def GetArgs():
32-
"""
33-
Supports the command-line arguments listed below.
34-
"""
35-
parser = argparse.ArgumentParser(description='Process args for retrieving all the Virtual Machines')
36-
parser.add_argument('-s', '--host', required=True, action='store', help='Remote host to connect to')
37-
parser.add_argument('-o', '--port', type=int, default=443, action='store', help='Port to connect on')
38-
parser.add_argument('-u', '--user', required=True, action='store', help='User name to use when connecting to host')
39-
parser.add_argument('-p', '--password', required=True, action='store', help='Password to use when connecting to host')
40-
parser.add_argument('-c', '--count', required=True, action='store', help='Number of VMs to create')
41-
parser.add_argument('-d', '--datastore', required=True, action='store', help='Name of Datastore to create VM in')
42-
args = parser.parse_args()
43-
return args
36+
"""
37+
Supports the command-line arguments listed below.
38+
"""
39+
parser = argparse.ArgumentParser(
40+
description='Process args for retrieving all the Virtual Machines')
41+
parser.add_argument('-s', '--host', required=True,
42+
action='store', help='Remote host to connect to')
43+
parser.add_argument('-o', '--port', type=int, default=443,
44+
action='store', help='Port to connect on')
45+
parser.add_argument('-u', '--user', required=True, action='store',
46+
help='User name to use when connecting to host')
47+
parser.add_argument('-p', '--password', required=True,
48+
action='store', help='Password to use when connecting to host')
49+
parser.add_argument('-c', '--count', required=True,
50+
action='store', help='Number of VMs to create')
51+
parser.add_argument('-d', '--datastore', required=True,
52+
action='store', help='Name of Datastore to create VM in')
53+
parser.add_argument('-e', '--datacenter', required=True,
54+
action='store', help='Name of Datastore to create VM in')
55+
parser.add_argument('-f', '--opid', default='create-marvel-vm',
56+
action='store', help='Name of Datastore to create VM in')
57+
args = parser.parse_args()
58+
return args
59+
60+
def find_datacenter(service_instance, datacenter_name):
61+
content = service_instance.RetrieveContent()
62+
63+
# Traverse the inventory hierarchy starting from the root folder
64+
for child_entity in content.rootFolder.childEntity:
65+
if isinstance(child_entity, vim.Datacenter):
66+
if child_entity.name == datacenter_name:
67+
return child_entity
68+
69+
# Datacenter not found
70+
return None
4471

4572
def getMarvelCharacters(number_of_characters):
4673
timestamp = str(int(time.time()))
4774
# hash is required as part of request which is md5(timestamp + private + public key)
48-
hash_value = hashlib.md5(timestamp + marvel_private_key + marvel_public_key).hexdigest()
75+
hash_value = hashlib.md5(
76+
(timestamp + marvel_private_key + marvel_public_key).encode('utf-8')).hexdigest()
4977

5078
characters = []
51-
for x in xrange(number_of_characters):
52-
#randomly select one of the 1402 Marvel character
53-
offset = random.randrange(1,1402)
79+
for x in range(number_of_characters):
80+
# randomly select one of the 1402 Marvel character
81+
offset = random.randrange(1, 1402)
5482
limit = '1'
5583

5684
# GET /v1/public/characters
57-
url = 'http://gateway.marvel.com:80/v1/public/characters?limit=' + limit + '&offset=' + str(offset) + '&apikey=' + marvel_public_key + '&ts=' + timestamp + '&hash=' + hash_value
58-
headers = {'content-type':'application/json'}
85+
url = 'http://gateway.marvel.com:80/v1/public/characters?limit=' + limit + '&offset=' + \
86+
str(offset) + '&apikey=' + marvel_public_key + \
87+
'&ts=' + timestamp + '&hash=' + hash_value
88+
headers = {'content-type': 'application/json'}
5989
request = requests.get(url, headers=headers)
6090
data = json.loads(request.content)
6191
# retrieve character name & replace spaces with underscore so we don't have stupid spaces in our VM names
62-
character = data['data']['results'][0]['name'].strip().replace(' ','_')
63-
characters.append(character)
92+
character = 'marvelvm-' + \
93+
data['data']['results'][0]['name'].strip().replace(' ', '_')
94+
characters.append(character.lower())
6495
return characters
6596

66-
def CreateDummyVM(name,si,vmFolder,rp,datastore):
67-
vmName = 'MARVEL-' + name
68-
datastorePath = '[' + datastore + '] ' + vmName
97+
def CreateDummyVM(name, si, vmFolder, rp, datastore):
98+
datastorePath = f"[{datastore}]"
6999

70-
# bare minimum VM shell, no disks. Feel free to edit
71-
file = vim.vm.FileInfo(logDirectory=None,snapshotDirectory=None,suspendDirectory=None,vmPathName=datastorePath)
72-
config = vim.vm.ConfigSpec(name=vmName, memoryMB=128, numCPUs=1, files=file, guestId='dosGuest', version='vmx-07')
100+
# bare minimum VM shell, no disks. Feel free to edit
101+
file = vim.vm.FileInfo(logDirectory=None, snapshotDirectory=None,
102+
suspendDirectory=None, vmPathName=datastorePath)
103+
config = vim.vm.ConfigSpec(
104+
name=name, memoryMB=128, numCPUs=1, files=file, guestId='dosGuest', version='vmx-13')
73105

74-
print "Creating VM " + vmName + " ..."
75-
task = vmFolder.CreateVM_Task(config=config,pool=rp)
76-
WaitForTasks([task],si)
106+
print("Creating VM " + name + " ...")
107+
task = vmFolder.CreateVM_Task(config=config, pool=rp)
108+
WaitForTasks([task], si)
77109

78110
# borrowed from poweronvm.py sample
79111
def WaitForTasks(tasks, si):
80-
"""
81-
Given the service instance si and tasks, it returns after all the
82-
tasks are complete
83-
"""
84-
85-
pc = si.content.propertyCollector
86-
87-
taskList = [str(task) for task in tasks]
88-
89-
# Create filter
90-
objSpecs = [vmodl.query.PropertyCollector.ObjectSpec(obj=task)
91-
for task in tasks]
92-
propSpec = vmodl.query.PropertyCollector.PropertySpec(type=vim.Task,
93-
pathSet=[], all=True)
94-
filterSpec = vmodl.query.PropertyCollector.FilterSpec()
95-
filterSpec.objectSet = objSpecs
96-
filterSpec.propSet = [propSpec]
97-
filter = pc.CreateFilter(filterSpec, True)
98-
99-
try:
100-
version, state = None, None
101-
102-
# Loop looking for updates till the state moves to a completed state.
103-
while len(taskList):
104-
update = pc.WaitForUpdates(version)
105-
for filterSet in update.filterSet:
106-
for objSet in filterSet.objectSet:
107-
task = objSet.obj
108-
for change in objSet.changeSet:
109-
if change.name == 'info':
110-
state = change.val.state
111-
elif change.name == 'info.state':
112-
state = change.val
113-
else:
114-
continue
115-
116-
if not str(task) in taskList:
117-
continue
118-
119-
if state == vim.TaskInfo.State.success:
120-
# Remove task from taskList
121-
taskList.remove(str(task))
122-
elif state == vim.TaskInfo.State.error:
123-
raise task.info.error
124-
# Move to next version
125-
version = update.version
126-
finally:
127-
if filter:
128-
filter.Destroy()
112+
"""
113+
Given the service instance si and tasks, it returns after all the
114+
tasks are complete
115+
"""
116+
117+
pc = si.content.propertyCollector
118+
119+
taskList = [str(task) for task in tasks]
120+
121+
# Create filter
122+
objSpecs = [vmodl.query.PropertyCollector.ObjectSpec(obj=task)
123+
for task in tasks]
124+
propSpec = vmodl.query.PropertyCollector.PropertySpec(type=vim.Task, pathSet=[], all=True)
125+
filterSpec = vmodl.query.PropertyCollector.FilterSpec()
126+
filterSpec.objectSet = objSpecs
127+
filterSpec.propSet = [propSpec]
128+
filter = pc.CreateFilter(filterSpec, True)
129+
130+
try:
131+
version, state = None, None
132+
133+
# Loop looking for updates till the state moves to a completed state.
134+
while len(taskList):
135+
update = pc.WaitForUpdates(version)
136+
for filterSet in update.filterSet:
137+
for objSet in filterSet.objectSet:
138+
task = objSet.obj
139+
for change in objSet.changeSet:
140+
if change.name == 'info':
141+
state = change.val.state
142+
elif change.name == 'info.state':
143+
state = change.val
144+
else:
145+
continue
146+
147+
if not str(task) in taskList:
148+
continue
149+
150+
if state == vim.TaskInfo.State.success:
151+
# Remove task from taskList
152+
taskList.remove(str(task))
153+
elif state == vim.TaskInfo.State.error:
154+
raise task.info.error
155+
# Move to next version
156+
version = update.version
157+
finally:
158+
if filter:
159+
filter.Destroy()
129160

130161
def main():
131-
"""
132-
Simple command-line program for creating Dummy VM based on Marvel character names
133-
"""
134-
135-
# Ensure user sets up Marvel API keys
136-
if marvel_public_key == '' or marvel_private_key == '':
137-
print "\nPlease configure your Marvel Public/Private API Key by setting marvel_public_key and marvel_private_key variable\n"
138-
return -1
139-
140-
args = GetArgs()
141-
try:
142-
si = None
143-
try:
144-
si = SmartConnect(host=args.host,
145-
user=args.user,
146-
pwd=args.password,
147-
port=int(args.port))
148-
except IOError, e:
149-
pass
150-
if not si:
151-
print "Could not connect to the specified host using specified username and password"
152-
return -1
153-
154-
atexit.register(Disconnect, si)
155-
156-
content = si.RetrieveContent()
157-
datacenter = content.rootFolder.childEntity[0]
158-
vmFolder = datacenter.vmFolder
159-
hosts = datacenter.hostFolder.childEntity
160-
rp = hosts[0].resourcePool
161-
162-
print "Connecting to Marvel API and retrieving " + args.count + " random character(s) ..."
163-
characters = getMarvelCharacters(int(args.count))
164-
165-
for name in characters:
166-
CreateDummyVM(name,si,vmFolder,rp,args.datastore)
167-
168-
except vmodl.MethodFault, e:
169-
print "Caught vmodl fault : " + e.msg
170-
return -1
171-
except Exception, e:
172-
print "Caught exception : " + str(e)
173-
return -1
174-
175-
return 0
162+
"""
163+
Simple command-line program for creating Dummy VM based on Marvel character names
164+
"""
165+
166+
args = GetArgs()
167+
168+
# Set custom OpID for this connection
169+
reqCtx = VmomiSupport.GetRequestContext()
170+
reqCtx["operationID"] = args.opid
171+
172+
try:
173+
context = None
174+
try:
175+
if sys.version_info[:3] > (2, 7, 8):
176+
context = ssl.create_default_context()
177+
context.check_hostname = False
178+
context.verify_mode = ssl.CERT_NONE
179+
180+
# Disabling the annoying InsecureRequestWarning message
181+
requests.packages.urllib3.disable_warnings(InsecureRequestWarning)
182+
183+
si = SmartConnect(host=args.host,
184+
user=args.user,
185+
pwd=args.password,
186+
port=int(args.port),
187+
sslContext=context)
188+
except IOError as e:
189+
pass
190+
if not si:
191+
print(
192+
"Could not connect to the specified host using specified username and password")
193+
return -1
194+
195+
atexit.register(Disconnect, si)
196+
197+
content = si.RetrieveContent()
198+
dc = find_datacenter(si, args.datacenter)
199+
vmFolder = dc.vmFolder
200+
hosts = dc.hostFolder.childEntity
201+
rp = hosts[0].resourcePool
202+
203+
# Ensure user sets up Marvel API keys
204+
if marvel_public_key == '' or marvel_private_key == '':
205+
print("\nPlease configure your Marvel Public/Private API Key by setting marvel_public_key and marvel_private_key variable\n")
206+
print("Generating random VM name for now ...")
207+
characters = ['randomvm-' + ''.join(random.choice(string.ascii_letters)
208+
for _ in range(10)) for _ in range(int(args.count))]
209+
else:
210+
print("Connecting to Marvel API and retrieving " + args.count + " random character(s) ...")
211+
characters = getMarvelCharacters(int(args.count))
212+
213+
for name in characters:
214+
CreateDummyVM(name, si, vmFolder, rp, args.datastore)
215+
216+
except vmodl.MethodFault as e:
217+
print("Caught vmodl fault : " + e.msg)
218+
return -1
219+
except Exception as e:
220+
print("Caught exception : " + str(e))
221+
return -1
222+
223+
return 0
176224

177225
# Start program
178226
if __name__ == "__main__":

0 commit comments

Comments
 (0)