Skip to content

Commit e23d354

Browse files
Merge pull request #1243 from vojtechtrefny/3.10-devel_dbus-example
tests: add dbus example to traverse the devices and call test the fac…
2 parents d631420 + f85412f commit e23d354

File tree

2 files changed

+252
-13
lines changed

2 files changed

+252
-13
lines changed

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,3 +28,4 @@ tests/pylint/.pylint.d/
2828
MANIFEST
2929
misc/.vagrant
3030
ChangeLog
31+
.vscode

examples/dbus_client.py

Lines changed: 251 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,257 @@
1+
# Copyright (C) 2023 Red Hat, Inc.
2+
#
3+
# This copyrighted material is made available to anyone wishing to use,
4+
# modify, copy, or redistribute it subject to the terms and conditions of
5+
# the GNU General Public License v.2, or (at your option) any later version.
6+
# This program is distributed in the hope that it will be useful, but WITHOUT
7+
# ANY WARRANTY expressed or implied, including the implied warranties of
8+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
9+
# Public License for more details. You should have received a copy of the
10+
# GNU General Public License along with this program; if not, write to the
11+
# Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
12+
# 02110-1301, USA. Any Red Hat trademarks that are incorporated in the
13+
# source code or documentation are not subject to the GNU General Public
14+
# License and may only be used or replicated with the express permission of
15+
# Red Hat, Inc.
16+
#
17+
# Red Hat Author(s): Todd Gill <[email protected]>
18+
#
119

20+
import argparse
21+
import sys
222
import dbus
323

4-
bus = dbus.SystemBus()
524

6-
# This adds a signal match so that the client gets signals sent by Blivet1's
7-
# ObjectManager. These signals are used to notify clients of changes to the
8-
# managed objects (for blivet, this will be devices, formats, and actions).
9-
bus.add_match_string("type='signal',sender='com.redhat.Blivet1',path_namespace='/com/redhat/Blivet1'")
25+
import blivet
26+
from blivet.devicefactory import (
27+
DEVICE_TYPE_LVM,
28+
DEVICE_TYPE_MD,
29+
DEVICE_TYPE_BTRFS,
30+
DEVICE_TYPE_STRATIS,
31+
)
1032

11-
blivet = bus.get_object('com.redhat.Blivet1', '/com/redhat/Blivet1/Blivet')
12-
blivet.Reset()
33+
OBJECT_MANAGER = "org.freedesktop.DBus.ObjectManager"
34+
BUS = dbus.SystemBus()
35+
BUS_NAME = "com.redhat.Blivet0"
36+
TOP_OBJECT = "/com/redhat/Blivet0/Blivet"
37+
REVISION_NUMBER = 1
38+
REVISION = f"r{REVISION_NUMBER}"
1339

