
On Wed, Nov 19, 2008 at 01:50:09PM -0500, Shahar Frank wrote:
Hi All, here is an initial version of the operations required for SolidICE and the proposed high level interface.
I would like to discuss how to map it to libvirt calls and what libvirt calls are missing.
Thanks,
Shahar Frank
HostLevel --------- enumarateLuns(): return: returns all luns visible by the host. In case multipathing is enabled then only the multipath device should be in the return list.
libvirt does not yet have support for SCSI FiberChannel, but it will be added following this forthcoming release. libvirt's storage model has two core concepts, a 'pool' object, which contains multiple 'volume' objects. There are different types of pool for each type of storage, so we intend to add a 'scsi' storage pool. The way it will work is that each SCSI HBA will be seen as its own storage pool. The LUNs for a HBA will then be volumes within the pool. So for enumerateLuns, a combination of API calls would be relevant. - virConnectFindStoragePoolSources() with a type='scsi' will discover all available HBAs, and return XML describing them. For each HBA you care about, you would define a storage pool and active it using - virStoragePoolDefineXML() - virStoragePoolStart() Then, for each storage pool you can get the list of LUNs by asking for its volumes with - virStoragePoolListVolumes()
enumerateISCSILuns(target): params: target - ISCSI target Description: enumerate all ISCSI luns on a specific target return: list of
This will work in exactly the same way as for SCIS, except that instead of calling virConnectFindStoragePoolSources with type='scsi', you'd call it with type='iscsi'. You'd also need to give a 'srcSpec' XML document with details of the host providing the iSCSI server. With this libvirt will connect to the iSCSI server, and ask it for all its exported iSCSI targets. The returned XML will provide details on each target. For each target you wish to use, then you call virStoragePoolDefinXML and virStoragePoolStart(), as before.
getBlockInfo(name or UUID): return: at least uuid & size
Once you have a virStorageVolPtr object, you can use the API virStorageVolGetInfo this gives you logical capacity, and actual allocation - allocation may be less than capacity if querying a file based volume like a sparse file, or qcow2. To get a persistent name, akin to a UUID, you can use the API virStorageVolGetKey() for SCSI LUNS, the volume key will be based off the UUID avialable.
enumerateVGs(): return: VG UUID list
This is very similar to the other enumerate methods. You'd call virConnectFindStoragePoolSources() with type='logical' this gives you back XML describing all available volume groups on a machine. For each volume group you want to use, you can then define a storage pool, and query volumes within it.
open issues - should we assume ISCSI auto connect or FC login?
libvirt can take care of that when needed, which is why we have a two step process for accessing a storage pool - virStoragePoolDefineXML() will write out a persistent configuratipon file with details of the pool. - virStoragePoolCreate() will actually login to the iSCSI target, or activate the LVM volume group, or equivalent operations needed for the type of storage being accessed. NB 'Create' is probably better thought of as 'Start' You can later call virStoragePoolDestroy() to logout if desired. If you want login to happen automatically when the machine boots you can call virStoragePoolSetAutostart() to turn on the autostart flag. Authentication is an open, unresolved issue & welcome suggestions for how to deal with this. Our original thoughts were to just embed the iSCSI username/password in the XML configuration file for the storage pool, but we've not implemented this in the backend yet.
StoragePool level ----------------- createVolumeGroup(name, devices): params: name = name devices - a list of UUIDs description: Should create a volume group out of the UUID list In case multipathing is enabled then only the multipath device should be used In case it is not a PV yet then a PV is to be created. Return: Uuid of the VG
This is accomplished with a combination of two methods. First you define the configuration for the pool, which requires giving the volume group name, and list of devices to become PVs in the VG. This is done with virStoragePoolDefineXML(). Then you actually format the PVs & construct the VG by invoking the virStoragePoolBuild() method. Once this is done, the virStoragePoolCreate() method will activate the VG.
removeVolumeGroup(VG): params: VG - uuid of the Volume group Description: Remove all remains for the VolumeGroup (LVs, PVs ...) Return: Sucsess/failure
Given a existing virStoragePoolPtr object, you can blow away the entire volume group using the API virStoragePoolDelete
mountNFS(server, remotePath, localPath, params) params: server - the NFS server name or IP temotePath - remote server export path localPath - local path to mount on params - nfs mount params description: mounts the remote export onto the local path using the mount params return: success/failure
Each NFS mount is modelled as a storage pool. So as before, you'd create a XML document providing the configuration for server, remotePath, localPath, and then invoke virStoragePoolDefineXML() Then you can use virStoragePoolCreate() to mount the NFS server. Once done, you can use virStoragePoolListVolumes() to query files within the mount.
unmount(localPath, forceFlag) params: localPath - the local path to unmount forceFlag - a flag indicating whether to force unmount description: unmounts local path (trivial) return: success/failure
The virStoragePoolDestory() method will unmount the NFS volume. If you wish to also remove the persistent libvirt config file for the pool, then also issue virStoragePoolUndefine
Open issues: 1. NFS configuration persistency? 2. What happens in case the libvirt is restarted should it be reconfigured?
Most objects in the libvirt API have two modes of setup, one which is persistent, and one which is transient. The examples I've given earlier all describe persistent use. The general pattern is - virStoragePoolDefineXML() writes the persistent config - virStoragePoolCreate() activates the backend from persistent config - virStoragePoolDestroy() de-activates the backend - virStoragePoolUndefine() deletes the persistent config If you instead prefer to use transient objects, then you can do - virStoragePoolCreateXML() - activates a backend directly from XML - virStoragePoolDestroy() - de-actives the backend With this style, no persistent configuration file is written out to disk, so once destroyed, libvirt looses all knowledge of it. If libvirtd is restarted, all information about transient objects is lost. Persistent objects will be identified when libvirtd is started again. For persistent objects you can also set a autostart flag, so that libvirt will immediately activate them, if not already running.
VolumeGroup level ----------------- listPV(VG): params: VG - Volume group UUID Description: Lists all PV in a specific volume group Return: A list of PV UUIDs
The XML description for a virStoragePoolPtr object pointing to a VG, will include information about the physical volumes it contains.
infoPV(VG, PV) params: VG - Volume group UUID PV - Physical volume UUID description: trivial return: returns the PV information (at least size & path)
Given a device path or device key (akin to UUID) you can use one of the methods virStorageVolLookupByPath virStorageVolLookupByKey to retrieve a virStorageVolPtr object for it. Once you have one of these, then you can call virStorageVolGetInfo, to find out its capacity / allocation
extendVolumeGroup(VG, devices): params: VG - Volume Group UUID devices - a list of UUIDs description: This function adds Phisical Volume to the VolumeGroup. Each UUID device is checked, In case multipathing is enabled then only the multipath device should be used (PV create in case it's not) and added to the volume group return: success/fauilure
removePV(VG, PV): params: VG - Volume Group UUID PV - Physical volume's UUID to be removed description: removes the physical volume return: success failure
These two are not currently implemented in libvirt. The intent is though, that you can re-define the XML for an existing virStoragePoolPtr object, with PV devices added/removed from the XML. Then invoke the virStoragePoolBuild() method to actually make the changes to the underlying volume group.
LV operations -------------- listLVs(VG): params: VG - Volume Group UUID description: trivial return: list of all LV UUIDs
This is again possible with the virStoragePoolListVolumes() method once you have an active virStoragePoolPtr object for a volume group.
infoLV(VG, LV): params: VG - Volume Group UUID LV - Logical Volume UUID description: trivial return: returns LV information (at least size and path)
Given a virStorageVolPtr object for a LV, you can call virStorageVolGetInfo to get size information, or virStorageVolGetXMLDesc() for more general metadata.
createLV(VG, LvName, size): params: VG - Volume Group UUID LvName - name of the logical volume
Given a virStoragePoolPtr object refering to a volume group, you can use virStorageVolCreateXML() to allocate a new logical volume within it. Similarly virStorageVolDelete will remove a logical volume. All the method names I'm refering to here are the C apis. If you just want to experiment & play with the APIs to get a better understanding of them, the 'virsh' command line tool exposes practically all of the functionality in a fairly friendly manner. For example, using the virConnectFindStoragePoolSources() method to disocver LVM volume groups is possible with: # virsh find-storage-pool-sources-as logical <sources> <source> <device path='/dev/sda2'/> <name>HostVG</name> <format type='lvm2'/> </source> </sources> You can then use, virStoragePoolDefineXML with info by running the 'virsh pool-define' command, and so on - 'virsh help' will show you all the possible commands. 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 :|