New: [rhinstaller/blivet/pulls/60 master] Master tasks

mulkieran installerbot-noreply at redhat.com
Wed Mar 25 22:47:39 UTC 2015


The purpose of this patch is to make blivet able to operate in a context in which it is aware of what external dependencies are available. What this means is a couple of things:

* If a DeviceAction that requires an external resource is constructed and that resource is unavailable then the constructor will raise an exception. Currently these exceptions are ValueErrors, which are the same kind of exception raised when the device or some other aspect of the environment has a problem.

* All methods on formats like formattable, supported, are environment aware. Previously they usually returned True if the functionality was implemented in blivet...now they only return True if the functionality is implemented _and_ also the external tool required is available. So, where anaconda uses methods to determine whether to display a particular filesystem type in a combo, those should all return False if the operations they check can not be run.

* Ultimately, if by some chance a method is called requiring a task with an unavailable external dependency, an exception will be raised indicating that the problem is the unavailability of the external application. This is already implemented in the filesystem format tasks and will be implemented in the libblockdev plugins. There are two external apps in devices, multipath and kpartx for which perhaps it should be implemented as well.

Availability of resources has its own separate simple packages. There are only two kinds of external resources so far, libblockdev plugins and executables. libblockdev plugin availability is checked by loadedness, which is always going to be correct on an installed system. executable are available if their names are in $PATH.

There are three different categories of things to track availability of, in order of difficulty are:
* non-filesystem formats
* filesystem formats
* devices

Non-filesystem formats are easy, because if they depend on anything external they depend on exactly one libblockdev plugin. SwapSpace is an example and all others are handled similarly. All methods like formattable, supportable, typically just check whether the plugin is available. There's just not much to look at for this.

Filesystem formats are bit harder. Each filesystem has a lot of tasks to do, create, mount, fsck, info getting, size calculating, etc, and these can be handled by different applications that get installed by different packages. To handle this, these tasks are abstracted out into subclasses of Task and each is set up with an unavailable and an unimplemented method. It is the availability of these tasks that is checked for the various filesystem format properties. Abstracting these tasks into separate tasks forms a significant part of these patches but these probably don't require a lot of scrutiny either. There are no additional tests for these tasks, as they are like friend classes of the filesystem formats and don't really make sense being tested outside the formats classes. They all pass a bunch of regression tests on filesystem formats.

Devices is of course the hardest. Besides device classes just generally being more intricate there are the following problems:
* Calculations must be done recursively on ancestor devices.
* Dependencies seem to accumulate as you travel down the class hierarchy.
* Abstracting into tasks like for filesystem formats is not going to happen, but devices aren't really like non-filesystems formats in having just one simple dependency, either.

Under these circumstances it is impossible to be correct about all dependencies so I have aimed for being conservative, i.e., sometimes raising an exception when constructing a DeviceAction that actually could go through by some special circumstances. There are only two mechanisms:
* an ability to find unavailable external resources for a device and all its ancestors
* an ability to find unavailable external resources required for setting up formats for the formats on all the ancestors of a device
I've chosen these because it seems, from study of the code, that for almost every DeviceAction a setup task must be performed that requires doing things to the device and to the formats on that device.

Generally there will be some small check on the specifics of the action as well; for example, the ActionDestroyFormat class has a check whether the format to be destroyed is actually destroyable.
When creating a format, I check whether the format is formattable, DeviceFormat's are not formattable so an exception is raised in that case.

Currently, the search for unavailable external resources for a device and all its ancestors has only two modes, Default and Destroy. I chose to add the Destroy mode, because a PartitionDevice has a dependency on the dm plugin but only in the _postDestroy method and AFAICT, it would be a little harsh to require the dm plugin for every combination of DeviceAction, PartitionDevice. The mode mechanism is ready to be extended as necessary to refine the search to only relevant dependencies in case some other situation comes up where the DeviceAction constructor would raise an exception even though the action could be succesfully executed (and it is considered worthwhile to distinguish).

For checking whether formats are setupable I wrote two functions that mirror the structure of Device.setup and Device.setupParents, so that these function do not check the setupability of formats that setup does not actually try to setup.

In summary, it's probably OK to skip the code about formats, although you might want to look at the Tasks abstractions, and to focus on how I deal with devices, and how I insert calls into DeviceAction classes. That's the tricky part.
-- 
To view this pull request on github, visit https://github.com/rhinstaller/blivet/pull/60


More information about the anaconda-patches mailing list