From a9589bbc5e1458bfde849337151b6824f6c25468 Mon Sep 17 00:00:00 2001 From: Scott Moser Date: Thu, 6 Jan 2011 20:23:45 -0500 Subject: initial import of work-in-progress OVF code --- cloudinit/DataSourceOVF.py | 152 +++++++++++++++++++++++++ doc/ovf/README | 6 + doc/ovf/environment.xml | 71 ++++++++++++ doc/ovf/maverick-server.ovf | 264 ++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 493 insertions(+) create mode 100644 cloudinit/DataSourceOVF.py create mode 100644 doc/ovf/README create mode 100755 doc/ovf/environment.xml create mode 100644 doc/ovf/maverick-server.ovf diff --git a/cloudinit/DataSourceOVF.py b/cloudinit/DataSourceOVF.py new file mode 100644 index 00000000..b76d2ea8 --- /dev/null +++ b/cloudinit/DataSourceOVF.py @@ -0,0 +1,152 @@ +# vi: ts=4 expandtab +# +# Copyright (C) 2011 Canonical Ltd. +# +# Author: Scott Moser +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License version 3, as +# published by the Free Software Foundation. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . + +import DataSource + +import cloudinit +import cloudinit.util as util +import sys +import os.path +import os +import errno +from xml.dom import minidom +from xml.dom import Node + +class DataSourceOVF(DataSource.DataSource): + pass + +def get_ovf_env(dirname): + env_names = ("ovf-env.xml", "ovf_env.xml", "OVF_ENV.XML", "OVF-ENV.XML" ) + for fname in env_names: + if os.path.isfile("%s/%s" % (dirname,fname)): + fp = open("%s/%s" % (dirname,fname)) + contents = fp.read() + fp.close() + return(fname,contents) + return(None,False) + +def find_ovf_env(require_iso=False): + + # default_regex matches values in + # /lib/udev/rules.d/60-cdrom_id.rules + # KERNEL!="sr[0-9]*|hd[a-z]|xvd*", GOTO="cdrom_end" + envname = "CLOUD_INIT_CDROM_DEV_REGEX" + default_regex = "^(sr[0-9]+|hd[a-z]|xvd.*)" + + devname_regex = os.environ.get(envname,default_regex) + cdmatch = re.compile(devname_regex) + + # go through mounts to see if it was already mounted + fp = open("/proc/mounts") + mounts = fp.readlines() + fp.close() + + mounted = { } + for mpline in mounts: + (dev,mp,fstype,opts,freq,passno) = mpline.split() + mounted[dev]=(dev,fstype,mp,False) + mp = mp.replace("\\040"," ") + if fstype != "iso9660" and require_iso: continue + + if cdmatch.match(dev[5:]) == None: # take off '/dev/' + continue + + (fname,contents) = get_ovf_env(mp) + if contents is not False: + return (dev,fname,contents) + + tmpd = None + dvnull = None + + devs = os.listdir("/dev/") + devs.sort() + + for dev in devs: + fullp = "/dev/%s" % dev + + if fullp in mounted or not cdmatch.match(dev) or os.path.isdir(fullp): + continue + + if tmpd is None: + tmpd = tempfile.mkdtemp() + if dvnull is None: + try: + dvnull = open("/dev/null") + except: + pass + + cmd = [ "mount", "-o", "ro", fullp, tmpd ] + if require_iso: cmd.extend(('-t','iso9660')) + + rc = subprocess.call(cmd, stderr=dvnull, stdout=dvnull, stdin=dvnull) + if rc: + continue + + (fname,contents) = get_ovf_env(tmpd) + + subprocess.call(["umount", tmpd]) + + if contents is not False: + os.rmdir(tmpd) + return (fullp,fname,contents) + + if tmpd: + os.rmdir(tmpd) + + if dvnull: + dvnull.close() + + return (None,None,False) + +def findChild(node,filter_func): + ret = [] + if not node.hasChildNodes(): return ret + for child in node.childNodes: + if filter_func(child): ret.append(child) + return(ret) + +def getProperties(environString): + dom = minidom.parseString(environString) + if dom.documentElement.localName != "Environment": + raise Exception("No Environment Node") + + if not dom.documentElement.hasChildNodes(): + raise Exception("No Child Nodes") + + envNsURI = "http://schemas.dmtf.org/ovf/environment/1" + + # could also check here that elem.namespaceURI == + # "http://schemas.dmtf.org/ovf/environment/1" + propSections = findChild(dom.documentElement, + lambda n: n.localName == "PropertySection") + + if len(propSections) == 0: + raise Exception("No 'PropertySection's") + + props = { } + propElems = findChild(propSections[0], lambda n: n.localName == "Property") + + for elem in propElems: + key, val = ( None, None ) + for attr in elem.attributes.values(): + if attr.namespaceURI == envNsURI: + if attr.localName == "key" : key = attr.value + if attr.localName == "value": val = attr.value + props[key] = val + + return(props) diff --git a/doc/ovf/README b/doc/ovf/README new file mode 100644 index 00000000..1fd399fc --- /dev/null +++ b/doc/ovf/README @@ -0,0 +1,6 @@ +- environment.xml + This is an example ovf environment file +- ProductSection.xml + TODO: document what the ProductSection can look like +- maverick-server.ovf + Example generated by virtualbox "export" of a simple VM diff --git a/doc/ovf/environment.xml b/doc/ovf/environment.xml new file mode 100755 index 00000000..74559abc --- /dev/null +++ b/doc/ovf/environment.xml @@ -0,0 +1,71 @@ + + + + + + + + ESX Server + 3.0.1 + VMware, Inc. + en_US + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/doc/ovf/maverick-server.ovf b/doc/ovf/maverick-server.ovf new file mode 100644 index 00000000..f4f0d4cb --- /dev/null +++ b/doc/ovf/maverick-server.ovf @@ -0,0 +1,264 @@ + + + + + + + List of the virtual disks used in the package + + + + Logical networks used in the package + + Logical network used by this appliance. + + + + A virtual machine + + Meta-information about the installed software + My-Product + My-Vendor + My-Version + My-Product-URL + My-Vendor-URL + + + A human-readable annotation + My-Description + + + License agreement for the virtual system + My-License + + + The kind of installed guest operating system + Ubuntu + + + Virtual hardware requirements for a virtual machine + + Virtual Hardware Family + 0 + maverick-server + virtualbox-2.2 + + + 1 virtual CPU + Number of virtual CPUs + 1 virtual CPU + 1 + 3 + 1 + + + MegaBytes + 256 MB of memory + Memory Size + 256 MB of memory + 2 + 4 + 256 + + + 0 + ideController0 + IDE Controller + ideController0 + 3 + PIIX4 + 5 + + + 1 + ideController1 + IDE Controller + ideController1 + 4 + PIIX4 + 5 + + + 0 + sataController0 + SATA Controller + sataController0 + 5 + AHCI + 20 + + + true + Ethernet adapter on 'NAT' + NAT + Ethernet adapter on 'NAT' + 6 + E1000 + 10 + + + 3 + false + sound + Sound Card + sound + 7 + ensoniq1371 + 35 + + + 0 + true + cdrom1 + CD-ROM Drive + cdrom1 + 8 + 4 + 15 + + + 0 + disk1 + Disk Image + disk1 + /disk/vmdisk1 + 9 + 5 + 17 + + + + Complete VirtualBox machine configuration in VirtualBox format + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + -- cgit v1.2.3