Bug 996457

Summary: LUKSDevice map name always becomes luks-$UUID once the slave is formatted
Product: [Fedora] Fedora Reporter: Jan Synacek <jsynacek>
Component: python-blivetAssignee: David Lehman <dlehman>
Status: CLOSED ERRATA QA Contact: Fedora Extras Quality Assurance <extras-qa>
Severity: unspecified Docs Contact:
Priority: unspecified    
Version: 20CC: anaconda-maint-list, bcl, dlehman, jsafrane, jsynacek
Target Milestone: ---Keywords: Reopened
Target Release: ---   
Hardware: Unspecified   
OS: Unspecified   
Whiteboard:
Fixed In Version: python-blivet-0.22-1.fc20 Doc Type: Bug Fix
Doc Text:
Story Points: ---
Clone Of: Environment:
Last Closed: 2013-10-17 16:31:58 UTC Type: Bug
Regression: --- Mount Type: ---
Documentation: --- CRM:
Verified Versions: Category: ---
oVirt Team: --- RHEL 7.3 requirements from Atomic Host:
Cloudforms Team: --- Target Upstream Version:
Embargoed:
Attachments:
Description Flags
Reproducer none

Description Jan Synacek 2013-08-13 08:14:44 UTC
Created attachment 786041 [details]
Reproducer

Description of problem:
Creating LUKSDevice does not work. For more details, see below.


Version-Release number of selected component (if applicable):
python-blivet-0.19-1.fc20.noarch


How reproducible:
Always


Steps to Reproduce:
1. Create a LUKS partition (/dev/vda12 in my case)
2. Run the reproducer (tweak partition/password if necessary)
3. Observe the error


Actual results:
Program output:
 DEBUG: d.format.device: /dev/vda12
 DEBUG: luksdevice.format.device: /dev/mapper/luks-test-blivet
 DEBUG: luksdevice.format.device: /dev/mapper/luks-test-blivet
 DEBUG: d.format.device: /dev/mapper/luks-test-blivet

and then a traceback:
FormatSetupError                          Traceback (most recent call last)
/usr/lib/python2.7/site-packages/IPython/utils/py3compat.pyc in execfile(fname, *where)
    176             else:
    177                 filename = fname
--> 178             __builtin__.execfile(filename, *where)

/home/jsynacek/openlmi-storage-nfs/blivet-luks-bug2.py in <module>()
     27 
     28 action = blivet.ActionCreateDevice(luksdevice)
---> 29 action.execute()

/usr/lib/python2.7/site-packages/blivet/deviceaction.pyc in execute(self)
    270 
    271     def execute(self):
--> 272         self.device.create()
    273 
    274     def requires(self, action):

/usr/lib/python2.7/site-packages/blivet/devices.pyc in create(self)
    784         """ Create the device. """
    785         log_method_call(self, self.name, status=self.status)
--> 786         self._preCreate()
    787         try:
    788             self._create()

/usr/lib/python2.7/site-packages/blivet/devices.pyc in _preCreate(self)
    775             raise DeviceError("device has already been created", self.name)
    776 
--> 777         self.setupParents()
    778 
    779     def _create(self):

/usr/lib/python2.7/site-packages/blivet/devices.pyc in setupParents(self, orig)
    839             # set up the formatting, if present
    840             if _format.type and _format.exists:
--> 841                 _format.setup()
    842 
    843     def _getSize(self):

/usr/lib/python2.7/site-packages/blivet/formats/luks.pyc in setup(self, *args, **kwargs)
    166             return
    167 
