diff options
-rw-r--r-- | cloudinit/DataSourceOVF.py | 152 | ||||
-rw-r--r-- | doc/ovf/README | 6 | ||||
-rwxr-xr-x | doc/ovf/environment.xml | 71 | ||||
-rw-r--r-- | doc/ovf/maverick-server.ovf | 264 |
4 files changed, 493 insertions, 0 deletions
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 <scott.moser@canonical.com> +# +# 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 <http://www.gnu.org/licenses/>. + +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 @@ +<?xml version="1.0" encoding="UTF-8"?>
+<Environment xmlns="http://schemas.dmtf.org/ovf/environment/1"
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xmlns:oe="http://schemas.dmtf.org/ovf/environment/1"
+ xsi:schemaLocation="http://schemas.dmtf.org/ovf/environment/1 ../dsp8027.xsd"
+ oe:id="WebTier">
+
+ <!-- This example reference a local schema file, to validate against online schema use:
+ xsi:schemaLocation="http://schemas.dmtf.org/ovf/envelope/1 http://schemas.dmtf.org/ovf/envelope/1/dsp8027_1.0.0.xsd"
+ -->
+
+ <!-- Information about hypervisor platform -->
+ <oe:PlatformSection>
+ <Kind>ESX Server</Kind>
+ <Version>3.0.1</Version>
+ <Vendor>VMware, Inc.</Vendor>
+ <Locale>en_US</Locale>
+ </oe:PlatformSection>
+
+ <!--- Properties defined for this virtual machine -->
+ <PropertySection>
+ <!-- md.instance-id is required, a unique instance-id -->
+ <Property oe:key="md.instance-id" oe:value="i-abcdefg"/>
+ <!--
+ md.seedfrom is optional, but indicates to 'seed' user-data
+ and meta-data the given url. In this example, pull
+ http://tinyurl.com/sm-meta-data and http://tinyurl.com/sm-user-data
+ -->
+ <Property oe:key="md.seedfrom" oe:value="http://tinyurl.com/sm-"/>
+ <!--
+ md.public-keys is a public key to add to users authorized keys
+ -->
+ <Property oe:key="md.public-keys" oe:value="ssh-rsa AAAAB3NzaC1yc2EAAAABIwAAAQEA3I7VUf2l5gSn5uavROsc5HRDpZdQueUq5ozemNSj8T7enqKHOEaFoU2VoPgGEWC9RyzSQVeyD6s7APMcE82EtmW4skVEgEGSbDc1pvxzxtchBj78hJP6Cf5TCMFSXw+Fz5rF1dR23QDbN1mkHs7adr8GW4kSWqU7Q7NDwfIrJJtO7Hi42GyXtvEONHbiRPOe8stqUly7MvUoN+5kfjBM8Qqpfl2+FNhTYWpMfYdPUnE7u536WqzFmsaqJctz3gBxH9Ex7dFtrxR4qiqEr9Qtlu3xGn7Bw07/+i1D+ey3ONkZLN+LQ714cgj8fRS4Hj29SCmXp5Kt5/82cD/VN3NtHw== smoser@brickies"/>
+ <!-- md.local-hostname: the hostname to set -->
+ <Property oe:key="md.local-hostname" oe:value="ubuntuhost"/>
+ <!--
+ The value for user-data can be either base64 encoded or url encoded.
+ it will be decoded, and then processed normally as user-data.
+ The following represents '#!/bin/sh\necho "hi world"'
+
+ <Property oe:key="user-data" oe:value="IyEvYmluL3NoDQplY2hvICJoaSB3b3JsZCI="/>
+ -->
+ <Property oe:key="user-data" oe:value="%23!%2Fbin%2Fsh%0Aecho%20%22hi%20world%22"/>
+ </PropertySection>
+
+ <PropertySection>
+ <!-- md.instance-id is required, a unique instance-id -->
+ <Property oe:key="md.instance-id" oe:value="i-abcdefg"/>
+ <!--
+ md.seedfrom is optional, but indicates to 'seed' user-data
+ and meta-data the given url. In this example, pull
+ http://tinyurl.com/sm-meta-data and http://tinyurl.com/sm-user-data
+ -->
+ <Property oe:key="md.seedfrom" oe:value="http://tinyurl.com/sm-"/>
+ <!--
+ md.public-keys is a public key to add to users authorized keys
+ -->
+ <Property oe:key="md.public-keys" oe:value="ssh-rsa AAAAB3NzaC1yc2EAAAABIwAAAQEA3I7VUf2l5gSn5uavROsc5HRDpZdQueUq5ozemNSj8T7enqKHOEaFoU2VoPgGEWC9RyzSQVeyD6s7APMcE82EtmW4skVEgEGSbDc1pvxzxtchBj78hJP6Cf5TCMFSXw+Fz5rF1dR23QDbN1mkHs7adr8GW4kSWqU7Q7NDwfIrJJtO7Hi42GyXtvEONHbiRPOe8stqUly7MvUoN+5kfjBM8Qqpfl2+FNhTYWpMfYdPUnE7u536WqzFmsaqJctz3gBxH9Ex7dFtrxR4qiqEr9Qtlu3xGn7Bw07/+i1D+ey3ONkZLN+LQ714cgj8fRS4Hj29SCmXp5Kt5/82cD/VN3NtHw== smoser@brickies"/>
+ <!-- md.local-hostname: the hostname to set -->
+ <Property oe:key="md.local-hostname" oe:value="ubuntuhost"/>
+ <!--
+ The value for user-data can be either base64 encoded or url encoded.
+ it will be decoded, and then processed normally as user-data.
+ The following represents '#!/bin/sh\necho "hi world"'
+
+ <Property oe:key="user-data" oe:value="IyEvYmluL3NoDQplY2hvICJoaSB3b3JsZCI="/>
+ -->
+ <Property oe:key="user-data" oe:value="%23!%2Fbin%2Fsh%0Aecho%20%22hi%20world%22"/>
+ </PropertySection>
+
+</Environment>
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 @@ +<?xml version="1.0"?> +<Envelope ovf:version="1.0" xml:lang="en-US" xmlns="http://schemas.dmtf.org/ovf/envelope/1" xmlns:ovf="http://schemas.dmtf.org/ovf/envelope/1" xmlns:rasd="http://schemas.dmtf.org/wbem/wscim/1/cim-schema/2/CIM_ResourceAllocationSettingData" xmlns:vssd="http://schemas.dmtf.org/wbem/wscim/1/cim-schema/2/CIM_VirtualSystemSettingData" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:vbox="http://www.virtualbox.org/ovf/machine"> + <References> + <File ovf:href="disk1.vmdk" ovf:id="file1" ovf:size="328192"/> + </References> + <DiskSection> + <Info>List of the virtual disks used in the package</Info> + <Disk ovf:capacity="2147483648" ovf:diskId="vmdisk1" ovf:fileRef="file1" ovf:format="http://www.vmware.com/interfaces/specifications/vmdk.html#streamOptimized" vbox:uuid="5aeae59e-afeb-403b-9c1d-d07ee9dc5946"/> + </DiskSection> + <NetworkSection> + <Info>Logical networks used in the package</Info> + <Network ovf:name="NAT"> + <Description>Logical network used by this appliance.</Description> + </Network> + </NetworkSection> + <VirtualSystem ovf:id="maverick-server"> + <Info>A virtual machine</Info> + <ProductSection> + <Info>Meta-information about the installed software</Info> + <Product>My-Product</Product> + <Vendor>My-Vendor</Vendor> + <Version>My-Version</Version> + <ProductUrl>My-Product-URL</ProductUrl> + <VendorUrl>My-Vendor-URL</VendorUrl> + </ProductSection> + <AnnotationSection> + <Info>A human-readable annotation</Info> + <Annotation>My-Description</Annotation> + </AnnotationSection> + <EulaSection> + <Info>License agreement for the virtual system</Info> + <License>My-License</License> + </EulaSection> + <OperatingSystemSection ovf:id="93"> + <Info>The kind of installed guest operating system</Info> + <Description>Ubuntu</Description> + </OperatingSystemSection> + <VirtualHardwareSection> + <Info>Virtual hardware requirements for a virtual machine</Info> + <System> + <vssd:ElementName>Virtual Hardware Family</vssd:ElementName> + <vssd:InstanceID>0</vssd:InstanceID> + <vssd:VirtualSystemIdentifier>maverick-server</vssd:VirtualSystemIdentifier> + <vssd:VirtualSystemType>virtualbox-2.2</vssd:VirtualSystemType> + </System> + <Item> + <rasd:Caption>1 virtual CPU</rasd:Caption> + <rasd:Description>Number of virtual CPUs</rasd:Description> + <rasd:ElementName>1 virtual CPU</rasd:ElementName> + <rasd:InstanceID>1</rasd:InstanceID> + <rasd:ResourceType>3</rasd:ResourceType> + <rasd:VirtualQuantity>1</rasd:VirtualQuantity> + </Item> + <Item> + <rasd:AllocationUnits>MegaBytes</rasd:AllocationUnits> + <rasd:Caption>256 MB of memory</rasd:Caption> + <rasd:Description>Memory Size</rasd:Description> + <rasd:ElementName>256 MB of memory</rasd:ElementName> + <rasd:InstanceID>2</rasd:InstanceID> + <rasd:ResourceType>4</rasd:ResourceType> + <rasd:VirtualQuantity>256</rasd:VirtualQuantity> + </Item> + <Item> + <rasd:Address>0</rasd:Address> + <rasd:Caption>ideController0</rasd:Caption> + <rasd:Description>IDE Controller</rasd:Description> + <rasd:ElementName>ideController0</rasd:ElementName> + <rasd:InstanceID>3</rasd:InstanceID> + <rasd:ResourceSubType>PIIX4</rasd:ResourceSubType> + <rasd:ResourceType>5</rasd:ResourceType> + </Item> + <Item> + <rasd:Address>1</rasd:Address> + <rasd:Caption>ideController1</rasd:Caption> + <rasd:Description>IDE Controller</rasd:Description> + <rasd:ElementName>ideController1</rasd:ElementName> + <rasd:InstanceID>4</rasd:InstanceID> + <rasd:ResourceSubType>PIIX4</rasd:ResourceSubType> + <rasd:ResourceType>5</rasd:ResourceType> + </Item> + <Item> + <rasd:Address>0</rasd:Address> + <rasd:Caption>sataController0</rasd:Caption> + <rasd:Description>SATA Controller</rasd:Description> + <rasd:ElementName>sataController0</rasd:ElementName> + <rasd:InstanceID>5</rasd:InstanceID> + <rasd:ResourceSubType>AHCI</rasd:ResourceSubType> + <rasd:ResourceType>20</rasd:ResourceType> + </Item> + <Item> + <rasd:AutomaticAllocation>true</rasd:AutomaticAllocation> + <rasd:Caption>Ethernet adapter on 'NAT'</rasd:Caption> + <rasd:Connection>NAT</rasd:Connection> + <rasd:ElementName>Ethernet adapter on 'NAT'</rasd:ElementName> + <rasd:InstanceID>6</rasd:InstanceID> + <rasd:ResourceSubType>E1000</rasd:ResourceSubType> + <rasd:ResourceType>10</rasd:ResourceType> + </Item> + <Item> + <rasd:AddressOnParent>3</rasd:AddressOnParent> + <rasd:AutomaticAllocation>false</rasd:AutomaticAllocation> + <rasd:Caption>sound</rasd:Caption> + <rasd:Description>Sound Card</rasd:Description> + <rasd:ElementName>sound</rasd:ElementName> + <rasd:InstanceID>7</rasd:InstanceID> + <rasd:ResourceSubType>ensoniq1371</rasd:ResourceSubType> + <rasd:ResourceType>35</rasd:ResourceType> + </Item> + <Item> + <rasd:AddressOnParent>0</rasd:AddressOnParent> + <rasd:AutomaticAllocation>true</rasd:AutomaticAllocation> + <rasd:Caption>cdrom1</rasd:Caption> + <rasd:Description>CD-ROM Drive</rasd:Description> + <rasd:ElementName>cdrom1</rasd:ElementName> + <rasd:InstanceID>8</rasd:InstanceID> + <rasd:Parent>4</rasd:Parent> + <rasd:ResourceType>15</rasd:ResourceType> + </Item> + <Item> + <rasd:AddressOnParent>0</rasd:AddressOnParent> + <rasd:Caption>disk1</rasd:Caption> + <rasd:Description>Disk Image</rasd:Description> + <rasd:ElementName>disk1</rasd:ElementName> + <rasd:HostResource>/disk/vmdisk1</rasd:HostResource> + <rasd:InstanceID>9</rasd:InstanceID> + <rasd:Parent>5</rasd:Parent> + <rasd:ResourceType>17</rasd:ResourceType> + </Item> + </VirtualHardwareSection> + <vbox:Machine ovf:required="false" version="1.10-linux" uuid="{c41d497b-671f-4d64-9fa1-06df3d2613b4}" name="maverick-server" OSType="Ubuntu" lastStateChange="2011-01-06T17:58:28Z"> + <ovf:Info>Complete VirtualBox machine configuration in VirtualBox format</ovf:Info> + <ExtraData> + <ExtraDataItem name="GUI/MiniToolBarAlignment" value="bottom"/> + <ExtraDataItem name="GUI/SaveMountedAtRuntime" value="yes"/> + <ExtraDataItem name="GUI/ShowMiniToolBar" value="yes"/> + </ExtraData> + <Hardware version="2"> + <CPU count="1" hotplug="false"> + <HardwareVirtEx enabled="true" exclusive="true"/> + <HardwareVirtExNestedPaging enabled="true"/> + <HardwareVirtExVPID enabled="true"/> + <PAE enabled="false"/> + <HardwareVirtForce enabled="false"/> + </CPU> + <Memory RAMSize="256" PageFusion="false"/> + <HID Pointing="USBTablet" Keyboard="PS2Keyboard"/> + <HPET enabled="false"/> + <Boot> + <Order position="1" device="Floppy"/> + <Order position="2" device="DVD"/> + <Order position="3" device="HardDisk"/> + <Order position="4" device="None"/> + </Boot> + <Display VRAMSize="12" monitorCount="1" accelerate3D="false" accelerate2DVideo="false"/> + <RemoteDisplay enabled="true" port="3389" authType="Null" authTimeout="5000"> + <VideoChannel enabled="false" quality="75"/> + </RemoteDisplay> + <BIOS> + <ACPI enabled="true"/> + <IOAPIC enabled="false"/> + <Logo fadeIn="true" fadeOut="true" displayTime="0"/> + <BootMenu mode="MessageAndMenu"/> + <TimeOffset value="0"/> + <PXEDebug enabled="false"/> + </BIOS> + <USBController enabled="true" enabledEhci="false"/> + <Network> + <Adapter slot="0" enabled="true" MACAddress="080027FFC036" cable="true" speed="0" type="82540EM"> + <NAT> + <DNS pass-domain="true" use-proxy="false" use-host-resolver="false"/> + <Alias logging="false" proxy-only="false" use-same-ports="false"/> + </NAT> + </Adapter> + <Adapter slot="1" enabled="false" MACAddress="0800275B8697" cable="true" speed="0" type="82540EM"> + <DisabledModes> + <NAT> + <DNS pass-domain="true" use-proxy="false" use-host-resolver="false"/> + <Alias logging="false" proxy-only="false" use-same-ports="false"/> + </NAT> + </DisabledModes> + </Adapter> + <Adapter slot="2" enabled="false" MACAddress="080027F82D92" cable="true" speed="0" type="82540EM"> + <DisabledModes> + <NAT> + <DNS pass-domain="true" use-proxy="false" use-host-resolver="false"/> + <Alias logging="false" proxy-only="false" use-same-ports="false"/> + </NAT> + </DisabledModes> + </Adapter> + <Adapter slot="3" enabled="false" MACAddress="08002709F8D6" cable="true" speed="0" type="82540EM"> + <DisabledModes> + <NAT> + <DNS pass-domain="true" use-proxy="false" use-host-resolver="false"/> + <Alias logging="false" proxy-only="false" use-same-ports="false"/> + </NAT> + </DisabledModes> + </Adapter> + <Adapter slot="4" enabled="false" MACAddress="080027B55EED" cable="true" speed="0" type="82540EM"> + <DisabledModes> + <NAT> + <DNS pass-domain="true" use-proxy="false" use-host-resolver="false"/> + <Alias logging="false" proxy-only="false" use-same-ports="false"/> + </NAT> + </DisabledModes> + </Adapter> + <Adapter slot="5" enabled="false" MACAddress="0800275AFCEB" cable="true" speed="0" type="82540EM"> + <DisabledModes> + <NAT> + <DNS pass-domain="true" use-proxy="false" use-host-resolver="false"/> + <Alias logging="false" proxy-only="false" use-same-ports="false"/> + </NAT> + </DisabledModes> + </Adapter> + <Adapter slot="6" enabled="false" MACAddress="080027FA01EC" cable="true" speed="0" type="82540EM"> + <DisabledModes> + <NAT> + <DNS pass-domain="true" use-proxy="false" use-host-resolver="false"/> + <Alias logging="false" proxy-only="false" use-same-ports="false"/> + </NAT> + </DisabledModes> + </Adapter> + <Adapter slot="7" enabled="false" MACAddress="08002747C6D5" cable="true" speed="0" type="82540EM"> + <DisabledModes> + <NAT> + <DNS pass-domain="true" use-proxy="false" use-host-resolver="false"/> + <Alias logging="false" proxy-only="false" use-same-ports="false"/> + </NAT> + </DisabledModes> + </Adapter> + </Network> + <UART> + <Port slot="0" enabled="false" IOBase="0x3f8" IRQ="4" hostMode="Disconnected"/> + <Port slot="1" enabled="false" IOBase="0x2f8" IRQ="3" hostMode="Disconnected"/> + </UART> + <LPT> + <Port slot="0" enabled="false" IOBase="0x378" IRQ="4"/> + <Port slot="1" enabled="false" IOBase="0x378" IRQ="4"/> + </LPT> + <AudioAdapter controller="AC97" driver="Pulse" enabled="true"/> + <RTC localOrUTC="UTC"/> + <SharedFolders/> + <Clipboard mode="Bidirectional"/> + <IO> + <IoCache enabled="true" size="5"/> + <IoBandwidth max="0"/> + </IO> + <Guest memoryBalloonSize="0"/> + <GuestProperties> + <GuestProperty name="/VirtualBox/HostInfo/GUI/LanguageID" value="en_US" timestamp="1294336766813578000" flags=""/> + </GuestProperties> + </Hardware> + <StorageControllers> + <StorageController name="IDE Controller" type="PIIX4" PortCount="2" useHostIOCache="true"> + <AttachedDevice passthrough="false" type="DVD" port="0" device="0"/> + </StorageController> + <StorageController name="SATA Controller" type="AHCI" PortCount="1" useHostIOCache="false" IDE0MasterEmulationPort="0" IDE0SlaveEmulationPort="1" IDE1MasterEmulationPort="2" IDE1SlaveEmulationPort="3"> + <AttachedDevice type="HardDisk" port="0" device="0"> + <Image uuid="{5aeae59e-afeb-403b-9c1d-d07ee9dc5946}"/> + </AttachedDevice> + </StorageController> + </StorageControllers> + </vbox:Machine> + </VirtualSystem> +</Envelope> |