Skip to content

Instantly share code, notes, and snippets.

@jnovack
Created March 31, 2018 13:21
Show Gist options
  • Star 2 You must be signed in to star a gist
  • Fork 2 You must be signed in to fork a gist
  • Save jnovack/47e54b92871db9ca48681e0d9a40615e to your computer and use it in GitHub Desktop.
Save jnovack/47e54b92871db9ca48681e0d9a40615e to your computer and use it in GitHub Desktop.
ovfenv
#!/usr/bin/python
#
# Copyright 2011 VMware, Inc. All rights reserved.
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal
# in the Software without restriction, including without limitation the rights
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
# copies of the Software, and to permit persons to whom the Software is
# furnished to do so, subject to the following conditions:
#
# The above copyright notice and this permission notice shall be included in
# all copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
# THE SOFTWARE.
#
#
#
# Show the value of an OVF property, whether the properties
# were presented to this VM in guestinfo, on a cdrom, or
# in Studio's default file.
#
# Optionally, allows a property value to be modified. In that
# case, the guestinfo structure is modified, and Studio's
# default file is also updated.
#
#
# Examples of usage:
#
# ovfenv
# shows all the properties in id[key]=value format
#
#
# ovfenv --dump
# dumps the raw XML to stdout
#
#
# ovfenv --key vm.name
#
# shows the local VM's value for the property named
# vm.name, which is equivalent to
#
# ovfenv --key [vm.name]
#
#
# ovfenv --key Property_1 --id ubuntu8044
#
# shows the VM named ubuntu8044's value for the property
# named Property_1, which is equivalent to
#
# ovfenv --key ubuntu8044[Property_1]
#
#
# ovfenv --key vm.email --value foo@bar.com
#
# sets the value of the local VM's property named
# vm.email to foo@bar.com, which is equivalent to
#
# ovfenv --key [vm.email]=foo@bar.com
#
#
# ovfenv --key vm.password --value ''
#
# clears the value of the local VM's property named
# vm.password, which is equivalent to
#
# ovfenv --key [vm.password]=
#
import sys
import os
import libxml2
import getopt
import subprocess
import tempfile
import gettext
__t = gettext.translation('ovfenv', '/opt/vmware/lib/locale', fallback=True)
_ = __t.ugettext
debug = False
quiet = False
#
# Xpath expressions
#
XPATH_ENVIRONMENT = "//o:Environment"
XPATH_PROPERTY = "/o:PropertySection/o:Property"
XPATH_MYPROPERTY = XPATH_ENVIRONMENT + XPATH_PROPERTY
XPATH_ENTITY = XPATH_ENVIRONMENT + "/o:Entity"
XPATH_ENTITYID = XPATH_ENTITY + "[@oe:id='"
XPATH_KEY = "key"
XPATH_NSKEY = "@oe:" + XPATH_KEY
XPATH_VALUE = "value"
XPATH_NSVALUE = "oe:value"
XPATH_ID = "id"
#
# Various unavoidable shell commands
#
VMTOOLS_PATH = '/usr/lib/vmware-tools/sbin:/usr/sbin'
GET_GUESTINFO = ["vmware-rpctool", "'info-get guestinfo.ovfEnv'"]
SET_GUESTINFO = ["vmware-rpctool", "info-set guestinfo.ovfEnv "]
MOUNTCD = ["/bin/mount", "-r"]
UNMOUNTCD = ["/bin/umount"]
#
# pathnames
#
OVFENV = "ovf-env.xml"
CDDRIVES = "/proc/sys/dev/cdrom/info"
STUDIOENVCOPY = "/opt/vmware/etc/vami/ovfEnv.xml"
#
# Namespaces
#
NSDICT = \
{
'o' : "http://schemas.dmtf.org/ovf/environment/1",
'xsi' : "http://www.w3.org/2001/XMLSchema-instance",
'oe' : "http://schemas.dmtf.org/ovf/environment/1",
've' : "http://www.vmware.com/schema/ovfenv"
}
def stderr(msg):
if not quiet:
print >> sys.stderr, msg
def runcmd(cmd):
if debug:
print ' '.join(cmd)
pobj = subprocess.Popen(cmd, bufsize=1, shell=False,
stdout=subprocess.PIPE,
stderr=subprocess.STDOUT)
while True:
line = pobj.stdout.readline()
if not line:
break
if debug:
print >> sys.stderr, line,
return(pobj.wait())
def parse_error(ctx, msg):
stderr (_("XML parse error: ") + msg)
def set_vmtools_path():
vmtools_env = os.environ.copy()
vmtools_env["PATH"] = VMTOOLS_PATH + ':' + vmtools_env["PATH"]
return vmtools_env
def get_env_from_guestinfo():
try:
pobj = subprocess.Popen(' '.join(GET_GUESTINFO), bufsize=1, shell=True,
stdout=subprocess.PIPE,
stderr=subprocess.STDOUT,
env=set_vmtools_path())
dom = pobj.stdout.read()
ret = pobj.wait()
if ret or not dom or dom.startswith("No value found"):
return False
return dom
except:
return False
def get_cd_devices():
devices = []
line = "dummy"
try:
fd = open(CDDRIVES, "r")
while line:
line = fd.readline()
if line.startswith("drive name:"):
#
# take a line that looks like this:
# drive name: hdb hda
# and turn it into a list like this:
# ['/dev/hdb', '/dev/hda']
#
devices = map(lambda x: "/dev/"+x, line.split(':', 1)[1].split())
break
except Exception, msg:
if debug:
stderr(_("Unable to determine the cdrom devices, perhaps none have been configured: ") + str(msg))
return devices
def cd_has_media(dev):
if runcmd(['dd', 'if=' + dev, 'bs=1', 'count=1']):
return False
return True
def get_env_from_iso():
ovfenv = False
cds = get_cd_devices()
tmpmount = tempfile.mkdtemp()
cmd = []
for c in cds:
if debug:
stderr (_("CD found ") + c)
if not cd_has_media(c):
if debug:
stderr(_(c + " has no media"))
continue
try:
cmd = MOUNTCD + [c, tmpmount]
runcmd(cmd)
try:
ovfenvpath = os.path.join(tmpmount, OVFENV)
fd = open(ovfenvpath, 'r')
except:
cmd = UNMOUNTCD + [tmpmount]
runcmd(cmd)
else:
ovfenv = fd.read()
fd.close()
cmd = UNMOUNTCD + [tmpmount]
runcmd(cmd)
except Exception, msg:
stderr (_("Unable to run ") + ' '.join(cmd) + ": " + str(msg))
os.rmdir(tmpmount)
return ovfenv
def get_env_from_file(f):
dom = False
try:
fd = open(f, "r")
dom = fd.read()
fd.close()
except Exception, msg:
if debug:
stderr (_("Unable to use ") + f + ": " + str(msg))
return dom
def load_ovfenv(xp, ovfenv):
nodes = xp.xpathEval(XPATH_MYPROPERTY)
for n in nodes:
ovfenv.append((None, n.prop(XPATH_KEY), n.prop(XPATH_VALUE)))
nodes = xp.xpathEval(XPATH_ENTITY)
for n in nodes:
entity = n.prop(XPATH_ID)
subnodes = xp.xpathEval(XPATH_ENTITYID + entity + "']" + XPATH_PROPERTY)
for sn in subnodes:
ovfenv.append((entity, sn.prop(XPATH_KEY), sn.prop(XPATH_VALUE)))
if debug:
stderr(ovfenv)
def set_property_value(doc, xp, entity_id, key, value):
if entity_id:
xpath = XPATH_ENTITYID + entity_id + "']" + XPATH_PROPERTY
else:
xpath = XPATH_MYPROPERTY
xpath += '[' + XPATH_NSKEY + '=' + "'" + key + "']"
node = xp.xpathEval(xpath)
if len(node):
node[0].setProp(XPATH_NSVALUE, value)
else:
stderr(_("Unable to find a key named '" + key + "'"))
return 1
cmd = [SET_GUESTINFO[0], SET_GUESTINFO[1] + doc.serialize()]
if debug:
print ' '.join(cmd)
if subprocess.call(cmd, env=set_vmtools_path()) != 0:
stderr (_("Unable to set guestinfo property values"))
return 1
try:
fd = open(STUDIOENVCOPY, "w")
fd.write(doc.serialize())
fd.close()
except Exception, msg:
stderr (_("Unable to write to ") + STUDIOENVCOPY + ": " + str(msg))
return 1
return 0
def usage():
stderr (_("Usage: ") +
sys.argv[0] +
" [-h|--help] [-d|--dump] [-f|--file <ovfenvfile>] [-i|--id <VM ID>] [-k|--key <key>] [-v|--value <value>] [-D|--debug] [-q|--quiet]")
stderr(_("""\nExamples of usage:
ovfenv
shows all the properties in id[key]=value format
ovfenv --dump
dumps the raw OVF Environment XML to stdout
ovfenv --key vm.name
ovfenv --key [vm.name]
shows the local VM's value for the property named vm.name
ovfenv --key Property_1 --id ubuntu8044
ovfenv --key ubuntu8044[Property_1]
shows the VM named ubuntu8044's value for the property
named Property_1
ovfenv --key vm.email --value foo@bar.com
ovfenv --key [vm.email]=foo@bar.com
sets the value of the local VM's property named
vm.email to foo@bar.com
ovfenv --key vm.password --value ''
ovfenv --key [vm.password]=
clears the value of the local VM's property named
vm.password"""))
def main():
global debug
global quiet
ovfenv = []
searchkey = None
searchentity = None
setvalue = None
show_all = False
dump = False
fromfile = False
try:
opts, args = getopt.getopt(sys.argv[1:],
"hk:dv:Df:i:q",
["help",
"key=",
"dump",
"quiet",
"value=",
"debug",
"file=",
"id="])
except getopt.GetoptError, msg:
stderr(msg)
usage()
return 1
for o, a in opts:
if o in ("-h", "--help"):
usage()
sys.exit(0)
elif o in ("-k", "--key"):
searchkey = a
elif o in ("-v", "--value"):
setvalue = a
elif o in ("-d", "--dump"):
dump = True
elif o in ("-D", "--debug"):
debug = True
elif o in ("-f", "--file"):
fromfile = a
elif o in ("-i", "--id"):
searchentity = a
elif o in ("-q", "--quiet"):
quiet = True
if not searchkey:
show_all = True
else:
#
# Extract the entity and key out of the passed
# key. We can be passed
# entity[my.key.name]=newvalue
#
# and we want entity to be in searchentity, my.key.name
# in searchkey, and newvalue in setvalue
#
equalsfound = searchkey.find('=')
if equalsfound != -1:
setvalue = searchkey[equalsfound+1:]
start_bracket = searchkey.find('[')
end_bracket = searchkey.rfind(']')
if start_bracket != -1 and end_bracket != -1:
searchentity = searchkey[0:start_bracket]
if not searchentity:
searchentity = None
searchkey = searchkey[start_bracket + 1:end_bracket]
#
# Try the default place that Studio copies the property xml,
# then guestinfo, then cdrom drives
#
if not fromfile:
dom = get_env_from_file(STUDIOENVCOPY)
if not dom:
dom = get_env_from_guestinfo()
if not dom:
dom = get_env_from_iso()
else:
dom = get_env_from_file(fromfile)
if not dom:
stderr (_("Unable to find the ovf environment."))
return 1
try:
doc = libxml2.parseDoc(dom)
except:
stderr (_("Unable to parse the following ovf environment: ") + dom)
return 1
xp = doc.xpathNewContext()
for k, v in NSDICT.iteritems():
xp.xpathRegisterNs(k, v)
if dump:
print doc.serialize()
return 0
load_ovfenv(xp, ovfenv)
if setvalue is not None and searchkey:
return set_property_value(doc, xp, searchentity, searchkey, setvalue)
if not show_all:
for entity, key, value in ovfenv:
if searchentity == entity and key == searchkey:
print value
return 0
stderr(_("Unable to find a key named '" + searchkey + "'"))
return 1
else:
for entity, key, value in ovfenv:
if entity:
print entity + '[' + key + ']=' + value
else:
print '[' + key + ']=' + value
return 0
if __name__ == "__main__":
sys.exit(main())
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment