So here's what I've come up with so far. I have run this past a few folks and hopefully it's in a reasonable shape now. I suspect there may be some aspects that are lacking or need changing but that's what lots of eyes are for. :) Also once we get into implementation it'll flesh itself out. For those who haven't seen this yet, this is an XML markup for qpid modeling. qpid is an implementation of the AMQP specification, see http://cwiki.apache.org/qpid/ for more information. The modeling aspect is pretty new and I don't know if there's any good documentation on it yet. It's also not released yet so I guess that's to be expected.. :) This defines a model or object oriented API that taskomatic will use to talk to the managed nodes. Properties are updated when set on the nodes and statistics are pushed at a regular interval. Methods can be called asynchronously or synchronously. The idea is to unify our communications between the nodes and wui with qpid modeling. If you look at what is available here and what taskomatic, host-status, host-collect and even some of ovirt-identify-node do, you'll see that's pretty much all contained within this model/API. So please take a look and feel free to post questions or comments. Thanks! Ian -- <schema package="ManagedNode"> <!-- This is an object model of a managed node. access: Access mode: RC = Read/Create, RO = read only, RW = read/write. dir: Direction of argument: I = in, O = out, IO = in/out. --> <class name="Node"> <property name="uuid" index="y" type="sstr" access="RC"/> <property name="hypervisor_type" type="sstr" desc="Hypervisor type"/> <property name="hardware_pool_id" type="sstr" desc="Hardware pool this host belongs to"/> <property name="hostname" type="sstr" access="RC" desc="Host name"/> <property name="OS version" type="sstr" access="RC" desc="Operating system information and version"/> <property name="arch" type="sstr" access="RC" desc="Architecture"/> <property name="num_cpus" type="sstr" access="RC" desc="Number of CPUs on system"/> <property name="cpu_speed" type="sstr" access="RC" desc="Speed of CPUs"/> <property name="memory" type="sstr" access="RC" desc="Amount of memory in KB"/> <!-- Statistics are pushed to the broker every 10s by default from the agent. --> <statistic name="load_average" type="count64" unit="message" desc="Load average of host"/> <statistic name="free_memory" type="count64" unit="message" desc="Amount memory available in KB"/> <!-- We may get this for free in the broker. We'll have to see. --> <statistic name="heartbeat" type="count64" unit="message" desc="Incremented in 5 second intervals to measure host availability"/> <method name="create_domain" desc="Start a new domain"> <arg name="description" dir="I" type="sstr" desc="Domain description"/> <arg name="vcpus" dir="I" type="unit32" desc="Number of virtual CPUs"/> <arg name="max_memory" dir="I" type="unit32" desc="Maximum memory allocated in KB"/> <arg name="current_memory" dir="I" type="unit32" desc="Memory to use in KB"/> <arg name="boot_device" dir="I" type="sstr" desc="Boot device"/> <arg name="domain" dir="O" type="sstr" desc="Newly created domain object"/> <arg name="result" dir="O" type="ObjID" desc="Description of result. 'success' or 'failure: error msg'"/> </method> <method name="create_storage_pool" desc="Create a new storage pool"> <arg name="uuid" type="sstr" desc="Storage pool UUID"/> <arg name="description" type="sstr" desc="Storage pool description"/> <arg name="type" type="sstr" desc="Type of storage; nfs, iscsi etc."/> <arg name="allocation" type="uint64" desc="Allocation size in KB"/> <arg name="capacity" type="uint64" desc="Capacity to allocate in bytes"/> <arg name="available" type="uint64" desc="The free space available for allocating new volumes in the pool in KB"/> <arg name="host" type="sstr" desc="Storage host"/> <arg name="device_path" type="sstr" desc="Device path"/> <arg name="pool" dir="O" type="sstr" desc="Newly created storage pool"/> <arg name="result" dir="O" type="ObjID" desc="Description of result. 'success' or 'failure: error msg'"/> </method> </class> <class name="Domain"> <property name="uuid" type="sstr" desc="Domain UUID"/> <property name="boot_volume" type="ObjID" desc="Boot storage volume object"/> <property name="boot_device" type="sstr" desc="Boot device"/> <property name="num_vcpus" type="uint32" desc="Number of virtualized CPUs for domain"/> <property name="num_vcpus_used" type="uint32" desc="Number of virtualized CPUs used"/> <property name="memory_allocated" type="uint32" desc="Amount of memory allocated for domain in KB"/> <property name="memory_used" type="uint32" desc="Amount of memory used by domain in KB"/> <property name="vnic_mac_addr" type="sstr" desc="Virtualized NIC MAC address"/> <property name="state" type="sstr" desc="VM State: 'running', 'stopped', 'suspended'"/> <property name="vnc_port" type="uint32" access="RW" index="y" desc="VNC viewer port"/> <!-- Set up an association of hosts to VMs. This will setup a domain list in the node object and give us a reference here to the node object. --> <property name="node" type="objId" reference="Node" desc="Node of this VM"/> <method name="add_volume" desc="Add a storage volume to this VM"/> <arg name="storage_volume" type="ObjID" desc="storage volume to add to Domain"/> <arg name="target" type="sstr" desc="target for volume"/> <arg name="result" dir="O" type="sstr" desc="Description of result. 'success' or 'failure: error msg'"/> </method> <method name="remove_volume" desc="Add a storage volume to this VM"/> <arg name="storage_volume" type="ObjID" desc="storage volume to add to remove"/> <arg name="result" dir="O" type="sstr" desc="Description of result. 'success' or 'failure: error msg'"/> </method> <method name="start" desc="Start stopped VM"/> <arg name="result" dir="O" type="sstr" desc="Description of result. 'success' or 'failure: error msg'"/> </method> <method name="stop" desc="Stop this VM"/> <arg name="result" dir="O" type="sstr" desc="Description of result. 'success' or 'failure: error msg'"/> </method> <method name="destroy" desc="Destroy this VM instance"/> <arg name="result" dir="O" type="sstr" desc="Description of result. 'success' or 'failure: error msg'"/> </method> <method name="suspend" desc="Suspend this VM"/> <arg name="result" dir="O" type="sstr" desc="Description of result. 'success' or 'failure: error msg'"/> </method> <method name="resume" desc="Resume suspended VM"/> <arg name="result" dir="O" type="sstr" desc="Description of result. 'success' or 'failure: error msg'"/> </method> <method name="save" desc="Save this VM"/> <arg name="filename" type="sstr" desc="Name of file to save VM image in"/> <arg name="result" dir="O" type="sstr" desc="Description of result. 'success' or 'failure: error msg'"/> </method> <method name="restore" desc="Restore saved VM"/> <arg name="result" dir="O" type="sstr" desc="Description of result. 'success' or 'failure: error msg'"/> </method> <method name="migrate" desc="Migrate this VM to another host"/> <arg name="host" dir="I" type="ObjID" desc="Object representing a host to migrate to"/> <arg name="result" dir="O" type="sstr" desc="Description of result. 'success' or 'failure: error msg'"/> <arg name="domain" dir="O" type="sstr" desc="New VM object on new host"/> </method> </class> <class name="Pool"> <property name="uuid" type="sstr" desc="Pool UUID"/> <property name="hostname" type="sstr" desc="Pool host"/> <property name="device_info" type="sstr" desc="Target device name or nfs path"/> <property name="type" type="sstr" desc="Storage type"/> <!-- Set up an association of hosts to storage pools. This will setup a list of pools in the node object and give us a reference here to the node. --> <property name="node" type="objId" reference="Node" desc="Node of this storage pool"/> <method name="destroy" desc="Destroy this storage pool"> <arg name="result" dir="O" type="ObjID" desc="Description of result. 'success' or 'failure: error msg'"/> </method> </class> <class name="Volume"> <property name="uuid" type="sstr" access="RC" index="y" desc="Storage Volume UUID"/> <property name="path" type="sstr" desc="Storage volume path"/> <property name="size" type="sstr" desc="Volume size in KB"/> <property name="type" type="sstr" desc="Storage type"/> <property name="lun" type="sstr" desc="Target lun if iscsi"/> <!-- A storage volume is linked to a domain. --> <property name="domain" type="objId" reference="Domain" desc="Domains using this storage volume"/> <!-- And also linked to its storage pool. I think we can make this populate as soon as the storage pool is created on the host, so a list of volumes would show up in the pool as a property. --> <property name="storage_pool" type="objId" reference="Pool" desc="Pool where this storage volume exists"/> </class> </schema>
On Wed, Jul 09, 2008 at 09:55:44PM -0700, Ian Main wrote:> So please take a look and feel free to post questions or comments. > > <method name="create_domain" desc="Start a new domain"> > <arg name="description" dir="I" type="sstr" desc="Domain description"/> > <arg name="vcpus" dir="I" type="unit32" desc="Number of virtual CPUs"/> > <arg name="max_memory" dir="I" type="unit32" desc="Maximum memory allocated in KB"/> > <arg name="current_memory" dir="I" type="unit32" desc="Memory to use in KB"/> > <arg name="boot_device" dir="I" type="sstr" desc="Boot device"/> > > <arg name="domain" dir="O" type="sstr" desc="Newly created domain object"/> > <arg name="result" dir="O" type="ObjID" desc="Description of result. 'success' or 'failure: error msg'"/> > </method>This is a seriously bad direction to take. libvirt explicitly uses XML for passing domain creation information so that it is extendable without having to constantly change the API of the creation methods. IMHO any wire protocol between managed nodes and WUI should map pretty much 1-to-1 onto the libvirt APIs. In fact rather than defining an oVirt AMQP protocol I'd like this to be positioned as the canonical libvirt AMQP protocol. This will enable good interoperability for any other applications using AMQP who also interact with libvirt. For it to be a libvirt AMQP protocol it should be a pretty much direct serialization of libvirt API onto the wire. Sure you'll probably need some oVirt specific bits too for APIs outside the scope of libvirt, such as the broader monitoring / stats stuff oVirt does. So we'll actually want 2 separate AMQP specifications - one for libvirt & one for oVirt. Regards, Daniel -- |: Red Hat, Engineering, London -o- http://people.redhat.com/berrange/ :| |: http://libvirt.org -o- http://virt-manager.org -o- http://ovirt.org :| |: http://autobuild.org -o- http://search.cpan.org/~danberr/ :| |: GnuPG: 7D3B9505 -o- F3C9 553F A1DA 4AC2 5648 23C1 B3DF F742 7D3B 9505 :|
Ian Main wrote:> So here's what I've come up with so far. I have run this past a few folks and hopefully it's in a reasonable shape now. I suspect there may be some aspects that are lacking or need changing but that's what lots of eyes are for. :) Also once we get into implementation it'll flesh itself out. > > For those who haven't seen this yet, this is an XML markup for qpid modeling. qpid is an implementation of the AMQP specification, see http://cwiki.apache.org/qpid/ for more information. The modeling aspect is pretty new and I don't know if there's any good documentation on it yet. It's also not released yet so I guess that's to be expected.. :) > > This defines a model or object oriented API that taskomatic will use to talk to the managed nodes. Properties are updated when set on the nodes and statistics are pushed at a regular interval. Methods can be called asynchronously or synchronously. > > The idea is to unify our communications between the nodes and wui with qpid modeling. If you look at what is available here and what taskomatic, host-status, host-collect and even some of ovirt-identify-node do, you'll see that's pretty much all contained within this model/API. > > So please take a look and feel free to post questions or comments. > > Thanks! > > Ian >This seems to combine state with RPC syntax. Any way of breaking those out into seperate schemas? -- bk
OK, similar idea. I spent a bunch of time looking at the libvirt API and decided that I would keep the properties and object relations in place rather than going to all libvirt style calls. I like the idea of modeling the system and having any state changes pushed up rather than having to poll. I did change the main creation functions to mirror the libvirt calls using XML descriptions. Very good call there. I also switched the create/destroy etc. to use libvirt equivalents. New version is attached. Sorry it took a while. I probably should deal with the >80 width lines at some point too.. Ian -------------- next part -------------- A non-text attachment was scrubbed... Name: managed-node-model.xml Type: application/xml Size: 6887 bytes Desc: not available URL: <http://listman.redhat.com/archives/ovirt-devel/attachments/20080714/fd2b078c/attachment.wsdl>
OK, one more time :) Daniel and I went through it some more and this is where we're at currently. It's basically the libvirt API with some methods moved to properties. I did do one last iteration since Dan last looked at it but at this point I think it'd be best to just implement it and work out the kinks then. This version does not have any lookup methods in it. According to Ted Ross the management infrastructure tracks all the objects and lookups can be done through the management infrastructure. <schema package="Libvirt"> <!-- This is an object model of the libvirt API. access: Access mode: RC = Read/Create, RO = read only, RW = read/write. dir: Direction of argument: I = in, O = out, IO = in/out. --> <!-- In libvirt this is really the 'Connect' class, I may end up changing it.. --> <class name="Node"> <property name="type" type="sstr" desc="Hypervisor type"/> <property name="hostname" type="sstr" access="RC" desc="Host name"/> <property name="version" type="sstr" access="RC" desc="Hypervisor Version"/> <property name="uri" type="sstr" access="RC" desc="URI of libvirt"/> <property name="libvirt_version" type="sstr" access="RC" desc="Version of libvirt on the managed node"/> <!-- Set up an association of the node with the host info class. --> <property name="host_info" type="objId" reference="NodeInfo" desc="Host information and statistics gathered from qpid modeling agent."/> <!-- This should be a property or statistic, but I think it's too slow to poll? --> <method name="get_free_memory" desc="provides the free memory available on the Node."> <arg name="result" dir="O" type="int64" desc="Amount of free memory in KB."/> </method> <method name="define_domain_xml" desc="Define a new domain, but does not start it."> <arg name="xml_desc" dir="I" type="sstr" desc="XML domain description"/> <arg name="domain" dir="O" type="sstr" desc="Newly created domain object"/> </method> <method name="storage_pool_define_xml" desc="Define a new inactive storage pool based on its XML description. The pool is persistent, until explicitly undefined."> <arg name="xml_desc" type="sstr" desc="XML Description of the storage pool"/> <arg name="pool" dir="O" type="ObjID" desc="Newly created storage pool"/> </method> <method name="storage_pool_create_xml" desc="Create a new storage based on its XML description. The pool is not persistent, so its definition will disappear when it is destroyed, or if the host is restarted"> <arg name="xml_desc" type="sstr" desc="XML Description of the storage pool"/> <arg name="pool" dir="O" type="ObjID" desc="Newly created storage pool"/> </method> </class> <!-- Mapped in from the 'Node' class. --> <class name="NodeInfo"> <property name="model" type="sstr"/> <property name="memory" type="int64"/> <property name="cpus" type="int32"/> <property name="mhz" type="int32"/> <property name="nodes" type="int32"/> <property name="sockets" type="int32"/> <property name="cores" type="int32"/> <property name="threads" type="int32"/> </class> <class name="Domain"> <property name="uuid" type="sstr" desc="Domain UUID"/> <property name="name" type="sstr" desc="Domain name"/> <property name="id" type="sstr" desc="Hypervisor Domain id"/> <!-- Set up an association of hosts to VMs. This will setup a domain list in the node object and give us a reference here to the node object. --> <property name="node" type="objId" reference="Node" desc="Node of this VM"/> <property name="domain_info" type="objId" reference="DomainInfo" desc="Domain information. This will be updated on a regular basis."/> <method name="create" desc="Start stopped VM"/> </method> <method name="destroy" desc="Stop this VM"/> </method> <method name="undefine" desc="Undefine the domain"/> </method> <method name="suspend" desc="Suspend this VM"/> </method> <method name="resume" desc="Resume suspended VM"/> </method> <method name="save" desc="Save this VM"/> <arg name="filename" type="sstr" desc="Name of file to save VM image in"/> </method> <method name="restore" desc="Restore saved VM"/> <arg name="filename" type="sstr" desc="Name of file to restore from"/> </method> <method name="shutdown" desc="Shutdown a VM"/> </method> <method name="reboot" desc="Reboot VM"/> </method> <method name="xml_desc" desc="Return an XML description of the domain."/> <arg name="description" dir="O" type="sstr" desc="XML description of the domain."/> </method> <method name="migrate" desc="Migrate this VM to another host"/> <arg name="destination_node" dir="I" type="ObjID" desc="Object representing destination host."/> <arg name="flags" dir="I" type="int32" desc="Flags for migration, see documentation for details."/> <arg name="new_domain_name" dir="I" type="sstr" desc="New domain name on new host if applicable."/> <arg name="uri" dir="I" type="sstr" desc="Destination hostname/URI as seen from host."/> <arg name="bandwidth" dir="I" type="int32" desc="Maximum bandwidth to consume in Mbps."/> <arg name="domain" dir="O" type="ObjID" desc="New VM object on new host"/> </method> </class> <class name="DomainInfo"> <property name="state" type="sstr" desc="State of Domain. 'suspended', 'running' etc."/> <property name="maximum_memory" type="int64" desc="Maximum memory allowed in KB."/> <property name="memory" type="int64" desc="Memory used in KB."/> <property name="num_vcpus" type="int32" desc="Number of virtual CPUs."/> <property name="cpu_time" type="int64" desc="CPU time used in nanoseconds."/> </class> <class name="Pool"> <property name="uuid" type="sstr" desc="Pool UUID"/> <property name="name" type="sstr" desc="Pool host"/> <!-- Set up an association of hosts to storage pools. This will setup a list of pools in the node object and give us a reference here to the node. --> <property name="node" type="objId" reference="Node" desc="Node of this storage pool"/> <method name="xml_desc" desc="Return an XML description of the storage pool."/> <arg name="description" dir="O" type="sstr" desc="XML description of the storage pool."/> </method> <method name="create" desc="Starts an inactive storage pool."> </method> <method name="destroy" desc="Destroy an active storage pool. This will deactivate the pool on the host, but keep any persistent config associated with it. If it has a persistent config it can later be restarted with a create() call"> </method> <method name="delete" desc="Destroy the pool and delete its definition"> </method> <method name="create_volume_xml" desc="Create a storage volume within a pool based on an XML description. Not all pool types support volume creation."> <arg name="xml_desc" type="sstr" desc="XML Description of the volume to create"/> <arg name="volume" dir="O" type="ObjID" desc="Newly created volume"/> </method> <method name="lookup_volume_by_name" desc="Look up a storage volume by name."> <arg name="volume_name" dir="I" type="sstr" desc="Volume name."/> <arg name="volume" dir="O" type="ObjID" desc="Volume if found."/> </method> <method name="lookup_volume_by_key" desc="Look up a storage volume by key."> <arg name="volume_key" dir="I" type="sstr" desc="Volume key."/> <arg name="volume" dir="O" type="ObjID" desc="Volume if found."/> </method> <method name="lookup_volume_by_path" desc="Look up a storage volume by path."> <arg name="volume_path" dir="I" type="sstr" desc="Volume path."/> <arg name="volume" dir="O" type="ObjID" desc="Volume if found."/> </method> </class> <class name="Volume"> <property name="key" type="sstr" desc="Storage volume key"/> <property name="path" type="sstr" desc="Storage volume path"/> <property name="name" type="sstr" desc="Storage volume name"/> <property name="storage_pool" type="objId" reference="Pool" desc="Pool where this storage volume exists"/> <method name="xml_desc" desc="Return an XML description of the volume."/> <arg name="description" dir="O" type="sstr" desc="XML description of the volume."/> </method> </class> </schema>