anaconda: update to 22.20.13-1
Apply diff anaconda-21.48.21-1..anaconda-22.20.13-1
This commit is contained in:
parent
47a0aea0c6
commit
701ced5ddb
@ -1,9 +0,0 @@
|
||||
[anaconda.f21-branch]
|
||||
file_filter = po/<lang>.po
|
||||
source_file = po/anaconda.pot
|
||||
source_lang = en
|
||||
type = PO
|
||||
|
||||
[main]
|
||||
host = https://www.transifex.com
|
||||
|
@ -44,18 +44,16 @@ dist_sbin_SCRIPTS = anaconda
|
||||
|
||||
ARCHIVE_TAG = $(PACKAGE_NAME)-$(PACKAGE_VERSION)-$(PACKAGE_RELEASE)
|
||||
|
||||
TX_PULL_ARGS = -a -f
|
||||
TX_PUSH_ARGS = -s
|
||||
|
||||
INSTALLATION_GUIDE_REPO_URL = git://git.fedorahosted.org/git/docs/install-guide.git
|
||||
ZANATA_PULL_ARGS = --transdir $(srcdir)/po/
|
||||
ZANATA_PUSH_ARGS = --srcdir $(srcdir)/po/ --push-type source --force
|
||||
|
||||
tag:
|
||||
@git tag -s -a -m "Tag as $(ARCHIVE_TAG)" $(ARCHIVE_TAG)
|
||||
@echo "Tagged as $(ARCHIVE_TAG)"
|
||||
|
||||
po-pull:
|
||||
rpm -q transifex-client &>/dev/null || ( echo "need to run: yum install transifex-client"; exit 1 )
|
||||
tx pull $(TX_PULL_ARGS)
|
||||
rpm -q zanata-python-client &>/dev/null || ( echo "need to run: yum install zanata-python-client"; exit 1 )
|
||||
zanata pull $(ZANATA_PULL_ARGS)
|
||||
|
||||
po-empty:
|
||||
for lingua in $$(grep -v '^#' $(srcdir)/po/LINGUAS) ; do \
|
||||
@ -64,12 +62,12 @@ po-empty:
|
||||
exit 1 ; \
|
||||
done
|
||||
|
||||
scratch: po-empty get-help
|
||||
scratch: po-empty
|
||||
$(MAKE) ARCHIVE_TAG=HEAD dist
|
||||
git checkout -- $(srcdir)/po/$(PACKAGE_NAME).pot
|
||||
|
||||
scratch-bumpver: po-empty get-help
|
||||
@opts="-n $(PACKAGE_NAME) -v $(PACKAGE_VERSION) -r $(PACKAGE_RELEASE) -b $(PACKAGE_BUGREPORT)" ; \
|
||||
scratch-bumpver: po-empty
|
||||
@opts="-S -n $(PACKAGE_NAME) -v $(PACKAGE_VERSION) -r $(PACKAGE_RELEASE) -b $(PACKAGE_BUGREPORT)" ; \
|
||||
if [ ! -z "$(IGNORE)" ]; then \
|
||||
opts="$${opts} -i $(IGNORE)" ; \
|
||||
fi ; \
|
||||
@ -79,18 +77,12 @@ scratch-bumpver: po-empty get-help
|
||||
if [ ! -z "$(BZDEBUG)" ]; then \
|
||||
opts="$${opts} -d" ; \
|
||||
fi ; \
|
||||
if [ ! -z "$(SKIP_ACKS)" ]; then \
|
||||
opts="$${opts} -s" ; \
|
||||
fi ; \
|
||||
( cd $(srcdir) && scripts/makebumpver $${opts} ) || exit 1 ; \
|
||||
$(MAKE) -C po $(PACKAGE_NAME).pot-update ;
|
||||
( cd $(srcdir) && scripts/makebumpver --skip-zanata $${opts} ) || exit 1 ; \
|
||||
$(MAKE) -C po $(PACKAGE_NAME).pot-update ;
|
||||
|
||||
release: get-help
|
||||
release:
|
||||
$(MAKE) dist && $(MAKE) tag && git checkout -- $(srcdir)/po/$(PACKAGE_NAME).pot
|
||||
|
||||
api:
|
||||
doxygen docs/api.cfg
|
||||
|
||||
bumpver: po-pull
|
||||
@opts="-n $(PACKAGE_NAME) -v $(PACKAGE_VERSION) -r $(PACKAGE_RELEASE) -b $(PACKAGE_BUGREPORT)" ; \
|
||||
if [ ! -z "$(IGNORE)" ]; then \
|
||||
@ -107,21 +99,21 @@ bumpver: po-pull
|
||||
fi ; \
|
||||
( cd $(srcdir) && scripts/makebumpver $${opts} ) || exit 1 ; \
|
||||
$(MAKE) -C po $(PACKAGE_NAME).pot-update && \
|
||||
tx push $(TX_PUSH_ARGS)
|
||||
zanata push $(ZANATA_PUSH_ARGS)
|
||||
|
||||
# Install all packages specified as BuildRequires in the Anaconda specfile
|
||||
# -> installs packages needed to build Anaconda
|
||||
install-buildrequires:
|
||||
srcdir="$(srcdir)" && \
|
||||
: $${srcdir:=.} && \
|
||||
yum install $$(grep BuildRequires: $${srcdir}/anaconda.spec.in | cut -d ' ' -f 2)
|
||||
yum install $$(grep ^BuildRequires: $${srcdir}/anaconda.spec.in | cut -d ' ' -f 2)
|
||||
|
||||
# Install all packages specified as Requires in the Anaconda specfile
|
||||
# -> installs packages needed to run Anaconda and the Anaconda unit tests
|
||||
install-requires:
|
||||
srcdir="$(srcdir)" && \
|
||||
: $${srcdir:=.} && \
|
||||
yum install $$(grep Requires: $${srcdir}/anaconda.spec.in | cut -d ' ' -f 2)
|
||||
yum install $$(grep ^Requires: $${srcdir}/anaconda.spec.in | cut -d ' ' -f 2 | grep -v ^anaconda)
|
||||
|
||||
# Generate an updates.img based on the changed files since the release
|
||||
# was tagged. Updates are copied to ./updates-img and then the image is
|
||||
@ -141,43 +133,6 @@ unittests-logpicker:
|
||||
PYTHONPATH=$(builddir)/pyanaconda/isys/.libs:tests/:$(srcdir):utils/ nosetests -v old_tests/logpicker_test
|
||||
|
||||
# GUI TESTING
|
||||
runspoke:
|
||||
ANACONDA_DATA=$(srcdir)/data \
|
||||
ANACONDA_WIDGETS_OVERRIDES=$(srcdir)/widgets/python \
|
||||
ANACONDA_WIDGETS_DATA=$(srcdir)/widgets/data \
|
||||
ANACONDA_INSTALL_CLASSES=$(srcdir)/pyanaconda/installclasses \
|
||||
PYTHONPATH=$(srcdir):$(builddir)/pyanaconda/isys/.libs:$(srcdir)/widgets/python/:$(builddir)/widgets/src/.libs/ \
|
||||
LD_LIBRARY_PATH=$(builddir)/widgets/src/.libs \
|
||||
UIPATH=$(srcdir)/pyanaconda/ui/gui/ \
|
||||
GI_TYPELIB_PATH=$(builddir)/widgets/src/ \
|
||||
$(srcdir)/pyanaconda/ui/gui/tools/run-spoke.py ${SPOKE_MODULE} ${SPOKE_CLASS}
|
||||
|
||||
runhub:
|
||||
ANACONDA_DATA=$(srcdir)/data \
|
||||
ANACONDA_WIDGETS_OVERRIDES=$(srcdir)/widgets/python \
|
||||
ANACONDA_WIDGETS_DATA=$(srcdir)/widgets/data \
|
||||
ANACONDA_INSTALL_CLASSES=$(srcdir)/pyanaconda/installclasses \
|
||||
PYTHONPATH=$(srcdir):$(builddir)/pyanaconda/isys/.libs:$(srcdir)/widgets/python/:$(builddir)/widgets/src/.libs/ \
|
||||
LD_LIBRARY_PATH=$(builddir)/widgets/src/.libs \
|
||||
UIPATH=$(srcdir)/pyanaconda/ui/gui/ \
|
||||
GI_TYPELIB_PATH=$(builddir)/widgets/src/ \
|
||||
$(srcdir)/pyanaconda/ui/gui/tools/run-hub.py ${HUB_MODULE} ${HUB_CLASS}
|
||||
|
||||
runtextspoke:
|
||||
ANACONDA_DATA=$(srcdir)/data \
|
||||
ANACONDA_INSTALL_CLASSES=$(srcdir)/pyanaconda/installclasses \
|
||||
PYTHONPATH=$(srcdir):$(builddir)/pyanaconda/isys/.libs:$(srcdir)/widgets/python/:$(builddir)/widgets/src/.libs/ \
|
||||
LD_LIBRARY_PATH=$(builddir)/widgets/src/.libs \
|
||||
$(srcdir)/pyanaconda/ui/tui/tools/run-text-spoke.py ${SPOKE_MODULE} ${SPOKE_CLASS}
|
||||
|
||||
runtexthub:
|
||||
ANACONDA_DATA=$(srcdir)/data \
|
||||
ANACONDA_INSTALL_CLASSES=$(srcdir)/pyanaconda/installclasses \
|
||||
PYTHONPATH=$(srcdir):$(builddir)/pyanaconda/isys/.libs:$(srcdir)/widgets/python/:$(builddir)/widgets/src/.libs/ \
|
||||
LD_LIBRARY_PATH=$(builddir)/widgets/src/.libs \
|
||||
$(srcdir)/pyanaconda/ui/tui/tools/run-text-hub.py ${HUB_MODULE} ${HUB_CLASS}
|
||||
|
||||
|
||||
runglade:
|
||||
ANACONDA_DATA=$(srcdir)/data \
|
||||
ANACONDA_WIDGETS_OVERRIDES=$(srcdir)/widgets/python \
|
||||
@ -190,24 +145,3 @@ runglade:
|
||||
GLADE_CATALOG_SEARCH_PATH=$(srcdir)/widgets/glade \
|
||||
GLADE_MODULE_SEARCH_PATH=$(builddir)/widgets/src/.libs \
|
||||
glade ${GLADE_FILE}
|
||||
|
||||
|
||||
# Get content for the Anaconda built-in help system by cloning the
|
||||
# installation guide git repository and running the help processing
|
||||
# script (it is part of the repository).
|
||||
# Once the help content has been generated copy it to our help folder,
|
||||
# so that it can be included in the tarball.
|
||||
# Skip the git clone if the repository already exists but run git pull
|
||||
# to make sure it is up to date. We also clone the repository
|
||||
# without history as it si rather big (>400 MB!), which is quite
|
||||
# an overkill for <100 kB of help conent. :)
|
||||
get-help:
|
||||
if [ ! -d "install-guide" ]; then \
|
||||
if [ -f "installation_guide_repo_url" ]; then \
|
||||
git clone --depth=1 `cat installation_guide_repo_url` ; \
|
||||
else \
|
||||
git clone --depth=1 $(INSTALLATION_GUIDE_REPO_URL) ; \
|
||||
fi ; \
|
||||
fi ; \
|
||||
( cd install-guide && git pull --rebase && python prepare_anaconda_help_content.py )
|
||||
cp -r install-guide/anaconda_help_content/* $(srcdir)/data/help
|
||||
|
75
anaconda/acinclude.m4
Normal file
75
anaconda/acinclude.m4
Normal file
@ -0,0 +1,75 @@
|
||||
dnl autoconf macros for anaconda
|
||||
dnl
|
||||
dnl Copyright (C) 2014 Red Hat, Inc.
|
||||
dnl
|
||||
dnl This program is free software; you can redistribute it and/or modify
|
||||
dnl it under the terms of the GNU Lesser General Public License as published
|
||||
dnl by the Free Software Foundation; either version 2.1 of the License, or
|
||||
dnl (at your option) any later version.
|
||||
dnl
|
||||
dnl This program is distributed in the hope that it will be useful,
|
||||
dnl but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
dnl MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
dnl GNU Lesser General Public License for more details.
|
||||
dnl
|
||||
dnl You should have received a copy of the GNU Lesser General Public License
|
||||
dnl along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
dnl
|
||||
dnl Author: David Shea <dshea@redhat.com>
|
||||
|
||||
dnl ANACONDA_SOFT_FAILURE(MESSAGE)
|
||||
dnl
|
||||
dnl Store a message that in some contexts could be considered indicative
|
||||
dnl of a failure, but in other contexts could be indicative of who cares.
|
||||
dnl
|
||||
dnl For example, the anaconda widgets require a version of gtk3-devel of
|
||||
dnl particular newness, and the widgets will fail to build if this library
|
||||
dnl and headers are not available. On the other hand, gtk3 isn't required at
|
||||
dnl all for most everything else, so it would be nice if a missing or old
|
||||
dnl gtk3-devel didn't halt the configure script.
|
||||
dnl
|
||||
dnl Any message sent to this macro will be stored, and they can all be
|
||||
dnl displayed at the end of configure using the ANACONDA_FAILURES macro.
|
||||
AC_DEFUN([ANACONDA_SOFT_FAILURE], [dnl
|
||||
AS_IF([test x"$anaconda_failure_messages" = x],
|
||||
[anaconda_failure_messages="[$1]"],
|
||||
[anaconda_failure_messages="$anaconda_failure_messages
|
||||
[$1]"
|
||||
])])dnl
|
||||
|
||||
dnl ANACONDA_PKG_CHECK_MODULES(VARIABLE-PREFIX, MODULES)
|
||||
dnl
|
||||
dnl Check whether a module is available, using pkg-config. Instead of failing
|
||||
dnl if a module is not found, store the failure in a message that can be
|
||||
dnl printed using the ANACONDA_FAILURES macro.
|
||||
dnl
|
||||
dnl The syntax and behavior of VARIABLE-PREFIX and MODULES is the same as for
|
||||
dnl PKG_CHECK_MODULES.
|
||||
AC_DEFUN([ANACONDA_PKG_CHECK_MODULES], [dnl
|
||||
PKG_CHECK_MODULES([$1], [$2], [], [ANACONDA_SOFT_FAILURE($[$1]_PKG_ERRORS)])
|
||||
])dnl
|
||||
|
||||
dnl ANACONDA_PKG_CHECK_EXISTS(MODULES)
|
||||
dnl
|
||||
dnl Check whether a module exists, using pkg-config. Instead of failing
|
||||
dnl if a module is not found, store the failure in a message that can be
|
||||
dnl printed using the ANACONDA_FAILURES macro.
|
||||
dnl
|
||||
dnl The syntax and behavior of MOUDLES is the same as for
|
||||
dnl PKG_CHECK_EXISTS.
|
||||
AC_DEFUN([ANACONDA_PKG_CHECK_EXISTS], [dnl
|
||||
PKG_CHECK_EXISTS([$1], [], [ANACONDA_SOFT_FAILURE([Check for $1 failed])])
|
||||
])dnl
|
||||
|
||||
dnl ANACONDA_FAILURES
|
||||
dnl
|
||||
dnl Print the failure messages collected by ANACONDA_SOFT_FAILURE and
|
||||
dnl ANACONDA_PKG_CHECK_MODULES
|
||||
AC_DEFUN([ANACONDA_FAILURES], [dnl
|
||||
AS_IF([test x"$anaconda_failure_messages" = x], [], [dnl
|
||||
echo ""
|
||||
echo "*** Anaconda encountered the following issues during configuration:"
|
||||
echo "$anaconda_failure_messages"
|
||||
echo ""
|
||||
echo "*** Anaconda will not successfully build without these missing dependencies"
|
||||
])])dnl
|
@ -1,4 +1,4 @@
|
||||
#!/usr/bin/python
|
||||
#!/usr/bin/python2
|
||||
#
|
||||
# anaconda: The Red Hat Linux Installation program
|
||||
#
|
||||
@ -44,85 +44,11 @@ if ("debug=1" in proc_cmdline) or ("debug" in proc_cmdline):
|
||||
cov.start()
|
||||
|
||||
|
||||
import atexit, sys, os, time, subprocess, signal, errno
|
||||
import atexit, sys, os, time, signal, stat, errno
|
||||
|
||||
# Install a global SIGCHLD handler to keep track of things that should be
|
||||
# running for as long as anaconda does. The dictionary is of the form
|
||||
# {pid: name, ...}. The handler will raise ExitError (defined below), so if
|
||||
# not caught a SIGCHLD from a watched process will halt anaconda.
|
||||
forever_pids = {}
|
||||
|
||||
class ExitError(RuntimeError):
|
||||
pass
|
||||
|
||||
def sigchld_handler(num, frame):
|
||||
# Check whether anything in the list of processes being watched has
|
||||
# exited. We don't want to call waitpid(-1), since that would break
|
||||
# anything else using wait/waitpid (like the subprocess module).
|
||||
exited_pids = []
|
||||
exn_message = []
|
||||
|
||||
for child_pid in forever_pids:
|
||||
try:
|
||||
pid_result, status = iutil.eintr_retry_call(os.waitpid, child_pid, os.WNOHANG)
|
||||
except OSError as e:
|
||||
if e.errno == errno.ECHILD:
|
||||
continue
|
||||
|
||||
if pid_result:
|
||||
proc_name = forever_pids[child_pid]
|
||||
exited_pids.append(child_pid)
|
||||
|
||||
if os.WIFEXITED(status):
|
||||
status_str = "with status %s" % os.WEXITSTATUS(status)
|
||||
elif os.WIFSIGNALED(status):
|
||||
status_str = "on signal %s" % os.WTERMSIG(status)
|
||||
else:
|
||||
status_str = "with unknown status code %s" % status
|
||||
|
||||
exn_message.append("%s exited %s" % (proc_name, status_str))
|
||||
|
||||
for child_pid in exited_pids:
|
||||
del forever_pids[child_pid]
|
||||
|
||||
if exn_message:
|
||||
raise ExitError(", ".join(exn_message))
|
||||
|
||||
signal.signal(signal.SIGCHLD, sigchld_handler)
|
||||
|
||||
# Fork a new process and add it to forever_pids. The return values are the
|
||||
# the same as os.fork, but neither the parent nor the child will return
|
||||
# until the process is watched.
|
||||
def start_watched_pid(proc_name):
|
||||
readpipe, writepipe = os.pipe()
|
||||
childpid = os.fork()
|
||||
if childpid == 0:
|
||||
# No need for the write pipe in the child
|
||||
iutil.eintr_retry_call(os.close, writepipe)
|
||||
|
||||
# Wait for the parent to signal that it's ready to return
|
||||
iutil.eintr_retry_call(os.read, readpipe, 1)
|
||||
|
||||
# Ready to go
|
||||
iutil.eintr_retry_call(os.close, readpipe)
|
||||
return childpid
|
||||
else:
|
||||
# No need for the read pipe in the parent
|
||||
iutil.eintr_retry_call(os.close, readpipe)
|
||||
|
||||
# Add the pid to the list of watched pids
|
||||
forever_pids[childpid] = proc_name
|
||||
|
||||
# Signal to the child that we're ready to return
|
||||
# D is for Done
|
||||
iutil.eintr_retry_call(os.write, writepipe, 'D')
|
||||
iutil.eintr_retry_call(os.close, writepipe)
|
||||
return childpid
|
||||
|
||||
def exitHandler(rebootData, storage, exitCode=None):
|
||||
def exitHandler(rebootData, storage):
|
||||
# Clear the list of watched PIDs.
|
||||
global forever_pids
|
||||
forever_pids = {}
|
||||
iutil.unwatchAllProcesses()
|
||||
|
||||
# stop and save coverage here b/c later the file system may be unavailable
|
||||
if coverage is not None:
|
||||
@ -133,9 +59,6 @@ def exitHandler(rebootData, storage, exitCode=None):
|
||||
if flags.usevnc:
|
||||
vnc.shutdownServer()
|
||||
|
||||
if exitCode:
|
||||
anaconda.intf.shutdown()
|
||||
|
||||
if "nokill" in flags.cmdline:
|
||||
iutil.vtActivate(1)
|
||||
print("anaconda halting due to nokill flag.")
|
||||
@ -158,10 +81,18 @@ def exitHandler(rebootData, storage, exitCode=None):
|
||||
uninhibit_screensaver(anaconda.dbus_session_connection, anaconda.dbus_inhibit_id)
|
||||
anaconda.dbus_inhibit_id = None
|
||||
|
||||
# Unsetup the payload, which most usefully unmounts live images
|
||||
if anaconda.payload:
|
||||
anaconda.payload.unsetup()
|
||||
|
||||
# Clean up the PID file
|
||||
if pidfile_created:
|
||||
os.unlink(pidfile_path)
|
||||
|
||||
if not flags.imageInstall and not flags.livecdInstall \
|
||||
and not flags.dirInstall:
|
||||
from pykickstart.constants import KS_SHUTDOWN, KS_WAIT
|
||||
from pyanaconda.iutil import dracut_eject, get_mount_paths
|
||||
from pyanaconda.iutil import dracut_eject, get_mount_paths, execWithRedirect
|
||||
|
||||
if flags.eject or rebootData.eject:
|
||||
for cdrom in storage.devicetree.getDevicesByType("cdrom"):
|
||||
@ -169,11 +100,11 @@ def exitHandler(rebootData, storage, exitCode=None):
|
||||
dracut_eject(cdrom.path)
|
||||
|
||||
if rebootData.action == KS_SHUTDOWN:
|
||||
subprocess.Popen(["systemctl", "--no-wall", "poweroff"])
|
||||
execWithRedirect("systemctl", ["--no-wall", "poweroff"])
|
||||
elif rebootData.action == KS_WAIT:
|
||||
subprocess.Popen(["systemctl", "--no-wall", "halt"])
|
||||
execWithRedirect("systemctl", ["--no-wall", "halt"])
|
||||
else: # reboot action is KS_REBOOT or None
|
||||
subprocess.Popen(["systemctl", "--no-wall", "reboot"])
|
||||
execWithRedirect("systemctl", ["--no-wall", "reboot"])
|
||||
|
||||
def startSpiceVDAgent():
|
||||
status = iutil.execWithRedirect("spice-vdagent", [])
|
||||
@ -184,125 +115,37 @@ def startSpiceVDAgent():
|
||||
log.info("Started spice-vdagent.")
|
||||
|
||||
def startX11():
|
||||
# Start X11 with its USR1 handler set to ignore, which will make it send
|
||||
# us SIGUSR1 if it succeeds. If it fails, catch SIGCHLD and bomb out.
|
||||
# Use a list so the value can be modified from the handler
|
||||
x11_started = [False]
|
||||
def sigusr1_handler(num, frame):
|
||||
log.debug("X server has signalled a successful start.")
|
||||
x11_started[0] = True
|
||||
# Open /dev/tty5 for stdout and stderr redirects
|
||||
xfd = open("/dev/tty5", "a")
|
||||
|
||||
# Fail after, let's say a minute, in case something weird happens
|
||||
# and we don't receive SIGUSR1
|
||||
def sigalrm_handler(num, frame):
|
||||
# Check that it didn't make it under the wire
|
||||
if x11_started[0]:
|
||||
return
|
||||
log.error("Timeout trying to start the X server")
|
||||
raise ExitError("Timeout trying to start the X server")
|
||||
# Start Xorg and wait for it become ready
|
||||
iutil.startX(["Xorg", "-br", "-logfile", "/tmp/X.log",
|
||||
":%s" % constants.X_DISPLAY_NUMBER, "vt6", "-s", "1440", "-ac",
|
||||
"-nolisten", "tcp", "-dpi", "96",
|
||||
"-noreset"], output_redirect=xfd)
|
||||
|
||||
try:
|
||||
old_sigusr1_handler = signal.signal(signal.SIGUSR1, sigusr1_handler)
|
||||
old_sigalrm_handler = signal.signal(signal.SIGALRM, sigalrm_handler)
|
||||
# function to handle X startup special issues for anaconda
|
||||
def doStartupX11Actions():
|
||||
"""Start window manager"""
|
||||
from copy import copy
|
||||
|
||||
childpid = start_watched_pid("Xorg")
|
||||
|
||||
if not childpid:
|
||||
# after this point the method should never return (or throw an exception
|
||||
# outside)
|
||||
try:
|
||||
# dup /dev/tty5 to stdout and stderr
|
||||
xfd = iutil.eintr_retry_call(os.open, "/dev/tty5", os.O_WRONLY | os.O_APPEND)
|
||||
iutil.eintr_retry_call(os.dup2, xfd, sys.stdout.fileno())
|
||||
iutil.eintr_retry_call(os.dup2, xfd, sys.stderr.fileno())
|
||||
|
||||
# Close all other file descriptors
|
||||
try:
|
||||
maxfd = os.sysconf("SC_OPEN_MAX")
|
||||
except ValueError:
|
||||
maxfd = 1024
|
||||
|
||||
os.closerange(3, maxfd)
|
||||
|
||||
# Replace the SIGUSR1 handler with SIG_IGN as described above
|
||||
signal.signal(signal.SIGUSR1, signal.SIG_IGN)
|
||||
|
||||
# Run it
|
||||
os.execlp("Xorg", "Xorg", "-br",
|
||||
"-logfile", "/tmp/X.log",
|
||||
":1", "vt6", "-s", "1440", "-ac",
|
||||
"-nolisten", "tcp", "-dpi", "96",
|
||||
"-noreset")
|
||||
|
||||
# We should never get here
|
||||
raise OSError(0, "Unable to exec")
|
||||
except BaseException as e:
|
||||
# catch all possible exceptions
|
||||
# Reopen the logger in case it was closed by closerange.
|
||||
# Use a different name because assigning to variables across a
|
||||
# fork confuses the hell out of python.
|
||||
child_log = logging.getLogger("anaconda")
|
||||
child_log.error("Problems running Xorg: %s", e)
|
||||
os._exit(1)
|
||||
|
||||
# Parent process
|
||||
# Start the timer
|
||||
signal.alarm(60)
|
||||
|
||||
# Wait for SIGUSR1
|
||||
while not x11_started[0]:
|
||||
signal.pause()
|
||||
|
||||
# Now that X is started, make $DISPLAY available
|
||||
os.environ["DISPLAY"] = ":1"
|
||||
finally:
|
||||
# Put everything back where it was
|
||||
signal.alarm(0)
|
||||
signal.signal(signal.SIGUSR1, old_sigusr1_handler)
|
||||
signal.signal(signal.SIGALRM, old_sigalrm_handler)
|
||||
|
||||
def startMetacityWM():
|
||||
# When metacity actually connects to the X server is unknowable, but
|
||||
# fortunately it doesn't matter. metacity does not need to be the first
|
||||
# connection to Xorg, and if anaconda starts up before metacity, metacity
|
||||
# will just take over and maximize the window and make everything right,
|
||||
# fingers crossed.
|
||||
# Add XDG_DATA_DIRS to the environment to pull in our overridden schema
|
||||
# files.
|
||||
env_bak = copy(os.environ)
|
||||
if 'XDG_DATA_DIRS' in os.environ:
|
||||
xdg_data_dirs = '/usr/share/anaconda/window-manager:' + os.environ['XDG_DATA_DIRS']
|
||||
else:
|
||||
xdg_data_dirs = '/usr/share/anaconda/window-manager:/usr/share'
|
||||
|
||||
childpid = start_watched_pid("metacity")
|
||||
if not childpid:
|
||||
# after this point the method should never return (or throw an exception
|
||||
# outside)
|
||||
try:
|
||||
returncode = iutil.execWithRedirect('metacity', ["--display", ":1", "--sm-disable"])
|
||||
except BaseException as e:
|
||||
# catch all possible exceptions
|
||||
log.error("Problems running the window manager: %s", e)
|
||||
os._exit(1)
|
||||
|
||||
log.info("The window manager has terminated.")
|
||||
os._exit(returncode)
|
||||
|
||||
return childpid
|
||||
|
||||
def startAuditDaemon():
|
||||
childpid = os.fork()
|
||||
if not childpid:
|
||||
cmd = '/sbin/auditd'
|
||||
try:
|
||||
os.execl(cmd, cmd)
|
||||
except OSError as e:
|
||||
log.error("Error running the audit daemon: %s", e)
|
||||
os._exit(0)
|
||||
# auditd will turn into a daemon so catch the immediate child pid now:
|
||||
iutil.eintr_retry_call(os.waitpid, childpid, 0)
|
||||
|
||||
# function to handle X startup special issues for anaconda
|
||||
def doStartupX11Actions():
|
||||
"""Start window manager"""
|
||||
|
||||
# now start up the window manager
|
||||
wm_pid = startMetacityWM()
|
||||
log.info("Starting window manager, pid %s.", wm_pid)
|
||||
childproc = iutil.startProgram(["metacity", "--display", ":1", "--sm-disable"],
|
||||
env_add={'XDG_DATA_DIRS': xdg_data_dirs})
|
||||
os.environ = env_bak
|
||||
iutil.watchProcess(childproc, "metacity")
|
||||
|
||||
def set_x_resolution(runres):
|
||||
if runres and opts.display_mode == 'g' and not flags.usevnc:
|
||||
@ -474,6 +317,7 @@ def parseArguments(argv=None, boot_cmdline=None):
|
||||
# Obvious
|
||||
ap.add_argument("--loglevel", metavar="LEVEL", help=help_parser.help_text("loglevel"))
|
||||
ap.add_argument("--syslog", metavar="HOST[:PORT]", help=help_parser.help_text("syslog"))
|
||||
ap.add_argument("--remotelog", metavar="HOST:PORT", help=help_parser.help_text("remotelog"))
|
||||
|
||||
from pykickstart.constants import SELINUX_DISABLED, SELINUX_ENFORCING
|
||||
from pyanaconda.constants import SELINUX_DEFAULT
|
||||
@ -519,8 +363,8 @@ def parseArguments(argv=None, boot_cmdline=None):
|
||||
help=help_parser.help_text("extlinux"))
|
||||
ap.add_argument("--nombr", action="store_true", default=False,
|
||||
help=help_parser.help_text("nombr"))
|
||||
ap.add_argument("--dnf", action="store_true", default=False,
|
||||
help=help_parser.help_text("dnf"))
|
||||
ap.add_argument("--nodnf", action="store_false", dest="dnf", default=True,
|
||||
help=help_parser.help_text("nodnf"))
|
||||
ap.add_argument("--mpathfriendlynames", action="store_true", default=True,
|
||||
help=help_parser.help_text("mpathfriendlynames"))
|
||||
|
||||
@ -541,6 +385,12 @@ def setupPythonPath():
|
||||
sys.path.extend(ADDON_PATHS)
|
||||
|
||||
def setupEnvironment():
|
||||
from pyanaconda.users import createLuserConf
|
||||
|
||||
# This method is run before any threads are started, so this is the one
|
||||
# point where it's ok to modify the environment.
|
||||
# pylint: disable=environment-modify
|
||||
|
||||
# Silly GNOME stuff
|
||||
if 'HOME' in os.environ and not "XAUTHORITY" in os.environ:
|
||||
os.environ['XAUTHORITY'] = os.environ['HOME'] + '/.Xauthority'
|
||||
@ -559,6 +409,16 @@ def setupEnvironment():
|
||||
if "LD_PRELOAD" in os.environ:
|
||||
del os.environ["LD_PRELOAD"]
|
||||
|
||||
# Go ahead and set $DISPLAY whether we're going to use X or not
|
||||
if 'DISPLAY' in os.environ:
|
||||
flags.preexisting_x11 = True
|
||||
else:
|
||||
os.environ["DISPLAY"] = ":%s" % constants.X_DISPLAY_NUMBER
|
||||
|
||||
# Call createLuserConf now to setup $LIBUSER_CONF
|
||||
# the config file can change later but the environment variable cannot
|
||||
createLuserConf(iutil.getSysroot())
|
||||
|
||||
def setupLoggingFromOpts(options):
|
||||
if (options.debug or options.updateSrc) and not options.loglevel:
|
||||
# debugging means debug logging if an explicit level hasn't been st
|
||||
@ -567,15 +427,24 @@ def setupLoggingFromOpts(options):
|
||||
if options.loglevel and options.loglevel in anaconda_log.logLevelMap:
|
||||
log.info("Switching logging level to %s", options.loglevel)
|
||||
level = anaconda_log.logLevelMap[options.loglevel]
|
||||
anaconda_log.logger.tty_loglevel = level
|
||||
anaconda_log.logger.loglevel = level
|
||||
anaconda_log.setHandlersLevel(log, level)
|
||||
storage_log = logging.getLogger("storage")
|
||||
anaconda_log.setHandlersLevel(storage_log, level)
|
||||
packaging_log = logging.getLogger("packaging")
|
||||
anaconda_log.setHandlersLevel(packaging_log, level)
|
||||
|
||||
if options.syslog:
|
||||
anaconda_log.logger.updateRemote(options.syslog)
|
||||
if can_touch_runtime_system("syslog setup"):
|
||||
if options.syslog:
|
||||
anaconda_log.logger.updateRemote(options.syslog)
|
||||
|
||||
if options.remotelog:
|
||||
try:
|
||||
host, port = options.remotelog.split(":", 1)
|
||||
port = int(port)
|
||||
anaconda_log.logger.setup_remotelog(host, port)
|
||||
except ValueError:
|
||||
log.error("Could not setup remotelog with %s", options.remotelog)
|
||||
|
||||
def gtk_warning(title, reason):
|
||||
from gi.repository import Gtk
|
||||
@ -643,6 +512,8 @@ def check_memory(anaconda, options, display_mode=None):
|
||||
reason % reason_args,
|
||||
buttons = (_("OK"),))
|
||||
screen.finish()
|
||||
|
||||
iutil.ipmi_report(constants.IPMI_ABORTED)
|
||||
sys.exit(1)
|
||||
|
||||
# override display mode if machine cannot nicely run X
|
||||
@ -658,6 +529,7 @@ def check_memory(anaconda, options, display_mode=None):
|
||||
stdoutLog.warning(reason % reason_args)
|
||||
title = livecd_title
|
||||
gtk_warning(title, reason % reason_args)
|
||||
iutil.ipmi_report(constants.IPMI_ABORTED)
|
||||
sys.exit(1)
|
||||
else:
|
||||
reason += nolivecd_extra
|
||||
@ -693,7 +565,7 @@ def setupDisplay(anaconda, options, addons=None):
|
||||
|
||||
# Only consider vncconnect when vnc is a param
|
||||
if options.vncconnect:
|
||||
cargs = string.split(options.vncconnect, ":")
|
||||
cargs = options.vncconnect.split(":")
|
||||
vncS.vncconnecthost = cargs[0]
|
||||
if len(cargs) > 1 and len(cargs[1]) > 0:
|
||||
if len(cargs[1]) > 0:
|
||||
@ -755,9 +627,6 @@ def setupDisplay(anaconda, options, addons=None):
|
||||
stdoutLog.warning("Not asking for VNC because we don't have Xvnc")
|
||||
flags.vncquestion = False
|
||||
|
||||
if 'DISPLAY' in os.environ:
|
||||
flags.preexisting_x11 = True
|
||||
|
||||
# Should we try to start Xorg?
|
||||
want_x = anaconda.displayMode == 'g' and \
|
||||
not (flags.preexisting_x11 or flags.usevnc)
|
||||
@ -845,6 +714,7 @@ def prompt_for_ssh():
|
||||
|
||||
if not ip:
|
||||
stdoutLog.error("No IP addresses found, cannot continue installation.")
|
||||
iutil.ipmi_report(constants.IPMI_ABORTED)
|
||||
sys.exit(1)
|
||||
|
||||
ipstr = ip
|
||||
@ -915,8 +785,7 @@ if __name__ == "__main__":
|
||||
initThreading()
|
||||
from pyanaconda.threads import threadMgr
|
||||
|
||||
import gettext
|
||||
_ = lambda x: gettext.ldgettext("anaconda", x)
|
||||
from pyanaconda.i18n import _
|
||||
|
||||
from pyanaconda import constants
|
||||
from pyanaconda.addons import collect_addon_paths
|
||||
@ -950,7 +819,7 @@ if __name__ == "__main__":
|
||||
# see if we're on s390x and if we've got an ssh connection
|
||||
uname = os.uname()
|
||||
if uname[4] == 's390x':
|
||||
if 'TMUX' not in os.environ and not flags.ksprompt and not flags.imageInstall:
|
||||
if 'TMUX' not in os.environ and 'ks' not in flags.cmdline and not flags.imageInstall:
|
||||
prompt_for_ssh()
|
||||
sys.exit(0)
|
||||
|
||||
@ -969,12 +838,13 @@ if __name__ == "__main__":
|
||||
|
||||
from pyanaconda import isys
|
||||
|
||||
import string
|
||||
|
||||
from pyanaconda import iutil
|
||||
|
||||
iutil.ipmi_report(constants.IPMI_STARTED)
|
||||
|
||||
if opts.images and opts.dirinstall:
|
||||
stdoutLog.error("--images and --dirinstall cannot be used at the same time")
|
||||
iutil.ipmi_report(constants.IPMI_ABORTED)
|
||||
sys.exit(1)
|
||||
elif opts.dirinstall:
|
||||
if opts.dirinstall is True:
|
||||
@ -1031,20 +901,97 @@ if __name__ == "__main__":
|
||||
|
||||
from pyanaconda.anaconda import Anaconda
|
||||
anaconda = Anaconda()
|
||||
iutil.setup_translations(gettext)
|
||||
iutil.setup_translations()
|
||||
|
||||
# reset python's default SIGINT handler
|
||||
signal.signal(signal.SIGINT, signal.SIG_IGN)
|
||||
signal.signal(signal.SIGSEGV, isys.handleSegv)
|
||||
signal.signal(signal.SIGTERM, lambda num, frame: sys.exit(1))
|
||||
|
||||
# synchronously-delivered signals such as SIGSEGV and SIGILL cannot be
|
||||
# handled properly from python, so install signal handlers from the C
|
||||
# function in isys.
|
||||
isys.installSyncSignalHandlers()
|
||||
|
||||
setupEnvironment()
|
||||
|
||||
# make sure we have /var/log soon, some programs fail to start without it
|
||||
iutil.mkdirChain("/var/log")
|
||||
|
||||
pidfile = open("/var/run/anaconda.pid", "w")
|
||||
pidfile.write("%s\n" % (os.getpid(),))
|
||||
del pidfile
|
||||
# Share these with the exit handler, installed later
|
||||
pidfile_path = '/var/run/anaconda.pid'
|
||||
pidfile_created = False
|
||||
|
||||
# Look for a stale pid file
|
||||
try:
|
||||
with open(pidfile_path, 'r') as pidfile:
|
||||
pid = int(pidfile.read())
|
||||
except IOError as e:
|
||||
# Ignore errors due to the file not existing. Other errors mean (most
|
||||
# likely) that we're not running as root, there's a filesystem error,
|
||||
# or someone filled our PID file with garbage, so just let those be
|
||||
# raised.
|
||||
if e.errno != errno.ENOENT:
|
||||
raise
|
||||
else:
|
||||
# Is the PID still running?
|
||||
if not os.path.isdir("/proc/%s" % pid):
|
||||
log.info("Removing stale PID file: %s no longer running", pid)
|
||||
os.unlink(pidfile_path)
|
||||
# Is the PID anaconda?
|
||||
else:
|
||||
try:
|
||||
with open("/proc/%s/stat" % pid, "r") as pidstat:
|
||||
# The part we care about is in the start, "PID (name) ..."
|
||||
procname = pidstat.read().split(' ', 2)[1]
|
||||
if procname != "(anaconda)":
|
||||
log.info("Removing stale PID file: PID %s is now %s", pid, procname)
|
||||
os.unlink(pidfile_path)
|
||||
# If it is anaconda, let the pidfile creation below fail
|
||||
# and print an error
|
||||
except IOError as e:
|
||||
# Ignore failures due to the file not existing in case the
|
||||
# process ended while we were trying to read about it. Assume
|
||||
# in this case that the process was another anaconda instance,
|
||||
# and the PID file was cleaned up.
|
||||
# If the process ended between open and read, we'll get ESRCH
|
||||
if e.errno not in (errno.ENOENT, errno.ESRCH):
|
||||
raise
|
||||
|
||||
# Attempt to create the pidfile
|
||||
try:
|
||||
# Set all of the read/write bits and let umask make it make sense
|
||||
pidfile = iutil.eintr_retry_call(os.open, pidfile_path, os.O_WRONLY|os.O_CREAT|os.O_EXCL,
|
||||
stat.S_IRUSR|stat.S_IWUSR|stat.S_IRGRP|stat.S_IWGRP|stat.S_IROTH|stat.S_IWOTH)
|
||||
pidfile_created = True
|
||||
iutil.eintr_retry_call(os.write, pidfile, "%s\n" % os.getpid())
|
||||
iutil.eintr_retry_call(os.close, pidfile)
|
||||
except OSError as e:
|
||||
# If the failure was anything other than EEXIST during the open call,
|
||||
# just re-raise the exception
|
||||
if e.errno != errno.EEXIST:
|
||||
raise
|
||||
|
||||
log.error("%s already exists, exiting", pidfile_path)
|
||||
|
||||
# If we had a $DISPLAY at start and zenity is available, we may be
|
||||
# running in a live environment and we can display an error dialog.
|
||||
# Otherwise just print an error.
|
||||
if flags.preexisting_x11 and os.access("/usr/bin/zenity", os.X_OK):
|
||||
# The module-level _() calls are ok here because the language may
|
||||
# be set from the live environment in this case, and anaconda's
|
||||
# language setup hasn't happened yet.
|
||||
# pylint: disable=found-_-in-module-class
|
||||
iutil.execWithRedirect("zenity",
|
||||
["--error", "--title", _("Unable to create PID file"), "--text",
|
||||
_("Anaconda is unable to create %s because the file" +
|
||||
" already exists. Anaconda is already running, or a previous instance" +
|
||||
" of anaconda has crashed.") % pidfile_path])
|
||||
else:
|
||||
print("%s already exists, exiting" % pidfile_path)
|
||||
|
||||
iutil.ipmi_report(constants.IPMI_FAILED)
|
||||
sys.exit(1)
|
||||
|
||||
# add our own additional signal handlers
|
||||
signal.signal(signal.SIGHUP, startDebugger)
|
||||
|
||||
@ -1101,16 +1048,20 @@ if __name__ == "__main__":
|
||||
# text console with a traceback instead of being left looking at a blank
|
||||
# screen. python-meh will replace this excepthook with its own handler
|
||||
# once it gets going.
|
||||
if not flags.imageInstall and not flags.livecdInstall \
|
||||
and not flags.dirInstall:
|
||||
if can_touch_runtime_system("early exception handler"):
|
||||
def _earlyExceptionHandler(ty, value, traceback):
|
||||
iutil.ipmi_report(constants.IPMI_FAILED)
|
||||
iutil.vtActivate(1)
|
||||
return sys.__excepthook__(ty, value, traceback)
|
||||
|
||||
sys.excepthook = _earlyExceptionHandler
|
||||
|
||||
if can_touch_runtime_system("start audit daemon"):
|
||||
startAuditDaemon()
|
||||
# auditd will turn into a daemon and exit. Ignore startup errors
|
||||
try:
|
||||
iutil.execWithRedirect("/sbin/auditd", [])
|
||||
except OSError:
|
||||
pass
|
||||
|
||||
# setup links required for all install types
|
||||
for i in ("services", "protocols", "nsswitch.conf", "joe", "selinux",
|
||||
@ -1124,7 +1075,7 @@ if __name__ == "__main__":
|
||||
log.info("anaconda called with cmdline = %s", sys.argv)
|
||||
log.info("Default encoding = %s ", sys.getdefaultencoding())
|
||||
|
||||
os.system("udevadm control --env=ANACONDA=1")
|
||||
iutil.execWithRedirect("udevadm", ["control", "--env=ANACONDA=1"])
|
||||
|
||||
# Collect all addon paths
|
||||
addon_paths = collect_addon_paths(constants.ADDON_PATHS)
|
||||
@ -1134,6 +1085,11 @@ if __name__ == "__main__":
|
||||
# shipped with the installation media.
|
||||
ksdata = None
|
||||
if opts.ksfile and not opts.liveinst:
|
||||
if not os.path.exists(opts.ksfile):
|
||||
stdoutLog.error("Kickstart file %s is missing.", opts.ksfile)
|
||||
iutil.ipmi_report(constants.IPMI_ABORTED)
|
||||
sys.exit(1)
|
||||
|
||||
flags.automatedInstall = True
|
||||
flags.eject = False
|
||||
ksFiles = [opts.ksfile]
|
||||
@ -1197,14 +1153,14 @@ if __name__ == "__main__":
|
||||
log.info("Failed to parse proxy \"%s\": %s", anaconda.proxy, e)
|
||||
else:
|
||||
# Set environmental variables to be used by pre/post scripts
|
||||
os.environ["PROXY"] = proxy.noauth_url
|
||||
os.environ["PROXY_USER"] = proxy.username or ""
|
||||
os.environ["PROXY_PASSWORD"] = proxy.password or ""
|
||||
iutil.setenv("PROXY", proxy.noauth_url)
|
||||
iutil.setenv("PROXY_USER", proxy.username or "")
|
||||
iutil.setenv("PROXY_PASSWORD", proxy.password or "")
|
||||
|
||||
# Variables used by curl, libreport, etc.
|
||||
os.environ["http_proxy"] = proxy.url
|
||||
os.environ["ftp_proxy"] = proxy.url
|
||||
os.environ["HTTPS_PROXY"] = proxy.url
|
||||
iutil.setenv("http_proxy", proxy.url)
|
||||
iutil.setenv("ftp_proxy", proxy.url)
|
||||
iutil.setenv("HTTPS_PROXY", proxy.url)
|
||||
|
||||
if flags.noverifyssl:
|
||||
ksdata.method.noverifyssl = flags.noverifyssl
|
||||
@ -1263,34 +1219,57 @@ if __name__ == "__main__":
|
||||
from pyanaconda import localization
|
||||
# Set the language before loading an interface, when it may be too late.
|
||||
|
||||
# check if the LANG environmental variable is set
|
||||
env_lang = os.environ.get("LANG")
|
||||
if env_lang is not None:
|
||||
# parse it using langtable
|
||||
env_langs = localization.get_language_locales(env_lang)
|
||||
# if parsed LANG is the same as our default language - ignore it;
|
||||
# otherwise use it as valid language candidate
|
||||
if env_langs and env_langs[0] != constants.DEFAULT_LANG:
|
||||
env_lang = env_langs[0] # the first language is the best match
|
||||
else:
|
||||
env_lang = None
|
||||
# GNU defines four (four!) ways to set the locale via the environment.
|
||||
# At least three of those are just going to get in the way of anaconda's
|
||||
# ability to set the language and locale after startup. If any of, in
|
||||
# order, $LANGUAGE, $LC_ALL, or $LC_MESSAGES is in the environment, copy
|
||||
# the information to $LANG, and then clear the rest.
|
||||
for varname in ("LANGUAGE", "LC_ALL", "LC_MESSAGES"):
|
||||
if varname in os.environ:
|
||||
os.environ["LANG"] = os.environ[varname] # pylint: disable=environment-modify
|
||||
break
|
||||
|
||||
requested_lang = opts.lang or ksdata.lang.lang or env_lang
|
||||
for varname in ("LANGUAGE", "LC_ALL", "LC_MESSAGES"):
|
||||
if varname in os.environ:
|
||||
del os.environ[varname] # pylint: disable=environment-modify
|
||||
|
||||
if requested_lang:
|
||||
locales = localization.get_language_locales(requested_lang)
|
||||
if locales:
|
||||
localization.setup_locale(locales[0], ksdata.lang)
|
||||
ksdata.lang.seen = True
|
||||
else:
|
||||
log.error("Invalid locale '%s' given on command line or in kickstart", requested_lang)
|
||||
# first, try to load firmware language if nothing is already set in
|
||||
# the environment
|
||||
if "LANG" not in os.environ:
|
||||
localization.load_firmware_language(ksdata.lang)
|
||||
|
||||
# If command line options or kickstart set LANG, override the environment
|
||||
if opts.lang:
|
||||
os.environ["LANG"] = opts.lang # pylint: disable=environment-modify
|
||||
ksdata.lang.seen = True
|
||||
elif ksdata.lang.lang:
|
||||
os.environ["LANG"] = ksdata.lang.lang # pylint: disable=environment-modify
|
||||
|
||||
# Make sure LANG is set to something
|
||||
if "LANG" not in os.environ:
|
||||
os.environ["LANG"] = constants.DEFAULT_LANG # pylint: disable=environment-modify
|
||||
|
||||
# parse it using langtable and update the environment
|
||||
# If langtable returns no locales, fall back to the default
|
||||
env_langs = localization.get_language_locales(os.environ["LANG"])
|
||||
if env_langs:
|
||||
# the first language is the best match
|
||||
os.environ["LANG"] = env_langs[0] # pylint: disable=environment-modify
|
||||
else:
|
||||
# no kickstart or bootoption - use default
|
||||
localization.setup_locale(constants.DEFAULT_LANG, ksdata.lang)
|
||||
log.error("Invalid locale '%s' given on command line or in kickstart", os.environ["LANG"])
|
||||
os.environ["LANG"] = constants.DEFAULT_LANG # pylint: disable=environment-modify
|
||||
|
||||
localization.setup_locale(os.environ["LANG"], ksdata.lang)
|
||||
|
||||
import blivet
|
||||
blivet.enable_installer_mode()
|
||||
|
||||
# Initialize the network now, in case the display needs it
|
||||
from pyanaconda.network import networkInitialize, wait_for_connecting_NM_thread
|
||||
|
||||
networkInitialize(ksdata)
|
||||
threadMgr.add(AnacondaThread(name=constants.THREAD_WAIT_FOR_CONNECTING_NM, target=wait_for_connecting_NM_thread, args=(ksdata,)))
|
||||
|
||||
# now start the interface
|
||||
setupDisplay(anaconda, opts, addon_paths)
|
||||
|
||||
@ -1323,15 +1302,14 @@ if __name__ == "__main__":
|
||||
flags.imageInstall = True
|
||||
except ValueError as e:
|
||||
stdoutLog.error("error specifying image file: %s", e)
|
||||
iutil.ipmi_report(constants.IPMI_ABORTED)
|
||||
sys.exit(1)
|
||||
|
||||
if image_count:
|
||||
anaconda.storage.setupDiskImages()
|
||||
|
||||
# only install interactive exception handler in interactive modes
|
||||
if ksdata.displaymode.displayMode != DISPLAY_MODE_CMDLINE or flags.debug:
|
||||
from pyanaconda import exception
|
||||
anaconda.mehConfig = exception.initExceptionHandling(anaconda)
|
||||
from pyanaconda import exception
|
||||
anaconda.mehConfig = exception.initExceptionHandling(anaconda)
|
||||
|
||||
# add our own additional signal handlers
|
||||
signal.signal(signal.SIGUSR1, lambda signum, frame:
|
||||
@ -1339,9 +1317,8 @@ if __name__ == "__main__":
|
||||
signal.signal(signal.SIGUSR2, lambda signum, frame: anaconda.dumpState())
|
||||
atexit.register(exitHandler, ksdata.reboot, anaconda.storage)
|
||||
|
||||
from blivet import storageInitialize
|
||||
from blivet.osinstall import storageInitialize
|
||||
from pyanaconda.packaging import payloadMgr
|
||||
from pyanaconda.network import networkInitialize, wait_for_connecting_NM_thread
|
||||
from pyanaconda.timezone import time_initialize
|
||||
|
||||
if flags.rescue_mode:
|
||||
@ -1349,14 +1326,12 @@ if __name__ == "__main__":
|
||||
else:
|
||||
cleanPStore()
|
||||
|
||||
networkInitialize(ksdata)
|
||||
if not flags.dirInstall:
|
||||
threadMgr.add(AnacondaThread(name=constants.THREAD_STORAGE, target=storageInitialize,
|
||||
args=(anaconda.storage, ksdata, anaconda.protected)))
|
||||
threadMgr.add(AnacondaThread(name=constants.THREAD_TIME_INIT, target=time_initialize,
|
||||
args=(ksdata.timezone, anaconda.storage, anaconda.bootloader)))
|
||||
|
||||
threadMgr.add(AnacondaThread(name=constants.THREAD_WAIT_FOR_CONNECTING_NM, target=wait_for_connecting_NM_thread, args=(ksdata,)))
|
||||
|
||||
# Fallback to default for interactive or for a kickstart with no installation method.
|
||||
fallback = not (flags.automatedInstall and ksdata.method.method)
|
||||
@ -1390,14 +1365,12 @@ if __name__ == "__main__":
|
||||
# setup ntp servers and start NTP daemon if not requested otherwise
|
||||
if can_touch_runtime_system("start chronyd"):
|
||||
if anaconda.ksdata.timezone.ntpservers:
|
||||
ntp.save_servers_to_config(anaconda.ksdata.timezone.ntpservers)
|
||||
pools, servers = ntp.internal_to_pools_and_servers(anaconda.ksdata.timezone.ntpservers)
|
||||
ntp.save_servers_to_config(pools, servers)
|
||||
|
||||
if not anaconda.ksdata.timezone.nontp:
|
||||
iutil.start_service("chronyd")
|
||||
|
||||
# try to load firmware language
|
||||
localization.load_firmware_language(ksdata.lang)
|
||||
|
||||
# FIXME: This will need to be made cleaner once this file starts to take
|
||||
# shape with the new UI code.
|
||||
anaconda._intf.setup(ksdata)
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -20,7 +20,7 @@
|
||||
m4_define(python_required_version, 2.5)
|
||||
|
||||
AC_PREREQ([2.63])
|
||||
AC_INIT([anaconda], [21.48.21], [anaconda-devel-list@redhat.com])
|
||||
AC_INIT([anaconda], [22.20.13], [anaconda-devel-list@redhat.com])
|
||||
AM_INIT_AUTOMAKE([foreign no-dist-gzip dist-bzip2 tar-ustar])
|
||||
|
||||
AC_CONFIG_HEADERS([config.h])
|
||||
@ -29,13 +29,12 @@ AC_CONFIG_MACRO_DIR([m4])
|
||||
AC_DEFINE_UNQUOTED([BUILD_DATE], ["`date +%m%d%Y`"], [Date of anaconda build])
|
||||
AM_SILENT_RULES([yes]) # make --enable-silent-rules the default.
|
||||
|
||||
AC_USE_SYSTEM_EXTENSIONS
|
||||
AC_SYS_LARGEFILE
|
||||
|
||||
# Checks for programs.
|
||||
AC_PROG_AWK
|
||||
AC_PROG_GREP
|
||||
AC_PROG_CC
|
||||
AC_PROG_INSTALL
|
||||
AC_PROG_LN_S
|
||||
AC_PROG_MAKE_SET
|
||||
AC_PROG_LIBTOOL
|
||||
AC_PROG_MKDIR_P
|
||||
|
||||
@ -45,7 +44,7 @@ AC_PROG_MKDIR_P
|
||||
AC_PATH_PROG([INTLTOOL_EXTRACT], [intltool-extract])
|
||||
AC_PATH_PROG([INTLTOOL_MERGE], [intltool-merge])
|
||||
AS_IF([test -z "$INTLTOOL_EXTRACT" -o -z "$INTLTOOL_MERGE"],
|
||||
[AC_MSG_ERROR([*** intltool not found])])
|
||||
[ANACONDA_SOFT_FAILURE([intltool not found])])
|
||||
|
||||
# Add the bits for Makefile rules
|
||||
INTLTOOL_V_MERGE='$(INTLTOOL__v_MERGE_$(V))'
|
||||
@ -69,10 +68,9 @@ AM_GNU_GETTEXT([external])
|
||||
AM_GNU_GETTEXT_VERSION([0.18.3])
|
||||
|
||||
# Checks for header files.
|
||||
AC_PATH_X
|
||||
AC_CHECK_HEADERS([fcntl.h stdlib.h string.h sys/time.h unistd.h],
|
||||
[],
|
||||
[AC_MSG_FAILURE([*** Header file $ac_header not found.])],
|
||||
[ANACONDA_SOFT_FAILURE([Header file $ac_header not found.])],
|
||||
[])
|
||||
|
||||
# Checks for typedefs, structures, and compiler characteristics.
|
||||
@ -86,7 +84,10 @@ AC_TYPE_INT64_T
|
||||
AC_FUNC_FORK
|
||||
AC_CHECK_FUNCS([getcwd memset mkdir strchr strdup],
|
||||
[],
|
||||
[AC_MSG_FAILURE([*** Required function $ac_func not found.])])
|
||||
[ANACONDA_SOFT_FAILURE([Function $ac_func not found.])])
|
||||
|
||||
AC_CHECK_LIB([audit], [audit_open], [:],
|
||||
[ANACONDA_SOFT_FAILURE([libaudit not found])])
|
||||
|
||||
AM_PATH_PYTHON(python_required_version)
|
||||
|
||||
@ -98,69 +99,21 @@ PKG_CHECK_MODULES([PYTHON], [python], [
|
||||
AC_TRY_LINK_FUNC([Py_Initialize],
|
||||
[AC_MSG_RESULT([yes])],
|
||||
[AC_MSG_RESULT([no])
|
||||
AC_MSG_FAILURE([*** Unable to use python library])])
|
||||
ANACONDA_SOFT_FAILURE([Unable to use python library])])
|
||||
LIBS="$LIBS_save"
|
||||
],
|
||||
[AC_MSG_FAILURE([*** Unable to find python library])])
|
||||
[ANACONDA_SOFT_FAILURE([Unable to find python library])])
|
||||
|
||||
# Check for libraries we need that provide pkg-config scripts
|
||||
PKG_PROG_PKG_CONFIG([0.23])
|
||||
PKG_CHECK_MODULES([RPM], [rpm >= 4.10.0])
|
||||
PKG_CHECK_MODULES([LIBARCHIVE], [libarchive >= 3.0.4])
|
||||
|
||||
# Set $RPM_OPT_FLAGS if we don't have it
|
||||
if test -z $RPM_OPT_FLAGS ; then
|
||||
CFLAGS="$CFLAGS -g -pipe -Wp,-D_FORTIFY_SOURCE=2 -fexceptions"
|
||||
else
|
||||
CFLAGS="$CFLAGS $RPM_OPT_FLAGS"
|
||||
fi
|
||||
|
||||
# NFS support can, in theory, be enabled or disabled
|
||||
AC_ARG_ENABLE(nfs,
|
||||
AC_HELP_STRING([--enable-nfs],
|
||||
[enable NFS support (default is yes)]),
|
||||
[nfs=$enableval],
|
||||
[nfs=yes])
|
||||
|
||||
# IPv6 support can be enabled or disabled
|
||||
AC_ARG_ENABLE(ipv6,
|
||||
AC_HELP_STRING([--enable-ipv6],
|
||||
[enable IPv6 support (default is yes)]),
|
||||
[ipv6=$enableval],
|
||||
[ipv6=yes])
|
||||
if test x$ipv6 = xyes ; then
|
||||
AC_SUBST(IPV6_CFLAGS, [-DENABLE_IPV6])
|
||||
fi
|
||||
ANACONDA_PKG_CHECK_MODULES([RPM], [rpm >= 4.10.0])
|
||||
ANACONDA_PKG_CHECK_MODULES([LIBARCHIVE], [libarchive >= 3.0.4])
|
||||
|
||||
# GCC likes to bomb out on some ridiculous warnings. Add your favorites
|
||||
# here.
|
||||
SHUT_UP_GCC="-Wno-unused-result"
|
||||
|
||||
# Add remaining compiler flags we want to use
|
||||
CFLAGS="$CFLAGS -Wall -Werror $SHUT_UP_GCC -D_GNU_SOURCE -D_FILE_OFFSET_BITS=64 -D_LARGEFILE_SOURCE"
|
||||
|
||||
# Filter CFLAGS (remove duplicate flags)
|
||||
cflags_filter() {
|
||||
have=
|
||||
first=1
|
||||
for flag in $* ; do
|
||||
if test -z "`echo $have | grep -- $flag`" ; then
|
||||
if test x$first == x1 ; then
|
||||
first=2
|
||||
else
|
||||
echo -n " "
|
||||
fi
|
||||
echo -n $flag
|
||||
have="$have $flag"
|
||||
fi
|
||||
done
|
||||
}
|
||||
CFLAGS="`cflags_filter $CFLAGS`"
|
||||
|
||||
# Unset $(LIBS) because different programs and libraries will have different
|
||||
# lists of libraries to link with, we don't want everything linking against
|
||||
# all libraries we checked for.
|
||||
LIBS=
|
||||
CFLAGS="$CFLAGS -Wall -Werror $SHUT_UP_GCC"
|
||||
|
||||
# Get the release number from the spec file
|
||||
rel="`awk '/Release:/ { split($2, r, "%"); print r[[1]] }' $srcdir/anaconda.spec`"
|
||||
@ -186,8 +139,9 @@ AC_CONFIG_FILES([Makefile
|
||||
data/liveinst/gnome/Makefile
|
||||
data/liveinst/pam.d/Makefile
|
||||
data/systemd/Makefile
|
||||
data/help/Makefile
|
||||
data/help/en-US/Makefile
|
||||
data/window-manager/Makefile
|
||||
data/window-manager/config/Makefile
|
||||
data/window-manager/theme/Makefile
|
||||
po/Makefile.in
|
||||
scripts/Makefile
|
||||
pyanaconda/Makefile
|
||||
@ -201,15 +155,16 @@ AC_CONFIG_FILES([Makefile
|
||||
pyanaconda/ui/gui/spokes/Makefile
|
||||
pyanaconda/ui/gui/spokes/advstorage/Makefile
|
||||
pyanaconda/ui/gui/spokes/lib/Makefile
|
||||
pyanaconda/ui/gui/tools/Makefile
|
||||
pyanaconda/ui/gui/Makefile
|
||||
pyanaconda/ui/tui/hubs/Makefile
|
||||
pyanaconda/ui/tui/simpleline/Makefile
|
||||
pyanaconda/ui/tui/spokes/Makefile
|
||||
pyanaconda/ui/tui/tools/Makefile
|
||||
pyanaconda/ui/tui/Makefile
|
||||
data/post-scripts/Makefile
|
||||
tests/Makefile
|
||||
utils/Makefile
|
||||
utils/dd/Makefile])
|
||||
AC_OUTPUT
|
||||
|
||||
# Gently advise the user about the build failures they are about to encounter
|
||||
ANACONDA_FAILURES
|
||||
|
@ -1,272 +0,0 @@
|
||||
# configure.ac for anaconda
|
||||
#
|
||||
# Copyright (C) 2009 Red Hat, Inc.
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or modify
|
||||
# it under the terms of the GNU Lesser General Public License as published
|
||||
# by the Free Software Foundation; either version 2.1 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# This program 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 Lesser General Public License
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
#
|
||||
# Author: David Cantrell <dcantrell@redhat.com>
|
||||
|
||||
m4_define(python_required_version, 2.5)
|
||||
|
||||
AC_PREREQ([2.63])
|
||||
AC_INIT([anaconda], [20.25.16], [anaconda-devel-list@redhat.com])
|
||||
AM_INIT_AUTOMAKE([foreign no-dist-gzip dist-bzip2 tar-ustar])
|
||||
|
||||
AC_CONFIG_HEADERS([config.h])
|
||||
AC_CONFIG_MACRO_DIR([m4])
|
||||
|
||||
AC_DEFINE_UNQUOTED([BUILD_DATE], ["`date +%m%d%Y`"], [Date of anaconda build])
|
||||
AM_SILENT_RULES([yes]) # make --enable-silent-rules the default.
|
||||
|
||||
# Checks for programs.
|
||||
AC_PROG_AWK
|
||||
AC_PROG_GREP
|
||||
AC_PROG_CC
|
||||
AC_PROG_INSTALL
|
||||
AC_PROG_LN_S
|
||||
AC_PROG_MAKE_SET
|
||||
AC_PROG_LIBTOOL
|
||||
|
||||
# Check for the intltool programs
|
||||
# These checks and subsitutions are adapted IT_PROG_INTLTOOL provided in
|
||||
# intltool.m4, but without the parts where it breaks gettext.
|
||||
AC_PATH_PROG([INTLTOOL_EXTRACT], [intltool-extract])
|
||||
AC_PATH_PROG([INTLTOOL_MERGE], [intltool-merge])
|
||||
AS_IF([test -z "$INTLTOOL_EXTRACT" -o -z "$INTLTOOL_MERGE"],
|
||||
[AC_MSG_ERROR([*** intltool not found])])
|
||||
|
||||
# Add the bits for Makefile rules
|
||||
INTLTOOL_V_MERGE='$(INTLTOOL__v_MERGE_$(V))'
|
||||
INTLTOOL__v_MERGE_='$(INTLTOOL__v_MERGE_$(AM_DEFAULT_VERBOSITY))'
|
||||
INTLTOOL__v_MERGE_0='@echo " ITMRG " $@;'
|
||||
INTLTOOL_V_MERGE_OPTIONS='$(intltool__v_merge_options_$(V))'
|
||||
intltool__v_merge_options_='$(intltool__v_merge_options_$(AM_DEFAULT_VERBOSITY))'
|
||||
intltool__v_merge_options_0='-q'
|
||||
AC_SUBST(INTLTOOL_V_MERGE)
|
||||
AC_SUBST(INTLTOOL__v_MERGE_)
|
||||
AC_SUBST(INTLTOOL__v_MERGE_0)
|
||||
AC_SUBST(INTLTOOL_V_MERGE_OPTIONS)
|
||||
AC_SUBST(intltool__v_merge_options_)
|
||||
AC_SUBST(intltool__v_merge_options_0)
|
||||
|
||||
INTLTOOL_DESKTOP_RULE='%.desktop: %.desktop.in $(INTLTOOL_MERGE) $(wildcard $(top_srcdir)/po/*.po) ; $(INTLTOOL_V_MERGE)LC_ALL=C $(INTLTOOL_MERGE) $(INTLTOOL_V_MERGE_OPTIONS) -d -u -c $(top_builddir)/po/.intltool-merge-cache $(top_srcdir)/po $< $@'
|
||||
AC_SUBST(INTLTOOL_DESKTOP_RULE)
|
||||
|
||||
AM_GNU_GETTEXT([external])
|
||||
AM_GNU_GETTEXT_VERSION([0.18.1])
|
||||
|
||||
# Checks for libraries.
|
||||
AC_CHECK_LIB([X11], [XGetWindowAttributes],
|
||||
[AC_SUBST(X11_LIBS, [-lX11])],
|
||||
[AC_MSG_FAILURE([*** libX11 not usable.])])
|
||||
|
||||
AC_CHECK_LIB([audit], [audit_open],
|
||||
[AC_SUBST(AUDIT_LIBS, [-laudit])],
|
||||
[AC_MSG_FAILURE([*** libaudit not usable.])])
|
||||
|
||||
AC_CHECK_LIB([z], [zlibVersion],
|
||||
[AC_SUBST(ZLIB_LIBS, [-lz])],
|
||||
[AC_MSG_FAILURE([*** libz not usable.])])
|
||||
|
||||
# Checks for header files.
|
||||
AC_PATH_X
|
||||
AC_FUNC_ALLOCA
|
||||
AC_HEADER_RESOLV
|
||||
AC_HEADER_MAJOR
|
||||
AC_CHECK_HEADERS([argz.h arpa/inet.h fcntl.h inttypes.h libintl.h limits.h \
|
||||
malloc.h netdb.h netinet/in.h stddef.h stdint.h stdlib.h \
|
||||
string.h strings.h sys/ioctl.h sys/mount.h sys/param.h \
|
||||
sys/socket.h sys/time.h sys/vfs.h syslog.h termios.h \
|
||||
unistd.h utime.h wchar.h],
|
||||
[],
|
||||
[AC_MSG_FAILURE([*** Header file $ac_header not found.])],
|
||||
[])
|
||||
|
||||
# Checks for typedefs, structures, and compiler characteristics.
|
||||
AC_TYPE_UID_T
|
||||
AC_C_INLINE
|
||||
AC_TYPE_INT32_T
|
||||
AC_TYPE_MODE_T
|
||||
AC_TYPE_OFF_T
|
||||
AC_TYPE_PID_T
|
||||
AC_TYPE_SIZE_T
|
||||
AC_TYPE_SSIZE_T
|
||||
AC_CHECK_MEMBERS([struct stat.st_rdev])
|
||||
AC_TYPE_UINT16_T
|
||||
AC_TYPE_UINT32_T
|
||||
AC_TYPE_UINT64_T
|
||||
AC_TYPE_UINT8_T
|
||||
AC_TYPE_INT64_T
|
||||
|
||||
# Checks for library functions.
|
||||
AC_FUNC_CHOWN
|
||||
AC_FUNC_ERROR_AT_LINE
|
||||
AC_FUNC_FORK
|
||||
AC_FUNC_LSTAT_FOLLOWS_SLASHED_SYMLINK
|
||||
AC_FUNC_MALLOC
|
||||
AC_FUNC_MMAP
|
||||
AC_FUNC_REALLOC
|
||||
AC_CHECK_FUNCS([dup2 fdatasync ftruncate getcwd gethostbyname gettimeofday \
|
||||
lchown memmove memset mkdir mkfifo munmap realpath select \
|
||||
setenv sethostname socket strcasecmp strchr strcspn strdup \
|
||||
strerror strncasecmp strndup strrchr strstr strtol strtoul \
|
||||
strverscmp uname utime wcwidth],
|
||||
[],
|
||||
[AC_MSG_FAILURE([*** Required function $ac_func not found.])])
|
||||
|
||||
AM_PATH_PYTHON(python_required_version)
|
||||
|
||||
# Check for the python extension paths
|
||||
PKG_CHECK_MODULES([PYTHON], [python], [
|
||||
LIBS_save="$LIBS"
|
||||
LIBS="$LIBS $PYTHON_LIBS"
|
||||
AC_MSG_CHECKING([Python libraries])
|
||||
AC_TRY_LINK_FUNC([Py_Initialize],
|
||||
[AC_MSG_RESULT([yes])],
|
||||
[AC_MSG_RESULT([no])
|
||||
AC_MSG_FAILURE([*** Unable to use python library])])
|
||||
LIBS="$LIBS_save"
|
||||
],
|
||||
[AC_MSG_FAILURE([*** Unable to find python library])])
|
||||
|
||||
# Check for libraries we need that provide pkg-config scripts
|
||||
PKG_PROG_PKG_CONFIG([0.23])
|
||||
PKG_CHECK_MODULES([X11], [x11 >= 1.3])
|
||||
PKG_CHECK_MODULES([XCOMPOSITE], [xcomposite >= 0.4.1])
|
||||
PKG_CHECK_MODULES([GLIB], [glib-2.0 >= 2.16.1])
|
||||
PKG_CHECK_MODULES([GTK_X11], [gtk+-x11-3.0 >= 3.0])
|
||||
PKG_CHECK_MODULES([GDK], [gdk-3.0])
|
||||
PKG_CHECK_MODULES([NETWORKMANAGER], [NetworkManager >= 0.7.1])
|
||||
PKG_CHECK_MODULES([LIBNL], [libnl-1 >= 1.0])
|
||||
PKG_CHECK_MODULES([LIBNM_GLIB], [libnm-glib >= 0.7.1 libnm-util >= 0.7.1])
|
||||
PKG_CHECK_MODULES([RPM], [rpm >= 4.10.0])
|
||||
PKG_CHECK_MODULES([LIBARCHIVE], [libarchive >= 3.0.4])
|
||||
|
||||
# Set $RPM_OPT_FLAGS if we don't have it
|
||||
if test -z $RPM_OPT_FLAGS ; then
|
||||
CFLAGS="$CFLAGS -g -pipe -Wp,-D_FORTIFY_SOURCE=2 -fexceptions"
|
||||
else
|
||||
CFLAGS="$CFLAGS $RPM_OPT_FLAGS"
|
||||
fi
|
||||
|
||||
# NFS support can, in theory, be enabled or disabled
|
||||
AC_ARG_ENABLE(nfs,
|
||||
AC_HELP_STRING([--enable-nfs],
|
||||
[enable NFS support (default is yes)]),
|
||||
[nfs=$enableval],
|
||||
[nfs=yes])
|
||||
|
||||
# IPv6 support can be enabled or disabled
|
||||
AC_ARG_ENABLE(ipv6,
|
||||
AC_HELP_STRING([--enable-ipv6],
|
||||
[enable IPv6 support (default is yes)]),
|
||||
[ipv6=$enableval],
|
||||
[ipv6=yes])
|
||||
if test x$ipv6 = xyes ; then
|
||||
AC_SUBST(IPV6_CFLAGS, [-DENABLE_IPV6])
|
||||
fi
|
||||
|
||||
# GCC likes to bomb out on some ridiculous warnings. Add your favorites
|
||||
# here.
|
||||
SHUT_UP_GCC="-Wno-unused-result"
|
||||
|
||||
# Add remaining compiler flags we want to use
|
||||
CFLAGS="$CFLAGS -Wall -Werror $SHUT_UP_GCC -D_GNU_SOURCE -D_FILE_OFFSET_BITS=64 -D_LARGEFILE_SOURCE"
|
||||
|
||||
# Filter CFLAGS (remove duplicate flags)
|
||||
cflags_filter() {
|
||||
have=
|
||||
first=1
|
||||
for flag in $* ; do
|
||||
if test -z "`echo $have | grep -- $flag`" ; then
|
||||
if test x$first == x1 ; then
|
||||
first=2
|
||||
else
|
||||
echo -n " "
|
||||
fi
|
||||
echo -n $flag
|
||||
have="$have $flag"
|
||||
fi
|
||||
done
|
||||
}
|
||||
CFLAGS="`cflags_filter $CFLAGS`"
|
||||
|
||||
# Unset $(LIBS) because different programs and libraries will have different
|
||||
# lists of libraries to link with, we don't want everything linking against
|
||||
# all libraries we checked for.
|
||||
LIBS=
|
||||
|
||||
# Get the release number from the spec file
|
||||
rel="`awk '/Release:/ { split($2, r, "%"); print r[[1]] }' $srcdir/anaconda.spec`"
|
||||
AC_SUBST(PACKAGE_RELEASE, [$rel])
|
||||
|
||||
# Perform arch related tests
|
||||
AC_CANONICAL_BUILD
|
||||
s_arch="`echo $build_cpu | sed -e s/i.86/i386/ -e s/powerpc.*/ppc/`"
|
||||
|
||||
AM_CONDITIONAL(IS_LIVEINST_ARCH,
|
||||
[test x$s_arch = xppc || test x$s_arch = xi386 || test x$s_arch = xx86_64])
|
||||
|
||||
AC_CONFIG_SUBDIRS([widgets])
|
||||
|
||||
AC_CONFIG_FILES([Makefile
|
||||
data/Makefile
|
||||
data/command-stubs/Makefile
|
||||
docs/Makefile
|
||||
dracut/Makefile
|
||||
pyanaconda/installclasses/Makefile
|
||||
data/liveinst/Makefile
|
||||
data/liveinst/console.apps/Makefile
|
||||
data/liveinst/gnome/Makefile
|
||||
data/liveinst/pam.d/Makefile
|
||||
data/pixmaps/Makefile
|
||||
data/icons/Makefile
|
||||
data/icons/hicolor/Makefile
|
||||
data/icons/hicolor/16x16/Makefile
|
||||
data/icons/hicolor/16x16/apps/Makefile
|
||||
data/icons/hicolor/22x22/Makefile
|
||||
data/icons/hicolor/22x22/apps/Makefile
|
||||
data/icons/hicolor/24x24/Makefile
|
||||
data/icons/hicolor/24x24/apps/Makefile
|
||||
data/icons/hicolor/32x32/Makefile
|
||||
data/icons/hicolor/32x32/apps/Makefile
|
||||
data/icons/hicolor/48x48/Makefile
|
||||
data/icons/hicolor/48x48/apps/Makefile
|
||||
data/icons/hicolor/256x256/Makefile
|
||||
data/icons/hicolor/256x256/apps/Makefile
|
||||
data/systemd/Makefile
|
||||
po/Makefile.in
|
||||
scripts/Makefile
|
||||
pyanaconda/Makefile
|
||||
pyanaconda/isys/Makefile
|
||||
pyanaconda/packaging/Makefile
|
||||
pyanaconda/ui/Makefile
|
||||
pyanaconda/ui/lib/Makefile
|
||||
pyanaconda/ui/gui/categories/Makefile
|
||||
pyanaconda/ui/gui/hubs/Makefile
|
||||
pyanaconda/ui/gui/spokes/Makefile
|
||||
pyanaconda/ui/gui/spokes/advstorage/Makefile
|
||||
pyanaconda/ui/gui/spokes/lib/Makefile
|
||||
pyanaconda/ui/gui/tools/Makefile
|
||||
pyanaconda/ui/gui/Makefile
|
||||
pyanaconda/ui/tui/hubs/Makefile
|
||||
pyanaconda/ui/tui/simpleline/Makefile
|
||||
pyanaconda/ui/tui/spokes/Makefile
|
||||
pyanaconda/ui/tui/tools/Makefile
|
||||
pyanaconda/ui/tui/Makefile
|
||||
data/post-scripts/Makefile
|
||||
tests/Makefile
|
||||
utils/Makefile
|
||||
utils/dd/Makefile])
|
||||
AC_OUTPUT
|
@ -17,7 +17,7 @@
|
||||
#
|
||||
# Author: Martin Sivak <msivak@redhat.com>
|
||||
|
||||
SUBDIRS = command-stubs liveinst systemd post-scripts help
|
||||
SUBDIRS = command-stubs liveinst systemd post-scripts window-manager
|
||||
|
||||
CLEANFILES = *~
|
||||
|
||||
|
@ -160,11 +160,9 @@ AnacondaSpokeWindow #nav-box {
|
||||
|
||||
/* These rules were removed when the Adwaita theme moved from
|
||||
* gnome-themes-standard to gtk. The selectors had been wildcards, but after
|
||||
* the move they were replaced with more specific selectors, because gtk is
|
||||
* maintained by garbage people who don't care about how anyone else's
|
||||
* applications look. We need to apply the old style to anconda's custom
|
||||
* widgets in order for the selection highlight and insensitive shading to
|
||||
* appear.
|
||||
* the move they were replaced with more specific selectors. We need to apply
|
||||
* the old style to anconda's custom widgets in order for the selection
|
||||
* highlight and insensitive shading to appear.
|
||||
*/
|
||||
@define-color anaconda_selected_bg_color #4a90d9;
|
||||
@define-color anaconda_selected_fg_color #ffffff;
|
||||
@ -200,3 +198,9 @@ AnacondaSpokeSelector:insensitive {
|
||||
GtkTreeView.solid-separator {
|
||||
-GtkTreeView-horizontal-separator: 0;
|
||||
}
|
||||
|
||||
/* Set the layout indicator colors */
|
||||
AnacondaLayoutIndicator {
|
||||
background-color: #fdfdfd;
|
||||
color: black;
|
||||
}
|
||||
|
@ -223,11 +223,16 @@ installed OS will be booted. /etc/grub.d/40_custom can be used with
|
||||
manually created menuentrys which can use configfile to point to the
|
||||
grub.cfg on the newly installed OS.
|
||||
|
||||
dnf
|
||||
Use the experimental DNF package management backend instead of the YUM backend
|
||||
that is used by default. For more information about the DNF project see:
|
||||
nodnf
|
||||
Don't use the DNF package management backend (default since F22) and
|
||||
use the legacy YUM backend instead.
|
||||
For more information about the DNF project see:
|
||||
http://dnf.baseurl.org
|
||||
|
||||
mpathfriendlynames
|
||||
Tell multipathd to use user friendly names when naming devices during the installation.
|
||||
See the multipathd documentation for more info.
|
||||
|
||||
remotelog
|
||||
Send all the logs to a remote host:port using a TCP connection. The connection will
|
||||
be retried if there is no listener (ie. won't block the installation).
|
||||
|
@ -1,4 +1,4 @@
|
||||
#!/usr/bin/python
|
||||
#!/usr/bin/python2
|
||||
#
|
||||
# scan system for harddrives and output device name/size
|
||||
#
|
||||
@ -35,7 +35,7 @@ def main(argv):
|
||||
lst = list(lst)
|
||||
lst.sort()
|
||||
for dev, size in lst:
|
||||
print(dev, size)
|
||||
print("%s %s" % (dev, size))
|
||||
|
||||
if __name__ == "__main__":
|
||||
main(sys.argv)
|
||||
|
@ -1,21 +0,0 @@
|
||||
# data/Makefile.am for anaconda
|
||||
#
|
||||
# Copyright (C) 2014 Red Hat, Inc.
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or modify
|
||||
# it under the terms of the GNU Lesser General Public License as published
|
||||
# by the Free Software Foundation; either version 2.1 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# This program 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 Lesser General Public License
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
#
|
||||
# Author: Martin Kolman <mkolman@redhat.com>
|
||||
SUBDIRS = en-US
|
||||
|
||||
MAINTAINERCLEANFILES = Makefile.in
|
@ -1,26 +0,0 @@
|
||||
# data/Makefile.am for anaconda
|
||||
#
|
||||
# Copyright (C) 2014 Red Hat, Inc.
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or modify
|
||||
# it under the terms of the GNU Lesser General Public License as published
|
||||
# by the Free Software Foundation; either version 2.1 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# This program 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 Lesser General Public License
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
#
|
||||
# Author: Martin Kolman <mkolman@redhat.com>
|
||||
|
||||
enhelpcontentdir = $(datadir)/anaconda/help/en-US
|
||||
# The $(srcdir)/*.*ml expression matches both the *.html placeholders and *.xml help
|
||||
# content files. It also works around the fact that autotools complain if the xml files
|
||||
# are not present but $(srcdir)/*.xml is used.
|
||||
dist_enhelpcontent_DATA = $(srcdir)/*.*ml
|
||||
|
||||
MAINTAINERCLEANFILES = Makefile.in
|
@ -2,3 +2,10 @@
|
||||
# This is not loaded if a kickstart file is provided on the command line.
|
||||
auth --enableshadow --passalgo=sha512
|
||||
firstboot --enable
|
||||
|
||||
%anaconda
|
||||
# Default password policies
|
||||
pwpolicy root --notstrict --minlen=6 --minquality=50 --nochanges --emptyok
|
||||
pwpolicy user --notstrict --minlen=6 --minquality=50 --nochanges --emptyok
|
||||
pwpolicy luks --notstrict --minlen=6 --minquality=50 --nochanges --emptyok
|
||||
%end
|
||||
|
@ -31,6 +31,9 @@ dist_xinit_SCRIPTS = zz-liveinst.sh
|
||||
install-exec-local:
|
||||
$(MKDIR_P) $(DESTDIR)$(bindir)
|
||||
$(LN_S) consolehelper $(DESTDIR)$(bindir)/liveinst
|
||||
|
||||
uninstall-local:
|
||||
rm -f $(DESTDIR)$(bindir)/liveinst
|
||||
endif
|
||||
|
||||
EXTRA_DIST = README liveinst.desktop.in
|
||||
|
@ -18,8 +18,9 @@
|
||||
# Author: Kalev Lember <kalevlember@gmail.com>
|
||||
|
||||
welcomedir = $(datadir)/$(PACKAGE_NAME)/gnome
|
||||
dist_welcome_DATA = fedora-welcome.desktop install-button.png
|
||||
dist_welcome_DATA = install-button.png
|
||||
dist_welcome_SCRIPTS = fedora-welcome
|
||||
welcome_DATA = fedora-welcome.desktop
|
||||
|
||||
EXTRA_DIST = fedora-welcome.desktop.in
|
||||
|
||||
|
@ -77,7 +77,7 @@ fi
|
||||
|
||||
export ANACONDA_BUGURL=${ANACONDA_BUGURL:="https://bugzilla.redhat.com/bugzilla/"}
|
||||
|
||||
RELEASE=$(rpm -q --qf '%{Release}' fedora-release)
|
||||
RELEASE=$(rpm -q --qf '%{Release}' --whatprovides system-release)
|
||||
if [ "${RELEASE:0:2}" = "0." ]; then
|
||||
export ANACONDA_ISFINAL="false"
|
||||
else
|
||||
@ -85,6 +85,7 @@ else
|
||||
fi
|
||||
|
||||
export PATH=/sbin:/usr/sbin:$PATH
|
||||
export PYTHONPATH=/usr/share/anaconda/site-python
|
||||
|
||||
if [ -x /usr/sbin/getenforce ]; then
|
||||
current=$(/usr/sbin/getenforce)
|
||||
@ -154,7 +155,7 @@ if [ ! -z "$UPDATES" ]; then
|
||||
exit 1
|
||||
fi
|
||||
|
||||
curl -L -o /tmp/updates.img $UPDATES
|
||||
curl -o /tmp/updates.img $UPDATES
|
||||
|
||||
# We officially support two updates.img formats: a filesystem image, and
|
||||
# a compressed cpio blob.
|
||||
|
@ -7,6 +7,5 @@ Exec=/usr/bin/liveinst
|
||||
Terminal=false
|
||||
Type=Application
|
||||
Icon=anaconda
|
||||
Encoding=UTF-8
|
||||
StartupNotify=true
|
||||
NoDisplay=true
|
||||
|
@ -28,6 +28,7 @@ dist_systemd_DATA = anaconda.service \
|
||||
anaconda-shell@.service \
|
||||
instperf.service \
|
||||
anaconda-sshd.service \
|
||||
anaconda-nm-config.service \
|
||||
zram.service
|
||||
|
||||
dist_generator_SCRIPTS = anaconda-generator
|
||||
|
@ -11,7 +11,7 @@ Environment=HOME=/root MALLOC_CHECK_=2 MALLOC_PERTURB_=204 PATH=/usr/bin:/bin:/s
|
||||
Type=oneshot
|
||||
WorkingDirectory=/root
|
||||
ExecStart=/usr/sbin/anaconda
|
||||
StandardInput=null
|
||||
StandardInput=tty
|
||||
StandardOutput=journal+console
|
||||
StandardError=journal+console
|
||||
TimeoutSec=0
|
||||
|
@ -31,3 +31,5 @@ for tty in hvc0 hvc1 xvc0 hvsi0 hvsi1 hvsi2; do
|
||||
service_on_tty anaconda-shell@.service $tty
|
||||
fi
|
||||
done
|
||||
|
||||
ln -sf $systemd_dir/anaconda-nm-config.service $target_dir/anaconda-nm-config.service
|
||||
|
7
anaconda/data/systemd/anaconda-nm-config.service
Normal file
7
anaconda/data/systemd/anaconda-nm-config.service
Normal file
@ -0,0 +1,7 @@
|
||||
[Unit]
|
||||
ConditionKernelCommandLine=!ip=ibft
|
||||
Description=Anaconda NetworkManager configuration
|
||||
Before=NetworkManager.service
|
||||
|
||||
[Service]
|
||||
ExecStart=/usr/bin/anaconda-disable-nm-ibft-plugin
|
@ -1,12 +1,16 @@
|
||||
# tmux.conf for the anaconda environment
|
||||
|
||||
bind -n M-tab next
|
||||
bind -n F1 list-keys
|
||||
|
||||
set-option -s exit-unattached off
|
||||
set-option -g base-index 1
|
||||
set-option -g set-remain-on-exit on
|
||||
set-option -g history-limit 10000
|
||||
|
||||
new-session -s anaconda -n main "anaconda"
|
||||
|
||||
set-option status-right ""
|
||||
set-option status-right-length 0
|
||||
set-option status-right '#[fg=blue]#(echo -n "Switch tab: Alt+Tab | Help: F1 ")'
|
||||
|
||||
new-window -d -n shell "bash --login"
|
||||
new-window -d -n log "tail -F /tmp/anaconda.log"
|
||||
|
@ -1,4 +1,6 @@
|
||||
# Copyright (C) 2011 Red Hat, Inc.
|
||||
# data/window-manager/Makefile.am for anaconda
|
||||
#
|
||||
# Copyright (C) 2015 Red Hat, Inc.
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or modify
|
||||
# it under the terms of the GNU Lesser General Public License as published
|
||||
@ -13,8 +15,6 @@
|
||||
# You should have received a copy of the GNU Lesser General Public License
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
#
|
||||
# Author: Chris Lumens <clumens@redhat.com>
|
||||
# Author: David Shea <dshea@redhat.com>
|
||||
|
||||
EXTRA_DIST = README run-hub.py run-spoke.py
|
||||
|
||||
MAINTAINERCLEANFILES = Makefile.in
|
||||
SUBDIRS = config theme
|
39
anaconda/data/window-manager/config/Makefile.am
Normal file
39
anaconda/data/window-manager/config/Makefile.am
Normal file
@ -0,0 +1,39 @@
|
||||
# data/window-manager/config/Makefile.am for anaconda
|
||||
#
|
||||
# Copyright (C) 2015 Red Hat, Inc.
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or modify
|
||||
# it under the terms of the GNU Lesser General Public License as published
|
||||
# by the Free Software Foundation; either version 2.1 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# This program 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 Lesser General Public License
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
#
|
||||
# Author: David Shea <dshea@redhat.com>
|
||||
|
||||
schemadir = $(pkgdatadir)/window-manager/glib-2.0/schemas
|
||||
|
||||
# These files need to be compiled by glib-compile-schemas. This is handled
|
||||
# in the spec file scriptlets.
|
||||
dist_schema_DATA = org.gnome.desktop.wm.keybindings.gschema.override \
|
||||
org.gnome.desktop.wm.preferences.gschema.override
|
||||
|
||||
# GSettings insists on the override files being in the same directory as the
|
||||
# schemas they modify, so pretend that this is the case with symlinks and
|
||||
# create the compiled schema.
|
||||
install-data-hook:
|
||||
$(MKDIR_P) $(DESTDIR)$(schemadir)
|
||||
$(LN_S) -f /usr/share/glib-2.0/schemas/org.gnome.desktop.wm.keybindings.gschema.xml $(DESTDIR)$(schemadir)
|
||||
$(LN_S) -f /usr/share/glib-2.0/schemas/org.gnome.desktop.wm.preferences.gschema.xml $(DESTDIR)$(schemadir)
|
||||
$(LN_S) -f /usr/share/glib-2.0/schemas/org.gnome.desktop.enums.xml $(DESTDIR)$(schemadir)
|
||||
glib-compile-schemas $(DESTDIR)$(schemadir)
|
||||
|
||||
uninstall-local:
|
||||
rm -f $(DESTDIR)$(schemadir)/*.xml
|
||||
rm -f $(DESTDIR)$(schemadir)/gschemas.compiled
|
@ -0,0 +1,35 @@
|
||||
[org.gnome.desktop.wm.keybindings]
|
||||
switch-to-workspace-left=[]
|
||||
switch-to-workspace-right=[]
|
||||
switch-to-workspace-up=[]
|
||||
switch-to-workspace-down=[]
|
||||
switch-to-workspace-1=[]
|
||||
switch-to-workspace-last=[]
|
||||
switch-group=[]
|
||||
switch-windows=[]
|
||||
switch-panels=[]
|
||||
cycle-group=[]
|
||||
cycle-windows=[]
|
||||
cycle-panels=[]
|
||||
activate-window-menu=[]
|
||||
toggle-maximized=[]
|
||||
minimize=[]
|
||||
maximize=[]
|
||||
unmaximize=[]
|
||||
begin-move=[]
|
||||
begin-resize=[]
|
||||
move-to-workspace-1=[]
|
||||
move-to-workspace-left=[]
|
||||
move-to-workspace-right=[]
|
||||
move-to-workspace-up=[]
|
||||
move-to-workspace-down=[]
|
||||
move-to-workspace-last=[]
|
||||
move-to-monitor-left=[]
|
||||
move-to-monitor-right=[]
|
||||
move-to-monitor-up=[]
|
||||
move-to-monitor-down=[]
|
||||
close=[]
|
||||
panel-main-menu=[]
|
||||
panel-run-dialog=[]
|
||||
switch-applications=[]
|
||||
switch-input-source=[]
|
@ -0,0 +1,6 @@
|
||||
[org.gnome.desktop.wm.preferences]
|
||||
button-layout=':'
|
||||
action-right-click-titlebar='none'
|
||||
num-workspaces=1
|
||||
theme='Anaconda'
|
||||
mouse-button-modifier=''
|
@ -1,6 +1,6 @@
|
||||
# tests/regex/Makefile.am for anaconda
|
||||
# data/window-manager/config/Makefile.am for anaconda
|
||||
#
|
||||
# Copyright (C) 2010 Red Hat, Inc.
|
||||
# Copyright (C) 2015 Red Hat, Inc.
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or modify
|
||||
# it under the terms of the GNU Lesser General Public License as published
|
||||
@ -15,8 +15,8 @@
|
||||
# You should have received a copy of the GNU Lesser General Public License
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
#
|
||||
# Author: Brian C. Lane <bcl@redhat.com>
|
||||
# Author: David Shea <dshea@redhat.com>
|
||||
|
||||
EXTRA_DIST = *.py
|
||||
themedir = $(datadir)/themes/Anaconda/metacity-1
|
||||
|
||||
MAINTAINERCLEANFILES = Makefile.in
|
||||
dist_theme_DATA = metacity-theme-1.xml
|
958
anaconda/data/window-manager/theme/metacity-theme-1.xml
Normal file
958
anaconda/data/window-manager/theme/metacity-theme-1.xml
Normal file
@ -0,0 +1,958 @@
|
||||
<?xml version="1.0"?>
|
||||
<!-- This is a copy of the Clearlooks theme, with normal_maximized modified
|
||||
to hide the titlebar.
|
||||
-->
|
||||
<metacity_theme>
|
||||
<info>
|
||||
<name>Anaconda</name>
|
||||
<author>Daniel Borgmann <daniel.borgmann@gmail.com>, Andrea Cimitan <andrea.cimitan@gmail.com></author>
|
||||
<copyright>Â 2005-2007 Daniel Borgmann, Andrea Cimitan</copyright>
|
||||
<date>Apr, 2007</date>
|
||||
<description>The Clearlooks "Gummy" Metacity Theme</description>
|
||||
</info>
|
||||
|
||||
<!-- ::: GEOMETRY ::: -->
|
||||
<frame_geometry name="normal" rounded_top_left="true" rounded_top_right="true" rounded_bottom_left="false" rounded_bottom_right="false">
|
||||
<distance name="left_width" value="4"/>
|
||||
<distance name="right_width" value="4"/>
|
||||
<distance name="bottom_height" value="4"/>
|
||||
<distance name="left_titlebar_edge" value="4"/>
|
||||
<distance name="right_titlebar_edge" value="4"/>
|
||||
<aspect_ratio name="button" value="1.0"/>
|
||||
<distance name="title_vertical_pad" value="0"/>
|
||||
<border name="title_border" left="2" right="2" top="4" bottom="3"/>
|
||||
<border name="button_border" left="1" right="1" top="2" bottom="2"/>
|
||||
</frame_geometry>
|
||||
|
||||
<frame_geometry name="shaded" parent="normal" rounded_top_left="true" rounded_top_right="true" rounded_bottom_left="true" rounded_bottom_right="true"/>
|
||||
|
||||
<frame_geometry name="normal_maximized" parent="normal" rounded_top_left="false" rounded_top_right="false" rounded_bottom_left="false" rounded_bottom_right="false" has_title="false">
|
||||
<!-- strip frame spacing off the normal geometry when maximised -->
|
||||
<distance name="left_width" value="0"/>
|
||||
<distance name="right_width" value="0"/>
|
||||
<distance name="bottom_height" value="1"/>
|
||||
<distance name="left_titlebar_edge" value="1"/>
|
||||
<distance name="right_titlebar_edge" value="1"/>
|
||||
<border name="title_border" left="0" right="0" top="0" bottom="0"/>
|
||||
<border name="button_border" left="0" right="0" top="0" bottom="0"/>
|
||||
</frame_geometry>
|
||||
|
||||
<frame_geometry name="utility" title_scale="small" rounded_top_left="false" rounded_top_right="false" rounded_bottom_left="false" rounded_bottom_right="false">
|
||||
<distance name="left_width" value="4"/>
|
||||
<distance name="right_width" value="4"/>
|
||||
<distance name="bottom_height" value="4"/>
|
||||
<distance name="left_titlebar_edge" value="4"/>
|
||||
<distance name="right_titlebar_edge" value="4"/>
|
||||
<distance name="title_vertical_pad" value="0"/>
|
||||
<border name="title_border" left="2" right="2" top="4" bottom="3"/>
|
||||
<border name="button_border" left="0" right="0" top="2" bottom="2"/>
|
||||
<aspect_ratio name="button" value="1"/>
|
||||
</frame_geometry>
|
||||
|
||||
<frame_geometry name="border" has_title="false">
|
||||
<distance name="left_width" value="4"/>
|
||||
<distance name="right_width" value="4"/>
|
||||
<distance name="bottom_height" value="4"/>
|
||||
<distance name="left_titlebar_edge" value="0"/>
|
||||
<distance name="right_titlebar_edge" value="0"/>
|
||||
<distance name="button_width" value="0"/>
|
||||
<distance name="button_height" value="0"/>
|
||||
<distance name="title_vertical_pad" value="4"/>
|
||||
<border name="title_border" left="0" right="0" top="0" bottom="0"/>
|
||||
<border name="button_border" left="0" right="0" top="0" bottom="0"/>
|
||||
</frame_geometry>
|
||||
|
||||
<!-- button minimum size -->
|
||||
<constant name="Bmin" value="7"/>
|
||||
<!-- button inside padding -->
|
||||
<constant name="Bpad" value="6"/>
|
||||
|
||||
<!-- ::: CORNERS ::: -->
|
||||
<draw_ops name="corners_outline_selected_top">
|
||||
<!-- top left -->
|
||||
<line color="shade/gtk:bg[SELECTED]/0.6" x1="1" y1="3" x2="1" y2="3"/>
|
||||
<line color="shade/gtk:bg[SELECTED]/0.73" x1="1" y1="4" x2="1" y2="4"/>
|
||||
<line color="shade/gtk:bg[SELECTED]/0.6" x1="2" y1="2" x2="2" y2="2"/>
|
||||
<line color="shade/gtk:bg[SELECTED]/0.6" x1="3" y1="1" x2="3" y2="1"/>
|
||||
<line color="shade/gtk:bg[SELECTED]/0.73" x1="4" y1="1" x2="4" y2="1"/>
|
||||
|
||||
<!-- top right -->
|
||||
<line color="shade/gtk:bg[SELECTED]/0.6" x1="width-2" y1="3" x2="width-2" y2="3"/>
|
||||
<line color="shade/gtk:bg[SELECTED]/0.73" x1="width-2" y1="4" x2="width-2" y2="4"/>
|
||||
<line color="shade/gtk:bg[SELECTED]/0.6" x1="width-3" y1="2" x2="width-3" y2="2"/>
|
||||
<line color="shade/gtk:bg[SELECTED]/0.6" x1="width-4" y1="1" x2="width-4" y2="1"/>
|
||||
<line color="shade/gtk:bg[SELECTED]/0.73" x1="width-5" y1="1" x2="width-5" y2="1"/>
|
||||
</draw_ops>
|
||||
|
||||
<draw_ops name="corners_outline_top">
|
||||
<!-- top left -->
|
||||
<line color="shade/gtk:bg[NORMAL]/0.55" x1="1" y1="3" x2="1" y2="3"/>
|
||||
<line color="shade/gtk:bg[NORMAL]/0.68" x1="1" y1="4" x2="1" y2="4"/>
|
||||
<line color="shade/gtk:bg[NORMAL]/0.55" x1="2" y1="2" x2="2" y2="2"/>
|
||||
<line color="shade/gtk:bg[NORMAL]/0.55" x1="3" y1="1" x2="3" y2="1"/>
|
||||
<line color="shade/gtk:bg[NORMAL]/0.68" x1="4" y1="1" x2="4" y2="1"/>
|
||||
|
||||
<!-- top right -->
|
||||
<line color="shade/gtk:bg[NORMAL]/0.55" x1="width-2" y1="3" x2="width-2" y2="3"/>
|
||||
<line color="shade/gtk:bg[NORMAL]/0.68" x1="width-2" y1="4" x2="width-2" y2="4"/>
|
||||
<line color="shade/gtk:bg[NORMAL]/0.55" x1="width-3" y1="2" x2="width-3" y2="2"/>
|
||||
<line color="shade/gtk:bg[NORMAL]/0.55" x1="width-4" y1="1" x2="width-4" y2="1"/>
|
||||
<line color="shade/gtk:bg[NORMAL]/0.68" x1="width-5" y1="1" x2="width-5" y2="1"/>
|
||||
</draw_ops>
|
||||
|
||||
<draw_ops name="corners_outline_selected_bottom">
|
||||
<!-- bottom left -->
|
||||
<line color="shade/gtk:bg[SELECTED]/0.6" x1="1" y1="height-4" x2="1" y2="height-5"/>
|
||||
<line color="shade/gtk:bg[SELECTED]/0.6" x1="2" y1="height-3" x2="2" y2="height-3"/>
|
||||
<line color="shade/gtk:bg[SELECTED]/0.6" x1="2" y1="height-2" x2="4" y2="height-2"/>
|
||||
|
||||
<!-- bottom right -->
|
||||
<line color="shade/gtk:bg[SELECTED]/0.6" x1="width-2" y1="height-4" x2="width-2" y2="height-5"/>
|
||||
<line color="shade/gtk:bg[SELECTED]/0.6" x1="width-3" y1="height-3" x2="width-3" y2="height-3"/>
|
||||
<line color="shade/gtk:bg[SELECTED]/0.6" x1="width-4" y1="height-2" x2="width-5" y2="height-2"/>
|
||||
</draw_ops>
|
||||
|
||||
<draw_ops name="corners_outline_bottom">
|
||||
<!-- bottom left -->
|
||||
<line color="shade/gtk:bg[NORMAL]/0.55" x1="1" y1="height-4" x2="1" y2="height-5"/>
|
||||
<line color="shade/gtk:bg[NORMAL]/0.55" x1="2" y1="height-3" x2="2" y2="height-3"/>
|
||||
<line color="shade/gtk:bg[NORMAL]/0.55" x1="2" y1="height-2" x2="4" y2="height-2"/>
|
||||
|
||||
<!-- bottom right -->
|
||||
<line color="shade/gtk:bg[NORMAL]/0.55" x1="width-2" y1="height-4" x2="width-2" y2="height-5"/>
|
||||
<line color="shade/gtk:bg[NORMAL]/0.55" x1="width-3" y1="height-3" x2="width-3" y2="height-3"/>
|
||||
<line color="shade/gtk:bg[NORMAL]/0.55" x1="width-4" y1="height-2" x2="width-5" y2="height-2"/>
|
||||
</draw_ops>
|
||||
|
||||
<draw_ops name="corners_highlight">
|
||||
<!-- ** corner highlight for left top ** -->
|
||||
<line color="shade/gtk:bg[SELECTED]/1.18" x1="2" y1="3" x2="2" y2="4"/>
|
||||
<line color="shade/gtk:bg[SELECTED]/1.18" x1="3" y1="2" x2="4" y2="2"/>
|
||||
|
||||
<!-- ** corner highlight for right top ** -->
|
||||
<line color="shade/gtk:bg[SELECTED]/0.98" x1="width-3" y1="3" x2="width-3" y2="4"/>
|
||||
<line color="shade/gtk:bg[SELECTED]/1.16" x1="width-5" y1="2" x2="width-4" y2="2"/>
|
||||
|
||||
<!-- ** corner highlight for left bottom ** -->
|
||||
<!--<line color="shade/gtk:bg[NORMAL]/1.3" x1="2" y1="height-4" x2="2" y2="height-5"/>
|
||||
<line color="shade/gtk:bg[NORMAL]/0.88" x1="3" y1="height-3" x2="4" y2="height-3"/>-->
|
||||
|
||||
<!-- ** corner highlight for right bottom ** -->
|
||||
<!--<line color="shade/gtk:bg[NORMAL]/0.88" x1="width-3" y1="height-4" x2="width-3" y2="height-5"/>
|
||||
<line color="shade/gtk:bg[NORMAL]/0.88" x1="width-4" y1="height-3" x2="width-5" y2="height-3"/>-->
|
||||
</draw_ops>
|
||||
|
||||
<draw_ops name="corners_highlight_unfocused">
|
||||
<!-- ** corner highlight for left top ** -->
|
||||
<line color="shade/gtk:bg[NORMAL]/1.05" x1="2" y1="3" x2="2" y2="4"/>
|
||||
<line color="shade/gtk:bg[NORMAL]/1.05" x1="3" y1="2" x2="4" y2="2"/>
|
||||
|
||||
<!-- ** corner highlight for right top ** -->
|
||||
<line color="shade/gtk:bg[NORMAL]/0.88" x1="width-3" y1="3" x2="width-3" y2="4"/>
|
||||
<line color="shade/gtk:bg[NORMAL]/1.04" x1="width-5" y1="2" x2="width-4" y2="2"/>
|
||||
|
||||
<!-- ** corner highlight for left bottom ** -->
|
||||
<!--<line color="shade/gtk:bg[NORMAL]/1.3" x1="2" y1="height-4" x2="2" y2="height-5"/>
|
||||
<line color="shade/gtk:bg[NORMAL]/0.88" x1="3" y1="height-3" x2="4" y2="height-3"/>-->
|
||||
|
||||
<!-- ** corner highlight for right bottom ** -->
|
||||
<!--<line color="shade/gtk:bg[NORMAL]/0.88" x1="width-3" y1="height-4" x2="width-3" y2="height-5"/>
|
||||
<line color="shade/gtk:bg[NORMAL]/0.88" x1="width-4" y1="height-3" x2="width-5" y2="height-3"/>-->
|
||||
</draw_ops>
|
||||
|
||||
<draw_ops name="corners_highlight_shaded">
|
||||
<!-- ** corner highlight for left top ** -->
|
||||
<line color="shade/gtk:bg[SELECTED]/1.18" x1="2" y1="3" x2="2" y2="4"/>
|
||||
<line color="shade/gtk:bg[SELECTED]/1.18" x1="3" y1="2" x2="4" y2="2"/>
|
||||
|
||||
<!-- ** corner highlight for right top ** -->
|
||||
<line color="shade/gtk:bg[SELECTED]/0.98" x1="width-3" y1="3" x2="width-3" y2="4"/>
|
||||
<line color="shade/gtk:bg[SELECTED]/1.16" x1="width-5" y1="2" x2="width-4" y2="2"/>
|
||||
|
||||
<!-- ** corner highlight for left bottom ** -->
|
||||
<line color="shade/gtk:bg[SELECTED]/1.08" x1="2" y1="height-4" x2="2" y2="height-5"/>
|
||||
<line color="shade/gtk:bg[SELECTED]/0.98" x1="3" y1="height-3" x2="4" y2="height-3"/>
|
||||
|
||||
<!-- ** corner highlight for right bottom ** -->
|
||||
<line color="shade/gtk:bg[SELECTED]/0.98" x1="width-3" y1="height-4" x2="width-3" y2="height-5"/>
|
||||
<line color="shade/gtk:bg[SELECTED]/0.98" x1="width-4" y1="height-3" x2="width-5" y2="height-3"/>
|
||||
</draw_ops>
|
||||
|
||||
<draw_ops name="corners_highlight_shaded_unfocused">
|
||||
<!-- ** corner highlight for left top ** -->
|
||||
<line color="shade/gtk:bg[NORMAL]/1.05" x1="2" y1="3" x2="2" y2="4"/>
|
||||
<line color="shade/gtk:bg[NORMAL]/1.05" x1="3" y1="2" x2="4" y2="2"/>
|
||||
|
||||
<!-- ** corner highlight for right top ** -->
|
||||
<line color="shade/gtk:bg[NORMAL]/0.88" x1="width-3" y1="3" x2="width-3" y2="4"/>
|
||||
<line color="shade/gtk:bg[NORMAL]/1.04" x1="width-5" y1="2" x2="width-4" y2="2"/>
|
||||
|
||||
<!-- ** corner highlight for left bottom ** -->
|
||||
<line color="shade/gtk:bg[NORMAL]/1.02" x1="2" y1="height-4" x2="2" y2="height-5"/>
|
||||
<line color="shade/gtk:bg[NORMAL]/0.88" x1="3" y1="height-3" x2="4" y2="height-3"/>
|
||||
|
||||
<!-- ** corner highlight for right bottom ** -->
|
||||
<line color="shade/gtk:bg[NORMAL]/0.88" x1="width-3" y1="height-4" x2="width-3" y2="height-5"/>
|
||||
<line color="shade/gtk:bg[NORMAL]/0.88" x1="width-4" y1="height-3" x2="width-5" y2="height-3"/>
|
||||
</draw_ops>
|
||||
|
||||
<draw_ops name="window_bg">
|
||||
<rectangle color="gtk:bg[NORMAL]" filled="true" x="0" y="0" width="width" height="height"/>
|
||||
</draw_ops>
|
||||
|
||||
<!-- ::: BEVEL FOCUSED ::: -->
|
||||
<draw_ops name="bevel">
|
||||
<include name="window_bg"/>
|
||||
<!-- ** titlebar outline ** -->
|
||||
<rectangle color="shade/gtk:bg[SELECTED]/0.55" filled="false" x="0" y="0" width="width - 1" height="((title_height + 6) `max` (top_height - 2))"/>
|
||||
|
||||
<!-- ** 3d beveled frame ** -->
|
||||
<line color="shade/gtk:bg[NORMAL]/0.88" x1="1" y1="height - 2" x2="width - 2" y2="height - 2"/>
|
||||
<line color="shade/gtk:bg[NORMAL]/0.88" x1="width - 2" y1="3" x2="width - 2" y2="height - 2"/>
|
||||
<line color="shade/gtk:bg[NORMAL]/1.2" x1="3" y1="1" x2="width - 4" y2="1"/>
|
||||
<line color="shade/gtk:bg[NORMAL]/1.2" x1="1" y1="3" x2="1" y2="height - 2"/>
|
||||
|
||||
<line color="shade/gtk:bg[SELECTED]/0.94" x1="2" y1="((title_height + 5) `max` (top_height - 3))" x2="width - 3" y2="((title_height + 5) `max` (top_height - 3))"/>
|
||||
<line color="shade/gtk:bg[SELECTED]/0.95" x1="width - 2" y1="2" x2="width - 2" y2="((title_height + 6) `max` (top_height - 2))"/>
|
||||
<line color="shade/gtk:bg[SELECTED]/1.18" x1="1" y1="1" x2="width - 2" y2="1"/>
|
||||
<line color="shade/gtk:bg[SELECTED]/1.1" x1="1" y1="2" x2="1" y2="((title_height + 5) `max` (top_height - 3))"/>
|
||||
|
||||
<!-- ** fancy gradient ** -->
|
||||
<gradient type="vertical" x="2" y="top_height/2" width="width-4" height="top_height/2-1">
|
||||
<color value="shade/gtk:bg[SELECTED]/1.0"/>
|
||||
<color value="shade/gtk:bg[SELECTED]/0.94"/>
|
||||
</gradient>
|
||||
<gradient type="vertical" x="2" y="2" width="width-4" height="top_height/2-2">
|
||||
<color value="shade/gtk:bg[SELECTED]/1.08"/>
|
||||
<color value="shade/gtk:bg[SELECTED]/1.02"/>
|
||||
</gradient>
|
||||
|
||||
<line color="shade/gtk:bg[SELECTED]/0.7" x1="1" y1="((title_height + 6) `max` (top_height - 2))" x2="width - 2" y2="((title_height + 6) `max` (top_height - 2))"/>
|
||||
|
||||
<!-- ** border outline ** -->
|
||||
<line color="shade/gtk:bg[NORMAL]/0.45" x1="0" y1="((title_height + 6) `max` (top_height - 2))" x2="0" y2="height"/>
|
||||
<line color="shade/gtk:bg[NORMAL]/0.45" x1="width - 1" y1="((title_height + 6) `max` (top_height - 2))" x2="width - 1" y2="height"/>
|
||||
<line color="shade/gtk:bg[NORMAL]/0.45" x1="1" y1="height - 1" x2="width - 2" y2="height - 1"/>
|
||||
</draw_ops>
|
||||
|
||||
<draw_ops name="bevel_maximized">
|
||||
<!-- ** 3d beveled frame ** -->
|
||||
<line color="shade/gtk:bg[SELECTED]/0.55" x1="0" y1="0" x2="width" y2="0"/>
|
||||
<line color="shade/gtk:bg[SELECTED]/1.18" x1="0" y1="1" x2="width" y2="1"/>
|
||||
<line color="shade/gtk:bg[SELECTED]/0.94" x1="0" y1="((title_height + 5) `max` (top_height - 3))" x2="width" y2="((title_height + 5) `max` (top_height - 3))"/>
|
||||
|
||||
<!-- ** fancy gradient ** -->
|
||||
<gradient type="vertical" x="0" y="top_height/2" width="width" height="top_height/2-1">
|
||||
<color value="shade/gtk:bg[SELECTED]/1.0"/>
|
||||
<color value="shade/gtk:bg[SELECTED]/0.94"/>
|
||||
</gradient>
|
||||
<gradient type="vertical" x="0" y="1" width="width" height="top_height/2-1">
|
||||
<color value="shade/gtk:bg[SELECTED]/1.08"/>
|
||||
<color value="shade/gtk:bg[SELECTED]/1.02"/>
|
||||
</gradient>
|
||||
|
||||
<line color="shade/gtk:bg[SELECTED]/0.7" x1="0" y1="((title_height + 6) `max` (top_height - 2))" x2="width" y2="((title_height + 6) `max` (top_height - 2))"/>
|
||||
<line color="shade/gtk:bg[SELECTED]/0.55" x1="0" y1="height-1" x2="width" y2="height-1"/>
|
||||
</draw_ops>
|
||||
|
||||
<draw_ops name="round_bevel">
|
||||
<include name="bevel"/>
|
||||
<include name="corners_outline_selected_top"/>
|
||||
<!--<include name="corners_outline_bottom"/>-->
|
||||
<include name="corners_highlight"/>
|
||||
</draw_ops>
|
||||
|
||||
<draw_ops name="bevel_shaded">
|
||||
<include name="bevel"/>
|
||||
<line color="shade/gtk:bg[SELECTED]/0.6" x1="0" y1="height-1" x2="width" y2="height-1"/>
|
||||
</draw_ops>
|
||||
|
||||
<draw_ops name="round_bevel_shaded">
|
||||
<include name="bevel"/>
|
||||
<include name="corners_outline_selected_top"/>
|
||||
<include name="corners_outline_selected_bottom"/>
|
||||
<include name="corners_highlight_shaded"/>
|
||||
<line color="shade/gtk:bg[SELECTED]/0.6" x1="5" y1="height-1" x2="width-6" y2="height-1"/>
|
||||
</draw_ops>
|
||||
|
||||
<!-- ::: BEVEL UNFOCUSED ::: -->
|
||||
<draw_ops name="bevel_unfocused">
|
||||
<include name="window_bg"/>
|
||||
<line color="shade/gtk:bg[NORMAL]/0.88" x1="1" y1="height - 2" x2="width - 2" y2="height - 2"/>
|
||||
<line color="shade/gtk:bg[NORMAL]/0.88" x1="width - 2" y1="2" x2="width - 2" y2="height - 2"/>
|
||||
<line color="shade/gtk:bg[NORMAL]/1.05" x1="1" y1="1" x2="width - 2" y2="1"/>
|
||||
<line color="shade/gtk:bg[NORMAL]/1.03" x1="1" y1="2" x2="1" y2="height - 2"/>
|
||||
<line color="shade/gtk:bg[NORMAL]/0.89" x1="2" y1="((title_height + 5) `max` (top_height - 3))" x2="width - 3" y2="((title_height + 5) `max` (top_height - 3))"/>
|
||||
|
||||
<!-- ** fancy gradient ** -->
|
||||
<gradient type="vertical" x="2" y="top_height/2" width="width-4" height="top_height/2-1">
|
||||
<color value="shade/gtk:bg[NORMAL]/0.93"/>
|
||||
<color value="shade/gtk:bg[NORMAL]/0.89"/>
|
||||
</gradient>
|
||||
<gradient type="vertical" x="2" y="2" width="width-4" height="top_height/2-2">
|
||||
<color value="shade/gtk:bg[NORMAL]/0.99"/>
|
||||
<color value="shade/gtk:bg[NORMAL]/0.95"/>
|
||||
</gradient>
|
||||
|
||||
<line color="shade/gtk:bg[NORMAL]/0.65" x1="1" y1="((title_height + 6) `max` (top_height - 2))" x2="width - 2" y2="((title_height + 6) `max` (top_height - 2))"/>
|
||||
<rectangle color="shade/gtk:bg[NORMAL]/0.55" filled="false" x="0" y="0" width="width - 1" height="height - 1"/>
|
||||
</draw_ops>
|
||||
|
||||
<draw_ops name="bevel_maximized_unfocused">
|
||||
<!-- ** 3d beveled frame ** -->
|
||||
<line color="shade/gtk:bg[NORMAL]/0.55" x1="0" y1="0" x2="width" y2="0"/>
|
||||
<line color="shade/gtk:bg[NORMAL]/1.05" x1="0" y1="1" x2="width" y2="1"/>
|
||||
<line color="shade/gtk:bg[NORMAL]/0.89" x1="0" y1="((title_height + 5) `max` (top_height - 3))" x2="width" y2="((title_height + 5) `max` (top_height - 3))"/>
|
||||
|
||||
<!-- ** fancy gradient ** -->
|
||||
<gradient type="vertical" x="0" y="top_height/2" width="width" height="top_height/2-1">
|
||||
<color value="shade/gtk:bg[NORMAL]/0.93"/>
|
||||
<color value="shade/gtk:bg[NORMAL]/0.89"/>
|
||||
</gradient>
|
||||
<gradient type="vertical" x="0" y="2" width="width" height="top_height/2-2">
|
||||
<color value="shade/gtk:bg[NORMAL]/0.99"/>
|
||||
<color value="shade/gtk:bg[NORMAL]/0.95"/>
|
||||
</gradient>
|
||||
|
||||
<line color="shade/gtk:bg[NORMAL]/0.65" x1="0" y1="((title_height + 6) `max` (top_height - 2))" x2="width" y2="((title_height + 6) `max` (top_height - 2))"/>
|
||||
<line color="shade/gtk:bg[NORMAL]/0.55" x1="0" y1="height-1" x2="width" y2="height-1"/>
|
||||
</draw_ops>
|
||||
|
||||
<draw_ops name="round_bevel_unfocused">
|
||||
<include name="bevel_unfocused"/>
|
||||
<include name="corners_outline_top"/>
|
||||
<!--<include name="corners_outline_bottom"/>-->
|
||||
<include name="corners_highlight_unfocused"/>
|
||||
</draw_ops>
|
||||
|
||||
<draw_ops name="round_bevel_unfocused_shaded">
|
||||
<include name="bevel_unfocused"/>
|
||||
<include name="corners_outline_top"/>
|
||||
<include name="corners_outline_bottom"/>
|
||||
<include name="corners_highlight_shaded_unfocused"/>
|
||||
</draw_ops>
|
||||
|
||||
<!-- ::: BORDER ::: -->
|
||||
<draw_ops name="border">
|
||||
<line color="shade/gtk:bg[NORMAL]/0.88" x1="1" y1="height - 2" x2="width - 2" y2="height - 2"/>
|
||||
<line color="shade/gtk:bg[NORMAL]/0.88" x1="width - 2" y1="1" x2="width - 2" y2="height - 2"/>
|
||||
<line color="shade/gtk:bg[NORMAL]/1.2" x1="1" y1="1" x2="width - 2" y2="1"/>
|
||||
<line color="shade/gtk:bg[NORMAL]/1.2" x1="1" y1="1" x2="1" y2="height - 2"/>
|
||||
|
||||
<rectangle color="shade/gtk:bg[NORMAL]/0.55" filled="false" x="0" y="0" width="width - 1" height="height - 1"/>
|
||||
</draw_ops>
|
||||
|
||||
<!-- ::: TITLES ::: -->
|
||||
<draw_ops name="title_text">
|
||||
<title color="shade/gtk:bg[SELECTED]/0.7" x="((3 `max` (width-title_width)) / 2)" y="(((height - title_height) / 2) `max` 0) + 1"/>
|
||||
<title color="shade/gtk:bg[SELECTED]/0.7" x="((3 `max` (width-title_width)) / 2)+1" y="(((height - title_height) / 2) `max` 0)"/>
|
||||
<title color="shade/gtk:bg[SELECTED]/0.7" x="((3 `max` (width-title_width)) / 2)-1" y="(((height - title_height) / 2) `max` 0)"/>
|
||||
<title color="shade/gtk:bg[SELECTED]/0.7" x="((3 `max` (width-title_width)) / 2)" y="(((height - title_height) / 2) `max` 0)-1"/>
|
||||
<title color="#FFFFFF" x="(3 `max` (width-title_width)) / 2" y="(((height - title_height) / 2) `max` 0)"/>
|
||||
</draw_ops>
|
||||
|
||||
<draw_ops name="title_text_unfocused">
|
||||
<!--<title color="shade/gtk:bg[NORMAL]/1.07" x="5 `max` (width-title_width)/2+1" y="1 `max` ((height-title_height)/2)+1"/>-->
|
||||
<title color="blend/gtk:fg[NORMAL]/gtk:bg[NORMAL]/0.45" x="4 `max` (width-title_width)/2" y="0 `max` ((height-title_height)/2)"/>
|
||||
</draw_ops>
|
||||
|
||||
<draw_ops name="title">
|
||||
<include name="title_text"/>
|
||||
</draw_ops>
|
||||
|
||||
<draw_ops name="title_unfocused">
|
||||
<include name="title_text_unfocused"/>
|
||||
</draw_ops>
|
||||
|
||||
<!-- ::: BUTTONS ::: -->
|
||||
<draw_ops name="button_bg">
|
||||
<!-- inset -->
|
||||
<gradient type="vertical" x="0" y="3" width="width" height="height-6">
|
||||
<color value="shade/gtk:bg[SELECTED]/0.96"/>
|
||||
<color value="shade/gtk:bg[SELECTED]/1.05"/>
|
||||
</gradient>
|
||||
|
||||
<line color="shade/gtk:bg[SELECTED]/1.00" x1="2" y1="0" x2="width-3" y2="0"/>
|
||||
<line color="shade/gtk:bg[SELECTED]/0.99" x1="1" y1="1" x2="width-2" y2="1"/>
|
||||
<line color="shade/gtk:bg[SELECTED]/0.99" x1="0" y1="2" x2="width-1" y2="2"/>
|
||||
<line color="shade/gtk:bg[SELECTED]/0.98" x1="3" y1="0" x2="width-4" y2="0"/>
|
||||
|
||||
<line color="shade/gtk:bg[SELECTED]/0.91" x1="2" y1="1" x2="width-3" y2="1"/>
|
||||
<line color="shade/gtk:bg[SELECTED]/0.90" x1="1" y1="2" x2="width-2" y2="2"/>
|
||||
|
||||
<line color="shade/gtk:bg[SELECTED]/1.03" x1="2" y1="height-1" x2="width-3" y2="height-1"/>
|
||||
<line color="shade/gtk:bg[SELECTED]/1.00" x1="1" y1="height-2" x2="width-2" y2="height-2"/>
|
||||
<line color="shade/gtk:bg[SELECTED]/1.01" x1="0" y1="height-3" x2="width-1" y2="height-3"/>
|
||||
<line color="shade/gtk:bg[SELECTED]/1.06" x1="3" y1="height-1" x2="width-4" y2="height-1"/>
|
||||
|
||||
<line color="shade/gtk:bg[SELECTED]/1.02" x1="2" y1="height-2" x2="width-3" y2="height-2"/>
|
||||
<line color="shade/gtk:bg[SELECTED]/1.03" x1="1" y1="height-3" x2="width-2" y2="height-3"/>
|
||||
|
||||
<!-- border outline -->
|
||||
<line color="shade/gtk:bg[SELECTED]/0.6" x1="3" y1="1" x2="width-4" y2="1"/>
|
||||
<line color="shade/gtk:bg[SELECTED]/0.6" x1="3" y1="height-2" x2="width-4" y2="height-2"/>
|
||||
<line color="shade/gtk:bg[SELECTED]/0.6" x1="1" y1="3" x2="1" y2="height-4"/>
|
||||
<line color="shade/gtk:bg[SELECTED]/0.6" x1="width-2" y1="3" x2="width-2" y2="height-4"/>
|
||||
<line color="shade/gtk:bg[SELECTED]/0.6" x1="2" y1="2" x2="width-3" y2="2"/>
|
||||
<line color="shade/gtk:bg[SELECTED]/0.6" x1="2" y1="height-3" x2="width-3" y2="height-3"/>
|
||||
|
||||
<!-- border smooth effect -->
|
||||
<line color="shade/gtk:bg[SELECTED]/1.02" x1="3" y1="2" x2="width-4" y2="2"/>
|
||||
<line color="shade/gtk:bg[SELECTED]/1.00" x1="2" y1="3" x2="2" y2="height-4"/>
|
||||
<line color="shade/gtk:bg[SELECTED]/0.90" x1="width-3" y1="3" x2="width-3" y2="height-4"/>
|
||||
|
||||
<!-- inside highlight -->
|
||||
<line color="shade/gtk:bg[SELECTED]/1.18" x1="4" y1="2" x2="width-5" y2="2"/>
|
||||
<line color="shade/gtk:bg[SELECTED]/1.1" x1="2" y1="4" x2="2" y2="height-5"/>
|
||||
<!-- inside shadow -->
|
||||
<line color="shade/gtk:bg[SELECTED]/1.0" x1="width-3" y1="4" x2="width-3" y2="height-5"/>
|
||||
|
||||
<!-- fill gradient -->
|
||||
<gradient type="vertical" x="3" y="3" width="width-6" height="(height)/2-1">
|
||||
<color value="shade/gtk:bg[SELECTED]/1.1"/>
|
||||
<color value="shade/gtk:bg[SELECTED]/1.02"/>
|
||||
</gradient>
|
||||
<gradient type="vertical" x="3" y="(height)/2" width="width-6" height="(height)/2-2">
|
||||
<color value="shade/gtk:bg[SELECTED]/1.0"/>
|
||||
<color value="shade/gtk:bg[SELECTED]/0.92"/>
|
||||
</gradient>
|
||||
|
||||
<!-- bottom border smooth effect -->
|
||||
<line color="shade/gtk:bg[SELECTED]/0.84" x1="3" y1="height-3" x2="width-4" y2="height-3"/>
|
||||
<line color="shade/gtk:bg[SELECTED]/0.92" x1="4" y1="height-3" x2="width-5" y2="height-3"/>
|
||||
</draw_ops>
|
||||
|
||||
<draw_ops name="button_bg_unfocused">
|
||||
<!-- inset -->
|
||||
<gradient type="vertical" x="0" y="3" width="width" height="height-6">
|
||||
<color value="shade/gtk:bg[NORMAL]/0.92"/>
|
||||
<color value="shade/gtk:bg[NORMAL]/0.96"/>
|
||||
</gradient>
|
||||
|
||||
<line color="shade/gtk:bg[NORMAL]/0.93" x1="2" y1="0" x2="width-3" y2="0"/>
|
||||
<line color="shade/gtk:bg[NORMAL]/0.92" x1="1" y1="1" x2="width-2" y2="1"/>
|
||||
<line color="shade/gtk:bg[NORMAL]/0.92" x1="0" y1="2" x2="width-1" y2="2"/>
|
||||
<line color="shade/gtk:bg[NORMAL]/0.91" x1="3" y1="0" x2="width-4" y2="0"/>
|
||||
|
||||
<line color="shade/gtk:bg[NORMAL]/0.87" x1="2" y1="1" x2="width-3" y2="1"/>
|
||||
<line color="shade/gtk:bg[NORMAL]/0.86" x1="1" y1="2" x2="width-2" y2="2"/>
|
||||
|
||||
<line color="shade/gtk:bg[NORMAL]/0.945" x1="2" y1="height-1" x2="width-3" y2="height-1"/>
|
||||
<line color="shade/gtk:bg[NORMAL]/0.93" x1="1" y1="height-2" x2="width-2" y2="height-2"/>
|
||||
<line color="shade/gtk:bg[NORMAL]/0.935" x1="0" y1="height-3" x2="width-1" y2="height-3"/>
|
||||
<line color="shade/gtk:bg[NORMAL]/0.96" x1="3" y1="height-1" x2="width-4" y2="height-1"/>
|
||||
|
||||
<line color="shade/gtk:bg[NORMAL]/0.94" x1="2" y1="height-2" x2="width-3" y2="height-2"/>
|
||||
<line color="shade/gtk:bg[NORMAL]/0.95" x1="1" y1="height-3" x2="width-2" y2="height-3"/>
|
||||
|
||||
<!-- border outline -->
|
||||
<line color="shade/gtk:bg[NORMAL]/0.6" x1="3" y1="1" x2="width-4" y2="1"/>
|
||||
<line color="shade/gtk:bg[NORMAL]/0.6" x1="3" y1="height-2" x2="width-4" y2="height-2"/>
|
||||
<line color="shade/gtk:bg[NORMAL]/0.6" x1="1" y1="3" x2="1" y2="height-4"/>
|
||||
<line color="shade/gtk:bg[NORMAL]/0.6" x1="width-2" y1="3" x2="width-2" y2="height-4"/>
|
||||
|
||||
<line color="shade/gtk:bg[NORMAL]/0.6" x1="2" y1="2" x2="width-3" y2="2"/>
|
||||
<line color="shade/gtk:bg[NORMAL]/0.6" x1="2" y1="height-3" x2="width-3" y2="height-3"/>
|
||||
|
||||
<!-- border smooth effect -->
|
||||
<line color="shade/gtk:bg[NORMAL]/1.02" x1="3" y1="2" x2="width-4" y2="2"/>
|
||||
<line color="shade/gtk:bg[NORMAL]/1.00" x1="2" y1="3" x2="2" y2="height-4"/>
|
||||
<line color="shade/gtk:bg[NORMAL]/0.95" x1="width-3" y1="3" x2="width-3" y2="height-4"/>
|
||||
|
||||
<!-- inside highlight -->
|
||||
<line color="shade/gtk:bg[NORMAL]/1.2" x1="4" y1="2" x2="width-5" y2="2"/>
|
||||
<line color="shade/gtk:bg[NORMAL]/1.1" x1="2" y1="4" x2="2" y2="height-5"/>
|
||||
<!-- inside shadow -->
|
||||
<line color="shade/gtk:bg[NORMAL]/1.05" x1="width-3" y1="4" x2="width-3" y2="height-5"/>
|
||||
|
||||
<!-- fill gradient -->
|
||||
<gradient type="vertical" x="3" y="3" width="width-6" height="(height)/2-1">
|
||||
<color value="shade/gtk:bg[NORMAL]/1.15"/>
|
||||
<color value="shade/gtk:bg[NORMAL]/1.07"/>
|
||||
</gradient>
|
||||
<gradient type="vertical" x="3" y="(height)/2" width="width-6" height="(height)/2-2">
|
||||
<color value="shade/gtk:bg[NORMAL]/1.05"/>
|
||||
<color value="shade/gtk:bg[NORMAL]/0.97"/>
|
||||
</gradient>
|
||||
|
||||
<!-- bottom border smooth effect -->
|
||||
<line color="shade/gtk:bg[NORMAL]/0.89" x1="3" y1="height-3" x2="width-4" y2="height-3"/>
|
||||
<line color="shade/gtk:bg[NORMAL]/0.97" x1="4" y1="height-3" x2="width-5" y2="height-3"/>
|
||||
</draw_ops>
|
||||
|
||||
<draw_ops name="button_bg_prelight">
|
||||
<include name="button_bg"/>
|
||||
<tint color="shade/gtk:bg[SELECTED]/1.5" alpha="0.2" x="3" y="3" width="width-5" height="height-5"/>
|
||||
<line color="shade/gtk:bg[SELECTED]/0.6" x1="width-3" y1="height-3" x2="width-3" y2="height-3"/>
|
||||
</draw_ops>
|
||||
|
||||
<draw_ops name="button_bg_pressed">
|
||||
<!-- outside highlight -->
|
||||
<gradient type="vertical" x="width-2" y="2" width="1" height="height-4">
|
||||
<color value="shade/gtk:bg[SELECTED]/1.2"/>
|
||||
<color value="shade/gtk:bg[SELECTED]/1.0"/>
|
||||
</gradient>
|
||||
<gradient type="vertical" x="width-1" y="3" width="1" height="height-6">
|
||||
<color value="shade/gtk:bg[SELECTED]/1.2"/>
|
||||
<color value="shade/gtk:bg[SELECTED]/1.0"/>
|
||||
</gradient>
|
||||
<line color="shade/gtk:bg[SELECTED]/1.0" x1="2" y1="height-2" x2="width-3" y2="height-2"/>
|
||||
<line color="shade/gtk:bg[SELECTED]/1.0" x1="3" y1="height-1" x2="width-4" y2="height-1"/>
|
||||
|
||||
<!-- border outline -->
|
||||
<line color="shade/gtk:bg[SELECTED]/0.55" x1="3" y1="1" x2="width-4" y2="1"/>
|
||||
<line color="shade/gtk:bg[SELECTED]/0.55" x1="3" y1="height-2" x2="width-4" y2="height-2"/>
|
||||
<line color="shade/gtk:bg[SELECTED]/0.55" x1="1" y1="3" x2="1" y2="height-4"/>
|
||||
<line color="shade/gtk:bg[SELECTED]/0.55" x1="width-2" y1="3" x2="width-2" y2="height-4"/>
|
||||
|
||||
<line color="shade/gtk:bg[SELECTED]/0.55" x1="2" y1="2" x2="width-3" y2="2"/>
|
||||
<line color="shade/gtk:bg[SELECTED]/0.55" x1="2" y1="height-3" x2="width-3" y2="height-3"/>
|
||||
|
||||
<!-- inside shadow -->
|
||||
<line color="shade/gtk:bg[SELECTED]/0.9" x1="3" y1="2" x2="width-4" y2="2"/>
|
||||
<line color="shade/gtk:bg[SELECTED]/0.85" x1="2" y1="3" x2="2" y2="height-4"/>
|
||||
|
||||
<!-- fill gradient -->
|
||||
<gradient type="vertical" x="3" y="3" width="width-5" height="height-6">
|
||||
<color value="shade/gtk:bg[SELECTED]/0.95"/>
|
||||
<color value="shade/gtk:bg[SELECTED]/0.9"/>
|
||||
</gradient>
|
||||
|
||||
<line color="shade/gtk:bg[SELECTED]/0.9" x1="3" y1="height-3" x2="width-4" y2="height-3"/>
|
||||
</draw_ops>
|
||||
|
||||
<draw_ops name="button_bg_unfocused_prelight">
|
||||
<include name="button_bg_unfocused"/>
|
||||
<tint color="shade/gtk:bg[NORMAL]/1.5" alpha="0.3" x="3" y="3" width="width-5" height="height-5"/>
|
||||
<line color="shade/gtk:bg[NORMAL]/0.6" x1="width-3" y1="height-3" x2="width-3" y2="height-3"/>
|
||||
</draw_ops>
|
||||
|
||||
<draw_ops name="button_bg_unfocused_pressed">
|
||||
<!-- outside highlight -->
|
||||
<gradient type="vertical" x="width-2" y="2" width="1" height="height-4">
|
||||
<color value="shade/gtk:bg[NORMAL]/1.25"/>
|
||||
<color value="shade/gtk:bg[NORMAL]/1.05"/>
|
||||
</gradient>
|
||||
<gradient type="vertical" x="width-1" y="3" width="1" height="height-6">
|
||||
<color value="shade/gtk:bg[NORMAL]/1.25"/>
|
||||
<color value="shade/gtk:bg[NORMAL]/1.05"/>
|
||||
</gradient>
|
||||
<line color="shade/gtk:bg[NORMAL]/1.05" x1="2" y1="height-2" x2="width-3" y2="height-2"/>
|
||||
<line color="shade/gtk:bg[NORMAL]/1.05" x1="3" y1="height-1" x2="width-4" y2="height-1"/>
|
||||
|
||||
<!-- border outline -->
|
||||
<line color="shade/gtk:bg[NORMAL]/0.55" x1="3" y1="1" x2="width-4" y2="1"/>
|
||||
<line color="shade/gtk:bg[NORMAL]/0.55" x1="3" y1="height-2" x2="width-4" y2="height-2"/>
|
||||
<line color="shade/gtk:bg[NORMAL]/0.55" x1="1" y1="3" x2="1" y2="height-4"/>
|
||||
<line color="shade/gtk:bg[NORMAL]/0.55" x1="width-2" y1="3" x2="width-2" y2="height-4"/>
|
||||
<line color="shade/gtk:bg[NORMAL]/0.55" x1="2" y1="2" x2="width-3" y2="2"/>
|
||||
<line color="shade/gtk:bg[NORMAL]/0.55" x1="2" y1="height-3" x2="width-3" y2="height-3"/>
|
||||
|
||||
<!-- inside shadow -->
|
||||
<line color="shade/gtk:bg[NORMAL]/0.8" x1="3" y1="2" x2="width-4" y2="2"/>
|
||||
<line color="shade/gtk:bg[NORMAL]/0.75" x1="2" y1="3" x2="2" y2="height-4"/>
|
||||
|
||||
<!-- fill gradient -->
|
||||
<gradient type="vertical" x="3" y="3" width="width-5" height="height-6">
|
||||
<color value="shade/gtk:bg[NORMAL]/0.9"/>
|
||||
<color value="shade/gtk:bg[NORMAL]/0.85"/>
|
||||
</gradient>
|
||||
|
||||
<line color="shade/gtk:bg[NORMAL]/0.85" x1="3" y1="height-3" x2="width-4" y2="height-3"/>
|
||||
</draw_ops>
|
||||
|
||||
<!-- ::: ICONS ::: -->
|
||||
<!--
|
||||
using a minimum icon size until there is a proper way to specify relative sizes
|
||||
unfortunately it's logically impossible to always center the icons on non-square
|
||||
buttons (utility windows) without distortion.
|
||||
|
||||
icon_size = (Bmin`max`height-Bpad*2)
|
||||
hpadding = (width - icon_size) / 2 = ((width-(Bmin`max`height-Bpad*2))/2)
|
||||
vpadding = (height - icon_size) / 2 = ((height-(Bmin`max`height-Bpad*2))/2)
|
||||
-->
|
||||
|
||||
<!-- menu icon -->
|
||||
<draw_ops name="menu_button_icon">
|
||||
<!--<icon x="0" y="0" width="width" height="height"/>-->
|
||||
<icon x="(width-mini_icon_width)/2" y="(height-mini_icon_height)/2" width="mini_icon_width" height="mini_icon_height"/>
|
||||
</draw_ops>
|
||||
|
||||
<draw_ops name="menu_button_icon_unfocused">
|
||||
<!--<icon x="0" y="0" width="width" height="height" alpha="0.5"/>-->
|
||||
<icon x="(width-mini_icon_width)/2" y="(height-mini_icon_height)/2" width="mini_icon_width" height="mini_icon_height"/>
|
||||
</draw_ops>
|
||||
|
||||
<draw_ops name="menu_button_normal">
|
||||
<include name="menu_button_icon"/>
|
||||
</draw_ops>
|
||||
<draw_ops name="menu_button_pressed">
|
||||
<include name="menu_button_icon"/>
|
||||
</draw_ops>
|
||||
<draw_ops name="menu_button_unfocused">
|
||||
<include name="menu_button_icon_unfocused"/>
|
||||
</draw_ops>
|
||||
|
||||
<!-- close icon -->
|
||||
<draw_ops name="close_button_icon">
|
||||
<!-- outside border -->
|
||||
|
||||
<!-- main cross -->
|
||||
<line color="shade/gtk:bg[SELECTED]/0.7" width="4"
|
||||
x1="((width-(Bmin`max`height-Bpad*2))/2)" y1="((height-(Bmin`max`height-Bpad*2))/2)"
|
||||
x2="width - ((width-(Bmin`max`height-Bpad*2))/2) - 1" y2="height - ((height-(Bmin`max`height-Bpad*2))/2) - 1"/>
|
||||
<line color="shade/gtk:bg[SELECTED]/0.7" width="4"
|
||||
x1="((width-(Bmin`max`height-Bpad*2))/2)" y1="height - ((height-(Bmin`max`height-Bpad*2))/2) - 1"
|
||||
x2="width - ((width-(Bmin`max`height-Bpad*2))/2) - 1" y2="((height-(Bmin`max`height-Bpad*2))/2)"/>
|
||||
<!-- top-left -->
|
||||
<tint color="shade/gtk:bg[SELECTED]/0.7" alpha="1.0"
|
||||
x="((width-(Bmin`max`height-Bpad*2))/2)" y="((height-(Bmin`max`height-Bpad*2))/2)-1"
|
||||
width="2" height="1"/>
|
||||
<tint color="shade/gtk:bg[SELECTED]/0.7" alpha="1.0"
|
||||
x="((width-(Bmin`max`height-Bpad*2))/2)-1" y="((height-(Bmin`max`height-Bpad*2))/2)/1"
|
||||
width="1" height="2"/>
|
||||
<!-- top-right -->
|
||||
<tint color="shade/gtk:bg[SELECTED]/0.7" alpha="1.0"
|
||||
x="width - ((width-(Bmin`max`height-Bpad*2))/2) -2" y="((height-(Bmin`max`height-Bpad*2))/2)-1"
|
||||
width="2" height="1"/>
|
||||
<tint color="shade/gtk:bg[SELECTED]/0.7" alpha="1.0"
|
||||
x="width - ((width-(Bmin`max`height-Bpad*2))/2)" y="((height-(Bmin`max`height-Bpad*2))/2)"
|
||||
width="1" height="2"/>
|
||||
<!-- bottom-left -->
|
||||
<tint color="shade/gtk:bg[SELECTED]/0.7" alpha="1.0"
|
||||
x="((width-(Bmin`max`height-Bpad*2))/2)" y="height - ((height-(Bmin`max`height-Bpad*2))/2)"
|
||||
width="2" height="1"/>
|
||||
<tint color="shade/gtk:bg[SELECTED]/0.7" alpha="1.0"
|
||||
x="((width-(Bmin`max`height-Bpad*2))/2)-1" y="height - ((height-(Bmin`max`height-Bpad*2))/2)-2"
|
||||
width="1" height="2"/>
|
||||
<!-- bottom-right -->
|
||||
<tint color="shade/gtk:bg[SELECTED]/0.7" alpha="1.0"
|
||||
x="width - ((width-(Bmin`max`height-Bpad*2))/2) -2" y="height - ((height-(Bmin`max`height-Bpad*2))/2)"
|
||||
width="2" height="1"/>
|
||||
<tint color="shade/gtk:bg[SELECTED]/0.7" alpha="1.0"
|
||||
x="width - ((width-(Bmin`max`height-Bpad*2))/2)" y="height - ((height-(Bmin`max`height-Bpad*2))/2)-2"
|
||||
width="1" height="2"/>
|
||||
|
||||
<!-- icon -->
|
||||
<line color="blend/gtk:bg[SELECTED]/#FFFFFF/0.75" width="2"
|
||||
x1="((width-(Bmin`max`height-Bpad*2))/2)" y1="((height-(Bmin`max`height-Bpad*2))/2)"
|
||||
x2="width - ((width-(Bmin`max`height-Bpad*2))/2) - 1" y2="height - ((height-(Bmin`max`height-Bpad*2))/2) - 1"/>
|
||||
<line color="blend/gtk:bg[SELECTED]/#FFFFFF/0.75" width="1"
|
||||
x1="((width-(Bmin`max`height-Bpad*2))/2)" y1="((height-(Bmin`max`height-Bpad*2))/2)"
|
||||
x2="width- ((width-(Bmin`max`height-Bpad*2))/2)" y2="height - ((height-(Bmin`max`height-Bpad*2))/2)"/>
|
||||
<line color="blend/gtk:bg[SELECTED]/#FFFFFF/0.75" width="2"
|
||||
x1="((width-(Bmin`max`height-Bpad*2))/2)" y1="height - ((height-(Bmin`max`height-Bpad*2))/2) - 1"
|
||||
x2="width - ((width-(Bmin`max`height-Bpad*2))/2) - 1" y2="((height-(Bmin`max`height-Bpad*2))/2)"/>
|
||||
<line color="blend/gtk:bg[SELECTED]/#FFFFFF/0.75" width="1"
|
||||
x1="((width-(Bmin`max`height-Bpad*2))/2)" y1="height - ((height-(Bmin`max`height-Bpad*2))/2) - 1"
|
||||
x2="width - ((width-(Bmin`max`height-Bpad*2))/2)" y2="((height-(Bmin`max`height-Bpad*2))/2) - 1"/>
|
||||
</draw_ops>
|
||||
|
||||
<draw_ops name="close_button_icon_unfocused">
|
||||
<line color="blend/gtk:fg[NORMAL]/gtk:bg[NORMAL]/0.45" width="2"
|
||||
x1="((width-(Bmin`max`height-Bpad*2))/2)" y1="((height-(Bmin`max`height-Bpad*2))/2)"
|
||||
x2="width-((width-(Bmin`max`height-Bpad*2))/2)-1" y2="height - ((height-(Bmin`max`height-Bpad*2))/2)-1"/>
|
||||
<line color="blend/gtk:fg[NORMAL]/gtk:bg[NORMAL]/0.45" width="1"
|
||||
x1="((width-(Bmin`max`height-Bpad*2))/2)" y1="((height-(Bmin`max`height-Bpad*2))/2)"
|
||||
x2="width-((width-(Bmin`max`height-Bpad*2))/2)" y2="height - ((height-(Bmin`max`height-Bpad*2))/2)"/>
|
||||
<line color="blend/gtk:fg[NORMAL]/gtk:bg[NORMAL]/0.45" width="2"
|
||||
x1="((width-(Bmin`max`height-Bpad*2))/2)" y1="height - ((height-(Bmin`max`height-Bpad*2))/2)-1"
|
||||
x2="width-((width-(Bmin`max`height-Bpad*2))/2)-1" y2="((height-(Bmin`max`height-Bpad*2))/2)"/>
|
||||
<line color="blend/gtk:fg[NORMAL]/gtk:bg[NORMAL]/0.45" width="1"
|
||||
x1="((width-(Bmin`max`height-Bpad*2))/2)" y1="height - ((height-(Bmin`max`height-Bpad*2))/2)-1"
|
||||
x2="width-((width-(Bmin`max`height-Bpad*2))/2)" y2="((height-(Bmin`max`height-Bpad*2))/2) - 1"/>
|
||||
</draw_ops>
|
||||
|
||||
<draw_ops name="close_button_normal">
|
||||
<include name="button_bg"/>
|
||||
<include name="close_button_icon"/>
|
||||
</draw_ops>
|
||||
<draw_ops name="close_button_prelight">
|
||||
<include name="button_bg_prelight"/>
|
||||
<include name="close_button_icon"/>
|
||||
</draw_ops>
|
||||
<draw_ops name="close_button_pressed">
|
||||
<include name="button_bg_pressed"/>
|
||||
<include name="close_button_icon"/>
|
||||
</draw_ops>
|
||||
<draw_ops name="close_button_unfocused">
|
||||
<include name="button_bg_unfocused"/>
|
||||
<include name="close_button_icon_unfocused"/>
|
||||
</draw_ops>
|
||||
<draw_ops name="close_button_unfocused_prelight">
|
||||
<include name="button_bg_unfocused_prelight"/>
|
||||
<include name="close_button_icon_unfocused"/>
|
||||
</draw_ops>
|
||||
<draw_ops name="close_button_unfocused_pressed">
|
||||
<include name="button_bg_unfocused_pressed"/>
|
||||
<include name="close_button_icon_unfocused"/>
|
||||
</draw_ops>
|
||||
|
||||
<!-- maximize icon -->
|
||||
<draw_ops name="maximize_button_icon">
|
||||
<!-- outside border -->
|
||||
<rectangle color="shade/gtk:bg[SELECTED]/0.7" filled="false"
|
||||
x="((width-(Bmin`max`height-Bpad*2))/2)-1" y="((height-(Bmin`max`height-Bpad*2))/2)-1"
|
||||
width="width-((width-(Bmin`max`height-Bpad*2))/2)*2+1" height="height-((height-(Bmin`max`height-Bpad*2))/2)*2+1"/>
|
||||
<rectangle color="shade/gtk:bg[SELECTED]/0.7" filled="false"
|
||||
x="((width-(Bmin`max`height-Bpad*2))/2)+1" y="((height-(Bmin`max`height-Bpad*2))/2)+2"
|
||||
width="width-((width-(Bmin`max`height-Bpad*2))/2)*2-3" height="height-((height-(Bmin`max`height-Bpad*2))/2)*2-4"/>
|
||||
|
||||
<!-- icon -->
|
||||
<rectangle color="blend/gtk:bg[SELECTED]/#FFFFFF/0.75" filled="false"
|
||||
x="((width-(Bmin`max`height-Bpad*2))/2)" y="((height-(Bmin`max`height-Bpad*2))/2)"
|
||||
width="width-((width-(Bmin`max`height-Bpad*2))/2)*2-1" height="height-((height-(Bmin`max`height-Bpad*2))/2)*2-1"/>
|
||||
<line color="blend/gtk:bg[SELECTED]/#FFFFFF/0.75" width="1"
|
||||
x1="((width-(Bmin`max`height-Bpad*2))/2) + 1" y1="((height-(Bmin`max`height-Bpad*2))/2) + 1"
|
||||
x2="width-((width-(Bmin`max`height-Bpad*2))/2)" y2="((height-(Bmin`max`height-Bpad*2))/2) + 1"/>
|
||||
</draw_ops>
|
||||
|
||||
<draw_ops name="maximize_button_icon_unfocused">
|
||||
<rectangle color="blend/gtk:fg[NORMAL]/gtk:bg[NORMAL]/0.45" filled="false"
|
||||
x="((width-(Bmin`max`height-Bpad*2))/2)" y="((height-(Bmin`max`height-Bpad*2))/2)"
|
||||
width="width-((width-(Bmin`max`height-Bpad*2))/2)*2-1" height="height-((height-(Bmin`max`height-Bpad*2))/2)*2-1"/>
|
||||
<line color="blend/gtk:fg[NORMAL]/gtk:bg[NORMAL]/0.45" width="1"
|
||||
x1="((width-(Bmin`max`height-Bpad*2))/2) + 1" y1="((height-(Bmin`max`height-Bpad*2))/2) + 1"
|
||||
x2="width-((width-(Bmin`max`height-Bpad*2))/2)" y2="((height-(Bmin`max`height-Bpad*2))/2) + 1"/>
|
||||
</draw_ops>
|
||||
|
||||
<draw_ops name="maximize_button_normal">
|
||||
<include name="button_bg"/>
|
||||
<include name="maximize_button_icon"/>
|
||||
</draw_ops>
|
||||
<draw_ops name="maximize_button_prelight">
|
||||
<include name="button_bg_prelight"/>
|
||||
<include name="maximize_button_icon"/>
|
||||
</draw_ops>
|
||||
<draw_ops name="maximize_button_pressed">
|
||||
<include name="button_bg_pressed"/>
|
||||
<include name="maximize_button_icon"/>
|
||||
</draw_ops>
|
||||
<draw_ops name="maximize_button_unfocused">
|
||||
<include name="button_bg_unfocused"/>
|
||||
<include name="maximize_button_icon_unfocused"/>
|
||||
</draw_ops>
|
||||
<draw_ops name="maximize_button_unfocused_prelight">
|
||||
<include name="button_bg_unfocused_prelight"/>
|
||||
<include name="maximize_button_icon_unfocused"/>
|
||||
</draw_ops>
|
||||
<draw_ops name="maximize_button_unfocused_pressed">
|
||||
<include name="button_bg_unfocused_pressed"/>
|
||||
<include name="maximize_button_icon_unfocused"/>
|
||||
</draw_ops>
|
||||
|
||||
<!-- restore icon -->
|
||||
<draw_ops name="restore_button_icon">
|
||||
<!-- outside border -->
|
||||
<rectangle color="shade/gtk:bg[SELECTED]/0.7" filled="false"
|
||||
x="((width-(Bmin`max`height-Bpad*2))/2)" y="((height-(Bmin`max`height-Bpad*2))/2)"
|
||||
width="width-((width-(Bmin`max`height-Bpad*2))/2)*2-1" height="height-((height-(Bmin`max`height-Bpad*2))/2)*2-1"/>
|
||||
<rectangle color="shade/gtk:bg[SELECTED]/0.7" filled="false"
|
||||
x="((width-(Bmin`max`height-Bpad*2))/2)+2" y="((height-(Bmin`max`height-Bpad*2))/2)+3"
|
||||
width="width-((width-(Bmin`max`height-Bpad*2))/2)*2-5" height="height-((height-(Bmin`max`height-Bpad*2))/2)*2-6"/>
|
||||
|
||||
<!-- icon -->
|
||||
<rectangle color="blend/gtk:bg[SELECTED]/#FFFFFF/0.75" filled="false"
|
||||
x="((width-(Bmin`max`height-Bpad*2))/2) + 1" y="((height-(Bmin`max`height-Bpad*2))/2) + 1"
|
||||
width="width-((width-(Bmin`max`height-Bpad*2))/2)*2-3" height="height-((height-(Bmin`max`height-Bpad*2))/2)*2-3"/>
|
||||
<line color="blend/gtk:bg[SELECTED]/#FFFFFF/0.75" width="1"
|
||||
x1="((width-(Bmin`max`height-Bpad*2))/2) + 2" y1="((height-(Bmin`max`height-Bpad*2))/2) + 2"
|
||||
x2="width-((width-(Bmin`max`height-Bpad*2))/2) - 2" y2="((height-(Bmin`max`height-Bpad*2))/2) + 2"/>
|
||||
</draw_ops>
|
||||
|
||||
<draw_ops name="restore_button_icon_unfocused">
|
||||
<rectangle color="blend/gtk:fg[NORMAL]/gtk:bg[NORMAL]/0.45" filled="false"
|
||||
x="((width-(Bmin`max`height-Bpad*2))/2) + 1" y="((height-(Bmin`max`height-Bpad*2))/2) + 1"
|
||||
width="width-((width-(Bmin`max`height-Bpad*2))/2)*2-3" height="height-((height-(Bmin`max`height-Bpad*2))/2)*2-3"/>
|
||||
<line color="blend/gtk:fg[NORMAL]/gtk:bg[NORMAL]/0.45" width="1"
|
||||
x1="((width-(Bmin`max`height-Bpad*2))/2) + 2" y1="((height-(Bmin`max`height-Bpad*2))/2) + 2"
|
||||
x2="width-((width-(Bmin`max`height-Bpad*2))/2) - 2" y2="((height-(Bmin`max`height-Bpad*2))/2) + 2"/>
|
||||
</draw_ops>
|
||||
|
||||
<draw_ops name="restore_button_normal">
|
||||
<include name="button_bg"/>
|
||||
<include name="restore_button_icon"/>
|
||||
</draw_ops>
|
||||
<draw_ops name="restore_button_prelight">
|
||||
<include name="button_bg_prelight"/>
|
||||
<include name="restore_button_icon"/>
|
||||
</draw_ops>
|
||||
<draw_ops name="restore_button_pressed">
|
||||
<include name="button_bg_pressed"/>
|
||||
<include name="restore_button_icon"/>
|
||||
</draw_ops>
|
||||
<draw_ops name="restore_button_unfocused">
|
||||
<include name="button_bg_unfocused"/>
|
||||
<include name="restore_button_icon_unfocused"/>
|
||||
</draw_ops>
|
||||
<draw_ops name="restore_button_unfocused_prelight">
|
||||
<include name="button_bg_unfocused_prelight"/>
|
||||
<include name="restore_button_icon_unfocused"/>
|
||||
</draw_ops>
|
||||
<draw_ops name="restore_button_unfocused_pressed">
|
||||
<include name="button_bg_unfocused_pressed"/>
|
||||
<include name="restore_button_icon_unfocused"/>
|
||||
</draw_ops>
|
||||
|
||||
<!-- minimize icon -->
|
||||
<draw_ops name="minimize_button_icon">
|
||||
<!-- outside border -->
|
||||
<rectangle color="shade/gtk:bg[SELECTED]/0.7" filled="false"
|
||||
x="((width-(Bmin`max`height-Bpad*2))/2)-1" y="height - ((height-(Bmin`max`height-Bpad*2))/2) - 3"
|
||||
width="width-((width-(Bmin`max`height-Bpad*2))/2)*2+1" height="3"/>
|
||||
<!-- icon -->
|
||||
<rectangle color="blend/gtk:bg[SELECTED]/#FFFFFF/0.75" filled="true"
|
||||
x="((width-(Bmin`max`height-Bpad*2))/2)" y="height - ((height-(Bmin`max`height-Bpad*2))/2) - 2"
|
||||
width="width-((width-(Bmin`max`height-Bpad*2))/2)*2" height="2"/>
|
||||
</draw_ops>
|
||||
|
||||
<draw_ops name="minimize_button_icon_unfocused">
|
||||
<rectangle color="blend/gtk:fg[NORMAL]/gtk:bg[NORMAL]/0.45" filled="true"
|
||||
x="((width-(Bmin`max`height-Bpad*2))/2)" y="height - ((height-(Bmin`max`height-Bpad*2))/2) - 2"
|
||||
width="width-((width-(Bmin`max`height-Bpad*2))/2)*2" height="2"/>
|
||||
</draw_ops>
|
||||
|
||||
<draw_ops name="minimize_button_normal">
|
||||
<include name="button_bg"/>
|
||||
<include name="minimize_button_icon"/>
|
||||
</draw_ops>
|
||||
<draw_ops name="minimize_button_prelight">
|
||||
<include name="button_bg_prelight"/>
|
||||
<include name="minimize_button_icon"/>
|
||||
</draw_ops>
|
||||
<draw_ops name="minimize_button_pressed">
|
||||
<include name="button_bg_pressed"/>
|
||||
<include name="minimize_button_icon"/>
|
||||
</draw_ops>
|
||||
<draw_ops name="minimize_button_unfocused">
|
||||
<include name="button_bg_unfocused"/>
|
||||
<include name="minimize_button_icon_unfocused"/>
|
||||
</draw_ops>
|
||||
<draw_ops name="minimize_button_unfocused_prelight">
|
||||
<include name="button_bg_unfocused_prelight"/>
|
||||
<include name="minimize_button_icon_unfocused"/>
|
||||
</draw_ops>
|
||||
<draw_ops name="minimize_button_unfocused_pressed">
|
||||
<include name="button_bg_unfocused_pressed"/>
|
||||
<include name="minimize_button_icon_unfocused"/>
|
||||
</draw_ops>
|
||||
|
||||
<draw_ops name="blank">
|
||||
<!-- nothing -->
|
||||
</draw_ops>
|
||||
|
||||
<!-- ::: FRAME STYLES ::: -->
|
||||
<frame_style name="normal" geometry="normal">
|
||||
<piece position="entire_background" draw_ops="round_bevel_unfocused"/>
|
||||
<piece position="title" draw_ops="title_unfocused"/>
|
||||
<button function="close" state="normal" draw_ops="close_button_unfocused"/>
|
||||
<button function="close" state="pressed" draw_ops="close_button_unfocused_pressed"/>
|
||||
<button function="close" state="prelight" draw_ops="close_button_unfocused_prelight"/>
|
||||
<button function="maximize" state="normal" draw_ops="maximize_button_unfocused"/>
|
||||
<button function="maximize" state="pressed" draw_ops="maximize_button_unfocused_pressed"/>
|
||||
<button function="maximize" state="prelight" draw_ops="maximize_button_unfocused_prelight"/>
|
||||
<button function="minimize" state="normal" draw_ops="minimize_button_unfocused"/>
|
||||
<button function="minimize" state="pressed" draw_ops="minimize_button_unfocused_pressed"/>
|
||||
<button function="minimize" state="prelight" draw_ops="minimize_button_unfocused_prelight"/>
|
||||
<button function="menu" state="normal" draw_ops="menu_button_normal"/>
|
||||
<button function="menu" state="pressed" draw_ops="menu_button_pressed"/>
|
||||
</frame_style>
|
||||
|
||||
<frame_style name="normal_shaded" geometry="shaded" parent="normal">
|
||||
<piece position="entire_background" draw_ops="round_bevel_unfocused_shaded"/>
|
||||
</frame_style>
|
||||
|
||||
<frame_style name="focused" geometry="normal" parent="normal">
|
||||
<piece position="entire_background" draw_ops="round_bevel"/>
|
||||
<piece position="title" draw_ops="title"/>
|
||||
<button function="close" state="normal" draw_ops="close_button_normal"/>
|
||||
<button function="close" state="pressed" draw_ops="close_button_pressed"/>
|
||||
<button function="close" state="prelight" draw_ops="close_button_prelight"/>
|
||||
<button function="maximize" state="normal" draw_ops="maximize_button_normal"/>
|
||||
<button function="maximize" state="pressed" draw_ops="maximize_button_pressed"/>
|
||||
<button function="maximize" state="prelight" draw_ops="maximize_button_prelight"/>
|
||||
<button function="minimize" state="normal" draw_ops="minimize_button_normal"/>
|
||||
<button function="minimize" state="pressed" draw_ops="minimize_button_pressed"/>
|
||||
<button function="minimize" state="prelight" draw_ops="minimize_button_prelight"/>
|
||||
</frame_style>
|
||||
|
||||
<frame_style name="focused_shaded" geometry="shaded" parent="focused">
|
||||
<piece position="entire_background" draw_ops="round_bevel_shaded"/>
|
||||
</frame_style>
|
||||
|
||||
<frame_style name="normal_maximized" geometry="normal_maximized" parent="normal">
|
||||
<piece position="entire_background" draw_ops="bevel_maximized_unfocused"/>
|
||||
<button function="maximize" state="normal" draw_ops="restore_button_unfocused"/>
|
||||
<button function="maximize" state="pressed" draw_ops="restore_button_unfocused_pressed"/>
|
||||
<button function="maximize" state="prelight" draw_ops="restore_button_unfocused_prelight"/>
|
||||
</frame_style>
|
||||
|
||||
<frame_style name="focused_maximized" geometry="normal_maximized" parent="focused">
|
||||
<piece position="entire_background" draw_ops="bevel_maximized"/>
|
||||
<button function="maximize" state="normal" draw_ops="restore_button_normal"/>
|
||||
<button function="maximize" state="pressed" draw_ops="restore_button_pressed"/>
|
||||
<button function="maximize" state="prelight" draw_ops="restore_button_prelight"/>
|
||||
</frame_style>
|
||||
|
||||
<frame_style name="border" geometry="border" parent="normal">
|
||||
<piece position="entire_background" draw_ops="border"/>
|
||||
<piece position="title" draw_ops="blank"/>
|
||||
</frame_style>
|
||||
|
||||
<frame_style name="utility_normal" geometry="utility" parent="normal">
|
||||
<piece position="entire_background" draw_ops="bevel_unfocused"/>
|
||||
</frame_style>
|
||||
<frame_style name="utility_focused" geometry="utility" parent="focused">
|
||||
<piece position="entire_background" draw_ops="bevel"/>
|
||||
</frame_style>
|
||||
<frame_style name="utility_focused_shaded" geometry="utility" parent="focused_shaded">
|
||||
<piece position="entire_background" draw_ops="bevel_shaded"/>
|
||||
</frame_style>
|
||||
|
||||
<frame_style_set name="normal">
|
||||
<frame focus="yes" state="normal" resize="both" style="focused"/>
|
||||
<frame focus="no" state="normal" resize="both" style="normal"/>
|
||||
<frame focus="yes" state="maximized" style="focused_maximized"/>
|
||||
<frame focus="no" state="maximized" style="normal_maximized"/>
|
||||
<frame focus="yes" state="shaded" style="focused_shaded"/>
|
||||
<frame focus="no" state="shaded" style="normal_shaded"/>
|
||||
<frame focus="yes" state="maximized_and_shaded" style="focused_maximized"/>
|
||||
<frame focus="no" state="maximized_and_shaded" style="normal_maximized"/>
|
||||
</frame_style_set>
|
||||
|
||||
<frame_style_set name="utility" parent="normal">
|
||||
<frame focus="yes" state="normal" resize="both" style="utility_focused"/>
|
||||
<frame focus="no" state="normal" resize="both" style="utility_normal"/>
|
||||
<!-- this is a bunch of crack since utility windows shouldn't be maximized -->
|
||||
<frame focus="yes" state="maximized" style="focused"/>
|
||||
<frame focus="no" state="maximized" style="normal"/>
|
||||
<frame focus="yes" state="shaded" style="utility_focused_shaded"/>
|
||||
<frame focus="no" state="shaded" style="utility_normal"/>
|
||||
<frame focus="yes" state="maximized_and_shaded" style="focused_shaded"/>
|
||||
<frame focus="no" state="maximized_and_shaded" style="normal"/>
|
||||
</frame_style_set>
|
||||
|
||||
<frame_style_set name="border">
|
||||
<frame focus="yes" state="normal" resize="both" style="border"/>
|
||||
<frame focus="no" state="normal" resize="both" style="border"/>
|
||||
<frame focus="yes" state="maximized" style="border"/>
|
||||
<frame focus="no" state="maximized" style="border"/>
|
||||
<frame focus="yes" state="shaded" style="border"/>
|
||||
<frame focus="no" state="shaded" style="border"/>
|
||||
<frame focus="yes" state="maximized_and_shaded" style="border"/>
|
||||
<frame focus="no" state="maximized_and_shaded" style="border"/>
|
||||
</frame_style_set>
|
||||
|
||||
<window type="normal" style_set="normal"/>
|
||||
<window type="dialog" style_set="normal"/>
|
||||
<window type="modal_dialog" style_set="normal"/>
|
||||
<window type="menu" style_set="normal"/>
|
||||
<window type="utility" style_set="utility"/>
|
||||
<window type="border" style_set="border"/>
|
||||
|
||||
<menu_icon function="close" state="normal" draw_ops="close_button_icon_unfocused"/>
|
||||
<menu_icon function="maximize" state="normal" draw_ops="maximize_button_icon_unfocused"/>
|
||||
<menu_icon function="unmaximize" state="normal" draw_ops="restore_button_icon_unfocused"/>
|
||||
<menu_icon function="minimize" state="normal" draw_ops="minimize_button_icon_unfocused"/>
|
||||
|
||||
</metacity_theme>
|
@ -17,8 +17,8 @@
|
||||
#
|
||||
# Author: David Cantrell <dcantrell@redhat.com>
|
||||
|
||||
EXTRA_DIST = *.rst *.txt
|
||||
EXTRA_DIST = $(srcdir)/*.rst $(srcdir)/*.txt
|
||||
|
||||
CLEANFILES = api *.xml
|
||||
CLEANFILES = api $(builddir)/*.xml
|
||||
|
||||
MAINTAINERCLEANFILES = Makefile.in
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -312,9 +312,14 @@ Requires the remote syslog process to accept incoming connections.
|
||||
|
||||
=== inst.virtiolog ===
|
||||
Forward logs through the named virtio port (a character device at
|
||||
`/dev/virtio-ports/<name>`). A port named `org.fedoraproject.anaconda.log.0`
|
||||
`/dev/virtio-ports/<name>`).
|
||||
|
||||
If not provided, a port named `org.fedoraproject.anaconda.log.0`
|
||||
will be used by default, if found.
|
||||
|
||||
See https://fedoraproject.org/wiki/Anaconda/Logging for more info on setting
|
||||
up logging via virtio.
|
||||
|
||||
=== inst.zram ===
|
||||
Forces/disables (on/off) usage of zRAM swap for the installation process.
|
||||
|
||||
|
63
anaconda/docs/kickstart.rst
Normal file
63
anaconda/docs/kickstart.rst
Normal file
@ -0,0 +1,63 @@
|
||||
Anaconda Kickstart Documentation
|
||||
================================
|
||||
|
||||
Anaconda uses `kickstart <https://github.com/rhinstaller/pykickstart>`_ to automate
|
||||
installation and as a data store for the user interface. It also extends the kickstart
|
||||
commands `documented here <https://fedoraproject.org/wiki/Anaconda/Kickstart>`_
|
||||
by adding a new kickstart section named %anaconda where commands to control the behavior
|
||||
of Anaconda will be defined.
|
||||
|
||||
.. contents:: %anaconda section commands
|
||||
|
||||
|
||||
pwpolicy
|
||||
========
|
||||
|
||||
pwpolicy <name> [--minlen=LENGTH] [--minquality=QUALITY] [--strict|notstrict] [--emptyok|notempty] [--changesok|nochanges]
|
||||
Set the policy to use for the named password entry.
|
||||
|
||||
name
|
||||
Name of the password entry, currently supported values are: root, user and luks
|
||||
|
||||
--minlen (**8**)
|
||||
Minimum password length. This is passed on to libpwquality.
|
||||
|
||||
--minquality (**50**)
|
||||
Minimum libpwquality to consider good. When using --strict it will not allow
|
||||
passwords with a quality lower than this.
|
||||
|
||||
--strict (**DEFAULT**)
|
||||
Strict password enforcement. Passwords not meeting the --minquality level will
|
||||
not be allowed.
|
||||
|
||||
--notstrict
|
||||
Passwords not meeting the --minquality level will be allowed after Done is clicked
|
||||
twice.
|
||||
|
||||
--emptyok (**DEFAULT**)
|
||||
Allow empty password.
|
||||
|
||||
--notempty
|
||||
Don't allow an empty password
|
||||
|
||||
--changesok
|
||||
Allow UI to be used to change the password/user when it has already been set in
|
||||
the kickstart.
|
||||
|
||||
--nochanges (**DEFAULT**)
|
||||
Do not allow UI to be used to change the password/user if it has been set in
|
||||
the kickstart.
|
||||
|
||||
The defaults for these are set in the /usr/share/anaconda/interactive-defaults.ks file
|
||||
provided by Anaconda. If a product, such as Fedora Workstation, wishes to override them
|
||||
then a product.img needs to be created with a new version of the file included.
|
||||
|
||||
When using a kickstart the defaults can be overridded by placing a %anaconda section into
|
||||
the kickstart, like this::
|
||||
|
||||
%anaconda
|
||||
pwpolicy root --minlen=10 --minquality=60 --strict --notempty --nochanges
|
||||
%end
|
||||
|
||||
.. note:: The commit message for pwpolicy included some incorrect examples.
|
||||
|
@ -1,13 +0,0 @@
|
||||
Updated June 11, 2002
|
||||
---------------------
|
||||
|
||||
Current list of things we check for (good for regression testing):
|
||||
|
||||
- That selected PE is smaller than any PV in VG.
|
||||
- That size requests for LV are a multiple of the PE.
|
||||
- That maximum LV for a given PE is bigger than any currently defined LV in VG.
|
||||
- That if you change the PE, all the reclamped LV will fit in VG.
|
||||
- That VG_name+LV_name is unique for all VG.
|
||||
- That mount points are used only once.
|
||||
- Give warning if more than 10% of a PV is lost because of the PE selected.
|
||||
- That the bootable partition is not a LV.
|
@ -1,15 +0,0 @@
|
||||
How to make screenshots:
|
||||
|
||||
|
||||
This will only currently work for graphical installs.
|
||||
|
||||
During a graphical installation, you can now press SHIFT-Print Screen
|
||||
and a screenshot of the current installation screen will be taken.
|
||||
|
||||
These are stored in the following directory:
|
||||
|
||||
/root/anaconda-screenshots/
|
||||
|
||||
The screenshots can be accessed once the newly-installed system is rebooted.
|
||||
|
||||
|
@ -1,25 +0,0 @@
|
||||
Mediacheck documentation
|
||||
October, 2008
|
||||
|
||||
|
||||
Mediacheck is a tool we use to test the integrity of ISO images. The
|
||||
ISO9660 specification allows for a 512 byte region which is for
|
||||
application use. We use it to store a checksum of the ISO image. Of
|
||||
couse putting the checksum into this region will change the checksum
|
||||
of the final ISO image, so when we verify the checksum later we have
|
||||
to fill in this 512 region with the original contents before the
|
||||
implantation. It is set to all ASCII 32 decimal spaces.
|
||||
|
||||
If you have a set of ISO images you can implant the checksum data with
|
||||
this command:
|
||||
|
||||
implantmd5iso <isoname>
|
||||
|
||||
NOTE: You cannot re-implant an ISO once its been implanted.
|
||||
|
||||
To check a ISO image you can use this command line:
|
||||
|
||||
checkisomd5 <isoname>
|
||||
|
||||
The tools are in the isomd5sum package.
|
||||
|
@ -1,16 +0,0 @@
|
||||
Rescue mode
|
||||
-----------
|
||||
|
||||
1/4/1999 Michael Fulbright
|
||||
|
||||
Rescue mode is implemented via a bootable CDROM currently. The user
|
||||
specifies 'linux rescue' at the syslinux prompt when the CDROM boots.
|
||||
Then the kernel and an initial ramdisk is loaded. The installer is
|
||||
run and the user is dropped into bash.
|
||||
|
||||
The upd-instroot script in the anaconda/ source toplevel directory
|
||||
is responsible for creating the instimage which is used as the
|
||||
root for the rescue environment. It is located in /mnt/cdrom/Redhat/instimage
|
||||
when the CDROM is mounted under /mnt/cdrom.
|
||||
|
||||
|
@ -1,100 +0,0 @@
|
||||
Threads in anaconda? No!
|
||||
David Cantrell <dcantrell@redhat.com>
|
||||
|
||||
|
||||
INTRODUCTION
|
||||
|
||||
Threads make a lot of people run screaming. That's entirely
|
||||
understandable because thread concurrency can be a pain. In this short
|
||||
document, I want to explain why threads are in anaconda and how to work
|
||||
with them in the code.
|
||||
|
||||
MISCONCEPTIONS
|
||||
|
||||
Just to make sure everyone is on the same page, threads are similar to
|
||||
processes. The big advantage we get is easier shared data structures.
|
||||
Threads can communicate over more methods than just signals. But,
|
||||
multithreaded does not mean that we are taking every operation out to
|
||||
a separate thread.
|
||||
|
||||
ANACONDA THREADS
|
||||
|
||||
The idea for anaconda threads is to simplify life for things that can
|
||||
or need to run parallel to other operations. So we will reserve the
|
||||
use of threads for tasks that fit in to this category well (the logging
|
||||
system, for instance) and keep the bulk of the installer in the main
|
||||
thread.
|
||||
|
||||
THREADS AND PYTHON
|
||||
|
||||
Python has a nice model for threading. Threads in Python extend the
|
||||
threading.Thread class. So an easy way to identify something that will
|
||||
run or can be run as a thread is seeing a class definition like this:
|
||||
|
||||
class SomeClass(threading.Thread):
|
||||
|
||||
You still have your __init__ method for the constructor, but threads
|
||||
also have a run() method and a join() method (there are others, but
|
||||
I will just discuss these).
|
||||
|
||||
The run() method is called when you start the thread. This is where
|
||||
you want to do the work. Normally this happens in the class
|
||||
constructor, but in threads we need that separated out to a different
|
||||
method.
|
||||
|
||||
The join() method is to block execution of other threads. Whatever you
|
||||
put in the join() method will run and other threads will be blocked
|
||||
while it runs. Now, this method is only run when you call it explicitly
|
||||
from another thread, so think of it as similar to waitpid().
|
||||
|
||||
Python has the thread and threading modules. Use threading as it's
|
||||
built on top of thread and provides a threading system similar to the
|
||||
POSIX thread model.
|
||||
|
||||
More information:
|
||||
http://docs.python.org/lib/module-threading.html
|
||||
|
||||
THREAD NAMES
|
||||
|
||||
Threads have names in Python. They are automatically assigned or you
|
||||
can specify the name. For anaconda it probably makes more sense to
|
||||
name our threads since we won't be launching more than one for the
|
||||
same task.
|
||||
|
||||
The convention I'm using is: NameThr
|
||||
For example: RelNotesThr
|
||||
|
||||
The name is arbitrary, but we should probably have some sort of
|
||||
consistency.
|
||||
|
||||
PYGTK AND THREADS
|
||||
|
||||
GTK+ presents the biggest challenge for threads, but it's not
|
||||
impossible. When you call gtk.main(), you need to call it like this:
|
||||
|
||||
gtk.threads_enter()
|
||||
gtk.main()
|
||||
gtk.threads_leave()
|
||||
|
||||
Calls to PyGTK methods or fiddling with GTK objects...all that has to
|
||||
be wrapped in threads_enter/threads_leave calls. The suggested syntax
|
||||
is:
|
||||
|
||||
gtk.threads_enter()
|
||||
try:
|
||||
# do stuff
|
||||
finally:
|
||||
gtk.threads_leave()
|
||||
|
||||
Suggested reading:
|
||||
|
||||
http://www.async.com.br/faq/pygtk/index.py?req=show&file=faq20.006.htp
|
||||
http://developer.gnome.org/doc/API/2.0/gdk/gdk-Threads.html
|
||||
|
||||
|
||||
I will try to expand this document as I move through more threading code.
|
||||
Email me if you have any questions.
|
||||
|
||||
--
|
||||
David Cantrell
|
||||
<dcantrell@redhat.com>
|
@ -1,129 +0,0 @@
|
||||
Transifex and anaconda Development
|
||||
09-Mar-2011
|
||||
by: David Cantrell <dcantrell@redhat.com>
|
||||
-----------------------------------------------------------------------------
|
||||
|
||||
Setting up the new transifex-client on your system for anaconda builds.
|
||||
|
||||
1) Install the transifex-client package:
|
||||
yum install transifex-client
|
||||
-or-
|
||||
yum --enablerepo=updates-testing install transifex-client
|
||||
-or-
|
||||
yum --enablerepo=epel-testing install transifex-client
|
||||
|
||||
2) Create a Transifex.net account at https://fedora.transifex.net/
|
||||
NOTE: This system is not linked to FAS, it's hosted by another company,
|
||||
so it requires another account at this time. I'm sure this will change
|
||||
in the future, but this is how it is for now.
|
||||
|
||||
3) Configure 'tx' on your system:
|
||||
tx init
|
||||
Accept default host, fill in your username and password generated in #2.
|
||||
|
||||
Now tx is set up on your system. The translation files will only be pulled
|
||||
when a 'make release' is done. The 'make dist' step will just create a tar
|
||||
file of the what we have in our repo. The 'make bumpver' step will also
|
||||
push a new anaconda.pot file to Transifex, so any string changes are pushed
|
||||
to them on a regular basis.
|
||||
|
||||
NOTE: tx pull is slow. This is why I only added it to the 'make bumpver'
|
||||
step.
|
||||
|
||||
There are some other procedures related to tx that will have to be done
|
||||
when we create new branches or when there are translation errors.
|
||||
|
||||
|
||||
MAKING A RELEASE
|
||||
----------------
|
||||
|
||||
git clean -d -x -f
|
||||
./autogen.sh && ./configure --disable-static \
|
||||
--enable-introspection --enable-gtk-doc
|
||||
make bumpver # tx pull by dependent po-pull target
|
||||
git commit -a -m "New version." # DO NOT run 'git clean -d -x -f' after
|
||||
make && make release # signed tag happens after dist now
|
||||
|
||||
The process here is mostly the same. I do not recommend that you run
|
||||
git clean between 'make bumpver' and 'make release'. The reason is you
|
||||
will have to run 'tx pull' again and that's slow, plus translations may
|
||||
have changed between the two steps.
|
||||
|
||||
The 'make tag' step now runs after 'make dist' in case dist generation
|
||||
fails. That way you don't end up with a partially created dist AND a
|
||||
bad tag you have to delete.
|
||||
|
||||
The 'make scratch' target will also run po-pull to get translations. If
|
||||
we need translation files in other targets, we can add po-pull as a
|
||||
dependent target.
|
||||
|
||||
|
||||
DEALING WITH ERRORS IN *.po FILES
|
||||
---------------------------------
|
||||
|
||||
Translators sometimes introduce errors in the .po files. What we generally
|
||||
do is try to fix it if it's an obvious typo, or just revert the change and
|
||||
go back to the old po file. Reverting is harder now since we are not
|
||||
storing po files in our repo, but in severe cases we can go and fetch the
|
||||
last build and pull the affected po file from there and use it to revert the
|
||||
changes.
|
||||
|
||||
Here's an example of a po file error that will halt a 'make release':
|
||||
|
||||
rm -f af.gmo && /usr/bin/msgfmt -c --statistics -o af.gmo af.po
|
||||
af.po:7: field `Language-Team' still has initial default value
|
||||
af.po:1614: number of format specifications in 'msgid' and 'msgstr[1]' does not match
|
||||
/usr/bin/msgfmt: found 1 fatal error
|
||||
|
||||
In this case, I am going to the last known good af.po. To update Transifex,
|
||||
I do:
|
||||
|
||||
cp /path/to/last/known/good/af.po po/af.po
|
||||
touch po/af.po
|
||||
tx push -t -l af
|
||||
|
||||
The touch is necessary because transifex.net uses timestamps to determine
|
||||
if it should update its translation data with the po file you are asking
|
||||
it to use.
|
||||
|
||||
|
||||
CREATING A NEW ANACONDA BRANCH
|
||||
------------------------------
|
||||
|
||||
When we make a new branch, we need to branch the translation files.
|
||||
|
||||
First you need to populate the project with the initial po files. I suggest
|
||||
using the ones from the master branch, e.g.:
|
||||
|
||||
git checkout master
|
||||
git clean -xdf
|
||||
tx pull -a
|
||||
# leave the *.po files in the po/ subdirectory
|
||||
git checkout BRANCH_NAME
|
||||
|
||||
Next you need to update the transifex config with the new branch:
|
||||
|
||||
tx set --execute --auto-local -r anaconda.BRANCH_NAME -s en -t PO \
|
||||
-f po/anaconda.pot "po/<lang>.po"
|
||||
|
||||
The last argument is correct as-is, it's not a place where you substitute
|
||||
something for <lang>. The BRANCH_NAME will be something other than 'master'.
|
||||
For example, when we branch for F-20:
|
||||
|
||||
tx set --execute --auto-local -r anaconda.f20-branch -s en -t PO \
|
||||
-f po/anaconda.pot "po/<lang>.po"
|
||||
|
||||
Check the .tx/config file on the branch to ensure it references the correct
|
||||
anaconda.BRANCH_NAME in Transifex and remove the [anaconda.master] block so
|
||||
that it doesn't try to push to master and the new branch.
|
||||
|
||||
Now you can run:
|
||||
|
||||
tx push -s -t
|
||||
|
||||
This will push the po files and anaconda.pot from master to the BRANCH_NAME
|
||||
resource for anaconda in Transifex. This is just an initial seed that the
|
||||
translation team can work with. And since we branch from master, the code
|
||||
should be more or less in sync with the po files at branch time.
|
||||
|
||||
Don't forget to commit the new .tx/config file to the branch.
|
116
anaconda/docs/translations.txt
Normal file
116
anaconda/docs/translations.txt
Normal file
@ -0,0 +1,116 @@
|
||||
Translations and anaconda Development
|
||||
24-Feb-2015
|
||||
by: David Cantrell <dcantrell@redhat.com>
|
||||
Brian C. Lane <bcl@redhat.com>
|
||||
-----------------------------------------------------------------------------
|
||||
|
||||
Anaconda, as of version 23.1, is using https://fedora.zanata.com for
|
||||
translations. You will need an account in order to pull translations until bug
|
||||
https://bugzilla.redhat.com/show_bug.cgi?id=1172618 (anonymous pull requests)
|
||||
has been resolved.
|
||||
|
||||
The zanata-python-client is used by the build scripts, not the full zanata
|
||||
package.
|
||||
|
||||
|
||||
CLIENT SETUP
|
||||
------------
|
||||
Setting up the zanata-python-client on your system for anaconda builds.
|
||||
|
||||
1) Install the zanata-python-client package:
|
||||
yum install zanata-python-client
|
||||
|
||||
2) Create a Zanata account at https://fedora.zanata.org
|
||||
NOTE: This system is linked to FAS, but the 'remember my login' option
|
||||
only appears to work for about an hour, not 7 days as it claims.
|
||||
|
||||
3) Navigate to Dashboard->Settings->Client and click 'Generate New API Key'
|
||||
|
||||
4) Copy the contents of the Configuration text box to ~/.config/zanata.ini
|
||||
and make sure permissions are 0600.
|
||||
|
||||
Now zanata is set up on your system. The translation files will only be pulled
|
||||
when a 'make release' is done. The 'make dist' step will just create a tar
|
||||
file of the what we have in our repo. The 'make bumpver' step will also push a
|
||||
new anaconda.pot file to Zanata, so any string changes are pushed to them on a
|
||||
regular basis.
|
||||
|
||||
NOTE: zanata pull is slow. This is why I only added it to the 'make bumpver'
|
||||
step.
|
||||
|
||||
There are some other procedures related to zanata that will have to be done
|
||||
when we create new branches or when there are translation errors.
|
||||
|
||||
|
||||
MAKING A RELEASE
|
||||
----------------
|
||||
|
||||
git clean -d -x -f
|
||||
./autogen.sh && ./configure --disable-static \
|
||||
--enable-introspection --enable-gtk-doc
|
||||
make bumpver # zanata pull by dependent po-pull target
|
||||
git commit -a -m "New version." # DO NOT run 'git clean -d -x -f' after
|
||||
make && make release # signed tag happens after dist now
|
||||
|
||||
The process here is mostly the same. I do not recommend that you run
|
||||
git clean between 'make bumpver' and 'make release'. The reason is you
|
||||
will have to run 'zanata pull' again and that's slow, plus translations may
|
||||
have changed between the two steps.
|
||||
|
||||
The 'make tag' step now runs after 'make dist' in case dist generation
|
||||
fails. That way you don't end up with a partially created dist AND a
|
||||
bad tag you have to delete.
|
||||
|
||||
The 'make scratch' and 'make po-empty' targets will now create empty
|
||||
translation files so that local test builds can be created without needing a
|
||||
zanata account.
|
||||
|
||||
|
||||
DEALING WITH ERRORS IN *.po FILES
|
||||
---------------------------------
|
||||
|
||||
Translators sometimes introduce errors in the .po files. What we generally
|
||||
do is try to fix it if it's an obvious typo, or just revert the change and
|
||||
go back to the old po file. Reverting is harder now since we are not
|
||||
storing po files in our repo, but in severe cases we can go and fetch the
|
||||
last build and pull the affected po file from there and use it to revert the
|
||||
changes.
|
||||
|
||||
Here's an example of a po file error that will halt a 'make release':
|
||||
|
||||
rm -f af.gmo && /usr/bin/msgfmt -c --statistics -o af.gmo af.po
|
||||
af.po:7: field `Language-Team' still has initial default value
|
||||
af.po:1614: number of format specifications in 'msgid' and 'msgstr[1]' does not match
|
||||
/usr/bin/msgfmt: found 1 fatal error
|
||||
|
||||
In this case, I am going to the last known good af.po. To update Zanata,
|
||||
I do:
|
||||
|
||||
cp /path/to/last/known/good/af.po po/af.po
|
||||
zanata push --push-type target --lang af
|
||||
|
||||
|
||||
CREATING A NEW ANACONDA BRANCH
|
||||
------------------------------
|
||||
|
||||
When we make a new branch, we need to branch the translation files.
|
||||
|
||||
On https://fedora.zanata.com go to the project and version to use as a base.
|
||||
Select 'New Version+' from the hidden drop down menu on the right. Give it a
|
||||
name that matches the git branch. eg. f23-branch and select the version to copy
|
||||
from (usually master). Wait for it to finish processing documents.
|
||||
|
||||
Create a new git branch:
|
||||
|
||||
git checkout master
|
||||
git clean -xdf
|
||||
git checkout BRANCH_NAME
|
||||
|
||||
At https://fedora.zanata.com select the new version and then select the
|
||||
'Download Config file' from the hidden dropdown menu next to 'Settings'. This
|
||||
will download a new zanata.xml file. Replace the zanata.xml file in the root
|
||||
directory of anaconda project with this new one.
|
||||
|
||||
git add -u
|
||||
git commit -m "New Zanata config file"
|
||||
git push --set-upstream origin BRANCH_NAME
|
@ -37,6 +37,17 @@ path="$2" # optional, could be empty
|
||||
|
||||
modprobe -q loop
|
||||
|
||||
# If we're waiting for a cdrom kickstart, the user might need to swap discs.
|
||||
# So if this is a CDROM drive, make a note of it, but don't mount it (yet).
|
||||
# Once we get the kickstart either the udev trigger or disk-reinsertion will
|
||||
# retrigger this script, and we'll mount the disk as normal.
|
||||
if str_starts "$kickstart" "cdrom" && [ ! -e /tmp/ks.cfg.done ]; then
|
||||
if dev_is_cdrom "$dev"; then
|
||||
> /tmp/anaconda-on-cdrom
|
||||
exit 0
|
||||
fi
|
||||
fi
|
||||
|
||||
info "anaconda using disk root at $dev"
|
||||
mount $dev $repodir || warn "Couldn't mount $dev"
|
||||
anaconda_live_root_dir $repodir $path
|
||||
|
@ -165,6 +165,26 @@ when_any_cdrom_appears() {
|
||||
>> $rulesfile
|
||||
}
|
||||
|
||||
plymouth_running() {
|
||||
type plymouth >/dev/null 2>&1 && plymouth --ping 2>/dev/null
|
||||
}
|
||||
|
||||
# print something to the display (and put it in the log so we know what's up)
|
||||
tell_user() {
|
||||
if plymouth_running; then
|
||||
# NOTE: if we're doing graphical splash but we don't have all the
|
||||
# font-rendering libraries, no message will appear.
|
||||
plymouth display-message --text="$*"
|
||||
echo "$*" # this goes to journal only
|
||||
else
|
||||
echo "$*" >&2 # this goes to journal+console
|
||||
fi
|
||||
}
|
||||
|
||||
dev_is_cdrom() {
|
||||
udevadm info --query=property --name=$1 | grep -q 'ID_CDROM=1'
|
||||
}
|
||||
|
||||
# dracut doesn't bring up the network unless:
|
||||
# a) $netroot is set (i.e. you have a network root device), or
|
||||
# b) /tmp/net.ifaces exists.
|
||||
|
@ -27,9 +27,14 @@ case $repo in
|
||||
. /lib/nfs-lib.sh
|
||||
info "anaconda mounting NFS repo at $repo"
|
||||
str_starts "$repo" "nfsiso:" && repo=nfs:${repo#nfsiso:}
|
||||
|
||||
# Replace hex space with a real one. All uses of repo need to be quoted
|
||||
# after this point.
|
||||
repo=${repo//\\x20/ }
|
||||
|
||||
# HACK: work around some Mysterious NFS4 Badness (#811242 and friends)
|
||||
# by defaulting to nfsvers=3 when no version is requested
|
||||
nfs_to_var $repo $netif
|
||||
nfs_to_var "$repo" $netif
|
||||
if [ "$nfs" != "nfs4" ] && ! strstr "$options" "vers="; then
|
||||
repo="nfs:$options,nfsvers=3:$server:$path"
|
||||
fi
|
||||
|
@ -1,4 +1,4 @@
|
||||
#!/usr/bin/python
|
||||
#!/usr/bin/python2
|
||||
#
|
||||
# Copyright (C) 2013 by Red Hat, Inc. All rights reserved.
|
||||
#
|
||||
@ -43,6 +43,7 @@ import os
|
||||
import subprocess
|
||||
import time
|
||||
import glob
|
||||
import readline # pylint:disable=unused-import
|
||||
|
||||
log = logging.getLogger("DD")
|
||||
|
||||
@ -312,7 +313,7 @@ def fake_drivers(num):
|
||||
""" Generate a number of fake drivers for testing
|
||||
"""
|
||||
drivers = []
|
||||
for i in xrange(0, num):
|
||||
for i in range(0, num):
|
||||
d = Driver()
|
||||
d.source = "driver-%d" % i
|
||||
d.flags = "modules"
|
||||
@ -475,7 +476,7 @@ def selection_menu(items, title, info_func, multi_choice=True, refresh=False):
|
||||
num_items = page_length
|
||||
else:
|
||||
num_items = len(items) % page_length
|
||||
for i in xrange(0, num_items):
|
||||
for i in range(0, num_items):
|
||||
item_idx = ((page-1) * page_length) + i
|
||||
if multi_choice:
|
||||
if items[item_idx].selected:
|
||||
|
@ -14,16 +14,27 @@ info "anaconda: fetching kickstart from $dev:$path"
|
||||
mnt="$(find_mount $dev)"
|
||||
|
||||
if [ -n "$mnt" ]; then
|
||||
cp $mnt$path /tmp/ks.cfg
|
||||
cp $mnt$path /tmp/ks.cfg 2>&1
|
||||
else
|
||||
tmpmnt="$(mkuniqdir /run/install tmpmnt)"
|
||||
if mount -o ro $dev $tmpmnt; then
|
||||
cp $tmpmnt/$path /tmp/ks.cfg
|
||||
cp $tmpmnt/$path /tmp/ks.cfg 2>&1
|
||||
umount $tmpmnt
|
||||
rmdir $tmpmnt
|
||||
fi
|
||||
fi
|
||||
|
||||
|
||||
# if we're waiting for a cdrom kickstart, tell the user so they can swap discs
|
||||
if str_starts "$kickstart" "cdrom"; then
|
||||
if [ ! -f /tmp/ks.cfg ]; then
|
||||
tell_user "Please insert CDROM containing '$path'..."
|
||||
exit 0
|
||||
elif [ -f /tmp/anaconda-on-cdrom ]; then
|
||||
tell_user "Kickstart loaded. Please re-insert installation media."
|
||||
fi
|
||||
fi
|
||||
|
||||
if [ -f /tmp/ks.cfg ]; then
|
||||
parse_kickstart /tmp/ks.cfg
|
||||
run_kickstart
|
||||
|
@ -1,4 +1,4 @@
|
||||
#!/usr/bin/python
|
||||
#!/usr/bin/python2
|
||||
#vim: set fileencoding=utf8
|
||||
# parse-kickstart - read a kickstart file and emit equivalent dracut boot args
|
||||
#
|
||||
@ -88,12 +88,26 @@ class NFS(commands.nfs.FC6_NFS):
|
||||
else:
|
||||
method="nfs:%s:%s" % (self.server, self.dir)
|
||||
|
||||
# Spaces on the cmdline need to be '\ '
|
||||
method = method.replace(" ", "\\ ")
|
||||
return "inst.repo=%s" % method
|
||||
|
||||
class URL(commands.url.F18_Url):
|
||||
def dracut_args(self, args, lineno, obj):
|
||||
# FIXME: self.proxy, self.noverifyssl
|
||||
return "inst.repo=%s" % self.url
|
||||
# Spaces in the url need to be %20
|
||||
if self.url:
|
||||
method = self.url.replace(" ", "%20")
|
||||
else:
|
||||
method = None
|
||||
|
||||
args = ["inst.repo=%s" % method]
|
||||
|
||||
if self.noverifyssl:
|
||||
args.append("rd.noverifyssl")
|
||||
if self.proxy:
|
||||
args.append("proxy=%s" % self.proxy)
|
||||
|
||||
return "\n".join(args)
|
||||
|
||||
class Updates(commands.updates.F7_Updates):
|
||||
def dracut_args(self, args, lineno, obj):
|
||||
@ -127,7 +141,7 @@ class DriverDisk(commands.driverdisk.F14_DriverDisk):
|
||||
# are processed later.
|
||||
return "\n".join(dd_net)
|
||||
|
||||
class Network(commands.network.F21_Network):
|
||||
class Network(commands.network.F22_Network):
|
||||
def dracut_args(self, args, lineno, net):
|
||||
'''
|
||||
NOTE: The first 'network' line get special treatment:
|
||||
@ -321,6 +335,16 @@ def ksnet_to_dracut(args, lineno, net, bootdev=False):
|
||||
|
||||
return " ".join(line)
|
||||
|
||||
def add_s390_settings(dev, ifcfg):
|
||||
s390cfg = s390_settings(dev)
|
||||
if s390cfg['SUBCHANNELS']:
|
||||
ifcfg.pop('HWADDR', None)
|
||||
ifcfg['SUBCHANNELS'] = s390cfg['SUBCHANNELS']
|
||||
if s390cfg['NETTYPE']:
|
||||
ifcfg['NETTYPE'] = s390cfg['NETTYPE']
|
||||
if s390cfg['OPTIONS']:
|
||||
ifcfg['OPTIONS'] = s390cfg['OPTIONS']
|
||||
|
||||
def ksnet_to_ifcfg(net, filename=None):
|
||||
'''Write an ifcfg file for the given kickstart network config'''
|
||||
dev = net.device
|
||||
@ -329,8 +353,8 @@ def ksnet_to_ifcfg(net, filename=None):
|
||||
if not dev:
|
||||
return
|
||||
if (not os.path.isdir("/sys/class/net/%s" % dev)
|
||||
and not net.bondslaves and not net.teamslaves):
|
||||
log.info("can't find device %s" % dev)
|
||||
and not net.bondslaves and not net.teamslaves and not net.bridgeslaves):
|
||||
log.info("can't find device %s", dev)
|
||||
return
|
||||
ifcfg = dict()
|
||||
if filename is None:
|
||||
@ -338,20 +362,16 @@ def ksnet_to_ifcfg(net, filename=None):
|
||||
if not os.path.isdir("/tmp/ifcfg"):
|
||||
os.makedirs("/tmp/ifcfg")
|
||||
ifcfg['DEVICE'] = dev
|
||||
ifcfg['HWADDR'] = readsysfile("/sys/class/net/%s/address" % dev)
|
||||
hwaddr = readsysfile("/sys/class/net/%s/address" % dev)
|
||||
if "ifname={0}:{1}".format(dev, hwaddr).upper() in open("/proc/cmdline").read().upper():
|
||||
# rename by initscript's 60-net-rules on target system after switchroot
|
||||
ifcfg['HWADDR'] = hwaddr
|
||||
ifcfg['UUID'] = str(uuid.uuid4())
|
||||
# we set real ONBOOT value in anaconda, here
|
||||
# we use it to activate devcies by NM on start
|
||||
ifcfg['ONBOOT'] = "yes" if net.activate else "no"
|
||||
|
||||
s390cfg = s390_settings(dev)
|
||||
if s390cfg['SUBCHANNELS']:
|
||||
ifcfg.pop('HWADDR')
|
||||
ifcfg['SUBCHANNELS'] = s390cfg['SUBCHANNELS']
|
||||
if s390cfg['NETTYPE']:
|
||||
ifcfg['NETTYPE'] = s390cfg['NETTYPE']
|
||||
if s390cfg['OPTIONS']:
|
||||
ifcfg['OPTIONS'] = s390cfg['OPTIONS']
|
||||
add_s390_settings(dev, ifcfg)
|
||||
|
||||
# dhcp etc.
|
||||
ifcfg['BOOTPROTO'] = net.bootProto
|
||||
@ -417,11 +437,12 @@ def ksnet_to_ifcfg(net, filename=None):
|
||||
'NAME' : "%s slave %s" % (dev, i),
|
||||
'UUID' : str(uuid.uuid4()),
|
||||
'ONBOOT' : "yes",
|
||||
'MASTER' : dev,
|
||||
'MASTER' : ifcfg['UUID'],
|
||||
'HWADDR' : readsysfile("/sys/class/net/%s/address" % slave),
|
||||
}
|
||||
add_s390_settings(slave, slave_ifcfg)
|
||||
slave_filename = "/tmp/ifcfg/ifcfg-%s" % "_".join(slave_ifcfg['NAME'].split(" "))
|
||||
log.info("writing ifcfg %s for slave %s of bond %s" % (slave_filename, slave, dev))
|
||||
log.info("writing ifcfg %s for slave %s of bond %s", slave_filename, slave, dev)
|
||||
write_ifcfg(slave_filename, slave_ifcfg)
|
||||
|
||||
if net.teamslaves:
|
||||
@ -445,7 +466,44 @@ def ksnet_to_ifcfg(net, filename=None):
|
||||
slave_ifcfg['TEAM_PORT_CONFIG'] = "'" + cfg + "'"
|
||||
|
||||
slave_filename = "/tmp/ifcfg/ifcfg-%s" % "_".join(slave_ifcfg['NAME'].split(" "))
|
||||
log.info("writing ifcfg %s for slave %s of team %s" % (slave_filename, slave, dev))
|
||||
log.info("writing ifcfg %s for slave %s of team %s", slave_filename, slave, dev)
|
||||
write_ifcfg(slave_filename, slave_ifcfg)
|
||||
|
||||
if net.bridgeslaves:
|
||||
|
||||
ifcfg.pop('HWADDR', None)
|
||||
ifcfg['TYPE'] = "Bridge"
|
||||
ifcfg['NAME'] = "Bridge connection %s" % dev
|
||||
|
||||
options = {}
|
||||
for opt in net.bridgeopts.split(","):
|
||||
key, _sep, value = opt.partition("=")
|
||||
if not value:
|
||||
log.error("Invalid bridge option %s", opt)
|
||||
continue
|
||||
key = key.replace('-', '_')
|
||||
options[key] = value
|
||||
stp = options.pop("stp", None)
|
||||
if stp:
|
||||
ifcfg['STP'] = stp
|
||||
delay = options.pop("forward_delay", None)
|
||||
if delay:
|
||||
ifcfg['DELAY'] = delay
|
||||
if options:
|
||||
keyvalues = ["%s=%s" % (key, options[key]) for key in options]
|
||||
ifcfg['BRIDGING_OPTS'] = '"' + " ".join(keyvalues) + '"'
|
||||
|
||||
for i, slave in enumerate(net.bridgeslaves.split(","), 1):
|
||||
slave_ifcfg = {
|
||||
'TYPE' : "Ethernet",
|
||||
'NAME' : "%s slave %s" % (dev, i),
|
||||
'UUID' : str(uuid.uuid4()),
|
||||
'ONBOOT' : "yes",
|
||||
'BRIDGE' : dev,
|
||||
'HWADDR' : readsysfile("/sys/class/net/%s/address" % slave),
|
||||
}
|
||||
slave_filename = "/tmp/ifcfg/ifcfg-%s" % "_".join(slave_ifcfg['NAME'].split(" "))
|
||||
log.info("writing ifcfg %s for slave %s of bridge %s", slave_filename, slave, dev)
|
||||
write_ifcfg(slave_filename, slave_ifcfg)
|
||||
|
||||
if net.vlanid:
|
||||
@ -459,7 +517,7 @@ def ksnet_to_ifcfg(net, filename=None):
|
||||
ifcfg['PHYSDEV'] = dev
|
||||
filename = "/tmp/ifcfg/ifcfg-%s" % interface_name
|
||||
|
||||
log.info("writing ifcfg %s for %s" % (filename, dev))
|
||||
log.info("writing ifcfg %s for %s", filename, dev)
|
||||
if write_ifcfg(filename, ifcfg):
|
||||
return filename
|
||||
|
||||
@ -470,7 +528,7 @@ def write_ifcfg(filename, ifcfg):
|
||||
for k,v in ifcfg.items():
|
||||
f.write("%s=%s\n" % (k,v))
|
||||
except IOError as e:
|
||||
log.error("can't write %s: %s" % (filename, e))
|
||||
log.error("can't write %s: %s", filename, e)
|
||||
return False
|
||||
return True
|
||||
|
||||
@ -479,6 +537,7 @@ def process_kickstart(ksfile):
|
||||
handler.ksdevice = os.environ.get('ksdevice')
|
||||
parser = KickstartParser(handler, missingIncludeIsFatal=False, errorsAreFatal=False)
|
||||
parser.registerSection(NullSection(handler, sectionOpen="%addon"))
|
||||
parser.registerSection(NullSection(handler, sectionOpen="%anaconda"))
|
||||
log.info("processing kickstart file %s", ksfile)
|
||||
processed_file = preprocessKickstart(ksfile)
|
||||
try:
|
||||
|
@ -1,6 +1,7 @@
|
||||
#!/usr/bin/python
|
||||
#!/usr/bin/python2
|
||||
# python-deps - find the dependencies of a given python script.
|
||||
|
||||
import copy
|
||||
import os, sys
|
||||
from modulefinder import ModuleFinder
|
||||
# pylint: disable=wildcard-import
|
||||
@ -9,6 +10,8 @@ from distutils.sysconfig import *
|
||||
sitedir = get_python_lib()
|
||||
libdir = get_config_var('LIBDEST')
|
||||
|
||||
alsoNeeded = { libdir+"/urllib.py": libdir+"/urllib2.py" }
|
||||
|
||||
# A couple helper functions...
|
||||
def moduledir(pyfile):
|
||||
'''Given a python file, return the module dir it belongs to, or None.'''
|
||||
@ -30,10 +33,15 @@ def pyfiles(moddir):
|
||||
# OK. Use modulefinder to find all the modules etc. this script uses!
|
||||
mods = []
|
||||
deps = []
|
||||
for script in sys.argv[1:]:
|
||||
|
||||
scripts = copy.copy(sys.argv[1:])
|
||||
|
||||
while scripts:
|
||||
script = scripts.pop()
|
||||
|
||||
finder = ModuleFinder()
|
||||
finder.run_script(script) # parse the script
|
||||
for name, mod in finder.modules.iteritems():
|
||||
for mod in finder.modules.itervalues():
|
||||
if not mod.__file__: # this module is builtin, so we can skip it
|
||||
continue
|
||||
|
||||
@ -45,6 +53,9 @@ for script in sys.argv[1:]:
|
||||
deps += list(pyfiles(moddir)) # ...get the whole module
|
||||
mods.append(moddir)
|
||||
|
||||
if mod.__file__ in alsoNeeded and alsoNeeded[mod.__file__] not in deps:
|
||||
scripts.append(alsoNeeded[mod.__file__])
|
||||
|
||||
# Include some bits that the python install itself needs
|
||||
print(get_makefile_filename())
|
||||
print(get_config_h_filename())
|
||||
|
@ -1,22 +0,0 @@
|
||||
# tests/Makefile.am for anaconda
|
||||
#
|
||||
# Copyright (C) 2009 Red Hat, Inc.
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or modify
|
||||
# it under the terms of the GNU Lesser General Public License as published
|
||||
# by the Free Software Foundation; either version 2.1 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# This program 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 Lesser General Public License
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
#
|
||||
# Author: David Cantrell <dcantrell@redhat.com>
|
||||
|
||||
SUBDIRS = mock kickstart_test regex pyanaconda_test logpicker_test
|
||||
|
||||
MAINTAINERCLEANFILES = Makefile.in
|
@ -1,21 +0,0 @@
|
||||
# tests/Makefile.am for anaconda
|
||||
#
|
||||
# Copyright (C) 2009 Red Hat, Inc.
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or modify
|
||||
# it under the terms of the GNU Lesser General Public License as published
|
||||
# by the Free Software Foundation; either version 2.1 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# This program 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 Lesser General Public License
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
#
|
||||
# Author: David Cantrell <dcantrell@redhat.com>
|
||||
|
||||
EXTRA_DIST = *.py
|
||||
MAINTAINERCLEANFILES = Makefile.in
|
@ -1,94 +0,0 @@
|
||||
# Mocking library for module and code injection, replay tests and other
|
||||
# unit testing purposes
|
||||
#
|
||||
# Copyright (C) 2010
|
||||
# Red Hat, Inc. All rights reserved.
|
||||
#
|
||||
# This program 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 program 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 General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
#
|
||||
# Author(s): Martin Sivak <msivak@redhat.com>
|
||||
|
||||
|
||||
from disk import *
|
||||
from mock import *
|
||||
import unittest
|
||||
|
||||
def slow(f):
|
||||
"""Decorates a test method as being slow, usefull for python-nose filtering"""
|
||||
f.slow = True
|
||||
return f
|
||||
|
||||
def acceptance(f):
|
||||
"""Decorates test as belonging to acceptance testing and not useable in common devellopment unit testing. To be used with python-nose filtering."""
|
||||
f.acceptance = True
|
||||
return f
|
||||
|
||||
class TestCase(unittest.TestCase):
|
||||
def __init__(self, *args, **kwargs):
|
||||
unittest.TestCase.__init__(self, *args, **kwargs)
|
||||
self.injectedModules = {}
|
||||
|
||||
def setupModules(self, a):
|
||||
"""Mock specified list of modules and store the list so it can be
|
||||
properly unloaded during tearDown"""
|
||||
|
||||
import sys
|
||||
self.preexistingModules = set(sys.modules.keys())
|
||||
|
||||
for m in a:
|
||||
sys.modules[m] = Mock()
|
||||
self.injectedModules[m] = sys.modules[m]
|
||||
|
||||
def modifiedModule(self, mname, mod = None):
|
||||
"""Mark module (and all it's parents) as tainted"""
|
||||
|
||||
oldname=""
|
||||
for m in mname.split("."):
|
||||
self.injectedModules[oldname+m] = mod
|
||||
oldname += m + "."
|
||||
self.injectedModules[mname] = mod
|
||||
|
||||
def tearDownModules(self):
|
||||
"""Unload previously Mocked modules"""
|
||||
|
||||
import sys
|
||||
|
||||
for m in sys.modules.keys():
|
||||
if m in self.preexistingModules and not m in self.injectedModules:
|
||||
continue
|
||||
|
||||
del sys.modules[m]
|
||||
|
||||
def take_over_io(self, disk, target_module):
|
||||
""" Trick target_module into using disk object as the filesystem.
|
||||
|
||||
This is achieved by overriding the module's 'open' binding as well
|
||||
as many global bindings in os.path.
|
||||
"""
|
||||
target_module.open = disk.open
|
||||
self.modifiedModule(target_module.__name__)
|
||||
|
||||
import glob
|
||||
self.modifiedModule("glob")
|
||||
glob.glob = disk.glob_glob
|
||||
|
||||
import os
|
||||
self.modifiedModule("os.path")
|
||||
# this is what os.path implementaion points at, reimport:
|
||||
import posixpath
|
||||
self.modifiedModule("posixpath")
|
||||
os.listdir = disk.os_listdir
|
||||
os.path.exists = disk.os_path_exists
|
||||
os.path.isdir = disk.os_path_isdir
|
||||
os.access = disk.os_access
|
@ -1,128 +0,0 @@
|
||||
# Copyright (C) 2010
|
||||
# Red Hat, Inc. All rights reserved.
|
||||
#
|
||||
# This program 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 program 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 General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
#
|
||||
# Author(s): Martin Sivak <msivak@redhat.com>
|
||||
|
||||
from StringIO import StringIO
|
||||
import fnmatch
|
||||
import os
|
||||
|
||||
class DiskIO(object):
|
||||
"""Simple object to simplify mocking of file operations in Mock
|
||||
based testing"""
|
||||
|
||||
class TestFile(StringIO):
|
||||
def __init__(self, store, path, content = ""):
|
||||
StringIO.__init__(self, content)
|
||||
self._store = store
|
||||
self._path = path
|
||||
self._ro = False
|
||||
|
||||
def flush(self):
|
||||
self._store[self._path] = self.getvalue()
|
||||
|
||||
def close(self):
|
||||
self.flush()
|
||||
return StringIO.close(self)
|
||||
|
||||
def __del__(self):
|
||||
try:
|
||||
self.close()
|
||||
except (AttributeError, ValueError):
|
||||
pass
|
||||
|
||||
def __enter__(self):
|
||||
return self
|
||||
|
||||
def __exit__(self, *_):
|
||||
self.close()
|
||||
|
||||
class Dir(object):
|
||||
pass
|
||||
|
||||
class Link(object):
|
||||
pass
|
||||
|
||||
def __init__(self):
|
||||
self.reset()
|
||||
|
||||
def __getitem__(self, key):
|
||||
return self.fs[key]
|
||||
|
||||
def __setitem__(self, key, value):
|
||||
self.fs[key] = value
|
||||
|
||||
def reset(self):
|
||||
self.fs = {
|
||||
"/proc": self.Dir,
|
||||
"/proc/cmdline": "linux",
|
||||
}
|
||||
self._pwd = "/"
|
||||
|
||||
#Emulate file objects
|
||||
def open(self, filename, mode = "r"):
|
||||
path = os.path.join(self._pwd, filename)
|
||||
content = self.fs.get(path, None)
|
||||
if content == self.Dir:
|
||||
raise IOError("[Errno 21] Is a directory: '%s'" % (path))
|
||||
elif mode.startswith("w"):
|
||||
self.fs[path] = ""
|
||||
f = self.TestFile(self.fs, path, self.fs[path])
|
||||
elif mode.endswith("a"):
|
||||
if not path in self.fs:
|
||||
self.fs[path] = ""
|
||||
f = self.TestFile(self.fs, path, self.fs[path])
|
||||
f.seek(0, os.SEEK_END)
|
||||
elif content == None:
|
||||
raise IOError("[Errno 2] No such file or directory: '%s'" % (path,))
|
||||
elif mode.endswith("+"):
|
||||
f = self.TestFile(self.fs, path, content)
|
||||
if mode.startswith('r'):
|
||||
f.seek(0, os.SEEK_SET)
|
||||
else:
|
||||
f.seek(0, os.SEEK_END)
|
||||
else:
|
||||
f = self.TestFile(self.fs, path, content)
|
||||
|
||||
return f
|
||||
|
||||
#Emulate os calls
|
||||
def glob_glob(self, pattern):
|
||||
return fnmatch.filter(self.fs.keys(), pattern)
|
||||
|
||||
def os_listdir(self, path):
|
||||
return [entry[len(path):].lstrip('/') for entry in self.fs.keys()\
|
||||
if entry.startswith(path) and entry != path]
|
||||
|
||||
def os_path_exists(self, path):
|
||||
path = os.path.join(self._pwd, path)
|
||||
return self.fs.has_key(path)
|
||||
|
||||
def os_path_isdir(self, path):
|
||||
if not path.endswith("/"):
|
||||
path += "/"
|
||||
path += "*"
|
||||
return len(fnmatch.filter(self.fs.keys(), path)) > 0
|
||||
|
||||
def os_remove(self, path):
|
||||
path = os.path.join(self._pwd, path)
|
||||
try:
|
||||
del self.fs[path]
|
||||
except KeyError:
|
||||
raise OSError("[Errno 2] No such file or directory: '%s'" % (path,))
|
||||
|
||||
def os_access(self, path, mode):
|
||||
return self.os_path_exists(path)
|
@ -1,271 +0,0 @@
|
||||
# mock.py
|
||||
# Test tools for mocking and patching.
|
||||
# Copyright (C) 2007-2009 Michael Foord
|
||||
# E-mail: fuzzyman AT voidspace DOT org DOT uk
|
||||
|
||||
# mock 0.6.0
|
||||
# http://www.voidspace.org.uk/python/mock/
|
||||
|
||||
# Released subject to the BSD License
|
||||
# Please see http://www.voidspace.org.uk/python/license.shtml
|
||||
|
||||
# Scripts maintained at http://www.voidspace.org.uk/python/index.shtml
|
||||
# Comments, suggestions and bug reports welcome.
|
||||
|
||||
|
||||
__all__ = (
|
||||
'Mock',
|
||||
'patch',
|
||||
'patch_object',
|
||||
'sentinel',
|
||||
'DEFAULT'
|
||||
)
|
||||
|
||||
__version__ = '0.6.0'
|
||||
|
||||
class SentinelObject(object):
|
||||
def __init__(self, name):
|
||||
self.name = name
|
||||
|
||||
def __repr__(self):
|
||||
return '<SentinelObject "%s">' % self.name
|
||||
|
||||
|
||||
class Sentinel(object):
|
||||
def __init__(self):
|
||||
self._sentinels = {}
|
||||
|
||||
def __getattr__(self, name):
|
||||
return self._sentinels.setdefault(name, SentinelObject(name))
|
||||
|
||||
|
||||
sentinel = Sentinel()
|
||||
|
||||
DEFAULT = sentinel.DEFAULT
|
||||
|
||||
class OldStyleClass:
|
||||
pass
|
||||
ClassType = type(OldStyleClass)
|
||||
|
||||
def _is_magic(name):
|
||||
return '__%s__' % name[2:-2] == name
|
||||
|
||||
def _copy(value):
|
||||
if type(value) in (dict, list, tuple, set):
|
||||
return type(value)(value)
|
||||
return value
|
||||
|
||||
|
||||
class Mock(object):
|
||||
|
||||
def __init__(self, spec=None, side_effect=None, return_value=DEFAULT,
|
||||
name=None, parent=None, wraps=None):
|
||||
self._parent = parent
|
||||
self._name = name
|
||||
if spec is not None and not isinstance(spec, list):
|
||||
spec = [member for member in dir(spec) if not _is_magic(member)]
|
||||
|
||||
self._methods = spec
|
||||
self._children = {}
|
||||
self._return_value = return_value
|
||||
self.side_effect = side_effect
|
||||
self._wraps = wraps
|
||||
|
||||
self.reset_mock()
|
||||
|
||||
|
||||
def reset_mock(self):
|
||||
self.called = False
|
||||
self.call_args = None
|
||||
self.call_count = 0
|
||||
self.call_args_list = []
|
||||
self.method_calls = []
|
||||
for child in self._children.itervalues():
|
||||
child.reset_mock()
|
||||
if isinstance(self._return_value, Mock):
|
||||
self._return_value.reset_mock()
|
||||
|
||||
|
||||
def __get_return_value(self):
|
||||
if self._return_value is DEFAULT:
|
||||
self._return_value = Mock()
|
||||
return self._return_value
|
||||
|
||||
def __set_return_value(self, value):
|
||||
self._return_value = value
|
||||
|
||||
return_value = property(__get_return_value, __set_return_value)
|
||||
|
||||
|
||||
def __call__(self, *args, **kwargs):
|
||||
self.called = True
|
||||
self.call_count += 1
|
||||
self.call_args = (args, kwargs)
|
||||
self.call_args_list.append((args, kwargs))
|
||||
|
||||
parent = self._parent
|
||||
name = self._name
|
||||
while parent is not None:
|
||||
parent.method_calls.append((name, args, kwargs))
|
||||
if parent._parent is None:
|
||||
break
|
||||
name = parent._name + '.' + name
|
||||
parent = parent._parent
|
||||
|
||||
ret_val = DEFAULT
|
||||
if self.side_effect is not None:
|
||||
if (isinstance(self.side_effect, Exception) or
|
||||
isinstance(self.side_effect, (type, ClassType)) and
|
||||
issubclass(self.side_effect, Exception)):
|
||||
raise self.side_effect
|
||||
|
||||
ret_val = self.side_effect(*args, **kwargs)
|
||||
if ret_val is DEFAULT:
|
||||
ret_val = self.return_value
|
||||
|
||||
if self._wraps is not None and self._return_value is DEFAULT:
|
||||
return self._wraps(*args, **kwargs)
|
||||
if ret_val is DEFAULT:
|
||||
ret_val = self.return_value
|
||||
return ret_val
|
||||
|
||||
|
||||
def __getattr__(self, name):
|
||||
if self._methods is not None:
|
||||
if name not in self._methods:
|
||||
raise AttributeError("Mock object has no attribute '%s'" % name)
|
||||
elif _is_magic(name):
|
||||
raise AttributeError(name)
|
||||
|
||||
if name not in self._children:
|
||||
wraps = None
|
||||
if self._wraps is not None:
|
||||
wraps = getattr(self._wraps, name)
|
||||
self._children[name] = Mock(parent=self, name=name, wraps=wraps)
|
||||
|
||||
return self._children[name]
|
||||
|
||||
|
||||
def assert_called_with(self, *args, **kwargs):
|
||||
assert self.call_args == (args, kwargs), 'Expected: %s\nCalled with: %s' % ((args, kwargs), self.call_args)
|
||||
|
||||
|
||||
def _dot_lookup(thing, comp, import_path):
|
||||
try:
|
||||
return getattr(thing, comp)
|
||||
except AttributeError:
|
||||
__import__(import_path)
|
||||
return getattr(thing, comp)
|
||||
|
||||
|
||||
def _importer(target):
|
||||
components = target.split('.')
|
||||
import_path = components.pop(0)
|
||||
thing = __import__(import_path)
|
||||
|
||||
for comp in components:
|
||||
import_path += ".%s" % comp
|
||||
thing = _dot_lookup(thing, comp, import_path)
|
||||
return thing
|
||||
|
||||
|
||||
class _patch(object):
|
||||
def __init__(self, target, attribute, new, spec, create):
|
||||
self.target = target
|
||||
self.attribute = attribute
|
||||
self.new = new
|
||||
self.spec = spec
|
||||
self.create = create
|
||||
self.has_local = False
|
||||
|
||||
|
||||
def __call__(self, func):
|
||||
if hasattr(func, 'patchings'):
|
||||
func.patchings.append(self)
|
||||
return func
|
||||
|
||||
def patched(*args, **keywargs):
|
||||
# don't use a with here (backwards compatability with 2.5)
|
||||
extra_args = []
|
||||
for patching in patched.patchings:
|
||||
arg = patching.__enter__()
|
||||
if patching.new is DEFAULT:
|
||||
extra_args.append(arg)
|
||||
args += tuple(extra_args)
|
||||
try:
|
||||
return func(*args, **keywargs)
|
||||
finally:
|
||||
for patching in getattr(patched, 'patchings', []):
|
||||
patching.__exit__()
|
||||
|
||||
patched.patchings = [self]
|
||||
patched.__name__ = func.__name__
|
||||
patched.compat_co_firstlineno = getattr(func, "compat_co_firstlineno",
|
||||
func.func_code.co_firstlineno)
|
||||
return patched
|
||||
|
||||
|
||||
def get_original(self):
|
||||
target = self.target
|
||||
name = self.attribute
|
||||
create = self.create
|
||||
|
||||
original = DEFAULT
|
||||
if _has_local_attr(target, name):
|
||||
try:
|
||||
original = target.__dict__[name]
|
||||
except AttributeError:
|
||||
# for instances of classes with slots, they have no __dict__
|
||||
original = getattr(target, name)
|
||||
elif not create and not hasattr(target, name):
|
||||
raise AttributeError("%s does not have the attribute %r" % (target, name))
|
||||
return original
|
||||
|
||||
|
||||
def __enter__(self):
|
||||
new, spec, = self.new, self.spec
|
||||
original = self.get_original()
|
||||
if new is DEFAULT:
|
||||
# XXXX what if original is DEFAULT - shouldn't use it as a spec
|
||||
inherit = False
|
||||
if spec == True:
|
||||
# set spec to the object we are replacing
|
||||
spec = original
|
||||
if isinstance(spec, (type, ClassType)):
|
||||
inherit = True
|
||||
new = Mock(spec=spec)
|
||||
if inherit:
|
||||
new.return_value = Mock(spec=spec)
|
||||
self.temp_original = original
|
||||
setattr(self.target, self.attribute, new)
|
||||
return new
|
||||
|
||||
|
||||
def __exit__(self, *_):
|
||||
if self.temp_original is not DEFAULT:
|
||||
setattr(self.target, self.attribute, self.temp_original)
|
||||
else:
|
||||
delattr(self.target, self.attribute)
|
||||
del self.temp_original
|
||||
|
||||
|
||||
def patch_object(target, attribute, new=DEFAULT, spec=None, create=False):
|
||||
return _patch(target, attribute, new, spec, create)
|
||||
|
||||
|
||||
def patch(target, new=DEFAULT, spec=None, create=False):
|
||||
try:
|
||||
target, attribute = target.rsplit('.', 1)
|
||||
except (TypeError, ValueError):
|
||||
raise TypeError("Need a valid target to patch. You supplied: %r" % (target,))
|
||||
target = _importer(target)
|
||||
return _patch(target, attribute, new, spec, create)
|
||||
|
||||
|
||||
|
||||
def _has_local_attr(obj, name):
|
||||
try:
|
||||
return name in vars(obj)
|
||||
except TypeError:
|
||||
# objects without a __dict__
|
||||
return hasattr(obj, name)
|
@ -1,45 +0,0 @@
|
||||
# tests/pyanaconda_test/Makefile.am for anaconda
|
||||
#
|
||||
# Copyright (C) 2010 Red Hat, Inc.
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or modify
|
||||
# it under the terms of the GNU Lesser General Public License as published
|
||||
# by the Free Software Foundation; either version 2.1 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# This program 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 Lesser General Public License
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
#
|
||||
# Author: Tomas Mlcoch <tmlcoch@redhat.com>
|
||||
|
||||
EXTRA_DIST = *.py
|
||||
|
||||
MAINTAINERCLEANFILES = Makefile.in
|
||||
|
||||
ANACDIR = $(top_builddir)/pyanaconda
|
||||
TESTS_ENVIRONMENT = PYTHONPATH=$(top_builddir)/tests:$(ANACDIR)/isys/.libs:$(ANACDIR):$(top_builddir)
|
||||
|
||||
TESTS = backend_test.py \
|
||||
bootloader_test.py \
|
||||
cmdline_test.py \
|
||||
desktop_test.py \
|
||||
flags_test.py \
|
||||
image_test.py \
|
||||
language_test.py \
|
||||
network_test.py \
|
||||
packages_test.py \
|
||||
packaging_test.py \
|
||||
partintfhelpers_test.py \
|
||||
product_test.py \
|
||||
rescue_test.py \
|
||||
security_test.py \
|
||||
simpleconfig_test.py \
|
||||
timezone_test.py \
|
||||
upgrade_test.py \
|
||||
users_test.py \
|
||||
vnc_test.py
|
@ -1,227 +0,0 @@
|
||||
#!/usr/bin/python
|
||||
|
||||
import mock
|
||||
|
||||
class BackendTest(mock.TestCase):
|
||||
|
||||
def setUp(self):
|
||||
import pykickstart.commands
|
||||
|
||||
self.setupModules(["_isys", "block", 'parted', 'storage',
|
||||
'pyanaconda.storage.formats', 'logging',
|
||||
'logging.config',
|
||||
'ConfigParser', 'pyanaconda.anaconda_log',
|
||||
'pyanaconda.storage.storage_log',
|
||||
'pyanaconda.yuminstall'])
|
||||
|
||||
import pyanaconda
|
||||
pyanaconda.anaconda_log = mock.Mock()
|
||||
|
||||
import logging
|
||||
self.logger = mock.Mock()
|
||||
logging.getLogger.return_value = self.logger
|
||||
|
||||
self.DD_EXTRACTED = '/tmp/DD'
|
||||
|
||||
import pyanaconda.backend
|
||||
pyanaconda.backend.os = mock.Mock()
|
||||
pyanaconda.backend.DD_EXTRACTED = self.DD_EXTRACTED
|
||||
pyanaconda.backend.glob = mock.Mock()
|
||||
pyanaconda.backend.shutil = mock.Mock()
|
||||
|
||||
self.logger.reset_mock()
|
||||
|
||||
def tearDown(self):
|
||||
self.tearDownModules()
|
||||
|
||||
def anaconda_backend_copy_firmware_test(self):
|
||||
import pyanaconda.backend
|
||||
FILE = 'foo'
|
||||
pyanaconda.backend.glob.glob.return_value = [FILE]
|
||||
|
||||
anaconda = mock.Mock()
|
||||
ab = pyanaconda.backend.AnacondaBackend(anaconda)
|
||||
ab.copyFirmware()
|
||||
self.assertEqual(pyanaconda.backend.shutil.copyfile.call_args[0][0], FILE)
|
||||
|
||||
def anaconda_backend_do_post_install_test(self):
|
||||
import pyanaconda.backend
|
||||
from pyanaconda.constants import ROOT_PATH
|
||||
FILE = 'foo'
|
||||
A = 'a'
|
||||
B = 'b'
|
||||
C = 'c'
|
||||
pyanaconda.backend.AnacondaBackend.copyFirmware = mock.Mock()
|
||||
pyanaconda.backend.AnacondaBackend.kernelVersionList = mock.Mock(
|
||||
return_value=[(A, B, C)])
|
||||
pyanaconda.backend.packages = mock.Mock()
|
||||
pyanaconda.backend.glob.glob.return_value = [FILE]
|
||||
|
||||
pyanaconda.backend.os.path.exists.return_value=True
|
||||
pyanaconda.backend.os.path.basename.return_value=""
|
||||
|
||||
pyanaconda.backend.storage = mock.Mock()
|
||||
pyanaconda.backend.sys = mock.Mock()
|
||||
|
||||
anaconda = mock.Mock()
|
||||
anaconda.extraModules = True
|
||||
|
||||
ab = pyanaconda.backend.AnacondaBackend(anaconda)
|
||||
ab.doPostInstall(anaconda)
|
||||
|
||||
self.assertEqual(pyanaconda.backend.packages.method_calls[0],
|
||||
('recreateInitrd', (A, ROOT_PATH), {}))
|
||||
self.assertEqual(pyanaconda.backend.shutil.method_calls[0],
|
||||
('copytree', (FILE, ROOT_PATH + '/root/'), {}))
|
||||
self.assertEqual(pyanaconda.backend.shutil.method_calls[1],
|
||||
('copytree', (self.DD_EXTRACTED, ROOT_PATH + '/root/DD'), {}))
|
||||
self.assertTrue(pyanaconda.backend.storage.writeEscrowPackets.called)
|
||||
|
||||
def anaconda_backend_do_install_test(self):
|
||||
import pyanaconda.backend
|
||||
anaconda = mock.Mock()
|
||||
ab = pyanaconda.backend.AnacondaBackend(anaconda)
|
||||
self.assertRaises(NotImplementedError, ab.doInstall, anaconda)
|
||||
|
||||
def anaconda_backend_kernel_version_list_test(self):
|
||||
import pyanaconda.backend
|
||||
anaconda = mock.Mock()
|
||||
ab = pyanaconda.backend.AnacondaBackend(anaconda)
|
||||
ret = ab.kernelVersionList()
|
||||
self.assertEqual([], ret)
|
||||
|
||||
def anaconda_backend_get_minimum_size_mb_test(self):
|
||||
import pyanaconda.backend
|
||||
PART = mock.Mock()
|
||||
anaconda = mock.Mock()
|
||||
ab = pyanaconda.backend.AnacondaBackend(anaconda)
|
||||
ret = ab.getMinimumSizeMB(PART)
|
||||
self.assertEqual(0, ret)
|
||||
|
||||
def anaconda_backend_do_backend_setup_test(self):
|
||||
import pyanaconda.backend
|
||||
anaconda = mock.Mock()
|
||||
ab = pyanaconda.backend.AnacondaBackend(anaconda)
|
||||
ab.doBackendSetup(anaconda)
|
||||
self.assertTrue(self.logger.warning.called)
|
||||
|
||||
def anaconda_backend_group_exists_test(self):
|
||||
import pyanaconda.backend
|
||||
GROUP = mock.Mock()
|
||||
anaconda = mock.Mock()
|
||||
ab = pyanaconda.backend.AnacondaBackend(anaconda)
|
||||
ab.groupExists(GROUP)
|
||||
self.assertTrue(self.logger.warning.called)
|
||||
|
||||
def anaconda_backend_select_group_test(self):
|
||||
import pyanaconda.backend
|
||||
GROUP = mock.Mock()
|
||||
anaconda = mock.Mock()
|
||||
ab = pyanaconda.backend.AnacondaBackend(anaconda)
|
||||
ab.selectGroup(GROUP)
|
||||
self.assertTrue(self.logger.warning.called)
|
||||
|
||||
def anaconda_backend_deselect_group_test(self):
|
||||
import pyanaconda.backend
|
||||
GROUP = mock.Mock()
|
||||
anaconda = mock.Mock()
|
||||
ab = pyanaconda.backend.AnacondaBackend(anaconda)
|
||||
ab.deselectGroup(GROUP)
|
||||
self.assertTrue(self.logger.warning.called)
|
||||
|
||||
def anaconda_backend_package_exists_test(self):
|
||||
import pyanaconda.backend
|
||||
PKG = mock.Mock()
|
||||
anaconda = mock.Mock()
|
||||
ab = pyanaconda.backend.AnacondaBackend(anaconda)
|
||||
ab.packageExists(PKG)
|
||||
self.assertTrue(self.logger.warning.called)
|
||||
|
||||
def anaconda_backend_select_package_test(self):
|
||||
import pyanaconda.backend
|
||||
PKG = mock.Mock()
|
||||
anaconda = mock.Mock()
|
||||
ab = pyanaconda.backend.AnacondaBackend(anaconda)
|
||||
ab.selectPackage(PKG)
|
||||
self.assertTrue(self.logger.warning.called)
|
||||
|
||||
def anaconda_backend_deselect_package_test(self):
|
||||
import pyanaconda.backend
|
||||
PKG = mock.Mock()
|
||||
anaconda = mock.Mock()
|
||||
ab = pyanaconda.backend.AnacondaBackend(anaconda)
|
||||
ab.deselectPackage(PKG)
|
||||
self.assertTrue(self.logger.warning.called)
|
||||
|
||||
def anaconda_backend_get_default_groups_test(self):
|
||||
import pyanaconda.backend
|
||||
anaconda = mock.Mock()
|
||||
ab = pyanaconda.backend.AnacondaBackend(anaconda)
|
||||
ab.getDefaultGroups(anaconda)
|
||||
self.assertTrue(self.logger.warning.called)
|
||||
|
||||
def anaconda_backend_write_configuration_test(self):
|
||||
import pyanaconda.backend
|
||||
anaconda = mock.Mock()
|
||||
ab = pyanaconda.backend.AnacondaBackend(anaconda)
|
||||
ab.writeConfiguration()
|
||||
self.assertTrue(self.logger.warning.called)
|
||||
|
||||
def do_backend_setup_1_test(self):
|
||||
import pyanaconda.backend
|
||||
RET = -1
|
||||
pyanaconda.backend.DISPATCH_BACK = RET
|
||||
anaconda = mock.Mock()
|
||||
anaconda.backend.doBackendSetup.return_value = RET
|
||||
ret = pyanaconda.backend.doBackendSetup(anaconda)
|
||||
self.assertEqual(RET, ret)
|
||||
|
||||
def do_post_selection_test(self):
|
||||
import pyanaconda.backend
|
||||
anaconda = mock.Mock()
|
||||
pyanaconda.backend.doPostSelection(anaconda)
|
||||
self.assertTrue(anaconda.backend.doPostSelection.called)
|
||||
|
||||
def do_pre_install_test(self):
|
||||
import pyanaconda.backend
|
||||
anaconda = mock.Mock()
|
||||
pyanaconda.backend.doPreInstall(anaconda)
|
||||
self.assertTrue(anaconda.backend.doPreInstall.called)
|
||||
|
||||
def do_post_install_test(self):
|
||||
import pyanaconda.backend
|
||||
anaconda = mock.Mock()
|
||||
pyanaconda.backend.doPostInstall(anaconda)
|
||||
self.assertTrue(anaconda.backend.doPostInstall.called)
|
||||
|
||||
def do_install_test(self):
|
||||
import pyanaconda.backend
|
||||
anaconda = mock.Mock()
|
||||
pyanaconda.backend.doInstall(anaconda)
|
||||
self.assertTrue(anaconda.backend.doInstall.called)
|
||||
|
||||
def do_base_package_select_1_test(self):
|
||||
import pyanaconda.backend
|
||||
pyanaconda.backend.kickstart = mock.Mock()
|
||||
anaconda = mock.Mock()
|
||||
anaconda.ksdata = True
|
||||
|
||||
pyanaconda.backend.doBasePackageSelect(anaconda)
|
||||
self.assertTrue(anaconda.backend.resetPackageSelections.called)
|
||||
|
||||
def do_base_package_select_2_test(self):
|
||||
import pyanaconda.backend
|
||||
anaconda = mock.Mock()
|
||||
anaconda.ksdata = False
|
||||
|
||||
pyanaconda.backend.doBasePackageSelect(anaconda)
|
||||
self.assertTrue(anaconda.backend.resetPackageSelections.called)
|
||||
self.assertTrue(anaconda.instClass.setPackageSelection.called)
|
||||
self.assertTrue(anaconda.instClass.setGroupSelection.called)
|
||||
|
||||
def write_configuration_test(self):
|
||||
import pyanaconda.backend
|
||||
anaconda = mock.Mock()
|
||||
pyanaconda.backend.writeConfiguration(anaconda)
|
||||
self.assertTrue(anaconda.write.called)
|
||||
self.assertTrue(anaconda.backend.writeConfiguration)
|
@ -1,59 +0,0 @@
|
||||
import mock
|
||||
|
||||
class ArgumentsTest(mock.TestCase):
|
||||
def setUp(self):
|
||||
self.setupModules(
|
||||
['_isys', 'logging', 'pyanaconda.anaconda_log', 'block',
|
||||
'pyanaconda.storage',
|
||||
'pyanaconda.storage.devicelibs',
|
||||
'pyanaconda.storage.errors'])
|
||||
|
||||
import pyanaconda
|
||||
pyanaconda.anaconda_log = mock.Mock()
|
||||
|
||||
def tearDown(self):
|
||||
self.tearDownModules()
|
||||
|
||||
def test_basic(self):
|
||||
from pyanaconda.bootloader import Arguments
|
||||
a = Arguments()
|
||||
a.update(set(["a", "b", "c"]))
|
||||
b = Arguments()
|
||||
b.add("b")
|
||||
diff = a - b
|
||||
self.assertEqual(diff, set(["a", "c"]))
|
||||
self.assertIsInstance(diff, Arguments)
|
||||
assert(str(diff) in ["a c", "c a"])
|
||||
|
||||
def test_merge_ip(self):
|
||||
from pyanaconda.bootloader import Arguments
|
||||
# test that _merge_ip() doesnt break the simple case:
|
||||
a = Arguments(["one", "two", "ip=eth0:dhcp"])
|
||||
a._merge_ip()
|
||||
self.assertEqual(a, Arguments(["one", "two", "ip=eth0:dhcp"]))
|
||||
|
||||
# test that it does what it's supposed to:
|
||||
a = Arguments(["one", "two", "ip=eth0:dhcp", "ip=eth0:auto6",
|
||||
"ip=wlan0:dhcp",
|
||||
"ip=10.34.102.102::10.34.39.255:24:aklab:eth2:none"])
|
||||
a._merge_ip()
|
||||
self.assertEqual(a, set([
|
||||
"one", "two",
|
||||
"ip=wlan0:dhcp",
|
||||
"ip=10.34.102.102::10.34.39.255:24:aklab:eth2:none",
|
||||
"ip=eth0:auto6,dhcp"]))
|
||||
|
||||
def test_output_with_merge(self):
|
||||
from pyanaconda.bootloader import Arguments
|
||||
a = Arguments(["ip=eth0:dhcp"])
|
||||
self.assertEqual(str(a), "ip=eth0:dhcp")
|
||||
a = Arguments(["ip=eth0:dhcp", "ip=eth0:auto6"])
|
||||
assert(str(a) in ["ip=eth0:auto6,dhcp", "ip=eth0:dhcp,auto6"])
|
||||
|
||||
def test_sorting(self):
|
||||
from pyanaconda.bootloader import Arguments
|
||||
a = Arguments(["ip=eth0:dhcp", "rhgb", "quiet",
|
||||
"root=/dev/mapper/destroyers-rubies", "rd.md=0",
|
||||
"rd.luks=0"])
|
||||
# 'rhgb quiet' should be the final entries:
|
||||
assert(str(a).endswith("rhgb quiet"))
|
@ -1,100 +0,0 @@
|
||||
#!/usr/bin/python
|
||||
|
||||
import mock
|
||||
import sys
|
||||
|
||||
class DesktopTest(mock.TestCase):
|
||||
|
||||
def setUp(self):
|
||||
self.setupModules(["_isys", "block", "ConfigParser"])
|
||||
self.fs = mock.DiskIO()
|
||||
|
||||
self.fs.open('/mnt/sysimage/etc/inittab', 'w').write('id:5:initdefault:')
|
||||
self.fs.open('/mnt/sysimage/etc/sysconfig/desktop', 'w').write('')
|
||||
|
||||
import pyanaconda.desktop
|
||||
pyanaconda.desktop.log = mock.Mock()
|
||||
pyanaconda.desktop.open = self.fs.open
|
||||
|
||||
def tearDown(self):
|
||||
self.tearDownModules()
|
||||
|
||||
def set_default_run_level_1_test(self):
|
||||
import pyanaconda.desktop
|
||||
dskt = pyanaconda.desktop.Desktop()
|
||||
self.assertRaises(RuntimeError, dskt.setDefaultRunLevel, 1)
|
||||
self.assertRaises(RuntimeError, dskt.setDefaultRunLevel, 2)
|
||||
self.assertRaises(RuntimeError, dskt.setDefaultRunLevel, 4)
|
||||
|
||||
def set_default_run_level_2_test(self):
|
||||
import pyanaconda.desktop
|
||||
dskt = pyanaconda.desktop.Desktop()
|
||||
dskt.setDefaultRunLevel(3)
|
||||
self.assertEqual(dskt.runlevel, 3)
|
||||
dskt.setDefaultRunLevel(5)
|
||||
self.assertEqual(dskt.runlevel, 5)
|
||||
|
||||
def get_default_run_level_test(self):
|
||||
import pyanaconda.desktop
|
||||
dskt = pyanaconda.desktop.Desktop()
|
||||
self.assertEqual(dskt.getDefaultRunLevel(), dskt.runlevel)
|
||||
|
||||
def set_get_default_run_level_1_test(self):
|
||||
import pyanaconda.desktop
|
||||
dskt = pyanaconda.desktop.Desktop()
|
||||
dskt.setDefaultRunLevel(3)
|
||||
self.assertEqual(dskt.getDefaultRunLevel(), 3)
|
||||
|
||||
def set_get_default_run_level_2_test(self):
|
||||
import pyanaconda.desktop
|
||||
dskt = pyanaconda.desktop.Desktop()
|
||||
dskt.setDefaultRunLevel(5)
|
||||
self.assertEqual(dskt.getDefaultRunLevel(), 5)
|
||||
|
||||
def set_default_desktop_test(self):
|
||||
import pyanaconda.desktop
|
||||
dskt = pyanaconda.desktop.Desktop()
|
||||
dskt.setDefaultDesktop('desktop')
|
||||
self.assertEqual(dskt.info['DESKTOP'], 'desktop')
|
||||
|
||||
def get_default_desktop_test(self):
|
||||
import pyanaconda.desktop
|
||||
dskt = pyanaconda.desktop.Desktop()
|
||||
dskt.info['DESKTOP'] = 'foobar'
|
||||
ret = dskt.getDefaultDesktop()
|
||||
self.assertEqual(ret, 'foobar')
|
||||
|
||||
def set_get_default_desktop_test(self):
|
||||
import pyanaconda.desktop
|
||||
dskt = pyanaconda.desktop.Desktop()
|
||||
dskt.setDefaultDesktop('foo')
|
||||
ret = dskt.getDefaultDesktop()
|
||||
self.assertEqual(ret, 'foo')
|
||||
|
||||
def write_1_test(self):
|
||||
import pyanaconda.desktop
|
||||
dskt = pyanaconda.desktop.Desktop()
|
||||
dskt.write()
|
||||
self.assertEqual(self.fs['/mnt/sysimage/etc/inittab'],
|
||||
'id:3:initdefault:')
|
||||
|
||||
def write_2_test(self):
|
||||
import pyanaconda.desktop
|
||||
dskt = pyanaconda.desktop.Desktop()
|
||||
dskt.setDefaultRunLevel(5)
|
||||
dskt.write()
|
||||
self.assertEqual(self.fs['/mnt/sysimage/etc/inittab'],
|
||||
'id:5:initdefault:')
|
||||
|
||||
def write_3_test(self):
|
||||
import pyanaconda.desktop
|
||||
pyanaconda.desktop.os = mock.Mock()
|
||||
pyanaconda.desktop.os.path.isdir.return_value = True
|
||||
dskt = pyanaconda.desktop.Desktop()
|
||||
dskt.setDefaultDesktop('foo')
|
||||
dskt.write()
|
||||
self.assertEqual(self.fs['/mnt/sysimage/etc/inittab'],
|
||||
'id:3:initdefault:')
|
||||
self.assertEqual(self.fs['/mnt/sysimage/etc/sysconfig/desktop'],
|
||||
'DESKTOP="foo"\n')
|
||||
|
@ -1,132 +0,0 @@
|
||||
#!/usr/bin/python
|
||||
|
||||
# Test Bug 500198
|
||||
|
||||
import mock
|
||||
import sys
|
||||
|
||||
|
||||
class FlagsTest(mock.TestCase):
|
||||
"""Simulate /proc/cmdline parameters parsing (#500198)"""
|
||||
|
||||
def setUp(self):
|
||||
self.setupModules(["_isys", "block", "ConfigParser"])
|
||||
|
||||
self.fs = mock.DiskIO()
|
||||
|
||||
import pyanaconda.flags
|
||||
|
||||
self.mock2 = mock.Mock()
|
||||
pyanaconda.flags.open = mock.Mock(return_value=self.mock2)
|
||||
|
||||
def tearDown(self):
|
||||
self.tearDownModules()
|
||||
|
||||
def createcmdlinedict_1_test(self):
|
||||
"""/proc/cmdline without BOOT_IMAGE param"""
|
||||
import pyanaconda.flags
|
||||
|
||||
self.cmd = 'vmlinuz initrd=initrd.img stage2=hd:LABEL="Fedora" xdriver=vesa nomodeset'
|
||||
self.mock2.read = mock.Mock(return_value=self.cmd)
|
||||
cmddict = pyanaconda.flags.flags.createCmdlineDict()
|
||||
|
||||
self.assertEqual(set(cmddict.keys()),
|
||||
set(['vmlinuz', 'initrd', 'stage2', 'xdriver', 'nomodeset']))
|
||||
|
||||
def createcmdlinedict_2_test(self):
|
||||
"""/proc/cmdline param: quotes at end"""
|
||||
import pyanaconda.flags
|
||||
|
||||
self.cmd = 'vmlinuz BOOT_IMAGE=/boot/img initrd=initrd.img stage2=hd:LABEL="Fedora"'
|
||||
self.mock2.read = mock.Mock(return_value=self.cmd)
|
||||
try:
|
||||
cmddict = pyanaconda.flags.flags.createCmdlineDict()
|
||||
except (ValueError):
|
||||
self.assertTrue(False, "ValueError exception was raised.")
|
||||
|
||||
self.assertEqual(set(cmddict.keys()),
|
||||
set(['vmlinuz', 'BOOT_IMAGE', 'initrd', 'stage2']))
|
||||
|
||||
def createcmdlinedict_3_test(self):
|
||||
"""/proc/cmdline param BOOT_IMAGE with quotes (no quotes at end)"""
|
||||
import pyanaconda.flags
|
||||
|
||||
self.cmd = 'vmlinuz BOOT_IMAGE="img img" initrd=initrd.img'
|
||||
self.mock2.read = mock.Mock(return_value=self.cmd)
|
||||
cmddict = pyanaconda.flags.flags.createCmdlineDict()
|
||||
|
||||
self.assertEqual(set(cmddict.keys()),
|
||||
set(['vmlinuz', 'BOOT_IMAGE', 'initrd']))
|
||||
|
||||
def createcmdlinedict_4_test(self):
|
||||
"""/proc/cmdline param BOOT_IMAGE with quotes (no quotes at end) v2"""
|
||||
import pyanaconda.flags
|
||||
|
||||
self.cmd = 'vmlinuz BOOT_IMAGE="/boot/img" stage2=hd:LABEL="Fedora" initrd=initrd.img'
|
||||
self.mock2.read = mock.Mock(return_value=self.cmd)
|
||||
cmddict = pyanaconda.flags.flags.createCmdlineDict()
|
||||
|
||||
self.assertEqual(set(cmddict.keys()),
|
||||
set(['vmlinuz', 'BOOT_IMAGE', 'initrd', 'stage2']))
|
||||
|
||||
def createcmdlinedict_5_test(self):
|
||||
"""/proc/cmdline param: BOOT_IMAGE with quotes (+ quotes at end)"""
|
||||
import pyanaconda.flags
|
||||
|
||||
self.cmd = 'vmlinuz BOOT_IMAGE="/boot/img img" initrd=initrd.img stage2=hd:LABEL="Fedora"'
|
||||
self.mock2.read = mock.Mock(return_value=self.cmd)
|
||||
try:
|
||||
cmddict = pyanaconda.flags.flags.createCmdlineDict()
|
||||
except (ValueError):
|
||||
self.assertTrue(False, "ValueError exception was raised.")
|
||||
|
||||
self.assertEqual(set(cmddict.keys()),
|
||||
set(['vmlinuz', 'BOOT_IMAGE', 'initrd', 'stage2']))
|
||||
|
||||
def setattr_getattr_1_test(self):
|
||||
import pyanaconda.flags
|
||||
RET = 1
|
||||
self.cmd = 'vmlinuz initrd=initrd.img xdriver=vesa nomodeset'
|
||||
self.mock2.read = mock.Mock(return_value=self.cmd)
|
||||
pyanaconda.flags.flags.sshd = RET
|
||||
self.assertEqual(RET, pyanaconda.flags.flags.sshd)
|
||||
|
||||
def setattr_getattr_2_test(self):
|
||||
import pyanaconda.flags
|
||||
RET = 0
|
||||
self.cmd = 'vmlinuz initrd=initrd.img xdriver=vesa nomodeset'
|
||||
self.mock2.read = mock.Mock(return_value=self.cmd)
|
||||
pyanaconda.flags.flags.sshd = RET
|
||||
self.assertEqual(RET, pyanaconda.flags.flags.sshd)
|
||||
|
||||
def setattr_getattr_3_test(self):
|
||||
import pyanaconda.flags
|
||||
self.cmd = 'vmlinuz initrd=initrd.img xdriver=vesa nomodeset'
|
||||
self.mock2.read = mock.Mock(return_value=self.cmd)
|
||||
|
||||
def f(): return pyanaconda.flags.flags.fooattr
|
||||
self.assertRaises(AttributeError, f)
|
||||
|
||||
def setattr_getattr_4_test(self):
|
||||
import pyanaconda.flags
|
||||
self.cmd = 'vmlinuz initrd=initrd.img xdriver=vesa nomodeset'
|
||||
self.mock2.read = mock.Mock(return_value=self.cmd)
|
||||
|
||||
def f(): pyanaconda.flags.flags.fooattr = 1
|
||||
self.assertRaises(AttributeError, f)
|
||||
|
||||
def get_1_test(self):
|
||||
import pyanaconda.flags
|
||||
RET = 'text'
|
||||
self.cmd = 'vmlinuz initrd=initrd.img xdriver=vesa nomodeset'
|
||||
self.mock2.read = mock.Mock(return_value=self.cmd)
|
||||
ret = pyanaconda.flags.flags.get('foobar', RET)
|
||||
self.assertEqual(RET, ret)
|
||||
|
||||
def get_2_test(self):
|
||||
import pyanaconda.flags
|
||||
RET = 'text'
|
||||
self.cmd = 'vmlinuz initrd=initrd.img xdriver=vesa nomodeset'
|
||||
self.mock2.read = mock.Mock(return_value=self.cmd)
|
||||
ret = pyanaconda.flags.flags.get('sshd', RET)
|
||||
self.assertNotEqual(RET, ret)
|
@ -1,147 +0,0 @@
|
||||
#!/usr/bin/python
|
||||
|
||||
import mock
|
||||
import sys
|
||||
|
||||
IMAGENAME = 'Fedora-13-i386-DVD.iso'
|
||||
|
||||
class ImageTest(mock.TestCase):
|
||||
|
||||
def setUp(self):
|
||||
self.setupModules(["_isys", "block", "ConfigParser"])
|
||||
self.fs = mock.DiskIO()
|
||||
|
||||
DISCINFO = "1273712438.740122\n"
|
||||
DISCINFO += "Fedora 13\n"
|
||||
DISCINFO += "i386\n"
|
||||
DISCINFO += "ALL\n"
|
||||
|
||||
DISCINFO2 = "1273712438.740122\n"
|
||||
DISCINFO2 += "Fedora 13\n"
|
||||
DISCINFO2 += "i386\n"
|
||||
DISCINFO2 += "1,2\n"
|
||||
|
||||
self.fs.open('/mnt/install/cdimage/.discinfo', 'w').write(DISCINFO)
|
||||
self.fs.open('/tmp/.discinfo', 'w').write(DISCINFO2)
|
||||
|
||||
import pyanaconda.image
|
||||
pyanaconda.image.gettext = mock.Mock()
|
||||
pyanaconda.image.log = mock.Mock()
|
||||
pyanaconda.image.open = self.fs.open
|
||||
pyanaconda.image.isys = mock.Mock()
|
||||
pyanaconda.image._arch = 'i386'
|
||||
pyanaconda.image.stat = mock.Mock()
|
||||
pyanaconda.image.stat.ST_SIZE = 0
|
||||
|
||||
pyanaconda.image.os = mock.Mock()
|
||||
pyanaconda.image.os.R_OK = 0
|
||||
pyanaconda.image.os.stat.return_value = [2048]
|
||||
pyanaconda.image.os.listdir.return_value=[IMAGENAME]
|
||||
|
||||
def tearDown(self):
|
||||
self.tearDownModules()
|
||||
|
||||
def get_media_id_1_test(self):
|
||||
import pyanaconda.image
|
||||
ret = pyanaconda.image.getMediaId('/mnt/install/cdimage')
|
||||
self.assertEqual(ret, '1273712438.740122')
|
||||
|
||||
def get_media_id_2_test(self):
|
||||
import pyanaconda.image
|
||||
pyanaconda.image.os.access = mock.Mock(return_value=False)
|
||||
ret = pyanaconda.image.getMediaId('/')
|
||||
self.assertEqual(ret, None)
|
||||
|
||||
def mount_directory_1_test(self):
|
||||
import pyanaconda.image
|
||||
pyanaconda.image.os.path.ismount = mock.Mock(return_value=False)
|
||||
pyanaconda.image.mountDirectory('hd:/dev/sda1:/', mock.Mock())
|
||||
self.assertEqual(pyanaconda.image.isys.method_calls,
|
||||
[('mount', ('/dev/sda1', '/mnt/install/isodir'), {'fstype': 'auto', 'options':''})])
|
||||
|
||||
def mount_directory_2_test(self):
|
||||
import pyanaconda.image
|
||||
pyanaconda.image.os.path.ismount = mock.Mock(return_value=False)
|
||||
pyanaconda.image.mountDirectory('hd:sda1:/', mock.Mock())
|
||||
self.assertEqual(pyanaconda.image.isys.method_calls,
|
||||
[('mount', ('/dev/sda1', '/mnt/install/isodir'), {'fstype': 'auto', 'options':''})])
|
||||
|
||||
def mount_directory_3_test(self):
|
||||
import pyanaconda.image
|
||||
pyanaconda.image.os.path.ismount = mock.Mock(return_value=True)
|
||||
pyanaconda.image.mountDirectory('hd:sda1:/', mock.Mock())
|
||||
self.assertEqual(pyanaconda.image.isys.method_calls, [])
|
||||
|
||||
def mount_image_1_test(self):
|
||||
import pyanaconda.image
|
||||
self.assertRaises(SystemError, pyanaconda.image.mountImage, '', '/mnt/install/cdimage', mock.Mock())
|
||||
|
||||
def mount_image_2_test(self):
|
||||
import pyanaconda.image
|
||||
pyanaconda.image.os.path.ismount = mock.Mock(return_value=False)
|
||||
ret = pyanaconda.image.mountImage('', '/mnt/install/cdimage', mock.Mock())
|
||||
|
||||
self.assertEqual(pyanaconda.image.isys.method_calls,
|
||||
[('isIsoImage', ('/Fedora-13-i386-DVD.iso',), {}),
|
||||
('mount', ('/Fedora-13-i386-DVD.iso', '/mnt/install/cdimage'),
|
||||
{'readOnly': True, 'fstype': 'iso9660'}),
|
||||
('umount', ('/mnt/install/cdimage',), {'removeDir': False}),
|
||||
('mount', ('/Fedora-13-i386-DVD.iso', '/mnt/install/cdimage'),
|
||||
{'readOnly': True, 'fstype': 'iso9660'}),
|
||||
])
|
||||
|
||||
def scan_for_media_1_test(self):
|
||||
import pyanaconda.image
|
||||
storage = mock.Mock()
|
||||
storage.devicetree.devices = []
|
||||
ret = pyanaconda.image.scanForMedia(mock.Mock(), storage)
|
||||
self.assertEqual(ret, None)
|
||||
|
||||
def scan_for_media_2_test(self):
|
||||
import pyanaconda.image
|
||||
device = mock.Mock()
|
||||
device.type = 'cdrom'
|
||||
device.name = 'deviceName'
|
||||
storage = mock.Mock()
|
||||
storage.devicetree.devices = [device]
|
||||
ret = pyanaconda.image.scanForMedia('/tmp', storage)
|
||||
self.assertEqual(ret, 'deviceName')
|
||||
self.assertEqual(device.method_calls,
|
||||
[('format.mount', (), {'mountpoint': '/tmp'})])
|
||||
|
||||
def umount_image_1_test(self):
|
||||
import pyanaconda.image
|
||||
pyanaconda.image.umountImage('/tmp')
|
||||
self.assertEqual(pyanaconda.image.isys.method_calls,
|
||||
[('umount', ('/tmp',), {'removeDir': False})])
|
||||
|
||||
def unmount_cd_1_test(self):
|
||||
import pyanaconda.image
|
||||
window = mock.Mock()
|
||||
pyanaconda.image.unmountCD(None, window)
|
||||
self.assertEqual(window.method_calls, [])
|
||||
|
||||
def unmount_cd_2_test(self):
|
||||
import pyanaconda.image
|
||||
window = mock.Mock()
|
||||
device = mock.Mock()
|
||||
pyanaconda.image.unmountCD(device, window)
|
||||
self.assertEqual(window.method_calls, [])
|
||||
self.assertEqual(device.method_calls,
|
||||
[('format.unmount', (), {})])
|
||||
|
||||
def verify_media_1_test(self):
|
||||
import pyanaconda.image
|
||||
ret = pyanaconda.image.verifyMedia('/tmp')
|
||||
self.assertTrue(ret)
|
||||
|
||||
def verify_media_2_test(self):
|
||||
import pyanaconda.image
|
||||
ret = pyanaconda.image.verifyMedia('/tmp', timestamp=1337)
|
||||
self.assertFalse(ret)
|
||||
|
||||
def verify_media_3_test(self):
|
||||
import pyanaconda.image
|
||||
pyanaconda.image._arch = 'x86_64'
|
||||
ret = pyanaconda.image.verifyMedia('/tmp', 1)
|
||||
self.assertFalse(ret)
|
@ -1,49 +0,0 @@
|
||||
import mock
|
||||
|
||||
class IndexedDictTest(mock.TestCase):
|
||||
def setUp(self):
|
||||
self.setupModules(['_isys'])
|
||||
|
||||
def tearDown(self):
|
||||
self.tearDownModules()
|
||||
|
||||
def instantiation_test(self):
|
||||
from pyanaconda.indexed_dict import IndexedDict
|
||||
d = IndexedDict()
|
||||
self.assertIsInstance(d, IndexedDict)
|
||||
|
||||
def append_test(self):
|
||||
from pyanaconda.indexed_dict import IndexedDict
|
||||
d = IndexedDict()
|
||||
stored_data = [1, 2, 3]
|
||||
d["some_step"] = stored_data
|
||||
self.assertIs(d["some_step"], stored_data)
|
||||
|
||||
def cant_append_test(self):
|
||||
from pyanaconda.indexed_dict import IndexedDict
|
||||
def assign_int(indexed_dict):
|
||||
indexed_dict[3] = [1, 2, 3]
|
||||
d = IndexedDict()
|
||||
self.assertRaises(TypeError, d.__setitem__, 3, [1, 2, 3])
|
||||
|
||||
def referencing_test(self):
|
||||
from pyanaconda.indexed_dict import IndexedDict
|
||||
d = IndexedDict()
|
||||
d["first"] = 10
|
||||
d["second"] = 20
|
||||
d["third"] = 30
|
||||
self.assertEqual(d[0], 10)
|
||||
self.assertEqual(d[1], 20)
|
||||
self.assertEqual(d[2], 30)
|
||||
self.assertRaises(IndexError, d.__getitem__, 3)
|
||||
|
||||
def index_test(self):
|
||||
from pyanaconda.indexed_dict import IndexedDict
|
||||
d = IndexedDict()
|
||||
d["first"] = 10
|
||||
d["second"] = 20
|
||||
d["third"] = 30
|
||||
|
||||
self.assertEqual(d.index("first"), 0)
|
||||
self.assertEqual(d.index("second"), 1)
|
||||
self.assertEqual(d.index("third"), 2)
|
@ -1,37 +0,0 @@
|
||||
import mock
|
||||
import sys
|
||||
|
||||
class IutilTest(mock.TestCase):
|
||||
def setUp(self):
|
||||
self.setupModules(
|
||||
['_isys', 'logging', 'pyanaconda.anaconda_log', 'block'])
|
||||
|
||||
import pyanaconda
|
||||
pyanaconda.anaconda_log = mock.Mock()
|
||||
|
||||
def tearDown(self):
|
||||
self.tearDownModules()
|
||||
|
||||
def copy_to_sysimage_test(self):
|
||||
from pyanaconda import iutil
|
||||
fs = mock.DiskIO()
|
||||
self.take_over_io(fs, iutil)
|
||||
self.assertEqual(iutil.copy_to_sysimage("/etc/securetty"), False)
|
||||
|
||||
fs["/etc/securetty"] = "tty1"
|
||||
iutil.os.makedirs = mock.Mock()
|
||||
iutil.shutil.copy = mock.Mock()
|
||||
self.assertEqual(iutil.copy_to_sysimage("/etc/securetty"), True)
|
||||
iutil.os.makedirs.assert_called_with("/mnt/sysimage/etc")
|
||||
iutil.shutil.copy.assert_called_with("/etc/securetty",
|
||||
"/mnt/sysimage/etc/securetty")
|
||||
|
||||
def testExecCaptureNonZeroFatal (self):
|
||||
import iutil
|
||||
try:
|
||||
argv = ["-c", "import sys; sys.exit(3);"]
|
||||
iutil.execWithCapture(sys.executable, argv, root=None, fatal=True)
|
||||
except RuntimeError, ex:
|
||||
self.assertIn("return code: 3", str(ex))
|
||||
else:
|
||||
self.fail("RuntimeError not raised")
|
@ -1,389 +0,0 @@
|
||||
#!/usr/bin/python
|
||||
|
||||
import mock
|
||||
import os
|
||||
|
||||
class NetworkTest(mock.TestCase):
|
||||
|
||||
def setUp(self):
|
||||
self.setupModules(['_isys', 'block', 'logging', 'ConfigParser'])
|
||||
self.fs = mock.DiskIO()
|
||||
|
||||
self.OK = 22
|
||||
self.SYSCONFIGDIR = "/tmp/etc/sysconfig"
|
||||
self.NETSCRIPTSDIR = "%s/network-scripts" % (self.SYSCONFIGDIR)
|
||||
self.NETWORKCONFFILE = '%s/network' % self.SYSCONFIGDIR
|
||||
self.IFCFGLOG = '/tmp/ifcfg.log'
|
||||
self.DEFAULT_HOSTNAME = 'localhost.localdomain'
|
||||
|
||||
self.CONT = "DEVICE=eth0\nHWADDR=00:11:22:50:55:50\nTYPE=Ethernet\nBOOTPROTO=dhcp\n"
|
||||
self.DEVICE = 'eth0'
|
||||
self.DEV_FILE = self.NETSCRIPTSDIR + '/ifcfg-eth0'
|
||||
self.DEV_KEY_FILE = self.NETSCRIPTSDIR + '/keys-eth0'
|
||||
self.fs.open(self.DEV_FILE, 'w').write(self.CONT)
|
||||
|
||||
import pyanaconda
|
||||
pyanaconda.anaconda_log = mock.Mock()
|
||||
|
||||
import pyanaconda.network
|
||||
pyanaconda.network.socket = mock.Mock()
|
||||
pyanaconda.network.socket.gethostname.return_value = self.DEFAULT_HOSTNAME
|
||||
pyanaconda.network.open = self.fs.open
|
||||
pyanaconda.simpleconfig.open = self.fs.open
|
||||
pyanaconda.network.sysconfigDir = self.SYSCONFIGDIR
|
||||
pyanaconda.network.netscriptsDir = self.NETSCRIPTSDIR
|
||||
pyanaconda.network.networkConfFile = self.NETWORKCONFFILE
|
||||
pyanaconda.network.ifcfgLogFile = self.IFCFGLOG
|
||||
self.fs.open(self.IFCFGLOG, 'w')
|
||||
|
||||
# Network mock
|
||||
pyanaconda.network.Network.update = mock.Mock()
|
||||
self.setNMControlledDevices_backup = pyanaconda.network.Network.setNMControlledDevices
|
||||
pyanaconda.network.Network.setNMControlledDevices = mock.Mock()
|
||||
pyanaconda.network.Network.netdevices = {}
|
||||
|
||||
def tearDown(self):
|
||||
self.tearDownModules()
|
||||
|
||||
def sanity_check_hostname_1_test(self):
|
||||
import pyanaconda.network
|
||||
(valid, err) = pyanaconda.network.sanityCheckHostname('desktop')
|
||||
self.assertTrue(valid)
|
||||
|
||||
def sanity_check_hostname_2_test(self):
|
||||
import pyanaconda.network
|
||||
(valid, err) = pyanaconda.network.sanityCheckHostname('')
|
||||
self.assertFalse(valid)
|
||||
|
||||
def sanity_check_hostname_3_test(self):
|
||||
import pyanaconda.network
|
||||
(valid, err) = pyanaconda.network.sanityCheckHostname('c'*256)
|
||||
self.assertFalse(valid)
|
||||
|
||||
def sanity_check_hostname_4_test(self):
|
||||
import pyanaconda.network
|
||||
(valid, err) = pyanaconda.network.sanityCheckHostname('_asf')
|
||||
self.assertFalse(valid)
|
||||
|
||||
def sanity_check_hostname_5_test(self):
|
||||
import pyanaconda.network
|
||||
(valid, err) = pyanaconda.network.sanityCheckHostname('a?f')
|
||||
self.assertFalse(valid)
|
||||
|
||||
def get_default_hostname_1_test(self):
|
||||
import pyanaconda.network
|
||||
|
||||
HOSTNAME = 'host1'
|
||||
pyanaconda.network.getActiveNetDevs = mock.Mock(return_value=['dev'])
|
||||
pyanaconda.network.isys = mock.Mock()
|
||||
pyanaconda.network.isys.getIPAddresses.return_value = ['10.0.0.1']
|
||||
pyanaconda.network.socket = mock.Mock()
|
||||
pyanaconda.network.socket.gethostbyaddr.return_value = [HOSTNAME, '', '']
|
||||
|
||||
ret = pyanaconda.network.getDefaultHostname(mock.Mock())
|
||||
self.assertEqual(ret, HOSTNAME)
|
||||
|
||||
def get_default_hostname_2_test(self):
|
||||
import pyanaconda.network
|
||||
|
||||
HOSTNAME = 'host2'
|
||||
pyanaconda.network.getActiveNetDevs = mock.Mock(return_value=[])
|
||||
pyanaconda.network.isys = mock.Mock()
|
||||
pyanaconda.network.socket = mock.Mock()
|
||||
anaconda = mock.Mock()
|
||||
anaconda.network.hostname = HOSTNAME
|
||||
|
||||
ret = pyanaconda.network.getDefaultHostname(anaconda)
|
||||
self.assertEqual(ret, HOSTNAME)
|
||||
|
||||
def get_default_hostname_3_test(self):
|
||||
import pyanaconda.network
|
||||
|
||||
HOSTNAME = 'host3'
|
||||
pyanaconda.network.getActiveNetDevs = mock.Mock(return_value=[])
|
||||
pyanaconda.network.isys = mock.Mock()
|
||||
pyanaconda.network.socket = mock.Mock()
|
||||
pyanaconda.network.socket.gethostname.return_value = HOSTNAME
|
||||
anaconda = mock.Mock()
|
||||
anaconda.network.hostname = ''
|
||||
|
||||
ret = pyanaconda.network.getDefaultHostname(anaconda)
|
||||
self.assertEqual(ret, HOSTNAME)
|
||||
|
||||
def get_default_hostname_4_test(self):
|
||||
import pyanaconda.network
|
||||
|
||||
pyanaconda.network.getActiveNetDevs = mock.Mock(return_value=[])
|
||||
pyanaconda.network.isys = mock.Mock()
|
||||
pyanaconda.network.socket = mock.Mock()
|
||||
pyanaconda.network.socket.gethostname.return_value = ''
|
||||
anaconda = mock.Mock()
|
||||
anaconda.network.hostname = ''
|
||||
|
||||
ret = pyanaconda.network.getDefaultHostname(anaconda)
|
||||
self.assertEqual(ret, self.DEFAULT_HOSTNAME)
|
||||
|
||||
def sanity_check_ip_string_1_test(self):
|
||||
import pyanaconda.network
|
||||
|
||||
IPADDR = '10.0.0.5'
|
||||
pyanaconda.network.sanityCheckIPString(IPADDR)
|
||||
|
||||
def sanity_check_ip_string_2_test(self):
|
||||
import pyanaconda.network
|
||||
|
||||
IPADDR = "ff06:0:0:0:0:0:0:c3"
|
||||
pyanaconda.network.sanityCheckIPString(IPADDR)
|
||||
|
||||
def sanity_check_ip_string_3_test(self):
|
||||
import pyanaconda.network
|
||||
|
||||
IPADDR = "ff06:.:.:0:0:0:0:c3"
|
||||
self.assertRaises(pyanaconda.network.IPError,
|
||||
pyanaconda.network.sanityCheckIPString, IPADDR)
|
||||
|
||||
def sanity_check_ip_string_4_test(self):
|
||||
import pyanaconda.network
|
||||
import socket
|
||||
pyanaconda.network.socket.error = socket.error
|
||||
pyanaconda.network.socket.inet_pton = mock.Mock(side_effect=socket.error)
|
||||
|
||||
IPADDR = "1.8.64.512"
|
||||
self.assertRaises(pyanaconda.network.IPError,
|
||||
pyanaconda.network.sanityCheckIPString, IPADDR)
|
||||
|
||||
def sanity_check_ip_string_5_test(self):
|
||||
import pyanaconda.network
|
||||
import socket
|
||||
pyanaconda.network.socket.error = socket.error
|
||||
pyanaconda.network.socket.inet_pton = mock.Mock(side_effect=socket.error)
|
||||
|
||||
IPADDR = "top.secret.address"
|
||||
self.assertRaises(pyanaconda.network.IPError,
|
||||
pyanaconda.network.sanityCheckIPString, IPADDR)
|
||||
|
||||
def has_active_net_dev_1_test(self):
|
||||
import pyanaconda.network
|
||||
|
||||
pyanaconda.network.dbus = mock.Mock()
|
||||
pyanaconda.network.dbus.Interface().Get.return_value = \
|
||||
pyanaconda.network.isys.NM_STATE_CONNECTED_GLOBAL
|
||||
|
||||
ret = pyanaconda.network.hasActiveNetDev()
|
||||
self.assertTrue(ret)
|
||||
self.assertTrue(pyanaconda.network.dbus.Interface().Get.called)
|
||||
|
||||
def has_active_net_dev_2_test(self):
|
||||
import pyanaconda.network
|
||||
|
||||
pyanaconda.network.dbus = mock.Mock(side_effect=Exception)
|
||||
|
||||
ret = pyanaconda.network.hasActiveNetDev()
|
||||
self.assertFalse(ret)
|
||||
|
||||
def has_active_net_dev_3_test(self):
|
||||
import pyanaconda.network
|
||||
|
||||
pyanaconda.network.dbus = mock.Mock()
|
||||
pyanaconda.network.dbus.Interface().Get.return_value = self.OK
|
||||
pyanaconda.network.isys.NM_STATE_CONNECTED = (self.OK - 5)
|
||||
|
||||
ret = pyanaconda.network.hasActiveNetDev()
|
||||
self.assertFalse(ret)
|
||||
|
||||
def networkdevice_read_test(self):
|
||||
import pyanaconda.network
|
||||
|
||||
nd = pyanaconda.network.NetworkDevice(self.NETSCRIPTSDIR, self.DEVICE)
|
||||
ret = nd.read()
|
||||
self.assertEqual(ret, 4)
|
||||
self.assertEqual(nd.info,
|
||||
{'DEVICE': 'eth0', 'HWADDR': '00:11:22:50:55:50',
|
||||
'BOOTPROTO': 'dhcp', 'TYPE': 'Ethernet'})
|
||||
|
||||
def networkdevice_clear_test(self):
|
||||
import pyanaconda.network
|
||||
|
||||
nd = pyanaconda.network.NetworkDevice(self.NETSCRIPTSDIR, self.DEVICE)
|
||||
nd.info = {'DEVICE': 'eth0', 'HWADDR': '00:11:22:50:55:50', 'TYPE': 'Ethernet'}
|
||||
nd.clear()
|
||||
self.assertEqual(nd.info, {})
|
||||
|
||||
def networkdevice_str_test(self):
|
||||
import pyanaconda.network
|
||||
pyanaconda.network.arch = mock.Mock()
|
||||
pyanaconda.network.arch.isS390.return_value = False
|
||||
|
||||
nd = pyanaconda.network.NetworkDevice(self.NETSCRIPTSDIR, self.DEVICE)
|
||||
nd.info = {'HWADDR': '00:11:22:50:55:50', 'DEVICE': 'eth0', 'TYPE': 'Ethernet'}
|
||||
self.assertIn('DEVICE="eth0"', str(nd))
|
||||
self.assertIn('TYPE="Ethernet"', str(nd))
|
||||
|
||||
def networkdevice_load_ifcfg_file_test(self):
|
||||
import pyanaconda.network
|
||||
nd = pyanaconda.network.NetworkDevice(self.NETSCRIPTSDIR, self.DEVICE)
|
||||
nd.loadIfcfgFile()
|
||||
self.assertFalse(nd._dirty)
|
||||
self.assertEqual(nd.info,
|
||||
{'DEVICE': 'eth0', 'HWADDR': '00:11:22:50:55:50',
|
||||
'TYPE': 'Ethernet', 'BOOTPROTO': 'dhcp'})
|
||||
|
||||
def networkdevice_write_ifcfg_file_test(self):
|
||||
import pyanaconda.network
|
||||
nd = pyanaconda.network.NetworkDevice(self.NETSCRIPTSDIR, self.DEVICE)
|
||||
nd.info = {'HWADDR': '66:55:44:33:22:11', 'DEVICE': 'eth1', 'TYPE': 'Ethernet'}
|
||||
nd._dirty = True
|
||||
nd.writeIfcfgFile()
|
||||
self.assertIn('DEVICE="eth1"\n', self.fs[self.DEV_FILE])
|
||||
self.assertIn('HWADDR="66:55:44:33:22:11"', self.fs[self.DEV_FILE])
|
||||
self.assertIn('TYPE="Ethernet"', self.fs[self.DEV_FILE])
|
||||
|
||||
def networkdevice_set_1_test(self):
|
||||
import pyanaconda.network
|
||||
nd = pyanaconda.network.NetworkDevice(self.NETSCRIPTSDIR, self.DEVICE)
|
||||
nd.set(('key', 'value'))
|
||||
self.assertEqual(nd.info, {'KEY': 'value'})
|
||||
self.assertTrue(nd._dirty)
|
||||
|
||||
def networkdevice_set_2_test(self):
|
||||
import pyanaconda.network
|
||||
nd = pyanaconda.network.NetworkDevice(self.NETSCRIPTSDIR, self.DEVICE)
|
||||
nd.set(('key', 'value'))
|
||||
nd.set(('key', 'other_value'))
|
||||
self.assertEqual(nd.info, {'KEY': 'other_value'})
|
||||
self.assertTrue(nd._dirty)
|
||||
|
||||
def networkdevice_set_3_test(self):
|
||||
import pyanaconda.network
|
||||
nd = pyanaconda.network.NetworkDevice(self.NETSCRIPTSDIR, self.DEVICE)
|
||||
nd.set(('key', 'value'))
|
||||
nd._dirty = False
|
||||
nd.set(('key', 'other_value'))
|
||||
self.assertEqual(nd.info, {'KEY': 'other_value'})
|
||||
self.assertTrue(nd._dirty)
|
||||
|
||||
def networkdevice_set_gateway_test(self):
|
||||
import pyanaconda.network
|
||||
nd = pyanaconda.network.NetworkDevice(self.NETSCRIPTSDIR, self.DEVICE)
|
||||
nd.setGateway('10.0.0.1')
|
||||
self.assertEqual(nd.info, {'GATEWAY': '10.0.0.1'})
|
||||
self.assertTrue(nd._dirty)
|
||||
|
||||
def networkdevice_set_gateway_ipv6_test(self):
|
||||
import pyanaconda.network
|
||||
nd = pyanaconda.network.NetworkDevice(self.NETSCRIPTSDIR, self.DEVICE)
|
||||
nd.setGateway('fe80::5675:d0ff:feac:4d3f')
|
||||
self.assertEqual(nd.info, {'IPV6_DEFAULTGW': 'fe80::5675:d0ff:feac:4d3f'})
|
||||
self.assertTrue(nd._dirty)
|
||||
|
||||
def networkdevice_set_dns_test(self):
|
||||
import pyanaconda.network
|
||||
nd = pyanaconda.network.NetworkDevice(self.NETSCRIPTSDIR, self.DEVICE)
|
||||
nd.setDNS('10.0.0.1, 10.0.0.2')
|
||||
self.assertEqual(nd.info, {'DNS1': '10.0.0.1'})
|
||||
self.assertEqual(nd.info, {'DNS2': '10.0.0.2'})
|
||||
self.assertTrue(nd._dirty)
|
||||
|
||||
def networkdevice_keyfile_path_test(self):
|
||||
import pyanaconda.network
|
||||
nd = pyanaconda.network.NetworkDevice(self.NETSCRIPTSDIR, self.DEVICE)
|
||||
ret = nd.keyfilePath
|
||||
self.assertEqual(ret, self.DEV_KEY_FILE)
|
||||
|
||||
def networkdevice_write_wepkey_file_1_test(self):
|
||||
import pyanaconda.network
|
||||
nd = pyanaconda.network.NetworkDevice(self.NETSCRIPTSDIR, self.DEVICE)
|
||||
nd.wepkey = False
|
||||
ret = nd.writeWepkeyFile()
|
||||
self.assertFalse(ret)
|
||||
|
||||
def networkdevice_write_wepkey_file_2_test(self):
|
||||
import pyanaconda.network
|
||||
TMP_FILE = '/tmp/wep.key'
|
||||
TMP_DIR = '/tmp/wepkeyfiles'
|
||||
pyanaconda.network.tempfile = mock.Mock()
|
||||
pyanaconda.network.tempfile.mkstemp.return_value = (88, TMP_FILE)
|
||||
pyanaconda.network.os = mock.Mock()
|
||||
pyanaconda.network.os.path = os.path
|
||||
pyanaconda.network.shutil = mock.Mock()
|
||||
|
||||
nd = pyanaconda.network.NetworkDevice(self.NETSCRIPTSDIR, self.DEVICE)
|
||||
nd.iface = self.DEVICE
|
||||
nd.wepkey = '12345'
|
||||
|
||||
nd.writeWepkeyFile(dir=TMP_DIR)
|
||||
self.assertEqual(pyanaconda.network.os.write.call_args[0], (88, 'KEY1=12345\n'))
|
||||
self.assertEqual(pyanaconda.network.shutil.move.call_args[0],
|
||||
(TMP_FILE, '%s/keys-%s' % (TMP_DIR, self.DEVICE)))
|
||||
|
||||
def network_nm_controlled_devices_1_test(self):
|
||||
import pyanaconda.network
|
||||
nw = pyanaconda.network.Network()
|
||||
nw.netdevices = {'dev': mock.Mock()}
|
||||
pyanaconda.network.Network.setNMControlledDevices = self.setNMControlledDevices_backup
|
||||
nw.setNMControlledDevices()
|
||||
self.assertEqual(nw.netdevices['dev'].method_calls,
|
||||
[('set', (('NM_CONTROLLED', 'yes'),), {})])
|
||||
|
||||
def network_nm_controlled_devices_2_test(self):
|
||||
import pyanaconda.network
|
||||
nw = pyanaconda.network.Network()
|
||||
nw.netdevices = {'dev': mock.Mock()}
|
||||
pyanaconda.network.Network.setNMControlledDevices = self.setNMControlledDevices_backup
|
||||
nw.setNMControlledDevices([''])
|
||||
self.assertEqual(nw.netdevices['dev'].method_calls,
|
||||
[('set', (('NM_CONTROLLED', 'no'),), {})])
|
||||
|
||||
def network_write_ks_test(self):
|
||||
import pyanaconda.network
|
||||
TMPFILE = '/tmp/networkKS'
|
||||
f = self.fs.open(TMPFILE, 'w')
|
||||
|
||||
nw = pyanaconda.network.Network()
|
||||
nw.netdevices[self.DEVICE] = pyanaconda.network.NetworkDevice(
|
||||
self.NETSCRIPTSDIR, self.DEVICE)
|
||||
nw.netdevices[self.DEVICE].loadIfcfgFile()
|
||||
nw.writeKS(f)
|
||||
f.close()
|
||||
|
||||
self.assertEqual(self.fs[TMPFILE],
|
||||
'network --device eth0 --bootproto dhcp --noipv6\n')
|
||||
|
||||
def network_wait_for_connection_1_test(self):
|
||||
import pyanaconda.network
|
||||
pyanaconda.network.dbus = mock.Mock()
|
||||
pyanaconda.network.dbus.Interface().Get.return_value = \
|
||||
pyanaconda.network.isys.NM_STATE_CONNECTED_GLOBAL
|
||||
|
||||
ret = pyanaconda.network.waitForConnection()
|
||||
self.assertTrue(ret)
|
||||
|
||||
def network_wait_for_connection_2_test(self):
|
||||
import pyanaconda.network
|
||||
pyanaconda.network.dbus = mock.Mock()
|
||||
pyanaconda.network.dbus.Interface().Get.return_value = self.OK-5
|
||||
pyanaconda.network.isys = mock.Mock()
|
||||
pyanaconda.network.isys.NM_STATE_CONNECTED = self.OK
|
||||
pyanaconda.network.time.sleep = mock.Mock()
|
||||
|
||||
ret = pyanaconda.network.waitForConnection()
|
||||
self.assertFalse(ret)
|
||||
|
||||
def network_bring_up_test(self):
|
||||
import pyanaconda.network
|
||||
pyanaconda.network.Network.write = mock.Mock()
|
||||
pyanaconda.network.waitForConnection = mock.Mock()
|
||||
|
||||
nw = pyanaconda.network.Network()
|
||||
nw.bringUp()
|
||||
self.assertTrue(pyanaconda.network.Network.write.called)
|
||||
self.assertTrue(pyanaconda.network.waitForConnection.called)
|
||||
|
||||
def iface_for_host_ip_test(self):
|
||||
import pyanaconda.network
|
||||
pyanaconda.network.arch = mock.Mock()
|
||||
pyanaconda.network.arch.execWithCapture.return_value = \
|
||||
"10.0.0.2 dev eth0 src 10.0.0.1"
|
||||
|
||||
ret = pyanaconda.network.ifaceForHostIP('10.0.0.2')
|
||||
self.assertEqual(ret, 'eth0')
|
@ -1,25 +0,0 @@
|
||||
#!/usr/bin/python
|
||||
|
||||
import mock
|
||||
|
||||
class PackagesTest(mock.TestCase):
|
||||
|
||||
def setUp(self):
|
||||
self.setupModules(["_isys", "block", "logging", "parted", "storage",
|
||||
"pyanaconda.storage.formats", "ConfigParser",
|
||||
"pyanaconda.storage.storage_log"])
|
||||
self.fs = mock.DiskIO()
|
||||
|
||||
import pyanaconda
|
||||
pyanaconda.anaconda_log = mock.Mock()
|
||||
|
||||
import pyanaconda.packages
|
||||
|
||||
def tearDown(self):
|
||||
self.tearDownModules()
|
||||
|
||||
def do_post_action_test(self):
|
||||
import pyanaconda.packages
|
||||
anaconda = mock.Mock()
|
||||
pyanaconda.packages.doPostAction(anaconda)
|
||||
self.assertTrue(anaconda.instClass.postAction.called)
|
@ -1,126 +0,0 @@
|
||||
#!/usr/bin/python
|
||||
|
||||
import mock
|
||||
|
||||
class PackagingTest(mock.TestCase):
|
||||
|
||||
def setUp(self):
|
||||
self.setupModules(["_isys", "logging"])
|
||||
|
||||
import pyanaconda
|
||||
pyanaconda.anaconda_log = mock.Mock()
|
||||
|
||||
from pykickstart.version import makeVersion
|
||||
from pyanaconda.flags import flags
|
||||
|
||||
# set some things specially since we're just testing
|
||||
flags.testing = True
|
||||
|
||||
# set up ksdata
|
||||
self.ksdata = makeVersion()
|
||||
|
||||
from pyanaconda.packaging import Payload
|
||||
self.payload = Payload(self.ksdata)
|
||||
|
||||
def tearDown(self):
|
||||
self.tearDownModules()
|
||||
#os.system("rm -rf %s" % self.root)
|
||||
|
||||
def payload_abstract_test(self):
|
||||
self.assertRaises(NotImplementedError, self.payload.setup, None)
|
||||
self.assertRaises(NotImplementedError, self.payload.description, None)
|
||||
|
||||
def payload_repo_test(self):
|
||||
# ksdata repo list initially empty
|
||||
self.assertEqual(self.payload.data.repo.dataList(), [])
|
||||
|
||||
# create and add a new ksdata repo
|
||||
repo_name = "test1"
|
||||
repo = self.ksdata.RepoData(name=repo_name, baseurl="http://localhost/")
|
||||
self.payload.addRepo(repo)
|
||||
|
||||
# verify the repo was added
|
||||
self.assertEqual(self.payload.data.repo.dataList(), [repo])
|
||||
self.assertEqual(self.payload.getAddOnRepo(repo_name), repo)
|
||||
|
||||
# remove the repo
|
||||
self.payload.removeRepo(repo_name)
|
||||
|
||||
# verify the repo was removed
|
||||
self.assertEqual(self.payload.getAddOnRepo(repo_name), None)
|
||||
|
||||
def payload_group_test(self):
|
||||
import pykickstart.constants
|
||||
from pykickstart.parser import Group
|
||||
|
||||
# verify that ksdata group lists are initially empty
|
||||
self.assertEqual(self.payload.data.packages.groupList, [])
|
||||
self.assertEqual(self.payload.data.packages.excludedGroupList, [])
|
||||
|
||||
self.payload.deselectGroup("core")
|
||||
self.assertEqual(self.payload.groupSelected("core"), False)
|
||||
|
||||
# select a group and verify the selection is reflected afterward
|
||||
self.payload.selectGroup("core", optional=True)
|
||||
self.assertTrue(self.payload.groupSelected("core"))
|
||||
|
||||
# verify the group is not in the excluded group list
|
||||
self.assertTrue(Group("core") not in self.payload.data.packages.excludedGroupList)
|
||||
|
||||
# verify the include (optional/all) is recorded
|
||||
groups = self.payload.data.packages.groupList
|
||||
group = groups[[g.name for g in groups].index("core")]
|
||||
self.assertEqual(group.include, pykickstart.constants.GROUP_ALL)
|
||||
|
||||
# select more groups
|
||||
self.payload.selectGroup("base")
|
||||
self.payload.selectGroup("development", default=False)
|
||||
|
||||
# verify include types for newly selected groups
|
||||
group = groups[[g.name for g in groups].index("development")]
|
||||
self.assertEqual(group.include, pykickstart.constants.GROUP_REQUIRED)
|
||||
|
||||
group = groups[[g.name for g in groups].index("base")]
|
||||
self.assertEqual(group.include, pykickstart.constants.GROUP_DEFAULT)
|
||||
|
||||
# deselect a group and verify the set of groups is correct afterward
|
||||
self.payload.deselectGroup("base")
|
||||
self.assertFalse(self.payload.groupSelected("base"))
|
||||
self.assertTrue(self.payload.groupSelected("core"))
|
||||
self.assertTrue(self.payload.groupSelected("development"))
|
||||
|
||||
def payload_package_test(self):
|
||||
# verify that ksdata package lists are initially empty
|
||||
self.assertEqual(self.payload.data.packages.packageList, [])
|
||||
self.assertEqual(self.payload.data.packages.excludedList, [])
|
||||
|
||||
name = "vim-common"
|
||||
|
||||
# deselect a package
|
||||
self.payload.deselectPackage(name)
|
||||
self.assertEqual(self.payload.packageSelected(name), False)
|
||||
|
||||
# select the same package and verify it
|
||||
self.payload.selectPackage(name)
|
||||
self.assertEqual(self.payload.packageSelected(name), True)
|
||||
self.assertTrue(name in self.payload.data.packages.packageList)
|
||||
self.assertFalse(name in self.payload.data.packages.excludedList)
|
||||
|
||||
# select some other packages
|
||||
self.payload.selectPackage("bash")
|
||||
self.payload.selectPackage("gnote")
|
||||
|
||||
# deselect one of them and then verify the selection state of them all
|
||||
self.payload.deselectPackage("bash")
|
||||
self.assertFalse(self.payload.packageSelected("bash"))
|
||||
self.assertTrue(self.payload.packageSelected("gnote"))
|
||||
self.assertTrue(self.payload.packageSelected(name))
|
||||
|
||||
def payload_get_release_version_test(self):
|
||||
# Given no URL, _getReleaseVersion should be able to get a releasever
|
||||
# from pyanaconda.constants.productVersion. This trickery is due to the
|
||||
# fact that pyanaconda/packaging/__init__.py will have already imported
|
||||
# productVersion from pyanaconda.constants.
|
||||
import pyanaconda.packaging
|
||||
pyanaconda.packaging.productVersion = "17-Beta"
|
||||
self.assertEqual(self.payload._getReleaseVersion(None), "17")
|
@ -1,480 +0,0 @@
|
||||
#!/usr/bin/python
|
||||
|
||||
import mock
|
||||
|
||||
class PartIntfHelpersTest(mock.TestCase):
|
||||
|
||||
def setUp(self):
|
||||
self.setupModules(["_isys", "block", 'parted', 'storage',
|
||||
'pyanaconda.storage.formats', 'logging',
|
||||
'ConfigParser', 'pyanaconda.storage.storage_log'])
|
||||
|
||||
self.fs = mock.DiskIO()
|
||||
|
||||
import pyanaconda
|
||||
pyanaconda.anaconda_log = mock.Mock()
|
||||
|
||||
import pyanaconda.partIntfHelpers
|
||||
|
||||
def tearDown(self):
|
||||
self.tearDownModules()
|
||||
|
||||
# sanityCheckVolumeGroupName tests
|
||||
|
||||
def sanitycheckvolumegroupname_right_hostname_1_test(self):
|
||||
import pyanaconda.partIntfHelpers
|
||||
HOSTNAME = "hostname"
|
||||
ret = pyanaconda.partIntfHelpers.sanityCheckVolumeGroupName(HOSTNAME)
|
||||
self.assertEqual(ret, None)
|
||||
|
||||
def sanitycheckvolumegroupname_right_hostname_2_test(self):
|
||||
import pyanaconda.partIntfHelpers
|
||||
HOSTNAME = "h"
|
||||
ret = pyanaconda.partIntfHelpers.sanityCheckVolumeGroupName(HOSTNAME)
|
||||
self.assertEqual(ret, None)
|
||||
|
||||
def sanitycheckvolumegroupname_right_hostname_3_test(self):
|
||||
import pyanaconda.partIntfHelpers
|
||||
HOSTNAME = "a" * 127
|
||||
ret = pyanaconda.partIntfHelpers.sanityCheckVolumeGroupName(HOSTNAME)
|
||||
self.assertEqual(ret, None)
|
||||
|
||||
def sanitycheckvolumegroupname_right_hostname_4_test(self):
|
||||
import pyanaconda.partIntfHelpers
|
||||
HOSTNAME = "h-o_s-t.name"
|
||||
ret = pyanaconda.partIntfHelpers.sanityCheckVolumeGroupName(HOSTNAME)
|
||||
self.assertEqual(ret, None)
|
||||
|
||||
def sanitycheckvolumegroupname_empty_hostname_test(self):
|
||||
import pyanaconda.partIntfHelpers
|
||||
HOSTNAME = ""
|
||||
ret = pyanaconda.partIntfHelpers.sanityCheckVolumeGroupName(HOSTNAME)
|
||||
self.assertNotEqual(ret, None)
|
||||
|
||||
def sanitycheckvolumegroupname_long_hostname_test(self):
|
||||
import pyanaconda.partIntfHelpers
|
||||
HOSTNAME = "asdfasdfas" * 13
|
||||
ret = pyanaconda.partIntfHelpers.sanityCheckVolumeGroupName(HOSTNAME)
|
||||
self.assertNotEqual(ret, None)
|
||||
|
||||
def sanitycheckvolumegroupname_bad_hostname_1_test(self):
|
||||
import pyanaconda.partIntfHelpers
|
||||
HOSTNAME = 'lvm'
|
||||
ret = pyanaconda.partIntfHelpers.sanityCheckVolumeGroupName(HOSTNAME)
|
||||
self.assertNotEqual(ret, None)
|
||||
|
||||
def sanitycheckvolumegroupname_bad_hostname_2_test(self):
|
||||
import pyanaconda.partIntfHelpers
|
||||
HOSTNAME = 'root'
|
||||
ret = pyanaconda.partIntfHelpers.sanityCheckVolumeGroupName(HOSTNAME)
|
||||
self.assertNotEqual(ret, None)
|
||||
|
||||
def sanitycheckvolumegroupname_bad_hostname_3_test(self):
|
||||
import pyanaconda.partIntfHelpers
|
||||
HOSTNAME = '.'
|
||||
ret = pyanaconda.partIntfHelpers.sanityCheckVolumeGroupName(HOSTNAME)
|
||||
self.assertNotEqual(ret, None)
|
||||
|
||||
def sanitycheckvolumegroupname_bad_hostname_4_test(self):
|
||||
import pyanaconda.partIntfHelpers
|
||||
HOSTNAME = '..'
|
||||
ret = pyanaconda.partIntfHelpers.sanityCheckVolumeGroupName(HOSTNAME)
|
||||
self.assertNotEqual(ret, None)
|
||||
|
||||
def sanitycheckvolumegroupname_bad_hostname_5_test(self):
|
||||
import pyanaconda.partIntfHelpers
|
||||
HOSTNAME = 'foo bar'
|
||||
ret = pyanaconda.partIntfHelpers.sanityCheckVolumeGroupName(HOSTNAME)
|
||||
self.assertNotEqual(ret, None)
|
||||
|
||||
def sanitycheckvolumegroupname_bad_hostname_6_test(self):
|
||||
import pyanaconda.partIntfHelpers
|
||||
HOSTNAME = 'foob@r'
|
||||
ret = pyanaconda.partIntfHelpers.sanityCheckVolumeGroupName(HOSTNAME)
|
||||
self.assertNotEqual(ret, None)
|
||||
|
||||
# sanityCheckLogicalVolumeName test
|
||||
|
||||
def sanitychecklogicalvolumename_right_name_1_test(self):
|
||||
import pyanaconda.partIntfHelpers
|
||||
LOGVOLNAME = "name"
|
||||
ret = pyanaconda.partIntfHelpers.sanityCheckLogicalVolumeName(LOGVOLNAME)
|
||||
self.assertEqual(ret, None)
|
||||
|
||||
def sanitychecklogicalvolumename_right_name_2_test(self):
|
||||
import pyanaconda.partIntfHelpers
|
||||
LOGVOLNAME = "name_00.9"
|
||||
ret = pyanaconda.partIntfHelpers.sanityCheckLogicalVolumeName(LOGVOLNAME)
|
||||
self.assertEqual(ret, None)
|
||||
|
||||
def sanitychecklogicalvolumename_right_name_3_test(self):
|
||||
import pyanaconda.partIntfHelpers
|
||||
LOGVOLNAME = "a"
|
||||
ret = pyanaconda.partIntfHelpers.sanityCheckLogicalVolumeName(LOGVOLNAME)
|
||||
self.assertEqual(ret, None)
|
||||
|
||||
def sanitychecklogicalvolumename_empty_name_test(self):
|
||||
import pyanaconda.partIntfHelpers
|
||||
LOGVOLNAME = ""
|
||||
ret = pyanaconda.partIntfHelpers.sanityCheckLogicalVolumeName(LOGVOLNAME)
|
||||
self.assertNotEqual(ret, None)
|
||||
|
||||
def sanitychecklogicalvolumename_long_name_test(self):
|
||||
import pyanaconda.partIntfHelpers
|
||||
LOGVOLNAME = "b" * 129
|
||||
ret = pyanaconda.partIntfHelpers.sanityCheckLogicalVolumeName(LOGVOLNAME)
|
||||
self.assertNotEqual(ret, None)
|
||||
|
||||
def sanitychecklogicalvolumename_bad_name_1_test(self):
|
||||
import pyanaconda.partIntfHelpers
|
||||
LOGVOLNAME = "group"
|
||||
ret = pyanaconda.partIntfHelpers.sanityCheckLogicalVolumeName(LOGVOLNAME)
|
||||
self.assertNotEqual(ret, None)
|
||||
|
||||
def sanitychecklogicalvolumename_bad_name_2_test(self):
|
||||
import pyanaconda.partIntfHelpers
|
||||
LOGVOLNAME = "."
|
||||
ret = pyanaconda.partIntfHelpers.sanityCheckLogicalVolumeName(LOGVOLNAME)
|
||||
self.assertNotEqual(ret, None)
|
||||
|
||||
def sanitychecklogicalvolumename_bad_name_3_test(self):
|
||||
import pyanaconda.partIntfHelpers
|
||||
LOGVOLNAME = ".."
|
||||
ret = pyanaconda.partIntfHelpers.sanityCheckLogicalVolumeName(LOGVOLNAME)
|
||||
self.assertNotEqual(ret, None)
|
||||
|
||||
def sanitychecklogicalvolumename_bad_name_4_test(self):
|
||||
import pyanaconda.partIntfHelpers
|
||||
LOGVOLNAME = 'foo bar'
|
||||
ret = pyanaconda.partIntfHelpers.sanityCheckLogicalVolumeName(LOGVOLNAME)
|
||||
self.assertNotEqual(ret, None)
|
||||
|
||||
def sanitychecklogicalvolumename_bad_name_5_test(self):
|
||||
import pyanaconda.partIntfHelpers
|
||||
LOGVOLNAME = 'foob@r'
|
||||
ret = pyanaconda.partIntfHelpers.sanityCheckLogicalVolumeName(LOGVOLNAME)
|
||||
self.assertNotEqual(ret, None)
|
||||
|
||||
# sanityCheckMountPoint test
|
||||
|
||||
def sanitycheckmountpoint_right_name_1_test(self):
|
||||
import pyanaconda.partIntfHelpers
|
||||
MNTPT = '/foob@r'
|
||||
ret = pyanaconda.partIntfHelpers.sanityCheckMountPoint(MNTPT)
|
||||
self.assertEqual(ret, None)
|
||||
|
||||
def sanitycheckmountpoint_right_name_2_test(self):
|
||||
import pyanaconda.partIntfHelpers
|
||||
MNTPT = '/var'
|
||||
ret = pyanaconda.partIntfHelpers.sanityCheckMountPoint(MNTPT)
|
||||
self.assertEqual(ret, None)
|
||||
|
||||
def sanitycheckmountpoint_right_name_3_test(self):
|
||||
import pyanaconda.partIntfHelpers
|
||||
MNTPT = '/'
|
||||
ret = pyanaconda.partIntfHelpers.sanityCheckMountPoint(MNTPT)
|
||||
self.assertEqual(ret, None)
|
||||
|
||||
def sanitycheckmountpoint_bad_name_1_test(self):
|
||||
import pyanaconda.partIntfHelpers
|
||||
MNTPT = '//'
|
||||
ret = pyanaconda.partIntfHelpers.sanityCheckMountPoint(MNTPT)
|
||||
self.assertNotEqual(ret, None)
|
||||
|
||||
def sanitycheckmountpoint_bad_name_2_test(self):
|
||||
import pyanaconda.partIntfHelpers
|
||||
MNTPT = '/foo bar'
|
||||
ret = pyanaconda.partIntfHelpers.sanityCheckMountPoint(MNTPT)
|
||||
self.assertNotEqual(ret, None)
|
||||
|
||||
def sanitycheckmountpoint_bad_name_3_test(self):
|
||||
import pyanaconda.partIntfHelpers
|
||||
MNTPT = '/./'
|
||||
ret = pyanaconda.partIntfHelpers.sanityCheckMountPoint(MNTPT)
|
||||
self.assertNotEqual(ret, None)
|
||||
|
||||
def sanitycheckmountpoint_bad_name_4_test(self):
|
||||
import pyanaconda.partIntfHelpers
|
||||
MNTPT = '/../'
|
||||
ret = pyanaconda.partIntfHelpers.sanityCheckMountPoint(MNTPT)
|
||||
self.assertNotEqual(ret, None)
|
||||
|
||||
def sanitycheckmountpoint_bad_name_5_test(self):
|
||||
import pyanaconda.partIntfHelpers
|
||||
MNTPT = '/..'
|
||||
ret = pyanaconda.partIntfHelpers.sanityCheckMountPoint(MNTPT)
|
||||
self.assertNotEqual(ret, None)
|
||||
|
||||
def sanitycheckmountpoint_bad_name_6_test(self):
|
||||
import pyanaconda.partIntfHelpers
|
||||
MNTPT = '/.'
|
||||
ret = pyanaconda.partIntfHelpers.sanityCheckMountPoint(MNTPT)
|
||||
self.assertNotEqual(ret, None)
|
||||
|
||||
def dodeletedevice_1_test(self):
|
||||
import pyanaconda.partIntfHelpers
|
||||
INTF = mock.Mock()
|
||||
STORAGE = mock.Mock()
|
||||
DEVICE = None
|
||||
ret = pyanaconda.partIntfHelpers.doDeleteDevice(INTF, STORAGE, DEVICE)
|
||||
self.assertFalse(ret)
|
||||
|
||||
def dodeletedevice_2_test(self):
|
||||
import pyanaconda.partIntfHelpers
|
||||
INTF = mock.Mock()
|
||||
STORAGE = mock.Mock()
|
||||
STORAGE.deviceImmutable.return_value = True
|
||||
DEVICE = mock.Mock()
|
||||
ret = pyanaconda.partIntfHelpers.doDeleteDevice(INTF, STORAGE, DEVICE)
|
||||
self.assertFalse(ret)
|
||||
|
||||
def dodeletedevice_3_test(self):
|
||||
import pyanaconda.partIntfHelpers
|
||||
pyanaconda.partIntfHelpers.confirmDelete = mock.Mock(return_value=False)
|
||||
INTF = mock.Mock()
|
||||
STORAGE = mock.Mock()
|
||||
STORAGE.deviceImmutable.return_value = False
|
||||
DEVICE = mock.Mock()
|
||||
ret = pyanaconda.partIntfHelpers.doDeleteDevice(INTF, STORAGE, DEVICE)
|
||||
self.assertFalse(ret)
|
||||
|
||||
def dodeletedevice_4_test(self):
|
||||
import pyanaconda.partIntfHelpers
|
||||
pyanaconda.partIntfHelpers.confirmDelete = mock.Mock(return_value=False)
|
||||
INTF = mock.Mock()
|
||||
STORAGE = mock.Mock()
|
||||
STORAGE.deviceImmutable.return_value = False
|
||||
STORAGE.deviceDeps.return_value = []
|
||||
DEVICE = mock.Mock()
|
||||
ret = pyanaconda.partIntfHelpers.doDeleteDevice(INTF, STORAGE, DEVICE,
|
||||
confirm=0)
|
||||
self.assertTrue(ret)
|
||||
self.assertTrue(STORAGE.destroyDevice.called)
|
||||
|
||||
def dodeletedevice_5_test(self):
|
||||
import pyanaconda.partIntfHelpers
|
||||
pyanaconda.partIntfHelpers.confirmDelete = mock.Mock(return_value=True)
|
||||
INTF = mock.Mock()
|
||||
STORAGE = mock.Mock()
|
||||
STORAGE.deviceImmutable.return_value = False
|
||||
STORAGE.deviceDeps.return_value = []
|
||||
DEVICE = mock.Mock()
|
||||
ret = pyanaconda.partIntfHelpers.doDeleteDevice(INTF, STORAGE, DEVICE)
|
||||
self.assertTrue(ret)
|
||||
self.assertTrue(STORAGE.destroyDevice.called)
|
||||
|
||||
def doclearpartitioneddevice_1_test(self):
|
||||
import pyanaconda.partIntfHelpers
|
||||
INTF = mock.Mock()
|
||||
INTF.messageWindow.return_value = 0
|
||||
STORAGE = mock.Mock()
|
||||
DEVICE = mock.Mock()
|
||||
ret = pyanaconda.partIntfHelpers.doClearPartitionedDevice(INTF, STORAGE,
|
||||
DEVICE)
|
||||
self.assertFalse(ret)
|
||||
|
||||
def doclearpartitioneddevice_2_test(self):
|
||||
import pyanaconda.partIntfHelpers
|
||||
INTF = mock.Mock()
|
||||
INTF.messageWindow.return_value = 1
|
||||
STORAGE = mock.Mock()
|
||||
STORAGE.partitions = []
|
||||
DEVICE = mock.Mock()
|
||||
ret = pyanaconda.partIntfHelpers.doClearPartitionedDevice(INTF, STORAGE,
|
||||
DEVICE)
|
||||
self.assertFalse(ret)
|
||||
|
||||
def doclearpartitioneddevice_3_test(self):
|
||||
import pyanaconda.partIntfHelpers
|
||||
INTF = mock.Mock()
|
||||
INTF.messageWindow.return_value = 1
|
||||
DEVICE = mock.Mock()
|
||||
p = mock.Mock()
|
||||
p.disk = DEVICE
|
||||
p.partedPartition.number = 0
|
||||
STORAGE = mock.Mock()
|
||||
STORAGE.partitions = [p]
|
||||
STORAGE.deviceImmutable.return_value = False
|
||||
STORAGE.deviceDeps.return_value = []
|
||||
|
||||
ret = pyanaconda.partIntfHelpers.doClearPartitionedDevice(INTF, STORAGE,
|
||||
DEVICE)
|
||||
self.assertTrue(ret)
|
||||
|
||||
def checkforswapnomatch_test(self):
|
||||
import pyanaconda.partIntfHelpers
|
||||
pyanaconda.partIntfHelpers.parted.PARTITION_SWAP = 5
|
||||
device = mock.Mock()
|
||||
device.exists.return_value = True
|
||||
device.getFlag.return_value = True
|
||||
device.format.type == "swap"
|
||||
ANACONDA = mock.Mock()
|
||||
ANACONDA.storage.partitions = [device]
|
||||
ANACONDA.intf.messageWindow.return_value = 1
|
||||
pyanaconda.partIntfHelpers.checkForSwapNoMatch(ANACONDA)
|
||||
self.assertTrue(ANACONDA.storage.formatDevice.called)
|
||||
|
||||
def musthaveselecteddrive_test(self):
|
||||
import pyanaconda.partIntfHelpers
|
||||
INTF = mock.Mock()
|
||||
pyanaconda.partIntfHelpers.mustHaveSelectedDrive(INTF)
|
||||
self.assertTrue(INTF.messageWindow.called)
|
||||
|
||||
def querynoformatpreexisting_test(self):
|
||||
import pyanaconda.partIntfHelpers
|
||||
RET = 22
|
||||
INTF = mock.Mock()
|
||||
ret = INTF.messageWindow.return_value = RET
|
||||
self.assertEqual(RET, ret)
|
||||
|
||||
def partitionsanityerrors_1_test(self):
|
||||
import pyanaconda.partIntfHelpers
|
||||
INTF = mock.Mock()
|
||||
ERRORS = []
|
||||
ret = pyanaconda.partIntfHelpers.partitionSanityErrors(INTF, ERRORS)
|
||||
self.assertEqual(1, ret)
|
||||
|
||||
def partitionsanityerrors_2_test(self):
|
||||
import pyanaconda.partIntfHelpers
|
||||
RET = 5
|
||||
INTF = mock.Mock()
|
||||
INTF.messageWindow.return_value = RET
|
||||
ERRORS = ['err string', 'foo string']
|
||||
ret = pyanaconda.partIntfHelpers.partitionSanityErrors(INTF, ERRORS)
|
||||
self.assertEqual(RET, ret)
|
||||
self.assertTrue(ERRORS[0] in INTF.messageWindow.call_args[0][1])
|
||||
self.assertTrue(ERRORS[1] in INTF.messageWindow.call_args[0][1])
|
||||
|
||||
def partitionsanitywarnings_1_test(self):
|
||||
import pyanaconda.partIntfHelpers
|
||||
INTF = mock.Mock()
|
||||
WARNINGS = []
|
||||
ret = pyanaconda.partIntfHelpers.partitionSanityWarnings(INTF, WARNINGS)
|
||||
self.assertEqual(1, ret)
|
||||
|
||||
def partitionsanitywarnings_2_test(self):
|
||||
import pyanaconda.partIntfHelpers
|
||||
RET = 5
|
||||
INTF = mock.Mock()
|
||||
INTF.messageWindow.return_value = RET
|
||||
WARNINGS = ['warning string', 'foo string']
|
||||
ret = pyanaconda.partIntfHelpers.partitionSanityWarnings(INTF, WARNINGS)
|
||||
self.assertEqual(RET, ret)
|
||||
self.assertTrue(WARNINGS[0] in INTF.messageWindow.call_args[0][1])
|
||||
self.assertTrue(WARNINGS[1] in INTF.messageWindow.call_args[0][1])
|
||||
|
||||
def partitionpreexistformatwarnings_1_test(self):
|
||||
import pyanaconda.partIntfHelpers
|
||||
INTF = mock.Mock()
|
||||
WARNINGS = []
|
||||
ret = pyanaconda.partIntfHelpers.partitionPreExistFormatWarnings(INTF, WARNINGS)
|
||||
self.assertEqual(1, ret)
|
||||
|
||||
def partitionpreexistformatwarnings_2_test(self):
|
||||
import pyanaconda.partIntfHelpers
|
||||
RET = 10
|
||||
INTF = mock.Mock()
|
||||
INTF.messageWindow.return_value = RET
|
||||
WARNINGS = [('foo', 'foobar', '/foodir')]
|
||||
ret = pyanaconda.partIntfHelpers.partitionPreExistFormatWarnings(INTF, WARNINGS)
|
||||
self.assertEqual(RET, ret)
|
||||
self.assertTrue(WARNINGS[0][0] in INTF.messageWindow.call_args[0][1])
|
||||
|
||||
def getpreexistformatwarnings_1_test(self):
|
||||
import pyanaconda.partIntfHelpers
|
||||
STORAGE = mock.Mock()
|
||||
STORAGE.devicetree.devices = []
|
||||
ret = pyanaconda.partIntfHelpers.getPreExistFormatWarnings(STORAGE)
|
||||
self.assertEqual([], ret)
|
||||
|
||||
def getpreexistformatwarnings_2_test(self):
|
||||
import pyanaconda.partIntfHelpers
|
||||
STORAGE = mock.Mock()
|
||||
device = mock.Mock()
|
||||
device.exists = True
|
||||
device.name = 'foodev'
|
||||
device.path = '/foodevdir'
|
||||
device.format.name = 'fffoodev'
|
||||
device.format.mountpoint = '/mnt/foo'
|
||||
device.format.exists = False
|
||||
device.format.hidden = False
|
||||
STORAGE.devicetree.devices = [device]
|
||||
ret = pyanaconda.partIntfHelpers.getPreExistFormatWarnings(STORAGE)
|
||||
self.assertEqual([('/foodevdir', 'fffoodev', '/mnt/foo')], ret)
|
||||
|
||||
def confirmdelete_1_test(self):
|
||||
import pyanaconda.partIntfHelpers
|
||||
INTF = mock.Mock()
|
||||
DEVICE = False
|
||||
ret = pyanaconda.partIntfHelpers.confirmDelete(INTF, DEVICE)
|
||||
self.assertEqual(None, ret)
|
||||
|
||||
def confirmdelete_2_test(self):
|
||||
import pyanaconda.partIntfHelpers
|
||||
RET = 51
|
||||
INTF = mock.Mock()
|
||||
INTF.messageWindow.return_value = RET
|
||||
DEVICE = mock.Mock()
|
||||
DEVICE.type = "lvmvg"
|
||||
DEVICE.name = "devname"
|
||||
ret = pyanaconda.partIntfHelpers.confirmDelete(INTF, DEVICE)
|
||||
self.assertEqual(RET, ret)
|
||||
self.assertTrue(DEVICE.name in INTF.messageWindow.call_args[0][1])
|
||||
|
||||
def confirmdelete_3_test(self):
|
||||
import pyanaconda.partIntfHelpers
|
||||
RET = 52
|
||||
INTF = mock.Mock()
|
||||
INTF.messageWindow.return_value = RET
|
||||
DEVICE = mock.Mock()
|
||||
DEVICE.type = "lvmlv"
|
||||
DEVICE.name = "devname"
|
||||
ret = pyanaconda.partIntfHelpers.confirmDelete(INTF, DEVICE)
|
||||
self.assertEqual(RET, ret)
|
||||
self.assertTrue(DEVICE.name in INTF.messageWindow.call_args[0][1])
|
||||
|
||||
def confirmdelete_4_test(self):
|
||||
import pyanaconda.partIntfHelpers
|
||||
RET = 53
|
||||
INTF = mock.Mock()
|
||||
INTF.messageWindow.return_value = RET
|
||||
DEVICE = mock.Mock()
|
||||
DEVICE.type = "mdarray"
|
||||
DEVICE.name = "devname"
|
||||
ret = pyanaconda.partIntfHelpers.confirmDelete(INTF, DEVICE)
|
||||
self.assertEqual(RET, ret)
|
||||
|
||||
def confirmdelete_5_test(self):
|
||||
import pyanaconda.partIntfHelpers
|
||||
RET = 54
|
||||
INTF = mock.Mock()
|
||||
INTF.messageWindow.return_value = RET
|
||||
DEVICE = mock.Mock()
|
||||
DEVICE.type = "partition"
|
||||
DEVICE.name = "devname"
|
||||
DEVICE.path = "/dev/devname"
|
||||
ret = pyanaconda.partIntfHelpers.confirmDelete(INTF, DEVICE)
|
||||
self.assertEqual(RET, ret)
|
||||
self.assertTrue(DEVICE.path in INTF.messageWindow.call_args[0][1])
|
||||
|
||||
def confirmdelete_6_test(self):
|
||||
import pyanaconda.partIntfHelpers
|
||||
RET = 55
|
||||
INTF = mock.Mock()
|
||||
INTF.messageWindow.return_value = RET
|
||||
DEVICE = mock.Mock()
|
||||
DEVICE.type = "other"
|
||||
DEVICE.name = "devname"
|
||||
ret = pyanaconda.partIntfHelpers.confirmDelete(INTF, DEVICE)
|
||||
self.assertEqual(RET, ret)
|
||||
self.assertTrue(DEVICE.type in INTF.messageWindow.call_args[0][1])
|
||||
self.assertTrue(DEVICE.name in INTF.messageWindow.call_args[0][1])
|
||||
|
||||
def confirmresetpartitionstate_test(self):
|
||||
import pyanaconda.partIntfHelpers
|
||||
RET = 61
|
||||
INTF = mock.Mock()
|
||||
INTF.messageWindow.return_value = RET
|
||||
ret = pyanaconda.partIntfHelpers.confirmResetPartitionState(INTF)
|
||||
self.assertEqual(RET, ret)
|
||||
|
@ -1,82 +0,0 @@
|
||||
#!/usr/bin/python
|
||||
|
||||
import mock
|
||||
import sys
|
||||
import __builtin__
|
||||
|
||||
import ConfigParser
|
||||
|
||||
class ProductTest(mock.TestCase):
|
||||
|
||||
def setUp(self):
|
||||
self.setupModules(['_isys', 'block', 'os'])
|
||||
self.fs = mock.DiskIO()
|
||||
|
||||
# os module global mock
|
||||
self.modifiedModule("os")
|
||||
os = sys.modules['os']
|
||||
os.access = mock.Mock(return_value=False)
|
||||
os.uname.return_value = ('', '', '', '', 'i386')
|
||||
os.environ = {}
|
||||
|
||||
# fake /tmp/product/.buildstamp file
|
||||
self.BUGURL = 'http://bug.url'
|
||||
self.FINAL = 'false'
|
||||
self.ARCH = 'i386'
|
||||
self.NAME = '__anaconda'
|
||||
self.UUID = '123456.%s' % self.ARCH
|
||||
self.VERSION = '14'
|
||||
self.FILENAME = '/tmp/product/.buildstamp'
|
||||
self.FILE = \
|
||||
"[Main]\n"\
|
||||
"BugURL: %s\n"\
|
||||
"IsFinal: %s\n"\
|
||||
"Arch: %s\n"\
|
||||
"Product: %s\n"\
|
||||
"UUID: %s\n"\
|
||||
"Version: %s\n" % \
|
||||
(self.BUGURL, self.FINAL, self.ARCH, self.NAME, self.UUID, self.VERSION)
|
||||
|
||||
self.fs.open(self.FILENAME, 'w').write(self.FILE)
|
||||
|
||||
# mock builtin open function
|
||||
self.open = __builtin__.open
|
||||
__builtin__.open = self.fs.open
|
||||
|
||||
if 'pyanaconda.product' in sys.modules:
|
||||
del(sys.modules["pyanaconda.product"])
|
||||
|
||||
def tearDown(self):
|
||||
__builtin__.open = self.open
|
||||
self.tearDownModules()
|
||||
|
||||
def bug_url_test(self):
|
||||
sys.modules['os'].access = mock.Mock(return_value=True)
|
||||
import pyanaconda.product
|
||||
self.assertEqual(pyanaconda.product.bugUrl, self.BUGURL)
|
||||
|
||||
def is_final_test(self):
|
||||
sys.modules['os'].access = mock.Mock(return_value=True)
|
||||
import pyanaconda.product
|
||||
self.assertFalse(pyanaconda.product.isFinal)
|
||||
|
||||
def product_arch_test(self):
|
||||
sys.modules['os'].access = mock.Mock(return_value=True)
|
||||
import pyanaconda.product
|
||||
self.assertEqual(pyanaconda.product.productArch, self.ARCH)
|
||||
|
||||
def product_name_test(self):
|
||||
sys.modules['os'].access = mock.Mock(return_value=True)
|
||||
import pyanaconda.product
|
||||
self.assertEqual(pyanaconda.product.productName, self.NAME)
|
||||
|
||||
def product_stamp_test(self):
|
||||
sys.modules['os'].access = mock.Mock(return_value=True)
|
||||
import pyanaconda.product
|
||||
self.assertEqual(pyanaconda.product.productStamp, self.UUID)
|
||||
|
||||
def product_version_test(self):
|
||||
sys.modules['os'].access = mock.Mock(return_value=True)
|
||||
import pyanaconda.product
|
||||
self.assertEqual(pyanaconda.product.productVersion, self.VERSION)
|
||||
|
@ -1,297 +0,0 @@
|
||||
#!/usr/bin/python
|
||||
|
||||
import mock
|
||||
|
||||
class RescueTest(mock.TestCase):
|
||||
|
||||
def setUp(self):
|
||||
self.setupModules(
|
||||
['_isys', 'block', 'parted', 'storage', 'pyanaconda.storage.formats',
|
||||
'logging', 'add_drive_text', 'ConfigParser',
|
||||
'pyanaconda.storage.storage_log', 'pyanaconda.anaconda_log', 'snack'
|
||||
])
|
||||
|
||||
self.fs = mock.DiskIO()
|
||||
|
||||
import pyanaconda
|
||||
pyanaconda.anaconda_log = mock.Mock()
|
||||
import snack
|
||||
snack.SnackScreen = mock.Mock()
|
||||
|
||||
import pyanaconda.rescue
|
||||
pyanaconda.rescue.open = self.fs.open
|
||||
|
||||
def tearDown(self):
|
||||
self.tearDownModules()
|
||||
|
||||
#
|
||||
# RescueInterface class tests
|
||||
#
|
||||
|
||||
def rescueinterface_waitwindow_test(self):
|
||||
import pyanaconda.rescue
|
||||
RET = 'foo1'
|
||||
pyanaconda.rescue.WaitWindow = mock.Mock(return_value=RET)
|
||||
TITLE = 'title'
|
||||
TEXT = 'text'
|
||||
ri = pyanaconda.rescue.RescueInterface()
|
||||
ret = ri.waitWindow(TITLE, TEXT)
|
||||
self.assertEqual(ret, RET)
|
||||
|
||||
def rescueinterface_progresswindow_test(self):
|
||||
import pyanaconda.rescue
|
||||
RET = 'foo2'
|
||||
pyanaconda.rescue.ProgressWindow = mock.Mock(return_value=RET)
|
||||
TITLE = 'title'
|
||||
TEXT = 'text'
|
||||
TOTAL = 100
|
||||
ri = pyanaconda.rescue.RescueInterface()
|
||||
ret = ri.progressWindow(TITLE, TEXT, TOTAL)
|
||||
self.assertEqual(ret, RET)
|
||||
|
||||
def rescueinterface_detailedmessagewindow_test(self):
|
||||
import pyanaconda.rescue
|
||||
RET = 'foo3'
|
||||
pyanaconda.rescue.RescueInterface.messageWindow = mock.Mock(return_value=RET)
|
||||
TITLE = 'title'
|
||||
TEXT = 'text'
|
||||
ri = pyanaconda.rescue.RescueInterface()
|
||||
ret = ri.detailedMessageWindow(TITLE, TEXT)
|
||||
self.assertEqual(ret, RET)
|
||||
|
||||
def rescueinterface_messagewindow_1_test(self):
|
||||
import pyanaconda.rescue
|
||||
pyanaconda.rescue.ButtonChoiceWindow = mock.Mock()
|
||||
TITLE = 'title'
|
||||
TEXT = 'text'
|
||||
TYPE = 'ok'
|
||||
ri = pyanaconda.rescue.RescueInterface()
|
||||
ri.detailedMessageWindow(TITLE, TEXT, TYPE)
|
||||
self.assertTrue(pyanaconda.rescue.ButtonChoiceWindow.called)
|
||||
|
||||
def rescueinterface_messagewindow_2_test(self):
|
||||
import pyanaconda.rescue
|
||||
RET='yes'
|
||||
pyanaconda.rescue.ButtonChoiceWindow = mock.Mock(return_value=RET)
|
||||
TITLE = 'title'
|
||||
TEXT = 'text'
|
||||
TYPE = 'yesno'
|
||||
ri = pyanaconda.rescue.RescueInterface()
|
||||
ret = ri.messageWindow(TITLE, TEXT, TYPE)
|
||||
self.assertEqual(ret, 1)
|
||||
|
||||
def rescueinterface_messagewindow_3_test(self):
|
||||
import pyanaconda.rescue
|
||||
RET = 'barfoo'
|
||||
pyanaconda.rescue.ButtonChoiceWindow = mock.Mock(return_value=RET)
|
||||
TITLE = 'title'
|
||||
TEXT = 'text'
|
||||
TYPE = 'custom'
|
||||
CUSTOM_BUTT = ['foo_bar', 'bar_foo']
|
||||
ri = pyanaconda.rescue.RescueInterface()
|
||||
ret = ri.messageWindow(TITLE, TEXT, TYPE, custom_buttons=CUSTOM_BUTT)
|
||||
self.assertEqual(ret, 1)
|
||||
|
||||
def rescueinterface_messagewindow_4_test(self):
|
||||
import pyanaconda.rescue
|
||||
RET = 'foo4'
|
||||
pyanaconda.rescue.OkCancelWindow = mock.Mock(return_value=RET)
|
||||
TITLE = 'title'
|
||||
TEXT = 'text'
|
||||
TYPE = 'otherfoo'
|
||||
ri = pyanaconda.rescue.RescueInterface()
|
||||
ret = ri.messageWindow(TITLE, TEXT, TYPE)
|
||||
self.assertEqual(ret, RET)
|
||||
|
||||
def rescueinterface_enablenetwork_1_test(self):
|
||||
import pyanaconda.rescue
|
||||
anaconda = mock.Mock()
|
||||
anaconda.network.netdevices = {}
|
||||
|
||||
ri = pyanaconda.rescue.RescueInterface()
|
||||
ret = ri.enableNetwork(anaconda)
|
||||
self.assertFalse(ret)
|
||||
|
||||
def rescueinterface_passphraseentrywindow_test(self):
|
||||
import pyanaconda.rescue
|
||||
RET = ('secret', False)
|
||||
pyanaconda.rescue.PassphraseEntryWindow = mock.Mock()
|
||||
pyanaconda.rescue.PassphraseEntryWindow().run.return_value = RET
|
||||
DEVICE = 'dev'
|
||||
|
||||
ri = pyanaconda.rescue.RescueInterface()
|
||||
ret = ri.passphraseEntryWindow(DEVICE)
|
||||
self.assertEqual(ret, RET)
|
||||
self.assertTrue(pyanaconda.rescue.PassphraseEntryWindow().pop.called)
|
||||
|
||||
def rescueinterface_resetinitializediskquestion_test(self):
|
||||
import pyanaconda.rescue
|
||||
ri = pyanaconda.rescue.RescueInterface()
|
||||
ri._initLabelAnswers = {'foo': 'bar'}
|
||||
ri.resetInitializeDiskQuestion()
|
||||
|
||||
def rescueinterface_resetreinitinconsistentlvmquestion_test(self):
|
||||
import pyanaconda.rescue
|
||||
ri = pyanaconda.rescue.RescueInterface()
|
||||
ri._inconsistentLVMAnswers = {'foo': 'bar'}
|
||||
ri.resetReinitInconsistentLVMQuestion()
|
||||
self.assertEqual(ri._inconsistentLVMAnswers, {})
|
||||
|
||||
def rescueinterface_questioninitializedisk_test(self):
|
||||
import pyanaconda.rescue
|
||||
ri = pyanaconda.rescue.RescueInterface()
|
||||
ret = ri.questionInitializeDisk('/', '', 0)
|
||||
self.assertFalse(ret)
|
||||
|
||||
def rescueinterface_questionreinitinconsistentlvm_test(self):
|
||||
import pyanaconda.rescue
|
||||
ri = pyanaconda.rescue.RescueInterface()
|
||||
ret = ri.questionReinitInconsistentLVM()
|
||||
self.assertFalse(ret)
|
||||
|
||||
def rescueinterface_questioninitializedasd_test(self):
|
||||
import pyanaconda.rescue
|
||||
ri = pyanaconda.rescue.RescueInterface()
|
||||
ret = ri.questionInitializeDASD('', '')
|
||||
self.assertEqual(ret, 1)
|
||||
|
||||
#
|
||||
# module function tests
|
||||
#
|
||||
|
||||
def makefstab_test(self):
|
||||
import pyanaconda.rescue
|
||||
INSTPATH = '/tmp'
|
||||
FSTAB = 'rootfs / rootfs rw 0 0'
|
||||
pyanaconda.rescue.os = mock.Mock()
|
||||
pyanaconda.rescue.os.access.return_value = True
|
||||
self.fs.open('/proc/mounts', 'w').write(FSTAB)
|
||||
self.fs.open('%s/etc/fstab' % INSTPATH, 'w')
|
||||
|
||||
ret = pyanaconda.rescue.makeFStab(INSTPATH)
|
||||
self.assertEqual(self.fs['%s/etc/fstab' % INSTPATH], FSTAB)
|
||||
|
||||
def makeresolvconf_1_test(self):
|
||||
import pyanaconda.rescue
|
||||
INSTPATH = '/tmp'
|
||||
RESOLV = "nameserver 10.0.0.1"
|
||||
pyanaconda.rescue.os = mock.Mock()
|
||||
pyanaconda.rescue.os.access.return_value = False
|
||||
pyanaconda.rescue.shutil = mock.Mock()
|
||||
|
||||
pyanaconda.rescue.makeResolvConf(INSTPATH)
|
||||
self.assertFalse(pyanaconda.rescue.shutil.copyfile.called)
|
||||
|
||||
def makeresolvconf_2_test(self):
|
||||
import pyanaconda.rescue
|
||||
INSTPATH = '/tmp'
|
||||
RESOLV = "nameserver 10.0.0.1"
|
||||
pyanaconda.rescue.os = mock.Mock()
|
||||
pyanaconda.rescue.os.access.return_value = True
|
||||
pyanaconda.rescue.shutil = mock.Mock()
|
||||
self.fs.open('%s/etc/resolv.conf' % INSTPATH, 'w').write(RESOLV)
|
||||
|
||||
pyanaconda.rescue.makeResolvConf(INSTPATH)
|
||||
self.assertFalse(pyanaconda.rescue.shutil.copyfile.called)
|
||||
|
||||
def makeresolvconf_3_test(self):
|
||||
import pyanaconda.rescue
|
||||
INSTPATH = '/tmp'
|
||||
RESOLV = "nameserver 10.0.0.1"
|
||||
pyanaconda.rescue.os = mock.Mock()
|
||||
pyanaconda.rescue.os.access.return_value = True
|
||||
pyanaconda.rescue.shutil = mock.Mock()
|
||||
self.fs.open('%s/etc/resolv.conf' % INSTPATH, 'w').write('')
|
||||
self.fs.open('/etc/resolv.conf', 'w').write('')
|
||||
|
||||
pyanaconda.rescue.makeResolvConf(INSTPATH)
|
||||
self.assertFalse(pyanaconda.rescue.shutil.copyfile.called)
|
||||
self.assertEqual(self.fs['%s/etc/resolv.conf' % INSTPATH], '')
|
||||
|
||||
def makeresolvconf_4_test(self):
|
||||
import pyanaconda.rescue
|
||||
INSTPATH = '/tmp'
|
||||
RESOLV = "nameserver 10.0.0.1"
|
||||
pyanaconda.rescue.os = mock.Mock()
|
||||
pyanaconda.rescue.os.access.return_value = True
|
||||
pyanaconda.rescue.shutil = mock.Mock()
|
||||
self.fs.open('%s/etc/resolv.conf' % INSTPATH, 'w').write('')
|
||||
self.fs.open('/etc/resolv.conf', 'w').write(RESOLV)
|
||||
|
||||
pyanaconda.rescue.makeResolvConf(INSTPATH)
|
||||
self.assertTrue(pyanaconda.rescue.shutil.copyfile.called)
|
||||
self.assertEqual(self.fs['%s/etc/resolv.conf' % INSTPATH],
|
||||
'nameserver 10.0.0.1')
|
||||
|
||||
def startnetworking_test(self):
|
||||
import pyanaconda.rescue
|
||||
NETWORK = mock.Mock()
|
||||
pyanaconda.rescue.os = mock.Mock()
|
||||
pyanaconda.rescue.startNetworking(NETWORK, '')
|
||||
self.assertEqual(pyanaconda.rescue.os.system.call_args,
|
||||
(('/usr/sbin/ifconfig lo 127.0.0.1',), {}))
|
||||
self.assertTrue(NETWORK.bringUp.called)
|
||||
|
||||
def runshell_1_test(self):
|
||||
import pyanaconda.rescue
|
||||
import sys
|
||||
TMPFILE = '/tmp/abc'
|
||||
MSG = "foo bar"
|
||||
pyanaconda.rescue.os = mock.Mock()
|
||||
pyanaconda.rescue.os.path.exists.return_value = True
|
||||
pyanaconda.rescue.subprocess = mock.Mock()
|
||||
proc = mock.Mock()
|
||||
proc.returncode = 0
|
||||
pyanaconda.rescue.subprocess.Popen.return_value = proc
|
||||
|
||||
stdout = sys.stdout
|
||||
sys.stdout = self.fs.open(TMPFILE, 'w')
|
||||
pyanaconda.rescue.runShell(msg=MSG)
|
||||
sys.stdout.close()
|
||||
sys.stdout = stdout
|
||||
|
||||
self.assertTrue(MSG in self.fs[TMPFILE])
|
||||
self.assertEqual(pyanaconda.rescue.subprocess.Popen.call_args,
|
||||
((['/usr/bin/firstaidkit-qs'],), {}))
|
||||
|
||||
def runshell_2_test(self):
|
||||
import pyanaconda.rescue
|
||||
import sys
|
||||
TMPFILE = '/tmp/abc'
|
||||
MSG = "foo bar"
|
||||
|
||||
def fake_f(filename, _=""):
|
||||
return filename == "/bin/bash"
|
||||
|
||||
pyanaconda.rescue.os = mock.Mock()
|
||||
pyanaconda.rescue.os.path.exists = fake_f
|
||||
pyanaconda.rescue.iutil = mock.Mock()
|
||||
proc = mock.Mock()
|
||||
proc.returncode = 0
|
||||
pyanaconda.rescue.subprocess.Popen.return_value = proc
|
||||
|
||||
stdout = sys.stdout
|
||||
sys.stdout = self.fs.open(TMPFILE, 'w')
|
||||
pyanaconda.rescue.runShell(msg=MSG)
|
||||
sys.stdout.close()
|
||||
sys.stdout = stdout
|
||||
|
||||
self.assertTrue(MSG in self.fs[TMPFILE])
|
||||
self.assertTrue(pyanaconda.rescue.iutil.execConsole.called)
|
||||
|
||||
def runshell_3_test(self):
|
||||
import pyanaconda.rescue
|
||||
import sys
|
||||
TMPFILE = '/tmp/abc'
|
||||
SCREEN = mock.Mock()
|
||||
pyanaconda.rescue.os = mock.Mock()
|
||||
pyanaconda.rescue.os.path.exists.return_value = True
|
||||
pyanaconda.rescue.subprocess = mock.Mock()
|
||||
proc = mock.Mock()
|
||||
proc.returncode = 0
|
||||
pyanaconda.rescue.subprocess.Popen.return_value = proc
|
||||
|
||||
pyanaconda.rescue.runShell(screen=SCREEN)
|
||||
|
||||
self.assertTrue(SCREEN.suspend.called)
|
||||
self.assertTrue(SCREEN.finish.called)
|
@ -1,62 +0,0 @@
|
||||
#!/usr/bin/python
|
||||
|
||||
import mock
|
||||
import sys
|
||||
|
||||
class SecurityTest(mock.TestCase):
|
||||
def setUp(self):
|
||||
self.setupModules(["_isys", "block", "ConfigParser"])
|
||||
|
||||
self.fs = mock.DiskIO()
|
||||
|
||||
import pyanaconda.security
|
||||
pyanaconda.security.log = mock.Mock()
|
||||
pyanaconda.security.open = self.fs.open
|
||||
pyanaconda.security.iutil = mock.Mock()
|
||||
|
||||
import pyanaconda.flags
|
||||
pyanaconda.flags.flags.selinux = 1
|
||||
|
||||
def tearDown(self):
|
||||
self.tearDownModules()
|
||||
|
||||
def set_get_selinux_test(self):
|
||||
import pyanaconda.security
|
||||
|
||||
states = pyanaconda.security.selinux_states
|
||||
scrt = pyanaconda.security.Security()
|
||||
|
||||
for state in states:
|
||||
scrt.setSELinux(state)
|
||||
self.assertEqual(scrt.getSELinux(), state)
|
||||
|
||||
def set_get_selinux_bad_sate_test(self):
|
||||
import pyanaconda.security
|
||||
|
||||
states = pyanaconda.security.selinux_states
|
||||
scrt = pyanaconda.security.Security()
|
||||
scrt.setSELinux('bad_state')
|
||||
self.assertTrue(scrt.getSELinux() in states)
|
||||
|
||||
def write_test(self):
|
||||
"""Simulate writing security (simulate executing lokkit and authconfig)"""
|
||||
import pyanaconda.security
|
||||
|
||||
scrt = pyanaconda.security.Security()
|
||||
pyanaconda.security.ROOT_PATH = "/tmp/security"
|
||||
scrt.write()
|
||||
|
||||
self.assertEqual(pyanaconda.security.iutil.method_calls,
|
||||
[('execWithRedirect',
|
||||
('/usr/sbin/lokkit', ['--selinux=enforcing']),
|
||||
{'root': '/tmp/security', 'stderr': '/dev/null', 'stdout': '/dev/null'}
|
||||
),
|
||||
('resetRpmDb', (), {}),
|
||||
('execWithRedirect',
|
||||
('/usr/sbin/authconfig',
|
||||
['--update', '--nostart', '--enableshadow', '--passalgo=sha512']
|
||||
),
|
||||
{'root': '/tmp/security', 'stderr': '/dev/tty5', 'stdout': '/dev/tty5'}
|
||||
)
|
||||
]
|
||||
)
|
@ -1,154 +0,0 @@
|
||||
#!/usr/bin/python
|
||||
|
||||
import mock
|
||||
import os
|
||||
import sys
|
||||
|
||||
class SimpleconfigTest(mock.TestCase):
|
||||
def setUp(self):
|
||||
self.setupModules(["_isys", "block", "ConfigParser"])
|
||||
import pyanaconda.simpleconfig
|
||||
|
||||
# Stuff for IfcfgFile class tests
|
||||
self.DIR = '/tmp/'
|
||||
self.IFACE = 'eth0'
|
||||
self.PATH = "%sifcfg-%s" % (self.DIR, self.IFACE)
|
||||
self.CONTENT = '# Broadcom Corporation NetXtreme BCM5761 Gigabit Ethernet\n'
|
||||
self.CONTENT += 'DEVICE=eth0\n'
|
||||
self.CONTENT += 'HWADDR=00:10:18:61:35:98\n'
|
||||
self.CONTENT += 'ONBOOT=no\n'
|
||||
open(self.PATH, 'w').write(self.CONTENT)
|
||||
|
||||
def tearDown(self):
|
||||
self.tearDownModules()
|
||||
|
||||
def uppercase_ascii_string_letters_test(self):
|
||||
"""Converting to uppercase (letters)"""
|
||||
import pyanaconda.simpleconfig
|
||||
ret = pyanaconda.simpleconfig.uppercase_ASCII_string('abcd')
|
||||
self.assertEqual(ret, 'ABCD')
|
||||
ret = pyanaconda.simpleconfig.uppercase_ASCII_string('aBCD')
|
||||
self.assertEqual(ret, 'ABCD')
|
||||
ret = pyanaconda.simpleconfig.uppercase_ASCII_string('ABCD')
|
||||
self.assertEqual(ret, 'ABCD')
|
||||
|
||||
def uppercase_ascii_string_numbers_test(self):
|
||||
"""Converting to uppercase (numbers)"""
|
||||
import pyanaconda.simpleconfig
|
||||
ret = pyanaconda.simpleconfig.uppercase_ASCII_string('123')
|
||||
self.assertEqual(ret, '123')
|
||||
|
||||
def uppercase_ascii_string_others_test(self):
|
||||
"""Converting to uppercase (special chars)"""
|
||||
import pyanaconda.simpleconfig
|
||||
ret = pyanaconda.simpleconfig.uppercase_ASCII_string('--')
|
||||
self.assertEqual(ret, '--')
|
||||
ret = pyanaconda.simpleconfig.uppercase_ASCII_string(' ')
|
||||
self.assertEqual(ret, ' ')
|
||||
ret = pyanaconda.simpleconfig.uppercase_ASCII_string('')
|
||||
self.assertEqual(ret, '')
|
||||
|
||||
def unquote_test(self):
|
||||
from pyanaconda.simpleconfig import unquote
|
||||
self.assertEqual(unquote("plain string"), "plain string")
|
||||
self.assertEqual(unquote('"double quote"'), "double quote")
|
||||
self.assertEqual(unquote("'single quote'"), "single quote")
|
||||
|
||||
def quote_test(self):
|
||||
from pyanaconda.simpleconfig import quote
|
||||
self.assertEqual(quote("nospaces"), "nospaces")
|
||||
self.assertEqual(quote("plain string"), '"plain string"')
|
||||
self.assertEqual(quote("alwaysquote", always=True), '"alwaysquote"')
|
||||
|
||||
def set_and_get_test(self):
|
||||
"""Setting and getting values"""
|
||||
import pyanaconda.simpleconfig
|
||||
scf = pyanaconda.simpleconfig.SimpleConfigFile()
|
||||
scf.set(('key1', 'value1'))
|
||||
self.assertEqual(scf.get('key1'), 'value1')
|
||||
scf.set(('KEY2', 'value2'))
|
||||
self.assertEqual(scf.get('key2'), 'value2')
|
||||
scf.set(('KEY3', 'value3'))
|
||||
self.assertEqual(scf.get('KEY3'), 'value3')
|
||||
scf.set(('key4', 'value4'))
|
||||
self.assertEqual(scf.get('KEY4'), 'value4')
|
||||
|
||||
def unset_test(self):
|
||||
import pyanaconda.simpleconfig
|
||||
scf = pyanaconda.simpleconfig.SimpleConfigFile()
|
||||
scf.set(('key1', 'value1'))
|
||||
scf.unset(('key1'))
|
||||
self.assertEqual(scf.get('key1'), '')
|
||||
|
||||
def write_test(self):
|
||||
import pyanaconda.simpleconfig
|
||||
scf = pyanaconda.simpleconfig.SimpleConfigFile()
|
||||
scf.set(('key1', 'value1'))
|
||||
scf.write('/tmp/file')
|
||||
self.assertEqual(open('/tmp/file').read(), 'KEY1=value1\n')
|
||||
|
||||
def read_test(self):
|
||||
import pyanaconda.simpleconfig
|
||||
scf = pyanaconda.simpleconfig.SimpleConfigFile()
|
||||
open('/tmp/file', 'w').write('KEY1="value1"\n')
|
||||
scf.read('/tmp/file')
|
||||
self.assertEqual(scf.get('key1'), 'value1')
|
||||
|
||||
def read_write_test(self):
|
||||
from pyanaconda.simpleconfig import SimpleConfigFile
|
||||
scf = SimpleConfigFile()
|
||||
scf.read(self.PATH)
|
||||
scf.write("/tmp/file")
|
||||
self.assertEqual(open("/tmp/file").read(), self.CONTENT)
|
||||
|
||||
def write_new_keys_test(self):
|
||||
from pyanaconda.simpleconfig import SimpleConfigFile
|
||||
scf = SimpleConfigFile()
|
||||
scf.read(self.PATH)
|
||||
scf.set(("key1", "value1"))
|
||||
scf.write("/tmp/file")
|
||||
self.assertEqual(open("/tmp/file").read(),
|
||||
self.CONTENT+"KEY1=value1\n")
|
||||
|
||||
def remove_key_test(self):
|
||||
from pyanaconda.simpleconfig import SimpleConfigFile
|
||||
scf = SimpleConfigFile()
|
||||
scf.read(self.PATH)
|
||||
scf.unset("BOOT")
|
||||
scf.write("/tmp/file")
|
||||
scf.reset()
|
||||
scf.read("/tmp/file")
|
||||
self.assertEqual(scf.get("BOOT"), "")
|
||||
|
||||
def ifcfgfile_path_property_test(self):
|
||||
import pyanaconda.simpleconfig
|
||||
scf = pyanaconda.simpleconfig.IfcfgFile(self.DIR, self.IFACE)
|
||||
self.assertEqual(scf.path, self.PATH)
|
||||
|
||||
def ifcfgfile_read_test(self):
|
||||
import pyanaconda.simpleconfig
|
||||
scf = pyanaconda.simpleconfig.IfcfgFile(self.DIR, self.IFACE)
|
||||
scf.read()
|
||||
self.assertEqual(scf.get('device'), 'eth0')
|
||||
self.assertEqual(scf.get('hwaddr'), '00:10:18:61:35:98')
|
||||
self.assertEqual(scf.get('onboot'), 'no')
|
||||
|
||||
def ifcfgfile_read_and_clear_test(self):
|
||||
import pyanaconda.simpleconfig
|
||||
scf = pyanaconda.simpleconfig.IfcfgFile(self.DIR, self.IFACE)
|
||||
scf.read()
|
||||
scf.clear()
|
||||
self.assertEqual(scf.get('device'), '')
|
||||
self.assertEqual(scf.get('hwaddr'), '')
|
||||
self.assertEqual(scf.get('onboot'), '')
|
||||
|
||||
def ifcfgfile_write_test(self):
|
||||
import pyanaconda.simpleconfig
|
||||
scf = pyanaconda.simpleconfig.IfcfgFile(self.DIR, self.IFACE)
|
||||
scf.set(('device', 'eth0'))
|
||||
scf.set(('hwaddr', '00:11:22:33:44:55'))
|
||||
scf.set(('onboot', 'no'))
|
||||
scf.write()
|
||||
self.assertEqual(open(self.PATH).read(),
|
||||
'DEVICE="eth0"\nHWADDR="00:11:22:33:44:55"\nONBOOT="no"\n')
|
||||
|
@ -1,56 +0,0 @@
|
||||
#!/usr/bin/python
|
||||
|
||||
import mock
|
||||
import sys
|
||||
|
||||
ZONE = 'Europe/Prague'
|
||||
UTC = 2
|
||||
|
||||
class TimeZoneTest(mock.TestCase):
|
||||
def setUp(self):
|
||||
self.setupModules(["_isys", "block", "ConfigParser"])
|
||||
|
||||
self.fs = mock.DiskIO()
|
||||
|
||||
import pyanaconda.timezone
|
||||
pyanaconda.timezone.log = mock.Mock()
|
||||
pyanaconda.timezone.open = self.fs.open
|
||||
pyanaconda.timezone.os.access = mock.Mock(return_value = True)
|
||||
pyanaconda.timezone.shutil.copyfile = mock.Mock()
|
||||
pyanaconda.timezone.os = mock.Mock()
|
||||
pyanaconda.timezone.os.access.return_value = True
|
||||
pyanaconda.timezone.shutil = mock.Mock()
|
||||
#pyanaconda.timezone.shutil.copyfile = mock.Mock()
|
||||
|
||||
def tearDown(self):
|
||||
self.tearDownModules()
|
||||
|
||||
def get_timezone_info_test(self):
|
||||
import pyanaconda.timezone
|
||||
tz = pyanaconda.timezone.Timezone()
|
||||
info = tz.getTimezoneInfo()
|
||||
self.assertEqual( (tz.tz, tz.utc), info )
|
||||
|
||||
def set_timezone_info_test(self):
|
||||
import pyanaconda.timezone
|
||||
tz = pyanaconda.timezone.Timezone()
|
||||
tz.setTimezoneInfo(ZONE, UTC)
|
||||
self.assertEqual((ZONE, UTC), (tz.tz, tz.utc))
|
||||
|
||||
def write_test(self):
|
||||
import pyanaconda.timezone
|
||||
|
||||
tz = pyanaconda.timezone.Timezone()
|
||||
tz.tz = ZONE
|
||||
tz.utc = True
|
||||
|
||||
PATH = ''
|
||||
ADJTIME = '0.013782 1279118821 0.000000\n1279118821\nUTC\n'
|
||||
f = self.fs.open('/mnt/sysimage/etc/adjtime', 'w')
|
||||
f.write(ADJTIME)
|
||||
f.close()
|
||||
|
||||
tz.write()
|
||||
self.assertEqual(self.fs['/mnt/sysimage/etc/adjtime'], ADJTIME)
|
||||
|
||||
|
@ -1,142 +0,0 @@
|
||||
#!/usr/bin/python
|
||||
|
||||
import mock
|
||||
import sys
|
||||
|
||||
GIDNUMBER = 'pw_gid'
|
||||
HOMEDIRECTORY = 'pw_dir'
|
||||
|
||||
class UsersTest(mock.TestCase):
|
||||
def setUp(self):
|
||||
self.setupModules(["_isys", "block", "ConfigParser"])
|
||||
|
||||
self.fs = mock.DiskIO()
|
||||
self.anaconda = mock.Mock()
|
||||
self.anaconda.security.auth.find.return_value = -1
|
||||
|
||||
import pyanaconda.users
|
||||
pyanaconda.users.log = mock.Mock()
|
||||
pyanaconda.users.iutil = mock.Mock()
|
||||
pyanaconda.users.iutil.mkdirChain = mock.Mock()
|
||||
|
||||
pyanaconda.users.os = mock.Mock()
|
||||
pyanaconda.users.os.fork.return_value=False
|
||||
pyanaconda.users.os.waitpid.return_value=(1, 1)
|
||||
pyanaconda.users.os.WEXITSTATUS.return_value=0
|
||||
|
||||
pyanaconda.users.libuser.admin = mock.Mock()
|
||||
pyanaconda.users.libuser.GIDNUMBER = GIDNUMBER
|
||||
pyanaconda.users.libuser.HOMEDIRECTORY = HOMEDIRECTORY
|
||||
pyanaconda.users.libuser.admin().lookupGroupByName.return_value = False
|
||||
pyanaconda.users.libuser.admin().lookupUserByName.return_value = False
|
||||
pyanaconda.users.libuser.admin().initGroup().get.return_value = ['']
|
||||
pyanaconda.users.libuser.admin().initGroup().reset_mock()
|
||||
pyanaconda.users.libuser.admin().reset_mock()
|
||||
|
||||
def tearDown(self):
|
||||
self.tearDownModules()
|
||||
|
||||
def create_group_test(self):
|
||||
import pyanaconda.users
|
||||
|
||||
GROUP = 'Group'
|
||||
GID = 100
|
||||
group_dict = { "name" : GROUP,
|
||||
"gid" : GID,
|
||||
"root" : ""
|
||||
}
|
||||
|
||||
usr = pyanaconda.users.Users(self.anaconda)
|
||||
self.assertTrue(usr.createGroup(GROUP, **group_dict))
|
||||
|
||||
methods = pyanaconda.users.libuser.admin().method_calls[:]
|
||||
try:
|
||||
if methods[2][0] == 'addGroup':
|
||||
methods.pop()
|
||||
except:
|
||||
pass
|
||||
|
||||
self.assertEqual(methods,
|
||||
[('lookupGroupByName', (GROUP,), {}), ('initGroup', (GROUP,), {}),])
|
||||
|
||||
self.assertEqual(
|
||||
pyanaconda.users.libuser.admin().initGroup().method_calls,
|
||||
[('set', (GIDNUMBER, GID), {})])
|
||||
|
||||
def create_user_test(self):
|
||||
import pyanaconda.users
|
||||
|
||||
USER = 'TestUser'
|
||||
PASS = 'abcde'
|
||||
user_dict = { "name" : USER,
|
||||
"password" : PASS,
|
||||
"groups" : [],
|
||||
"homedir" : "",
|
||||
"isCrypted" : False,
|
||||
"shell" : "",
|
||||
"uid" : None,
|
||||
"root" : ""
|
||||
}
|
||||
|
||||
usr = pyanaconda.users.Users(self.anaconda)
|
||||
self.assertTrue(usr.createUser(USER, **user_dict))
|
||||
|
||||
self.assertTrue(pyanaconda.users.iutil.mkdirChain.called)
|
||||
methods = [x[0] for x in pyanaconda.users.libuser.admin().method_calls]
|
||||
|
||||
self.assertEqual(methods,
|
||||
['lookupUserByName', 'initUser', 'initGroup', 'addUser','addGroup',
|
||||
'setpassUser', 'lookupGroupByName'])
|
||||
|
||||
self.assertEqual(pyanaconda.users.libuser.admin().initUser.call_args_list,
|
||||
[((USER,), {})])
|
||||
|
||||
self.assertEqual(pyanaconda.users.libuser.admin().initGroup.call_args_list,
|
||||
[((USER,), {})])
|
||||
|
||||
self.assertEqual(pyanaconda.users.libuser.admin().initUser().method_calls,
|
||||
[('set', (GIDNUMBER, ['']), {}),
|
||||
('set', (HOMEDIRECTORY, '/home/%s' % USER), {})]
|
||||
)
|
||||
|
||||
self.assertEqual(pyanaconda.users.libuser.admin().initGroup().method_calls,
|
||||
[('get', (GIDNUMBER,), {})])
|
||||
|
||||
def check_user_exists_test(self):
|
||||
import pyanaconda.users
|
||||
|
||||
USER = 'TestUser'
|
||||
|
||||
usr = pyanaconda.users.Users(self.anaconda)
|
||||
self.assertTrue(usr.checkUserExists(USER, root=''))
|
||||
self.assertEqual(pyanaconda.users.libuser.admin().method_calls,
|
||||
[('lookupUserByName', (USER,), {})])
|
||||
|
||||
def get_pass_algo_md5_test(self):
|
||||
import pyanaconda.users
|
||||
usr = pyanaconda.users.Users(self.anaconda)
|
||||
self.assertEqual(usr.getPassAlgo(), None)
|
||||
|
||||
def set_user_password_test(self):
|
||||
import pyanaconda.users
|
||||
|
||||
USER = 'TestUser'
|
||||
PASS = 'abcde'
|
||||
CRYPTED = False
|
||||
LOCK = False
|
||||
|
||||
usr = pyanaconda.users.Users(self.anaconda)
|
||||
usr.setUserPassword(USER, PASS, CRYPTED, LOCK)
|
||||
|
||||
methods = [x[0] for x in pyanaconda.users.libuser.admin().method_calls]
|
||||
self.assertEqual(methods,
|
||||
['lookupUserByName', 'setpassUser', 'modifyUser'])
|
||||
|
||||
def set_root_password_test(self):
|
||||
import pyanaconda.users
|
||||
|
||||
usr = pyanaconda.users.Users(self.anaconda)
|
||||
usr.setRootPassword()
|
||||
methods = [x[0] for x in pyanaconda.users.libuser.admin().method_calls]
|
||||
self.assertEqual(methods,
|
||||
['lookupUserByName', 'setpassUser', 'modifyUser'])
|
@ -1,116 +0,0 @@
|
||||
#!/usr/bin/python
|
||||
|
||||
import mock
|
||||
import os
|
||||
|
||||
class VncTest(mock.TestCase):
|
||||
|
||||
def setUp(self):
|
||||
self.setupModules(["_isys", "block", "logging", "ConfigParser"])
|
||||
self.fs = mock.DiskIO()
|
||||
|
||||
self.anaconda = mock.Mock()
|
||||
self.anaconda.ksdata.vnc.password = ''
|
||||
|
||||
import pyanaconda
|
||||
pyanaconda.anaconda_log = mock.Mock()
|
||||
|
||||
self.OK = 22
|
||||
|
||||
import pyanaconda.vnc
|
||||
pyanaconda.vnc.log = mock.Mock()
|
||||
pyanaconda.vnc.os = mock.Mock()
|
||||
pyanaconda.vnc.subprocess = mock.Mock()
|
||||
pyanaconda.vnc.subprocess.Popen().communicate.return_value = (1, 2)
|
||||
pyanaconda.vnc.subprocess.Popen().returncode = self.OK
|
||||
pyanaconda.vnc.open = self.fs.open
|
||||
|
||||
self.ROOT = '/'
|
||||
self.DISPLAY = '2'
|
||||
self.DESKTOP = 'Desktop'
|
||||
self.PASS = ''
|
||||
self.LOG_FILE = '/tmp/vnc.log'
|
||||
self.PW_FILE = '/tmp/vncpassword'
|
||||
self.VNCCONNECTHOST = 'host'
|
||||
|
||||
def tearDown(self):
|
||||
self.tearDownModules()
|
||||
|
||||
def set_vnc_password_1_test(self):
|
||||
import pyanaconda.vnc
|
||||
server = pyanaconda.vnc.VncServer()
|
||||
server.anaconda = self.anaconda
|
||||
pyanaconda.vnc.iutil = mock.Mock()
|
||||
pyanaconda.vnc.os.pipe.return_value = (1, 2)
|
||||
|
||||
server.setVNCPassword()
|
||||
self.assertEqual(
|
||||
pyanaconda.vnc.iutil.execWithRedirect.call_args_list,
|
||||
[(('vncpasswd', ['-f']), {'stdin': 1, 'stdout': '/tmp/vncpassword'})])
|
||||
|
||||
def initialize_test(self):
|
||||
import pyanaconda.vnc
|
||||
|
||||
IP = '192.168.0.21'
|
||||
HOSTNAME = 'desktop'
|
||||
|
||||
dev = mock.Mock()
|
||||
dev.get.return_value = 'eth0'
|
||||
pyanaconda.vnc.network = mock.Mock()
|
||||
pyanaconda.vnc.network.Network().netdevices = [dev]
|
||||
pyanaconda.vnc.network.getActiveNetDevs.return_value = [0]
|
||||
pyanaconda.vnc.network.getDefaultHostname.return_value = HOSTNAME
|
||||
pyanaconda.vnc.isys = mock.Mock()
|
||||
pyanaconda.vnc.isys.getIPAddresses = mock.Mock(return_value=[IP])
|
||||
|
||||
server = pyanaconda.vnc.VncServer(display=self.DISPLAY)
|
||||
server.initialize()
|
||||
expected = "%s:%s (%s)" % (HOSTNAME, self.DISPLAY, IP)
|
||||
self.assertEqual(server.connxinfo, expected)
|
||||
|
||||
def openlogfile_test(self):
|
||||
import pyanaconda.vnc
|
||||
FILE = 'file'
|
||||
pyanaconda.vnc.os.O_RDWR = os.O_RDWR
|
||||
pyanaconda.vnc.os.O_CREAT = os.O_CREAT
|
||||
pyanaconda.vnc.os.open.return_value = FILE
|
||||
|
||||
server = pyanaconda.vnc.VncServer(log_file=self.LOG_FILE)
|
||||
ret = server.openlogfile()
|
||||
self.assertEqual(ret, FILE)
|
||||
self.assertEqual(pyanaconda.vnc.os.open.call_args,
|
||||
((self.LOG_FILE, os.O_RDWR | os.O_CREAT), {})
|
||||
)
|
||||
|
||||
def connect_to_view_test(self):
|
||||
import pyanaconda.vnc
|
||||
pyanaconda.vnc.subprocess.Popen().communicate.return_value = (self.OK, '')
|
||||
|
||||
server = pyanaconda.vnc.VncServer(vncconnecthost=self.VNCCONNECTHOST)
|
||||
ret = server.connectToView()
|
||||
self.assertTrue(ret)
|
||||
|
||||
params = pyanaconda.vnc.subprocess.Popen.call_args[0][0]
|
||||
self.assertTrue(self.VNCCONNECTHOST in params)
|
||||
self.assertTrue(params[params.index(self.VNCCONNECTHOST)-1] == "-connect")
|
||||
|
||||
def start_server_test(self):
|
||||
import pyanaconda.vnc
|
||||
pyanaconda.vnc.VncServer.initialize = mock.Mock()
|
||||
pyanaconda.vnc.VncServer.setVNCPassword = mock.Mock()
|
||||
pyanaconda.vnc.VncServer.VNCListen = mock.Mock()
|
||||
pyanaconda.vnc.subprocess.Popen().poll.return_value = None
|
||||
pyanaconda.vnc.os.environ = {}
|
||||
pyanaconda.vnc.time.sleep = mock.Mock()
|
||||
|
||||
server = pyanaconda.vnc.VncServer(root=self.ROOT, display=self.DISPLAY,
|
||||
desktop=self.DESKTOP, password=self.PASS, vncconnecthost="")
|
||||
server.openlogfile = mock.Mock()
|
||||
server.startServer()
|
||||
|
||||
params = pyanaconda.vnc.subprocess.Popen.call_args[0][0]
|
||||
self.assertTrue('desktop=%s'%self.DESKTOP in params)
|
||||
self.assertTrue(':%s'%self.DISPLAY in params)
|
||||
self.assertTrue(pyanaconda.vnc.VncServer.VNCListen.called)
|
||||
self.assertTrue("DISPLAY" in pyanaconda.vnc.os.environ)
|
||||
self.assertEqual(pyanaconda.vnc.os.environ['DISPLAY'], ":%s" % self.DISPLAY)
|
@ -23,10 +23,6 @@ pyanaconda/text.py
|
||||
pyanaconda/users.py
|
||||
pyanaconda/vnc.py
|
||||
|
||||
# Install class definitions
|
||||
pyanaconda/installclasses/fedora.py
|
||||
pyanaconda/installclasses/rhel.py
|
||||
|
||||
# Packaging module source files
|
||||
pyanaconda/packaging/__init__.py
|
||||
pyanaconda/packaging/livepayload.py
|
||||
@ -131,6 +127,7 @@ pyanaconda/ui/gui/spokes/custom.glade
|
||||
pyanaconda/ui/gui/spokes/advstorage/fcoe.glade
|
||||
pyanaconda/ui/gui/spokes/advstorage/iscsi.glade
|
||||
pyanaconda/ui/gui/spokes/advstorage/dasd.glade
|
||||
pyanaconda/ui/gui/spokes/advstorage/zfcp.glade
|
||||
pyanaconda/ui/gui/spokes/lib/cart.glade
|
||||
pyanaconda/ui/gui/spokes/lib/custom_storage_helpers.glade
|
||||
pyanaconda/ui/gui/spokes/lib/dasdfmt.glade
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -56,9 +56,9 @@ def collect_addon_paths(toplevel_addon_paths, ui_subdir="gui"):
|
||||
if os.path.isdir(addon_spoke_path):
|
||||
module_paths["spokes"].append(("%s.%s.spokes.%%s" % (addon_id, ui_subdir), addon_spoke_path))
|
||||
|
||||
addon_category_path = os.path.join(path, addon_id, ui_subdir, "categories")
|
||||
if os.path.isdir(addon_spoke_path):
|
||||
module_paths["categories"].append(("%s.%s.categories.%%s" % (addon_id, ui_subdir), addon_category_path))
|
||||
addon_category_path = os.path.join(path, addon_id, "categories")
|
||||
if os.path.isdir(addon_category_path):
|
||||
module_paths["categories"].append(("%s.categories.%%s" % addon_id, addon_category_path))
|
||||
|
||||
return module_paths
|
||||
|
||||
@ -75,17 +75,17 @@ class AddonRegistry(object):
|
||||
|
||||
def __str__(self):
|
||||
return functools.reduce(lambda acc, (id, addon): acc + str(addon),
|
||||
self.__dict__.iteritems(), "")
|
||||
self.__dict__.items(), "")
|
||||
|
||||
def execute(self, storage, ksdata, instClass, users):
|
||||
"""This method calls execute on all the registered addons."""
|
||||
for v in self.__dict__.itervalues():
|
||||
for v in self.__dict__.values():
|
||||
if hasattr(v, "execute"):
|
||||
v.execute(storage, ksdata, instClass, users)
|
||||
|
||||
def setup(self, storage, ksdata, instClass):
|
||||
"""This method calls setup on all the registered addons."""
|
||||
for v in self.__dict__.itervalues():
|
||||
for v in self.__dict__.values():
|
||||
if hasattr(v, "setup"):
|
||||
v.setup(storage, ksdata, instClass)
|
||||
|
||||
|
@ -188,7 +188,7 @@ class Anaconda(object):
|
||||
|
||||
# gather up info on the running threads
|
||||
threads = "\nThreads\n-------\n"
|
||||
for thread_id, frame in sys._current_frames().iteritems():
|
||||
for thread_id, frame in sys._current_frames().items():
|
||||
threads += "\nThread %s\n" % (thread_id,)
|
||||
threads += "".join(format_stack(frame))
|
||||
|
||||
@ -211,8 +211,11 @@ class Anaconda(object):
|
||||
|
||||
if self.displayMode == 'g':
|
||||
from pyanaconda.ui.gui import GraphicalUserInterface
|
||||
# Run the GUI in non-fullscreen mode, so live installs can still
|
||||
# use the window manager
|
||||
self._intf = GraphicalUserInterface(self.storage, self.payload,
|
||||
self.instClass, gui_lock=self.gui_initialized)
|
||||
self.instClass, gui_lock=self.gui_initialized,
|
||||
fullscreen=False)
|
||||
|
||||
# needs to be refreshed now we know if gui or tui will take place
|
||||
addon_paths = addons.collect_addon_paths(constants.ADDON_PATHS,
|
||||
|
@ -161,7 +161,7 @@ class AnacondaArgumentParser(ArgumentParser):
|
||||
according to the option definitions set by add_argument.
|
||||
|
||||
boot_cmdline can be given as a string (to be parsed by BootArgs), or a
|
||||
dict (or any object with .iteritems()) of {bootarg:value} pairs.
|
||||
dict (or any object with .items()) of {bootarg:value} pairs.
|
||||
|
||||
If boot_cmdline is None, the boot_cmdline data will be whatever BootArgs reads
|
||||
by default (/proc/cmdline, /run/initramfs/etc/cmdline, /etc/cmdline).
|
||||
@ -186,7 +186,7 @@ class AnacondaArgumentParser(ArgumentParser):
|
||||
# go over all options corresponding to current boot cmdline
|
||||
# and do any modifications necessary
|
||||
# NOTE: program cmdline overrides boot cmdline
|
||||
for arg, val in bootargs.iteritems():
|
||||
for arg, val in bootargs.items():
|
||||
option = self._get_bootarg_option(arg)
|
||||
if option is None:
|
||||
# this boot option is unknown to Anaconda, skip it
|
||||
@ -349,7 +349,7 @@ class HelpTextParser(object):
|
||||
with open(self._path) as lines:
|
||||
for parsed_option, parsed_text in self.read(lines):
|
||||
self._help_text[parsed_option] = parsed_text
|
||||
except StandardError:
|
||||
except Exception: # pylint: disable=broad-except
|
||||
log.error("error reading help text file %s", self._path)
|
||||
|
||||
return self._help_text.get(option, "")
|
||||
|
@ -23,7 +23,7 @@
|
||||
#
|
||||
|
||||
import logging
|
||||
from logging.handlers import SysLogHandler, SYSLOG_UDP_PORT
|
||||
from logging.handlers import SysLogHandler, SocketHandler, SYSLOG_UDP_PORT
|
||||
import os
|
||||
import sys
|
||||
import types
|
||||
@ -32,16 +32,13 @@ import warnings
|
||||
from pyanaconda.flags import flags
|
||||
from pyanaconda.constants import LOGLVL_LOCK
|
||||
|
||||
DEFAULT_TTY_LEVEL = logging.INFO
|
||||
DEFAULT_LEVEL = logging.INFO
|
||||
ENTRY_FORMAT = "%(asctime)s,%(msecs)03d %(levelname)s %(name)s: %(message)s"
|
||||
TTY_FORMAT = "%(levelname)s %(name)s: %(message)s"
|
||||
STDOUT_FORMAT = "%(asctime)s %(message)s"
|
||||
DATE_FORMAT = "%H:%M:%S"
|
||||
|
||||
MAIN_LOG_FILE = "/tmp/anaconda.log"
|
||||
MAIN_LOG_TTY = "/dev/tty3"
|
||||
PROGRAM_LOG_FILE = "/tmp/program.log"
|
||||
PROGRAM_LOG_TTY = "/dev/tty5"
|
||||
STORAGE_LOG_FILE = "/tmp/storage.log"
|
||||
PACKAGING_LOG_FILE = "/tmp/packaging.log"
|
||||
SENSITIVE_INFO_LOG_FILE = "/tmp/sensitive-info.log"
|
||||
@ -89,12 +86,16 @@ class AnacondaSyslogHandler(SysLogHandler):
|
||||
"""Map the priority level to a syslog level """
|
||||
return self.levelMap.get(level, SysLogHandler.mapPriority(self, level))
|
||||
|
||||
class AnacondaSocketHandler(SocketHandler):
|
||||
def makePickle(self, record):
|
||||
return self.formatter.format(record) + "\n"
|
||||
|
||||
class AnacondaLog:
|
||||
SYSLOG_CFGFILE = "/etc/rsyslog.conf"
|
||||
VIRTIO_PORT = "/dev/virtio-ports/org.fedoraproject.anaconda.log.0"
|
||||
|
||||
def __init__ (self):
|
||||
self.tty_loglevel = DEFAULT_TTY_LEVEL
|
||||
self.loglevel = DEFAULT_LEVEL
|
||||
self.remote_syslog = None
|
||||
# Rename the loglevels so they are the same as in syslog.
|
||||
logging.addLevelName(logging.WARNING, "WARN")
|
||||
@ -117,22 +118,12 @@ class AnacondaLog:
|
||||
for logr in [self.anaconda_logger, storage_logger]:
|
||||
logr.setLevel(logging.DEBUG)
|
||||
self.forwardToSyslog(logr)
|
||||
# Logging of basic stuff and storage to tty3.
|
||||
# XXX Use os.uname here since it's too early to be importing the
|
||||
# storage module.
|
||||
if not os.uname()[4].startswith('s390') and os.access(MAIN_LOG_TTY, os.W_OK):
|
||||
self.addFileHandler(MAIN_LOG_TTY, logr,
|
||||
fmtStr=TTY_FORMAT,
|
||||
autoLevel=True)
|
||||
|
||||
# External program output log
|
||||
program_logger = logging.getLogger("program")
|
||||
program_logger.setLevel(logging.DEBUG)
|
||||
self.addFileHandler(PROGRAM_LOG_FILE, program_logger,
|
||||
minLevel=logging.DEBUG)
|
||||
self.addFileHandler(PROGRAM_LOG_TTY, program_logger,
|
||||
fmtStr=TTY_FORMAT,
|
||||
autoLevel=True)
|
||||
self.forwardToSyslog(program_logger)
|
||||
|
||||
# Create the packaging logger.
|
||||
@ -175,7 +166,7 @@ class AnacondaLog:
|
||||
fmtStr=STDOUT_FORMAT, minLevel=logging.INFO)
|
||||
|
||||
# Add a simple handler - file or stream, depending on what we're given.
|
||||
def addFileHandler (self, dest, addToLogger, minLevel=DEFAULT_TTY_LEVEL,
|
||||
def addFileHandler (self, dest, addToLogger, minLevel=DEFAULT_LEVEL,
|
||||
fmtStr=ENTRY_FORMAT,
|
||||
autoLevel=False):
|
||||
try:
|
||||
@ -216,8 +207,16 @@ class AnacondaLog:
|
||||
self.anaconda_logger.warning("%s", warnings.formatwarning(
|
||||
message, category, filename, lineno, line))
|
||||
|
||||
def setup_remotelog(self, host, port):
|
||||
remotelog = AnacondaSocketHandler(host, port)
|
||||
remotelog.setFormatter(logging.Formatter(ENTRY_FORMAT, DATE_FORMAT))
|
||||
remotelog.setLevel(logging.DEBUG)
|
||||
logging.getLogger().addHandler(remotelog)
|
||||
|
||||
def restartSyslog(self):
|
||||
os.system("systemctl restart rsyslog.service")
|
||||
# Import here instead of at the module level to avoid an import loop
|
||||
from pyanaconda.iutil import execWithRedirect
|
||||
execWithRedirect("systemctl", ["restart", "rsyslog.service"])
|
||||
|
||||
def updateRemote(self, remote_syslog):
|
||||
"""Updates the location of remote rsyslogd to forward to.
|
||||
@ -237,12 +236,13 @@ class AnacondaLog:
|
||||
"""
|
||||
TEMPLATE = "*.* %s;anaconda_syslog\n"
|
||||
|
||||
if not os.path.exists(self.VIRTIO_PORT) \
|
||||
or not os.access(self.VIRTIO_PORT, os.W_OK):
|
||||
vport = flags.cmdline.get('virtiolog', self.VIRTIO_PORT)
|
||||
|
||||
if not os.access(vport, os.W_OK):
|
||||
return
|
||||
|
||||
with open(self.SYSLOG_CFGFILE, 'a') as cfgfile:
|
||||
cfgfile.write(TEMPLATE % (self.VIRTIO_PORT,))
|
||||
cfgfile.write(TEMPLATE % (vport,))
|
||||
self.restartSyslog()
|
||||
|
||||
|
||||
|
@ -28,12 +28,13 @@ import shutil
|
||||
import struct
|
||||
import blivet
|
||||
from parted import PARTITION_BIOS_GRUB
|
||||
from glob import glob
|
||||
|
||||
from pyanaconda import iutil
|
||||
from blivet.devicelibs import raid
|
||||
from pyanaconda.isys import sync
|
||||
from pyanaconda.product import productName
|
||||
from pyanaconda.flags import flags
|
||||
from pyanaconda.flags import flags, can_touch_runtime_system
|
||||
from blivet.errors import StorageError
|
||||
from blivet.fcoe import fcoe
|
||||
import pyanaconda.network
|
||||
@ -245,7 +246,7 @@ class BootLoader(object):
|
||||
stage2_mountpoints = ["/boot", "/"]
|
||||
stage2_bootable = False
|
||||
stage2_must_be_primary = True
|
||||
stage2_description = N_("/boot filesystem")
|
||||
stage2_description = N_("/boot file system")
|
||||
stage2_max_end = Size("2 TiB")
|
||||
|
||||
@property
|
||||
@ -779,7 +780,7 @@ class BootLoader(object):
|
||||
@update_only.setter
|
||||
def update_only(self, value):
|
||||
if value and not self.can_update:
|
||||
raise ValueError("this bootloader does not support updates")
|
||||
raise ValueError("this boot loader does not support updates")
|
||||
elif self.can_update:
|
||||
self._update_only = value
|
||||
|
||||
@ -818,6 +819,14 @@ class BootLoader(object):
|
||||
if usr_device:
|
||||
dracut_devices.extend([usr_device])
|
||||
|
||||
netdevs = storage.devicetree.getDevicesByInstance(NetworkStorageDevice)
|
||||
rootdev = storage.rootDevice
|
||||
if any(rootdev.dependsOn(netdev) for netdev in netdevs):
|
||||
dracut_devices = set(dracut_devices)
|
||||
for dev in storage.mountpoints.values():
|
||||
if any(dev.dependsOn(netdev) for netdev in netdevs):
|
||||
dracut_devices.add(dev)
|
||||
|
||||
done = []
|
||||
for device in dracut_devices:
|
||||
for dep in storage.devices:
|
||||
@ -867,6 +876,11 @@ class BootLoader(object):
|
||||
continue
|
||||
self.boot_args.add("ifname=%s:%s" % (nic, hwaddr.lower()))
|
||||
|
||||
# Add iscsi_firmware to trigger dracut running iscsistart
|
||||
# See rhbz#1099603 and rhbz#1185792
|
||||
if len(glob("/sys/firmware/iscsi_boot*")) > 0:
|
||||
self.boot_args.add("iscsi_firmware")
|
||||
|
||||
#
|
||||
# preservation of most of our boot args
|
||||
#
|
||||
@ -927,7 +941,7 @@ class BootLoader(object):
|
||||
def write_config(self):
|
||||
""" Write the bootloader configuration. """
|
||||
if not self.config_file:
|
||||
raise BootLoaderError("no config file defined for this bootloader")
|
||||
raise BootLoaderError("no config file defined for this boot loader")
|
||||
|
||||
config_path = os.path.normpath(iutil.getSysroot() + self.config_file)
|
||||
if os.access(config_path, os.R_OK):
|
||||
@ -1096,12 +1110,13 @@ class GRUB(BootLoader):
|
||||
if not self.password:
|
||||
raise BootLoaderError("cannot encrypt empty password")
|
||||
|
||||
import string
|
||||
# Used for ascii_letters and digits constants
|
||||
import string # pylint: disable=deprecated-module
|
||||
import crypt
|
||||
import random
|
||||
salt = "$6$"
|
||||
salt_len = 16
|
||||
salt_chars = string.letters + string.digits + './'
|
||||
salt_chars = string.ascii_letters + string.digits + './'
|
||||
|
||||
rand_gen = random.SystemRandom()
|
||||
salt += "".join(rand_gen.choice(salt_chars) for i in range(salt_len))
|
||||
@ -1272,16 +1287,28 @@ class GRUB(BootLoader):
|
||||
# add the redundant targets if installing stage1 to a disk that is
|
||||
# a member of the stage2 array.
|
||||
|
||||
# Look for both mdraid and btrfs raid
|
||||
if self.stage2_device.type == "mdarray" and \
|
||||
self.stage2_device.level == raid.RAID1 and \
|
||||
self.stage2_device.level == raid.RAID1:
|
||||
stage2_raid = True
|
||||
# Set parents to the list of partitions in the RAID
|
||||
stage2_parents = self.stage2_device.parents
|
||||
elif self.stage2_device.type == "btrfs subvolume" and \
|
||||
self.stage2_device.parents[0].dataLevel == raid.RAID1:
|
||||
stage2_raid = True
|
||||
# Set parents to the list of partitions in the parent volume
|
||||
stage2_parents = self.stage2_device.parents[0].parents
|
||||
else:
|
||||
stage2_raid = False
|
||||
|
||||
if stage2_raid and \
|
||||
self.stage1_device.isDisk and \
|
||||
self.stage2_device.dependsOn(self.stage1_device):
|
||||
for stage2dev in self.stage2_device.parents:
|
||||
for stage2dev in stage2_parents:
|
||||
# if target disk contains any of /boot array's member
|
||||
# partitions, set up stage1 on each member's disk
|
||||
# and stage2 on each member partition
|
||||
stage1dev = stage2dev.disk
|
||||
targets.append((stage1dev, stage2dev))
|
||||
targets.append((stage1dev, self.stage2_device))
|
||||
else:
|
||||
targets.append((self.stage1_device, self.stage2_device))
|
||||
|
||||
@ -1290,7 +1317,7 @@ class GRUB(BootLoader):
|
||||
def install(self, args=None):
|
||||
rc = iutil.execInSysroot("grub-install", ["--just-copy"])
|
||||
if rc:
|
||||
raise BootLoaderError("bootloader install failed")
|
||||
raise BootLoaderError("boot loader install failed")
|
||||
|
||||
for (stage1dev, stage2dev) in self.install_targets:
|
||||
cmd = ("root %(stage2dev)s\n"
|
||||
@ -1311,7 +1338,7 @@ class GRUB(BootLoader):
|
||||
rc = iutil.execInSysroot("grub", args, stdin=pread)
|
||||
iutil.eintr_retry_call(os.close, pread)
|
||||
if rc:
|
||||
raise BootLoaderError("bootloader install failed")
|
||||
raise BootLoaderError("boot loader install failed")
|
||||
|
||||
def update(self):
|
||||
self.install()
|
||||
@ -1342,14 +1369,14 @@ class GRUB(BootLoader):
|
||||
self.stage2_device.level == raid.RAID1 and \
|
||||
self.stage1_device.type != "mdarray":
|
||||
if not self.stage1_device.isDisk:
|
||||
msg = _("bootloader stage2 device %(stage2dev)s is on a multi-disk array, but bootloader stage1 device %(stage1dev)s is not. " \
|
||||
msg = _("boot loader stage2 device %(stage2dev)s is on a multi-disk array, but boot loader stage1 device %(stage1dev)s is not. " \
|
||||
"A drive failure in %(stage2dev)s could render the system unbootable.") % \
|
||||
{"stage1dev" : self.stage1_device.name,
|
||||
"stage2dev" : self.stage2_device.name}
|
||||
self.warnings.append(msg)
|
||||
elif not self.stage2_device.dependsOn(self.stage1_device):
|
||||
msg = _("bootloader stage2 device %(stage2dev)s is on a multi-disk array, but bootloader stage1 device %(stage1dev)s is not part of this array. " \
|
||||
"The stage1 bootloader will only be installed to a single drive.") % \
|
||||
msg = _("boot loader stage2 device %(stage2dev)s is on a multi-disk array, but boot loader stage1 device %(stage1dev)s is not part of this array. " \
|
||||
"The stage1 boot loader will only be installed to a single drive.") % \
|
||||
{"stage1dev" : self.stage1_device.name,
|
||||
"stage2dev" : self.stage2_device.name}
|
||||
self.warnings.append(msg)
|
||||
@ -1373,7 +1400,7 @@ class GRUB2(GRUB):
|
||||
|
||||
- BIOS boot partition (GPT)
|
||||
- parted /dev/sda set <partition_number> bios_grub on
|
||||
- can't contain a filesystem
|
||||
- can't contain a file system
|
||||
- 31KiB min, 1MiB recommended
|
||||
|
||||
"""
|
||||
@ -1381,15 +1408,11 @@ class GRUB2(GRUB):
|
||||
packages = ["grub2"]
|
||||
_config_file = "grub.cfg"
|
||||
_config_dir = "grub2"
|
||||
config_file_mode = 0o600
|
||||
defaults_file = "/etc/default/grub"
|
||||
can_dual_boot = True
|
||||
can_update = True
|
||||
terminal_type = "gfxterm"
|
||||
|
||||
# requirements for boot devices
|
||||
stage2_device_types = ["partition", "mdarray", "lvmlv", "btrfs volume",
|
||||
"btrfs subvolume"]
|
||||
stage2_device_types = ["partition", "mdarray", "lvmlv"]
|
||||
stage2_raid_levels = [raid.RAID0, raid.RAID1, raid.RAID4,
|
||||
raid.RAID5, raid.RAID6, raid.RAID10]
|
||||
stage2_raid_metadata = ["0", "0.90", "1.0", "1.2"]
|
||||
@ -1511,7 +1534,7 @@ class GRUB2(GRUB):
|
||||
iutil.eintr_retry_call(os.close, pread)
|
||||
self.encrypted_password = buf.split()[-1].strip()
|
||||
if not self.encrypted_password.startswith("grub.pbkdf2."):
|
||||
raise BootLoaderError("failed to encrypt bootloader password")
|
||||
raise BootLoaderError("failed to encrypt boot loader password")
|
||||
|
||||
def write_password_config(self):
|
||||
if not self.password and not self.encrypted_password:
|
||||
@ -1544,22 +1567,23 @@ class GRUB2(GRUB):
|
||||
try:
|
||||
self.write_password_config()
|
||||
except (BootLoaderError, OSError, RuntimeError) as e:
|
||||
log.error("bootloader password setup failed: %s", e)
|
||||
log.error("boot loader password setup failed: %s", e)
|
||||
|
||||
# disable non-xen entries
|
||||
os.chmod("%s/etc/grub.d/10_linux" % iutil.getSysroot(), 0644)
|
||||
|
||||
# make sure the default entry is the OS we are installing
|
||||
entry_title = "0"
|
||||
rc = iutil.execInSysroot("grub2-set-default", [entry_title])
|
||||
if rc:
|
||||
log.error("failed to set default menu entry to %s", productName)
|
||||
if self.default is not None:
|
||||
entry_title = "0"
|
||||
rc = iutil.execInSysroot("grub2-set-default", [entry_title])
|
||||
if rc:
|
||||
log.error("failed to set default menu entry to %s", productName)
|
||||
|
||||
# now tell grub2 to generate the main configuration file
|
||||
rc = iutil.execInSysroot("grub2-mkconfig",
|
||||
["-o", self.config_file])
|
||||
if rc:
|
||||
raise BootLoaderError("failed to write bootloader configuration")
|
||||
raise BootLoaderError("failed to write boot loader configuration")
|
||||
|
||||
#
|
||||
# installation
|
||||
@ -1587,7 +1611,7 @@ class GRUB2(GRUB):
|
||||
root=iutil.getSysroot(),
|
||||
env_prune=['MALLOC_PERTURB_'])
|
||||
if rc:
|
||||
raise BootLoaderError("bootloader install failed")
|
||||
raise BootLoaderError("boot loader install failed")
|
||||
|
||||
def write(self):
|
||||
""" Write the bootloader configuration and install the bootloader. """
|
||||
@ -1679,6 +1703,10 @@ class EFIGRUB(GRUB2):
|
||||
log.info("Skipping efibootmgr for image/directory install.")
|
||||
return ""
|
||||
|
||||
if "noefi" in flags.cmdline:
|
||||
log.info("Skipping efibootmgr for noefi")
|
||||
return ""
|
||||
|
||||
if kwargs.pop("capture", False):
|
||||
exec_func = iutil.execWithCapture
|
||||
else:
|
||||
@ -1724,7 +1752,7 @@ class EFIGRUB(GRUB2):
|
||||
|
||||
rc = self.efibootmgr("-b", slot_id, "-B")
|
||||
if rc:
|
||||
raise BootLoaderError("failed to remove old efi boot entry. This is most likely a kernel bug.")
|
||||
raise BootLoaderError("failed to remove old efi boot entry. This is most likely a kernel or firmware bug.")
|
||||
|
||||
@property
|
||||
def efi_dir_as_efifs_dir(self):
|
||||
@ -1741,7 +1769,7 @@ class EFIGRUB(GRUB2):
|
||||
self.efi_dir_as_efifs_dir + self._efi_binary,
|
||||
root=iutil.getSysroot())
|
||||
if rc:
|
||||
raise BootLoaderError("failed to set new efi boot target. This is most likely a kernel bug.")
|
||||
raise BootLoaderError("failed to set new efi boot target. This is most likely a kernel or firmware bug.")
|
||||
|
||||
def add_efi_boot_target(self):
|
||||
if self.stage1_device.type == "partition":
|
||||
@ -1780,6 +1808,7 @@ class EFIGRUB(GRUB2):
|
||||
def check(self):
|
||||
return True
|
||||
|
||||
|
||||
class XenEFI(EFIGRUB):
|
||||
packages = ["efibootmgr"]
|
||||
_config_file = 'xen.cfg'
|
||||
@ -1852,22 +1881,15 @@ class XenEFI(EFIGRUB):
|
||||
write_config = BootLoader.write_config
|
||||
|
||||
|
||||
# FIXME: We need to include grubby, and omit the shim package
|
||||
# on aarch64 until we get all the EFI bits in place.
|
||||
class Aarch64EFIGRUB(EFIGRUB):
|
||||
packages = ["grub2-efi", "efibootmgr", "grubby"]
|
||||
|
||||
_serial_consoles = ["ttyAMA", "ttyS"]
|
||||
|
||||
_efi_binary = "\\grubaa64.efi"
|
||||
|
||||
|
||||
class MacEFIGRUB(EFIGRUB):
|
||||
def mactel_config(self):
|
||||
if os.path.exists(iutil.getSysroot() + "/usr/libexec/mactel-boot-setup"):
|
||||
rc = iutil.execInSysroot("/usr/libexec/mactel-boot-setup", [])
|
||||
if rc:
|
||||
log.error("failed to configure Mac bootloader")
|
||||
log.error("failed to configure Mac boot loader")
|
||||
|
||||
def install(self, args=None):
|
||||
super(MacEFIGRUB, self).install()
|
||||
@ -2016,7 +2038,7 @@ class Yaboot(YabootBase):
|
||||
args = ["-f", "-C", self.config_file]
|
||||
rc = iutil.execInSysroot(self.prog, args)
|
||||
if rc:
|
||||
raise BootLoaderError("bootloader installation failed")
|
||||
raise BootLoaderError("boot loader installation failed")
|
||||
|
||||
|
||||
class IPSeriesYaboot(Yaboot):
|
||||
@ -2040,6 +2062,8 @@ class IPSeriesYaboot(Yaboot):
|
||||
super(IPSeriesYaboot, self).install()
|
||||
|
||||
def updatePowerPCBootList(self):
|
||||
if not can_touch_runtime_system("updatePowerPCBootList", touch_live=True):
|
||||
return
|
||||
|
||||
log.debug("updatePowerPCBootList: self.stage1_device.path = %s", self.stage1_device.path)
|
||||
|
||||
@ -2065,7 +2089,7 @@ class IPSeriesYaboot(Yaboot):
|
||||
|
||||
# Place the disk containing the PReP partition first.
|
||||
# Remove all other occurances of it.
|
||||
boot_list = [boot_disk] + filter(lambda x: x != boot_disk, boot_list)
|
||||
boot_list = [boot_disk] + [x for x in boot_list if x != boot_disk]
|
||||
|
||||
log.debug("updatePowerPCBootList: updated boot_list = %s", boot_list)
|
||||
|
||||
@ -2100,6 +2124,8 @@ class IPSeriesGRUB2(GRUB2):
|
||||
|
||||
# This will update the PowerPC's (ppc) bios boot devive order list
|
||||
def updateNVRAMBootList(self):
|
||||
if not can_touch_runtime_system("updateNVRAMBootList", touch_live=True):
|
||||
return
|
||||
|
||||
log.debug("updateNVRAMBootList: self.stage1_device.path = %s", self.stage1_device.path)
|
||||
|
||||
@ -2124,7 +2150,7 @@ class IPSeriesGRUB2(GRUB2):
|
||||
|
||||
# Place the disk containing the PReP partition first.
|
||||
# Remove all other occurances of it.
|
||||
boot_list = [boot_disk] + filter(lambda x: x != boot_disk, boot_list)
|
||||
boot_list = [boot_disk] + [x for x in boot_list if x != boot_disk]
|
||||
|
||||
update_value = "boot-device=%s" % " ".join(boot_list)
|
||||
|
||||
@ -2357,7 +2383,7 @@ class EXTLINUX(BootLoader):
|
||||
rc = iutil.execInSysroot("extlinux", args)
|
||||
|
||||
if rc:
|
||||
raise BootLoaderError("bootloader install failed")
|
||||
raise BootLoaderError("boot loader install failed")
|
||||
|
||||
|
||||
# every platform that wants a bootloader needs to be in this dict
|
||||
@ -2450,21 +2476,31 @@ def writeBootLoader(storage, payload, instClass, ksdata):
|
||||
"""
|
||||
if not storage.bootloader.skip_bootloader:
|
||||
stage1_device = storage.bootloader.stage1_device
|
||||
log.info("bootloader stage1 target device is %s", stage1_device.name)
|
||||
log.info("boot loader stage1 target device is %s", stage1_device.name)
|
||||
stage2_device = storage.bootloader.stage2_device
|
||||
log.info("bootloader stage2 target device is %s", stage2_device.name)
|
||||
log.info("boot loader stage2 target device is %s", stage2_device.name)
|
||||
|
||||
# Bridge storage EFI configuration to bootloader
|
||||
if hasattr(storage.bootloader, 'efi_dir'):
|
||||
storage.bootloader.efi_dir = instClass.efi_dir
|
||||
|
||||
if isinstance(payload, RPMOSTreePayload):
|
||||
if storage.bootloader.skip_bootloader:
|
||||
log.info("skipping bootloader install per user request")
|
||||
log.info("skipping boot loader install per user request")
|
||||
return
|
||||
writeBootLoaderFinal(storage, payload, instClass, ksdata)
|
||||
return
|
||||
|
||||
# get a list of installed kernel packages
|
||||
kernel_versions = payload.kernelVersionList + payload.rescueKernelList
|
||||
# add whatever rescue kernels we can find to the end
|
||||
kernel_versions = list(payload.kernelVersionList)
|
||||
|
||||
rescue_versions = glob(iutil.getSysroot() + "/boot/vmlinuz-*-rescue-*")
|
||||
rescue_versions += glob(iutil.getSysroot() + "/boot/efi/EFI/%s/vmlinuz-*-rescue-*" % instClass.efi_dir)
|
||||
kernel_versions += (f.split("/")[-1][8:] for f in rescue_versions)
|
||||
|
||||
if not kernel_versions:
|
||||
log.warning("no kernel was installed -- bootloader config unchanged")
|
||||
log.warning("no kernel was installed -- boot loader config unchanged")
|
||||
return
|
||||
|
||||
# all the linux images' labels are based on the default image's
|
||||
@ -2480,14 +2516,12 @@ def writeBootLoader(storage, payload, instClass, ksdata):
|
||||
short=base_short_label)
|
||||
storage.bootloader.add_image(default_image)
|
||||
storage.bootloader.default = default_image
|
||||
if hasattr(storage.bootloader, 'efi_dir'):
|
||||
storage.bootloader.efi_dir = instClass.efi_dir
|
||||
|
||||
# write out /etc/sysconfig/kernel
|
||||
writeSysconfigKernel(storage, version, instClass)
|
||||
|
||||
if storage.bootloader.skip_bootloader:
|
||||
log.info("skipping bootloader install per user request")
|
||||
log.info("skipping boot loader install per user request")
|
||||
return
|
||||
|
||||
# now add an image for each of the other kernels
|
||||
|
@ -19,7 +19,8 @@
|
||||
# Author(s): Erik Troan <ewt@redhat.com>
|
||||
#
|
||||
|
||||
import string
|
||||
# Used for digits, ascii_letters, punctuation constants
|
||||
import string # pylint: disable=deprecated-module
|
||||
from pyanaconda.i18n import N_
|
||||
|
||||
# Use -1 to indicate that the selinux configuration is unset
|
||||
@ -51,7 +52,7 @@ DD_RPMS = "/tmp/DD-*"
|
||||
TRANSLATIONS_UPDATE_DIR="/tmp/updates/po"
|
||||
|
||||
ANACONDA_CLEANUP = "anaconda-cleanup"
|
||||
MOUNT_DIR = "/mnt/install"
|
||||
MOUNT_DIR = "/run/install"
|
||||
DRACUT_REPODIR = "/run/install/repo"
|
||||
DRACUT_ISODIR = "/run/install/source"
|
||||
ISO_DIR = MOUNT_DIR + "/isodir"
|
||||
@ -62,7 +63,7 @@ BASE_REPO_NAME = "anaconda"
|
||||
# NOTE: this should be LANG_TERRITORY.CODESET, e.g. en_US.UTF-8
|
||||
DEFAULT_LANG = "en_US.UTF-8"
|
||||
|
||||
DEFAULT_VC_FONT = "latarcyrheb-sun16"
|
||||
DEFAULT_VC_FONT = "eurlatgr"
|
||||
|
||||
DEFAULT_KEYBOARD = "us"
|
||||
|
||||
@ -133,15 +134,16 @@ FIRSTBOOT_ENVIRON = "firstboot"
|
||||
UNSUPPORTED_HW = 1 << 28
|
||||
|
||||
# Password validation
|
||||
PASSWORD_MIN_LEN = 6
|
||||
PASSWORD_MIN_LEN = 8
|
||||
PASSWORD_EMPTY_ERROR = N_("The password is empty.")
|
||||
PASSWORD_CONFIRM_ERROR_GUI = N_("The passwords do not match.")
|
||||
PASSWORD_CONFIRM_ERROR_TUI = N_("The passwords you entered were different. Please try again.")
|
||||
PASSWORD_WEAK = N_("The password you have provided is weak. You will have to press Done twice to confirm it.")
|
||||
PASSWORD_WEAK_WITH_ERROR = N_("The password you have provided is weak: %s. You will have to press Done twice to confirm it.")
|
||||
PASSWORD_WEAK = N_("The password you have provided is weak. %s")
|
||||
PASSWORD_WEAK_WITH_ERROR = N_("The password you have provided is weak: %s. %s")
|
||||
PASSWORD_WEAK_CONFIRM = N_("You have provided a weak password. Press Done again to use anyway.")
|
||||
PASSWORD_WEAK_CONFIRM_WITH_ERROR = N_("You have provided a weak password: %s. Press Done again to use anyway.")
|
||||
PASSWORD_ASCII = N_("The password you have provided contains non-ASCII characters. You may not be able to switch between keyboard layouts to login. Press Done to continue.")
|
||||
PASSWORD_DONE_TWICE = N_("You will have to press Done twice to confirm it.")
|
||||
|
||||
PASSWORD_STRENGTH_DESC = [N_("Empty"), N_("Weak"), N_("Fair"), N_("Good"), N_("Strong")]
|
||||
|
||||
@ -159,9 +161,22 @@ CMDLINE_APPEND = ["modprobe.blacklist"]
|
||||
|
||||
DEFAULT_AUTOPART_TYPE = AUTOPART_TYPE_LVM
|
||||
|
||||
# Default to these units when reading user input when no units given
|
||||
SIZE_UNITS_DEFAULT = "MiB"
|
||||
|
||||
import logging
|
||||
LOGLVL_LOCK = logging.DEBUG-1
|
||||
|
||||
# Constants for reporting status to IPMI. These are from the IPMI spec v2 rev1.1, page 512.
|
||||
IPMI_STARTED = 0x7 # installation started
|
||||
IPMI_FINISHED = 0x8 # installation finished successfully
|
||||
IPMI_ABORTED = 0x9 # installation finished unsuccessfully, due to some non-exn error
|
||||
IPMI_FAILED = 0xA # installation hit an exception
|
||||
|
||||
|
||||
# for how long (in seconds) we try to wait for enough entropy for LUKS
|
||||
# keep this a multiple of 60 (minutes)
|
||||
MAX_ENTROPY_WAIT = 10 * 60
|
||||
MAX_ENTROPY_WAIT = 10 * 60
|
||||
|
||||
# X display number to use
|
||||
X_DISPLAY_NUMBER = 1
|
||||
|
@ -55,6 +55,11 @@ class CmdlineError(Exception):
|
||||
class RemovedModuleError(ImportError):
|
||||
pass
|
||||
|
||||
class PasswordCryptError(Exception):
|
||||
def __init__(self, algo):
|
||||
Exception.__init__(self)
|
||||
self.algo = algo
|
||||
|
||||
class ZIPLError(Exception):
|
||||
pass
|
||||
|
||||
@ -122,20 +127,11 @@ class ErrorHandler(object):
|
||||
self.ui.showError(message)
|
||||
return ERROR_RAISE
|
||||
|
||||
def _dirtyFSHandler(self, exn):
|
||||
message = _("The following file systems for your Linux system were "
|
||||
"not unmounted cleanly. Would you like to mount them "
|
||||
"anyway?\n%s") % exn.devices
|
||||
if self.ui.showYesNoQuestion(message):
|
||||
return ERROR_CONTINUE
|
||||
else:
|
||||
return ERROR_RAISE
|
||||
|
||||
def _fstabTypeMismatchHandler(self, exn):
|
||||
# FIXME: include the two types in the message instead of including
|
||||
# the raw exception text
|
||||
message = _("There is an entry in your /etc/fstab file that contains "
|
||||
"an invalid or incorrect filesystem type:\n\n")
|
||||
"an invalid or incorrect file system type:\n\n")
|
||||
message += " " + str(exn)
|
||||
self.ui.showError(message)
|
||||
|
||||
@ -245,7 +241,7 @@ class ErrorHandler(object):
|
||||
return ERROR_RAISE
|
||||
|
||||
def _bootLoaderErrorHandler(self, exn):
|
||||
message = _("The following error occurred while installing the bootloader. "
|
||||
message = _("The following error occurred while installing the boot loader. "
|
||||
"The system will not be bootable. "
|
||||
"Would you like to ignore this and continue with "
|
||||
"installation?")
|
||||
@ -256,6 +252,12 @@ class ErrorHandler(object):
|
||||
else:
|
||||
return ERROR_RAISE
|
||||
|
||||
def _passwordCryptErrorHandler(self, exn):
|
||||
message = _("Unable to encrypt password: unsupported algorithm %s") % exn.algo
|
||||
|
||||
self.ui.showError(message)
|
||||
return ERROR_RAISE
|
||||
|
||||
def _ziplErrorHandler(self, *args, **kwargs):
|
||||
details = kwargs["exception"]
|
||||
message = _("Installation was stopped due to an error installing the "
|
||||
@ -283,7 +285,6 @@ class ErrorHandler(object):
|
||||
_map = {"PartitioningError": self._partitionErrorHandler,
|
||||
"FSResizeError": self._fsResizeHandler,
|
||||
"NoDisksError": self._noDisksHandler,
|
||||
"DirtyFSError": self._dirtyFSHandler,
|
||||
"FSTabTypeMismatchError": self._fstabTypeMismatchHandler,
|
||||
"InvalidImageSizeError": self._invalidImageSizeHandler,
|
||||
"MissingImageError": self._missingImageHandler,
|
||||
@ -295,6 +296,7 @@ class ErrorHandler(object):
|
||||
"PayloadInstallError": self._payloadInstallHandler,
|
||||
"DependencyError": self._dependencyErrorHandler,
|
||||
"BootLoaderError": self._bootLoaderErrorHandler,
|
||||
"PasswordCryptError": self._passwordCryptErrorHandler,
|
||||
"ZIPLError": self._ziplErrorHandler}
|
||||
|
||||
if exn.__class__.__name__ in _map:
|
||||
|
@ -28,7 +28,6 @@ from pyanaconda import iutil, kickstart
|
||||
import sys
|
||||
import os
|
||||
import shutil
|
||||
import signal
|
||||
import time
|
||||
import re
|
||||
import errno
|
||||
@ -37,7 +36,7 @@ import traceback
|
||||
import blivet.errors
|
||||
from pyanaconda.errors import CmdlineError
|
||||
from pyanaconda.ui.communication import hubQ
|
||||
from pyanaconda.constants import THREAD_EXCEPTION_HANDLING_TEST
|
||||
from pyanaconda.constants import THREAD_EXCEPTION_HANDLING_TEST, IPMI_FAILED
|
||||
from pyanaconda.threads import threadMgr
|
||||
from pyanaconda.i18n import _
|
||||
from pyanaconda import flags
|
||||
@ -50,7 +49,7 @@ log = logging.getLogger("anaconda")
|
||||
|
||||
class AnacondaExceptionHandler(ExceptionHandler):
|
||||
|
||||
def __init__(self, confObj, intfClass, exnClass, tty_num, gui_lock):
|
||||
def __init__(self, confObj, intfClass, exnClass, tty_num, gui_lock, interactive):
|
||||
"""
|
||||
:see: python-meh's ExceptionHandler
|
||||
:param tty_num: the number of tty the interface is running on
|
||||
@ -60,8 +59,9 @@ class AnacondaExceptionHandler(ExceptionHandler):
|
||||
ExceptionHandler.__init__(self, confObj, intfClass, exnClass)
|
||||
self._gui_lock = gui_lock
|
||||
self._intf_tty_num = tty_num
|
||||
self._interactive = interactive
|
||||
|
||||
def run_handleException(self, dump_info):
|
||||
def _main_loop_handleException(self, dump_info):
|
||||
"""
|
||||
Helper method with one argument only so that it can be registered
|
||||
with GLib.idle_add() to run on idle or called from a handler.
|
||||
@ -70,8 +70,21 @@ class AnacondaExceptionHandler(ExceptionHandler):
|
||||
|
||||
"""
|
||||
|
||||
super(AnacondaExceptionHandler, self).handleException(dump_info)
|
||||
return False
|
||||
ty = dump_info.exc_info.type
|
||||
value = dump_info.exc_info.value
|
||||
|
||||
if (issubclass(ty, blivet.errors.StorageError) and value.hardware_fault) \
|
||||
or (issubclass(ty, OSError) and value.errno == errno.EIO):
|
||||
# hardware fault or '[Errno 5] Input/Output error'
|
||||
hw_error_msg = _("The installation was stopped due to what "
|
||||
"seems to be a problem with your hardware. "
|
||||
"The exact error message is:\n\n%s.\n\n "
|
||||
"The installer will now terminate.") % str(value)
|
||||
self.intf.messageWindow(_("Hardware error occured"), hw_error_msg)
|
||||
sys.exit(0)
|
||||
else:
|
||||
super(AnacondaExceptionHandler, self).handleException(dump_info)
|
||||
return False
|
||||
|
||||
def handleException(self, dump_info):
|
||||
"""
|
||||
@ -90,78 +103,70 @@ class AnacondaExceptionHandler(ExceptionHandler):
|
||||
ty = dump_info.exc_info.type
|
||||
value = dump_info.exc_info.value
|
||||
|
||||
if (issubclass(ty, blivet.errors.StorageError) and value.hardware_fault) \
|
||||
or (issubclass(ty, OSError) and value.errno == errno.EIO):
|
||||
# hardware fault or '[Errno 5] Input/Output error'
|
||||
hw_error_msg = _("The installation was stopped due to what "
|
||||
"seems to be a problem with your hardware. "
|
||||
"The exact error message is:\n\n%s.\n\n "
|
||||
"The installer will now terminate.") % str(value)
|
||||
self.intf.messageWindow(_("Hardware error occured"), hw_error_msg)
|
||||
sys.exit(0)
|
||||
else:
|
||||
try:
|
||||
from gi.repository import Gtk
|
||||
try:
|
||||
from gi.repository import Gtk
|
||||
|
||||
# XXX: Gtk stopped raising RuntimeError if it fails to
|
||||
# initialize. Horay! But will it stay like this? Let's be
|
||||
# cautious and raise the exception on our own to work in both
|
||||
# cases
|
||||
initialized = Gtk.init_check(None)[0]
|
||||
if not initialized:
|
||||
raise RuntimeError()
|
||||
# XXX: Gtk stopped raising RuntimeError if it fails to
|
||||
# initialize. Horay! But will it stay like this? Let's be
|
||||
# cautious and raise the exception on our own to work in both
|
||||
# cases
|
||||
initialized = Gtk.init_check(None)[0]
|
||||
if not initialized:
|
||||
raise RuntimeError()
|
||||
|
||||
# Attempt to grab the GUI initializing lock, do not block
|
||||
if not self._gui_lock.acquire(False):
|
||||
# the graphical interface is running, don't crash it by
|
||||
# running another one potentially from a different thread
|
||||
log.debug("Gtk running, queuing exception handler to the "
|
||||
"main loop")
|
||||
GLib.idle_add(self.run_handleException, dump_info)
|
||||
else:
|
||||
log.debug("Gtk not running, starting Gtk and running "
|
||||
"exception handler in it")
|
||||
super(AnacondaExceptionHandler, self).handleException(
|
||||
dump_info)
|
||||
|
||||
except (RuntimeError, ImportError):
|
||||
log.debug("Gtk cannot be initialized")
|
||||
# X not running (Gtk cannot be initialized)
|
||||
if threadMgr.in_main_thread():
|
||||
log.debug("In the main thread, running exception handler")
|
||||
if (issubclass (ty, CmdlineError)):
|
||||
# Attempt to grab the GUI initializing lock, do not block
|
||||
if not self._gui_lock.acquire(False):
|
||||
# the graphical interface is running, don't crash it by
|
||||
# running another one potentially from a different thread
|
||||
log.debug("Gtk running, queuing exception handler to the "
|
||||
"main loop")
|
||||
GLib.idle_add(self._main_loop_handleException, dump_info)
|
||||
else:
|
||||
log.debug("Gtk not running, starting Gtk and running "
|
||||
"exception handler in it")
|
||||
self._main_loop_handleException(dump_info)
|
||||
|
||||
except (RuntimeError, ImportError):
|
||||
log.debug("Gtk cannot be initialized")
|
||||
# X not running (Gtk cannot be initialized)
|
||||
if threadMgr.in_main_thread():
|
||||
log.debug("In the main thread, running exception handler")
|
||||
if issubclass(ty, CmdlineError) or not self._interactive:
|
||||
if issubclass(ty, CmdlineError):
|
||||
cmdline_error_msg = _("\nThe installation was stopped due to "
|
||||
"incomplete spokes detected while running "
|
||||
"in non-interactive cmdline mode. Since there "
|
||||
"can not be any questions in cmdline mode, "
|
||||
"cannot be any questions in cmdline mode, "
|
||||
"edit your kickstart file and retry "
|
||||
"installation.\nThe exact error message is: "
|
||||
"\n\n%s.\n\nThe installer will now terminate.") % str(value)
|
||||
|
||||
# since there is no UI in cmdline mode and it is completely
|
||||
# non-interactive, we can't show a message window asking the user
|
||||
# to acknowledge the error; instead, print the error out and sleep
|
||||
# for a few seconds before exiting the installer
|
||||
print(cmdline_error_msg)
|
||||
time.sleep(10)
|
||||
sys.exit(0)
|
||||
else:
|
||||
print("\nAn unknown error has occured, look at the "
|
||||
"/tmp/anaconda-tb* file(s) for more details")
|
||||
# in the main thread, run exception handler
|
||||
super(AnacondaExceptionHandler, self).handleException(
|
||||
dump_info)
|
||||
cmdline_error_msg = _("\nRunning in cmdline mode, no interactive debugging "
|
||||
"allowed.\nThe exact error message is: "
|
||||
"\n\n%s.\n\nThe installer will now terminate.") % str(value)
|
||||
|
||||
# since there is no UI in cmdline mode and it is completely
|
||||
# non-interactive, we can't show a message window asking the user
|
||||
# to acknowledge the error; instead, print the error out and sleep
|
||||
# for a few seconds before exiting the installer
|
||||
print(cmdline_error_msg)
|
||||
time.sleep(10)
|
||||
sys.exit(1)
|
||||
else:
|
||||
log.debug("In a non-main thread, sending a message with "
|
||||
"exception data")
|
||||
# not in the main thread, just send message with exception
|
||||
# data and let message handler run the exception handler in
|
||||
# the main thread
|
||||
exc_info = dump_info.exc_info
|
||||
hubQ.send_exception((exc_info.type,
|
||||
exc_info.value,
|
||||
exc_info.stack))
|
||||
print("\nAn unknown error has occured, look at the "
|
||||
"/tmp/anaconda-tb* file(s) for more details")
|
||||
# in the main thread, run exception handler
|
||||
self._main_loop_handleException(dump_info)
|
||||
else:
|
||||
log.debug("In a non-main thread, sending a message with "
|
||||
"exception data")
|
||||
# not in the main thread, just send message with exception
|
||||
# data and let message handler run the exception handler in
|
||||
# the main thread
|
||||
exc_info = dump_info.exc_info
|
||||
hubQ.send_exception((exc_info.type,
|
||||
exc_info.value,
|
||||
exc_info.stack))
|
||||
|
||||
def postWriteHook(self, dump_info):
|
||||
anaconda = dump_info.object
|
||||
@ -181,19 +186,13 @@ class AnacondaExceptionHandler(ExceptionHandler):
|
||||
except:
|
||||
pass
|
||||
|
||||
iutil.ipmi_report(IPMI_FAILED)
|
||||
|
||||
def runDebug(self, exc_info):
|
||||
if flags.can_touch_runtime_system("switch console") \
|
||||
and self._intf_tty_num != 1:
|
||||
iutil.vtActivate(1)
|
||||
|
||||
pidfl = "/tmp/vncshell.pid"
|
||||
if os.path.exists(pidfl) and os.path.isfile(pidfl):
|
||||
pf = open(pidfl, "r")
|
||||
for pid in pf.readlines():
|
||||
if not int(pid) == os.getpid():
|
||||
os.kill(int(pid), signal.SIGKILL)
|
||||
pf.close()
|
||||
|
||||
iutil.eintr_retry_call(os.open, "/dev/console", os.O_RDWR) # reclaim stdin
|
||||
iutil.eintr_retry_call(os.dup2, 0, 1) # reclaim stdout
|
||||
iutil.eintr_retry_call(os.dup2, 0, 2) # reclaim stderr
|
||||
@ -266,9 +265,10 @@ def initExceptionHandling(anaconda):
|
||||
# anaconda-tb file
|
||||
conf.register_callback("journalctl", journalctl_callback, attchmnt_only=False)
|
||||
|
||||
interactive = not anaconda.displayMode == 'c'
|
||||
handler = AnacondaExceptionHandler(conf, anaconda.intf.meh_interface,
|
||||
ReverseExceptionDump, anaconda.intf.tty_num,
|
||||
anaconda.gui_initialized)
|
||||
anaconda.gui_initialized, interactive)
|
||||
handler.install(anaconda)
|
||||
|
||||
return conf
|
||||
|
@ -65,11 +65,12 @@ class Flags(object):
|
||||
self.gpt = False
|
||||
self.leavebootorder = False
|
||||
self.testing = False
|
||||
self.dnf = False
|
||||
self.dnf = True
|
||||
self.mpathFriendlyNames = True
|
||||
# ksprompt is whether or not to prompt for missing ksdata
|
||||
self.ksprompt = True
|
||||
self.rescue_mode = False
|
||||
self.noefi = False
|
||||
# parse the boot commandline
|
||||
self.cmdline = BootArgs()
|
||||
# Lock it down: no more creating new flags!
|
||||
@ -79,7 +80,7 @@ class Flags(object):
|
||||
|
||||
def read_cmdline(self):
|
||||
for f in ("selinux", "debug", "leavebootorder", "testing", "extlinux",
|
||||
"nombr", "gpt", "dnf"):
|
||||
"nombr", "gpt", "dnf", "noefi"):
|
||||
self.set_cmdline_bool(f)
|
||||
|
||||
if not selinux.is_selinux_enabled():
|
||||
|
@ -99,10 +99,8 @@ in a couple seconds
|
||||
* cell tower geolocation
|
||||
|
||||
"""
|
||||
|
||||
import requests
|
||||
import urllib
|
||||
import urllib2
|
||||
import json
|
||||
import dbus
|
||||
import threading
|
||||
import time
|
||||
@ -525,10 +523,9 @@ class FedoraGeoIPProvider(GeolocationBackend):
|
||||
|
||||
def _refresh(self):
|
||||
try:
|
||||
reply = urllib2.urlopen(self.API_URL, timeout=
|
||||
constants.NETWORK_CONNECTION_TIMEOUT)
|
||||
if reply:
|
||||
json_reply = json.load(reply)
|
||||
reply = requests.get(self.API_URL, timeout=constants.NETWORK_CONNECTION_TIMEOUT, verify=True)
|
||||
if reply.status_code == requests.codes.ok:
|
||||
json_reply = reply.json()
|
||||
territory = json_reply.get("country_code", None)
|
||||
timezone_source = "GeoIP"
|
||||
timezone_code = json_reply.get("time_zone", None)
|
||||
@ -549,10 +546,10 @@ class FedoraGeoIPProvider(GeolocationBackend):
|
||||
territory_code=territory,
|
||||
timezone=timezone_code,
|
||||
timezone_source=timezone_source))
|
||||
except urllib2.HTTPError as e:
|
||||
log.debug("Geoloc: HTTPError for Fedora GeoIP API lookup:\n%s", e)
|
||||
except urllib2.URLError as e:
|
||||
log.debug("Geoloc: URLError for Fedora GeoIP API lookup:\n%s", e)
|
||||
else:
|
||||
log.error("Geoloc: Fedora GeoIP API lookup failed with status code: %s", reply.status_code)
|
||||
except requests.exceptions.RequestException as e:
|
||||
log.debug("Geoloc: RequestException for Fedora GeoIP API lookup:\n%s", e)
|
||||
except ValueError as e:
|
||||
log.debug("Geoloc: Unable to decode GeoIP JSON:\n%s", e)
|
||||
|
||||
@ -570,10 +567,9 @@ class HostipGeoIPProvider(GeolocationBackend):
|
||||
|
||||
def _refresh(self):
|
||||
try:
|
||||
reply = urllib2.urlopen(self.API_URL, timeout=
|
||||
constants.NETWORK_CONNECTION_TIMEOUT)
|
||||
if reply:
|
||||
reply_dict = json.load(reply)
|
||||
reply = requests.get(self.API_URL, timeout=constants.NETWORK_CONNECTION_TIMEOUT, verify=True)
|
||||
if reply.status_code == requests.codes.ok:
|
||||
reply_dict = reply.json()
|
||||
territory = reply_dict.get("country_code", None)
|
||||
|
||||
# unless at least country_code is available,
|
||||
@ -584,8 +580,13 @@ class HostipGeoIPProvider(GeolocationBackend):
|
||||
public_ip_address=reply_dict.get("ip", None),
|
||||
city=reply_dict.get("city", None)
|
||||
))
|
||||
except urllib2.URLError as e:
|
||||
log.debug("Geoloc: URLError during Hostip lookup:\n%s", e)
|
||||
else:
|
||||
log.error("Geoloc: Hostip lookup failed with status code: %s", reply.status_code)
|
||||
except requests.exceptions.RequestException as e:
|
||||
log.debug("Geoloc: RequestException during Hostip lookup:\n%s", e)
|
||||
except ValueError as e:
|
||||
log.debug("Geoloc: Unable to decode Hostip JSON:\n%s", e)
|
||||
|
||||
|
||||
|
||||
class GoogleWiFiLocationProvider(GeolocationBackend):
|
||||
@ -607,9 +608,8 @@ class GoogleWiFiLocationProvider(GeolocationBackend):
|
||||
if access_points:
|
||||
try:
|
||||
url = self._get_url(access_points)
|
||||
reply = urllib2.urlopen(url, timeout=
|
||||
constants.NETWORK_CONNECTION_TIMEOUT)
|
||||
result_dict = json.load(reply)
|
||||
reply = requests.get(url, timeout=constants.NETWORK_CONNECTION_TIMEOUT, verify=True)
|
||||
result_dict = reply.json()
|
||||
status = result_dict.get('status', 'NOT OK')
|
||||
if status == 'OK':
|
||||
lat = result_dict['location']['lat']
|
||||
@ -623,12 +623,13 @@ class GoogleWiFiLocationProvider(GeolocationBackend):
|
||||
t_code = geocoding_result.territory_code
|
||||
self._set_result(LocationResult(territory_code=t_code))
|
||||
else:
|
||||
log.info("Service couldn't find current location.")
|
||||
except urllib2.URLError as e:
|
||||
log.debug("Geoloc: URLError during Google"
|
||||
" Wifi lookup:\n%s", e)
|
||||
log.info("Geoloc: Service couldn't find current location.")
|
||||
except requests.exceptions.RequestException as e:
|
||||
log.debug("Geoloc: RequestException during Google Wifi lookup:\n%s", e)
|
||||
except ValueError as e:
|
||||
log.debug("Geoloc: Unable to decode Google Wifi JSON:\n%s", e)
|
||||
else:
|
||||
log.info("No WiFi access points found - can't detect location.")
|
||||
log.info("Geoloc: No WiFi access points found - can't detect location.")
|
||||
|
||||
def _get_url(self, access_points):
|
||||
"""Generate Google API URL for the given access points
|
||||
@ -697,18 +698,19 @@ class Geocoder(object):
|
||||
coordinates.latitude,
|
||||
coordinates.longitude)
|
||||
try:
|
||||
reply = urllib2.urlopen(url, timeout=
|
||||
constants.NETWORK_CONNECTION_TIMEOUT)
|
||||
if reply:
|
||||
reply_dict = json.load(reply)
|
||||
reply = requests.get(url, timeout=constants.NETWORK_CONNECTION_TIMEOUT, verify=True)
|
||||
if reply.status_code == requests.codes.ok:
|
||||
reply_dict = reply.json()
|
||||
territory_code = reply_dict['address']['country_code'].upper()
|
||||
return GeocodingResult(coordinates=coordinates,
|
||||
territory_code=territory_code)
|
||||
else:
|
||||
log.error("Geoloc: Nominatim reverse geocoding failed with status code: %s", reply.status_code)
|
||||
return None
|
||||
except urllib2.URLError as e:
|
||||
log.debug("Geoloc: URLError during Nominatim reverse geocoding"
|
||||
" :\n%s", e)
|
||||
except requests.exceptions.RequestException as e:
|
||||
log.debug("Geoloc: RequestException during Nominatim reverse geocoding:\n%s", e)
|
||||
except ValueError as e:
|
||||
log.debug("Geoloc: Unable to decode Nominatim reverse geocoding JSON:\n%s", e)
|
||||
|
||||
|
||||
class GeocodingResult(object):
|
||||
|
@ -23,9 +23,9 @@ __all__ = ["_", "N_", "P_", "C_", "CN_", "CP_"]
|
||||
|
||||
import gettext
|
||||
|
||||
_ = lambda x: gettext.ldgettext("anaconda", x) if x else ""
|
||||
_ = lambda x: gettext.translation("anaconda", fallback=True).ugettext(x) if x != "" else u""
|
||||
N_ = lambda x: x
|
||||
P_ = lambda x, y, z: gettext.ldngettext("anaconda", x, y, z)
|
||||
P_ = lambda x, y, z: gettext.translation("anaconda", fallback=True).ungettext(x, y, z)
|
||||
|
||||
# This is equivalent to "pgettext" in GNU gettext. The pgettext functions
|
||||
# are not exported by Python, but all they really do is a stick a EOT
|
||||
|
@ -21,11 +21,11 @@
|
||||
Anaconda built-in help module
|
||||
"""
|
||||
import os
|
||||
import subprocess
|
||||
|
||||
from pyanaconda.flags import flags
|
||||
from pyanaconda.localization import find_best_locale_match
|
||||
from pyanaconda.constants import DEFAULT_LANG
|
||||
from pyanaconda.iutil import startProgram
|
||||
|
||||
import logging
|
||||
log = logging.getLogger("anaconda")
|
||||
@ -124,7 +124,7 @@ def start_yelp(help_path):
|
||||
# under some extreme circumstances (placeholders missing)
|
||||
# the help path can be None and we need to prevent Popen
|
||||
# receiving None as an argument instead of a string
|
||||
yelp_process = subprocess.Popen(["yelp", help_path or ""])
|
||||
yelp_process = startProgram(["yelp", help_path or ""], reset_lang=False)
|
||||
|
||||
def kill_yelp():
|
||||
"""Try to kill any existing yelp processes"""
|
||||
|
@ -1,46 +0,0 @@
|
||||
# indexed_dict.py
|
||||
# Implements IndexedDictionary class.
|
||||
#
|
||||
# Copyright (C) 2009 Red Hat, Inc.
|
||||
#
|
||||
# This copyrighted material is made available to anyone wishing to use,
|
||||
# modify, copy, or redistribute it subject to the terms and conditions of
|
||||
# the GNU General Public License v.2, or (at your option) any later version.
|
||||
# This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
# ANY WARRANTY expressed or implied, including the implied warranties of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
|
||||
# Public License for more details. You should have received a copy of the
|
||||
# GNU General Public License along with this program; if not, write to the
|
||||
# Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
|
||||
# 02110-1301, USA. Any Red Hat trademarks that are incorporated in the
|
||||
# source code or documentation are not subject to the GNU General Public
|
||||
# License and may only be used or replicated with the express permission of
|
||||
# Red Hat, Inc.
|
||||
#
|
||||
|
||||
class IndexedDict(dict):
|
||||
""" Indexed dictionary that remembers order of the inserted elements.
|
||||
|
||||
Values can be inserted with string keys only, but referenced by both
|
||||
string keys or index.
|
||||
|
||||
There's a unit test for the class, please maintain it along.
|
||||
"""
|
||||
def __init__(self):
|
||||
super(IndexedDict, self).__init__()
|
||||
self._indexes = []
|
||||
|
||||
def __getitem__(self, key):
|
||||
if type(key) is int:
|
||||
key = self._indexes[key]
|
||||
return super(IndexedDict, self).__getitem__(key)
|
||||
|
||||
def __setitem__(self, key, value):
|
||||
if type(key) is int:
|
||||
raise TypeError("IndexedDict only accepts strings as new keys")
|
||||
assert(len(self) == len(self._indexes))
|
||||
self._indexes.append(key)
|
||||
return super(IndexedDict, self).__setitem__(key, value)
|
||||
|
||||
def index(self, string_key):
|
||||
return self._indexes.index(string_key)
|
@ -20,13 +20,16 @@
|
||||
# Red Hat Author(s): Chris Lumens <clumens@redhat.com>
|
||||
#
|
||||
|
||||
from blivet import turnOnFilesystems, callbacks
|
||||
from blivet import callbacks
|
||||
from blivet.osinstall import turnOnFilesystems
|
||||
from blivet.devices import BTRFSDevice
|
||||
from pyanaconda.bootloader import writeBootLoader
|
||||
from pyanaconda.progress import progress_report, progress_message, progress_step, progress_complete, progress_init
|
||||
from pyanaconda.users import createLuserConf, getPassAlgo, Users
|
||||
from pyanaconda import flags
|
||||
from pyanaconda import iutil
|
||||
from pyanaconda import timezone
|
||||
from pyanaconda import network
|
||||
from pyanaconda.i18n import _
|
||||
from pyanaconda.threads import threadMgr
|
||||
from pyanaconda.ui.lib.entropy import wait_for_entropy
|
||||
@ -97,12 +100,20 @@ def doConfiguration(storage, payload, ksdata, instClass):
|
||||
ksdata.rootpw.execute(storage, ksdata, instClass, u)
|
||||
ksdata.group.execute(storage, ksdata, instClass, u)
|
||||
ksdata.user.execute(storage, ksdata, instClass, u)
|
||||
ksdata.sshkey.execute(storage, ksdata, instClass, u)
|
||||
|
||||
with progress_report(_("Configuring addons")):
|
||||
ksdata.addons.execute(storage, ksdata, instClass, u)
|
||||
|
||||
with progress_report(_("Generating initramfs")):
|
||||
payload.recreateInitrds(force=True)
|
||||
payload.recreateInitrds()
|
||||
|
||||
# Work around rhbz#1200539, grubby doesn't handle grub2 missing initrd with /boot on btrfs
|
||||
# So rerun writing the bootloader if this is live and /boot is on btrfs
|
||||
boot_on_btrfs = isinstance(storage.mountpoints.get("/boot", storage.mountpoints.get("/")), BTRFSDevice)
|
||||
if flags.flags.livecdInstall and boot_on_btrfs \
|
||||
and (not ksdata.bootloader.disabled and ksdata.bootloader != "none"):
|
||||
writeBootLoader(storage, payload, instClass, ksdata)
|
||||
|
||||
if willRunRealmd:
|
||||
with progress_report(_("Joining realm: %s") % ksdata.realm.discovered):
|
||||
@ -117,17 +128,6 @@ def doConfiguration(storage, payload, ksdata, instClass):
|
||||
|
||||
progress_complete()
|
||||
|
||||
def moveBootMntToPhysical(storage):
|
||||
"""Move the /boot mount to /mnt/sysimage/boot."""
|
||||
if iutil.getSysroot() == iutil.getTargetPhysicalRoot():
|
||||
return
|
||||
bootmnt = storage.mountpoints.get('/boot')
|
||||
if bootmnt is None:
|
||||
return
|
||||
bootmnt.format.teardown()
|
||||
bootmnt.teardown()
|
||||
bootmnt.format.setup(options=bootmnt.format.options, chroot=iutil.getTargetPhysicalRoot())
|
||||
|
||||
def doInstall(storage, payload, ksdata, instClass):
|
||||
"""Perform an installation. This method takes the ksdata as prepared by
|
||||
the UI (the first hub, in graphical mode) and applies it to the disk.
|
||||
@ -147,6 +147,11 @@ def doInstall(storage, payload, ksdata, instClass):
|
||||
steps = len(storage.devicetree.findActions(action_type="create", object_type="format")) + \
|
||||
len(storage.devicetree.findActions(action_type="resize", object_type="format"))
|
||||
|
||||
# Update every 10% of packages installed. We don't know how many packages
|
||||
# we are installing until it's too late (see realmd later on) so this is
|
||||
# the best we can do.
|
||||
steps += 10
|
||||
|
||||
# pre setup phase, post install
|
||||
steps += 2
|
||||
|
||||
@ -190,9 +195,8 @@ def doInstall(storage, payload, ksdata, instClass):
|
||||
|
||||
turnOnFilesystems(storage, mountOnly=flags.flags.dirInstall, callbacks=callbacks_reg)
|
||||
write_storage_late = (flags.flags.livecdInstall or ksdata.ostreesetup.seen
|
||||
or ksdata.method.method == "liveimg"
|
||||
and not flags.flags.dirInstall)
|
||||
if not write_storage_late:
|
||||
or ksdata.method.method == "liveimg")
|
||||
if not write_storage_late and not flags.flags.dirInstall:
|
||||
storage.write()
|
||||
|
||||
# Do packaging.
|
||||
@ -207,6 +211,10 @@ def doInstall(storage, payload, ksdata, instClass):
|
||||
ksdata.authconfig.setup()
|
||||
ksdata.firewall.setup()
|
||||
|
||||
# make name resolution work for rpm scripts in chroot
|
||||
if flags.can_touch_runtime_system("copy /etc/resolv.conf to sysroot"):
|
||||
network.copyFileToPath("/etc/resolv.conf", iutil.getSysroot())
|
||||
|
||||
# anaconda requires storage packages in order to make sure the target
|
||||
# system is bootable and configurable, and some other packages in order
|
||||
# to finish setting up the system.
|
||||
@ -216,6 +224,9 @@ def doInstall(storage, payload, ksdata, instClass):
|
||||
if willInstallBootloader:
|
||||
packages += storage.bootloader.packages
|
||||
|
||||
if network.is_using_team_device():
|
||||
packages.append("teamd")
|
||||
|
||||
# don't try to install packages from the install class' ignored list and the
|
||||
# explicitly excluded ones (user takes the responsibility)
|
||||
packages = [p for p in packages
|
||||
@ -223,7 +234,7 @@ def doInstall(storage, payload, ksdata, instClass):
|
||||
payload.preInstall(packages=packages, groups=payload.languageGroups())
|
||||
payload.install()
|
||||
|
||||
if write_storage_late:
|
||||
if write_storage_late and not flags.flags.dirInstall:
|
||||
if iutil.getSysroot() != iutil.getTargetPhysicalRoot():
|
||||
blivet.setSysroot(iutil.getTargetPhysicalRoot(),
|
||||
iutil.getSysroot())
|
||||
@ -251,13 +262,10 @@ def doInstall(storage, payload, ksdata, instClass):
|
||||
|
||||
# Do bootloader.
|
||||
if willInstallBootloader:
|
||||
with progress_report(_("Installing bootloader")):
|
||||
with progress_report(_("Installing boot loader")):
|
||||
writeBootLoader(storage, payload, instClass, ksdata)
|
||||
|
||||
with progress_report(_("Performing post-installation setup tasks")):
|
||||
# Now, let's reset the state here so that the payload has
|
||||
# /boot in the system root.
|
||||
moveBootMntToPhysical(storage)
|
||||
payload.postInstall()
|
||||
|
||||
progress_complete()
|
||||
|
@ -26,7 +26,7 @@ import os, sys
|
||||
import imputil
|
||||
|
||||
from blivet.partspec import PartSpec
|
||||
from blivet.devicelibs import swap
|
||||
from blivet.autopart import swapSuggestion
|
||||
from blivet.platform import platform
|
||||
from blivet.size import Size
|
||||
|
||||
@ -37,7 +37,7 @@ from pyanaconda.kickstart import getAvailableDiskSpace
|
||||
|
||||
class BaseInstallClass(object):
|
||||
# default to not being hidden
|
||||
hidden = 0
|
||||
hidden = False
|
||||
name = "base"
|
||||
bootloaderTimeoutDefault = None
|
||||
bootloaderExtraArgs = []
|
||||
@ -58,15 +58,18 @@ class BaseInstallClass(object):
|
||||
# Blivet uses by default.
|
||||
defaultFS = None
|
||||
|
||||
# don't select this class by default
|
||||
default = 0
|
||||
|
||||
# help
|
||||
help_folder = "/usr/share/anaconda/help"
|
||||
help_main_page = "Installation_Guide.xml"
|
||||
help_placeholder = None
|
||||
help_placeholder_with_links = None
|
||||
|
||||
# path to the installclass stylesheet, if any
|
||||
stylesheet = None
|
||||
|
||||
# comps environment id to select by default
|
||||
defaultPackageEnvironment = None
|
||||
|
||||
@property
|
||||
def l10n_domain(self):
|
||||
if self._l10n_domain is None:
|
||||
@ -101,7 +104,7 @@ class BaseInstallClass(object):
|
||||
|
||||
|
||||
disk_space = getAvailableDiskSpace(storage)
|
||||
swp = swap.swapSuggestion(disk_space=disk_space)
|
||||
swp = swapSuggestion(disk_space=disk_space)
|
||||
autorequests.append(PartSpec(fstype="swap", size=swp, grow=False,
|
||||
lv=True, encrypted=True))
|
||||
|
||||
@ -128,8 +131,8 @@ class BaseInstallClass(object):
|
||||
allClasses = []
|
||||
allClasses_hidden = []
|
||||
|
||||
# returns ( className, classObject, classLogo ) tuples
|
||||
def availableClasses(showHidden=0):
|
||||
# returns ( className, classObject ) tuples
|
||||
def availableClasses(showHidden=False):
|
||||
global allClasses
|
||||
global allClasses_hidden
|
||||
|
||||
@ -194,7 +197,7 @@ def availableClasses(showHidden=0):
|
||||
try:
|
||||
found = imputil.imp.find_module(mainName)
|
||||
except ImportError:
|
||||
log.warning ("module import of %s failed: %s", mainName, sys.exc_type)
|
||||
log.warning ("module import of %s failed: %s", mainName, sys.exc_info()[0])
|
||||
continue
|
||||
|
||||
try:
|
||||
@ -204,10 +207,10 @@ def availableClasses(showHidden=0):
|
||||
# If it's got these two methods, it's an InstallClass.
|
||||
if hasattr(obj, "setDefaultPartitioning") and hasattr(obj, "setPackageSelection"):
|
||||
sortOrder = getattr(obj, "sortPriority", 0)
|
||||
if obj.hidden == 0 or showHidden == 1:
|
||||
if not obj.hidden or showHidden:
|
||||
lst.append(((obj.name, obj), sortOrder))
|
||||
except (ImportError, AttributeError):
|
||||
log.warning ("module import of %s failed: %s", mainName, sys.exc_type)
|
||||
log.warning ("module import of %s failed: %s", mainName, sys.exc_info()[0])
|
||||
|
||||
lst.sort(_ordering)
|
||||
for (item, _) in lst:
|
||||
@ -223,8 +226,8 @@ def availableClasses(showHidden=0):
|
||||
|
||||
def getBaseInstallClass():
|
||||
# figure out what installclass we should base on.
|
||||
allavail = availableClasses(showHidden = 1)
|
||||
avail = availableClasses(showHidden = 0)
|
||||
allavail = availableClasses(showHidden=True)
|
||||
avail = availableClasses(showHidden=False)
|
||||
|
||||
if len(avail) == 1:
|
||||
(cname, cobject) = avail[0]
|
||||
@ -240,8 +243,6 @@ def getBaseInstallClass():
|
||||
elif len(allavail) > 1:
|
||||
(cname, cobject) = allavail.pop()
|
||||
log.info('%s is the highest priority installclass, using it', cname)
|
||||
|
||||
# Default to the base installclass if nothing else is found.
|
||||
else:
|
||||
raise RuntimeError("Unable to find an install class to use!!!")
|
||||
|
||||
|
@ -33,7 +33,7 @@ _isys_la_SOURCES = isys.c
|
||||
auditddir = $(libexecdir)/$(PACKAGE_NAME)
|
||||
auditd_PROGRAMS = auditd
|
||||
auditd_SOURCES = auditd.c
|
||||
auditd_CFLAGS = -DSTANDALONE $(SELINUX_CFLAGS)
|
||||
auditd_LDADD = $(SELINUX_LIBS) $(LIBNL_LIBS)
|
||||
auditd_CFLAGS = $(SELINUX_CFLAGS)
|
||||
auditd_LDFLAGS = -laudit
|
||||
|
||||
MAINTAINERCLEANFILES = Makefile.in
|
||||
|
@ -29,18 +29,10 @@ except ImportError:
|
||||
# up PYTHONPATH and just do this basic import.
|
||||
import _isys
|
||||
|
||||
import os
|
||||
import os.path
|
||||
import socket
|
||||
import stat
|
||||
import sys
|
||||
from pyanaconda import iutil
|
||||
import blivet.arch
|
||||
import re
|
||||
import struct
|
||||
import dbus
|
||||
import time
|
||||
import datetime
|
||||
import pytz
|
||||
|
||||
import logging
|
||||
log = logging.getLogger("anaconda")
|
||||
@ -117,34 +109,39 @@ def set_system_time(secs):
|
||||
"""
|
||||
|
||||
_isys.set_system_time(secs)
|
||||
log.info("System time set to %s", time.ctime(secs))
|
||||
log.info("System time set to %s UTC", time.asctime(time.gmtime(secs)))
|
||||
|
||||
def set_system_date_time(year=None, month=None, day=None, hour=None, minute=None,
|
||||
second=None, utc=False):
|
||||
second=None, tz=None):
|
||||
"""
|
||||
Set system date and time given by the parameters as numbers. If some
|
||||
parameter is missing or None, the current system date/time field is used
|
||||
instead (i.e. the value is not changed by this function).
|
||||
|
||||
:type year, month, ..., second: int
|
||||
:param utc: wheter the other parameters specify UTC or local time
|
||||
:type utc: bool
|
||||
|
||||
"""
|
||||
|
||||
# get the right values
|
||||
local = 0 if utc else 1
|
||||
now = datetime.datetime.now()
|
||||
year = year or now.year
|
||||
month = month or now.month
|
||||
day = day or now.day
|
||||
hour = hour or now.hour
|
||||
minute = minute or now.minute
|
||||
second = second or now.second
|
||||
# If no timezone is set, use UTC
|
||||
if not tz:
|
||||
tz = pytz.UTC
|
||||
|
||||
# struct fields -> year, month, day, hour, minute, second, week_day, year_day, local
|
||||
time_struct = time.struct_time((year, month, day, hour, minute, second, 0, 0, local))
|
||||
set_system_time(int(time.mktime(time_struct)))
|
||||
# get the right values
|
||||
now = datetime.datetime.now(tz)
|
||||
year = year if year is not None else now.year
|
||||
month = month if month is not None else now.month
|
||||
day = day if day is not None else now.day
|
||||
hour = hour if hour is not None else now.hour
|
||||
minute = minute if minute is not None else now.minute
|
||||
second = second if second is not None else now.second
|
||||
|
||||
set_date = datetime.datetime(year, month, day, hour, minute, second, tzinfo=tz)
|
||||
|
||||
# Calculate the number of seconds between this time and timestamp 0
|
||||
epoch = datetime.datetime.fromtimestamp(0, pytz.UTC)
|
||||
timestamp = (set_date - epoch).total_seconds()
|
||||
|
||||
set_system_time(timestamp)
|
||||
|
||||
def total_memory():
|
||||
"""Returns total system memory in kB (given to us by /proc/meminfo)"""
|
||||
@ -180,4 +177,4 @@ def total_memory():
|
||||
log.error("MemTotal: line not found in /proc/meminfo")
|
||||
raise RuntimeError("MemTotal: line not found in /proc/meminfo")
|
||||
|
||||
handleSegv = _isys.handleSegv
|
||||
installSyncSignalHandlers = _isys.installSyncSignalHandlers
|
||||
|
@ -38,7 +38,6 @@
|
||||
|
||||
#include "auditd.h"
|
||||
|
||||
#ifdef USESELINUX
|
||||
static int done;
|
||||
|
||||
static void sig_done(int sig)
|
||||
@ -92,43 +91,38 @@ static void do_auditd(int fd) {
|
||||
}
|
||||
return;
|
||||
}
|
||||
#endif /* USESELINUX */
|
||||
|
||||
int audit_daemonize(void) {
|
||||
#ifdef USESELINUX
|
||||
int fd;
|
||||
pid_t child;
|
||||
|
||||
/* I guess we should actually do something with the output of AC_FUNC_FORK */
|
||||
#ifndef HAVE_WORKING_FORK
|
||||
#error "Autoconf could not find a working fork. Please fix this."
|
||||
#endif
|
||||
|
||||
if ((child = fork()) > 0)
|
||||
return 0;
|
||||
|
||||
if (child < 0)
|
||||
return -1;
|
||||
|
||||
#ifndef STANDALONE
|
||||
for (fd = 0; fd < getdtablesize(); fd++)
|
||||
close(fd);
|
||||
signal(SIGTTOU, SIG_IGN);
|
||||
signal(SIGTTIN, SIG_IGN);
|
||||
signal(SIGTSTP, SIG_IGN);
|
||||
#endif /* !defined(STANDALONE) */
|
||||
/* Close stdin and friends */
|
||||
close(STDIN_FILENO);
|
||||
close(STDOUT_FILENO);
|
||||
close(STDERR_FILENO);
|
||||
|
||||
if ((fd = open("/proc/self/oom_adj", O_RDWR)) >= 0) {
|
||||
write(fd, "-17", 3);
|
||||
if ((fd = open("/proc/self/oom_score_adj", O_RDWR)) >= 0) {
|
||||
write(fd, "-1000", 5);
|
||||
close(fd);
|
||||
}
|
||||
fd = audit_open();
|
||||
do_auditd(fd);
|
||||
audit_close(fd);
|
||||
|
||||
#ifndef STANDALONE
|
||||
exit(0);
|
||||
#endif /* !defined(STANDALONE) */
|
||||
|
||||
#endif /* USESELINUX */
|
||||
return 0;
|
||||
}
|
||||
|
||||
#ifdef STANDALONE
|
||||
int main(void) {
|
||||
if (audit_daemonize() < 0)
|
||||
{
|
||||
@ -138,7 +132,6 @@ int main(void) {
|
||||
|
||||
return 0;
|
||||
}
|
||||
#endif /* STANDALONE */
|
||||
|
||||
/*
|
||||
* vim:ts=8:sw=4:sts=4:et
|
||||
|
@ -28,14 +28,15 @@
|
||||
#include <signal.h>
|
||||
#include <execinfo.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
static PyObject * doSync(PyObject * s, PyObject * args);
|
||||
static PyObject * doSegvHandler(PyObject *s, PyObject *args);
|
||||
static PyObject * doSignalHandlers(PyObject *s, PyObject *args);
|
||||
static PyObject * doSetSystemTime(PyObject *s, PyObject *args);
|
||||
|
||||
static PyMethodDef isysModuleMethods[] = {
|
||||
{ "sync", (PyCFunction) doSync, METH_VARARGS, NULL},
|
||||
{ "handleSegv", (PyCFunction) doSegvHandler, METH_VARARGS, NULL },
|
||||
{ "sync", (PyCFunction) doSync, METH_NOARGS, NULL},
|
||||
{ "installSyncSignalHandlers", (PyCFunction) doSignalHandlers, METH_NOARGS, NULL},
|
||||
{ "set_system_time", (PyCFunction) doSetSystemTime, METH_VARARGS, NULL},
|
||||
{ NULL, NULL, 0, NULL }
|
||||
} ;
|
||||
@ -46,27 +47,22 @@ void init_isys(void) {
|
||||
}
|
||||
|
||||
static PyObject * doSync(PyObject * s, PyObject * args) {
|
||||
int fd;
|
||||
|
||||
if (!PyArg_ParseTuple(args, "", &fd)) return NULL;
|
||||
sync();
|
||||
|
||||
Py_INCREF(Py_None);
|
||||
return Py_None;
|
||||
}
|
||||
|
||||
static PyObject * doSegvHandler(PyObject *s, PyObject *args) {
|
||||
static void sync_signal_handler(int signum) {
|
||||
void *array[20];
|
||||
size_t size;
|
||||
char **strings;
|
||||
size_t i;
|
||||
|
||||
signal(SIGSEGV, SIG_DFL); /* back to default */
|
||||
|
||||
size = backtrace (array, 20);
|
||||
strings = backtrace_symbols (array, size);
|
||||
|
||||
printf ("Anaconda received SIGSEGV!. Backtrace:\n");
|
||||
printf ("Anaconda received signal %d!. Backtrace:\n", signum);
|
||||
for (i = 0; i < size; i++)
|
||||
printf ("%s\n", strings[i]);
|
||||
|
||||
@ -74,6 +70,43 @@ static PyObject * doSegvHandler(PyObject *s, PyObject *args) {
|
||||
exit(1);
|
||||
}
|
||||
|
||||
static PyObject * doSignalHandlers(PyObject *s, PyObject *args) {
|
||||
/* Install a signal handler for all synchronous signals */
|
||||
struct sigaction sa;
|
||||
|
||||
memset(&sa, 0, sizeof(struct sigaction));
|
||||
sa.sa_handler = sync_signal_handler;
|
||||
|
||||
/* Use these flags to ensure that a crash within the signal handler will
|
||||
* just crash anaconda and not get stuck in a loop. RESETHAND resets the
|
||||
* handler to SIG_DFL when the handler is entered, so that further signals
|
||||
* will exit the program, and NODEFER ensures that the signal is not blocked
|
||||
* during the signal handler, so a SIGSEGV triggered by handling a SIGSEGV will
|
||||
* be processed and will use the default handler. The Linux kernel forces
|
||||
* both of these things during a signal handler crash, but this makes it
|
||||
* explicit.
|
||||
*
|
||||
* These flags also mean that a SIGSEGV from a second thread could abort
|
||||
* the processing of a SIGSEGV from a first, but too bad.
|
||||
*/
|
||||
sa.sa_flags = SA_RESETHAND | SA_NODEFER;
|
||||
|
||||
if (sigaction(SIGILL, &sa, NULL) != 0) {
|
||||
return PyErr_SetFromErrno(PyExc_SystemError);
|
||||
}
|
||||
|
||||
if (sigaction(SIGFPE, &sa, NULL) != 0) {
|
||||
return PyErr_SetFromErrno(PyExc_SystemError);
|
||||
}
|
||||
|
||||
if (sigaction(SIGSEGV, &sa, NULL) != 0) {
|
||||
return PyErr_SetFromErrno(PyExc_SystemError);
|
||||
}
|
||||
|
||||
Py_INCREF(Py_None);
|
||||
return Py_None;
|
||||
}
|
||||
|
||||
static PyObject * doSetSystemTime(PyObject *s, PyObject *args) {
|
||||
struct timeval tv;
|
||||
tv.tv_usec = 0;
|
||||
@ -82,7 +115,7 @@ static PyObject * doSetSystemTime(PyObject *s, PyObject *args) {
|
||||
return NULL;
|
||||
|
||||
if (settimeofday(&tv, NULL) != 0)
|
||||
PyErr_SetFromErrno(PyExc_SystemError);
|
||||
return PyErr_SetFromErrno(PyExc_SystemError);
|
||||
|
||||
Py_INCREF(Py_None);
|
||||
return Py_None;
|
||||
|
@ -1,7 +1,7 @@
|
||||
#
|
||||
# iutil.py - generic install utility functions
|
||||
#
|
||||
# Copyright (C) 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007
|
||||
# Copyright (C) 1999-2014
|
||||
# Red Hat, Inc. All rights reserved.
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or modify
|
||||
@ -27,12 +27,16 @@ import os.path
|
||||
import errno
|
||||
import subprocess
|
||||
import unicodedata
|
||||
import string
|
||||
# Used for ascii_lowercase, ascii_uppercase constants
|
||||
import string # pylint: disable=deprecated-module
|
||||
import tempfile
|
||||
import types
|
||||
import re
|
||||
from threading import Thread
|
||||
from Queue import Queue, Empty
|
||||
from urllib import quote, unquote
|
||||
import gettext
|
||||
import signal
|
||||
|
||||
from gi.repository import GLib
|
||||
|
||||
from pyanaconda.flags import flags
|
||||
from pyanaconda.constants import DRACUT_SHUTDOWN_EJECT, TRANSLATIONS_UPDATE_DIR, UNSUPPORTED_HW
|
||||
@ -46,11 +50,25 @@ program_log = logging.getLogger("program")
|
||||
|
||||
from pyanaconda.anaconda_log import program_log_lock
|
||||
|
||||
_child_env = {}
|
||||
|
||||
def setenv(name, value):
|
||||
""" Set an environment variable to be used by child processes.
|
||||
|
||||
This method does not modify os.environ for the running process, which
|
||||
is not thread-safe. If setenv has already been called for a particular
|
||||
variable name, the old value is overwritten.
|
||||
|
||||
:param str name: The name of the environment variable
|
||||
:param str value: The value of the environment variable
|
||||
"""
|
||||
|
||||
_child_env[name] = value
|
||||
|
||||
def augmentEnv():
|
||||
env = os.environ.copy()
|
||||
env.update({"LC_ALL": "C",
|
||||
"ANA_INSTALL_PATH": getSysroot()
|
||||
})
|
||||
env.update({"ANA_INSTALL_PATH": getSysroot()})
|
||||
env.update(_child_env)
|
||||
return env
|
||||
|
||||
_root_path = "/mnt/sysimage"
|
||||
@ -97,16 +115,26 @@ def setSysroot(path):
|
||||
global _sysroot
|
||||
_sysroot = path
|
||||
|
||||
def _run_program(argv, root='/', stdin=None, stdout=None, env_prune=None, log_output=True, binary_output=False):
|
||||
""" Run an external program, log the output and return it to the caller
|
||||
def startProgram(argv, root='/', stdin=None, stdout=subprocess.PIPE, stderr=subprocess.STDOUT,
|
||||
env_prune=None, env_add=None, reset_handlers=True, reset_lang=True, **kwargs):
|
||||
""" Start an external program and return the Popen object.
|
||||
|
||||
The root and reset_handlers arguments are handled by passing a
|
||||
preexec_fn argument to subprocess.Popen, but an additional preexec_fn
|
||||
can still be specified and will be run. The user preexec_fn will be run
|
||||
last.
|
||||
|
||||
:param argv: The command to run and argument
|
||||
:param root: The directory to chroot to before running command.
|
||||
:param stdin: The file object to read stdin from.
|
||||
:param stdout: Optional file object to write stdout and stderr to.
|
||||
:param env_prune: environment variable to remove before execution
|
||||
:param log_output: whether to log the output of command
|
||||
:param binary_output: whether to treat the output of command as binary data
|
||||
:return: The return code of the command and the output
|
||||
:param stdout: The file object to write stdout to.
|
||||
:param stderr: The file object to write stderr to.
|
||||
:param env_prune: environment variables to remove before execution
|
||||
:param env_add: environment variables to add before execution
|
||||
:param reset_handlers: whether to reset to SIG_DFL any signal handlers set to SIG_IGN
|
||||
:param reset_lang: whether to set the locale of the child process to C
|
||||
:param kwargs: Additional parameters to pass to subprocess.Popen
|
||||
:return: A Popen object for the running command.
|
||||
"""
|
||||
if env_prune is None:
|
||||
env_prune = []
|
||||
@ -117,45 +145,152 @@ def _run_program(argv, root='/', stdin=None, stdout=None, env_prune=None, log_ou
|
||||
if target_root == _root_path:
|
||||
target_root = getSysroot()
|
||||
|
||||
def chroot():
|
||||
# Check for and save a preexec_fn argument
|
||||
preexec_fn = kwargs.pop("preexec_fn", None)
|
||||
|
||||
def preexec():
|
||||
# If a target root was specificed, chroot into it
|
||||
if target_root and target_root != '/':
|
||||
os.chroot(target_root)
|
||||
os.chdir("/")
|
||||
|
||||
# Signal handlers set to SIG_IGN persist across exec. Reset
|
||||
# these to SIG_DFL if requested. In particular this will include the
|
||||
# SIGPIPE handler set by python.
|
||||
if reset_handlers:
|
||||
for signum in range(1, signal.NSIG):
|
||||
if signal.getsignal(signum) == signal.SIG_IGN:
|
||||
signal.signal(signum, signal.SIG_DFL)
|
||||
|
||||
# If the user specified an additional preexec_fn argument, run it
|
||||
if preexec_fn is not None:
|
||||
preexec_fn()
|
||||
|
||||
with program_log_lock:
|
||||
program_log.info("Running... %s", " ".join(argv))
|
||||
|
||||
env = augmentEnv()
|
||||
for var in env_prune:
|
||||
env.pop(var, None)
|
||||
env = augmentEnv()
|
||||
for var in env_prune:
|
||||
env.pop(var, None)
|
||||
|
||||
try:
|
||||
proc = subprocess.Popen(argv,
|
||||
stdin=stdin,
|
||||
stdout=subprocess.PIPE,
|
||||
stderr=subprocess.STDOUT,
|
||||
preexec_fn=chroot, cwd=root, env=env)
|
||||
if reset_lang:
|
||||
env.update({"LC_ALL": "C"})
|
||||
|
||||
output_string = proc.communicate()[0]
|
||||
if output_string:
|
||||
if binary_output:
|
||||
output_lines = [output_string]
|
||||
else:
|
||||
if output_string[-1] != "\n":
|
||||
output_string = output_string + "\n"
|
||||
output_lines = output_string.splitlines(True)
|
||||
if env_add:
|
||||
env.update(env_add)
|
||||
|
||||
for line in output_lines:
|
||||
if log_output:
|
||||
return subprocess.Popen(argv,
|
||||
stdin=stdin,
|
||||
stdout=stdout,
|
||||
stderr=stderr,
|
||||
close_fds=True,
|
||||
preexec_fn=preexec, cwd=root, env=env, **kwargs)
|
||||
|
||||
def startX(argv, output_redirect=None):
|
||||
""" Start X and return once X is ready to accept connections.
|
||||
|
||||
X11, if SIGUSR1 is set to SIG_IGN, will send SIGUSR1 to the parent
|
||||
process once it is ready to accept client connections. This method
|
||||
sets that up and waits for the signal or bombs out if nothing happens
|
||||
for a minute. The process will also be added to the list of watched
|
||||
processes.
|
||||
|
||||
:param argv: The command line to run, as a list
|
||||
:param output_redirect: file or file descriptor to redirect stdout and stderr to
|
||||
"""
|
||||
# Use a list so the value can be modified from the handler function
|
||||
x11_started = [False]
|
||||
def sigusr1_handler(num, frame):
|
||||
log.debug("X server has signalled a successful start.")
|
||||
x11_started[0] = True
|
||||
|
||||
# Fail after, let's say a minute, in case something weird happens
|
||||
# and we don't receive SIGUSR1
|
||||
def sigalrm_handler(num, frame):
|
||||
# Check that it didn't make it under the wire
|
||||
if x11_started[0]:
|
||||
return
|
||||
log.error("Timeout trying to start %s", argv[0])
|
||||
raise ExitError("Timeout trying to start %s" % argv[0])
|
||||
|
||||
# preexec_fn to add the SIGUSR1 handler in the child
|
||||
def sigusr1_preexec():
|
||||
signal.signal(signal.SIGUSR1, signal.SIG_IGN)
|
||||
|
||||
try:
|
||||
old_sigusr1_handler = signal.signal(signal.SIGUSR1, sigusr1_handler)
|
||||
old_sigalrm_handler = signal.signal(signal.SIGALRM, sigalrm_handler)
|
||||
|
||||
# Start the timer
|
||||
signal.alarm(60)
|
||||
|
||||
childproc = startProgram(argv, stdout=output_redirect, stderr=output_redirect,
|
||||
preexec_fn=sigusr1_preexec)
|
||||
watchProcess(childproc, argv[0])
|
||||
|
||||
# Wait for SIGUSR1
|
||||
while not x11_started[0]:
|
||||
signal.pause()
|
||||
|
||||
finally:
|
||||
# Put everything back where it was
|
||||
signal.alarm(0)
|
||||
signal.signal(signal.SIGUSR1, old_sigusr1_handler)
|
||||
signal.signal(signal.SIGALRM, old_sigalrm_handler)
|
||||
|
||||
def _run_program(argv, root='/', stdin=None, stdout=None, env_prune=None, log_output=True,
|
||||
binary_output=False, filter_stderr=False):
|
||||
""" Run an external program, log the output and return it to the caller
|
||||
:param argv: The command to run and argument
|
||||
:param root: The directory to chroot to before running command.
|
||||
:param stdin: The file object to read stdin from.
|
||||
:param stdout: Optional file object to write the output to.
|
||||
:param env_prune: environment variable to remove before execution
|
||||
:param log_output: whether to log the output of command
|
||||
:param binary_output: whether to treat the output of command as binary data
|
||||
:param filter_stderr: whether to exclude the contents of stderr from the returned output
|
||||
:return: The return code of the command and the output
|
||||
"""
|
||||
try:
|
||||
if filter_stderr:
|
||||
stderr = subprocess.PIPE
|
||||
else:
|
||||
stderr = subprocess.STDOUT
|
||||
|
||||
proc = startProgram(argv, root=root, stdin=stdin, stdout=subprocess.PIPE, stderr=stderr,
|
||||
env_prune=env_prune)
|
||||
|
||||
(output_string, err_string) = proc.communicate()
|
||||
if output_string:
|
||||
if binary_output:
|
||||
output_lines = [output_string]
|
||||
else:
|
||||
if output_string[-1] != "\n":
|
||||
output_string = output_string + "\n"
|
||||
output_lines = output_string.splitlines(True)
|
||||
|
||||
if log_output:
|
||||
with program_log_lock:
|
||||
for line in output_lines:
|
||||
program_log.info(line.strip())
|
||||
|
||||
if stdout:
|
||||
stdout.write(line)
|
||||
if stdout:
|
||||
stdout.write(output_string)
|
||||
|
||||
except OSError as e:
|
||||
# If stderr was filtered, log it separately
|
||||
if filter_stderr and err_string and log_output:
|
||||
err_lines = err_string.splitlines(True)
|
||||
|
||||
with program_log_lock:
|
||||
for line in err_lines:
|
||||
program_log.info(line.strip())
|
||||
|
||||
except OSError as e:
|
||||
with program_log_lock:
|
||||
program_log.error("Error running %s: %s", argv[0], e.strerror)
|
||||
raise
|
||||
raise
|
||||
|
||||
with program_log_lock:
|
||||
program_log.debug("Return code: %d", proc.returncode)
|
||||
|
||||
return (proc.returncode, output_string)
|
||||
@ -192,13 +327,14 @@ def execWithRedirect(command, argv, stdin=None, stdout=None,
|
||||
return _run_program(argv, stdin=stdin, stdout=stdout, root=root, env_prune=env_prune,
|
||||
log_output=log_output, binary_output=binary_output)[0]
|
||||
|
||||
def execWithCapture(command, argv, stdin=None, root='/', log_output=True):
|
||||
def execWithCapture(command, argv, stdin=None, root='/', log_output=True, filter_stderr=False):
|
||||
""" Run an external program and capture standard out and err.
|
||||
:param command: The command to run
|
||||
:param argv: The argument list
|
||||
:param stdin: The file object to read stdin from.
|
||||
:param root: The directory to chroot to before running command.
|
||||
:param log_output: Whether to log the output of command
|
||||
:param filter_stderr: Whether stderr should be excluded from the returned output
|
||||
:return: The output of the command
|
||||
"""
|
||||
if flags.testing:
|
||||
@ -207,12 +343,17 @@ def execWithCapture(command, argv, stdin=None, root='/', log_output=True):
|
||||
return ""
|
||||
|
||||
argv = [command] + argv
|
||||
return _run_program(argv, stdin=stdin, root=root, log_output=log_output)[1]
|
||||
return _run_program(argv, stdin=stdin, root=root, log_output=log_output,
|
||||
filter_stderr=filter_stderr)[1]
|
||||
|
||||
def execReadlines(command, argv, stdin=None, root='/', env_prune=None):
|
||||
""" Execute an external command and return the line output of the command
|
||||
in real-time.
|
||||
|
||||
This method assumes that there is a reasonably low delay between the
|
||||
end of output and the process exiting. If the child process closes
|
||||
stdout and then keeps on truckin' there will be problems.
|
||||
|
||||
:param command: The command to run
|
||||
:param argv: The argument list
|
||||
:param stdin: The file object to read stdin from.
|
||||
@ -222,66 +363,210 @@ def execReadlines(command, argv, stdin=None, root='/', env_prune=None):
|
||||
:param env_prune: environment variable to remove before execution
|
||||
|
||||
Output from the file is not logged to program.log
|
||||
This returns a generator with the lines from the command until it has finished
|
||||
This returns an iterator with the lines from the command until it has finished
|
||||
"""
|
||||
if env_prune is None:
|
||||
env_prune = []
|
||||
|
||||
# Return the lines from stdout via a Queue
|
||||
def queue_lines(out, queue):
|
||||
for line in iter(out.readline, b''):
|
||||
queue.put(line.strip())
|
||||
out.close()
|
||||
class ExecLineReader(object):
|
||||
"""Iterator class for returning lines from a process and cleaning
|
||||
up the process when the output is no longer needed.
|
||||
"""
|
||||
|
||||
def chroot():
|
||||
if root and root != '/':
|
||||
os.chroot(root)
|
||||
os.chdir("/")
|
||||
def __init__(self, proc, argv):
|
||||
self._proc = proc
|
||||
self._argv = argv
|
||||
|
||||
def __iter__(self):
|
||||
return self
|
||||
|
||||
def __del__(self):
|
||||
# See if the process is still running
|
||||
if self._proc.poll() is None:
|
||||
# Stop the process and ignore any problems that might arise
|
||||
try:
|
||||
self._proc.terminate()
|
||||
except OSError:
|
||||
pass
|
||||
|
||||
def next(self):
|
||||
# Read the next line, blocking if a line is not yet available
|
||||
line = self._proc.stdout.readline()
|
||||
if line == '':
|
||||
# Output finished, wait for the process to end
|
||||
self._proc.communicate()
|
||||
|
||||
# Check for successful exit
|
||||
if self._proc.returncode < 0:
|
||||
raise OSError("process '%s' was killed by signal %s" %
|
||||
(self._argv, -self._proc.returncode))
|
||||
elif self._proc.returncode > 0:
|
||||
raise OSError("process '%s' exited with status %s" %
|
||||
(self._argv, self._proc.returncode))
|
||||
raise StopIteration
|
||||
|
||||
return line.strip()
|
||||
|
||||
argv = [command] + argv
|
||||
with program_log_lock:
|
||||
program_log.info("Running... %s", " ".join(argv))
|
||||
|
||||
env = augmentEnv()
|
||||
for var in env_prune:
|
||||
env.pop(var, None)
|
||||
try:
|
||||
proc = subprocess.Popen(argv,
|
||||
stdin=stdin,
|
||||
stdout=subprocess.PIPE,
|
||||
stderr=subprocess.STDOUT,
|
||||
bufsize=1,
|
||||
preexec_fn=chroot, cwd=root, env=env)
|
||||
proc = startProgram(argv, root=root, stdin=stdin, env_prune=env_prune, bufsize=1)
|
||||
except OSError as e:
|
||||
program_log.error("Error running %s: %s", argv[0], e.strerror)
|
||||
with program_log_lock:
|
||||
program_log.error("Error running %s: %s", argv[0], e.strerror)
|
||||
raise
|
||||
|
||||
q = Queue()
|
||||
t = Thread(target=queue_lines, args=(proc.stdout, q))
|
||||
t.daemon = True # thread dies with the program
|
||||
t.start()
|
||||
|
||||
while True:
|
||||
try:
|
||||
line = q.get(timeout=.1)
|
||||
yield line
|
||||
q.task_done()
|
||||
except Empty:
|
||||
if proc.poll() is not None:
|
||||
if os.WIFSIGNALED(proc.returncode):
|
||||
raise OSError("process '%s' was killed" % argv)
|
||||
break
|
||||
q.join()
|
||||
|
||||
return ExecLineReader(proc, argv)
|
||||
|
||||
## Run a shell.
|
||||
def execConsole():
|
||||
try:
|
||||
proc = subprocess.Popen(["/bin/sh"])
|
||||
proc = startProgram(["/bin/sh"], stdout=None, stderr=None, reset_lang=False)
|
||||
proc.wait()
|
||||
except OSError as e:
|
||||
raise RuntimeError("Error running /bin/sh: " + e.strerror)
|
||||
|
||||
# Dictionary of processes to watch in the form {pid: [name, GLib event source id], ...}
|
||||
_forever_pids = {}
|
||||
# Set to True if process watching is handled by GLib
|
||||
_watch_process_glib = False
|
||||
_watch_process_handler_set = False
|
||||
|
||||
class ExitError(RuntimeError):
|
||||
pass
|
||||
|
||||
# Raise an error on process exit. The argument is a list of tuples
|
||||
# of the form [(name, status), ...] with statuses in the subprocess
|
||||
# format (>=0 is return codes, <0 is signal)
|
||||
def _raise_exit_error(statuses):
|
||||
exn_message = []
|
||||
|
||||
for proc_name, status in statuses:
|
||||
if status >= 0:
|
||||
status_str = "with status %s" % status
|
||||
else:
|
||||
status_str = "on signal %s" % -status
|
||||
|
||||
exn_message.append("%s exited %s" % (proc_name, status_str))
|
||||
|
||||
raise ExitError(", ".join(exn_message))
|
||||
|
||||
# Signal handler used with watchProcess
|
||||
def _sigchld_handler(num=None, frame=None):
|
||||
# Check whether anything in the list of processes being watched has
|
||||
# exited. We don't want to call waitpid(-1), since that would break
|
||||
# anything else using wait/waitpid (like the subprocess module).
|
||||
exited_pids = []
|
||||
exit_statuses = []
|
||||
|
||||
for child_pid in _forever_pids:
|
||||
try:
|
||||
pid_result, status = eintr_retry_call(os.waitpid, child_pid, os.WNOHANG)
|
||||
except OSError as e:
|
||||
if e.errno == errno.ECHILD:
|
||||
continue
|
||||
|
||||
if pid_result:
|
||||
proc_name = _forever_pids[child_pid][0]
|
||||
exited_pids.append(child_pid)
|
||||
|
||||
# Convert the wait-encoded status to the format used by subprocess
|
||||
if os.WIFEXITED(status):
|
||||
sub_status = os.WEXITSTATUS(status)
|
||||
else:
|
||||
# subprocess uses negative return codes to indicate signal exit
|
||||
sub_status = -os.WTERMSIG(status)
|
||||
|
||||
exit_statuses.append((proc_name, sub_status))
|
||||
|
||||
for child_pid in exited_pids:
|
||||
if _forever_pids[child_pid][1]:
|
||||
GLib.source_remove(_forever_pids[child_pid][1])
|
||||
del _forever_pids[child_pid]
|
||||
|
||||
if exit_statuses:
|
||||
_raise_exit_error(exit_statuses)
|
||||
|
||||
# GLib callback used with watchProcess
|
||||
def _watch_process_cb(pid, status, proc_name):
|
||||
# Convert the wait-encoded status to the format used by subprocess
|
||||
if os.WIFEXITED(status):
|
||||
sub_status = os.WEXITSTATUS(status)
|
||||
else:
|
||||
# subprocess uses negative return codes to indicate signal exit
|
||||
sub_status = -os.WTERMSIG(status)
|
||||
|
||||
_raise_exit_error([(proc_name, sub_status)])
|
||||
|
||||
def watchProcess(proc, name):
|
||||
"""Watch for a process exit, and raise a ExitError when it does.
|
||||
|
||||
This method installs a SIGCHLD signal handler and thus interferes
|
||||
the child_watch_add methods in GLib. Use watchProcessGLib to convert
|
||||
to GLib mode if using a GLib main loop.
|
||||
|
||||
Since the SIGCHLD handler calls wait() on the watched process, this call
|
||||
cannot be combined with Popen.wait() or Popen.communicate, and also
|
||||
doing so wouldn't make a whole lot of sense.
|
||||
|
||||
:param proc: The Popen object for the process
|
||||
:param name: The name of the process
|
||||
"""
|
||||
global _watch_process_handler_set
|
||||
|
||||
if not _watch_process_glib and not _watch_process_handler_set:
|
||||
signal.signal(signal.SIGCHLD, _sigchld_handler)
|
||||
_watch_process_handler_set = True
|
||||
|
||||
# Add the PID to the dictionary
|
||||
# The second item in the list is for the GLib event source id and will be
|
||||
# replaced with the id once we have one.
|
||||
_forever_pids[proc.pid] = [name, None]
|
||||
|
||||
# If GLib is watching processes, add a watcher. child_watch_add checks if
|
||||
# the process has already exited.
|
||||
if _watch_process_glib:
|
||||
_forever_pids[proc.id][1] = GLib.child_watch_add(proc.pid, _watch_process_cb, name)
|
||||
else:
|
||||
# Check that the process didn't already exit
|
||||
if proc.poll() is not None:
|
||||
del _forever_pids[proc.pid]
|
||||
_raise_exit_error([(name, proc.returncode)])
|
||||
|
||||
def watchProcessGLib():
|
||||
"""Convert process watching to GLib mode.
|
||||
|
||||
This allows anaconda modes that use GLib main loops to use
|
||||
GLib.child_watch_add and continue to watch processes started before the
|
||||
main loop.
|
||||
"""
|
||||
|
||||
global _watch_process_glib
|
||||
|
||||
# The first call to child_watch_add will replace our SIGCHLD handler, and
|
||||
# child_watch_add checks if the process has already exited before it returns,
|
||||
# which will handle processes that exit while we're in the loop.
|
||||
|
||||
_watch_process_glib = True
|
||||
for child_pid in _forever_pids:
|
||||
_forever_pids[child_pid][1] = GLib.child_watch_add(child_pid, _watch_process_cb,
|
||||
_forever_pids[child_pid])
|
||||
|
||||
def unwatchProcess(proc):
|
||||
"""Unwatch a process watched by watchProcess.
|
||||
|
||||
:param proc: The Popen object for the process.
|
||||
"""
|
||||
if _forever_pids[proc.pid][1]:
|
||||
GLib.source_remove(_forever_pids[proc.pid][1])
|
||||
del _forever_pids[proc.pid]
|
||||
|
||||
def unwatchAllProcesses():
|
||||
"""Clear the watched process list."""
|
||||
global _forever_pids
|
||||
for child_pid in _forever_pids:
|
||||
if _forever_pids[child_pid][1]:
|
||||
GLib.source_remove(_forever_pids[child_pid][1])
|
||||
_forever_pids = {}
|
||||
|
||||
def getDirSize(directory):
|
||||
""" Get the size of a directory and all its subdirectories.
|
||||
:param dir: The name of the directory to find the size of.
|
||||
@ -396,7 +681,7 @@ def parseNfsUrl(nfsurl):
|
||||
|
||||
return (options, host, path)
|
||||
|
||||
def add_po_path(module, directory):
|
||||
def add_po_path(directory):
|
||||
""" Looks to see what translations are under a given path and tells
|
||||
the gettext module to use that path as the base dir """
|
||||
for d in os.listdir(directory):
|
||||
@ -408,27 +693,12 @@ def add_po_path(module, directory):
|
||||
if not basename.endswith(".mo"):
|
||||
continue
|
||||
log.info("setting %s as translation source for %s", directory, basename[:-3])
|
||||
module.bindtextdomain(basename[:-3], directory)
|
||||
gettext.bindtextdomain(basename[:-3], directory)
|
||||
|
||||
def setup_translations(module):
|
||||
def setup_translations():
|
||||
if os.path.isdir(TRANSLATIONS_UPDATE_DIR):
|
||||
add_po_path(module, TRANSLATIONS_UPDATE_DIR)
|
||||
module.textdomain("anaconda")
|
||||
|
||||
def fork_orphan():
|
||||
"""Forks an orphan.
|
||||
|
||||
Returns 1 in the parent and 0 in the orphaned child.
|
||||
"""
|
||||
intermediate = os.fork()
|
||||
if not intermediate:
|
||||
if os.fork():
|
||||
# the intermediate child dies
|
||||
os._exit(0)
|
||||
return 0
|
||||
# the original process waits for the intermediate child
|
||||
eintr_retry_call(os.waitpid, intermediate, 0)
|
||||
return 1
|
||||
add_po_path(TRANSLATIONS_UPDATE_DIR)
|
||||
gettext.textdomain("anaconda")
|
||||
|
||||
def _run_systemctl(command, service):
|
||||
"""
|
||||
@ -756,9 +1026,9 @@ def is_unsupported_hw():
|
||||
:rtype: bool
|
||||
"""
|
||||
try:
|
||||
tainted = long(open("/proc/sys/kernel/tainted").read())
|
||||
tainted = int(open("/proc/sys/kernel/tainted").read())
|
||||
except (IOError, ValueError):
|
||||
tainted = 0L
|
||||
tainted = 0
|
||||
|
||||
status = bool(tainted & UNSUPPORTED_HW)
|
||||
if status:
|
||||
@ -888,6 +1158,25 @@ def xprogressive_delay():
|
||||
yield 0.25*(2**counter)
|
||||
counter += 1
|
||||
|
||||
def get_platform_groupid():
|
||||
""" Return a platform group id string
|
||||
|
||||
This runs systemd-detect-virt and if the result is not 'none' it
|
||||
prefixes the lower case result with "platform-" for use as a group id.
|
||||
|
||||
:returns: Empty string or a group id for the detected platform
|
||||
:rtype: str
|
||||
"""
|
||||
try:
|
||||
platform = execWithCapture("systemd-detect-virt", []).strip()
|
||||
except (IOError, AttributeError):
|
||||
return ""
|
||||
|
||||
if platform == "none":
|
||||
return ""
|
||||
|
||||
return "platform-" + platform.lower()
|
||||
|
||||
def persistent_root_image():
|
||||
""":returns: whether we are running from a persistent (not in RAM) root.img"""
|
||||
|
||||
@ -901,6 +1190,30 @@ def persistent_root_image():
|
||||
|
||||
return True
|
||||
|
||||
_supports_ipmi = None
|
||||
|
||||
def ipmi_report(event):
|
||||
global _supports_ipmi
|
||||
if _supports_ipmi is None:
|
||||
_supports_ipmi = os.path.exists("/dev/ipmi0") and os.path.exists("/usr/bin/ipmitool")
|
||||
|
||||
if not _supports_ipmi:
|
||||
return
|
||||
|
||||
(fd, path) = tempfile.mkstemp()
|
||||
|
||||
# EVM revision - always 0x4
|
||||
# Sensor type - always 0x1F for Base OS Boot/Installation Status
|
||||
# Sensor num - passed in event
|
||||
# Event dir & type - always 0x0 for anaconda's purposes
|
||||
# Event data 1, 2, 3 - 0x0 for now
|
||||
eintr_retry_call(os.write, fd, "0x4 0x1F %#x 0x0 0x0 0x0 0x0\n" % event)
|
||||
eintr_retry_call(os.close, fd)
|
||||
|
||||
execWithCapture("ipmitool", ["sel", "add", path])
|
||||
|
||||
os.remove(path)
|
||||
|
||||
# Copied from python's subprocess.py
|
||||
def eintr_retry_call(func, *args):
|
||||
"""Retry an interruptible system call if interrupted."""
|
||||
@ -911,3 +1224,7 @@ def eintr_retry_call(func, *args):
|
||||
if e.errno == errno.EINTR:
|
||||
continue
|
||||
raise
|
||||
|
||||
def parent_dir(directory):
|
||||
"""Return the parent's path"""
|
||||
return "/".join(os.path.normpath(directory).split("/")[:-1])
|
||||
|
@ -395,12 +395,7 @@ class LocaledWrapper(object):
|
||||
# if there are more layouts than variants, empty strings should be appended
|
||||
diff = len(layouts) - len(variants)
|
||||
variants.extend(diff * [""])
|
||||
|
||||
# if there are more variants than layouts, throw the trailing ones away
|
||||
variants = variants[:len(layouts)]
|
||||
|
||||
# map can be used with multiple lists and works like zipWith (Haskell)
|
||||
return map(join_layout_variant, layouts, variants)
|
||||
return [join_layout_variant(layout, variant) for layout, variant in zip(layouts, variants)]
|
||||
|
||||
@property
|
||||
def options(self):
|
||||
|
@ -21,15 +21,16 @@
|
||||
from pyanaconda.errors import ScriptError, errorHandler
|
||||
from blivet.deviceaction import ActionCreateFormat, ActionDestroyFormat, ActionResizeDevice, ActionResizeFormat
|
||||
from blivet.devices import LUKSDevice
|
||||
from blivet.devicelibs.lvm import getPossiblePhysicalExtents, LVM_PE_SIZE, KNOWN_THPOOL_PROFILES
|
||||
from blivet.devices.lvm import LVMVolumeGroupDevice
|
||||
from blivet.devicelibs.lvm import LVM_PE_SIZE, KNOWN_THPOOL_PROFILES
|
||||
from blivet.devicelibs.crypto import MIN_CREATE_ENTROPY
|
||||
from blivet.devicelibs import swap as swap_lib
|
||||
from blivet.formats import getFormat
|
||||
from blivet.partitioning import doPartitioning
|
||||
from blivet.partitioning import growLVM
|
||||
from blivet.errors import PartitioningError
|
||||
from blivet.size import Size
|
||||
from blivet.errors import PartitioningError, StorageError, BTRFSValueError
|
||||
from blivet.size import Size, KiB
|
||||
from blivet import udev
|
||||
from blivet import autopart
|
||||
from blivet.platform import platform
|
||||
import blivet.iscsi
|
||||
import blivet.fcoe
|
||||
@ -41,9 +42,8 @@ from pyanaconda import iutil
|
||||
import os
|
||||
import os.path
|
||||
import tempfile
|
||||
import subprocess
|
||||
from pyanaconda.flags import flags, can_touch_runtime_system
|
||||
from pyanaconda.constants import ADDON_PATHS
|
||||
from pyanaconda.constants import ADDON_PATHS, IPMI_ABORTED
|
||||
import shlex
|
||||
import sys
|
||||
import urlgrabber
|
||||
@ -62,12 +62,15 @@ from pyanaconda.i18n import _
|
||||
from pyanaconda.ui.common import collect
|
||||
from pyanaconda.addons import AddonSection, AddonData, AddonRegistry, collect_addon_paths
|
||||
from pyanaconda.bootloader import GRUB2, get_bootloader
|
||||
from pyanaconda.pwpolicy import F22_PwPolicy, F22_PwPolicyData
|
||||
|
||||
from pykickstart.constants import CLEARPART_TYPE_NONE, FIRSTBOOT_SKIP, FIRSTBOOT_RECONFIG, KS_SCRIPT_POST, KS_SCRIPT_PRE, \
|
||||
KS_SCRIPT_TRACEBACK, SELINUX_DISABLED, SELINUX_ENFORCING, SELINUX_PERMISSIVE
|
||||
from pykickstart.base import BaseHandler
|
||||
from pykickstart.errors import formatErrorMsg, KickstartError, KickstartValueError
|
||||
from pykickstart.parser import KickstartParser
|
||||
from pykickstart.parser import Script as KSScript
|
||||
from pykickstart.sections import Section
|
||||
from pykickstart.sections import NullSection, PackageSection, PostScriptSection, PreScriptSection, TracebackScriptSection
|
||||
from pykickstart.version import returnClassForVersion
|
||||
|
||||
@ -76,8 +79,7 @@ log = logging.getLogger("anaconda")
|
||||
stderrLog = logging.getLogger("anaconda.stderr")
|
||||
storage_log = logging.getLogger("blivet")
|
||||
stdoutLog = logging.getLogger("anaconda.stdout")
|
||||
from pyanaconda.anaconda_log import logger, logLevelMap, setHandlersLevel,\
|
||||
DEFAULT_TTY_LEVEL
|
||||
from pyanaconda.anaconda_log import logger, logLevelMap, setHandlersLevel, DEFAULT_LEVEL
|
||||
|
||||
class AnacondaKSScript(KSScript):
|
||||
""" Execute a kickstart script
|
||||
@ -96,6 +98,9 @@ class AnacondaKSScript(KSScript):
|
||||
else:
|
||||
scriptRoot = "/"
|
||||
|
||||
# Environment variables that cause problems for %post scripts
|
||||
env_prune = ["LIBUSER_CONF"]
|
||||
|
||||
(fd, path) = tempfile.mkstemp("", "ks-script-", scriptRoot + "/tmp")
|
||||
|
||||
iutil.eintr_retry_call(os.write, fd, self.script)
|
||||
@ -122,7 +127,8 @@ class AnacondaKSScript(KSScript):
|
||||
with open(messages, "w") as fp:
|
||||
rc = iutil.execWithRedirect(self.interp, ["/tmp/%s" % os.path.basename(path)],
|
||||
stdout=fp,
|
||||
root = scriptRoot)
|
||||
root = scriptRoot,
|
||||
env_prune = env_prune)
|
||||
|
||||
if rc != 0:
|
||||
log.error("Error code %s running the kickstart script at line %s", rc, self.lineno)
|
||||
@ -132,6 +138,7 @@ class AnacondaKSScript(KSScript):
|
||||
err = "".join(fp.readlines())
|
||||
|
||||
errorHandler.cb(ScriptError(self.lineno, err))
|
||||
iutil.ipmi_report(IPMI_ABORTED)
|
||||
sys.exit(0)
|
||||
|
||||
class AnacondaInternalScript(AnacondaKSScript):
|
||||
@ -251,7 +258,7 @@ def refreshAutoSwapSize(storage):
|
||||
for request in storage.autoPartitionRequests:
|
||||
if request.fstype == "swap":
|
||||
disk_space = getAvailableDiskSpace(storage)
|
||||
request.size = swap_lib.swapSuggestion(disk_space=disk_space)
|
||||
request.size = autopart.swapSuggestion(disk_space=disk_space)
|
||||
break
|
||||
|
||||
###
|
||||
@ -270,7 +277,7 @@ class Authconfig(commands.authconfig.FC3_Authconfig):
|
||||
def execute(self, *args):
|
||||
cmd = "/usr/sbin/authconfig"
|
||||
if not os.path.lexists(iutil.getSysroot()+cmd):
|
||||
if self.seen:
|
||||
if flags.automatedInstall and self.seen:
|
||||
msg = _("%s is missing. Cannot setup authentication.") % cmd
|
||||
raise KickstartError(msg)
|
||||
else:
|
||||
@ -306,7 +313,7 @@ class AutoPart(commands.autopart.F21_AutoPart):
|
||||
return retval
|
||||
|
||||
def execute(self, storage, ksdata, instClass):
|
||||
from blivet.partitioning import doAutoPartition
|
||||
from blivet.autopart import doAutoPartition
|
||||
from pyanaconda.storage_utils import sanity_check
|
||||
|
||||
if not self.autopart:
|
||||
@ -351,6 +358,11 @@ class Bootloader(commands.bootloader.F21_Bootloader):
|
||||
raise KickstartValueError(formatErrorMsg(self.lineno,
|
||||
msg=_("GRUB2 does not support installation to a partition.")))
|
||||
|
||||
if self.isCrypted and isinstance(get_bootloader(), GRUB2):
|
||||
if not self.password.startswith("grub.pbkdf2."):
|
||||
raise KickstartValueError(formatErrorMsg(self.lineno,
|
||||
msg="GRUB2 encrypted password must be in grub.pbkdf2 format."))
|
||||
|
||||
return self
|
||||
|
||||
def execute(self, storage, ksdata, instClass):
|
||||
@ -449,12 +461,12 @@ class BTRFSData(commands.btrfs.F17_BTRFSData):
|
||||
|
||||
if dev and dev.format.type != "btrfs":
|
||||
raise KickstartValueError(formatErrorMsg(self.lineno,
|
||||
msg=_("BTRFS partition \"%(device)s\" has a format of \"%(format)s\", but should have a format of \"btrfs\".") %
|
||||
msg=_("Btrfs partition \"%(device)s\" has a format of \"%(format)s\", but should have a format of \"btrfs\".") %
|
||||
{"device": member, "format": dev.format.type}))
|
||||
|
||||
if not dev:
|
||||
raise KickstartValueError(formatErrorMsg(self.lineno,
|
||||
msg=_("Tried to use undefined partition \"%s\" in BTRFS volume specification.") % member))
|
||||
msg=_("Tried to use undefined partition \"%s\" in Btrfs volume specification.") % member))
|
||||
|
||||
members.append(dev)
|
||||
|
||||
@ -467,7 +479,7 @@ class BTRFSData(commands.btrfs.F17_BTRFSData):
|
||||
|
||||
if len(members) == 0 and not self.preexist:
|
||||
raise KickstartValueError(formatErrorMsg(self.lineno,
|
||||
msg=_("BTRFS volume defined without any member devices. Either specify member devices or use --useexisting.")))
|
||||
msg=_("Btrfs volume defined without any member devices. Either specify member devices or use --useexisting.")))
|
||||
|
||||
# allow creating btrfs vols/subvols without specifying mountpoint
|
||||
if self.mountpoint in ("none", "None"):
|
||||
@ -491,16 +503,19 @@ class BTRFSData(commands.btrfs.F17_BTRFSData):
|
||||
device = devicetree.resolveDevice(self.name)
|
||||
if not device:
|
||||
raise KickstartValueError(formatErrorMsg(self.lineno,
|
||||
msg=_("BTRFS volume \"%s\" specified with --useexisting does not exist.") % self.name))
|
||||
msg=_("Btrfs volume \"%s\" specified with --useexisting does not exist.") % self.name))
|
||||
|
||||
device.format.mountpoint = self.mountpoint
|
||||
else:
|
||||
request = storage.newBTRFS(name=name,
|
||||
try:
|
||||
request = storage.newBTRFS(name=name,
|
||||
subvol=self.subvol,
|
||||
mountpoint=self.mountpoint,
|
||||
metaDataLevel=self.metaDataLevel,
|
||||
dataLevel=self.dataLevel,
|
||||
parents=members)
|
||||
except BTRFSValueError as e:
|
||||
raise KickstartValueError(formatErrorMsg(self.lineno, msg=e.message))
|
||||
|
||||
storage.createDevice(request)
|
||||
|
||||
@ -515,17 +530,13 @@ class Realm(commands.realm.F19_Realm):
|
||||
return
|
||||
|
||||
try:
|
||||
argv = ["realm", "discover", "--verbose"] + \
|
||||
argv = ["discover", "--verbose"] + \
|
||||
self.discover_options + [self.join_realm]
|
||||
proc = subprocess.Popen(argv, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
|
||||
output, stderr = proc.communicate()
|
||||
# might contain useful information for users who use
|
||||
# use the realm kickstart command
|
||||
log.info("Realm discover stderr:\n%s", stderr)
|
||||
except OSError as msg:
|
||||
output = iutil.execWithCapture("realm", argv, filter_stderr=True)
|
||||
except OSError:
|
||||
# TODO: A lousy way of propagating what will usually be
|
||||
# 'no such realm'
|
||||
log.error("Error running realm %s: %s", argv, msg)
|
||||
# The error message is logged by iutil
|
||||
return
|
||||
|
||||
# Now parse the output for the required software. First line is the
|
||||
@ -557,25 +568,16 @@ class Realm(commands.realm.F19_Realm):
|
||||
# no explicit password arg using implicit --no-password
|
||||
pw_args = ["--no-password"]
|
||||
|
||||
argv = ["realm", "join", "--install", iutil.getSysroot(), "--verbose"] + \
|
||||
argv = ["join", "--install", iutil.getSysroot(), "--verbose"] + \
|
||||
pw_args + self.join_args
|
||||
rc = -1
|
||||
try:
|
||||
proc = subprocess.Popen(argv, stdout=subprocess.PIPE,
|
||||
stderr=subprocess.PIPE)
|
||||
stderr = proc.communicate()[1]
|
||||
# might contain useful information for users who use
|
||||
# use the realm kickstart command
|
||||
log.info("Realm join stderr:\n%s", stderr)
|
||||
rc = proc.returncode
|
||||
except OSError as msg:
|
||||
log.error("Error running %s: %s", argv, msg)
|
||||
rc = iutil.execWithRedirect("realm", argv)
|
||||
except OSError:
|
||||
pass
|
||||
|
||||
if rc != 0:
|
||||
log.error("Command failure: %s: %d", argv, rc)
|
||||
return
|
||||
|
||||
log.info("Joined realm %s", self.join_realm)
|
||||
if rc == 0:
|
||||
log.info("Joined realm %s", self.join_realm)
|
||||
|
||||
|
||||
class ClearPart(commands.clearpart.F21_ClearPart):
|
||||
@ -820,6 +822,11 @@ class LogVolData(commands.logvol.F21_LogVolData):
|
||||
|
||||
storage.doAutoPart = False
|
||||
|
||||
# FIXME: we should be running sanityCheck on partitioning that is not ks
|
||||
# autopart, but that's likely too invasive for #873135 at this moment
|
||||
if self.mountpoint == "/boot" and blivet.arch.isS390():
|
||||
raise KickstartValueError(formatErrorMsg(self.lineno, msg="/boot can not be of type 'lvmlv' on s390x"))
|
||||
|
||||
# we might have truncated or otherwise changed the specified vg name
|
||||
vgname = ksdata.onPart.get(self.vgname, self.vgname)
|
||||
|
||||
@ -833,7 +840,7 @@ class LogVolData(commands.logvol.F21_LogVolData):
|
||||
self.mountpoint = ""
|
||||
if self.recommended or self.hibernation:
|
||||
disk_space = getAvailableDiskSpace(storage)
|
||||
size = swap_lib.swapSuggestion(hibernation=self.hibernation, disk_space=disk_space)
|
||||
size = autopart.swapSuggestion(hibernation=self.hibernation, disk_space=disk_space)
|
||||
self.grow = False
|
||||
else:
|
||||
if self.fstype != "":
|
||||
@ -841,7 +848,7 @@ class LogVolData(commands.logvol.F21_LogVolData):
|
||||
else:
|
||||
ty = storage.defaultFSType
|
||||
|
||||
if size is None:
|
||||
if size is None and not self.preexist:
|
||||
if not self.size:
|
||||
raise KickstartValueError(formatErrorMsg(self.lineno,
|
||||
msg="Size can not be decided on from kickstart nor obtained from device."))
|
||||
@ -921,18 +928,10 @@ class LogVolData(commands.logvol.F21_LogVolData):
|
||||
msg=_("Logical volume name \"%(logvol)s\" is already in use in volume group \"%(volgroup)s\".") %
|
||||
{"logvol": self.name, "volgroup": vg.name}))
|
||||
|
||||
# Size specification checks
|
||||
if not self.percent:
|
||||
if not size:
|
||||
raise KickstartValueError(formatErrorMsg(self.lineno,
|
||||
msg=_("No size given for logical volume \"%s\". Use one of --useexisting, --size, or --percent.") % self.name))
|
||||
elif not self.grow and size < vg.peSize:
|
||||
raise KickstartValueError(formatErrorMsg(self.lineno,
|
||||
msg=_("Logical volume size \"%(logvolSize)s\" must be larger than the volume group extent size of \"%(extentSize)s\".") %
|
||||
{"logvolSize": size, "extentSize": vg.peSize}))
|
||||
elif self.percent <= 0 or self.percent > 100:
|
||||
if not self.percent and size and not self.grow and size < vg.peSize:
|
||||
raise KickstartValueError(formatErrorMsg(self.lineno,
|
||||
msg=_("Percentage must be between 0 and 100.")))
|
||||
msg=_("Logical volume size \"%(logvolSize)s\" must be larger than the volume group extent size of \"%(extentSize)s\".") %
|
||||
{"logvolSize": size, "extentSize": vg.peSize}))
|
||||
|
||||
# Now get a format to hold a lot of these extra values.
|
||||
fmt = getFormat(ty,
|
||||
@ -942,8 +941,9 @@ class LogVolData(commands.logvol.F21_LogVolData):
|
||||
mountopts=self.fsopts)
|
||||
if not fmt.type and not self.thin_pool:
|
||||
raise KickstartValueError(formatErrorMsg(self.lineno,
|
||||
msg=_("The \"%s\" filesystem type is not supported.") % ty))
|
||||
msg=_("The \"%s\" file system type is not supported.") % ty))
|
||||
|
||||
add_fstab_swap = None
|
||||
# If we were given a pre-existing LV to create a filesystem on, we need
|
||||
# to verify it and its VG exists and then schedule a new format action
|
||||
# to take place there. Also, we only support a subset of all the
|
||||
@ -967,7 +967,7 @@ class LogVolData(commands.logvol.F21_LogVolData):
|
||||
|
||||
devicetree.registerAction(ActionCreateFormat(device, fmt))
|
||||
if ty == "swap":
|
||||
storage.addFstabSwap(device)
|
||||
add_fstab_swap = device
|
||||
else:
|
||||
# If a previous device has claimed this mount point, delete the
|
||||
# old one.
|
||||
@ -1006,7 +1006,8 @@ class LogVolData(commands.logvol.F21_LogVolData):
|
||||
else:
|
||||
maxsize = None
|
||||
|
||||
request = storage.newLV(fmt=fmt,
|
||||
try:
|
||||
request = storage.newLV(fmt=fmt,
|
||||
name=self.name,
|
||||
parents=parents,
|
||||
size=size,
|
||||
@ -1016,15 +1017,26 @@ class LogVolData(commands.logvol.F21_LogVolData):
|
||||
maxsize=maxsize,
|
||||
percent=self.percent,
|
||||
**pool_args)
|
||||
except (StorageError, ValueError) as e:
|
||||
raise KickstartValueError(formatErrorMsg(self.lineno, msg=e.message))
|
||||
|
||||
storage.createDevice(request)
|
||||
if ty == "swap":
|
||||
storage.addFstabSwap(request)
|
||||
add_fstab_swap = request
|
||||
|
||||
if self.encrypted:
|
||||
if self.passphrase and not storage.encryptionPassphrase:
|
||||
storage.encryptionPassphrase = self.passphrase
|
||||
|
||||
# try to use the global passphrase if available
|
||||
# XXX: we require the LV/part with --passphrase to be processed
|
||||
# before this one to setup the storage.encryptionPassphrase
|
||||
self.passphrase = self.passphrase or storage.encryptionPassphrase
|
||||
|
||||
if not self.passphrase:
|
||||
raise KickstartValueError(formatErrorMsg(self.lineno,
|
||||
msg=_("No passphrase given for encrypted LV")))
|
||||
|
||||
cert = getEscrowCertificate(storage.escrowCertificates, self.escrowcert)
|
||||
if self.preexist:
|
||||
luksformat = fmt
|
||||
@ -1034,8 +1046,7 @@ class LogVolData(commands.logvol.F21_LogVolData):
|
||||
add_backup_passphrase=self.backuppassphrase)
|
||||
luksdev = LUKSDevice("luks%d" % storage.nextID,
|
||||
fmt=luksformat,
|
||||
parents=device,
|
||||
min_luks_entropy=MIN_CREATE_ENTROPY)
|
||||
parents=device)
|
||||
else:
|
||||
luksformat = request.format
|
||||
request.format = getFormat("luks", passphrase=self.passphrase,
|
||||
@ -1046,14 +1057,22 @@ class LogVolData(commands.logvol.F21_LogVolData):
|
||||
luksdev = LUKSDevice("luks%d" % storage.nextID,
|
||||
fmt=luksformat,
|
||||
parents=request)
|
||||
if ty == "swap":
|
||||
# swap is on the LUKS device not on the LUKS' parent device,
|
||||
# override the info here
|
||||
add_fstab_swap = luksdev
|
||||
|
||||
storage.createDevice(luksdev)
|
||||
|
||||
if add_fstab_swap:
|
||||
storage.addFstabSwap(add_fstab_swap)
|
||||
|
||||
class Logging(commands.logging.FC6_Logging):
|
||||
def execute(self, *args):
|
||||
if logger.tty_loglevel == DEFAULT_TTY_LEVEL:
|
||||
if logger.loglevel == DEFAULT_LEVEL:
|
||||
# not set from the command line
|
||||
level = logLevelMap[self.level]
|
||||
logger.tty_loglevel = level
|
||||
logger.loglevel = level
|
||||
setHandlersLevel(log, level)
|
||||
setHandlersLevel(storage_log, level)
|
||||
|
||||
@ -1064,7 +1083,7 @@ class Logging(commands.logging.FC6_Logging):
|
||||
remote_server = "%s:%s" %(self.host, self.port)
|
||||
logger.updateRemote(remote_server)
|
||||
|
||||
class Network(commands.network.F21_Network):
|
||||
class Network(commands.network.F22_Network):
|
||||
def execute(self, storage, ksdata, instClass):
|
||||
network.write_network_config(storage, ksdata, instClass, iutil.getSysroot())
|
||||
|
||||
@ -1092,7 +1111,7 @@ class PartitionData(commands.partition.F18_PartData):
|
||||
storage.doAutoPart = False
|
||||
|
||||
if self.onbiosdisk != "":
|
||||
for (disk, biosdisk) in storage.eddDict.iteritems():
|
||||
for (disk, biosdisk) in storage.eddDict.items():
|
||||
if "%x" % biosdisk == self.onbiosdisk:
|
||||
self.disk = disk
|
||||
break
|
||||
@ -1108,7 +1127,7 @@ class PartitionData(commands.partition.F18_PartData):
|
||||
self.mountpoint = ""
|
||||
if self.recommended or self.hibernation:
|
||||
disk_space = getAvailableDiskSpace(storage)
|
||||
size = swap_lib.swapSuggestion(hibernation=self.hibernation, disk_space=disk_space)
|
||||
size = autopart.swapSuggestion(hibernation=self.hibernation, disk_space=disk_space)
|
||||
self.grow = False
|
||||
# if people want to specify no mountpoint for some reason, let them
|
||||
# this is really needed for pSeries boot partitions :(
|
||||
@ -1156,7 +1175,7 @@ class PartitionData(commands.partition.F18_PartData):
|
||||
|
||||
if devicetree.getDeviceByName(kwargs["name"]):
|
||||
raise KickstartValueError(formatErrorMsg(self.lineno,
|
||||
msg=_("BTRFS partition \"%s\" is defined multiple times.") % kwargs["name"]))
|
||||
msg=_("Btrfs partition \"%s\" is defined multiple times.") % kwargs["name"]))
|
||||
|
||||
if self.onPart:
|
||||
ksdata.onPart[kwargs["name"]] = self.onPart
|
||||
@ -1229,7 +1248,7 @@ class PartitionData(commands.partition.F18_PartData):
|
||||
size=size)
|
||||
if not kwargs["fmt"].type:
|
||||
raise KickstartValueError(formatErrorMsg(self.lineno,
|
||||
msg=_("The \"%s\" filesystem type is not supported.") % ty))
|
||||
msg=_("The \"%s\" file system type is not supported.") % ty))
|
||||
|
||||
# If we were given a specific disk to create the partition on, verify
|
||||
# that it exists first. If it doesn't exist, see if it exists with
|
||||
@ -1275,6 +1294,7 @@ class PartitionData(commands.partition.F18_PartData):
|
||||
|
||||
kwargs["primary"] = self.primOnly
|
||||
|
||||
add_fstab_swap = None
|
||||
# If we were given a pre-existing partition to create a filesystem on,
|
||||
# we need to verify it exists and then schedule a new format action to
|
||||
# take place there. Also, we only support a subset of all the options
|
||||
@ -1297,11 +1317,14 @@ class PartitionData(commands.partition.F18_PartData):
|
||||
|
||||
devicetree.registerAction(ActionCreateFormat(device, kwargs["fmt"]))
|
||||
if ty == "swap":
|
||||
storage.addFstabSwap(device)
|
||||
add_fstab_swap = device
|
||||
# tmpfs mounts are not disks and don't occupy a disk partition,
|
||||
# so handle them here
|
||||
elif self.fstype == "tmpfs":
|
||||
request = storage.newTmpFS(**kwargs)
|
||||
try:
|
||||
request = storage.newTmpFS(**kwargs)
|
||||
except (StorageError, ValueError) as e:
|
||||
raise KickstartValueError(formatErrorMsg(self.lineno, msg=e.message))
|
||||
storage.createDevice(request)
|
||||
else:
|
||||
# If a previous device has claimed this mount point, delete the
|
||||
@ -1313,15 +1336,28 @@ class PartitionData(commands.partition.F18_PartData):
|
||||
except KeyError:
|
||||
pass
|
||||
|
||||
request = storage.newPartition(**kwargs)
|
||||
try:
|
||||
request = storage.newPartition(**kwargs)
|
||||
except (StorageError, ValueError) as e:
|
||||
raise KickstartValueError(formatErrorMsg(self.lineno, msg=e.message))
|
||||
|
||||
storage.createDevice(request)
|
||||
if ty == "swap":
|
||||
storage.addFstabSwap(request)
|
||||
add_fstab_swap = request
|
||||
|
||||
if self.encrypted:
|
||||
if self.passphrase and not storage.encryptionPassphrase:
|
||||
storage.encryptionPassphrase = self.passphrase
|
||||
|
||||
# try to use the global passphrase if available
|
||||
# XXX: we require the LV/part with --passphrase to be processed
|
||||
# before this one to setup the storage.encryptionPassphrase
|
||||
self.passphrase = self.passphrase or storage.encryptionPassphrase
|
||||
|
||||
if not self.passphrase:
|
||||
raise KickstartValueError(formatErrorMsg(self.lineno,
|
||||
msg=_("No passphrase given for encrypted part")))
|
||||
|
||||
cert = getEscrowCertificate(storage.escrowCertificates, self.escrowcert)
|
||||
if self.onPart:
|
||||
luksformat = kwargs["fmt"]
|
||||
@ -1343,8 +1379,17 @@ class PartitionData(commands.partition.F18_PartData):
|
||||
luksdev = LUKSDevice("luks%d" % storage.nextID,
|
||||
fmt=luksformat,
|
||||
parents=request)
|
||||
|
||||
if ty == "swap":
|
||||
# swap is on the LUKS device not on the LUKS' parent device,
|
||||
# override the info here
|
||||
add_fstab_swap = luksdev
|
||||
|
||||
storage.createDevice(luksdev)
|
||||
|
||||
if add_fstab_swap:
|
||||
storage.addFstabSwap(add_fstab_swap)
|
||||
|
||||
class Raid(commands.raid.F20_Raid):
|
||||
def execute(self, storage, ksdata, instClass):
|
||||
for r in self.raidList:
|
||||
@ -1384,7 +1429,7 @@ class RaidData(commands.raid.F18_RaidData):
|
||||
|
||||
if devicetree.getDeviceByName(kwargs["name"]):
|
||||
raise KickstartValueError(formatErrorMsg(self.lineno,
|
||||
msg=_("BTRFS partition \"%s\" is defined multiple times.") % kwargs["name"]))
|
||||
msg=_("Btrfs partition \"%s\" is defined multiple times.") % kwargs["name"]))
|
||||
|
||||
self.mountpoint = ""
|
||||
else:
|
||||
@ -1449,7 +1494,7 @@ class RaidData(commands.raid.F18_RaidData):
|
||||
mountopts=self.fsopts)
|
||||
if not kwargs["fmt"].type:
|
||||
raise KickstartValueError(formatErrorMsg(self.lineno,
|
||||
msg=_("The \"%s\" filesystem type is not supported.") % ty))
|
||||
msg=_("The \"%s\" file system type is not supported.") % ty))
|
||||
|
||||
kwargs["name"] = devicename
|
||||
kwargs["level"] = self.level
|
||||
@ -1485,8 +1530,8 @@ class RaidData(commands.raid.F18_RaidData):
|
||||
|
||||
try:
|
||||
request = storage.newMDArray(**kwargs)
|
||||
except ValueError as e:
|
||||
raise KickstartValueError(formatErrorMsg(self.lineno, msg=str(e)))
|
||||
except (StorageError, ValueError) as e:
|
||||
raise KickstartValueError(formatErrorMsg(self.lineno, msg=e.message))
|
||||
|
||||
storage.createDevice(request)
|
||||
|
||||
@ -1515,7 +1560,7 @@ class RaidData(commands.raid.F18_RaidData):
|
||||
parents=request)
|
||||
storage.createDevice(luksdev)
|
||||
|
||||
class RepoData(commands.repo.F15_RepoData):
|
||||
class RepoData(commands.repo.F21_RepoData):
|
||||
def __init__(self, *args, **kwargs):
|
||||
""" Add enabled kwarg
|
||||
|
||||
@ -1524,7 +1569,7 @@ class RepoData(commands.repo.F15_RepoData):
|
||||
"""
|
||||
self.enabled = kwargs.pop("enabled", True)
|
||||
|
||||
commands.repo.F15_RepoData.__init__(self, *args, **kwargs)
|
||||
commands.repo.F21_RepoData.__init__(self, *args, **kwargs)
|
||||
|
||||
class RootPw(commands.rootpw.F18_RootPw):
|
||||
def __init__(self, writePriority=100, *args, **kwargs):
|
||||
@ -1574,6 +1619,11 @@ class Services(commands.services.FC6_Services):
|
||||
|
||||
iutil.execInSysroot("systemctl", ["enable", svc])
|
||||
|
||||
class SshKey(commands.sshkey.F22_SshKey):
|
||||
def execute(self, storage, ksdata, instClass, users):
|
||||
for usr in self.sshUserList:
|
||||
users.setUserSshKey(usr.username, usr.key)
|
||||
|
||||
class Timezone(commands.timezone.F18_Timezone):
|
||||
def __init__(self, *args):
|
||||
commands.timezone.F18_Timezone.__init__(self, *args)
|
||||
@ -1637,9 +1687,9 @@ class Timezone(commands.timezone.F18_Timezone):
|
||||
# write out NTP configuration (if set)
|
||||
if not self.nontp and self.ntpservers:
|
||||
chronyd_conf_path = os.path.normpath(iutil.getSysroot() + ntp.NTP_CONFIG_FILE)
|
||||
pools, servers = ntp.internal_to_pools_and_servers(self.ntpservers)
|
||||
try:
|
||||
ntp.save_servers_to_config(self.ntpservers,
|
||||
conf_file_path=chronyd_conf_path)
|
||||
ntp.save_servers_to_config(pools, servers, conf_file_path=chronyd_conf_path)
|
||||
except ntp.NTPconfigError as ntperr:
|
||||
log.warning("Failed to save NTP configuration: %s", ntperr)
|
||||
|
||||
@ -1702,10 +1752,10 @@ class VolGroupData(commands.volgroup.F21_VolGroupData):
|
||||
|
||||
if self.pesize == 0:
|
||||
# default PE size requested -- we use blivet's default in KiB
|
||||
self.pesize = LVM_PE_SIZE.convertTo(spec="KiB")
|
||||
self.pesize = LVM_PE_SIZE.convertTo(KiB)
|
||||
|
||||
pesize = Size("%d KiB" % self.pesize)
|
||||
possible_extents = getPossiblePhysicalExtents()
|
||||
possible_extents = LVMVolumeGroupDevice.get_supported_pe_sizes()
|
||||
if pesize not in possible_extents:
|
||||
raise KickstartValueError(formatErrorMsg(self.lineno,
|
||||
msg=_("Volume group given physical extent size of \"%(extentSize)s\", but must be one of:\n%(validExtentSizes)s.") %
|
||||
@ -1725,9 +1775,12 @@ class VolGroupData(commands.volgroup.F21_VolGroupData):
|
||||
raise KickstartValueError(formatErrorMsg(self.lineno,
|
||||
msg=_("The volume group name \"%s\" is already in use.") % self.vgname))
|
||||
else:
|
||||
request = storage.newVG(parents=pvs,
|
||||
try:
|
||||
request = storage.newVG(parents=pvs,
|
||||
name=self.vgname,
|
||||
peSize=pesize)
|
||||
except (StorageError, ValueError) as e:
|
||||
raise KickstartValueError(formatErrorMsg(self.lineno, msg=e.message))
|
||||
|
||||
storage.createDevice(request)
|
||||
if self.reserved_space:
|
||||
@ -1777,8 +1830,64 @@ class Upgrade(commands.upgrade.F20_Upgrade):
|
||||
def parse(self, *args):
|
||||
log.error("The upgrade kickstart command is no longer supported. Upgrade functionality is provided through fedup.")
|
||||
sys.stderr.write(_("The upgrade kickstart command is no longer supported. Upgrade functionality is provided through fedup."))
|
||||
iutil.ipmi_report(IPMI_ABORTED)
|
||||
sys.exit(1)
|
||||
|
||||
###
|
||||
### %anaconda Section
|
||||
###
|
||||
|
||||
class AnacondaSectionHandler(BaseHandler):
|
||||
"""A handler for only the anaconda ection's commands."""
|
||||
commandMap = {
|
||||
"pwpolicy": F22_PwPolicy
|
||||
}
|
||||
|
||||
dataMap = {
|
||||
"PwPolicyData": F22_PwPolicyData
|
||||
}
|
||||
|
||||
def __init__(self):
|
||||
BaseHandler.__init__(self, mapping=self.commandMap, dataMapping=self.dataMap)
|
||||
|
||||
def __str__(self):
|
||||
"""Return the %anaconda section"""
|
||||
retval = ""
|
||||
lst = sorted(self._writeOrder.keys())
|
||||
for prio in lst:
|
||||
for obj in self._writeOrder[prio]:
|
||||
retval += str(obj)
|
||||
|
||||
if retval:
|
||||
retval = "\n%anaconda\n" + retval + "%end\n"
|
||||
return retval
|
||||
|
||||
class AnacondaSection(Section):
|
||||
"""A section for anaconda specific commands."""
|
||||
sectionOpen = "%anaconda"
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
Section.__init__(self, *args, **kwargs)
|
||||
self.cmdno = 0
|
||||
|
||||
def handleLine(self, line):
|
||||
if not self.handler:
|
||||
return
|
||||
|
||||
self.cmdno += 1
|
||||
args = shlex.split(line, comments=True)
|
||||
self.handler.currentCmd = args[0]
|
||||
self.handler.currentLine = self.cmdno
|
||||
return self.handler.dispatcher(args, self.cmdno)
|
||||
|
||||
def handleHeader(self, lineno, args):
|
||||
"""Process the arguments to the %anaconda header."""
|
||||
Section.handleHeader(self, lineno, args)
|
||||
|
||||
def finalize(self):
|
||||
"""Let %anaconda know no additional data will come."""
|
||||
Section.finalize(self)
|
||||
|
||||
###
|
||||
### HANDLERS
|
||||
###
|
||||
@ -1814,6 +1923,7 @@ commandMap = {
|
||||
"rootpw": RootPw,
|
||||
"selinux": SELinux,
|
||||
"services": Services,
|
||||
"sshkey": SshKey,
|
||||
"skipx": SkipX,
|
||||
"timezone": Timezone,
|
||||
"upgrade": Upgrade,
|
||||
@ -1870,8 +1980,11 @@ class AnacondaKSHandler(superclass):
|
||||
# Prepare the final structures for 3rd party addons
|
||||
self.addons = AddonRegistry(addons)
|
||||
|
||||
# The %anaconda section uses its own handler for a limited set of commands
|
||||
self.anaconda = AnacondaSectionHandler()
|
||||
|
||||
def __str__(self):
|
||||
return superclass.__str__(self) + "\n" + str(self.addons)
|
||||
return superclass.__str__(self) + "\n" + str(self.addons) + str(self.anaconda)
|
||||
|
||||
class AnacondaPreParser(KickstartParser):
|
||||
# A subclass of KickstartParser that only looks for %pre scripts and
|
||||
@ -1889,6 +2002,7 @@ class AnacondaPreParser(KickstartParser):
|
||||
self.registerSection(NullSection(self.handler, sectionOpen="%traceback"))
|
||||
self.registerSection(NullSection(self.handler, sectionOpen="%packages"))
|
||||
self.registerSection(NullSection(self.handler, sectionOpen="%addon"))
|
||||
self.registerSection(NullSection(self.handler.anaconda, sectionOpen="%anaconda"))
|
||||
|
||||
|
||||
class AnacondaKSParser(KickstartParser):
|
||||
@ -1909,6 +2023,7 @@ class AnacondaKSParser(KickstartParser):
|
||||
self.registerSection(TracebackScriptSection(self.handler, dataObj=self.scriptClass))
|
||||
self.registerSection(PackageSection(self.handler))
|
||||
self.registerSection(AddonSection(self.handler))
|
||||
self.registerSection(AnacondaSection(self.handler.anaconda))
|
||||
|
||||
def preScriptPass(f):
|
||||
# The first pass through kickstart file processing - look for %pre scripts
|
||||
@ -1922,6 +2037,7 @@ def preScriptPass(f):
|
||||
# We do not have an interface here yet, so we cannot use our error
|
||||
# handling callback.
|
||||
print(e)
|
||||
iutil.ipmi_report(IPMI_ABORTED)
|
||||
sys.exit(1)
|
||||
|
||||
# run %pre scripts
|
||||
@ -1949,6 +2065,7 @@ def parseKickstart(f):
|
||||
# We do not have an interface here yet, so we cannot use our error
|
||||
# handling callback.
|
||||
print(e)
|
||||
iutil.ipmi_report(IPMI_ABORTED)
|
||||
sys.exit(1)
|
||||
|
||||
return handler
|
||||
@ -1970,22 +2087,17 @@ def appendPostScripts(ksdata):
|
||||
ksparser.readKickstartFromString(scripts, reset=False)
|
||||
|
||||
def runPostScripts(scripts):
|
||||
postScripts = filter (lambda s: s.type == KS_SCRIPT_POST, scripts)
|
||||
postScripts = [s for s in scripts if s.type == KS_SCRIPT_POST]
|
||||
|
||||
if len(postScripts) == 0:
|
||||
return
|
||||
|
||||
# Remove environment variables that cause problems for %post scripts.
|
||||
for var in ["LIBUSER_CONF"]:
|
||||
if var in os.environ:
|
||||
del(os.environ[var])
|
||||
|
||||
log.info("Running kickstart %%post script(s)")
|
||||
map (lambda s: s.run(iutil.getSysroot()), postScripts)
|
||||
log.info("All kickstart %%post script(s) have been run")
|
||||
|
||||
def runPreScripts(scripts):
|
||||
preScripts = filter (lambda s: s.type == KS_SCRIPT_PRE, scripts)
|
||||
preScripts = [s for s in scripts if s.type == KS_SCRIPT_PRE]
|
||||
|
||||
if len(preScripts) == 0:
|
||||
return
|
||||
|
@ -29,7 +29,7 @@ import glob
|
||||
from collections import namedtuple
|
||||
|
||||
from pyanaconda import constants
|
||||
from pyanaconda.iutil import upcase_first_letter
|
||||
from pyanaconda.iutil import upcase_first_letter, setenv
|
||||
|
||||
import logging
|
||||
log = logging.getLogger("anaconda")
|
||||
@ -152,7 +152,7 @@ def find_best_locale_match(locale, langcodes):
|
||||
if not locale_parts or not langcode_parts:
|
||||
return score
|
||||
|
||||
for part, part_score in score_map.iteritems():
|
||||
for part, part_score in score_map.items():
|
||||
if locale_parts[part] and langcode_parts[part]:
|
||||
if locale_parts[part] == langcode_parts[part]:
|
||||
# match
|
||||
@ -187,6 +187,9 @@ def setup_locale(locale, lang=None):
|
||||
ksdata.lang object (if given). DOES NOT PERFORM ANY CHECKS OF THE GIVEN
|
||||
LOCALE.
|
||||
|
||||
$LANG must be set by the caller in order to set the language used by gettext.
|
||||
Doing this in a thread-safe way is up to the caller.
|
||||
|
||||
:param locale: locale to setup
|
||||
:type locale: str
|
||||
:param lang: ksdata.lang object or None
|
||||
@ -198,7 +201,7 @@ def setup_locale(locale, lang=None):
|
||||
if lang:
|
||||
lang.lang = locale
|
||||
|
||||
os.environ["LANG"] = locale
|
||||
setenv("LANG", locale)
|
||||
locale_mod.setlocale(locale_mod.LC_ALL, locale)
|
||||
|
||||
def get_english_name(locale):
|
||||
@ -395,7 +398,7 @@ def get_xlated_timezone(tz_spec_part):
|
||||
territoryIdQuery=parts.get("territory", ""),
|
||||
scriptIdQuery=parts.get("script", ""))
|
||||
|
||||
return xlated.encode("utf-8")
|
||||
return xlated
|
||||
|
||||
def write_language_configuration(lang, root):
|
||||
"""
|
||||
@ -420,6 +423,8 @@ def load_firmware_language(lang):
|
||||
information in the given ksdata.lang object and sets the $LANG environment
|
||||
variable.
|
||||
|
||||
This method must be run before any other threads are started.
|
||||
|
||||
:param lang: ksdata.lang object
|
||||
:return: None
|
||||
:rtype: None
|
||||
@ -471,6 +476,8 @@ def load_firmware_language(lang):
|
||||
log.debug("Using UEFI PlatformLang '%s' ('%s') as our language.", d, locales[0])
|
||||
setup_locale(locales[0], lang)
|
||||
|
||||
os.environ["LANG"] = locales[0] # pylint: disable=environment-modify
|
||||
|
||||
_DateFieldSpec = namedtuple("DateFieldSpec", ["format", "suffix"])
|
||||
|
||||
def resolve_date_format(year, month, day, fail_safe=True):
|
||||
|
@ -71,11 +71,6 @@ def setup_ifcfg_log():
|
||||
logger = logging.getLogger("ifcfg")
|
||||
logger.setLevel(logging.DEBUG)
|
||||
anaconda_log.logger.addFileHandler(ifcfgLogFile, logger, logging.DEBUG)
|
||||
if os.access("/dev/tty3", os.W_OK):
|
||||
anaconda_log.logger.addFileHandler("/dev/tty3", logger,
|
||||
anaconda_log.DEFAULT_TTY_LEVEL,
|
||||
anaconda_log.TTY_FORMAT,
|
||||
autoLevel=True)
|
||||
anaconda_log.logger.forwardToSyslog(logger)
|
||||
|
||||
ifcfglog = logging.getLogger("ifcfg")
|
||||
@ -100,13 +95,13 @@ def sanityCheckHostname(hostname):
|
||||
"""
|
||||
|
||||
if not hostname:
|
||||
return (False, _("Hostname cannot be None or an empty string."))
|
||||
return (False, _("Host name cannot be None or an empty string."))
|
||||
|
||||
if len(hostname) > 255:
|
||||
return (False, _("Hostname must be 255 or fewer characters in length."))
|
||||
return (False, _("Host name must be 255 or fewer characters in length."))
|
||||
|
||||
if not (re.match('^' + HOSTNAME_PATTERN_WITHOUT_ANCHORS + '$', hostname)):
|
||||
return (False, _("Hostnames can only contain the characters 'a-z', "
|
||||
return (False, _("Host names can only contain the characters 'a-z', "
|
||||
"'A-Z', '0-9', '-', or '.', parts between periods "
|
||||
"must contain something and cannot start or end with "
|
||||
"'-'."))
|
||||
@ -363,6 +358,11 @@ def dracutBootArguments(devname, ifcfg, storage_ipaddr, hostname=None):
|
||||
if hwaddr:
|
||||
netargs.add("ifname=%s:%s" % (devname, hwaddr.lower()))
|
||||
|
||||
if ifcfg.get("TYPE") == "Team" or ifcfg.get("DEVICETYPE") == "Team":
|
||||
slaves = get_team_slaves([devname, ifcfg.get("UUID")])
|
||||
netargs.add("team=%s:%s" % (devname,
|
||||
",".join(dev for dev, _cfg in slaves)))
|
||||
|
||||
nettype = ifcfg.get("NETTYPE")
|
||||
subchannels = ifcfg.get("SUBCHANNELS")
|
||||
if blivet.arch.isS390() and nettype and subchannels:
|
||||
@ -463,31 +463,8 @@ def add_connection_for_ksdata(networkdata, devname):
|
||||
values.append(['bond', 'interface-name', devname, 's'])
|
||||
options = bond_options_ksdata_to_dbus(networkdata.bondopts)
|
||||
values.append(['bond', 'options', options, 'a{ss}'])
|
||||
for _i, slave in enumerate(networkdata.bondslaves.split(","), 1):
|
||||
|
||||
#slave_name = "%s slave %d" % (devname, i)
|
||||
slave_name = slave
|
||||
|
||||
svalues = []
|
||||
suuid = str(uuid4())
|
||||
svalues.append(['connection', 'uuid', suuid, 's'])
|
||||
svalues.append(['connection', 'id', slave_name, 's'])
|
||||
svalues.append(['connection', 'slave-type', 'bond', 's'])
|
||||
svalues.append(['connection', 'master', devname, 's'])
|
||||
svalues.append(['connection', 'type', '802-3-ethernet', 's'])
|
||||
mac = nm.nm_device_perm_hwaddress(slave)
|
||||
mac = [int(b, 16) for b in mac.split(":")]
|
||||
svalues.append(['802-3-ethernet', 'mac-address', mac, 'ay'])
|
||||
|
||||
# disconnect slaves
|
||||
if networkdata.activate:
|
||||
nm.nm_disconnect_device(slave)
|
||||
# remove ifcfg file
|
||||
ifcfg_path = find_ifcfg_file_of_device(slave)
|
||||
if ifcfg_path and os.access(ifcfg_path, os.R_OK):
|
||||
os.unlink(ifcfg_path)
|
||||
|
||||
nm.nm_add_connection(svalues)
|
||||
for slave in networkdata.bondslaves.split(","):
|
||||
suuid = _add_slave_connection('bond', slave, devname, networkdata.activate)
|
||||
added_connections.append((suuid, slave))
|
||||
dev_spec = None
|
||||
# type "team"
|
||||
@ -496,33 +473,9 @@ def add_connection_for_ksdata(networkdata, devname):
|
||||
values.append(['connection', 'id', devname, 's'])
|
||||
values.append(['team', 'interface-name', devname, 's'])
|
||||
values.append(['team', 'config', networkdata.teamconfig, 's'])
|
||||
for _i, (slave, cfg) in enumerate(networkdata.teamslaves):
|
||||
|
||||
# assume ethernet, TODO: infiniband, wifi, vlan
|
||||
#slave_name = "%s slave %d" % (devname, i)
|
||||
slave_name = slave
|
||||
|
||||
svalues = []
|
||||
suuid = str(uuid4())
|
||||
svalues.append(['connection', 'uuid', suuid, 's'])
|
||||
svalues.append(['connection', 'id', slave_name, 's'])
|
||||
svalues.append(['connection', 'slave-type', 'team', 's'])
|
||||
svalues.append(['connection', 'master', devname, 's'])
|
||||
svalues.append(['connection', 'type', '802-3-ethernet', 's'])
|
||||
mac = nm.nm_device_perm_hwaddress(slave)
|
||||
mac = [int(b, 16) for b in mac.split(":")]
|
||||
svalues.append(['802-3-ethernet', 'mac-address', mac, 'ay'])
|
||||
svalues.append(['team-port', 'config', cfg, 's'])
|
||||
|
||||
# disconnect slaves
|
||||
if networkdata.activate:
|
||||
nm.nm_disconnect_device(slave)
|
||||
# remove ifcfg file
|
||||
ifcfg_path = find_ifcfg_file_of_device(slave)
|
||||
if ifcfg_path and os.access(ifcfg_path, os.R_OK):
|
||||
os.unlink(ifcfg_path)
|
||||
|
||||
nm.nm_add_connection(svalues)
|
||||
for (slave, cfg) in networkdata.teamslaves:
|
||||
values = [['team-port', 'config', cfg, 's']]
|
||||
suuid = _add_slave_connection('team', slave, devname, networkdata.activate, values)
|
||||
added_connections.append((suuid, slave))
|
||||
dev_spec = None
|
||||
# type "vlan"
|
||||
@ -533,19 +486,84 @@ def add_connection_for_ksdata(networkdata, devname):
|
||||
values.append(['vlan', 'interface-name', devname, 's'])
|
||||
values.append(['vlan', 'id', int(networkdata.vlanid), 'u'])
|
||||
dev_spec = None
|
||||
# type "bridge"
|
||||
elif networkdata.bridgeslaves:
|
||||
# bridge connection is autoactivated
|
||||
values.append(['connection', 'type', 'bridge', 's'])
|
||||
values.append(['connection', 'id', devname, 's'])
|
||||
values.append(['bridge', 'interface-name', devname, 's'])
|
||||
for opt in networkdata.bridgeopts.split(","):
|
||||
key, _sep, value = opt.partition("=")
|
||||
if key == "stp":
|
||||
if value == "yes":
|
||||
values.append(['bridge', key, True, 'b'])
|
||||
elif value == "no":
|
||||
values.append(['bridge', key, False, 'b'])
|
||||
continue
|
||||
try:
|
||||
value = int(value)
|
||||
except ValueError:
|
||||
log.error("Invalid bridge option %s", opt)
|
||||
continue
|
||||
values.append(['bridge', key, int(value), 'u'])
|
||||
for slave in networkdata.bridgeslaves.split(","):
|
||||
suuid = _add_slave_connection('bridge', slave, devname, networkdata.activate)
|
||||
added_connections.append((suuid, slave))
|
||||
dev_spec = None
|
||||
# type "802-3-ethernet"
|
||||
else:
|
||||
mac = nm.nm_device_perm_hwaddress(devname)
|
||||
if flags.cmdline.get("ifname", "").upper() == "{0}:{1}".format(devname, mac).upper():
|
||||
mac = [int(b, 16) for b in mac.split(":")]
|
||||
values.append(['802-3-ethernet', 'mac-address', mac, 'ay'])
|
||||
else:
|
||||
values.append(['802-3-ethernet', 'name', devname, 's'])
|
||||
values.append(['connection', 'type', '802-3-ethernet', 's'])
|
||||
values.append(['connection', 'id', devname, 's'])
|
||||
mac = nm.nm_device_perm_hwaddress(devname)
|
||||
mac = [int(b, 16) for b in mac.split(":")]
|
||||
values.append(['802-3-ethernet', 'mac-address', mac, 'ay'])
|
||||
values.append(['connection', 'interface-name', devname, 's'])
|
||||
|
||||
dev_spec = devname
|
||||
|
||||
nm.nm_add_connection(values)
|
||||
try:
|
||||
nm.nm_add_connection(values)
|
||||
except nm.BondOptionsError as e:
|
||||
log.error(e)
|
||||
return []
|
||||
added_connections.insert(0, (con_uuid, dev_spec))
|
||||
return added_connections
|
||||
|
||||
def _add_slave_connection(slave_type, slave, master, activate, values=None):
|
||||
values = values or []
|
||||
#slave_name = "%s slave %d" % (devname, slave_idx)
|
||||
slave_name = slave
|
||||
|
||||
values = []
|
||||
suuid = str(uuid4())
|
||||
# assume ethernet, TODO: infiniband, wifi, vlan
|
||||
values.append(['connection', 'uuid', suuid, 's'])
|
||||
values.append(['connection', 'id', slave_name, 's'])
|
||||
values.append(['connection', 'slave-type', slave_type, 's'])
|
||||
values.append(['connection', 'master', master, 's'])
|
||||
values.append(['connection', 'type', '802-3-ethernet', 's'])
|
||||
mac = nm.nm_device_perm_hwaddress(slave)
|
||||
mac = [int(b, 16) for b in mac.split(":")]
|
||||
values.append(['802-3-ethernet', 'mac-address', mac, 'ay'])
|
||||
|
||||
# disconnect slaves
|
||||
if activate:
|
||||
try:
|
||||
nm.nm_disconnect_device(slave)
|
||||
except nm.DeviceNotActiveError:
|
||||
pass
|
||||
# remove ifcfg file
|
||||
ifcfg_path = find_ifcfg_file_of_device(slave)
|
||||
if ifcfg_path and os.access(ifcfg_path, os.R_OK):
|
||||
os.unlink(ifcfg_path)
|
||||
|
||||
nm.nm_add_connection(values)
|
||||
|
||||
return suuid
|
||||
|
||||
def ksdata_from_ifcfg(devname, uuid=None):
|
||||
|
||||
if devname not in nm.nm_devices():
|
||||
@ -586,6 +604,8 @@ def ksdata_from_ifcfg(devname, uuid=None):
|
||||
nd.device = devname
|
||||
elif nm.nm_device_type_is_team(devname):
|
||||
nd.device = devname
|
||||
elif nm.nm_device_type_is_bridge(devname):
|
||||
nd.device = devname
|
||||
elif nm.nm_device_type_is_vlan(devname):
|
||||
if devname != default_ks_vlan_interface_name(nd.device, nd.vlanid):
|
||||
nd.interfacename = devname
|
||||
@ -604,6 +624,9 @@ def ifcfg_to_ksdata(ifcfg, devname):
|
||||
# no network command for team slaves
|
||||
if ifcfg.get("TEAM_MASTER"):
|
||||
return None
|
||||
# no network command for bridge slaves
|
||||
if ifcfg.get("BRIDGE"):
|
||||
return None
|
||||
|
||||
# ipv4 and ipv6
|
||||
if ifcfg.get("ONBOOT") and ifcfg.get("ONBOOT" ) == "no":
|
||||
@ -682,7 +705,7 @@ def ifcfg_to_ksdata(ifcfg, devname):
|
||||
# bonding
|
||||
# FIXME: dracut has only BOND_OPTS
|
||||
if ifcfg.get("BONDING_MASTER") == "yes" or ifcfg.get("TYPE") == "Bond":
|
||||
slaves = get_bond_slaves_from_ifcfgs([devname, ifcfg.get("UUID")])
|
||||
slaves = get_slaves_from_ifcfgs("MASTER", [devname, ifcfg.get("UUID")])
|
||||
if slaves:
|
||||
kwargs["bondslaves"] = ",".join(slaves)
|
||||
bondopts = ifcfg.get("BONDING_OPTS")
|
||||
@ -697,6 +720,20 @@ def ifcfg_to_ksdata(ifcfg, devname):
|
||||
kwargs["device"] = ifcfg.get("PHYSDEV")
|
||||
kwargs["vlanid"] = ifcfg.get("VLAN_ID")
|
||||
|
||||
# bridging
|
||||
if ifcfg.get("TYPE") == "Bridge":
|
||||
slaves = get_slaves_from_ifcfgs("BRIDGE", [devname, ifcfg.get("UUID")])
|
||||
if slaves:
|
||||
kwargs["bridgeslaves"] = ",".join(slaves)
|
||||
|
||||
bridgeopts = ifcfg.get("BRIDGING_OPTS").replace('_', '-').split()
|
||||
if ifcfg.get("STP"):
|
||||
bridgeopts.append("%s=%s" % ("stp", ifcfg.get("STP")))
|
||||
if ifcfg.get("DELAY"):
|
||||
bridgeopts.append("%s=%s" % ("forward-delay", ifcfg.get("DELAY")))
|
||||
if bridgeopts:
|
||||
kwargs["bridgeopts"] = ",".join(bridgeopts)
|
||||
|
||||
# pylint: disable=no-member
|
||||
nd = handler.NetworkData(**kwargs)
|
||||
|
||||
@ -734,6 +771,8 @@ def find_ifcfg_file_of_device(devname, root_path=""):
|
||||
ifcfg_path = find_ifcfg_file([("DEVICE", devname)])
|
||||
elif nm.nm_device_type_is_vlan(devname):
|
||||
ifcfg_path = find_ifcfg_file([("DEVICE", devname)])
|
||||
elif nm.nm_device_type_is_bridge(devname):
|
||||
ifcfg_path = find_ifcfg_file([("DEVICE", devname)])
|
||||
elif nm.nm_device_type_is_ethernet(devname):
|
||||
try:
|
||||
hwaddr = nm.nm_device_perm_hwaddress(devname)
|
||||
@ -750,6 +789,10 @@ def find_ifcfg_file_of_device(devname, root_path=""):
|
||||
ifcfg_path = find_ifcfg_file([("HWADDR", hwaddr_check),
|
||||
("TEAM_MASTER", nonempty)],
|
||||
root_path)
|
||||
if not ifcfg_path:
|
||||
ifcfg_path = find_ifcfg_file([("HWADDR", hwaddr_check),
|
||||
("BRIDGE", nonempty)],
|
||||
root_path)
|
||||
if not ifcfg_path:
|
||||
ifcfg_path = find_ifcfg_file([("HWADDR", hwaddr_check)], root_path)
|
||||
if not ifcfg_path:
|
||||
@ -772,9 +815,10 @@ def find_ifcfg_file(values, root_path=""):
|
||||
return filepath
|
||||
return None
|
||||
|
||||
def get_bond_slaves_from_ifcfgs(master_specs):
|
||||
"""List of slave device names of master specified by master_specs.
|
||||
def get_slaves_from_ifcfgs(master_option, master_specs):
|
||||
"""List of slaves of master specified by master_specs in master_option.
|
||||
|
||||
master_option is ifcfg option containing spec of master
|
||||
master_specs is a list containing device name of master (dracut)
|
||||
and/or master's connection uuid
|
||||
"""
|
||||
@ -783,7 +827,7 @@ def get_bond_slaves_from_ifcfgs(master_specs):
|
||||
for filepath in _ifcfg_files(netscriptsDir):
|
||||
ifcfg = IfcfgFile(filepath)
|
||||
ifcfg.read()
|
||||
master = ifcfg.get("MASTER")
|
||||
master = ifcfg.get(master_option)
|
||||
if master in master_specs:
|
||||
device = ifcfg.get("DEVICE")
|
||||
if device:
|
||||
@ -894,6 +938,15 @@ def copyDhclientConfFiles(destPath):
|
||||
copyFileToPath(dhclientfile, destPath)
|
||||
|
||||
def ks_spec_to_device_name(ksspec=""):
|
||||
"""
|
||||
Find the first network device which matches the kickstart specification.
|
||||
Will not match derived types such as bonds and vlans.
|
||||
|
||||
:param ksspec: kickstart-specified device name
|
||||
:returns: a string naming a physical device, or "" meaning none matched
|
||||
:rtype: str
|
||||
|
||||
"""
|
||||
bootif_mac = ''
|
||||
if ksspec == 'bootif' and "BOOTIF" in flags.cmdline:
|
||||
bootif_mac = flags.cmdline["BOOTIF"][3:].replace("-", ":").upper()
|
||||
@ -901,7 +954,7 @@ def ks_spec_to_device_name(ksspec=""):
|
||||
# "eth0"
|
||||
if ksspec == dev:
|
||||
break
|
||||
# "link"
|
||||
# "link" - match the first device which is plugged (has a carrier)
|
||||
elif ksspec == 'link':
|
||||
try:
|
||||
link_up = nm.nm_device_carrier(dev)
|
||||
@ -936,7 +989,7 @@ def ks_spec_to_device_name(ksspec=""):
|
||||
|
||||
def set_hostname(hn):
|
||||
if can_touch_runtime_system("set hostname", touch_live=True):
|
||||
log.info("setting installation environment hostname to %s", hn)
|
||||
log.info("setting installation environment host name to %s", hn)
|
||||
iutil.execWithRedirect("hostnamectl", ["set-hostname", hn])
|
||||
|
||||
def write_hostname(rootpath, ksdata, overwrite=False):
|
||||
@ -1040,7 +1093,7 @@ def update_hostname_data(ksdata, hostname=None):
|
||||
if not hostname:
|
||||
# Default to 'dom0' in Qubes
|
||||
hostname = 'dom0'
|
||||
log.debug("updating hostname %s", hostname)
|
||||
log.debug("updating host name %s", hostname)
|
||||
hostname_found = False
|
||||
for nd in ksdata.network.network:
|
||||
if nd.hostname:
|
||||
@ -1051,13 +1104,20 @@ def update_hostname_data(ksdata, hostname=None):
|
||||
ksdata.network.network.append(nd)
|
||||
|
||||
def get_device_name(network_data):
|
||||
"""
|
||||
Find the first network device which matches the kickstart specification.
|
||||
|
||||
:param network_data: A pykickstart NetworkData object
|
||||
:returns: a string naming a physical device, or "" meaning none matched
|
||||
:rtype: str
|
||||
|
||||
"""
|
||||
ksspec = network_data.device or flags.cmdline.get('ksdevice') or ""
|
||||
dev_name = ks_spec_to_device_name(ksspec)
|
||||
if not dev_name:
|
||||
return ""
|
||||
if dev_name not in nm.nm_devices():
|
||||
if not any((network_data.vlanid, network_data.bondslaves, network_data.teamslaves)):
|
||||
if not any((network_data.vlanid, network_data.bondslaves, network_data.teamslaves, network_data.bridgeslaves)):
|
||||
return ""
|
||||
if network_data.vlanid:
|
||||
network_data.parent = dev_name
|
||||
@ -1134,9 +1194,9 @@ def apply_kickstart(ksdata):
|
||||
for con_uuid, dev_name in added_connections:
|
||||
try:
|
||||
nm.nm_activate_device_connection(dev_name, con_uuid)
|
||||
except nm.UnknownConnectionError:
|
||||
log.warning("network: pre kickstart: can't activate connection %s on %s",
|
||||
con_uuid, dev_name)
|
||||
except (nm.UnknownConnectionError, nm.UnknownDeviceError) as e:
|
||||
log.warning("network: pre kickstart: can't activate connection %s on %s: %s",
|
||||
con_uuid, dev_name, e)
|
||||
return applied_devices
|
||||
|
||||
def networkInitialize(ksdata):
|
||||
@ -1181,7 +1241,7 @@ def _get_ntp_servers_from_dhcp(ksdata):
|
||||
hostname = socket.gethostbyaddr(server_address)[0]
|
||||
except socket.error:
|
||||
# getting hostname failed, just use the address returned from DHCP
|
||||
log.debug("getting NTP server hostname failed for address: %s",
|
||||
log.debug("getting NTP server host name failed for address: %s",
|
||||
server_address)
|
||||
hostname = server_address
|
||||
hostnames.append(hostname)
|
||||
@ -1301,10 +1361,14 @@ def status_message():
|
||||
msg = _("Team%(interface_name)s (%(list_of_slaves)s) connected") \
|
||||
% {"interface_name": devname, \
|
||||
"list_of_slaves": ",".join(slaves[devname])}
|
||||
elif nm.nm_device_type_is_bridge(devname):
|
||||
msg = _("Bridge%(interface_name)s (%(list_of_slaves)s) connected") \
|
||||
% {"interface_name": devname, \
|
||||
"list_of_slaves": ",".join(slaves[devname])}
|
||||
elif nm.nm_device_type_is_vlan(devname):
|
||||
parent = nm.nm_device_setting_value(devname, "vlan", "parent")
|
||||
vlanid = nm.nm_device_setting_value(devname, "vlan", "id")
|
||||
msg = _("Vlan %(interface_name)s (%(parent_device)s, ID %(vlanid)s) connected") \
|
||||
msg = _("VLAN %(interface_name)s (%(parent_device)s, ID %(vlanid)s) connected") \
|
||||
% {"interface_name": devname, "parent_device": parent, "vlanid": vlanid}
|
||||
elif len(nonslaves) > 1:
|
||||
devlist = []
|
||||
@ -1317,6 +1381,8 @@ def status_message():
|
||||
devlist.append("%s (%s)" % (devname, ",".join(slaves[devname])))
|
||||
elif nm.nm_device_type_is_team(devname):
|
||||
devlist.append("%s (%s)" % (devname, ",".join(slaves[devname])))
|
||||
elif nm.nm_device_type_is_bridge(devname):
|
||||
devlist.append("%s (%s)" % (devname, ",".join(slaves[devname])))
|
||||
elif nm.nm_device_type_is_vlan(devname):
|
||||
devlist.append("%s" % devname)
|
||||
msg = _("Connected: %(list_of_interface_names)s") \
|
||||
@ -1362,3 +1428,6 @@ def update_onboot_value(devname, value, ksdata):
|
||||
if nd.device == devname:
|
||||
nd.onboot = True
|
||||
break
|
||||
|
||||
def is_using_team_device():
|
||||
return any(nm.nm_device_type_is_team(d) for d in nm.nm_devices())
|
||||
|
@ -21,10 +21,8 @@
|
||||
|
||||
from gi.repository import Gio, GLib
|
||||
from gi.repository import NetworkManager
|
||||
import IPy
|
||||
import struct
|
||||
import socket
|
||||
import re
|
||||
import logging
|
||||
log = logging.getLogger("anaconda")
|
||||
|
||||
@ -77,6 +75,15 @@ class UnknownConnectionError(Exception):
|
||||
def __str__(self):
|
||||
return self.__repr__()
|
||||
|
||||
class AddConnectionError(Exception):
|
||||
"""Connection is not available for the device"""
|
||||
def __str__(self):
|
||||
return self.__repr__()
|
||||
|
||||
# bug #1039006
|
||||
class BondOptionsError(AddConnectionError):
|
||||
pass
|
||||
|
||||
def _get_proxy(bus_type=Gio.BusType.SYSTEM,
|
||||
proxy_flags=Gio.DBusProxyFlags.NONE,
|
||||
info=None,
|
||||
@ -312,6 +319,18 @@ def nm_device_type_is_team(name):
|
||||
"""
|
||||
return nm_device_type(name) == NetworkManager.DeviceType.TEAM
|
||||
|
||||
def nm_device_type_is_bridge(name):
|
||||
"""Is the type of device bridge?
|
||||
|
||||
:param name: name of device
|
||||
:type name: str
|
||||
:return: True if type of device is BRIDGE, False otherwise
|
||||
:rtype: bool
|
||||
:raise UnknownDeviceError: if device is not found
|
||||
:raise PropertyNotFoundError: if property is not found
|
||||
"""
|
||||
return nm_device_type(name) == NetworkManager.DeviceType.BRIDGE
|
||||
|
||||
def nm_device_type_is_vlan(name):
|
||||
"""Is the type of device vlan?
|
||||
|
||||
@ -483,7 +502,8 @@ def nm_device_ip_config(name, version=4):
|
||||
|
||||
addr_list = []
|
||||
for addr, prefix, gateway in addresses:
|
||||
# TODO - look for a library function (could have used IPy but byte order!)
|
||||
# NOTE: There is IPy for python2, ipaddress for python3 but
|
||||
# byte order of dbus value would need to be switched
|
||||
if version == 4:
|
||||
addr_str = nm_dbus_int_to_ipv4(addr)
|
||||
gateway_str = nm_dbus_int_to_ipv4(gateway)
|
||||
@ -584,6 +604,10 @@ def _device_settings(name):
|
||||
settings = _find_settings(name, 'bond', 'interface-name')
|
||||
elif devtype == NetworkManager.DeviceType.VLAN:
|
||||
settings = _find_settings(name, 'vlan', 'interface-name')
|
||||
if not settings:
|
||||
# connections generated by NM from iBFT
|
||||
_parent, _sep, vlanid = name.partition(".")
|
||||
settings = _find_settings(int(vlanid), 'vlan', 'id')
|
||||
else:
|
||||
settings = _find_settings(name, 'connection', 'interface-name')
|
||||
if not settings:
|
||||
@ -796,6 +820,8 @@ def nm_activate_device_connection(dev_name, con_uuid):
|
||||
raise UnmanagedDeviceError(dev_name, e)
|
||||
elif "org.freedesktop.NetworkManager.UnknownConnection" in e.message:
|
||||
raise UnknownConnectionError(dev_name, e)
|
||||
if "org.freedesktop.NetworkManager.UnknownDevice" in e.message:
|
||||
raise UnknownDeviceError(dev_name, e)
|
||||
raise
|
||||
|
||||
def nm_add_connection(values):
|
||||
@ -823,7 +849,12 @@ def nm_add_connection(values):
|
||||
|
||||
proxy = _get_proxy(object_path="/org/freedesktop/NetworkManager/Settings",
|
||||
interface_name="org.freedesktop.NetworkManager.Settings")
|
||||
connection = proxy.AddConnection('(a{sa{sv}})', settings)
|
||||
try:
|
||||
connection = proxy.AddConnection('(a{sa{sv}})', settings)
|
||||
except GLib.GError as e:
|
||||
if "bond.options: invalid option" in e.message:
|
||||
raise BondOptionsError(e)
|
||||
raise
|
||||
return connection
|
||||
|
||||
def nm_delete_connection(uuid):
|
||||
@ -973,7 +1004,7 @@ def nm_ipv6_to_dbus_ay(address):
|
||||
:return: address in format 'ay' for NM dbus setting
|
||||
:rtype: list of bytes
|
||||
"""
|
||||
return [int(byte, 16) for byte in re.findall('.{1,2}', IPy.IP(address).strFullsize().replace(':', ''))]
|
||||
return [int(byte) for byte in bytearray(socket.inet_pton(socket.AF_INET6, address))]
|
||||
|
||||
def nm_ipv4_to_dbus_int(address):
|
||||
"""Convert ipv4 address from string to int for dbus (switched endianess).
|
||||
|
@ -23,6 +23,8 @@ Module facilitating the work with NTP servers and NTP daemon's configuration
|
||||
|
||||
"""
|
||||
|
||||
from __future__ import division
|
||||
|
||||
import re
|
||||
import os
|
||||
import tempfile
|
||||
@ -39,7 +41,10 @@ NTP_CONFIG_FILE = "/etc/chrony.conf"
|
||||
|
||||
#example line:
|
||||
#server 0.fedora.pool.ntp.org iburst
|
||||
SRV_LINE_REGEXP = re.compile(r"^\s*server\s*([-a-zA-Z.0-9]+)\s*[a-zA-Z]+\s*$")
|
||||
SRV_LINE_REGEXP = re.compile(r"^\s*(server|pool)\s*([-a-zA-Z.0-9]+)\s*[a-zA-Z]+\s*$")
|
||||
|
||||
#treat pools as four servers with the same name
|
||||
SERVERS_PER_POOL = 4
|
||||
|
||||
class NTPconfigError(Exception):
|
||||
"""Exception class for NTP related problems"""
|
||||
@ -72,6 +77,31 @@ def ntp_server_working(server):
|
||||
|
||||
return True
|
||||
|
||||
def pools_servers_to_internal(pools, servers):
|
||||
ret = []
|
||||
for pool in pools:
|
||||
ret.extend(SERVERS_PER_POOL * [pool])
|
||||
ret.extend(servers)
|
||||
|
||||
return ret
|
||||
|
||||
def internal_to_pools_and_servers(pools_servers):
|
||||
server_nums = dict()
|
||||
pools = []
|
||||
servers = []
|
||||
|
||||
for item in pools_servers:
|
||||
server_nums[item] = server_nums.get(item, 0) + 1
|
||||
|
||||
for item in server_nums.keys():
|
||||
if server_nums[item] >= SERVERS_PER_POOL:
|
||||
pools.extend((server_nums[item] // SERVERS_PER_POOL) * [item])
|
||||
servers.extend((server_nums[item] % SERVERS_PER_POOL) * [item])
|
||||
else:
|
||||
servers.extend(server_nums[item] * [item])
|
||||
|
||||
return (pools, servers)
|
||||
|
||||
def get_servers_from_config(conf_file_path=NTP_CONFIG_FILE,
|
||||
srv_regexp=SRV_LINE_REGEXP):
|
||||
"""
|
||||
@ -83,29 +113,34 @@ def get_servers_from_config(conf_file_path=NTP_CONFIG_FILE,
|
||||
|
||||
"""
|
||||
|
||||
ret = list()
|
||||
pools = list()
|
||||
servers = list()
|
||||
|
||||
try:
|
||||
with open(conf_file_path, "r") as conf_file:
|
||||
for line in conf_file:
|
||||
match = srv_regexp.match(line)
|
||||
if match:
|
||||
ret.append(match.group(1))
|
||||
if match.group(1) == "pool":
|
||||
pools.append(match.group(2))
|
||||
else:
|
||||
servers.append(match.group(2))
|
||||
|
||||
except IOError as ioerr:
|
||||
msg = "Cannot open config file %s for reading (%s)" % (conf_file_path,
|
||||
ioerr.strerror)
|
||||
raise NTPconfigError(msg)
|
||||
|
||||
return ret
|
||||
return (pools, servers)
|
||||
|
||||
def save_servers_to_config(servers, conf_file_path=NTP_CONFIG_FILE,
|
||||
def save_servers_to_config(pools, servers, conf_file_path=NTP_CONFIG_FILE,
|
||||
srv_regexp=SRV_LINE_REGEXP, out_file_path=None):
|
||||
"""
|
||||
Replaces the servers defined in the chronyd's configuration file with
|
||||
the given ones. If the out_file is not None, then it is used for the
|
||||
Replaces the pools and servers defined in the chronyd's configuration file
|
||||
with the given ones. If the out_file is not None, then it is used for the
|
||||
resulting config.
|
||||
|
||||
:type pools: iterable
|
||||
:type servers: iterable
|
||||
:param out_file_path: path to the file used for the resulting config
|
||||
|
||||
@ -141,7 +176,10 @@ def save_servers_to_config(servers, conf_file_path=NTP_CONFIG_FILE,
|
||||
#write info about the origin of the following lines
|
||||
new_conf_file.write(heading)
|
||||
|
||||
#write new servers
|
||||
#write new servers and pools
|
||||
for pool in pools:
|
||||
new_conf_file.write("pool " + pool + " iburst\n")
|
||||
|
||||
for server in servers:
|
||||
new_conf_file.write("server " + server + " iburst\n")
|
||||
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user