<?xml version="1.0" ?>
<grammar xmlns="http://relaxng.org/ns/structure/1.0"
    datatypeLibrary="http://www.w3.org/2001/XMLSchema-datatypes">
  <!-- We handle only document defining a domain -->
  <start>
    <ref name='domain'/>
  </start>

  <!-- 
      We handle only document defining a domain
      Currently the virtualization types supported are:
        - xen, either paravirualized with a linux os or fully virtualized (hvm)
	- kvm, requiring a path to the emulator in devices
	- qemu, where the arch and machine must be provided in the os block
    -->
  <define name='domain'>
    <element name="domain">
      <choice>
        <ref name='xen-domain'/>
        <ref name='kvm-domain'/>
        <ref name='qemu-domain'/>
      </choice>
    </element>
  </define>

  <!--
      Description of a Xen domain:
      The description must start with the identification informations and then
      os or bootloader, resources, features, devices and termination informations
      can be given in any order.
    -->
  <define name='xen-domain'>
    <group>
      <attribute name='type'>
        <value>xen</value>
      </attribute>
      <ref name='ids'/>
      <interleave>
        <choice>
	  <group>
            <ref name='os'/>
	    <optional>
              <ref name='bootloader'/>
	    </optional>
	  </group>
	  <group>
	    <ref name='bootloader'/>
	    <optional>
              <ref name='os'/>
	    </optional>
	  </group>
	</choice>
        <ref name='resources'/>
        <ref name='features'/>
        <ref name='termination'/>
        <ref name='devices'/>
      </interleave>
    </group>
  </define>

  <!--
      Description of a QEmu domain:
      The description must start with the identification informations and then
      os, resources, devices can be given in any order.
      The specific part are the combinations of architectures and machines
      being emulated.
    -->
  <define name='qemu-domain'>
    <group>
      <attribute name='type'>
        <value>qemu</value>
      </attribute>
      <ref name='ids'/>
      <interleave>
        <element name='os'>
	  <element name='type'>
	    <choice>
	      <ref name='qemu-x86'/>
	      <ref name='qemu-mips'/>
	      <ref name='qemu-sparc'/>
	      <ref name='qemu-ppc'/>
	    </choice>
	    <value>hvm</value>
	  </element>
	</element>
        <ref name='resources'/>
        <ref name='devices'/>
      </interleave>
    </group>
  </define>

  <define name='qemu-x86'>
    <group>
      <attribute name='arch'>
	<choice>
	  <value>i686</value>
	  <value>x86_64</value>
	</choice>
      </attribute>
      <attribute name='machine'>
	<choice>
	  <value>pc</value>
	  <value>isapc</value>
	</choice>
      </attribute>
    </group>
  </define>

  <define name='qemu-mips'>
    <group>
      <attribute name='arch'>
        <value>mips</value>
      </attribute>
      <attribute name='machine'>
        <value>mips</value>
      </attribute>
    </group>
  </define>

  <define name='qemu-sparc'>
    <group>
      <attribute name='arch'>
	<value>sparc</value>
      </attribute>
      <attribute name='machine'>
	<value>sun4m</value>
      </attribute>
    </group>
  </define>

  <define name='qemu-ppc'>
    <group>
      <attribute name='arch'>
	<value>ppc</value>
      </attribute>
      <attribute name='machine'>
	<choice>
	  <value>g3bw</value>
	  <value>mac99</value>
	  <value>prep</value>
	</choice>
      </attribute>
    </group>
  </define>

  <!--
      Description of a KVM domain:
      The description must start with the identification informations and then
      os, resources, devices can be given in any order.
    -->
  <define name='kvm-domain'>
    <group>
      <attribute name='type'>
        <value>kvm</value>
      </attribute>
      <ref name='ids'/>
      <interleave>
        <element name='os'>
	  <element name='type'>
	    <value>hvm</value>
	  </element>
	</element>
        <ref name='resources'/>
        <ref name='devices-with-emulator'/>
      </interleave>
    </group>
  </define>

  <!-- 
      The Identifiers can be:
      - an optional id attribute with a number on the domain element
      - a mandatory name
      - an optional uuid
    -->
  <define name='ids'>
    <optional>
      <attribute name='id'>
        <ref name='unsignedInt'/>
      </attribute>
    </optional>
    <interleave>
      <element name="name">
        <ref name='domainName'/>
      </element>
      <optional>
        <element name="uuid">
          <ref name='UUID'/>
        </element>
      </optional>
    </interleave>
  </define>

  <!--
      Resources usage defines the amount of memory (maximum and possibly
      current usage) and number of virtual CPUs used by that domain.
      We can't check here the rule that currentMemory <= memory
    -->

  <define name='resources'>
    <interleave>
      <element name='memory'>
        <ref name='memoryKB'/>
      </element>
      <optional>
        <element name='currentMemory'>
          <ref name='memoryKB'/>
        </element>
      </optional>
      <optional>
        <element name='vcpu'>
          <ref name='countCPU'/>
        </element>
      </optional>
    </interleave>
  </define>

  <!--
      A bootloader may be used to extract the OS information instead of
      defining the OS parameter in the instance. It points just to the
      binary or script used to extract the data from the first disk device.
    -->
  <define name='bootloader'>
    <element name='bootloader'>
      <ref name='absFilePath'/>
    </element>
  </define>
  <!--
      The Operating system can be:
      - a linux paravirtualized OS
      - a fully virtualized machine where the OS is unknown
    -->
  <define name='os'>
    <element name='os'>
      <choice>
        <ref name='linux'/>
        <ref name='hvm'/>
      </choice>
    </element>
  </define>

  <!--
      A paravirtualized linux domain, this requires at least a kernel path
      and the root device, the initrd and command line arguments are optional
    -->
  <define name='linux'>
    <element name='type'>
      <value>linux</value>
    </element>
    <interleave>
      <element name='kernel'>
        <ref name='absFilePath'/>
      </element>
      <optional>
        <element name='initrd'>
	  <ref name='absFilePath'/>
	</element>
      </optional>
      <optional>
        <element name='root'>
          <ref name='devicePath'/>
        </element>
      </optional>
      <optional>
        <element name='cmdline'>
	  <text/>
	</element>
      </optional>
    </interleave>
  </define>

  <!--
      A fully virtualized domain, this requires the path to the loader and
      an optional boot device (hd, fd or cdrom).
    -->
  <define name='hvm'>
    <element name='type'>
      <value>hvm</value>
    </element>
    <interleave>
      <element name='loader'>
        <ref name='absFilePath'/>
      </element>
      <optional>
        <element name='boot'>
	  <attribute name='dev'>
	    <choice>
	      <value>hd</value>
	      <value>fd</value>
	      <value>cdrom</value>
	    </choice>
	  </attribute>
	  <empty/>
	</element>
      </optional>
    </interleave>
  </define>

  <!--
      A disk description can be either of type file or block
      The name of the attribute on the source element depends on the type

    -->
  <define name='disk'>
    <element name='disk'>
      <optional>
	<attribute name='device'>
	  <choice>
	    <value>floppy</value>
	    <value>disk</value>
	    <value>cdrom</value>
	  </choice>
	</attribute>
      </optional>
      <choice>
        <group>
          <attribute name='type'>
	    <value>file</value>
	  </attribute>
	  <interleave>
	    <element name='source'>
	      <attribute name='file'>
	        <ref name='absFilePath'/>
	      </attribute>
	      <empty/>
	    </element>
	    <optional>
	      <ref name='driver'/>
	    </optional>
	    <ref name='target'/>
	    <optional>
	      <ref name='readonly'/>
	    </optional>
	  </interleave>
        </group>
        <group>
          <attribute name='type'>
	    <value>block</value>
	  </attribute>
	  <interleave>
	    <element name='source'>
	      <attribute name='dev'>
	        <ref name='deviceName'/>
	      </attribute>
	      <empty/>
	    </element>
	    <optional>
	      <ref name='driver'/>
	    </optional>
	    <ref name='target'/>
	    <optional>
	      <ref name='readonly'/>
	    </optional>
	  </interleave>
        </group>
      </choice>
    </element>
  </define>

  <define name='target'>
    <element name='target'>
      <attribute name='dev'>
	<ref name='deviceName'/>
      </attribute>
    </element>
  </define>

  <define name='readonly'>
    <element name='readonly'>
      <empty/>
    </element>
  </define>

  <!--
      Disk may use a special driver for access. Currently this is 
      only defined for Xen for tap/aio and file, but will certainly be
      extended in the future, and libvirt doesn't look for specific values.
    -->
  <define name='driver'>
      <element name='driver'>
        <attribute name='name'>
	  <ref name='genericName'/>
	</attribute>
        <optional>
          <attribute name='type'>
	    <ref name='genericName'/>
	  </attribute>
	</optional>
	<empty/>
      </element>
  </define>
  <!--
      An interface description can either be of type bridge in which case
      it will use a bridging source, or of type ethernet which uses a device
      source and a device target instead. They both share a set of interface
      options.
    -->
  <define name='interface'>
    <element name='interface'>
      <choice>
        <group>
          <attribute name='type'>
            <value>bridge</value>
          </attribute>
	  <interleave>
	    <element name='source'>
	      <attribute name='bridge'>
		<ref name='deviceName'/>
	      </attribute>
	      <empty/>
	    </element>
	    <ref name='interface-options'/>
	  </interleave>
	</group>
        <group>
          <attribute name='type'>
            <value>ethernet</value>
          </attribute>
	  <interleave>
	    <element name='source'>
	      <attribute name='dev'>
		<ref name='deviceName'/>
	      </attribute>
	      <empty/>
	    </element>
	    <ref name='interface-options'/>
	  </interleave>
	</group>
        <group>
          <attribute name='type'>
            <value>user</value>
          </attribute>
	  <interleave>
	    <ref name='interface-options'/>
	  </interleave>
	</group>
      </choice>
    </element>
  </define>

  <!--
      The interface options possible are:
        - the MAC address
	- the IP address bound to the interface
	- the name of the script used to set up the binding
	- the target device used
    -->
  <define name='interface-options'>
      <interleave>
	<optional>
	  <element name='target'>
	    <attribute name='dev'>
	      <ref name='deviceName'/>
	    </attribute>
	    <empty/>
	  </element>
	</optional>
	<optional>
	  <element name='mac'>
	    <attribute name='address'>
	      <ref name='addrMAC'/>
	    </attribute>
	    <empty/>
	  </element>
	</optional>
	<optional>
	  <element name='ip'>
	    <attribute name='address'>
	      <ref name='addrIP'/>
	    </attribute>
	    <empty/>
	  </element>
	</optional>
	<optional>
	  <element name='script'>
	    <attribute name='path'>
	      <ref name='filePath'/>
	    </attribute>
	    <empty/>
	  </element>
	</optional>
      </interleave>
  </define>

  <!--
      An emulator descritpion is just a path to the binary used for the task
    -->
  <define name='emulator'>
    <element name='emulator'>
      <ref name='absFilePath'/>
    </element>
  </define>

  <!--
      A graphic description, currently in Xen only 2 types are supported:
        - sdl without arguments
	- vnc with a required port and optional listen IP address and password
    -->
  <define name='graphic'>
    <element name='graphics'>
      <choice>
        <attribute name='type'>
	  <value>sdl</value>
	</attribute>
	<group>
          <attribute name='type'>
	    <value>vnc</value>
	  </attribute>
          <attribute name='port'>
	    <ref name='PortNumber'/>
	  </attribute>
	  <optional>
	    <attribute name='listen'>
	      <ref name='addrIP'/>
	    </attribute>
	  </optional>
	  <optional>
	    <attribute name='passwd'>
	      <text/>
	    </attribute>
	  </optional>
	</group>
      </choice>
    </element>
  </define>

  <!--
      When a domain terminates multiple policies can be applied depending
      on how it ended:
    -->
  <define name='termination'>
    <interleave>
      <optional>
        <element name='on_reboot'>
	  <ref name='offOptions'/>
	</element>
      </optional>
      <optional>
        <element name='on_poweroff'>
	  <ref name='offOptions'/>
	</element>
      </optional>
      <optional>
        <element name='on_crash'>
	  <ref name='offOptions'/>
	</element>
      </optional>
    </interleave>
  </define>

  <!--
      Options when a domain terminates:
      destroy: The domain is cleaned up
      restart: A new domain is started in place of the old one
      preserve: The domain will remain in memory until it is destroyed manually
      rename-restart: a variant of the previous one but where the old domain is
                      renamed before being saved to allow a restart
    -->
  <define name='offOptions'>
    <choice>
      <value>destroy</value>
      <value>restart</value>
      <value>preserve</value>
      <value>rename-restart</value>
    </choice>
  </define>

  <!--
      The description for a console
      just a tty device
    -->
  <define name='console'>
    <element name='console'>
      <attribute name='tty'>
        <ref name='devicePath'/>
      </attribute>
      <empty/>
    </element>
  </define>

  <!--
      The devices bloc allows:
      - an optional emulator path, restricted to hvm configs but hard to check
      - an optional graphic description , restricted to hvm configs too
      - zero or more disk devices
      - zero or more interface devices
    -->
  <define name='devices'>
    <element name='devices'>
      <interleave>
	<optional>
	  <ref name='emulator'/>
	</optional>
	<optional>
	  <ref name='graphic'/>
	</optional>
	<zeroOrMore>
	  <ref name='disk'/>
	</zeroOrMore>
	<zeroOrMore>
	  <ref name='interface'/>
	</zeroOrMore>
	<optional>
	  <ref name='console'/>
	</optional>
      </interleave>
    </element>
  </define>

  <!--
      Sometimes the emulator is mandatory, e.g. with KVM
    -->
  <define name='devices-with-emulator'>
    <element name='devices'>
      <interleave>
	<ref name='emulator'/>
	<optional>
	  <ref name='graphic'/>
	</optional>
	<zeroOrMore>
	  <ref name='disk'/>
	</zeroOrMore>
	<zeroOrMore>
	  <ref name='interface'/>
	</zeroOrMore>
	<optional>
	  <ref name='console'/>
	</optional>
      </interleave>
    </element>
  </define>

  <!--
      A set of optional features: PAE, APIC and ACPI support
    -->
  <define name='features'>
    <optional>
      <element name="features">
        <interleave>
	  <optional>
	    <element name="pae">
	      <empty/>
	    </element>
	  </optional>
	  <optional>
	    <element name="apic">
	      <empty/>
	    </element>
	  </optional>
	  <optional>
	    <element name="acpi">
	      <empty/>
	    </element>
	  </optional>
	</interleave>
      </element>
    </optional>
  </define>

  <!--
       Type library

       Our unsignedInt doesn't allow a leading '+' in its lexical form
       A domain name shoul be made of ascii, numbers, _-+ and is non-empty
       UUID currently allows only the 32 characters strict syntax
       memoryKB request at least 4Mbytes though Xen will grow bigger if too low
    -->
  <define name='unsignedInt'>
    <data type='unsignedInt'>
      <param name="pattern">[0-9]+</param>
    </data>
  </define>
  <define name='countCPU'>
    <data type='unsignedShort'>
      <param name="pattern">[0-9]+</param>
      <param name="minInclusive">1</param>
    </data>
  </define>
  <define name='PortNumber'>
    <data type='short'>
      <param name="minInclusive">-1</param>
    </data>
  </define>
  <define name='memoryKB'>
    <data type='unsignedInt'>
      <param name="pattern">[0-9]+</param>
      <param name="minInclusive">4000</param>
    </data>
  </define>
  <define name='domainName'>
    <data type='string'>
      <param name="pattern">[a-zA-Z0-9_\+\-]+</param>
    </data>
  </define>
  <define name='genericName'>
    <data type='string'>
      <param name="pattern">[a-zA-Z0-9_\+\-]+</param>
    </data>
  </define>
  <define name='UUID'>
    <choice>
      <data type='string'>
        <param name="pattern">[a-fA-F0-9]{32}</param>
      </data>
      <data type='string'>
        <param name="pattern">[a-fA-F0-9]{8}\-([a-fA-F0-9]{4}\-){3}[a-fA-F0-9]{12}</param>
      </data>
    </choice>
  </define>
  <define name='filePath'>
    <data type='string'>
      <param name="pattern">[a-zA-Z0-9_\+\-%./]+</param>
    </data>
  </define>
  <define name='absFilePath'>
    <data type='string'>
      <param name="pattern">/[a-zA-Z0-9_\+\-%./]+</param>
    </data>
  </define>
  <define name='devicePath'>
    <data type='string'>
      <param name="pattern">/[a-zA-Z0-9_\+\-%/]+</param>
    </data>
  </define>
  <define name='deviceName'>
    <data type='string'>
      <param name="pattern">[a-zA-Z0-9_\-:./]+</param>
    </data>
  </define>
  <define name='addrMAC'>
    <data type='string'>
      <param name="pattern">([a-fA-F0-9]{2}:){5}[a-fA-F0-9]{2}</param>
    </data>
  </define>
  <define name='addrIP'>
    <data type='string'>
      <param name="pattern">([0-2]?[0-9]?[0-9]\.){3}[0-2]?[0-9]?[0-9]</param>
    </data>
  </define>
</grammar>