--> 168         DeviceFormat.setup(self, *args, **kwargs)
    169         crypto.luks_open(self.device, self.mapName,
    170                        passphrase=self.__passphrase,

/usr/lib/python2.7/site-packages/blivet/formats/__init__.pyc in setup(self, *args, **kwargs)
    345 
    346         if not self.device or not os.path.exists(self.device):
--> 347             raise FormatSetupError("invalid device specification")
    348 
    349     def teardown(self, *args, **kwargs):



Expected results:
The LUKS device is opened as expected.


Additional info:
Why is d.format.device changed to /dev/mapper/luks-test-blivet after calling the LUKSDevice constructor?
The conditional on line 346 then has to fail, since the path surely does not exist.

If you uncomment the marked line in the reproducer, the LUKS device gets opened as expected. The output
then looks like so:

DEBUG: d.format.device: /dev/vda12
DEBUG: luksdevice.format.device: /dev/mapper/luks-test-blivet
DEBUG: luksdevice.format.device: /dev/vda12
DEBUG: d.format.device: /dev/vda12

Howerver, it's possible to call it repeatedly without producing any error whatsoever, which I consider a bug too.

Comment 1 Jan Safranek 2013-08-13 08:32:02 UTC
Some background how OpenLMI uses LUKS / Blivet:

We want to be able separately control creation of LUKSFormat and opening it as LUKSDevice.

I.e. remote application scans a system and finds empty partition. The application then creates LUKSFormat there, *without opening it*.

As second step, (potentially different) remote application scans the same system and finds a LUKSFormat there and decides to *open* it - that's why we need working LUKSDevice() constructor and ActionCreateDevice. The same application might close the LUKSDevice later (ActionDestroyDevice with LUKSDevice), while leaving the LUKSFormat there to be opened again later.

(and that's why we need blivet.reset() not to open any LUKS formats it finds, see bug #996118 - reset() should just scan the system, without modifying it).

Comment 2 David Lehman 2013-08-13 15:33:41 UTC
(In reply to Jan Safranek from comment #1)
> need working LUKSDevice() constructor and ActionCreateDevice. The same
> application might close the LUKSDevice later (ActionDestroyDevice with
> LUKSDevice), while leaving the LUKSFormat there to be opened again later.

If you want to close a device, use device.teardown -- not device.destroy. StorageDevice.destroy permanently _destroys_ the device.

Basically, there will always be a LUKSDevice associated with a device that contains a LUKS format. Whether or not that LUKS format can be opened is a different matter (decided by presence of a valid key/passphrase).

Comment 3 David Lehman 2013-08-13 15:37:49 UTC
From your reproducer:

luksdevice = blivet.devices.LUKSDevice('luks-test-blivet',
                                       size=d.size,
                                       uuid=d.format.uuid,
                                       sysfsPath=d.sysfsPath,
                                       format=d.format, # <-- here's your problem
                                       parents=[d],
                                       exists=False)

Two devices cannot share the same DeviceFormat instance. Every block device contains its own DeviceFormat instance. The device that is formatted as luks has a LUKS instance as its format. The open/mapped device that represents the decrypted/usable luks device (eg: /dev/mapper/luks-whatever) has a format that represents what is on the decrypted device, such as an ext4 filesystem. Does this clarify things?

Comment 4 Jan Synacek 2013-08-14 08:51:40 UTC
Does it mean that I have to know what filesystem there is underneath the luks layer and prepare the format accordingly? That doesn't sound right to me. I'm still confused about what to put into the format parameter.

Comment 5 David Lehman 2013-08-14 14:18:10 UTC
You don't have to pass a format at all if you don't know what you'll be formatting it as or if you plan to leave it unformatted for the time being.

Comment 6 Jan Synacek 2013-08-15 06:28:46 UTC
Ok, the following seems to work:

import blivet

b = blivet.Blivet()
b.reset()
d = b.devicetree.getDeviceByPath('/dev/vda12')
d.format.passphrase = 'fiembi43mygf'
d.format.mapName = 'luks-test-blivet'
luksdevice = blivet.devices.LUKSDevice('luks-test-blivet',
                                       uuid=d.format.uuid,
                                       parents=[d])

action = blivet.ActionCreateDevice(luksdevice)
action.execute()

Is it supposed to work like that? I mean the part where I'm setting passphrase and mapName in the *original* format.

Comment 7 David Lehman 2013-08-15 15:36:40 UTC
(In reply to Jan Synacek from comment #6)
> Is it supposed to work like that? I mean the part where I'm setting
> passphrase and mapName in the *original* format.

Normally you would create a new luks format if you want to create a new luks device:

# no need to set map name as it will get updated automatically
fmt = blivet.formats.getFormat("luks", passphrase="blahblahblah")
b.formatDevice(d, fmt)

luksdevice = blivet.devices.LUKSDevice('luks-whatever',
                                       parents=[d])
b.createDevice(luksdevice)

b.doIt() # or b.devicetree.processActions()

Comment 8 Jan Synacek 2013-08-28 07:36:45 UTC
import blivet

b = blivet.Blivet()
b.reset()
d = b.devicetree.getDeviceByPath('/dev/vda12')

fmt = blivet.formats.getFormat("luks", passphrase='fiembi43mygf')
b.formatDevice(d, fmt)
luksdevice = blivet.devices.LUKSDevice('luks-test-blivet',
                                       parents=[d])

b.createDevice(luksdevice)
b.doIt()

This works, except that the LUKS device is opened as luks-<uuid>, not 'luks-test-blivet'. It seems that the first argument of LUKSDevice() gets somehow ignored. I even tried to set map name whereever it was possible, still ignored.

Comment 9 David Lehman 2013-08-28 13:39:49 UTC
(In reply to Jan Synacek from comment #8)
> This works, except that the LUKS device is opened as luks-<uuid>, not
> 'luks-test-blivet'. It seems that the first argument of LUKSDevice() gets
> somehow ignored. I even tried to set map name whereever it was possible,
> still ignored.

Right -- this is a relic from anaconda usage. I need to make the automatic transition to luks-$UUID for the map name installer-only behavior.

Comment 10 Fedora Update System 2013-09-06 00:37:09 UTC
python-blivet-0.21-1.fc20 has been submitted as an update for Fedora 20.
https://admin.fedoraproject.org/updates/python-blivet-0.21-1.fc20

Comment 11 Fedora Update System 2013-09-06 17:27:32 UTC
Package python-blivet-0.21-1.fc20:
* should fix your issue,
* was pushed to the Fedora 20 testing repository,
* should be available at your local mirror within two days.
Update it with:
# su -c 'yum update --enablerepo=updates-testing python-blivet-0.21-1.fc20'
as soon as you are able to.
Please go to the following url:
https://admin.fedoraproject.org/updates/FEDORA-2013-15976/python-blivet-0.21-1.fc20
then log in and leave karma (feedback).

Comment 12 Fedora Update System 2013-09-06 21:48:18 UTC
python-blivet-0.22-1.fc20 has been submitted as an update for Fedora 20.
https://admin.fedoraproject.org/updates/python-blivet-0.22-1.fc20

Comment 13 Jan Synacek 2013-09-10 11:12:58 UTC
Traceback (most recent call last):
  File "blivet-luks-bug2-bz.py", line 13, in <module>
    b.doIt()
  File "/usr/lib/python2.7/site-packages/blivet/__init__.py", line 310, in doIt
    self.devicetree.processActions()
  File "/usr/lib/python2.7/site-packages/blivet/devicetree.py", line 237, in processActions
    action.execute()
  File "/usr/lib/python2.7/site-packages/blivet/deviceaction.py", line 272, in execute
    self.device.create()
  File "/usr/lib/python2.7/site-packages/blivet/devices.py", line 786, in create
    self._preCreate()
  File "/usr/lib/python2.7/site-packages/blivet/devices.py", line 777, in _preCreate
    self.setupParents()
  File "/usr/lib/python2.7/site-packages/blivet/devices.py", line 841, in setupParents
    _format.setup()
  File "/usr/lib/python2.7/site-packages/blivet/formats/luks.py", line 164, in setup
    raise LUKSError("luks device not configured")
blivet.errors.LUKSError: luks device not configured

I'm getting this with the same code snipped as in comment 8.

# rpm -q python-blivet
python-blivet-0.22-1.fc21.noarch

Comment 14 Fedora End Of Life 2013-09-16 17:12:06 UTC
This bug appears to have been reported against 'rawhide' during the Fedora 20 development cycle.
Changing version to '20'.

More information and reason for this action is here:
https://fedoraproject.org/wiki/BugZappers/HouseKeeping/Fedora20

Comment 15 Fedora Update System 2013-09-26 06:19:51 UTC
python-blivet-0.22-1.fc20 has been pushed to the Fedora 20 stable repository.  If problems still persist, please make note of it in this bug report.

Comment 16 Jan Safranek 2013-10-14 12:17:18 UTC
I'm still able to reproduce the crash reported in comment #13 using python-blivet-0.23-1.fc21.noarch.

blivet creates the LUKS on the right device, but fails shortly after that, still in devicetree.processActions().

Comment 17 David Lehman 2013-10-17 16:31:58 UTC
(In reply to Jan Synacek from comment #8)
> fmt = blivet.formats.getFormat("luks", passphrase='fiembi43mygf')
> b.formatDevice(d, fmt)
> luksdevice = blivet.devices.LUKSDevice('luks-test-blivet',
>                                        parents=[d])

You should pass the name to the LUKS constructor as well as the LUKSDevice constructor. Your getFormat call should look like this:

fmt = blivet.formats.getFormat("luks",
                               passphrase='fiembi43mygf',
                               name='luks-test-blivet')