Compare commits

...

25 Commits

Author SHA1 Message Date
Marek Marczykowski-Górecki 9593f58731
anaconda 25.20.9-17, qubes-anaconda-addon 4.0.11-1
4 years ago
Marek Marczykowski-Górecki 9c8a8d2fb4
anaconda-addon: run salt into VMs too
4 years ago
Marek Marczykowski-Górecki 967c9caa7c
Prefer createrepo_c over createrepo
4 years ago
Marek Marczykowski-Górecki 87116a2094
anaconda: allow user setup durign initial-setup phase, if kickstart wishes so
4 years ago
Marek Marczykowski-Górecki 32b3a210e0
Make proper text-based initial setup UI
4 years ago
Marek Marczykowski-Górecki 556b584f74
Move applying configuration to kickstart addon
4 years ago
Marek Marczykowski-Górecki 0ec125b967
anaconda 25.20.9-16, blivet 2.1.11-6
5 years ago
Marek Marczykowski-Górecki 91728177c2
anaconda: fix required disk space reporting in reclaim space dialog
5 years ago
Marek Marczykowski-Górecki 12cc054a74
blivet: do not mount pre-existing partitions and do not detect OS there
5 years ago
Marek Marczykowski-Górecki 1abde9cad3
anaconda: do not drop /boot from automatic partitioning
5 years ago
Marek Marczykowski-Górecki 40a1574500
blivet: Double default LVM thin pool metadata size
5 years ago
Marek Marczykowski-Górecki 7c2d9b37e3
blivet: update to 2.1.11
5 years ago
Frédéric Pierret (fepitre) 70d4252d91
travis: switch to bionic
5 years ago
Marek Marczykowski-Górecki a089792060
anaconda 25.20.9-15, lorax-templates-qubes 4.0.6, qubes-anaconda-addon 4.0.10
5 years ago
Marek Marczykowski-Górecki 3541eda275
comps: update debian template description
5 years ago
Marek Marczykowski-Górecki 533e8e75bd
anaconda: add plymouth.ignore-serial-consoles boot option by default
5 years ago
Marek Marczykowski-Górecki f3f7ae7a87
lorax-templates-qubes: add plymouth.ignore-serial-consoles kernel option
5 years ago
Marek Marczykowski-Górecki afd1fe2d41
qubes-anaconda-addon: update default template
5 years ago
Marek Marczykowski-Górecki 60af84f159
comps: update template versions for R4.0.2
5 years ago
Marek Marczykowski-Górecki 3c12390129
qubes-release 4.0-8
5 years ago
unman 2ce7edc6fe
Add new onion addresses to repo lists
5 years ago
Frédéric Pierret (fepitre) beb177026c
Add 'kernel-latest' and 'kernel-latest-qubes-vm' as optional packages
5 years ago
Marek Marczykowski-Górecki c92b713f9f
conf: create separate iso-full-online.ks for release builds
5 years ago
Frédéric Pierret (fepitre) cfe1e28266
Create ISO with new name format instead of legacy one
5 years ago
Frédéric Pierret (fepitre) e574ea6c3c
Add stamp for latest built iso
5 years ago

@ -1,5 +1,5 @@
sudo: required
dist: trusty
dist: bionic
language: generic
install: git clone https://github.com/QubesOS/qubes-builder ~/qubes-builder
script:

@ -59,7 +59,8 @@ iso-installer: iso-prepare
pushd work && pungi --name=Qubes $(PUNGI_OPTS) -c $(INSTALLER_KICKSTART) && popd
# Move result files to known-named directories
mkdir -p build/ISO/qubes-x86_64/iso
mv work/$(ISO_VERSION)/x86_64/iso/*-DVD*.iso build/ISO/qubes-x86_64/iso/
mv work/$(ISO_VERSION)/x86_64/iso/*-DVD*.iso build/ISO/qubes-x86_64/iso/Qubes-$(ISO_VERSION)-x86_64.iso
echo $(ISO_VERSION) > build/ISO/qubes-x86_64/iso/build_latest
rm -rf build/work
mv work build/work
chown --reference=Makefile -R build yum

@ -17,7 +17,7 @@ new file mode 100644
index 000000000..e98912b63
--- /dev/null
+++ b/pyanaconda/installclasses/qubes.py
@@ -0,0 +1,93 @@
@@ -0,0 +1,89 @@
+#
+# qubes.py
+#
@ -92,10 +92,6 @@ index 000000000..e98912b63
+ storage.autopart_requests.remove(autoreq)
+ if autoreq.mountpoint == "/boot/efi":
+ autoreq.max_size=Size("500MiB")
+ if autoreq.mountpoint == "/boot" and \
+ isinstance(platform, blivet.platform.EFI):
+ # xen.efi don't need /boot
+ storage.autopart_requests.remove(autoreq)
+
+ def productMatches(self, oldprod):
+ if oldprod is None:

@ -0,0 +1,29 @@
From 83136384582280bde3379ee87898891d88463930 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Marek=20Marczykowski-G=C3=B3recki?=
<marmarek@invisiblethingslab.com>
Date: Tue, 25 Jun 2019 19:59:17 +0200
Subject: [PATCH] Add "plymouth.ignore-serial-consoles" boot option by default
This preserve graphical boot even if plymouth detects /dev/hvc0 as a
serial console.
QubesOS/qubes-issues#3849
---
pyanaconda/installclasses/qubes.py | 1 +
1 file changed, 1 insertion(+)
diff --git a/pyanaconda/installclasses/qubes.py b/pyanaconda/installclasses/qubes.py
index b5caff037..0ab8ce553 100644
--- a/pyanaconda/installclasses/qubes.py
+++ b/pyanaconda/installclasses/qubes.py
@@ -45,6 +45,7 @@ class InstallClass(BaseInstallClass):
installUpdates = False
bootloaderTimeoutDefault = 5
+ bootloaderExtraArgs = ["plymouth.ignore-serial-consoles"]
tasks = [(N_("Minimal"), ["base", "base-x", "kde-desktop-qubes", "qubes" ]) ]
--
2.20.1

@ -0,0 +1,79 @@
From 0f181e582ff47bb216f0f334a77518197d05f0fb Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Marek=20Marczykowski-G=C3=B3recki?=
<marmarek@invisiblethingslab.com>
Date: Thu, 24 Oct 2019 18:11:46 +0200
Subject: [PATCH] Report 20% space needed for LVM thin provisioning
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
Organization: Invisible Things Lab
Cc: Marek Marczykowski-Górecki <marmarek@invisiblethingslab.com>
blivet reserver 20% free space if thin pool is created. Anaconda/blivet
interface for reporting metadata/reserved space is lacking. As a
workaround add 20% at GUI layer.
Signed-off-by: Marek Marczykowski-Górecki <marmarek@invisiblethingslab.com>
---
pyanaconda/ui/gui/spokes/lib/resize.py | 7 +++++++
pyanaconda/ui/gui/spokes/storage.py | 5 +++++
2 files changed, 12 insertions(+)
diff --git a/pyanaconda/ui/gui/spokes/lib/resize.py b/pyanaconda/ui/gui/spokes/lib/resize.py
index 73be5e23e..2626bec0d 100644
--- a/pyanaconda/ui/gui/spokes/lib/resize.py
+++ b/pyanaconda/ui/gui/spokes/lib/resize.py
@@ -31,6 +31,7 @@ from pyanaconda.ui.gui import GUIObject
from pyanaconda.ui.gui.utils import blockedHandler, escape_markup, timed_action
from blivet.size import Size
from blivet.formats.fs import FS
+from pykickstart.constants import AUTOPART_TYPE_LVM_THINP
__all__ = ["ResizeDialog"]
@@ -84,6 +85,9 @@ class ResizeDialog(GUIObject):
self._required_label = self.builder.get_object("requiredSpaceLabel")
markup = _("Installation requires a total of <b>%s</b> for system data.")
required_dev_size = self.payload.requiredDeviceSize(FS.biggest_overhead_FS())
+ if self.storage.autopart_type == AUTOPART_TYPE_LVM_THINP:
+ # blivet reserve 20% free space in volume group if thin pool is created
+ required_dev_size /= 0.8
self._required_label.set_markup(markup % escape_markup(str(required_dev_size)))
self._reclaimDescLabel = self.builder.get_object("reclaimDescLabel")
@@ -315,6 +319,9 @@ class ResizeDialog(GUIObject):
def _update_reclaim_button(self, got):
required_dev_size = self.payload.requiredDeviceSize(FS.biggest_overhead_FS())
+ if self.storage.autopart_type == AUTOPART_TYPE_LVM_THINP:
+ # blivet reserve 20% free space in volume group if thin pool is created
+ required_dev_size /= 0.8
self._resizeButton.set_sensitive(got+self._initialFreeSpace >= required_dev_size)
# pylint: disable=arguments-differ
diff --git a/pyanaconda/ui/gui/spokes/storage.py b/pyanaconda/ui/gui/spokes/storage.py
index a75f1dfc9..0c6000f2e 100644
--- a/pyanaconda/ui/gui/spokes/storage.py
+++ b/pyanaconda/ui/gui/spokes/storage.py
@@ -874,6 +874,9 @@ class StorageSpoke(NormalSpoke, StorageChecker):
disks_size = sum((d.size for d in disks), Size(0))
required_space = self.payload.spaceRequired
+ if self.storage.autopart_type == AUTOPART_TYPE_LVM_THINP:
+ # blivet reserve 20% free space in volume group if thin pool is created
+ required_space /= 0.8
auto_swap = sum((r.size for r in self.storage.autopart_requests
if r.fstype == "swap"), Size(0))
if self.autopart and auto_swap == Size(0):
@@ -1021,6 +1024,8 @@ class StorageSpoke(NormalSpoke, StorageChecker):
dialog = ResizeDialog(self.data, self.storage, self.payload)
dialog.refresh(disks)
else:
+ # respect disk selection and other choices in the ReclaimDialog
+ self.apply()
dialog = self._check_space_and_get_dialog(disks)
if dialog:
--
2.20.1

@ -0,0 +1,35 @@
From 2bccfe3f8c5e7ce18f4c4208914a1ea865072481 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Marek=20Marczykowski-G=C3=B3recki?=
<marmarek@invisiblethingslab.com>
Date: Wed, 8 Jan 2020 20:28:25 +0100
Subject: [PATCH] Do not require user setup during automated (kickseeded)
install
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
Organization: Invisible Things Lab
Cc: Marek Marczykowski-Górecki <marmarek@invisiblethingslab.com>
OEM installation may prefer to setup it during initial-setup phase.
Signed-off-by: Marek Marczykowski-Górecki <marmarek@invisiblethingslab.com>
---
pyanaconda/ui/gui/spokes/user.py | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/pyanaconda/ui/gui/spokes/user.py b/pyanaconda/ui/gui/spokes/user.py
index 7db7e44..2bb110d 100644
--- a/pyanaconda/ui/gui/spokes/user.py
+++ b/pyanaconda/ui/gui/spokes/user.py
@@ -338,7 +338,7 @@ class UserSpoke(NormalSpoke, GUISpokeInputCheckHandler):
@property
def mandatory(self):
- return True
+ return not flags.automatedInstall
def apply(self):
# set the password only if the user enters anything to the text entry
--
2.21.0

@ -3,7 +3,7 @@
Summary: Graphical system installer
Name: anaconda
Version: 25.20.9
Release: 14%{?dist}
Release: 17%{?dist}
License: GPLv2+ and MIT
Epoch: 1000
Group: Applications/System
@ -74,6 +74,9 @@ Patch53: 0053-anaconda-require-user-password-being-set.patch
Patch54: 0054-anaconda-abort-installation-on-X-startup-fail.patch
Patch55: 0055-anaconda-fix-encryption-passphrase-check.patch
Patch56: 0056-anaconda-disable-os-prober.patch
Patch57: 0057-Add-plymouth.ignore-serial-consoles-boot-option-by-d.patch
Patch58: 0058-Report-20-space-needed-for-LVM-thin-provisioning.patch
Patch59: 0059-Do-not-require-user-setup-during-automated-kickseede.patch
# Versions of required components (done so we make sure the buildrequires
# match the requires versions of things).

@ -0,0 +1,47 @@
From 1ce66b58907e229e21a0012a7a36ae93e9e32054 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Marek=20Marczykowski-G=C3=B3recki?=
<marmarek@invisiblethingslab.com>
Date: Tue, 22 Oct 2019 16:15:31 +0200
Subject: [PATCH] Avoid mounting pre-existing disks
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
Organization: Invisible Things Lab
Cc: Marek Marczykowski-Górecki <marmarek@invisiblethingslab.com>
This operation may be harmfull in many ways:
- may unintentionally modify a disk not selected as installation target
(mounting even read only replays journal for example)
- if previous system was compromised, it may try to exploit some of the
parsing code (filesystem driver etc) to survive across
re-installation
Signed-off-by: Marek Marczykowski-Górecki <marmarek@invisiblethingslab.com>
---
blivet/osinstall.py | 9 ---------
1 file changed, 9 deletions(-)
diff --git a/blivet/osinstall.py b/blivet/osinstall.py
index 485e774c..f46388cd 100644
--- a/blivet/osinstall.py
+++ b/blivet/osinstall.py
@@ -211,14 +211,8 @@ def find_existing_installations(devicetree, teardown_all=True):
:rtype: list of :class:`Root`
"""
- try:
- roots = _find_existing_installations(devicetree)
- return roots
- except Exception: # pylint: disable=broad-except
- log_exception_info(log.info, "failure detecting existing installations")
- finally:
- if teardown_all:
- devicetree.teardown_all()
+ if teardown_all:
+ devicetree.teardown_all()
return []
--
2.20.1

@ -1,44 +0,0 @@
From a43dc757eff7fe9417f72e25fc373d09439963de Mon Sep 17 00:00:00 2001
From: Vratislav Podzimek <vpodzime@redhat.com>
Date: Fri, 18 Nov 2016 14:01:49 +0100
Subject: [PATCH 1/2] Change how we run e2fsck to check ext filesystems
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
The '-p' option means "Automatically repair ("preen") the file system. This
option will cause e2fsck to automatically fix any filesystem problems that can
be safely fixed without human intervention." which is something we really
shouldn't do as part of reset()/populate(). We should use '-n' instead "Open the
filesystem read-only, and assume an answer of `no' to all questions." which
guaranties no changes to be made on the file system.
We might want to add the '-p' functionality back at some point, but it needs to
be explicitly triggered by the user code (e.g. Anaconda). I think we need to add
a 'clean' property and a 'repair' method to the formats.FS class so that users
can see where the problem is (if any) and explicitly trigger a safe fixup
attempt if they want to.
Related: rhbz#1170803
---
blivet/tasks/fsck.py | 4 +++-
1 file changed, 3 insertions(+), 1 deletion(-)
diff --git a/blivet/tasks/fsck.py b/blivet/tasks/fsck.py
index a3ed775..c4214dc 100644
--- a/blivet/tasks/fsck.py
+++ b/blivet/tasks/fsck.py
@@ -114,7 +114,9 @@ class Ext2FSCK(FSCK):
128: "Shared library error."}
ext = availability.E2FSCK_APP
- options = ["-f", "-p", "-C", "0"]
+ # "Force checking even if the file system seems clean." (we might get false results otherwise)
+ # + "Open the filesystem read-only, and assume an answer of `no' to all questions."
+ options = ["-f", "-n"]
def _error_message(self, rc):
msgs = (self._fsck_errors[c] for c in self._fsck_errors.keys() if rc & c)
--
2.7.5

@ -0,0 +1,36 @@
From 88b59572bccd4cfa60d5eb8d0379094a81908358 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Marek=20Marczykowski-G=C3=B3recki?=
<marmarek@invisiblethingslab.com>
Date: Tue, 20 Aug 2019 04:17:42 +0200
Subject: [PATCH] Double recommended LVM thin pool metadata space
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
Organization: Invisible Things Lab
Cc: Marek Marczykowski-Górecki <marmarek@invisiblethingslab.com>
Running out of metadata space is fatal, and it happens with the default
value on Qubes OS. Double the default to be safe.
Signed-off-by: Marek Marczykowski-Górecki <marmarek@invisiblethingslab.com>
---
blivet/devices/lvm.py | 3 +++
1 file changed, 3 insertions(+)
diff --git a/blivet/devices/lvm.py b/blivet/devices/lvm.py
index 72a2d395..e163dbe3 100644
--- a/blivet/devices/lvm.py
+++ b/blivet/devices/lvm.py
@@ -1532,6 +1532,9 @@ class LVMThinPoolMixin(object):
self._metadata_size = Size( get_thpool_meta_size(self._size,
self._chunk_size,
100)) # snapshots
+ # use twice as much as thin_metadata_size recommends, to accommodate
+ # large number of frequent snapshots
+ self._metadata_size *= 2
log.debug("Recommended metadata size: %s", self._metadata_size)
self._metadata_size = self.vg.align(self._metadata_size, roundup=True)
--
2.20.1

@ -1,47 +0,0 @@
From d08d99dfb766e539b9e0074643ab3bc940d6fcee Mon Sep 17 00:00:00 2001
From: Adam Williamson <awilliam@redhat.com>
Date: Thu, 10 Nov 2016 11:34:24 -0800
Subject: [PATCH] Fix detection of 'macefi' partitions (#1393846)
368a4db6 lost a crucial condition in the detection of 'macefi'
partitions in the transition to the 'populator helper' design.
Previously we checked that the parted partition 'name' (which
is a GPT property, for GPT partitions) matched the expected
value according to the macefi format, which basically means we
will only detect partitions created by a previous anaconda run
as 'macefi' (because that name is a very specific one which is
only created by anaconda in the first place).
In the transition, that condition was lost, and now we treat
any device with an HFS+ filesystem that's over 50MiB in size
as a 'macefi' device, which means we mount it at /boot/efi and
try to write all kinds of stuff to it. Not surprisingly, this
borks the install. Fortunately, HFS+ filesystems are mounted
read-only unless they have journalling disabled, so this won't
result in us messing up people's OS X partitions with any luck.
---
blivet/populator/helpers/boot.py | 10 ++++++++++
tests/populator_test.py | 33 +++++++++++++++++++++++++++++++++
2 files changed, 43 insertions(+)
diff --git a/blivet/populator/helpers/boot.py b/blivet/populator/helpers/boot.py
index b679b3b..3d80dd2 100644
--- a/blivet/populator/helpers/boot.py
+++ b/blivet/populator/helpers/boot.py
@@ -54,6 +54,16 @@ class MacEFIFormatPopulator(BootFormatPopulator):
_type_specifier = "macefi"
_base_type_specifier = "hfsplus"
+ @classmethod
+ def match(cls, data, device):
+ fmt = formats.get_format(cls._type_specifier)
+ try:
+ return (super().match(data, device) and
+ device.parted_partition.name == fmt.name)
+ except AttributeError:
+ # just in case device.parted_partition has no name attr
+ return False
+
class AppleBootFormatPopulator(BootFormatPopulator):
_type_specifier = "appleboot"

@ -1,34 +0,0 @@
From 7a9697eae467fc0ed44022d948f70f30d156d69e Mon Sep 17 00:00:00 2001
From: Adam Williamson <adamw@fedoraproject.org>
Date: Fri, 11 Nov 2016 12:36:12 -0500
Subject: [PATCH] Fix "unknown" SAS device sysfs parsing.
Since the regexp matches the device type as well as the identifying
numbers, we need to pull the numbers from match groups 2 and 3, not 1
and 2.
Resolves: rhbz#1394026
Signed-off-by: Peter Jones <pjones@redhat.com>
---
blivet/devicelibs/edd.py | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/blivet/devicelibs/edd.py b/blivet/devicelibs/edd.py
index 7a1a1e2..51b7ed8 100644
--- a/blivet/devicelibs/edd.py
+++ b/blivet/devicelibs/edd.py
@@ -316,8 +316,8 @@ class EddEntry(object):
self.sas_address = int(sas_match.group(1), base=16)
self.sas_lun = int(sas_match.group(2), base=16)
elif unknown_match:
- self.sas_address = int(unknown_match.group(1), base=16)
- self.sas_lun = int(unknown_match.group(2), base=16)
+ self.sas_address = int(unknown_match.group(2), base=16)
+ self.sas_lun = int(unknown_match.group(3), base=16)
else:
log.warning("edd: can not match interface for %s: %s",
self.sysfspath, interface)
--
2.7.4

@ -0,0 +1,76 @@
From e6369b8986953e3d0eba93cc024a2219320fa42c Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Marek=20Marczykowski-G=C3=B3recki?=
<marmarek@invisiblethingslab.com>
Date: Tue, 22 Oct 2019 14:52:17 +0200
Subject: [PATCH 1/2] Revert "FBA DASD should use the msdos disk label type"
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
Organization: Invisible Things Lab
Cc: Marek Marczykowski-Górecki <marmarek@invisiblethingslab.com>
This reverts commit 41627e946cafc9341fd90c6713830aa67ebe28e7.
Signed-off-by: Marek Marczykowski-Górecki <marmarek@invisiblethingslab.com>
---
blivet/platform.py | 21 ++++-----------------
python-blivet.spec | 2 +-
2 files changed, 5 insertions(+), 18 deletions(-)
diff --git a/blivet/platform.py b/blivet/platform.py
index 4772b35d..9100487e 100644
--- a/blivet/platform.py
+++ b/blivet/platform.py
@@ -22,11 +22,6 @@
import logging
log = logging.getLogger("blivet")
-import gi
-gi.require_version("BlockDev", "2.0")
-
-from gi.repository import BlockDev as blockdev
-
import parted
from . import arch
@@ -356,20 +351,12 @@ class S390(Platform):
return [PartSpec(mountpoint="/boot", size=Size("1GiB"),
weight=self.weight(mountpoint="/boot"), lv=False)]
- def best_disklabel_type(self, device):
- """The best disklabel type for the specified device."""
- if flags.testing:
- return self.default_disklabel_type
-
- # the device is FBA DASD
- if blockdev.s390.dasd_is_fba(device.path):
- return "msdos"
- # the device is DASD
- elif parted.Device(path=device.path).type == parted.DEVICE_DASD:
+ def required_disklabel_type(self, device_type):
+ """The required disklabel type for the specified device type."""
+ if device_type == parted.DEVICE_DASD:
return "dasd"
- # other types of devices
- return super(S390, self).best_disklabel_type(device)
+ return super(S390, self).required_disklabel_type(device_type)
class ARM(Platform):
diff --git a/python-blivet.spec b/python-blivet.spec
index 1481bf84..0c3392c9 100644
--- a/python-blivet.spec
+++ b/python-blivet.spec
@@ -19,7 +19,7 @@ Source0: http://github.com/storaged-project/blivet/archive/%{realname}-%{realver
%global partedver 1.8.1
%global pypartedver 3.10.4
%global utillinuxver 2.15.1
-%global libblockdevver 2.6
+%global libblockdevver 2.1
%global libbytesizever 0.3
%global pyudevver 0.18
--
2.20.1

@ -1,28 +0,0 @@
From cf32290dd3a0561585837fddfcdb08b3389f356a Mon Sep 17 00:00:00 2001
From: Adam Williamson <awilliam@redhat.com>
Date: Wed, 26 Oct 2016 16:17:46 -0700
Subject: [PATCH 1/4] Use correct type for port in GVariant tuple
The type is `(sqa{sv})`, where `q` (according to the docs) is
"an unsigned 16 bit integer", so this should be an int, not a
string.
---
blivet/iscsi.py | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/blivet/iscsi.py b/blivet/iscsi.py
index 8773509..14c4b9a 100644
--- a/blivet/iscsi.py
+++ b/blivet/iscsi.py
@@ -369,7 +369,7 @@ class iSCSI(object):
if r_password:
auth_info["r_password"] = GLib.Variant("s", r_password)
- args = GLib.Variant("(sqa{sv})", (ipaddr, port, auth_info))
+ args = GLib.Variant("(sqa{sv})", (ipaddr, int(port), auth_info))
nodes, _n_nodes = self._call_initiator_method("DiscoverSendTargets", args)
found_nodes = _to_node_infos(nodes)
--
2.7.4

@ -1,84 +0,0 @@
From 32ba44edfa5cd4424154396b877cd5ad75e8c999 Mon Sep 17 00:00:00 2001
From: Vratislav Podzimek <vpodzime@redhat.com>
Date: Tue, 22 Nov 2016 08:52:34 +0100
Subject: [PATCH 2/2] Do not run FS check as part of updating (re)size info
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
If the FS tools tell us the minimum size of the file system we are supposed to
(see rhbz#1170803) consider that an evidence of the file system being in a good
enough shape to be resized.
Resolves: rhbz#1170803
---
blivet/formats/fs.py | 44 ++++++++++++++++++--------------------------
1 file changed, 18 insertions(+), 26 deletions(-)
diff --git a/blivet/formats/fs.py b/blivet/formats/fs.py
index 203926e..100bfce 100644
--- a/blivet/formats/fs.py
+++ b/blivet/formats/fs.py
@@ -296,8 +296,6 @@ class FS(DeviceFormat):
""" Update this filesystem's current and minimum size (for resize). """
# This method ensures:
- # * If there are fsck errors, self._resizable is False.
- # Note that if there is no fsck program, no errors are possible.
# * If it is not possible to obtain the current size of the
# filesystem by interrogating the filesystem, self._resizable
# is False (and self._size is 0).
@@ -317,32 +315,26 @@ class FS(DeviceFormat):
self._min_instance_size = Size(0)
self._resizable = self.__class__._resizable
- # We can't allow resize if the filesystem has errors.
+ # try to gather current size info
+ self._size = Size(0)
try:
- self.do_check()
- except FSError:
+ if self._info.available:
+ self._current_info = self._info.do_task()
+ except FSError as e:
+ log.info("Failed to obtain info for device %s: %s", self.device, e)
+ try:
+ self._size = self._size_info.do_task()
+ except (FSError, NotImplementedError) as e:
+ log.warning("Failed to obtain current size for device %s: %s", self.device, e)
+ else:
+ self._min_instance_size = self._size
+
+ # We absolutely need a current size to enable resize. To shrink the
+ # filesystem we need a real minimum size provided by the resize
+ # tool. Failing that, we can default to the current size,
+ # effectively disabling shrink.
+ if self._size == Size(0):
self._resizable = False
- raise
- finally:
- # try to gather current size info anyway
- self._size = Size(0)
- try:
- if self._info.available:
- self._current_info = self._info.do_task()
- except FSError as e:
- log.info("Failed to obtain info for device %s: %s", self.device, e)
- try:
- self._size = self._size_info.do_task()
- self._min_instance_size = self._size
- except (FSError, NotImplementedError) as e:
- log.warning("Failed to obtain current size for device %s: %s", self.device, e)
-
- # We absolutely need a current size to enable resize. To shrink the
- # filesystem we need a real minimum size provided by the resize
- # tool. Failing that, we can default to the current size,
- # effectively disabling shrink.
- if self._size == Size(0):
- self._resizable = False
try:
result = self._minsize.do_task()
--
2.7.5

@ -0,0 +1,497 @@
From cbf2890b7be57e159e0890da4fded5062152f191 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Marek=20Marczykowski-G=C3=B3recki?=
<marmarek@invisiblethingslab.com>
Date: Tue, 22 Oct 2019 14:52:36 +0200
Subject: [PATCH 2/2] Revert "Require BlockDev 2.0 in the gi.require_version()
call"
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
Organization: Invisible Things Lab
Cc: Marek Marczykowski-Górecki <marmarek@invisiblethingslab.com>
This reverts commit 778ca84050289f4a4c27857d923d6e3aea4919fc.
Signed-off-by: Marek Marczykowski-Górecki <marmarek@invisiblethingslab.com>
---
blivet/__init__.py | 2 +-
blivet/devicefactory.py | 2 +-
blivet/devicelibs/lvm.py | 2 +-
blivet/devices/btrfs.py | 2 +-
blivet/devices/disk.py | 2 +-
blivet/devices/dm.py | 2 +-
blivet/devices/loop.py | 2 +-
blivet/devices/lvm.py | 2 +-
blivet/devices/md.py | 2 +-
blivet/devices/partition.py | 2 +-
blivet/devicetree.py | 2 +-
blivet/formats/__init__.py | 2 +-
blivet/formats/luks.py | 2 +-
blivet/formats/lvmpv.py | 2 +-
blivet/formats/mdraid.py | 2 +-
blivet/formats/swap.py | 2 +-
blivet/osinstall.py | 2 +-
blivet/partitioning.py | 2 +-
blivet/populator/helpers/disk.py | 2 +-
blivet/populator/helpers/dmraid.py | 2 +-
blivet/populator/helpers/loop.py | 2 +-
blivet/populator/helpers/luks.py | 2 +-
blivet/populator/helpers/lvm.py | 2 +-
blivet/populator/helpers/mdraid.py | 2 +-
blivet/populator/helpers/partition.py | 2 +-
blivet/populator/populator.py | 2 +-
blivet/static_data/lvm_info.py | 2 +-
blivet/static_data/mpath_info.py | 2 +-
blivet/tasks/availability.py | 2 +-
blivet/tasks/lukstasks.py | 2 +-
blivet/tasks/pvtask.py | 2 +-
blivet/util.py | 2 +-
blivet/zfcp.py | 2 +-
python-blivet.spec | 2 +-
34 files changed, 34 insertions(+), 34 deletions(-)
diff --git a/blivet/__init__.py b/blivet/__init__.py
index 1325e540..d5105842 100644
--- a/blivet/__init__.py
+++ b/blivet/__init__.py
@@ -75,7 +75,7 @@ log_bd_message = lambda level, msg: program_log.info(msg)
import gi
gi.require_version("GLib", "2.0")
-gi.require_version("BlockDev", "2.0")
+gi.require_version("BlockDev", "1.0")
# initialize the libblockdev library
from gi.repository import GLib
diff --git a/blivet/devicefactory.py b/blivet/devicefactory.py
index 5b680668..5f486aab 100644
--- a/blivet/devicefactory.py
+++ b/blivet/devicefactory.py
@@ -38,7 +38,7 @@ from .size import Size
from .static_data import luks_data
import gi
-gi.require_version("BlockDev", "2.0")
+gi.require_version("BlockDev", "1.0")
from gi.repository import BlockDev as blockdev
diff --git a/blivet/devicelibs/lvm.py b/blivet/devicelibs/lvm.py
index 24adf9a0..352f67a2 100644
--- a/blivet/devicelibs/lvm.py
+++ b/blivet/devicelibs/lvm.py
@@ -27,7 +27,7 @@ from collections import namedtuple
import itertools
import gi
-gi.require_version("BlockDev", "2.0")
+gi.require_version("BlockDev", "1.0")
from gi.repository import BlockDev as blockdev
diff --git a/blivet/devices/btrfs.py b/blivet/devices/btrfs.py
index c5cb21f7..35a2b099 100644
--- a/blivet/devices/btrfs.py
+++ b/blivet/devices/btrfs.py
@@ -24,7 +24,7 @@ import copy
import tempfile
import gi
-gi.require_version("BlockDev", "2.0")
+gi.require_version("BlockDev", "1.0")
from gi.repository import BlockDev as blockdev
diff --git a/blivet/devices/disk.py b/blivet/devices/disk.py
index 1136a535..acf31eed 100644
--- a/blivet/devices/disk.py
+++ b/blivet/devices/disk.py
@@ -21,7 +21,7 @@
#
import gi
-gi.require_version("BlockDev", "2.0")
+gi.require_version("BlockDev", "1.0")
from gi.repository import BlockDev as blockdev
diff --git a/blivet/devices/dm.py b/blivet/devices/dm.py
index a0350b24..e7efddfb 100644
--- a/blivet/devices/dm.py
+++ b/blivet/devices/dm.py
@@ -21,7 +21,7 @@
#
import gi
-gi.require_version("BlockDev", "2.0")
+gi.require_version("BlockDev", "1.0")
from gi.repository import BlockDev as blockdev
diff --git a/blivet/devices/loop.py b/blivet/devices/loop.py
index 78f88d7d..fcef161d 100644
--- a/blivet/devices/loop.py
+++ b/blivet/devices/loop.py
@@ -20,7 +20,7 @@
#
import gi
-gi.require_version("BlockDev", "2.0")
+gi.require_version("BlockDev", "1.0")
from gi.repository import BlockDev as blockdev
diff --git a/blivet/devices/lvm.py b/blivet/devices/lvm.py
index 72a2d395..39c6f342 100644
--- a/blivet/devices/lvm.py
+++ b/blivet/devices/lvm.py
@@ -30,7 +30,7 @@ from functools import wraps
from enum import Enum
import gi
-gi.require_version("BlockDev", "2.0")
+gi.require_version("BlockDev", "1.0")
from gi.repository import BlockDev as blockdev
diff --git a/blivet/devices/md.py b/blivet/devices/md.py
index 891805aa..3006236e 100644
--- a/blivet/devices/md.py
+++ b/blivet/devices/md.py
@@ -23,7 +23,7 @@ import os
import six
import gi
-gi.require_version("BlockDev", "2.0")
+gi.require_version("BlockDev", "1.0")
from gi.repository import BlockDev as blockdev
diff --git a/blivet/devices/partition.py b/blivet/devices/partition.py
index 4c175403..66f768d2 100644
--- a/blivet/devices/partition.py
+++ b/blivet/devices/partition.py
@@ -24,7 +24,7 @@ import parted
import _ped
import gi
-gi.require_version("BlockDev", "2.0")
+gi.require_version("BlockDev", "1.0")
from gi.repository import BlockDev as blockdev
diff --git a/blivet/devicetree.py b/blivet/devicetree.py
index 805f6a04..8057f7e7 100644
--- a/blivet/devicetree.py
+++ b/blivet/devicetree.py
@@ -25,7 +25,7 @@ import pprint
import re
import gi
-gi.require_version("BlockDev", "2.0")
+gi.require_version("BlockDev", "1.0")
from gi.repository import BlockDev as blockdev
diff --git a/blivet/formats/__init__.py b/blivet/formats/__init__.py
index f60402fe..6d4eaf39 100644
--- a/blivet/formats/__init__.py
+++ b/blivet/formats/__init__.py
@@ -22,7 +22,7 @@
#
import gi
-gi.require_version("BlockDev", "2.0")
+gi.require_version("BlockDev", "1.0")
from gi.repository import BlockDev as blockdev
diff --git a/blivet/formats/luks.py b/blivet/formats/luks.py
index d8db8dd5..4ad8252a 100644
--- a/blivet/formats/luks.py
+++ b/blivet/formats/luks.py
@@ -21,7 +21,7 @@
#
import gi
-gi.require_version("BlockDev", "2.0")
+gi.require_version("BlockDev", "1.0")
from gi.repository import BlockDev as blockdev
diff --git a/blivet/formats/lvmpv.py b/blivet/formats/lvmpv.py
index 260cc0bd..b2f70cdc 100644
--- a/blivet/formats/lvmpv.py
+++ b/blivet/formats/lvmpv.py
@@ -21,7 +21,7 @@
#
import gi
-gi.require_version("BlockDev", "2.0")
+gi.require_version("BlockDev", "1.0")
from gi.repository import BlockDev as blockdev
diff --git a/blivet/formats/mdraid.py b/blivet/formats/mdraid.py
index 383160a3..ee7e887a 100644
--- a/blivet/formats/mdraid.py
+++ b/blivet/formats/mdraid.py
@@ -21,7 +21,7 @@
#
import gi
-gi.require_version("BlockDev", "2.0")
+gi.require_version("BlockDev", "1.0")
from gi.repository import BlockDev as blockdev
diff --git a/blivet/formats/swap.py b/blivet/formats/swap.py
index 46dc980f..185fda53 100644
--- a/blivet/formats/swap.py
+++ b/blivet/formats/swap.py
@@ -29,7 +29,7 @@ from . import DeviceFormat, register_device_format
from ..size import Size
import gi
-gi.require_version("BlockDev", "2.0")
+gi.require_version("BlockDev", "1.0")
from gi.repository import BlockDev as blockdev
diff --git a/blivet/osinstall.py b/blivet/osinstall.py
index a4f9535f..485e774c 100644
--- a/blivet/osinstall.py
+++ b/blivet/osinstall.py
@@ -26,7 +26,7 @@ import stat
import time
import gi
-gi.require_version("BlockDev", "2.0")
+gi.require_version("BlockDev", "1.0")
from gi.repository import BlockDev as blockdev
diff --git a/blivet/partitioning.py b/blivet/partitioning.py
index dcc7ce80..b7b2617c 100644
--- a/blivet/partitioning.py
+++ b/blivet/partitioning.py
@@ -25,7 +25,7 @@ from decimal import Decimal
import functools
import gi
-gi.require_version("BlockDev", "2.0")
+gi.require_version("BlockDev", "1.0")
import parted
diff --git a/blivet/populator/helpers/disk.py b/blivet/populator/helpers/disk.py
index e937128b..9313f766 100644
--- a/blivet/populator/helpers/disk.py
+++ b/blivet/populator/helpers/disk.py
@@ -21,7 +21,7 @@
#
import gi
-gi.require_version("BlockDev", "2.0")
+gi.require_version("BlockDev", "1.0")
from gi.repository import BlockDev as blockdev
diff --git a/blivet/populator/helpers/dmraid.py b/blivet/populator/helpers/dmraid.py
index 5db42196..987caec3 100644
--- a/blivet/populator/helpers/dmraid.py
+++ b/blivet/populator/helpers/dmraid.py
@@ -21,7 +21,7 @@
#
import gi
-gi.require_version("BlockDev", "2.0")
+gi.require_version("BlockDev", "1.0")
from gi.repository import BlockDev as blockdev
diff --git a/blivet/populator/helpers/loop.py b/blivet/populator/helpers/loop.py
index 99fc4bb5..33bb3423 100644
--- a/blivet/populator/helpers/loop.py
+++ b/blivet/populator/helpers/loop.py
@@ -21,7 +21,7 @@
#
import gi
-gi.require_version("BlockDev", "2.0")
+gi.require_version("BlockDev", "1.0")
from gi.repository import BlockDev as blockdev
from ... import udev
diff --git a/blivet/populator/helpers/luks.py b/blivet/populator/helpers/luks.py
index 433cc06e..d27089a6 100644
--- a/blivet/populator/helpers/luks.py
+++ b/blivet/populator/helpers/luks.py
@@ -21,7 +21,7 @@
#
import gi
-gi.require_version("BlockDev", "2.0")
+gi.require_version("BlockDev", "1.0")
from gi.repository import BlockDev as blockdev
diff --git a/blivet/populator/helpers/lvm.py b/blivet/populator/helpers/lvm.py
index 10ef1646..2a985adc 100644
--- a/blivet/populator/helpers/lvm.py
+++ b/blivet/populator/helpers/lvm.py
@@ -21,7 +21,7 @@
#
import gi
-gi.require_version("BlockDev", "2.0")
+gi.require_version("BlockDev", "1.0")
from gi.repository import BlockDev as blockdev
diff --git a/blivet/populator/helpers/mdraid.py b/blivet/populator/helpers/mdraid.py
index 998e8de9..5542cc4d 100644
--- a/blivet/populator/helpers/mdraid.py
+++ b/blivet/populator/helpers/mdraid.py
@@ -21,7 +21,7 @@
#
import gi
-gi.require_version("BlockDev", "2.0")
+gi.require_version("BlockDev", "1.0")
from gi.repository import BlockDev as blockdev
diff --git a/blivet/populator/helpers/partition.py b/blivet/populator/helpers/partition.py
index 73b15f11..d977ea49 100644
--- a/blivet/populator/helpers/partition.py
+++ b/blivet/populator/helpers/partition.py
@@ -23,7 +23,7 @@
import copy
import gi
-gi.require_version("BlockDev", "2.0")
+gi.require_version("BlockDev", "1.0")
from gi.repository import BlockDev as blockdev
from ... import udev
diff --git a/blivet/populator/populator.py b/blivet/populator/populator.py
index 7a6a4ae9..84c1d33d 100644
--- a/blivet/populator/populator.py
+++ b/blivet/populator/populator.py
@@ -26,7 +26,7 @@ import copy
import parted
import gi
-gi.require_version("BlockDev", "2.0")
+gi.require_version("BlockDev", "1.0")
from gi.repository import BlockDev as blockdev
diff --git a/blivet/static_data/lvm_info.py b/blivet/static_data/lvm_info.py
index 89e1b8e1..f8965f15 100644
--- a/blivet/static_data/lvm_info.py
+++ b/blivet/static_data/lvm_info.py
@@ -21,7 +21,7 @@
#
import gi
-gi.require_version("BlockDev", "2.0")
+gi.require_version("BlockDev", "1.0")
from gi.repository import BlockDev as blockdev
diff --git a/blivet/static_data/mpath_info.py b/blivet/static_data/mpath_info.py
index 71bf17e1..c9ca8a30 100644
--- a/blivet/static_data/mpath_info.py
+++ b/blivet/static_data/mpath_info.py
@@ -20,7 +20,7 @@
import os
import gi
-gi.require_version("BlockDev", "2.0")
+gi.require_version("BlockDev", "1.0")
from gi.repository import BlockDev as blockdev
diff --git a/blivet/tasks/availability.py b/blivet/tasks/availability.py
index 354a9ee1..c7f58b87 100644
--- a/blivet/tasks/availability.py
+++ b/blivet/tasks/availability.py
@@ -25,7 +25,7 @@ from distutils.spawn import find_executable
from six import add_metaclass
import gi
-gi.require_version("BlockDev", "2.0")
+gi.require_version("BlockDev", "1.0")
from gi.repository import BlockDev as blockdev
diff --git a/blivet/tasks/lukstasks.py b/blivet/tasks/lukstasks.py
index d32fe978..7814454f 100644
--- a/blivet/tasks/lukstasks.py
+++ b/blivet/tasks/lukstasks.py
@@ -20,7 +20,7 @@
# Red Hat Author(s): Anne Mulhern <amulhern@redhat.com>
import gi
-gi.require_version("BlockDev", "2.0")
+gi.require_version("BlockDev", "1.0")
from gi.repository import BlockDev as blockdev
diff --git a/blivet/tasks/pvtask.py b/blivet/tasks/pvtask.py
index a96d380d..2cb07a34 100644
--- a/blivet/tasks/pvtask.py
+++ b/blivet/tasks/pvtask.py
@@ -21,7 +21,7 @@
# Red Hat Author(s): Vojtěch Trefný <vtrefny@redhat.com>
import gi
-gi.require_version("BlockDev", "2.0")
+gi.require_version("BlockDev", "1.0")
from gi.repository import BlockDev as blockdev
diff --git a/blivet/util.py b/blivet/util.py
index 57f6372f..ba81bb6e 100644
--- a/blivet/util.py
+++ b/blivet/util.py
@@ -22,7 +22,7 @@ from enum import Enum
from .errors import DependencyError
import gi
-gi.require_version("BlockDev", "2.0")
+gi.require_version("BlockDev", "1.0")
from gi.repository import BlockDev as blockdev
diff --git a/blivet/zfcp.py b/blivet/zfcp.py
index 2381599c..0074c5dc 100644
--- a/blivet/zfcp.py
+++ b/blivet/zfcp.py
@@ -26,7 +26,7 @@ from .i18n import _
from .util import stringize, unicodeize
import gi
-gi.require_version("BlockDev", "2.0")
+gi.require_version("BlockDev", "1.0")
from gi.repository import BlockDev as blockdev
diff --git a/python-blivet.spec b/python-blivet.spec
index 0c3392c9..5e7bf8a1 100644
--- a/python-blivet.spec
+++ b/python-blivet.spec
@@ -19,7 +19,7 @@ Source0: http://github.com/storaged-project/blivet/archive/%{realname}-%{realver
%global partedver 1.8.1
%global pypartedver 3.10.4
%global utillinuxver 2.15.1
-%global libblockdevver 2.1
+%global libblockdevver 1.9
%global libbytesizever 0.3
%global pyudevver 0.18
--
2.20.1

@ -1,122 +0,0 @@
From 5eaadad9218210ed2a616104a6e56665c38f9277 Mon Sep 17 00:00:00 2001
From: Adam Williamson <awilliam@redhat.com>
Date: Wed, 26 Oct 2016 20:42:53 -0700
Subject: [PATCH 2/4] iSCSI: Store auth info in NodeInfo tuples
This seems to have been overlooked in 9280eff7 . When we were
using libiscsi, the `node` objects were `PyIscsiNode` instances
(I think), with `getAuth` and `setAuth` methods that let you
read and set the authentication information for the node. We
used `getAuth` in `iScsiDiskDevice.dracut_setup_args()` to
include the auth information in the `netroot` arg. anaconda
also expects the `node` attribute of an `iScsiDiskDevice`
instance to be a `PyIscsiNode` and calls its `getAuth` method
to populate the kickstart data for the node.
When we ditched libiscsi and turned the `node` objects into
`NodeInfo` namedtuples, this was missed and not handled at all.
Both blivet and anaconda are still trying to call methods that
these node objects just don't have any more. The blivet call
was changed from `getAuth()` to `get_auth()` in 4e8f941b , but
apparently whoever did that didn't notice that neither method
exists at all for these objects any more...
Here's my attempt to fix this: basically, just stuff the auth
information into the `NodeInfo` instances when we log in. I
thought of several different ways to do this, but I think in
the end it always has to boil down to storing the auth details
on the node object when we log in, so let's just go with the
obvious way. We could mimic the `getAuth` and `setAuth` methods
pretty easily for 'compatibility', but it doesn't seem worth
it, we'd probably still be missing other bits of the interface.
---
blivet/devices/disk.py | 11 +++++------
blivet/iscsi.py | 33 +++++++++++++++++++++++++++++++--
2 files changed, 36 insertions(+), 8 deletions(-)
diff --git a/blivet/devices/disk.py b/blivet/devices/disk.py
index 6880e1e..acf31ee 100644
--- a/blivet/devices/disk.py
+++ b/blivet/devices/disk.py
@@ -452,12 +452,11 @@ class iScsiDiskDevice(DiskDevice, NetworkStorageDevice):
address = "[%s]" % address
netroot = "netroot=iscsi:"
- auth = self.node.get_auth()
- if auth:
- netroot += "%s:%s" % (auth.username, auth.password)
- if len(auth.reverse_username) or len(auth.reverse_password):
- netroot += ":%s:%s" % (auth.reverse_username,
- auth.reverse_password)
+ if self.node.username and self.node.password:
+ netroot += "%s:%s" % (self.node.username, self.node.password)
+ if self.node.r_username and self.node.r_password:
+ netroot += ":%s:%s" % (self.node.r_username,
+ self.node.r_password)
iface_spec = ""
if self.nic != "default":
diff --git a/blivet/iscsi.py b/blivet/iscsi.py
index 14c4b9a..1969fc8 100644
--- a/blivet/iscsi.py
+++ b/blivet/iscsi.py
@@ -66,10 +66,31 @@ def has_iscsi():
return True
-NodeInfo = namedtuple("NodeInfo", ["name", "tpgt", "address", "port", "iface"])
TargetInfo = namedtuple("TargetInfo", ["ipaddr", "port"])
+class NodeInfo(object):
+ """Simple representation of node information."""
+ def __init__(self, name, tpgt, address, port, iface):
+ self.name = name
+ self.tpgt = tpgt
+ self.address = address
+ self.port = port
+ self.iface = iface
+ # These get set by log_into_node, but *NOT* _login
+ self.username = None
+ self.password = None
+ self.r_username = None
+ self.r_password = None
+
+ @property
+ def conn_info(self):
+ """The 5-tuple of connection info (no auth info). This form
+ is useful for interacting with storaged.
+ """
+ return (self.name, self.tpgt, self.address, self.port, self.iface)
+
+
class LoginInfo(object):
def __init__(self, node, logged_in):
self.node = node
@@ -239,7 +260,7 @@ class iSCSI(object):
extra = dict()
extra["node.startup"] = GLib.Variant("s", "automatic")
- args = GLib.Variant("(sisisa{sv})", tuple(list(node_info) + [extra]))
+ args = GLib.Variant("(sisisa{sv})", node_info.conn_info + (extra,))
self._call_initiator_method("Login", args)
@storaged_iscsi_required(critical=False, eval_mode=util.EvalMode.onetime)
@@ -414,6 +435,14 @@ class iSCSI(object):
node.name, node.address, node.port, node.iface)
if not self._mark_node_active(node):
log.error("iSCSI: node not found among discovered")
+ if username:
+ node.username = username
+ if password:
+ node.password = password
+ if r_username:
+ node.r_username = r_username
+ if r_password:
+ node.r_password = r_password
except safe_dbus.DBusCallError as e:
msg = str(e)
log.warning("iSCSI: could not log into %s: %s", node.name, msg)
--
2.7.4

@ -0,0 +1,34 @@
From 42d465514031eb083cac591327436ed6bca2b94c Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Marek=20Marczykowski-G=C3=B3recki?=
<marmarek@invisiblethingslab.com>
Date: Tue, 22 Oct 2019 15:07:01 +0200
Subject: [PATCH] Revert "Adapt to logging module name change"
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
Organization: Invisible Things Lab
Cc: Marek Marczykowski-Górecki <marmarek@invisiblethingslab.com>
This reverts commit c367d62a516e541ad28636c8259321f1c53417ce.
Signed-off-by: Marek Marczykowski-Górecki <marmarek@invisiblethingslab.com>
---
blivet/__init__.py | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/blivet/__init__.py b/blivet/__init__.py
index d5105842..ecaedad8 100644
--- a/blivet/__init__.py
+++ b/blivet/__init__.py
@@ -124,7 +124,7 @@ def enable_installer_mode():
from pyanaconda.constants import ROOT_PATH # pylint: disable=redefined-outer-name,no-name-in-module
_storage_root = _sysroot = ROOT_PATH
- from pyanaconda.anaconda_logging import program_log_lock
+ from pyanaconda.anaconda_log import program_log_lock
util.program_log_lock = program_log_lock
flags.installer_mode = True
--
2.20.1

@ -1,71 +0,0 @@
From 4d0b9f8338bfc1634340bb191058b888094ca81d Mon Sep 17 00:00:00 2001
From: Adam Williamson <awilliam@redhat.com>
Date: Thu, 27 Oct 2016 15:17:29 -0700
Subject: [PATCH 3/4] iSCSI: turn `iscsi.initiator_set` into a property
The iSCSI class has an `initiator_set` attribute whose meaning
feels a bit slippery these days. It has always been set to
True in `__init__()` if iBFT is active, right after we get the
initiator name from the firmware. Prior to 9280eff7, it was
also set true by `startup()` after it wrote out INITIATOR_FILE.
In 9280eff7, that was removed, without any kind of replacement.
Now `initiator_set` will never be True unless iBFT is being
used.
This is a problem because `iscsi.write()` checks if it's True,
and immediately bails if it isn't. The result of this is that
when you do an iSCSI install with anaconda, the contents of
`/var/lib/iscsi` from the installer environment are no longer
copied in the installed system.
vpodzime asked for this fix: making it into a property which
returns True if `self._initiator` is set, otherwise False.
I used `== ""` as the test because that's what we use in other
places, though in my own code I'd normally just use
`if self._initiator:`.
Note that `if iscsi.initiator_set:` and `if iscsi.initiator:`
are not quite equivalent, as the `initiator` property will try
and read the initiator name from storaged if `self._initiator`
is not set, but `initiator_set` will not. This best matches
the previous behaviour, but I'm not sure if all of this makes
any logical sense when considered from scratch.
---
blivet/iscsi.py | 7 +++++--
1 file changed, 5 insertions(+), 2 deletions(-)
diff --git a/blivet/iscsi.py b/blivet/iscsi.py
index 1969fc8..b221fd4 100644
--- a/blivet/iscsi.py
+++ b/blivet/iscsi.py
@@ -149,7 +149,6 @@ class iSCSI(object):
# This list contains nodes discovered through iBFT (or other firmware)
self.ibft_nodes = []
self._initiator = ""
- self.initiator_set = False
self.started = False
self.ifaces = {}
@@ -159,7 +158,6 @@ class iSCSI(object):
try:
initiatorname = self._call_initiator_method("GetFirmwareInitiatorName")[0]
self._initiator = initiatorname
- self.initiator_set = True
except Exception: # pylint: disable=broad-except
log_exception_info(fmt_str="failed to get initiator name from iscsi firmware")
@@ -197,6 +195,11 @@ class iSCSI(object):
connection=self._connection)
@property
+ def initiator_set(self):
+ """True if initiator is set at our level."""
+ return self._initiator != ""
+
+ @property
@storaged_iscsi_required(critical=False, eval_mode=util.EvalMode.onetime)
def initiator(self):
if self._initiator != "":
--
2.7.4

@ -1,45 +0,0 @@
From 274b0bfb6aa923a82662e754030ebce4d8694901 Mon Sep 17 00:00:00 2001
From: Vratislav Podzimek <vpodzime@redhat.com>
Date: Thu, 3 Nov 2016 12:53:03 +0100
Subject: [PATCH 4/4] Add device symlinks to the PVs dictionary for MD RAID PVs
(#1389130)
Otherwise if the symlink is used to search for the PV info, it's not found and
everything on that PV is ignored which leads e.g. to issues when removing the PV
(as described in the bug) and others.
---
blivet/static_data/lvm_info.py | 18 +++++++++++++++++-
1 file changed, 17 insertions(+), 1 deletion(-)
diff --git a/blivet/static_data/lvm_info.py b/blivet/static_data/lvm_info.py
index ed2e995..4f5a274 100644
--- a/blivet/static_data/lvm_info.py
+++ b/blivet/static_data/lvm_info.py
@@ -57,7 +57,23 @@ class PVsInfo(object):
def cache(self):
if self._pvs_cache is None:
pvs = blockdev.lvm.pvs()
- self._pvs_cache = dict((pv.pv_name, pv) for pv in pvs) # pylint: disable=attribute-defined-outside-init
+ self._pvs_cache = dict() # pylint: disable=attribute-defined-outside-init
+ for pv in pvs:
+ self._pvs_cache[pv.pv_name] = pv
+ # TODO: add get_all_device_symlinks() and resolve_device_symlink() functions to
+ # libblockdev and use them here
+ if pv.pv_name.startswith("/dev/md/"):
+ try:
+ md_node = blockdev.md.node_from_name(pv.pv_name[len("/dev/md/"):])
+ self._pvs_cache["/dev/" + md_node] = pv
+ except blockdev.MDRaidError:
+ pass
+ elif pv.pv_name.startswith("/dev/md"):
+ try:
+ md_named_dev = blockdev.md.name_from_node(pv.pv_name[len("/dev/"):])
+ self._pvs_cache["/dev/md/" + md_named_dev] = pv
+ except blockdev.MDRaidError:
+ pass
return self._pvs_cache
--
2.7.4

@ -0,0 +1,52 @@
From 7a4cfbeb1f971d4968248a6002a365835f11c72e Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Marek=20Marczykowski-G=C3=B3recki?=
<marmarek@invisiblethingslab.com>
Date: Wed, 23 Oct 2019 00:21:02 +0200
Subject: [PATCH] Backport lvm thin pool metadata size functions from BlockDev
2.0
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
Organization: Invisible Things Lab
Cc: Marek Marczykowski-Górecki <marmarek@invisiblethingslab.com>
Those are included only in BlockDev >= 2.0 API (libblockdev>=2.1), but
we don't have luxury of such new version. Since it's just one short
function and two constants, "copy" (translating from C) them directly
into blivet/devices/lvm.py.
Signed-off-by: Marek Marczykowski-Górecki <marmarek@invisiblethingslab.com>
---
blivet/devices/lvm.py | 16 ++++++++++++++++
1 file changed, 16 insertions(+)
diff --git a/blivet/devices/lvm.py b/blivet/devices/lvm.py
index 39c6f342..94894272 100644
--- a/blivet/devices/lvm.py
+++ b/blivet/devices/lvm.py
@@ -56,6 +56,22 @@ from .dm import DMDevice
from .md import MDRaidArrayDevice
from .cache import Cache, CacheStats, CacheRequest
+# loose backport from BlockDev 2.0 interface
+LVM_DEFAULT_CHUNK_SIZE = 65536
+LVM_MIN_THPOOL_MD_SIZE = 2 * 2**20 # 2 MiB
+
+def get_thpool_meta_size(pool_size, block_size, max_thins):
+
+ command = ["thin_metadata_size",
+ "-ub", "-n",
+ "-b", str(int(block_size)),
+ "-s", str(int(pool_size)),
+ "-m", str(int(max_thins))]
+ (rc, out) = util.run_program_and_capture_output(command)
+ if rc:
+ raise Exception("thin_metadata_size failed with %d" % rc)
+ return max(int(out), LVM_MIN_THPOOL_MD_SIZE)
+
class LVPVSpec(object):
""" Class for specifying how much space on a PV should be allocated for some LV """
--
2.20.1

@ -0,0 +1,36 @@
From 2aeba92531b6146a760440f857d526ca7c19053e Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Marek=20Marczykowski-G=C3=B3recki?=
<marmarek@invisiblethingslab.com>
Date: Wed, 23 Oct 2019 00:23:10 +0200
Subject: [PATCH 2/2] Use local backport of BlockDev 2.0 interface
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
Organization: Invisible Things Lab
Cc: Marek Marczykowski-Górecki <marmarek@invisiblethingslab.com>
Signed-off-by: Marek Marczykowski-Górecki <marmarek@invisiblethingslab.com>
---
blivet/devices/lvm.py | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/blivet/devices/lvm.py b/blivet/devices/lvm.py
index 15ddef74..da3dc853 100644
--- a/blivet/devices/lvm.py
+++ b/blivet/devices/lvm.py
@@ -1541,10 +1541,10 @@ class LVMThinPoolMixin(object):
# we need to know chunk size to calculate recommended metadata size
if self._chunk_size == 0:
- self._chunk_size = Size(blockdev.LVM_DEFAULT_CHUNK_SIZE)
+ self._chunk_size = Size(LVM_DEFAULT_CHUNK_SIZE)
log.debug("Using default chunk size: %s", self._chunk_size)
- self._metadata_size = Size(blockdev.lvm.get_thpool_meta_size(self._size,
+ self._metadata_size = Size( get_thpool_meta_size(self._size,
self._chunk_size,
100)) # snapshots
log.debug("Recommended metadata size: %s", self._metadata_size)
--
2.20.1

Binary file not shown.

Binary file not shown.

@ -1,11 +1,11 @@
Summary: A python module for system storage configuration
Name: python-blivet
Url: http://fedoraproject.org/wiki/blivet
Version: 2.1.6
Version: 2.1.11
#%%global prerelease .b1
# prerelease, if defined, should be something like .a1, .b1, .b2.dev1, or .c2
Release: 5%{?prerelease}%{?dist}
Release: 6%{?prerelease}%{?dist}
Epoch: 2
License: LGPLv2+
Group: System Environment/Libraries
@ -13,15 +13,17 @@ Group: System Environment/Libraries
%global realversion %{version}%{?prerelease}
Source0: http://github.com/rhinstaller/blivet/archive/%{realname}-%{realversion}.tar.gz
Patch0: 0001-Use-correct-type-for-port-in-GVariant-tuple.patch
Patch1: 0002-iSCSI-Store-auth-info-in-NodeInfo-tuples.patch
Patch2: 0003-iSCSI-turn-iscsi.initiator_set-into-a-property.patch
Patch3: 0004-Add-device-symlinks-to-the-PVs-dictionary-for-MD-RAI.patch
Patch4: 0001-Fix-detection-of-macefi-partitions-1393846.patch
Patch5: 0001-Fix-unknown-SAS-device-sysfs-parsing.patch
Patch6: 0001-Change-how-we-run-e2fsck-to-check-ext-filesystems.patch
Patch7: 0002-Do-not-run-FS-check-as-part-of-updating-re-size-info.patch
Patch8: 0001-Fix-AttributeError-in-fsminsize-1502587.patch
Patch0: 0001-Fix-AttributeError-in-fsminsize-1502587.patch
# make it compatible with fc25
Patch1: 0001-Revert-FBA-DASD-should-use-the-msdos-disk-label-type.patch
Patch2: 0002-Revert-Require-BlockDev-2.0-in-the-gi.require_versio.patch
Patch3: 0003-Revert-Adapt-to-logging-module-name-change.patch
Patch4: 0004-Backport-lvm-thin-pool-metadata-size-functions-from-.patch
Patch5: 0005-Use-local-backport-of-BlockDev-2.0-interface.patch
# Qubes patches
Patch100: 0001-Double-recommended-LVM-thin-pool-metadata-space.patch
Patch101: 0001-Avoid-mounting-pre-existing-disks.patch
# Versions of required components (done so we make sure the buildrequires
# match the requires versions of things).
@ -77,9 +79,9 @@ configuration.
%patch3 -p1
%patch4 -p1
%patch5 -p1
%patch6 -p1
%patch7 -p1
%patch8 -p1
%patch100 -p1
%patch101 -p1
rm -rf %{py3dir}
cp -a . %{py3dir}

@ -0,0 +1,7 @@
# Full ISO build using packages from online repositories instead of local build
%include qubes-kickstart.cfg
repo --name=qubes-r4.0 --gpgkey=file:///tmp/qubes-installer/qubes-release/RPM-GPG-KEY-qubes-4.0-primary --baseurl=http://yum.qubes-os.org/r4.0/current-testing/dom0/fc25 --ignoregroups=true
repo --name=qubes-r4.0-templates-itl --gpgkey=file:///tmp/qubes-installer/qubes-release/RPM-GPG-KEY-qubes-4.0-primary --mirrorlist=http://yum.qubes-os.org/r4.0/templates-itl/repodata/repomd.xml.metalink --ignoregroups=true
repo --name=qubes-r4.0-templates-community --gpgkey=file:///tmp/qubes-installer/qubes-release/RPM-GPG-KEY-qubes-4.0-templates-community --mirrorlist=http://yum.qubes-os.org/r4.0/templates-community/repodata/repomd.xml.metalink --ignoregroups=true

@ -1,8 +1,6 @@
%include qubes-kickstart.cfg
%include iso-full-online.ks
repo --name=qubes-r4.0-testing --gpgkey=file:///tmp/qubes-installer/qubes-release/RPM-GPG-KEY-qubes-4.0-primary --baseurl=http://mirrors.ukfast.co.uk/sites/qubes-os.org/repo/yum/r4.0/current-testing/dom0/fc25 --ignoregroups=true
repo --name=qubes-r4.0-templates-itl --gpgkey=file:///tmp/qubes-installer/qubes-release/RPM-GPG-KEY-qubes-4.0-primary --baseurl=http://mirrors.ukfast.co.uk/sites/qubes-os.org/repo/yum/r4.0/templates-itl --ignoregroups=true
repo --name=qubes-r4.0-templates-itl-testing --gpgkey=file:///tmp/qubes-installer/qubes-release/RPM-GPG-KEY-qubes-4.0-primary --baseurl=http://mirrors.ukfast.co.uk/sites/qubes-os.org/repo/yum/r4.0/templates-itl-testing --ignoregroups=true
repo --name=qubes-r4.0-templates-community --gpgkey=file:///tmp/qubes-installer/qubes-release/RPM-GPG-KEY-qubes-4.0-templates-community --baseurl=http://mirrors.ukfast.co.uk/sites/qubes-os.org/repo/yum/r4.0/templates-community --ignoregroups=true
repo --name=qubes-r4.0-templates-community-testing --gpgkey=file:///tmp/qubes-installer/qubes-release/RPM-GPG-KEY-qubes-4.0-templates-community --baseurl=http://mirrors.ukfast.co.uk/sites/qubes-os.org/repo/yum/r4.0/templates-community-testing --ignoregroups=true
repo --name=qubes-r4.0-testing --gpgkey=file:///tmp/qubes-installer/qubes-release/RPM-GPG-KEY-qubes-4.0-primary --baseurl=http://yum.qubes-os.org/r4.0/current-testing/dom0/fc25 --ignoregroups=true
repo --name=qubes-r4.0-templates-itl-testing --gpgkey=file:///tmp/qubes-installer/qubes-release/RPM-GPG-KEY-qubes-4.0-primary --mirrorlist=http://yum.qubes-os.org/r4.0/templates-itl-testing/repodata/repomd.xml.metalink --ignoregroups=true
repo --name=qubes-r4.0-templates-community-testing --gpgkey=file:///tmp/qubes-installer/qubes-release/RPM-GPG-KEY-qubes-4.0-templates-community --mirrorlist=http://yum.qubes-os.org/r4.0/templates-community-testing/repodata/repomd.xml.metalink --ignoregroups=true

@ -1,5 +1,5 @@
Name: lorax-templates-qubes
Version: 4.0.5
Version: 4.0.6
Release: 1%{?dist}
Summary: Lorax templates for Qubes installation ISO

@ -61,12 +61,12 @@ menu separator # insert an empty line
label linux
menu label ^Install @PRODUCT@ @VERSION@
kernel mboot.c32
append xen.gz console=none --- vmlinuz @ROOT@ i915.alpha_support=1 quiet rhgb --- initrd.img
append xen.gz console=none --- vmlinuz @ROOT@ i915.alpha_support=1 quiet rhgb plymouth.ignore-serial-consoles --- initrd.img
label check
menu label Test this ^media & install @PRODUCT@ @VERSION@
menu default
kernel mboot.c32
append xen.gz console=none --- vmlinuz @ROOT@ i915.alpha_support=1 quiet rhgb rd.live.check --- initrd.img
append xen.gz console=none --- vmlinuz @ROOT@ i915.alpha_support=1 quiet rhgb plymouth.ignore-serial-consoles rd.live.check --- initrd.img
menu separator # insert an empty line

@ -3,12 +3,12 @@ default=qubes-verbose
[qubes-check]
options=console=none
kernel=vmlinuz @ROOT@ i915.alpha_support=1 quiet rhgb rd.live.check
kernel=vmlinuz @ROOT@ i915.alpha_support=1 quiet rhgb plymouth.ignore-serial-consoles rd.live.check
ramdisk=initrd.img
[qubes]
options=console=none
kernel=vmlinuz @ROOT@ i915.alpha_support=1 quiet rhgb
kernel=vmlinuz @ROOT@ i915.alpha_support=1 quiet rhgb plymouth.ignore-serial-consoles
ramdisk=initrd.img
[qubes-verbose]

@ -1,160 +0,0 @@
#!/bin/bash
# Failsafe minimal text-mode firstboot
# Welcome
if [ "x$1" = "x--help" ]; then
echo "Failsafe minimal text-mode firstboot"
echo "For unattended mode use: $0 <username> <userpass> <vm-creation-option-number>"
exit 0
fi
echo "########################################################"
echo " Welcome to `cat /etc/qubes-release`"
echo "########################################################"
echo
echo "This is failsafe text-mode firstboot. If you see this message, you have"
echo "some problem with Xorg (most probably video driver)"
echo
echo "Anyway, some basic setup is needed to continue:"
# User creation
echo
echo "1. Setup user account"
exists=0
user=$1
while [ -z "$user" ]; do
echo -n "Enter desired username (may already exist): "
read user
if echo "$user" | grep -q "[^a-z0-9]"; then
echo "ERROR: Invalid characters in username, try again"
user=
elif id $user > /dev/null 2>&1; then
if [ $(id -u ${user}) -ge 1000 ] && id -n -G ${user} | grep -q qubes; then
echo "OK: Using an existing user: \"${user}\""
exists=1
break
fi
echo "ERROR: This user already exists or is not suitable. Please try again"
user=
else
break
fi
done
if [ ${exists} -eq 0 ]; then
useradd -G qubes -m "$user" || exit 1
if [ -n "$2" ]; then
echo -e "$2\n$2" | passwd --stdin "$user"
else
while ! passwd "$user"; do true; done
fi
fi
# Create default VMs
echo
echo "2. Create default VMs"
echo
echo "Choose one option:"
echo " 1. Create default service VMs, and pre-defined AppVMs (personal, work, untrusted, vault)"
echo " 2. Just create default service VMs"
echo " 3. Do not create any VMs right now, but configure template(s)"
echo " 4. Do not do anything (not recommended, for advanced users only)"
vms_option=$3
while true; do
if [ -z "$vms_option" ]; then
echo -n "Enter your choice (1/2/3/4): "
read vms_option
fi
if [ "$vms_option" == "1" ]; then
vms_template=yes
vms_service=yes
vms_app=yes
break
elif [ "$vms_option" == "2" ]; then
vms_template=yes
vms_service=yes
break
elif [ "$vms_option" == "3" ]; then
vms_template=yes
break
elif [ "$vms_option" == "4" ]; then
break
else
echo "ERROR: Invalid choice, try again"
vms_option=
fi
done
set -e
for service in rdisc kdump libvirt-guests salt-minion; do
systemctl disable ${service}.service || :
systemctl stop ${service}.service || :
done
if [ "$vms_template" == "yes" ]; then
for template in `ls /var/lib/qubes/vm-templates`; do
echo "-> Configuring template $template..."
qvm-start --no-guid $template
su -g "qubes" -c "qvm-sync-appmenus $template" - $user
qvm-shutdown --wait $template
done
qubes-prefs --set default-template 'fedora-29'
fi
if [ "$vms_service" == "yes" -o "$vms_app" == "yes" ]; then
echo "-> Configuring Qubes OS management framework..."
if test -e /var/log/salt/minion; then
mv /var/log/salt/minion /var/log/salt/minion.install || :
fi
qubesctl saltutil.clear_cache -l quiet --out quiet
qubesctl saltutil.sync_all -l quiet --out quiet
fi
states=()
if [ "$vms_service" == "yes" ]; then
states=("${states[@]}" qvm.sys-net qvm.sys-firewall)
fi
if [ "$vms_app" == "yes" ]; then
states=("${states[@]}" qvm.personal qvm.work qvm.untrusted qvm.vault)
fi
if [ "$vms_service" == "yes" -o "$vms_app" == "yes" ]; then
for state in "${states[@]}"; do
echo "-> Requesting creation of VM: ${state#qvm.}"
qubesctl top.enable "${state}" -l quiet --out quiet
done
echo "-> Creating VMs"
qubesctl "state.highstate"
fi
if [ "$vms_service" == "yes" ]; then
echo "--> Configuring service VMs"
default_netvm="sys-net"
default_firewallvm="sys-firewall"
su -g "qubes" -c "qvm-prefs --set ${default_firewallvm} netvm ${default_netvm}" - $user
su -g "qubes" -c "qubes-prefs --set default-netvm ${default_firewallvm}" - $user
su -g "qubes" -c "qubes-prefs --set updatevm ${default_firewallvm}" - $user
su -g "qubes" -c "qubes-prefs --set clockvm ${default_netvm}" - $user
echo "-> Starting network..."
service qubes-netvm start
# DispVM creation fails with the following error message, most likely due to missing $DISPLAY:
# "Cannot start qubes-guid!"
#echo "-> Creating DispVM savefile (can take long time)..."
#su -g "qubes" -c "/usr/bin/qvm-create-default-dvm --default-template --default-script" - $user || :
fi
echo "-> Done."

@ -2,4 +2,4 @@
# if X server is not yet running
#import gui
import tui
#import tui

@ -4,4 +4,98 @@ work.
"""
import spokes
import gi
gi.require_version('Gtk', '3.0')
gi.require_version('Gdk', '3.0')
gi.require_version('GLib', '2.0')
from gi.repository import Gtk
from gi.repository import Gdk
from gi.repository import GLib
import logging
import threading
class ThreadDialog(Gtk.Dialog):
def __init__(self, title, fun, args, transient_for=None):
Gtk.Dialog.__init__(self, title=title, transient_for=transient_for)
self.set_modal(True)
self.set_default_size(500, 100)
self.connect('delete-event', self.on_delete_event)
self.progress = Gtk.ProgressBar()
self.progress.set_pulse_step(100)
self.progress.set_text("")
self.progress.set_show_text(False)
self.label = Gtk.Label()
self.label.set_line_wrap(True)
self.label.set_text("")
self.box = Gtk.Box(orientation=Gtk.Orientation.VERTICAL)
self.box.pack_start(self.progress, True, True, 0)
self.box.pack_start(self.label, True, True, 0)
self.get_content_area().pack_start(self.box, True, True, 0)
self.fun = fun
self.args = args
self.logger = logging.getLogger("anaconda")
self.thread = threading.Thread(target=self.run_fun)
def run_fun(self):
try:
self.fun(*self.args)
except Exception as e:
self.showErrorMessage(str(e))
finally:
self.done()
def on_delete_event(self, widget=None, *args):
# Ignore the clicks on the close button by returning True.
self.logger.info("Caught delete-event")
return True
def set_text(self, text):
Gdk.threads_add_timeout(GLib.PRIORITY_DEFAULT, 0, self.label.set_text, text)
def done(self):
Gdk.threads_add_timeout(GLib.PRIORITY_DEFAULT, 100, self.done_helper, ())
def done_helper(self, *args):
self.logger.info("Joining thread.")
self.thread.join()
self.logger.info("Stopping self.")
self.response(Gtk.ResponseType.ACCEPT)
def run_in_ui_thread(self, fun, *args):
Gdk.threads_add_timeout(GLib.PRIORITY_DEFAULT, 0, fun, *args)
def run(self):
self.thread.start()
self.progress.pulse()
self.show_all()
ret = None
while ret in (None, Gtk.ResponseType.DELETE_EVENT):
ret = super(ThreadDialog, self).run()
return ret
def showErrorMessage(self, text):
self.run_in_ui_thread(self.showErrorMessageHelper, text)
def showErrorMessageHelper(self, text):
dlg = Gtk.MessageDialog(title="Error", message_type=Gtk.MessageType.ERROR, buttons=Gtk.ButtonsType.OK, text=text)
dlg.set_position(Gtk.WindowPosition.CENTER)
dlg.set_modal(True)
dlg.set_transient_for(self)
dlg.run()
dlg.destroy()

@ -29,15 +29,7 @@
_ = lambda x: x
N_ = lambda x: x
import distutils.version
import functools
import grp
import logging
import os
import os.path
import pyudev
import subprocess
import threading
import gi
@ -46,10 +38,7 @@ gi.require_version('Gdk', '3.0')
gi.require_version('GLib', '2.0')
from gi.repository import Gtk
from gi.repository import Gdk
from gi.repository import GLib
from pyanaconda import iutil
from pyanaconda.ui.categories.system import SystemCategory
from pyanaconda.ui.gui.spokes import NormalSpoke
from pyanaconda.ui.common import FirstbootOnlySpokeMixIn
@ -57,53 +46,15 @@ from pyanaconda.ui.common import FirstbootOnlySpokeMixIn
# export only the spoke, no helper functions, classes or constants
__all__ = ["QubesOsSpoke"]
def is_package_installed(pkgname):
pkglist = subprocess.check_output(['rpm', '-qa', pkgname])
return bool(pkglist)
def usb_keyboard_present():
context = pyudev.Context()
keyboards = context.list_devices(subsystem='input', ID_INPUT_KEYBOARD='1')
return any([d.get('ID_USB_INTERFACES', False) for d in keyboards])
def started_from_usb():
def get_all_used_devices(dev):
stat = os.stat(dev)
if stat.st_rdev:
# XXX any better idea how to handle device-mapper?
sysfs_slaves = '/sys/dev/block/{}:{}/slaves'.format(
os.major(stat.st_rdev), os.minor(stat.st_rdev))
if os.path.exists(sysfs_slaves):
for slave_dev in os.listdir(sysfs_slaves):
for d in get_all_used_devices('/dev/{}'.format(slave_dev)):
yield d
else:
yield dev
context = pyudev.Context()
mounts = open('/proc/mounts').readlines()
for mount in mounts:
device = mount.split(' ')[0]
if not os.path.exists(device):
continue
for dev in get_all_used_devices(device):
udev_info = pyudev.Device.from_device_file(context, dev)
if udev_info.get('ID_USB_INTERFACES', False):
return True
return False
class QubesChoice(object):
instances = []
def __init__(self, label, states, depend=None, extra_check=None,
replace=None, indent=False):
def __init__(self, label, depend=None, extra_check=None,
indent=False):
self.widget = Gtk.CheckButton(label=label)
self.states = states
self.depend = depend
self.extra_check = extra_check
self.selected = None
self.replace = replace
self._can_be_sensitive = True
@ -129,6 +80,11 @@ class QubesChoice(object):
if self.selected is not None
else self.widget.get_sensitive() and self.widget.get_active())
def set_selected(self, value):
self.widget.set_active(value)
if self.selected is not None:
self.selected = value
def store_selected(self):
self.selected = self.get_selected()
@ -146,27 +102,14 @@ class QubesChoice(object):
choice.set_sensitive(not selected and
(choice.depend is None or choice.depend.get_selected()))
@classmethod
def get_states(cls):
replaced = functools.reduce(
lambda x, y: x+y if y else x,
(choice.replace for choice in cls.instances if
choice.get_selected()),
()
)
for choice in cls.instances:
if choice.get_selected():
for state in choice.states:
if state not in replaced:
yield state
class DisabledChoice(QubesChoice):
def __init__(self, label):
super(DisabledChoice, self).__init__(label, ())
super(DisabledChoice, self).__init__(label)
self.widget.set_sensitive(False)
self._can_be_sensitive = False
class QubesOsSpoke(FirstbootOnlySpokeMixIn, NormalSpoke):
"""
Since this class inherits from the FirstbootOnlySpokeMixIn, it will
@ -226,55 +169,43 @@ class QubesOsSpoke(FirstbootOnlySpokeMixIn, NormalSpoke):
self.main_box = self.builder.get_object("mainBox")
self.thread_dialog = None
self.qubes_user = None
self.qubes_gid = None
self.default_template = 'fedora-29'
self.set_stage("Start-up")
self.done = False
self.qubes_data = self.data.addons.org_qubes_os_initial_setup
self.__init_qubes_choices()
def __init_qubes_choices(self):
self.choice_network = QubesChoice(
_('Create default system qubes (sys-net, sys-firewall, default DispVM)'),
('qvm.sys-net', 'qvm.sys-firewall', 'qvm.default-dispvm'))
self.choice_system = QubesChoice(
_('Create default system qubes (sys-net, sys-firewall, default DispVM)'))
self.choice_default = QubesChoice(
_('Create default application qubes '
'(personal, work, untrusted, vault)'),
('qvm.personal', 'qvm.work', 'qvm.untrusted', 'qvm.vault'),
depend=self.choice_network)
depend=self.choice_system)
if (is_package_installed('qubes-template-whonix-gw*') and
is_package_installed('qubes-template-whonix-ws*')):
if self.qubes_data.whonix_available:
self.choice_whonix = QubesChoice(
_('Create Whonix Gateway and Workstation qubes '
'(sys-whonix, anon-whonix)'),
('qvm.sys-whonix', 'qvm.anon-whonix'),
depend=self.choice_network)
depend=self.choice_system)
else:
self.choice_whonix = DisabledChoice(_("Whonix not installed"))
self.choice_whonix_updates = QubesChoice(
_('Enable system and template updates over the Tor anonymity '
'network using Whonix'),
('qvm.updates-via-whonix',),
depend=self.choice_whonix,
indent=True)
if not usb_keyboard_present() and not started_from_usb():
if self.qubes_data.usbvm_available:
self.choice_usb = QubesChoice(
_('Create USB qube holding all USB controllers (sys-usb)'),
('qvm.sys-usb',))
_('Create USB qube holding all USB controllers (sys-usb)'))
else:
self.choice_usb = DisabledChoice(
_('USB qube configuration disabled - you are using USB '
'keyboard or USB disk'))
self.choice_usb_with_net = QubesChoice(
self.choice_usb_with_netvm = QubesChoice(
_("Use sys-net qube for both networking and USB devices"),
('pillar.qvm.sys-net-as-usbvm',),
depend=self.choice_usb,
indent=True
)
@ -289,7 +220,7 @@ class QubesOsSpoke(FirstbootOnlySpokeMixIn, NormalSpoke):
self.check_advanced.set_active(False)
self.choice_network.widget.set_active(True)
self.choice_system.widget.set_active(True)
self.choice_default.widget.set_active(True)
if self.choice_whonix.widget.get_sensitive():
self.choice_whonix.widget.set_active(True)
@ -307,6 +238,7 @@ class QubesOsSpoke(FirstbootOnlySpokeMixIn, NormalSpoke):
"""
NormalSpoke.initialize(self)
self.qubes_data.gui_mode = True
def refresh(self):
"""
@ -318,8 +250,12 @@ class QubesOsSpoke(FirstbootOnlySpokeMixIn, NormalSpoke):
"""
# nothing to do here
pass
self.choice_system.set_selected(self.qubes_data.system_vms)
self.choice_default.set_selected(self.qubes_data.default_vms)
self.choice_whonix.set_selected(self.qubes_data.whonix_vms)
self.choice_whonix_updates.set_selected(self.qubes_data.whonix_default)
self.choice_usb.set_selected(self.qubes_data.usbvm)
self.choice_usb_with_netvm.set_selected(self.qubes_data.usbvm_with_netvm)
def apply(self):
"""
@ -328,8 +264,16 @@ class QubesOsSpoke(FirstbootOnlySpokeMixIn, NormalSpoke):
"""
# nothing to do here
pass
self.qubes_data.skip = self.check_advanced.get_active()
self.qubes_data.system_vms = self.choice_system.get_selected()
self.qubes_data.default_vms = self.choice_default.get_selected()
self.qubes_data.whonix_vms = self.choice_whonix.get_selected()
self.qubes_data.whonix_default = self.choice_whonix_updates.get_selected()
self.qubes_data.usbvm = self.choice_usb.get_selected()
self.qubes_data.usbvm_with_netvm = self.choice_usb_with_netvm.get_selected()
self.qubes_data.seen = True
@property
def ready(self):
@ -354,7 +298,7 @@ class QubesOsSpoke(FirstbootOnlySpokeMixIn, NormalSpoke):
"""
return self.done
return self.qubes_data.seen
@property
def mandatory(self):
@ -388,274 +332,4 @@ class QubesOsSpoke(FirstbootOnlySpokeMixIn, NormalSpoke):
the values set in the GUI elements.
"""
for choice in QubesChoice.instances:
choice.store_selected()
self.thread_dialog = ThreadDialog("Qubes OS Setup", self.do_setup, (), transient_for=self.main_window)
self.thread_dialog.run()
self.thread_dialog.destroy()
def do_setup(self, *args):
try:
self.qubes_gid = grp.getgrnam('qubes').gr_gid
qubes_users = grp.getgrnam('qubes').gr_mem
if len(qubes_users) < 1:
self.showErrorMessage(_("You must create a user account to create default VMs."))
return
else:
self.qubes_user = qubes_users[0]
if self.check_advanced.get_active():
return
errors = []
os.setgid(self.qubes_gid)
os.umask(0o0007)
self.configure_default_kernel()
# Finish template(s) installation, because it wasn't fully possible
# from anaconda (it isn't possible to start a VM there).
# This is specific to firstboot, not general configuration.
for template in os.listdir('/var/lib/qubes/vm-templates'):
try:
self.configure_template(template,
'/var/lib/qubes/vm-templates/' + template)
except Exception as e:
errors.append((self.stage, str(e)))
self.configure_dom0()
self.configure_default_template()
self.configure_qubes()
if self.choice_network.get_selected():
self.configure_network()
if self.choice_usb.get_selected() and not self.choice_usb_with_net.get_selected():
# Workaround for #1464 (so qvm.start from salt can't be used)
self.run_command(['systemctl', 'start', 'qubes-vm@sys-usb.service'])
try:
self.configure_default_dvm()
except Exception as e:
errors.append((self.stage, str(e)))
if errors:
msg = ""
for (stage, error) in errors:
msg += "{} failed:\n{}\n\n".format(stage, error)
raise Exception(msg)
except Exception as e:
self.showErrorMessage(str(e))
finally:
self.thread_dialog.done()
self.done = True
def set_stage(self, stage):
self.stage = stage
if self.thread_dialog != None:
self.thread_dialog.set_text(stage)
def run_command(self, command, stdin=None, ignore_failure=False):
process_error = None
try:
sys_root = iutil.getSysroot()
cmd = iutil.startProgram(command, stderr=subprocess.PIPE, stdin=stdin, root=sys_root)
(stdout, stderr) = cmd.communicate()
stdout = stdout.decode("utf-8")
stderr = stderr.decode("utf-8")
if not ignore_failure and cmd.returncode != 0:
process_error = "{} failed:\nstdout: \"{}\"\nstderr: \"{}\"".format(command, stdout, stderr)
except Exception as e:
process_error = str(e)
if process_error:
self.logger.error(process_error)
raise Exception(process_error)
return (stdout, stderr)
def configure_default_kernel(self):
self.set_stage("Setting up default kernel")
installed_kernels = os.listdir('/var/lib/qubes/vm-kernels')
installed_kernels = [distutils.version.LooseVersion(x) for x in installed_kernels]
default_kernel = str(sorted(installed_kernels)[-1])
self.run_command(['/usr/bin/qubes-prefs', 'default-kernel', default_kernel])
def configure_dom0(self):
self.set_stage("Setting up administration VM (dom0)")
for service in [ 'rdisc', 'kdump', 'libvirt-guests', 'salt-minion' ]:
self.run_command(['systemctl', 'disable', '{}.service'.format(service) ], ignore_failure=True)
self.run_command(['systemctl', 'stop', '{}.service'.format(service) ], ignore_failure=True)
def configure_qubes(self):
self.set_stage('Executing qubes configuration')
try:
# get rid of initial entries (from package installation time)
os.rename('/var/log/salt/minion', '/var/log/salt/minion.install')
except OSError:
pass
# Refresh minion configuration to make sure all installed formulas are included
self.run_command(['qubesctl', 'saltutil.clear_cache'])
self.run_command(['qubesctl', 'saltutil.sync_all'])
for state in QubesChoice.get_states():
print("Setting up state: {}".format(state))
if state.startswith('pillar.'):
self.run_command(['qubesctl', 'top.enable',
state[len('pillar.'):], 'pillar=True'])
else:
self.run_command(['qubesctl', 'top.enable', state])
try:
self.run_command(['qubesctl', 'state.highstate'])
# After successful call disable all the states to not leave them
# enabled, to not interfere with later user changes (like assigning
# additional PCI devices)
for state in QubesChoice.get_states():
if not state.startswith('pillar.'):
self.run_command(['qubesctl', 'top.disable', state])
except Exception:
raise Exception(
("Qubes initial configuration failed. Login to the system and " +
"check /var/log/salt/minion for details. " +
"You can retry configuration by calling " +
"'sudo qubesctl state.highstate' in dom0 (you will get " +
"detailed state there)."))
def configure_default_template(self):
self.set_stage('Setting default template')
self.run_command(['/usr/bin/qubes-prefs', 'default-template', self.default_template])
def configure_default_dvm(self):
self.set_stage("Creating default DisposableVM")
dispvm_name = self.default_template + '-dvm'
self.run_command(['/usr/bin/qubes-prefs', 'default-dispvm',
dispvm_name])
def configure_network(self):
self.set_stage('Setting up networking')
default_netvm = 'sys-firewall'
updatevm = default_netvm
if self.choice_whonix_updates.get_selected():
updatevm = 'sys-whonix'
self.run_command(['/usr/bin/qvm-prefs', 'sys-firewall', 'netvm', 'sys-net'])
self.run_command(['/usr/bin/qubes-prefs', 'default-netvm', default_netvm])
self.run_command(['/usr/bin/qubes-prefs', 'updatevm', updatevm])
self.run_command(['/usr/bin/qubes-prefs', 'clockvm', 'sys-net'])
self.run_command(['/usr/bin/qvm-start', default_netvm])
def configure_template(self, template, path):
self.set_stage("Configuring TemplateVM {}".format(template))
self.run_command(['qvm-template-postprocess', '--really', 'post-install', template, path])
def showErrorMessage(self, text):
self.thread_dialog.run_in_ui_thread(self.showErrorMessageHelper, text)
def showErrorMessageHelper(self, text):
dlg = Gtk.MessageDialog(title="Error", message_type=Gtk.MessageType.ERROR, buttons=Gtk.ButtonsType.OK, text=text)
dlg.set_position(Gtk.WindowPosition.CENTER)
dlg.set_modal(True)
dlg.set_transient_for(self.thread_dialog)
dlg.run()
dlg.destroy()
class ThreadDialog(Gtk.Dialog):
def __init__(self, title, fun, args, transient_for=None):
Gtk.Dialog.__init__(self, title=title, transient_for=transient_for)
self.set_modal(True)
self.set_default_size(500, 100)
self.connect('delete-event', self.on_delete_event)
self.progress = Gtk.ProgressBar()
self.progress.set_pulse_step(100)
self.progress.set_text("")
self.progress.set_show_text(False)
self.label = Gtk.Label()
self.label.set_line_wrap(True)
self.label.set_text("")
self.box = Gtk.Box(orientation=Gtk.Orientation.VERTICAL)
self.box.pack_start(self.progress, True, True, 0)
self.box.pack_start(self.label, True, True, 0)
self.get_content_area().pack_start(self.box, True, True, 0)
self.fun = fun
self.args = args
self.logger = logging.getLogger("anaconda")
self.thread = threading.Thread(target=self.fun, args=self.args)
def on_delete_event(self, widget=None, *args):
# Ignore the clicks on the close button by returning True.
self.logger.info("Caught delete-event")
return True
def set_text(self, text):
Gdk.threads_add_timeout(GLib.PRIORITY_DEFAULT, 0, self.label.set_text, text)
def done(self):
Gdk.threads_add_timeout(GLib.PRIORITY_DEFAULT, 100, self.done_helper, ())
def done_helper(self, *args):
self.logger.info("Joining thread.")
self.thread.join()
self.logger.info("Stopping self.")
self.response(Gtk.ResponseType.ACCEPT)
def run_in_ui_thread(self, fun, *args):
Gdk.threads_add_timeout(GLib.PRIORITY_DEFAULT, 0, fun, *args)
def run(self):
self.thread.start()
self.progress.pulse()
self.show_all()
ret = None
while ret in (None, Gtk.ResponseType.DELETE_EVENT):
ret = super(ThreadDialog, self).run()
return ret
if __name__ == "__main__":
import time
def hello_fun(*args):
global thread_dialog
thread_dialog.set_text("Hello, world! " * 30)
time.sleep(2)
thread_dialog.set_text("Goodbye, world!")
time.sleep(1)
thread_dialog.done()
return
logger = logging.getLogger("anaconda")
handler = logging.StreamHandler()
logger.addHandler(handler)
logger.setLevel(logging.DEBUG)
thread_dialog = ThreadDialog("Hello", hello_fun, ())
thread_dialog.run()
pass

@ -0,0 +1,362 @@
#
# The Qubes OS Project, https://www.qubes-os.org/
#
# Copyright (C) 2019 Marek Marczykowski-Górecki
# <marmarek@invisiblethingslab.com>
#
# This library is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public
# License as published by the Free Software Foundation; either
# version 2 of the License, or (at your option) any later version.
#
# This library is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
# Lesser General Public License for more details.
#
# You should have received a copy of the GNU General Public
# License along with this library; if not, see <https://www.gnu.org/licenses/>.
#
import grp
import os
import distutils.version
import pyudev
import subprocess
from pyanaconda import iutil
from pyanaconda.addons import AddonData
from pykickstart.errors import KickstartValueError
from pyanaconda.progress import progress_message
import logging
log = logging.getLogger("anaconda")
__all__ = ['QubesData']
def is_package_installed(pkgname):
pkglist = subprocess.check_output(['rpm', '-qa', pkgname])
return bool(pkglist)
def usb_keyboard_present():
context = pyudev.Context()
keyboards = context.list_devices(subsystem='input', ID_INPUT_KEYBOARD='1')
return any([d.get('ID_USB_INTERFACES', False) for d in keyboards])
def started_from_usb():
def get_all_used_devices(dev):
stat = os.stat(dev)
if stat.st_rdev:
# XXX any better idea how to handle device-mapper?
sysfs_slaves = '/sys/dev/block/{}:{}/slaves'.format(
os.major(stat.st_rdev), os.minor(stat.st_rdev))
if os.path.exists(sysfs_slaves):
for slave_dev in os.listdir(sysfs_slaves):
for d in get_all_used_devices('/dev/{}'.format(slave_dev)):
yield d
else:
yield dev
context = pyudev.Context()
mounts = open('/proc/mounts').readlines()
for mount in mounts:
device = mount.split(' ')[0]
if not os.path.exists(device):
continue
for dev in get_all_used_devices(device):
udev_info = pyudev.Device.from_device_file(context, dev)
if udev_info.get('ID_USB_INTERFACES', False):
return True
return False
class QubesData(AddonData):
"""
Class providing and storing data for the Qubes initial setup addon
"""
bool_options = (
'system_vms', 'default_vms', 'whonix_vms', 'whonix_default', 'usbvm',
'usbvm_with_netvm', 'skip')
def __init__(self, name):
"""
:param name: name of the addon
:type name: str
"""
super(QubesData, self).__init__(name)
self.whonix_available = (
is_package_installed('qubes-template-whonix-gw*') and
is_package_installed('qubes-template-whonix-ws*'))
self.usbvm_available = (
not usb_keyboard_present() and not started_from_usb())
self.system_vms = True
self.default_vms = True
self.whonix_vms = self.whonix_available
self.whonix_default = False
self.usbvm = self.usbvm_available
self.usbvm_with_netvm = False
self.skip = False
# this is a hack, but initial-setup do not have progress hub or similar
# provision for handling lengthy self.execute() call, so we must do it
# ourselves
self.gui_mode = False
self.thread_dialog = None
# choose latest fedora template
fedora_tpls = sorted(
name for name in os.listdir('/var/lib/qubes/vm-templates')
if 'fedora' in name)
if fedora_tpls:
self.default_template = fedora_tpls[-1]
else:
print(
'ERROR: No Fedora template is installed, '
'cannot set default template!')
self.default_template = None
self.qubes_user = None
self.seen = False
def handle_header(self, lineno, args):
pass
def handle_line(self, line):
"""
:param line:
:return:
"""
try:
(param, value) = line.strip().split(maxsplit=1)
except ValueError:
raise KickstartValueError('invalid line: %s' % line)
if param in self.bool_options:
if value.lower() not in ('true', 'false'):
raise KickstartValueError(
'invalid value for bool property: %s' % line)
bool_value = value.lower() == 'true'
setattr(self, param, bool_value)
elif param == 'default_template':
self.default_template = value
else:
raise KickstartValueError('invalid parameter: %s' % param)
self.seen = True
def __str__(self):
section = "%addon {}\n".format(self.name)
for param in self.bool_options:
section += "{} {!s}\n".format(param, getattr(self, param))
section += 'default_template {}\n'.format(self.default_template)
section += '%end\n'
return section
def execute(self, storage, ksdata, instClass, users, payload):
if self.gui_mode:
from ..gui import ThreadDialog
self.thread_dialog = ThreadDialog(
"Qubes OS Setup", self.do_setup, ())
self.thread_dialog.run()
self.thread_dialog.destroy()
else:
self.do_setup()
def set_stage(self, stage):
if self.thread_dialog is not None:
self.thread_dialog.set_text(stage)
else:
print(stage)
def do_setup(self):
qubes_gid = grp.getgrnam('qubes').gr_gid
qubes_users = grp.getgrnam('qubes').gr_mem
if len(qubes_users) < 1:
raise Exception(
"You must create a user account to create default VMs.")
else:
self.qubes_user = qubes_users[0]
if self.skip:
return
errors = []
os.setgid(qubes_gid)
os.umask(0o0007)
self.configure_default_kernel()
# Finish template(s) installation, because it wasn't fully possible
# from anaconda (it isn't possible to start a VM there).
# This is specific to firstboot, not general configuration.
for template in os.listdir('/var/lib/qubes/vm-templates'):
try:
self.configure_template(template,
'/var/lib/qubes/vm-templates/' + template)
except Exception as e:
errors.append(('Templates', str(e)))
self.configure_dom0()
self.configure_default_template()
self.configure_qubes()
if self.system_vms:
self.configure_network()
if self.usbvm and not self.usbvm_with_netvm:
# Workaround for #1464 (so qvm.start from salt can't be used)
self.run_command(['systemctl', 'start', 'qubes-vm@sys-usb.service'])
try:
self.configure_default_dvm()
except Exception as e:
errors.append(('Default DVM', str(e)))
if errors:
msg = ""
for (stage, error) in errors:
msg += "{} failed:\n{}\n\n".format(stage, error)
raise Exception(msg)
def run_command(self, command, stdin=None, ignore_failure=False):
process_error = None
try:
sys_root = iutil.getSysroot()
cmd = iutil.startProgram(command,
stderr=subprocess.PIPE,
stdin=stdin,
root=sys_root)
(stdout, stderr) = cmd.communicate()
stdout = stdout.decode("utf-8")
stderr = stderr.decode("utf-8")
if not ignore_failure and cmd.returncode != 0:
process_error = "{} failed:\nstdout: \"{}\"\nstderr: \"{}\"".format(command, stdout, stderr)
except Exception as e:
process_error = str(e)
if process_error:
log.error(process_error)
raise Exception(process_error)
return (stdout, stderr)
def configure_default_kernel(self):
self.set_stage("Setting up default kernel")
installed_kernels = os.listdir('/var/lib/qubes/vm-kernels')
installed_kernels = [distutils.version.LooseVersion(x) for x in installed_kernels]
default_kernel = str(sorted(installed_kernels)[-1])
self.run_command([
'/usr/bin/qubes-prefs', 'default-kernel', default_kernel])
def configure_dom0(self):
self.set_stage("Setting up administration VM (dom0)")
for service in ['rdisc', 'kdump', 'libvirt-guests', 'salt-minion']:
self.run_command(['systemctl', 'disable', '{}.service'.format(service) ], ignore_failure=True)
self.run_command(['systemctl', 'stop', '{}.service'.format(service) ], ignore_failure=True)
def configure_qubes(self):
self.set_stage('Executing qubes configuration')
states = []
if self.system_vms:
states.extend(
('qvm.sys-net', 'qvm.sys-firewall', 'qvm.default-dispvm'))
if self.default_vms:
states.extend(
('qvm.personal', 'qvm.work', 'qvm.untrusted', 'qvm.vault'))
if self.whonix_available and self.whonix_vms:
states.extend(
('qvm.sys-whonix', 'qvm.anon-whonix'))
if self.whonix_default:
states.append('qvm.updates-via-whonix')
if self.usbvm:
states.append('qvm.sys-usb')
if self.usbvm_with_netvm:
states.append('pillar.qvm.sys-net-as-usbvm')
try:
# get rid of initial entries (from package installation time)
os.rename('/var/log/salt/minion', '/var/log/salt/minion.install')
except OSError:
pass
# Refresh minion configuration to make sure all installed formulas are included
self.run_command(['qubesctl', 'saltutil.clear_cache'])
self.run_command(['qubesctl', 'saltutil.sync_all'])
for state in states:
print("Setting up state: {}".format(state))
if state.startswith('pillar.'):
self.run_command(['qubesctl', 'top.enable',
state[len('pillar.'):], 'pillar=True'])
else:
self.run_command(['qubesctl', 'top.enable', state])
try:
self.run_command(['qubesctl', '--all', 'state.highstate'])
# After successful call disable all the states to not leave them
# enabled, to not interfere with later user changes (like assigning
# additional PCI devices)
for state in states:
if not state.startswith('pillar.'):
self.run_command(['qubesctl', 'top.disable', state])
except Exception:
raise Exception(
("Qubes initial configuration failed. Login to the system and " +
"check /var/log/salt/minion for details. " +
"You can retry configuration by calling " +
"'sudo qubesctl state.highstate' in dom0 (you will get " +
"detailed state there)."))
def configure_default_template(self):
self.set_stage('Setting default template')
self.run_command(['/usr/bin/qubes-prefs', 'default-template', self.default_template])
def configure_default_dvm(self):
self.set_stage("Creating default DisposableVM")
dispvm_name = self.default_template + '-dvm'
self.run_command(['/usr/bin/qubes-prefs', 'default-dispvm',
dispvm_name])
def configure_network(self):
self.set_stage('Setting up networking')
default_netvm = 'sys-firewall'
updatevm = default_netvm
if self.whonix_default:
updatevm = 'sys-whonix'
self.run_command(['/usr/bin/qvm-prefs', 'sys-firewall', 'netvm', 'sys-net'])
self.run_command(['/usr/bin/qubes-prefs', 'default-netvm', default_netvm])
self.run_command(['/usr/bin/qubes-prefs', 'updatevm', updatevm])
self.run_command(['/usr/bin/qubes-prefs', 'clockvm', 'sys-net'])
self.run_command(['/usr/bin/qvm-start', default_netvm])
def configure_template(self, template, path):
self.set_stage("Configuring TemplateVM {}".format(template))
self.run_command([
'qvm-template-postprocess', '--really', 'post-install', template, path])

@ -27,11 +27,11 @@
_ = lambda x: x
N_ = lambda x: x
import subprocess
from pyanaconda.ui.categories.system import SystemCategory
from pyanaconda.ui.tui.spokes import NormalTUISpoke
from pyanaconda.constants_text import INPUT_PROCESSED, INPUT_DISCARDED
from simpleline.render.containers import ListColumnContainer
from simpleline.render.widgets import CheckboxWidget
from simpleline.render.screen import InputState
from pyanaconda.ui.common import FirstbootOnlySpokeMixIn
# export only the HelloWorldSpoke and HelloWorldEditSpoke classes
@ -51,21 +51,14 @@ class QubesOsSpoke(FirstbootOnlySpokeMixIn, NormalTUISpoke):
### class attributes defined by API ###
# title of the spoke
title = N_("Qubes OS")
# category this spoke belongs to
category = SystemCategory
def __init__(self, app, data, storage, payload, instclass):
def __init__(self, data, storage, payload, instclass):
"""
:see: pyanaconda.ui.tui.base.UIScreen
:see: pyanaconda.ui.tui.base.App
:param app: reference to application which is a main class for TUI
screen handling, it is responsible for mainloop control
and keeping track of the stack where all TUI screens are
scheduled
:type app: instance of pyanaconda.ui.tui.base.App
:param data: data object passed to every spoke to load/store data
from/to it
:type data: pykickstart.base.BaseHandler
@ -79,9 +72,22 @@ class QubesOsSpoke(FirstbootOnlySpokeMixIn, NormalTUISpoke):
"""
NormalTUISpoke.__init__(self, app, data, storage, payload, instclass)
NormalTUISpoke.__init__(self, data, storage, payload, instclass)
self.initialize_start()
# title of the spoke
self.title = N_("Qubes OS")
self._container = None
self.qubes_data = self.data.addons.org_qubes_os_initial_setup
for attr in self.qubes_data.bool_options:
setattr(self, '_' + attr, getattr(self.qubes_data, attr))
self.initialize_done()
self.done = False
def initialize(self):
"""
@ -95,6 +101,10 @@ class QubesOsSpoke(FirstbootOnlySpokeMixIn, NormalTUISpoke):
NormalTUISpoke.initialize(self)
def _add_checkbox(self, name, title):
w = CheckboxWidget(title=title, completed=getattr(self, name))
self._container.add(w, self._set_checkbox, name)
def refresh(self, args=None):
"""
The refresh method that is called every time the spoke is displayed.
@ -110,8 +120,44 @@ class QubesOsSpoke(FirstbootOnlySpokeMixIn, NormalTUISpoke):
:rtype: bool
"""
return True
super(QubesOsSpoke, self).refresh()
self._container = ListColumnContainer(1)
w = CheckboxWidget(title=_('Create default system qubes '
'(sys-net, sys-firewall, default DispVM)'),
completed=self._system_vms)
self._container.add(w, self._set_checkbox, '_system_vms')
w = CheckboxWidget(title=_('Create default application qubes '
'(personal, work, untrusted, vault)'),
completed=self._default_vms)
self._container.add(w, self._set_checkbox, '_default_vms')
if self.qubes_data.whonix_available:
w = CheckboxWidget(
title=_('Create Whonix Gateway and Workstation qubes '
'(sys-whonix, anon-whonix)'),
completed=self._whonix_vms)
self._container.add(w, self._set_checkbox, '_whonix_vms')
if self._whonix_vms:
w = CheckboxWidget(
title=_('Enable system and template updates over the Tor anonymity '
'network using Whonix'),
completed=self._whonix_default)
self._container.add(w, self._set_checkbox, '_whonix_default')
if self.qubes_data.usbvm_available:
w = CheckboxWidget(
title=_('Create USB qube holding all USB controllers (sys-usb)'),
completed=self._usbvm)
self._container.add(w, self._set_checkbox, '_usbvm')
if self._usbvm:
w = CheckboxWidget(
title=_('Use sys-net qube for both networking and USB devices'),
completed=self._usbvm_with_netvm)
self._container.add(w, self._set_checkbox, '_usbvm_with_netvm')
self.window.add_with_separator(self._container)
def _set_checkbox(self, name):
setattr(self, name, not getattr(self, name))
def apply(self):
"""
@ -120,10 +166,10 @@ class QubesOsSpoke(FirstbootOnlySpokeMixIn, NormalTUISpoke):
"""
proc = subprocess.Popen(["/usr/share/qubes/firstboot-qubes-text"])
proc.wait()
for attr in self.qubes_data.bool_options:
setattr(self.qubes_data, attr, getattr(self, '_' + attr))
self.done = True
self.qubes_data.seen = True
def execute(self):
"""
@ -147,7 +193,7 @@ class QubesOsSpoke(FirstbootOnlySpokeMixIn, NormalTUISpoke):
"""
return self.done
return self.qubes_data.seen
@property
def status(self):
@ -179,28 +225,8 @@ class QubesOsSpoke(FirstbootOnlySpokeMixIn, NormalTUISpoke):
"""
if key:
# Do something with the user's input.
pass
# no other actions scheduled, apply changes
self.apply()
# close the current screen (remove it from the stack)
self.close()
return INPUT_PROCESSED
def prompt(self, args=None):
"""
The prompt method that is called by the main loop to get the prompt
for this screen.
:param args: optional argument that can be passed to App.switch_screen*
methods
:type args: anything
:return: text that should be used in the prompt for the input
:rtype: unicode|None
"""
if self._container.process_user_input(key):
self.apply()
return InputState.PROCESSED_AND_REDRAW
return _("Please press enter to start Qubes OS configuration.")
return super().input(args, key)

@ -1,5 +1,5 @@
Name: qubes-anaconda-addon
Version: 4.0.9
Version: 4.0.11
Release: 1%{?dist}
Summary: Anaconda addon useful for Qubes OS specific setup procedures
@ -25,16 +25,12 @@ at first boot time.
%install
rm -rf $RPM_BUILD_ROOT
install -d $RPM_BUILD_ROOT/%{_datadir}/qubes
install --mode 0755 firstboot-qubes-text $RPM_BUILD_ROOT/%{_datadir}/qubes/firstboot-qubes-text
install -d $RPM_BUILD_ROOT/%{_datadir}/anaconda/addons
cp -a org_qubes_os_initial_setup $RPM_BUILD_ROOT/%{_datadir}/anaconda/addons/
%files
%defattr(-,root,root,-)
%doc LICENSE README
%{_datadir}/qubes/firstboot-qubes-text
%dir %{_datadir}/anaconda/addons/org_qubes_os_initial_setup
%{_datadir}/anaconda/addons/org_qubes_os_initial_setup/*

@ -1398,24 +1398,31 @@
<packagereq type="mandatory">qubes-gui-dom0</packagereq>
<packagereq type="mandatory">qubes-desktop-linux-manager</packagereq>
<packagereq type="mandatory">qubes-mgmt-salt-dom0</packagereq>
<packagereq type="mandatory">qubes-template-fedora-29</packagereq>
<packagereq type="mandatory">qubes-template-fedora-30</packagereq>
<packagereq type="default">qubes-gpg-split-dom0</packagereq>
<packagereq type="default">qubes-img-converter-dom0</packagereq>
<packagereq type="default">qubes-input-proxy</packagereq>
<packagereq type="default">qubes-pdf-converter-dom0</packagereq>
<packagereq type="default">qubes-usb-proxy-dom0</packagereq>
<packagereq type="default">libvirt-client</packagereq>
<!--
We add 'kernel-latest' and 'kernel-latest-qubes-vm' only as
optional because it is not included in stable official releases
but only in testing releases with latest kernels
-->
<packagereq type="optional">kernel-latest</packagereq>
<packagereq type="optional">kernel-latest-qubes-vm</packagereq>
</packagelist>
</group>
<group>
<id>debian</id>
<name>Debian 9 (stretch) template</name>
<description>Debian 9 (stretch) template</description>
<name>Debian 10 (buster) template</name>
<description>Debian 10 (buster) template</description>
<default>true</default>
<uservisible>true</uservisible>
<packagelist>
<packagereq>qubes-template-debian-9</packagereq>
<packagereq>qubes-template-debian-10</packagereq>
</packagelist>
</group>
@ -1426,8 +1433,8 @@
<description>Whonix templates (gateway and workstation)</description>
<uservisible>true</uservisible>
<packagelist>
<packagereq>qubes-template-whonix-gw-14</packagereq>
<packagereq>qubes-template-whonix-ws-14</packagereq>
<packagereq>qubes-template-whonix-gw-15</packagereq>
<packagereq>qubes-template-whonix-ws-15</packagereq>
</packagelist>
</group>

@ -1,7 +1,7 @@
[qubes-dom0-current]
name = Qubes Dom0 Repository (updates)
#baseurl = https://yum.qubes-os.org/r$releasever/current/dom0/%DIST%
#baseurl = http://yum.sik5nlgfc5qylnnsr57qrbm64zbdx6t4lreyhpon3ychmxmiem7tioad.onion/r$releasever/current/dom0/%DIST%
#baseurl = http://yum.qubesosfasa4zl44o4tws22di6kepyzfeqv3tg4e3ztknltfxqrymdad.onion/r$releasever/current/dom0/%DIST%
metalink = https://yum.qubes-os.org/r$releasever/current/dom0/%DIST%/repodata/repomd.xml.metalink
enabled = 1
metadata_expire = 7d
@ -11,7 +11,7 @@ gpgkey = file:///etc/pki/rpm-gpg/RPM-GPG-KEY-qubes-$releasever-primary
[qubes-dom0-current-testing]
name = Qubes Dom0 Repository (updates-testing)
#baseurl = https://yum.qubes-os.org/r$releasever/current-testing/dom0/%DIST%
#baseurl = http://yum.sik5nlgfc5qylnnsr57qrbm64zbdx6t4lreyhpon3ychmxmiem7tioad.onion/r$releasever/current-testing/dom0/%DIST%
#baseurl = http://yum.qubesosfasa4zl44o4tws22di6kepyzfeqv3tg4e3ztknltfxqrymdad.onion/r$releasever/current-testing/dom0/%DIST%
metalink = https://yum.qubes-os.org/r$releasever/current-testing/dom0/%DIST%/repodata/repomd.xml.metalink
enabled = 0
metadata_expire = 7d
@ -21,7 +21,7 @@ gpgkey = file:///etc/pki/rpm-gpg/RPM-GPG-KEY-qubes-$releasever-primary
[qubes-dom0-security-testing]
name = Qubes Dom0 Repository (security-testing)
#baseurl = https://yum.qubes-os.org/r$releasever/security-testing/dom0/%DIST%
#baseurl = http://yum.sik5nlgfc5qylnnsr57qrbm64zbdx6t4lreyhpon3ychmxmiem7tioad.onion/r$releasever/security-testing/dom0/%DIST%
#baseurl = http://yum.qubesosfasa4zl44o4tws22di6kepyzfeqv3tg4e3ztknltfxqrymdad.onion/r$releasever/security-testing/dom0/%DIST%
metalink = https://yum.qubes-os.org/r$releasever/security-testing/dom0/%DIST%/repodata/repomd.xml.metalink
enabled = 0
metadata_expire = 7d
@ -31,7 +31,7 @@ gpgkey = file:///etc/pki/rpm-gpg/RPM-GPG-KEY-qubes-$releasever-primary
[qubes-dom0-unstable]
name = Qubes Dom0 Repository (unstable)
#baseurl = https://yum.qubes-os.org/r$releasever/unstable/dom0/%DIST%
#baseurl = http://yum.sik5nlgfc5qylnnsr57qrbm64zbdx6t4lreyhpon3ychmxmiem7tioad.onion/r$releasever/unstable/dom0/%DIST%
#baseurl = http://yum.qubesosfasa4zl44o4tws22di6kepyzfeqv3tg4e3ztknltfxqrymdad.onion/r$releasever/unstable/dom0/%DIST%
metalink = https://yum.qubes-os.org/r$releasever/unstable/dom0/%DIST%/repodata/repomd.xml.metalink
enabled = 0
metadata_expire = 7d

@ -5,7 +5,7 @@
Summary: Qubes release files
Name: qubes-release
Version: %{dist_version}
Release: 7
Release: 8
License: GPLv2
Group: System Environment/Base
Source0: %{name}-%{version}.tar.bz2

@ -1,7 +1,7 @@
[qubes-templates-itl]
name = Qubes Templates repository
#baseurl = https://yum.qubes-os.org/r$releasever/templates-itl
#baseurl = http://yum.sik5nlgfc5qylnnsr57qrbm64zbdx6t4lreyhpon3ychmxmiem7tioad.onion/r$releasever/templates-itl
#baseurl = http://yum.qubesosfasa4zl44o4tws22di6kepyzfeqv3tg4e3ztknltfxqrymdad.onion/r$releasever/templates-itl
metalink = https://yum.qubes-os.org/r$releasever/templates-itl/repodata/repomd.xml.metalink
enabled = 1
fastestmirror = 1
@ -12,7 +12,7 @@ gpgkey = file:///etc/pki/rpm-gpg/RPM-GPG-KEY-qubes-$releasever-primary
[qubes-templates-itl-testing]
name = Qubes Templates repository
#baseurl = https://yum.qubes-os.org/r$releasever/templates-itl-testing
#baseurl = http://yum.sik5nlgfc5qylnnsr57qrbm64zbdx6t4lreyhpon3ychmxmiem7tioad.onion/r$releasever/templates-itl-testing
#baseurl = http://yum.qubesosfasa4zl44o4tws22di6kepyzfeqv3tg4e3ztknltfxqrymdad.onion/r$releasever/templates-itl-testing
metalink = https://yum.qubes-os.org/r$releasever/templates-itl-testing/repodata/repomd.xml.metalink
enabled = 0
fastestmirror = 1
@ -22,7 +22,7 @@ gpgkey = file:///etc/pki/rpm-gpg/RPM-GPG-KEY-qubes-$releasever-primary
[qubes-templates-community]
name = Qubes Community Templates repository
#baseurl = https://yum.qubes-os.org/r$releasever/templates-community
#baseurl = http://yum.sik5nlgfc5qylnnsr57qrbm64zbdx6t4lreyhpon3ychmxmiem7tioad.onion/r$releasever/templates-community
#baseurl = http://yum.qubesosfasa4zl44o4tws22di6kepyzfeqv3tg4e3ztknltfxqrymdad.onion/r$releasever/templates-community
metalink = https://yum.qubes-os.org/r$releasever/templates-community/repodata/repomd.xml.metalink
enabled = 0
fastestmirror = 1
@ -33,7 +33,7 @@ gpgkey = file:///etc/pki/rpm-gpg/RPM-GPG-KEY-qubes-$releasever-templates-communi
[qubes-templates-community-testing]
name = Qubes Community Templates repository
#baseurl = https://yum.qubes-os.org/r$releasever/templates-community-testing
#baseurl = http://yum.sik5nlgfc5qylnnsr57qrbm64zbdx6t4lreyhpon3ychmxmiem7tioad.onion/r$releasever/templates-community-testing
#baseurl = http://yum.qubesosfasa4zl44o4tws22di6kepyzfeqv3tg4e3ztknltfxqrymdad.onion/r$releasever/templates-community-testing
metalink = https://yum.qubes-os.org/r$releasever/templates-community-testing/repodata/repomd.xml.metalink
enabled = 0
fastestmirror = 1

@ -1,8 +1,9 @@
createrepo="$(which createrepo_c createrepo | head -n 1)"
for repo in dom0-updates installer qubes-dom0 ; do
echo "---> Cleaning up repo: $repo..."
rm -f $repo/rpm/*.rpm
rm -f $repo/repodata/*
createrepo -q $repo
$createrepo -q $repo
done

Loading…
Cancel
Save