14-
object_manager = bus.get_object('com.redhat.Blivet1', '/com/redhat/Blivet1')
15-
objects = object_manager.GetManagedObjects()
16-
for object_path in blivet.ListDevices():
17-
device = objects[object_path]['com.redhat.Blivet1.Device']
18-
fmt = objects[device['Format']]['com.redhat.Blivet1.Format']
19-
print(device['Name'], device['Type'], device['Size'], fmt['Type'])
40+
MOUNT_POINT = "/testmount"
41+
42+
TIMEOUT = 10 * 1000
43+
44+
# TODO: Add revision to dbus interface. Once completed, update to:
45+
# f"{BUS_NAME}.Blivet.{REVISION}"
46+
BLIVET_INTERFACE = f"{BUS_NAME}.Blivet"
47+
DEVICE_INTERFACE = f"{BUS_NAME}.Device"
48+
FORMAT_INTERFACE = f"{BUS_NAME}.Format"
49+
50+
top_object = BUS.get_object(BUS_NAME, TOP_OBJECT)
51+
blivet_interface = dbus.Interface(
52+
top_object,
53+
BLIVET_INTERFACE,
54+
)
55+
56+
57+
def get_managed_objects():
58+
"""
59+
Get managed objects for /com/redhat/Blivet0
60+
:return: dict of object paths, objects
61+
"""
62+
# TODO: GetManagedObjects is implemented at the /com/redhat/Blivet0 level.
63+
# The other methods are implemented at /com/redhat/Blivet0/Blivet. Is
64+
# that intentional?
65+
object_manager = dbus.Interface(
66+
BUS.get_object(BUS_NAME, "/com/redhat/Blivet0"),
67+
OBJECT_MANAGER,
68+
)
69+
return object_manager.GetManagedObjects(timeout=TIMEOUT)
70+
71+
72+
# pylint: disable=E1101
73+
def remove_device(path, disks_remove):
74+
75+
blivet.util.umount(MOUNT_POINT)
76+
blivet_interface.RemoveDevice(path)
77+
for disk in disks_remove:
78+
blivet_interface.RemoveDevice(disk)
79+
80+
blivet_interface.Commit()
81+
82+
83+
def list_device_objects():
84+
managed_objects = get_managed_objects().items()
85+
86+
return_objects = [
87+
obj_data[DEVICE_INTERFACE]
88+
for _, obj_data in managed_objects
89+
if DEVICE_INTERFACE in obj_data
90+
]
91+
return return_objects
92+
93+
94+
def print_dict(dict_type, dict_to_print):
95+
print(dict_type)
96+
for key, value in dict_to_print.items():
97+
print(" ", key, "\t: ", value)
98+
99+
100+
def print_properties(path, interface):
101+
path = BUS.get_object(BUS_NAME, path)
102+
properties_interface = dbus.Interface(
103+
path, dbus_interface="org.freedesktop.DBus.Properties"
104+
)
105+
props = properties_interface.GetAll(interface)
106+
print_dict(interface, props)
107+
108+
109+
def get_property(path, interface, value):
110+
property_object = BUS.get_object(BUS_NAME, path)
111+
properties_interface = dbus.Interface(
112+
property_object, dbus_interface="org.freedesktop.DBus.Properties"
113+
)
114+
props = properties_interface.GetAll(interface)
115+
return props[value]
116+
117+
118+
def lvm_create(disk_list, fs_name, size):
119+
kwargs = {
120+
"device_type": DEVICE_TYPE_LVM,
121+
"size": size,
122+
"disks": disk_list,
123+
"fstype": "xfs",
124+
"name": fs_name,
125+
"mountpoint": MOUNT_POINT,
126+
"raid_level": "raid1",
127+
}
128+
129+
return blivet_interface.Factory(kwargs)
130+
131+
132+
def btrfs_create(disk_list, fs_name, size):
133+
kwargs = {
134+
"device_type": DEVICE_TYPE_BTRFS,
135+
"size": size,
136+
"disks": disk_list,
137+
"name": fs_name,
138+
"mountpoint": MOUNT_POINT,
139+
"raid_level": "raid1",
140+
"container_raid_level": "raid1",
141+
"fstype": "btrfs",
142+
}
143+
144+
return blivet_interface.Factory(kwargs)
145+
146+
147+
def md_create(disk_list, fs_name, size):
148+
kwargs = {
149+
"device_type": DEVICE_TYPE_MD,
150+
"size": size,
151+
"disks": disk_list,
152+
"fstype": "xfs",
153+
"name": fs_name,
154+
"mountpoint": MOUNT_POINT,
155+
"raid_level": "raid1",
156+
"container_raid_level": "raid1",
157+
}
158+
159+
return blivet_interface.Factory(kwargs)
160+
161+
162+
def stratis_create(disk_list, fs_name, size):
163+
kwargs = {
164+
"device_type": DEVICE_TYPE_STRATIS,
165+
"size": size,
166+
"disks": disk_list,
167+
"name": fs_name,
168+
"mountpoint": MOUNT_POINT,
169+
}
170+
171+
return blivet_interface.Factory(kwargs)
172+
173+
174+
def initialize_disks(init_disks):
175+
for disk in init_disks:
176+
blivet_interface.InitializeDisk(disk)
177+
blivet_interface.Commit()
178+
179+
180+
def test_create_dev(disks_list, storage_type: int, size):
181+
initialize_disks(disks_list)
182+
183+
newdev_object_path = None
184+
185+
if storage_type == blivet.devicefactory.DEVICE_TYPE_LVM:
186+
newdev_object_path = lvm_create(disks_list, "test_lvm_filesystem", size)
187+
elif storage_type == blivet.devicefactory.DEVICE_TYPE_BTRFS:
188+
newdev_object_path = btrfs_create(disks_list, "test_btrfs_filesystem", size)
189+
elif storage_type == blivet.devicefactory.DEVICE_TYPE_MD:
190+
newdev_object_path = md_create(disks_list, "test_md_filesystem", size)
191+
elif storage_type == blivet.devicefactory.DEVICE_TYPE_STRATIS:
192+
newdev_object_path = stratis_create(disks_list, "test_stratis_filesystem", size)
193+
194+
blivet_interface.Commit()
195+
return newdev_object_path
196+
197+
198+
if __name__ == "__main__":
199+
bus = dbus.SystemBus()
200+
201+
parser = argparse.ArgumentParser()
202+
203+
parser.add_argument("--blockdevs", dest="blockdevs", type=str, default="")
204+
args = parser.parse_args()
205+
206+
# Accept a blockdev list in either "/dev/xxx,/dev/xxx" or [/dev/xxx /dev/xxx] format.
207+
blockdevs = (
208+
args.blockdevs.replace("'", "")
209+
.replace(" ", ",")
210+
.replace("[", "")
211+
.replace("]", "")
212+
)
213+
blockdevs_list = blockdevs.split(",")
214+
215+
if len(blockdevs_list) < 2:
216+
print("test requires at least 2 block devices.")
217+
sys.exit(1)
218+
219+
# This adds a signal match so that the client gets signals sent by Blivet1's
220+
# ObjectManager. These signals are used to notify clients of changes to the
221+
# managed objects (for blivet, this will be devices, formats, and actions).
222+
# bus.add_match_string("type='signal',sender=" + BUS_NAME + ",path_namespace=" + TOP_OBJECT)
223+
224+
SIZE = "3 GiB"
225+
blivet_interface.Reset()
226+
227+
objects = get_managed_objects()
228+
229+
device_objects = list_device_objects()
230+
disks = list()
231+
for object_path in blivet_interface.ListDevices():
232+
device = objects[object_path][DEVICE_INTERFACE]
233+
print_properties(object_path, DEVICE_INTERFACE)
234+
print_properties(device["Format"], FORMAT_INTERFACE)
235+
236+
# search for the disk object paths
237+
for to_use in blockdevs_list:
238+
if to_use == get_property(object_path, DEVICE_INTERFACE, "Path"):
239+
disks.append(str(object_path))
240+
241+
print("To Use", disks)
242+
243+
new_object_path = test_create_dev(disks, DEVICE_TYPE_LVM, SIZE)
244+
if new_object_path is not None:
245+
remove_device(new_object_path, disks)
246+
247+
new_object_path = test_create_dev(disks, DEVICE_TYPE_BTRFS, SIZE)
248+
if new_object_path is not None:
249+
remove_device(new_object_path, disks)
250+
251+
new_object_path = test_create_dev(disks, DEVICE_TYPE_MD, SIZE)
252+
if new_object_path is not None:
253+
remove_device(new_object_path, disks)
254+
255+
new_object_path = test_create_dev(disks, DEVICE_TYPE_STRATIS, SIZE)
256+
if new_object_path is not None:
257+
remove_device(new_object_path, disks)

0 commit comments

Comments
 (0)