Merge branch 'calamares' of https://github.com/calamares/calamares into development
2
.github/workflows/nightly-opensuse.yml
vendored
@ -31,7 +31,7 @@ jobs:
|
||||
uses: calamares/actions/generic-checkout@v5
|
||||
- name: "install dependencies"
|
||||
shell: bash
|
||||
run: ./ci/deps-opensuse.sh
|
||||
run: ./ci/deps-opensuse-qt6.sh
|
||||
- name: "build"
|
||||
shell: bash
|
||||
run: ./ci/build.sh
|
||||
|
37
CHANGES-3.3
@ -7,6 +7,43 @@ contributors are listed. Note that Calamares does not have a historical
|
||||
changelog -- this log starts with version 3.3.0. See CHANGES-3.2 for
|
||||
the history of the 3.2 series (2018-05 - 2022-08).
|
||||
|
||||
# 3.3.7 (unreleased)
|
||||
|
||||
This release contains contributions from (alphabetically by first name):
|
||||
- Nobody, yet
|
||||
|
||||
## Core ##
|
||||
|
||||
## Modules ##
|
||||
|
||||
|
||||
# 3.3.6 (2024-04-16)
|
||||
|
||||
This release contains contributions from (alphabetically by first name):
|
||||
- Adriaan de Groot
|
||||
- Anke Boersma
|
||||
- Eugene Sam
|
||||
- Evan James
|
||||
- Harald Sitter
|
||||
- Mike Stemle
|
||||
- Peter Jung
|
||||
- Simon Quigley
|
||||
|
||||
## Core ##
|
||||
- Various Qt6-related fixes.
|
||||
- Calamares now prevents sleep and suspend while the installation is
|
||||
running, so that unattended installs do not accidentally fall asleep.
|
||||
|
||||
## Modules ##
|
||||
- *bootloader* Adds "splash" to kernel parameters if plymouth is present.
|
||||
(thanks Eugene)
|
||||
- *locale* Now picks the correct timezone for Dubai, Muscat, Tehran.
|
||||
- *plymouthcfg* Use plymouth-set-default-theme to avoid issues with
|
||||
configuration. (thanks Peter)
|
||||
- *users* module now supports enrolling in Active Directory, if enabled.
|
||||
(thanks Simon)
|
||||
|
||||
|
||||
# 3.3.5 (2024-03-03)
|
||||
|
||||
This release contains contributions from (alphabetically by first name):
|
||||
|
@ -47,8 +47,8 @@
|
||||
|
||||
cmake_minimum_required(VERSION 3.16 FATAL_ERROR)
|
||||
|
||||
set(CALAMARES_VERSION 3.3.5)
|
||||
set(CALAMARES_RELEASE_MODE ON) # Set to ON during a release
|
||||
set(CALAMARES_VERSION 3.3.7)
|
||||
set(CALAMARES_RELEASE_MODE OFF) # Set to ON during a release
|
||||
|
||||
if(CMAKE_SCRIPT_MODE_FILE)
|
||||
include(${CMAKE_CURRENT_LIST_DIR}/CMakeModules/ExtendedVersion.cmake)
|
||||
|
@ -154,10 +154,15 @@ dependencies for the image (in this example, for openSUSE and Qt6).
|
||||
- `./ci/deps-opensuse-qt6.sh`
|
||||
|
||||
Then run CMake (add any CMake options you like at the end) and ninja.
|
||||
There is a script `ci/build.sh` that does this, too (without options).
|
||||
- `cmake -S /src -B /build -G Ninja`
|
||||
- `ninja -C /build`
|
||||
|
||||
There is a script `ci/build.sh` that does the CMake an ninja steps.
|
||||
- If you set `CMAKE_ARGS` in the environment those extra CMake options are used.
|
||||
- If you add an argument to the script command which names a workflow
|
||||
(e.g. "nightly-opensuse-qt6") then `CMAKE_ARGS` are extracted from that
|
||||
workflow and used for the build.
|
||||
|
||||
### Running in Docker
|
||||
|
||||
To run Calamares inside the container, or e.g. `loadmodule` to test
|
||||
|
35
ci/build.sh
@ -5,6 +5,41 @@
|
||||
# - BUILDDIR (e.g. /build)
|
||||
# - CMAKE_ARGS (e.g. "-DWITH_QT6=ON -DCMAKE_BUILD_TYPE=Debug")
|
||||
#
|
||||
# If SRCDIR is not set, it is assumed to be the directory above
|
||||
# wherever this script is being run from (this script is in ci/).
|
||||
#
|
||||
# If BUILDDIR is not set, and /build exists (e.g. in the recommended
|
||||
# Docker setup) then /build is used.
|
||||
#
|
||||
# If CMAKE_ARGS is not set, but the script is given an argument
|
||||
# that exists as a workflow (e.g. "nightly-opensuse-qt6" or
|
||||
# "nightly-debian.yml") and yq is installed, then the CMAKE_ARGS
|
||||
# are extracted from that workflow file.
|
||||
#
|
||||
# Summary, pick one:
|
||||
# - set environment variables, run "build.sh"
|
||||
# - set no variables, run "build.sh <workflow-name>"
|
||||
|
||||
if test -z "$SRCDIR" ; then
|
||||
_d=$(dirname "$0" )
|
||||
_d=$(dirname "$_d" )
|
||||
test -f "$_d/CMakeLists.txt" && SRCDIR="$_d"
|
||||
fi
|
||||
if test -z "$BUILDDIR" ; then
|
||||
test -d "/build" && BUILDDIR=/build
|
||||
fi
|
||||
if test -z "$CMAKE_ARGS" -a -n "$1" ; then
|
||||
_d="$SRCDIR/.github/workflows/$1"
|
||||
test -f "$_d" || _d="$SRCDIR/.github/workflows/$1.yml"
|
||||
test -f "$_d" || { echo "! No workflow $1" ; exit 1 ; }
|
||||
|
||||
if test -x "$(which yq)" ; then
|
||||
CMAKE_ARGS=$(yq ".env.CMAKE_ARGS" "$_d")
|
||||
else
|
||||
CMAKE_ARGS=$(python3 -c 'import yaml ; f=open("'$_d'","r"); print(yaml.safe_load(f)["env"]["CMAKE_ARGS"]);')
|
||||
fi
|
||||
|
||||
fi
|
||||
|
||||
# Sanity check
|
||||
test -n "$BUILDDIR" || { echo "! \$BUILDDIR not set" ; exit 1 ; }
|
||||
|
@ -4,7 +4,7 @@
|
||||
#
|
||||
|
||||
yum install -y bison flex git make cmake gcc-c++ ninja-build
|
||||
yum install -y yaml-cpp-devel libpwquality-devel parted-devel python-devel gettext gettext-devel
|
||||
yum install -y yaml-cpp-devel libpwquality-devel parted-devel python-devel gettext gettext-devel python3-pyyaml
|
||||
yum install -y libicu-devel libatasmart-devel
|
||||
yum install -y boost-devel
|
||||
# Qt6/KF6 dependencies
|
||||
|
@ -4,7 +4,7 @@
|
||||
#
|
||||
|
||||
yum install -y bison flex git make cmake gcc-c++ ninja-build
|
||||
yum install -y yaml-cpp-devel libpwquality-devel parted-devel python-devel gettext gettext-devel
|
||||
yum install -y yaml-cpp-devel libpwquality-devel parted-devel python-devel gettext gettext-devel python3-pyyaml
|
||||
yum install -y libicu-devel libatasmart-devel
|
||||
# Qt6/KF6 dependencies
|
||||
yum install -y qt6-qtbase-devel qt6-linguist qt6-qtbase-private-devel qt6-qtdeclarative-devel qt6-qtsvg-devel qt6-qttools-devel
|
||||
|
@ -8,7 +8,7 @@ zypper --non-interactive addrepo -f -G https://download.opensuse.org/repositorie
|
||||
|
||||
zypper --non-interactive refresh
|
||||
zypper --non-interactive up
|
||||
zypper --non-interactive in git-core jq curl ninja
|
||||
zypper --non-interactive in git-core jq yq curl ninja
|
||||
# From deploycala.py
|
||||
zypper --non-interactive in bison flex git make cmake gcc-c++
|
||||
zypper --non-interactive in yaml-cpp-devel libpwquality-devel parted-devel python3-devel
|
||||
@ -18,5 +18,5 @@ zypper --non-interactive in kf6-extra-cmake-modules
|
||||
zypper --non-interactive in "qt6-declarative-devel" "cmake(Qt6Concurrent)" "cmake(Qt6Gui)" "cmake(Qt6Network)" "cmake(Qt6Svg)" "cmake(Qt6Linguist)"
|
||||
zypper --non-interactive in "cmake(KF6CoreAddons)" "cmake(KF6DBusAddons)" "cmake(KF6Crash)"
|
||||
zypper --non-interactive in "cmake(KF6Parts)" # Also installs KF5 things
|
||||
zypper --non-interactive in "cmake(PolkitQt6-1)"
|
||||
zypper --non-interactive in "cmake(PolkitQt6-1)" appstream-qt6-devel
|
||||
true
|
||||
|
@ -52,6 +52,7 @@
|
||||
#include <QLabel>
|
||||
#include <QMainWindow>
|
||||
#include <QThread>
|
||||
#include <QTimer>
|
||||
|
||||
#include <memory>
|
||||
|
||||
@ -455,11 +456,11 @@ libcalamares.utils.debug('pre-script for testing purposes injected')
|
||||
int
|
||||
main( int argc, char* argv[] )
|
||||
{
|
||||
QCoreApplication* aw = createApplication( argc, argv );
|
||||
QCoreApplication* application = createApplication( argc, argv );
|
||||
|
||||
Logger::setupLogLevel( Logger::LOGVERBOSE );
|
||||
|
||||
ModuleConfig module = handle_args( *aw );
|
||||
ModuleConfig module = handle_args( *application );
|
||||
if ( module.moduleName().isEmpty() )
|
||||
{
|
||||
return 1;
|
||||
@ -469,7 +470,7 @@ main( int argc, char* argv[] )
|
||||
std::unique_ptr< Calamares::JobQueue > jobqueue_p( new Calamares::JobQueue( nullptr ) );
|
||||
std::unique_ptr< Calamares::System > system_p( new Calamares::System( settings_p->doChroot() ) );
|
||||
|
||||
QMainWindow* mw = nullptr;
|
||||
QMainWindow* mainWindow = nullptr;
|
||||
|
||||
auto* gs = jobqueue_p->globalStorage();
|
||||
if ( !module.globalConfigFile().isEmpty() )
|
||||
@ -513,21 +514,21 @@ main( int argc, char* argv[] )
|
||||
// tries to create the widget **which won't be used anyway**.
|
||||
//
|
||||
// To avoid that crash, re-create the QApplication, now with GUI
|
||||
if ( !qobject_cast< QApplication* >( aw ) )
|
||||
if ( !qobject_cast< QApplication* >( application ) )
|
||||
{
|
||||
auto* replace_app = new QApplication( argc, argv );
|
||||
replace_app->setQuitOnLastWindowClosed( true );
|
||||
aw = replace_app;
|
||||
application = replace_app;
|
||||
}
|
||||
mw = module.m_ui ? new QMainWindow() : nullptr;
|
||||
if ( mw )
|
||||
mainWindow = module.m_ui ? new QMainWindow() : nullptr;
|
||||
if ( mainWindow )
|
||||
{
|
||||
mw->installEventFilter( Calamares::Retranslator::instance() );
|
||||
mainWindow->installEventFilter( Calamares::Retranslator::instance() );
|
||||
}
|
||||
|
||||
(void)new Calamares::Branding( module.m_branding );
|
||||
auto* modulemanager = new Calamares::ModuleManager( QStringList(), nullptr );
|
||||
(void)Calamares::ViewManager::instance( mw );
|
||||
(void)Calamares::ViewManager::instance( mainWindow );
|
||||
modulemanager->addModule( m );
|
||||
}
|
||||
|
||||
@ -542,16 +543,16 @@ main( int argc, char* argv[] )
|
||||
return 1;
|
||||
}
|
||||
|
||||
if ( mw )
|
||||
if ( mainWindow )
|
||||
{
|
||||
auto* vm = Calamares::ViewManager::instance();
|
||||
vm->onInitComplete();
|
||||
QWidget* w = vm->currentStep()->widget();
|
||||
w->setParent( mw );
|
||||
mw->setCentralWidget( w );
|
||||
w->setParent( mainWindow );
|
||||
mainWindow->setCentralWidget( w );
|
||||
w->show();
|
||||
mw->show();
|
||||
return aw->exec();
|
||||
mainWindow->show();
|
||||
return application->exec();
|
||||
}
|
||||
|
||||
using TR = Logger::DebugRow< const char*, const QString >;
|
||||
@ -559,30 +560,10 @@ main( int argc, char* argv[] )
|
||||
cDebug() << Logger::SubEntry << "Module metadata" << TR( "name", m->name() ) << TR( "type", m->typeString() )
|
||||
<< TR( "interface", m->interfaceString() );
|
||||
|
||||
Calamares::JobList jobList = m->jobs();
|
||||
unsigned int failure_count = 0;
|
||||
unsigned int count = 1;
|
||||
for ( const auto& p : jobList )
|
||||
{
|
||||
// This doesn't get a SubEntry because the jobs may log a bunch of
|
||||
// things; print the function-header to make clear that we're back in main.
|
||||
cDebug() << "Job #" << count << "name" << p->prettyName();
|
||||
Calamares::JobResult r = p->exec();
|
||||
if ( !r )
|
||||
{
|
||||
cError() << "Job #" << count << "failed" << TR( "summary", r.message() ) << TR( "details", r.details() );
|
||||
if ( r.errorCode() > 0 )
|
||||
{
|
||||
++failure_count;
|
||||
}
|
||||
}
|
||||
++count;
|
||||
}
|
||||
Calamares::JobQueue::instance()->enqueue(100, m->jobs());
|
||||
|
||||
if ( aw )
|
||||
{
|
||||
delete aw;
|
||||
}
|
||||
QObject::connect(Calamares::JobQueue::instance(), &Calamares::JobQueue::finished, [application]() { QTimer::singleShot(std::chrono::seconds(3), application, &QApplication::quit); });
|
||||
QTimer::singleShot(0, []() { Calamares::JobQueue::instance()->start(); });
|
||||
|
||||
return failure_count ? 1 : 0;
|
||||
return application->exec();
|
||||
}
|
||||
|
@ -109,12 +109,23 @@ public:
|
||||
* which of the jobs is "heavy" and which is not.
|
||||
*/
|
||||
virtual int getJobWeight() const;
|
||||
|
||||
/** @brief The human-readable name of this job
|
||||
*
|
||||
* This should be a very short statement of what the job does.
|
||||
* For status and state information, see prettyStatusMessage().
|
||||
*
|
||||
* The job's name may be similar to the status message, but this is
|
||||
* a name, and should not be an active verb phrase. The translation
|
||||
* should use context @c \@label .
|
||||
*
|
||||
* The name of the job is used as a **fallback** when the status
|
||||
* or descriptions are empty. If a job has no implementation of
|
||||
* those methods, it is OK to use other contexts, but it may look
|
||||
* strange in some places in the UI.
|
||||
*/
|
||||
virtual QString prettyName() const = 0;
|
||||
|
||||
/** @brief a longer human-readable description of what the job will do
|
||||
*
|
||||
* This **may** be used by view steps to fill in the summary
|
||||
@ -122,15 +133,23 @@ public:
|
||||
* module does so.
|
||||
*
|
||||
* The default implementation returns an empty string.
|
||||
*
|
||||
* The translation should use context @c \@title .
|
||||
*/
|
||||
virtual QString prettyDescription() const;
|
||||
|
||||
/** @brief A human-readable status for progress reporting
|
||||
*
|
||||
* This is called from the JobQueue when progress is made, and should
|
||||
* return a not-too-long description of the job's status. This
|
||||
* is made visible in the progress bar of the execution view step.
|
||||
*
|
||||
* The job's status should say **what** the job is doing. It should be in
|
||||
* present active tense. Typically the translation uses tr() context
|
||||
* @c \@status . See prettyName() for examples.
|
||||
*/
|
||||
virtual QString prettyStatusMessage() const;
|
||||
|
||||
virtual JobResult exec() = 0;
|
||||
|
||||
bool isEmergency() const { return m_emergency; }
|
||||
|
@ -16,13 +16,174 @@
|
||||
#include "compat/Mutex.h"
|
||||
#include "utils/Logger.h"
|
||||
|
||||
#include <QApplication>
|
||||
#include <QDBusConnection>
|
||||
#include <QDBusMessage>
|
||||
#include <QDBusPendingCall>
|
||||
#include <QDBusPendingReply>
|
||||
#include <QMutex>
|
||||
#include <QThread>
|
||||
|
||||
#include <memory>
|
||||
|
||||
namespace
|
||||
{
|
||||
// This power-management code is largely cribbed from KDE Discover,
|
||||
// https://invent.kde.org/plasma/discover/-/blob/master/discover/PowerManagementInterface.cpp
|
||||
//
|
||||
// Upstream license text says:
|
||||
//
|
||||
// SPDX-FileCopyrightText: 2019 (c) Matthieu Gallien <matthieu_gallien@yahoo.fr>
|
||||
// SPDX-License-Identifier: LGPL-3.0-or-later
|
||||
|
||||
|
||||
/** @brief Class to manage sleep / suspend on inactivity
|
||||
*
|
||||
* Create an object of this class on the heap. Call inhibitSleep()
|
||||
* to (try to) stop system sleep / suspend. Call uninhibitSleep()
|
||||
* when the object is no longer needed. The object self-deletes
|
||||
* after uninhibitSleep() completes.
|
||||
*/
|
||||
class PowerManagementInterface : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
PowerManagementInterface( QObject* parent = nullptr );
|
||||
~PowerManagementInterface() override;
|
||||
|
||||
public Q_SLOTS:
|
||||
void inhibitSleep();
|
||||
void uninhibitSleep();
|
||||
|
||||
private Q_SLOTS:
|
||||
void hostSleepInhibitChanged();
|
||||
void inhibitDBusCallFinished( QDBusPendingCallWatcher* aWatcher );
|
||||
void uninhibitDBusCallFinished( QDBusPendingCallWatcher* aWatcher );
|
||||
|
||||
private:
|
||||
uint m_inhibitSleepCookie = 0;
|
||||
bool m_inhibitedSleep = false;
|
||||
};
|
||||
|
||||
PowerManagementInterface::PowerManagementInterface( QObject* parent )
|
||||
: QObject( parent )
|
||||
{
|
||||
auto sessionBus = QDBusConnection::sessionBus();
|
||||
|
||||
sessionBus.connect( QStringLiteral( "org.freedesktop.PowerManagement.Inhibit" ),
|
||||
QStringLiteral( "/org/freedesktop/PowerManagement/Inhibit" ),
|
||||
QStringLiteral( "org.freedesktop.PowerManagement.Inhibit" ),
|
||||
QStringLiteral( "HasInhibitChanged" ),
|
||||
this,
|
||||
SLOT( hostSleepInhibitChanged() ) );
|
||||
}
|
||||
|
||||
PowerManagementInterface::~PowerManagementInterface() = default;
|
||||
|
||||
void
|
||||
PowerManagementInterface::hostSleepInhibitChanged()
|
||||
{
|
||||
// We don't actually care
|
||||
}
|
||||
|
||||
void
|
||||
PowerManagementInterface::inhibitDBusCallFinished( QDBusPendingCallWatcher* aWatcher )
|
||||
{
|
||||
QDBusPendingReply< uint > reply = *aWatcher;
|
||||
if ( reply.isError() )
|
||||
{
|
||||
cError() << "Could not inhibit sleep:" << reply.error();
|
||||
// m_inhibitedSleep = false; // unchanged
|
||||
}
|
||||
else
|
||||
{
|
||||
m_inhibitSleepCookie = reply.argumentAt< 0 >();
|
||||
m_inhibitedSleep = true;
|
||||
cDebug() << "Sleep inhibited, cookie" << m_inhibitSleepCookie;
|
||||
}
|
||||
aWatcher->deleteLater();
|
||||
}
|
||||
|
||||
void
|
||||
PowerManagementInterface::uninhibitDBusCallFinished( QDBusPendingCallWatcher* aWatcher )
|
||||
{
|
||||
QDBusPendingReply<> reply = *aWatcher;
|
||||
if ( reply.isError() )
|
||||
{
|
||||
cError() << "Could not uninhibit sleep:" << reply.error();
|
||||
}
|
||||
else
|
||||
{
|
||||
m_inhibitedSleep = false;
|
||||
m_inhibitSleepCookie = 0;
|
||||
cDebug() << "Sleep uninhibited.";
|
||||
}
|
||||
aWatcher->deleteLater();
|
||||
this->deleteLater();
|
||||
}
|
||||
|
||||
void
|
||||
PowerManagementInterface::inhibitSleep()
|
||||
{
|
||||
if ( m_inhibitedSleep )
|
||||
{
|
||||
cDebug() << "Sleep is already inhibited.";
|
||||
return;
|
||||
}
|
||||
|
||||
auto sessionBus = QDBusConnection::sessionBus();
|
||||
auto inhibitCall = QDBusMessage::createMethodCall( QStringLiteral( "org.freedesktop.PowerManagement.Inhibit" ),
|
||||
QStringLiteral( "/org/freedesktop/PowerManagement/Inhibit" ),
|
||||
QStringLiteral( "org.freedesktop.PowerManagement.Inhibit" ),
|
||||
QStringLiteral( "Inhibit" ) );
|
||||
inhibitCall.setArguments(
|
||||
{ { tr( "Calamares" ) }, { tr( "Installation in progress", "@status" ) } } );
|
||||
|
||||
auto asyncReply = sessionBus.asyncCall( inhibitCall );
|
||||
auto* replyWatcher = new QDBusPendingCallWatcher( asyncReply, this );
|
||||
QObject::connect(
|
||||
replyWatcher, &QDBusPendingCallWatcher::finished, this, &PowerManagementInterface::inhibitDBusCallFinished );
|
||||
}
|
||||
|
||||
void
|
||||
PowerManagementInterface::uninhibitSleep()
|
||||
{
|
||||
if ( !m_inhibitedSleep )
|
||||
{
|
||||
cDebug() << "Sleep was never inhibited.";
|
||||
this->deleteLater();
|
||||
return;
|
||||
}
|
||||
|
||||
auto sessionBus = QDBusConnection::sessionBus();
|
||||
auto uninhibitCall = QDBusMessage::createMethodCall( QStringLiteral( "org.freedesktop.PowerManagement.Inhibit" ),
|
||||
QStringLiteral( "/org/freedesktop/PowerManagement/Inhibit" ),
|
||||
QStringLiteral( "org.freedesktop.PowerManagement.Inhibit" ),
|
||||
QStringLiteral( "UnInhibit" ) );
|
||||
uninhibitCall.setArguments( { { m_inhibitSleepCookie } } );
|
||||
|
||||
auto asyncReply = sessionBus.asyncCall( uninhibitCall );
|
||||
auto replyWatcher = new QDBusPendingCallWatcher( asyncReply, this );
|
||||
QObject::connect(
|
||||
replyWatcher, &QDBusPendingCallWatcher::finished, this, &PowerManagementInterface::uninhibitDBusCallFinished );
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
namespace Calamares
|
||||
{
|
||||
SleepInhibitor::SleepInhibitor()
|
||||
{
|
||||
// Create a PowerManagementInterface object with intentionally no parent
|
||||
// so it is not destroyed along with this. Instead, when this
|
||||
// is destroyed, **start** the uninhibit-sleep call which will (later)
|
||||
// destroy the PowerManagementInterface object.
|
||||
auto* p = new PowerManagementInterface( nullptr );
|
||||
p->inhibitSleep();
|
||||
connect( this, &QObject::destroyed, p, &PowerManagementInterface::uninhibitSleep );
|
||||
}
|
||||
|
||||
SleepInhibitor::~SleepInhibitor() = default;
|
||||
|
||||
struct WeightedJob
|
||||
{
|
||||
@ -188,6 +349,13 @@ private:
|
||||
// starts the job, or if the job itself reports 0.0) be more
|
||||
// accepting in what gets reported: jobs with no status fall
|
||||
// back to description and name, whichever is non-empty.
|
||||
//
|
||||
// Later calls (e.g. when percentage > 0) use the status unchanged.
|
||||
// It may be empty, but the ExecutionViewStep knows about empty
|
||||
// status messages and does not update the text in that case.
|
||||
//
|
||||
// This means that a Job can implement just prettyName() and get
|
||||
// a reasonable "status" message which will update only once.
|
||||
if ( percentage == 0.0 && message.isEmpty() )
|
||||
{
|
||||
message = jobitem.job->prettyDescription();
|
||||
@ -267,6 +435,10 @@ JobQueue::start()
|
||||
m_thread->finalize();
|
||||
m_finished = false;
|
||||
m_thread->start();
|
||||
|
||||
auto* inhibitor = new PowerManagementInterface( this );
|
||||
inhibitor->inhibitSleep();
|
||||
connect( this, &JobQueue::finished, inhibitor, &PowerManagementInterface::uninhibitSleep );
|
||||
}
|
||||
|
||||
|
||||
|
@ -20,6 +20,15 @@ namespace Calamares
|
||||
class GlobalStorage;
|
||||
class JobThread;
|
||||
|
||||
///@brief RAII class to suppress sleep / suspend during its lifetime
|
||||
class DLLEXPORT SleepInhibitor : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
SleepInhibitor();
|
||||
~SleepInhibitor() override;
|
||||
};
|
||||
|
||||
class DLLEXPORT JobQueue : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
|
@ -25,4 +25,8 @@
|
||||
#pragma clang diagnostic ignored "-Wextra-semi-stmt"
|
||||
#pragma clang diagnostic ignored "-Wredundant-parens"
|
||||
#pragma clang diagnostic ignored "-Wreserved-identifier"
|
||||
|
||||
#if __clang_major__ >= 17
|
||||
#pragma clang diagnostic ignored "-Wunsafe-buffer-usage"
|
||||
#endif
|
||||
#endif
|
||||
|
@ -125,23 +125,28 @@ def is_zfs_root(partition):
|
||||
return partition["mountPoint"] == "/" and partition["fs"] == "zfs"
|
||||
|
||||
|
||||
def have_program_in_target(program : str):
|
||||
"""Returns @c True if @p program is in path in the target"""
|
||||
return libcalamares.utils.target_env_call(["/usr/bin/which", program]) == 0
|
||||
|
||||
|
||||
def get_kernel_params(uuid):
|
||||
# Configured kernel parameters (default "quiet"), if plymouth installed, add splash
|
||||
# screen parameter and then "rw".
|
||||
kernel_params = libcalamares.job.configuration.get("kernelParams", ["quiet"])
|
||||
if have_program_in_target("plymouth"):
|
||||
kernel_params.append("splash")
|
||||
kernel_params.append("rw")
|
||||
|
||||
use_systemd_naming = have_program_in_target("dracut") or (libcalamares.utils.target_env_call(["/usr/bin/grep", "-q", "^HOOKS.*systemd", "/etc/mkinitcpio.conf"]) == 0)
|
||||
|
||||
partitions = libcalamares.globalstorage.value("partitions")
|
||||
|
||||
cryptdevice_params = []
|
||||
swap_uuid = ""
|
||||
swap_outer_mappername = None
|
||||
swap_outer_uuid = None
|
||||
|
||||
cryptdevice_params = []
|
||||
|
||||
has_dracut = libcalamares.utils.target_env_call(["sh", "-c", "which dracut"]) == 0
|
||||
uses_systemd_hook = libcalamares.utils.target_env_call(["sh", "-c",
|
||||
"grep -q \"^HOOKS.*systemd\" /etc/mkinitcpio.conf"]) == 0
|
||||
use_systemd_naming = has_dracut or uses_systemd_hook
|
||||
|
||||
|
||||
# Take over swap settings:
|
||||
# - unencrypted swap partition sets swap_uuid
|
||||
# - encrypted root sets cryptdevice_params
|
||||
|
@ -100,7 +100,7 @@ hostCPU_FreeBSD()
|
||||
|
||||
#if defined( Q_OS_LINUX )
|
||||
static QString
|
||||
hostCPUmatchARM( const QString& s )
|
||||
hostCPUmatchARM( const QString& )
|
||||
{
|
||||
/* The "CPU implementer" line is for ARM CPUs in general.
|
||||
*
|
||||
|
Before Width: | Height: | Size: 23 KiB After Width: | Height: | Size: 21 KiB |
Before Width: | Height: | Size: 3.2 KiB After Width: | Height: | Size: 3.3 KiB |
Before Width: | Height: | Size: 4.9 KiB After Width: | Height: | Size: 5.0 KiB |
Before Width: | Height: | Size: 15 KiB After Width: | Height: | Size: 15 KiB |
@ -1,6 +1,6 @@
|
||||
/* === This file is part of Calamares - <https://calamares.io> ===
|
||||
*
|
||||
* SPDX-FileCopyrightText: 2020 - 2022 Anke Boersma <demm@kaosx.us>
|
||||
* SPDX-FileCopyrightText: 2020 - 2024 Anke Boersma <demm@kaosx.us>
|
||||
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||
*
|
||||
* Calamares is Free Software: see the License-Identifier above.
|
||||
@ -112,7 +112,7 @@ Column {
|
||||
|
||||
Plugin {
|
||||
id: mapPlugin
|
||||
preferred: ["osm", "esri"] // "esri", "here", "itemsoverlay", "mapbox", "mapboxgl", "osm"
|
||||
name: ["osm"]
|
||||
}
|
||||
|
||||
Map {
|
||||
@ -177,6 +177,30 @@ Column {
|
||||
getTzOffline();
|
||||
}
|
||||
}
|
||||
|
||||
WheelHandler {
|
||||
id: wheel
|
||||
acceptedDevices: Qt.platform.pluginName === "cocoa" || Qt.platform.pluginName === "wayland"
|
||||
? PointerDevice.Mouse | PointerDevice.TouchPad
|
||||
: PointerDevice.Mouse
|
||||
rotationScale: 1/120
|
||||
property: "zoomLevel"
|
||||
}
|
||||
DragHandler {
|
||||
id: drag
|
||||
target: null
|
||||
onTranslationChanged: (delta) => map.pan(-delta.x, -delta.y)
|
||||
}
|
||||
Shortcut {
|
||||
enabled: map.zoomLevel < map.maximumZoomLevel
|
||||
sequence: StandardKey.ZoomIn
|
||||
onActivated: map.zoomLevel = Math.round(map.zoomLevel + 1)
|
||||
}
|
||||
Shortcut {
|
||||
enabled: map.zoomLevel > map.minimumZoomLevel
|
||||
sequence: StandardKey.ZoomOut
|
||||
onActivated: map.zoomLevel = Math.round(map.zoomLevel - 1)
|
||||
}
|
||||
}
|
||||
|
||||
Column {
|
||||
|
@ -223,7 +223,7 @@ PartitionViewStep::prettyStatus() const
|
||||
const QList< PartitionCoreModule::SummaryInfo > list = m_core->createSummaryInfo();
|
||||
|
||||
cDebug() << "Summary for Partition" << list.length() << choice;
|
||||
auto joinDiskInfo = [ choice = choice ]( QString& s, const PartitionCoreModule::SummaryInfo& i )
|
||||
auto joinDiskInfo = [ choice ]( QString& s, const PartitionCoreModule::SummaryInfo& i )
|
||||
{ return s + diskDescription( 1, i, choice ); };
|
||||
const QString diskInfoLabel = std::accumulate( list.begin(), list.end(), QString(), joinDiskInfo );
|
||||
const QString jobsLabel = jobDescriptions( jobs() ).join( QStringLiteral( "<br/>" ) );
|
||||
@ -497,11 +497,12 @@ shouldWarnForNotEncryptedBoot( const Config* config, const PartitionCoreModule*
|
||||
Partition* root_p = core->findPartitionByMountPoint( "/" );
|
||||
Partition* boot_p = core->findPartitionByMountPoint( "/boot" );
|
||||
|
||||
if ( root_p and boot_p )
|
||||
if ( root_p && boot_p )
|
||||
{
|
||||
if ( ( root_p->fileSystem().type() == FileSystem::Luks && boot_p->fileSystem().type() != FileSystem::Luks )
|
||||
|| ( root_p->fileSystem().type() == FileSystem::Luks2
|
||||
&& boot_p->fileSystem().type() != FileSystem::Luks2 ) )
|
||||
const auto encryptionMismatch
|
||||
= [ root_t = root_p->fileSystem().type(), boot_t = boot_p->fileSystem().type() ]( FileSystem::Type t )
|
||||
{ return root_t == t && boot_t != t; };
|
||||
if ( encryptionMismatch( FileSystem::Luks ) || encryptionMismatch( FileSystem::Luks2 ) )
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
@ -581,12 +581,7 @@ efiFilesystemMinimumSize()
|
||||
uefisys_part_sizeB = v > 0 ? v : 0;
|
||||
}
|
||||
// There is a lower limit of what can be configured
|
||||
if ( uefisys_part_sizeB < efiSpecificationHardMinimumSize )
|
||||
{
|
||||
uefisys_part_sizeB = efiSpecificationHardMinimumSize;
|
||||
}
|
||||
return uefisys_part_sizeB;
|
||||
return efiSpecificationHardMinimumSize;
|
||||
return std::max( uefisys_part_sizeB, efiSpecificationHardMinimumSize );
|
||||
}
|
||||
|
||||
QString
|
||||
|
@ -248,9 +248,9 @@ defaultFileSystemType: "ext4"
|
||||
# for root that uses 100% of the space and uses the filesystem defined by
|
||||
# defaultFileSystemType.
|
||||
#
|
||||
# Note: the EFI system partition is prepend automatically to the layout if
|
||||
# needed; the swap partition is appended to the layout if enabled (small of
|
||||
# suspend).
|
||||
# Note: the EFI system partition is prepended automatically to the layout if
|
||||
# needed; the swap partition is appended to the layout if enabled (selections
|
||||
# "small" or "suspend" in *userSwapChoices*).
|
||||
#
|
||||
# Otherwise, the partition layout is defined as follow:
|
||||
#
|
||||
|
@ -48,9 +48,7 @@ class PlymouthController:
|
||||
|
||||
def setTheme(self):
|
||||
plymouth_theme = libcalamares.job.configuration["plymouth_theme"]
|
||||
target_env_call(["sed", "-e", 's|^.*Theme=.*|Theme=' +
|
||||
plymouth_theme + '|', "-i",
|
||||
"/etc/plymouth/plymouthd.conf"])
|
||||
target_env_call(["plymouth-set-default-theme", plymouth_theme])
|
||||
|
||||
def run(self):
|
||||
if detect_plymouth():
|
||||
|
85
src/modules/users/ActiveDirectoryJob.cpp
Normal file
@ -0,0 +1,85 @@
|
||||
/* === This file is part of Calamares - <https://calamares.io> ===
|
||||
*
|
||||
* SPDX-FileCopyrightText: 2024 Simon Quigley <tsimonq2@ubuntu.com>
|
||||
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||
*/
|
||||
|
||||
#include "ActiveDirectoryJob.h"
|
||||
|
||||
#include "Config.h"
|
||||
|
||||
#include "GlobalStorage.h"
|
||||
#include "JobQueue.h"
|
||||
#include "utils/Logger.h"
|
||||
#include "utils/Permissions.h"
|
||||
#include "utils/System.h"
|
||||
|
||||
#include <QDateTime>
|
||||
#include <QDir>
|
||||
#include <QFile>
|
||||
#include <QFileInfo>
|
||||
#include <QProcess>
|
||||
#include <QTextStream>
|
||||
|
||||
ActiveDirectoryJob::ActiveDirectoryJob( const QString& adminLogin,
|
||||
const QString& adminPassword,
|
||||
const QString& domain,
|
||||
const QString& ip )
|
||||
: Calamares::Job()
|
||||
, m_adminLogin( adminLogin )
|
||||
, m_adminPassword( adminPassword )
|
||||
, m_domain( domain )
|
||||
, m_ip( ip )
|
||||
{
|
||||
}
|
||||
|
||||
QString
|
||||
ActiveDirectoryJob::prettyName() const
|
||||
{
|
||||
return tr( "Enroll system in Active Directory", "@label" );
|
||||
}
|
||||
|
||||
QString
|
||||
ActiveDirectoryJob::prettyStatusMessage() const
|
||||
{
|
||||
return tr( "Enrolling system in Active Directory…", "@status" );
|
||||
}
|
||||
|
||||
Calamares::JobResult
|
||||
ActiveDirectoryJob::exec()
|
||||
{
|
||||
if ( !m_ip.isEmpty() )
|
||||
{
|
||||
const QString hostsFilePath = Calamares::System::instance()->targetPath( QStringLiteral( "/etc/hosts" ) );
|
||||
;
|
||||
QFile hostsFile( hostsFilePath );
|
||||
if ( hostsFile.open( QIODevice::Append | QIODevice::Text ) )
|
||||
{
|
||||
QTextStream out( &hostsFile );
|
||||
out << m_ip << " " << m_domain << "\n";
|
||||
hostsFile.close();
|
||||
}
|
||||
else
|
||||
{
|
||||
return Calamares::JobResult::error( "Failed to open /etc/hosts for writing." );
|
||||
}
|
||||
}
|
||||
|
||||
const QString installPath = Calamares::System::instance()->targetPath( QStringLiteral( "/" ) );
|
||||
auto r = Calamares::System::instance()->runCommand(
|
||||
Calamares::System::RunLocation::RunInHost,
|
||||
{ "realm", "join", m_domain, "-U", m_adminLogin, "--install=" + installPath, "--verbose" },
|
||||
QString(),
|
||||
m_adminPassword,
|
||||
std::chrono::seconds( 30 ) );
|
||||
|
||||
|
||||
if ( r.getExitCode() == 0 )
|
||||
{
|
||||
return Calamares::JobResult::ok();
|
||||
}
|
||||
else
|
||||
{
|
||||
return Calamares::JobResult::error( QString( "Failed to join realm: %1" ).arg( r.getOutput() ) );
|
||||
}
|
||||
}
|
34
src/modules/users/ActiveDirectoryJob.h
Normal file
@ -0,0 +1,34 @@
|
||||
/* === This file is part of Calamares - <https://calamares.io> ===
|
||||
*
|
||||
* SPDX-FileCopyrightText: 2024 Simon Quigley <tsimonq2@ubuntu.com>
|
||||
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||
*
|
||||
* Calamares is Free Software: see the License-Identifier above.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef ACTIVEDIRECTORYJOB_H
|
||||
#define ACTIVEDIRECTORYJOB_H
|
||||
|
||||
#include "Job.h"
|
||||
|
||||
class ActiveDirectoryJob : public Calamares::Job
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
ActiveDirectoryJob( const QString& adminLogin,
|
||||
const QString& adminPassword,
|
||||
const QString& domain,
|
||||
const QString& ip );
|
||||
QString prettyName() const override;
|
||||
QString prettyStatusMessage() const override;
|
||||
Calamares::JobResult exec() override;
|
||||
|
||||
private:
|
||||
QString m_adminLogin; // Admin credentials to do the enrollment
|
||||
QString m_adminPassword;
|
||||
QString m_domain;
|
||||
QString m_ip;
|
||||
};
|
||||
|
||||
#endif /* ACTIVEDIRECTORYJOB_H */
|
@ -55,6 +55,7 @@ include_directories(${PROJECT_BINARY_DIR}/src/libcalamaresui)
|
||||
|
||||
set(_users_src
|
||||
# Jobs
|
||||
ActiveDirectoryJob.cpp
|
||||
CreateUserJob.cpp
|
||||
MiscJobs.cpp
|
||||
SetPasswordJob.cpp
|
||||
|
@ -9,6 +9,7 @@
|
||||
|
||||
#include "Config.h"
|
||||
|
||||
#include "ActiveDirectoryJob.h"
|
||||
#include "CreateUserJob.h"
|
||||
#include "MiscJobs.h"
|
||||
#include "SetHostNameJob.h"
|
||||
@ -444,8 +445,6 @@ makeHostnameSuggestion( const QString& templateString, const QStringList& fullNa
|
||||
|
||||
QString hostnameSuggestion = d.expand( templateString );
|
||||
|
||||
// RegExp for valid hostnames; if the suggestion produces a valid name, return it
|
||||
static const QRegularExpression HOSTNAME_RX( "^[a-zA-Z0-9][-a-zA-Z0-9_]*$" );
|
||||
return hostnameSuggestion.indexOf( HOSTNAME_RX ) != -1 ? hostnameSuggestion : QString();
|
||||
}
|
||||
|
||||
@ -656,6 +655,48 @@ Config::setRootPasswordSecondary( const QString& s )
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
Config::setActiveDirectoryUsed( bool used )
|
||||
{
|
||||
m_activeDirectoryUsed = used;
|
||||
}
|
||||
|
||||
bool
|
||||
Config::getActiveDirectoryEnabled() const
|
||||
{
|
||||
return m_activeDirectory;
|
||||
}
|
||||
|
||||
bool
|
||||
Config::getActiveDirectoryUsed() const
|
||||
{
|
||||
return m_activeDirectoryUsed && m_activeDirectory;
|
||||
}
|
||||
|
||||
void
|
||||
Config::setActiveDirectoryAdminUsername( const QString& s )
|
||||
{
|
||||
m_activeDirectoryAdminUsername = s;
|
||||
}
|
||||
|
||||
void
|
||||
Config::setActiveDirectoryAdminPassword( const QString& s )
|
||||
{
|
||||
m_activeDirectoryAdminPassword = s;
|
||||
}
|
||||
|
||||
void
|
||||
Config::setActiveDirectoryDomain( const QString& s )
|
||||
{
|
||||
m_activeDirectoryDomain = s;
|
||||
}
|
||||
|
||||
void
|
||||
Config::setActiveDirectoryIP( const QString& s )
|
||||
{
|
||||
m_activeDirectoryIP = s;
|
||||
}
|
||||
|
||||
QString
|
||||
Config::rootPassword() const
|
||||
{
|
||||
@ -913,6 +954,9 @@ Config::setConfigurationMap( const QVariantMap& configurationMap )
|
||||
m_sudoStyle = Calamares::getBool( configurationMap, "sudoersConfigureWithGroup", false ) ? SudoStyle::UserAndGroup
|
||||
: SudoStyle::UserOnly;
|
||||
|
||||
// Handle Active Directory enablement
|
||||
m_activeDirectory = Calamares::getBool( configurationMap, "allowActiveDirectory", false );
|
||||
|
||||
// Handle *hostname* key and subkeys and legacy settings
|
||||
{
|
||||
bool ok = false; // Ignored
|
||||
@ -990,6 +1034,15 @@ Config::createJobs() const
|
||||
jobs.append( Calamares::job_ptr( j ) );
|
||||
}
|
||||
|
||||
if ( getActiveDirectoryUsed() )
|
||||
{
|
||||
j = new ActiveDirectoryJob( m_activeDirectoryAdminUsername,
|
||||
m_activeDirectoryAdminPassword,
|
||||
m_activeDirectoryDomain,
|
||||
m_activeDirectoryIP );
|
||||
jobs.append( Calamares::job_ptr( j ) );
|
||||
}
|
||||
|
||||
j = new SetupGroupsJob( this );
|
||||
jobs.append( Calamares::job_ptr( j ) );
|
||||
|
||||
|
@ -226,6 +226,10 @@ public:
|
||||
bool permitWeakPasswords() const { return m_permitWeakPasswords; }
|
||||
/// Current setting for "require strong password"?
|
||||
bool requireStrongPasswords() const { return m_requireStrongPasswords; }
|
||||
/// Is Active Directory enabled in the config file?
|
||||
bool getActiveDirectoryEnabled() const;
|
||||
/// Is it both enabled and activated by user choice (checkbox)?
|
||||
bool getActiveDirectoryUsed() const;
|
||||
|
||||
const QList< GroupDescription >& defaultGroups() const { return m_defaultGroups; }
|
||||
/** @brief the names of all the groups for the current user
|
||||
@ -292,6 +296,12 @@ public Q_SLOTS:
|
||||
void setRootPassword( const QString& );
|
||||
void setRootPasswordSecondary( const QString& );
|
||||
|
||||
void setActiveDirectoryUsed( bool used );
|
||||
void setActiveDirectoryAdminUsername( const QString& );
|
||||
void setActiveDirectoryAdminPassword( const QString& );
|
||||
void setActiveDirectoryDomain( const QString& );
|
||||
void setActiveDirectoryIP( const QString& );
|
||||
|
||||
signals:
|
||||
void userShellChanged( const QString& );
|
||||
void autoLoginGroupChanged( const QString& );
|
||||
@ -343,6 +353,13 @@ private:
|
||||
|
||||
bool m_isReady = false; ///< Used to reduce readyChanged signals
|
||||
|
||||
bool m_activeDirectory = false;
|
||||
bool m_activeDirectoryUsed = false;
|
||||
QString m_activeDirectoryAdminUsername;
|
||||
QString m_activeDirectoryAdminPassword;
|
||||
QString m_activeDirectoryDomain;
|
||||
QString m_activeDirectoryIP;
|
||||
|
||||
HostNameAction m_hostnameAction = HostNameAction::EtcHostname;
|
||||
bool m_writeEtcHosts = false;
|
||||
QString m_hostnameTemplate;
|
||||
|
@ -162,6 +162,16 @@ UsersPage::UsersPage( Config* config, QWidget* parent )
|
||||
config, &Config::requireStrongPasswordsChanged, ui->checkBoxRequireStrongPassword, &QCheckBox::setChecked );
|
||||
}
|
||||
|
||||
// Active Directory is not checked or enabled by default
|
||||
ui->useADCheckbox->setVisible( m_config->getActiveDirectoryEnabled() );
|
||||
onActiveDirectoryToggled( false );
|
||||
|
||||
connect( ui->useADCheckbox, &QCheckBox::toggled, this, &UsersPage::onActiveDirectoryToggled );
|
||||
connect( ui->domainField, &QLineEdit::textChanged, config, &Config::setActiveDirectoryDomain );
|
||||
connect( ui->domainAdminField, &QLineEdit::textChanged, config, &Config::setActiveDirectoryAdminUsername );
|
||||
connect( ui->domainPasswordField, &QLineEdit::textChanged, config, &Config::setActiveDirectoryAdminPassword );
|
||||
connect( ui->ipAddressField, &QLineEdit::textChanged, config, &Config::setActiveDirectoryIP );
|
||||
|
||||
CALAMARES_RETRANSLATE_SLOT( &UsersPage::retranslate );
|
||||
|
||||
onReuseUserPasswordChanged( m_config->reuseUserPasswordForRoot() );
|
||||
@ -283,3 +293,18 @@ UsersPage::onReuseUserPasswordChanged( const int checked )
|
||||
ui->textBoxRootPassword->setVisible( visible );
|
||||
ui->textBoxVerifiedRootPassword->setVisible( visible );
|
||||
}
|
||||
|
||||
void
|
||||
UsersPage::onActiveDirectoryToggled( bool checked )
|
||||
{
|
||||
ui->domainLabel->setVisible( checked );
|
||||
ui->domainField->setVisible( checked );
|
||||
ui->domainAdminLabel->setVisible( checked );
|
||||
ui->domainAdminField->setVisible( checked );
|
||||
ui->domainPasswordField->setVisible( checked );
|
||||
ui->domainPasswordLabel->setVisible( checked );
|
||||
ui->ipAddressField->setVisible( checked );
|
||||
ui->ipAddressLabel->setVisible( checked );
|
||||
|
||||
m_config->setActiveDirectoryUsed( checked );
|
||||
}
|
||||
|
@ -44,6 +44,8 @@ protected slots:
|
||||
void reportUserPasswordStatus( int, const QString& );
|
||||
void reportRootPasswordStatus( int, const QString& );
|
||||
|
||||
void onActiveDirectoryToggled( bool checked );
|
||||
|
||||
private:
|
||||
void retranslate();
|
||||
|
||||
|
@ -603,6 +603,93 @@ SPDX-License-Identifier: GPL-3.0-or-later
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item>
|
||||
<spacer name="verticalSpacer_3">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Vertical</enum>
|
||||
</property>
|
||||
<property name="sizeType">
|
||||
<enum>QSizePolicy::Fixed</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>20</width>
|
||||
<height>6</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
<item>
|
||||
<layout class="QVBoxLayout" name="verticalLayout">
|
||||
<item>
|
||||
<widget class="QCheckBox" name="useADCheckbox">
|
||||
<property name="text">
|
||||
<string>Use Active Directory</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<layout class="QVBoxLayout" name="verticalLayout_3">
|
||||
<item>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_2">
|
||||
<item>
|
||||
<widget class="QLabel" name="domainLabel">
|
||||
<property name="text">
|
||||
<string>Domain:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QLineEdit" name="domainField"/>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout">
|
||||
<item>
|
||||
<widget class="QLabel" name="domainAdminLabel">
|
||||
<property name="text">
|
||||
<string>Domain Administrator:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QLineEdit" name="domainAdminField"/>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QLabel" name="domainPasswordLabel">
|
||||
<property name="text">
|
||||
<string>Password:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QLineEdit" name="domainPasswordField">
|
||||
<property name="echoMode">
|
||||
<enum>QLineEdit::Password</enum>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_3">
|
||||
<item>
|
||||
<widget class="QLabel" name="ipAddressLabel">
|
||||
<property name="text">
|
||||
<string>IP Address (optional):</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QLineEdit" name="ipAddressField"/>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item>
|
||||
<spacer name="verticalSpacer_7">
|
||||
<property name="orientation">
|
||||
|
@ -265,6 +265,12 @@ hostname:
|
||||
template: "derp-${cpu}"
|
||||
forbidden_names: [ localhost ]
|
||||
|
||||
# Enable Active Directory enrollment support (opt-in)
|
||||
#
|
||||
# This uses realmd to enroll the machine in an Active Directory server
|
||||
# It requires realmd as a runtime dependency of Calamares, if enabled
|
||||
allowActiveDirectory: false
|
||||
|
||||
presets:
|
||||
fullName:
|
||||
# value: "OEM User"
|
||||
|
@ -52,6 +52,7 @@ properties:
|
||||
writeHostsFile: { type: boolean, default: true }
|
||||
template: { type: string, default: "${first}-${product}" }
|
||||
forbidden_names: { type: array, items: { type: string } }
|
||||
allowActiveDirectory: { type: boolean, default: false }
|
||||
|
||||
# Presets
|
||||
#
|
||||
|