[f21-branch][PATCH] clean up stage1 volume check, check format as well as mountpoint
by Adam Williamson
This is a follow-on from e2d10a04. To reduce the change from
the previous behaviour and minimize the chance of any strange
corner-case breakage, this sorts the disk list, rather than
filtering it.
It also now checks the format_type constraint as well as the
mountpoint constraint. There are platforms (PPC) which use a
volume as the stage1 target, but don't require it to be mounted;
this handles those as well as platforms which require the target
volume to be mounted to a specific location.
It's also slightly re-arranged to flow better with the existing
check that filters out protected, hidden and unusable disks.
The overall behaviour change can be described as: on platforms
which require the stage1 target to be a volume, use the first
enumerated disk which contains a potentially valid volume as
the 'boot disk' if the user does not explicitly specify one,
rather than just using the first enumerated disk and failing
if it does not contain a valid stage1 target volume (#1168118).
This also debug logs the result of the 'disks with potential
stage1 targets' check.
---
pyanaconda/kickstart.py | 36 ++++++++++++++++++++++--------------
1 file changed, 22 insertions(+), 14 deletions(-)
diff --git a/pyanaconda/kickstart.py b/pyanaconda/kickstart.py
index d44b349..4aa4fd8 100644
--- a/pyanaconda/kickstart.py
+++ b/pyanaconda/kickstart.py
@@ -379,22 +379,30 @@ class Bootloader(commands.bootloader.F21_Bootloader):
if self.timeout is not None:
storage.bootloader.timeout = self.timeout
- # try to reduce the set of possible 'boot disks' to the disks containing
- # a valid stage1 mount point, if there are any, because those disks
- # should be searched for a stage1_valid device
- disks = storage.disks
- if platform.bootStage1ConstraintDict["mountpoints"]:
- disks = [p.disk for p in storage.devices if getattr(p.format, "mountpoint", None) in platform.bootStage1ConstraintDict["mountpoints"]]
- if not disks:
- # but if not, just go ahead and use the set of all disks or
- # else we'll error out later
- disks = storage.disks
-
# Throw out drives specified that don't exist or cannot be used (iSCSI
# device on an s390 machine)
- disk_names = [d.name for d in disks
- if not d.format.hidden and not d.protected and
- (not blivet.arch.isS390() or not isinstance(d, blivet.devices.iScsiDiskDevice))]
+ disks = [d for d in storage.disks
+ if not d.format.hidden and not d.protected and
+ (not blivet.arch.isS390() or not isinstance(d, blivet.devices.iScsiDiskDevice))]
+ if platform.bootStage1ConstraintDict["format_types"]:
+ # sort the list of disks with those that contain possibly-valid
+ # stage1 partitions first, so we'll pick a disk with one as
+ # bootDrive if it has not been explicitly set: RHBZ #1168118
+ s1vols = [vol for vol in storage.devices if
+ getattr(vol.format, "type", None) in
+ platform.bootStage1ConstraintDict["format_types"]]
+ if platform.bootStage1ConstraintDict["mountpoints"]:
+ # further sort by volumes with valid mount points, if
+ # the platform requires this
+ s1disks = [vol.disk for vol in s1vols if
+ getattr(vol.format, "mountpoint", None) in
+ platform.bootStage1ConstraintDict["mountpoints"]]
+ else:
+ s1disks = [vol.disk for vol in s1vols]
+ log.debug("Disks with potentially valid stage1 volumes: %s",
+ ' '.join([d.name for d in s1disks]))
+ disks.sort(key=lambda x: x in s1disks, reverse=True)
+ disk_names = [d.name for d in disks]
diskSet = set(disk_names)
for drive in self.driveorder[:]:
--
2.1.0
9 years, 2 months
Re: [PATCH 1/1] network: Overwrite resolv.conf generated by systemd
by Brian C. Lane
On Sun, Feb 22, 2015 at 02:45:13PM -0500, Colin Walters wrote:
> From: Colin Walters <walters(a)verbum.org>
>
> systemd changed to generate a symlink resolv.conf ->
> /run/networkd/resolv.conf which doesn't exist at installation time.
systemd needs to not create a broken symlink. Especially for a feature
that, AFAIK, isn't used in Fedora.
--
Brian C. Lane | Anaconda Team | IRC: bcl #anaconda | Port Orchard, WA (PST8PDT)
9 years, 2 months
[master] Move autopart and installation-specific code to separate blivet submodules
by Vratislav Podzimek
That code doesn't belong to the __init__.py module.
Vratislav Podzimek (1):
Move autopart and installation-specific code outside of __init__.py
blivet/__init__.py | 1010 +------------------------------------------
blivet/autopart.py | 483 +++++++++++++++++++++
blivet/devicelibs/swap.py | 67 ---
blivet/osinstall.py | 1035 +++++++++++++++++++++++++++++++++++++++++++++
blivet/partitioning.py | 386 +----------------
5 files changed, 1530 insertions(+), 1451 deletions(-)
create mode 100644 blivet/autopart.py
create mode 100644 blivet/osinstall.py
--
2.1.0
9 years, 2 months
[PATCH] Add a script to rebase and merge pull requests
by David Shea
This is both a tool for avoiding merge commits and something to point at
later when we decide that maybe merge commits aren't so bad in github's
contribution model.
---
scripts/merge-pr | 279 +++++++++++++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 279 insertions(+)
create mode 100644 scripts/merge-pr
diff --git a/scripts/merge-pr b/scripts/merge-pr
new file mode 100644
index 0000000..a307334
--- /dev/null
+++ b/scripts/merge-pr
@@ -0,0 +1,279 @@
+#!/usr/bin/python2
+#
+# merge-pr - Rebase, merge, and close a github pull request
+#
+# 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(a)redhat.com>
+
+# A quick note on logging in to github:
+# This script uses git's credentials API for retrieving and possibly storing
+# your github user name and password. Git comes with credential-cache, which
+# stores information in memory, and credential-store, which stores information
+# in a file in your home directory. Use `git config credential.helper <helper>'
+# if you want to use one of these. See the git help pages for credential-cache
+# and credential-store for more information, and also see the help pages for
+# 'credentials' for information on how to change the thing that asks for your
+# password.
+#
+# You can use an OAuth token in place of your username and password. Create a
+# personal access token using https://github.com/settings/tokens/new, input
+# "token" as your username and put in the token as your password. Github only
+# shows you these tokens once, so OAuth makes the most sense when combined with
+# a credential helper that permanently stores your passwords. The token only
+# needs access to the public_repo scope.
+#
+# If you use 2-factor authentication and do not use an OAuth token, you will
+# be asked for your 2-factor code three times.
+#
+# Use the --nosavepw option if you don't want to try saving your credentials
+# with git.
+
+# This script expects there to be local branches that match the names of
+# the remote branches the pull request is against. So if there's a pull
+# request against f22-branch but you don't have f22-branch locally, it won't
+# work.
+
+import argparse
+import subprocess
+import sys
+import os
+import re
+import atexit
+import json
+from tempfile import NamedTemporaryFile
+
+import requests
+import six
+
+DEVNULL = open(os.devnull, 'w')
+
+def talk_to_github(request):
+ # Send a requests.Request to github, handle 2-factor auth
+ request.headers.update({'User-Agent': 'merge-pr'})
+
+ prep = request.prepare()
+ session = requests.Session()
+ response = session.send(prep)
+
+ # github sometimes uses 404 in response to unauthenticated API calls
+ if response.status_code in (401, 404) and \
+ response.headers.get('X-GitHub-OTP', '').startswith('required'):
+ try:
+ twofactor = raw_input("Input 2-factor authentication code: ")
+ except EOFError:
+ twofactor = ""
+
+ request.headers.update({'X-GitHub-OTP': twofactor})
+ prep = request.prepare()
+ response = session.send(prep)
+
+ if response.status_code not in (200, 201):
+ print("Error communicating with github: %s\n%s" % (response.status_code, response.text))
+ sys.exit(1)
+
+ return response
+
+def main():
+ parser = argparse.ArgumentParser(description='Github pull request merger')
+
+ parser.add_argument('--nosavepw', action='store_true', default=False,
+ help='Do not attempt to save the github user name and password')
+ parser.add_argument('pr_url', metavar='URL', help='Pull request URL to merge')
+
+ args = parser.parse_args()
+
+ # SANITY CHECK: are we in a git repo? We need to be in a git repo.
+ # Git's error message is probably good enough if something went wrong.
+ if subprocess.call(['git', 'rev-parse']) != 0:
+ sys.exit(1)
+
+ # Parse the web URL into something that can be used for an API call, make
+ # sure all the pieces are there.
+ pr_url = six.moves.urllib.parse.urlparse(args.pr_url)
+ # The path should be /:owner/:repo/pull/:numbero
+ # The first part of the split will be empty since path starts with /
+ pr_path = pr_url[2].split('/')
+ if len(pr_path) != 5 or pr_path[3] != 'pull' or not pr_path[4].isdigit():
+ print("Unable to parse pull request URL")
+ sys.exit(1)
+
+ pr_owner = pr_path[1]
+ pr_repo = pr_path[2]
+ pr_number = pr_path[4]
+
+ # Figure out where we are in the current repo so we can go back to it
+ try:
+ current_head = subprocess.check_output(['git', 'symbolic-ref', '-q', '--short', 'HEAD'])
+ except subprocess.CalledProcessError:
+ try:
+ current_head = subprocess.check_output(['git', 'rev-parse', 'HEAD'])
+ except subprocess.CalledProcessError:
+ # There's probably a ton of error output from git by now, so just exit
+ sys.exit(1)
+
+ current_head = current_head.rstrip('\n')
+ atexit.register(lambda: subprocess.call(['git', 'checkout', '-q', current_head]))
+
+ # Time to get a password so we can start talking to github
+ github_cred = 'protocol=https\nhost=api.github.com\n'
+ try:
+ p = subprocess.Popen(['git', 'credential', 'fill'], stdin=subprocess.PIPE, stdout=subprocess.PIPE)
+ p.stdin.write(github_cred)
+ (stdin, _stderr) = p.communicate()
+ except (OSError, IOError) as e:
+ print("Unable to get github credentials: %s" % e)
+ sys.exit(1)
+
+ # Parse the username and password
+ m = re.search('^username=(.*)$', stdin, flags=re.MULTILINE)
+ if not m:
+ print("Unable to determine github username")
+ sys.exit(1)
+ username = m.group(1)
+
+ m = re.search('^password=(.*)$', stdin, flags=re.MULTILINE)
+ if not m:
+ print("Unable to determine github password")
+ sys.exit(1)
+ password = m.group(1)
+
+ # If using a OAuth token, rearrange the auth data to let github know we're
+ # sending a token as a basic http auth
+ if username == "token":
+ username = password
+ password = "x-oauth-basic"
+
+ # Save the username and password back to git
+ if not args.nosavepw:
+ try:
+ p = subprocess.Popen(['git', 'credential', 'approve'], stdin=subprocess.PIPE)
+ p.stdin.write(stdin)
+ p.communicate()
+ except (OSError, IOError) as e:
+ print("Unable to save github credentials: %s" % e)
+ sys.exit(1)
+
+ # Now to talk to github. First, get the PR object
+ pr_req = requests.Request(method='GET',
+ url='https://api.github.com/repos/%s/%s/pulls/%s' % (pr_owner, pr_repo, pr_number),
+ auth=(username, password))
+ pr = talk_to_github(pr_req).json()
+
+ # If github reports the PR is not mergeable, give up now
+ if not pr['mergeable']:
+ print("Pull request is not mergeable, exiting")
+ sys.exit(1)
+
+ # Start messing with the git repo
+
+ # Try checking out the base of the PR. If it isn't available, do a fetch of
+ # the base repo and try again.
+ try:
+ subprocess.check_call(['git', 'checkout', '-q', pr['base']['sha']], stderr=DEVNULL)
+ except subprocess.CalledProcessError:
+ try:
+ subprocess.check_call(['git', 'fetch', '-q', pr['base']['repo']['clone_url'], pr['base']['sha']])
+ subprocess.check_call(['git', 'checkout', '-q', pr['base']['sha']])
+ except subprocess.CalledProcessError:
+ sys.exit(1)
+
+ try:
+ branch_name = 'merge-pr-%s-%s' % (pr['head']['user']['login'], pr['head']['ref'])
+ # Create a branch for the PR and pull the data into it
+ subprocess.check_call(['git', 'checkout', '-q', '-b', branch_name])
+ subprocess.check_call(['git', 'pull', '-q', '--ff-only', pr['head']['repo']['clone_url'], pr['head']['sha']])
+
+ # Rebase the PR to the current state of the target branch
+ subprocess.check_call(['git', 'rebase', '-q', pr['base']['ref']])
+
+ # Merge the PR onto the target branch and delete the PR branch
+ subprocess.check_call(['git', 'checkout', '-q', pr['base']['ref']])
+ subprocess.check_call(['git', 'merge', '-q', '--ff-only', branch_name])
+ subprocess.check_call(['git', 'branch', '-q', '-d', branch_name])
+
+ # Before we push, launch an editor for the message to use when closing
+ # the pull request
+ try:
+ editor = subprocess.check_call(['git', 'config', '--get', 'core.editor'])
+ except subprocess.CalledProcessError:
+ if 'VISUAL' in os.environ:
+ editor = os.environ['VISUAL']
+ elif 'EDITOR' in os.environ:
+ editor = os.environ['EDITOR']
+ else:
+ editor = 'vi'
+
+ with NamedTemporaryFile() as pr_msg_file:
+ # Display some information about what the merge being pushed will
+ # be, and list the commits
+ commit_list = subprocess.check_output(['git', 'log', pr['base']['ref'],
+ '--not', '--remotes=*/%s' % pr['base']['ref'], '--pretty=format:%h %s'])
+ commit_list = '\n'.join('# %s' % line for line in commit_list.splitlines())
+ pr_msg_file.write("""
+# Please enter the message with which to close the pull request. Lines
+# starting with '#' will be ignored, and an empty message aborts the merge.
+# The merged pull request will remain in your working copy under the
+# '%s' branch.
+#
+# Pull request to merge: %s/%s/%s (%s)
+# into -> %s
+#
+%s
+""" % (pr['base']['ref'],
+ pr_owner, pr_repo, pr_number, pr['head']['label'],
+ subprocess.check_output(['git', 'rev-parse', '--abbrev-ref', '@{upstream}']).rstrip('\n'),
+ commit_list))
+
+ pr_msg_file.flush()
+ subprocess.check_call([editor, pr_msg_file.name])
+ pr_msg_file.seek(0)
+
+ # Strip comments and whitespace
+ pr_msg = ''.join(line for line in pr_msg_file if not line.startswith('#')).strip()
+
+ # Done with the message file at this point
+ # If the message is empty, abort
+ if not pr_msg:
+ print("Empty pull request message, aborting")
+ sys.exit(1)
+
+ # Push the commits
+ subprocess.check_call(['git', 'push', '-q'])
+
+ # Add a comment to the PR
+ pr_comment = requests.Request(method='POST',
+ url='https://api.github.com/repos/%s/%s/issues/%s/comments' % (pr_owner, pr_repo, pr_number),
+ data=json.dumps({'body': pr_msg}),
+ auth=(username, password))
+ talk_to_github(pr_comment)
+
+ # Close the PR
+ pr_close = requests.Request(method='PATCH',
+ url='https://api.github.com/repos/%s/%s/pulls/%s' % (pr_owner, pr_repo, pr_number),
+ data=json.dumps({'state': 'closed'}),
+ auth=(username, password))
+ talk_to_github(pr_close)
+
+ except subprocess.CalledProcessError:
+ sys.exit(1)
+
+if __name__ == "__main__":
+ try:
+ main()
+ except KeyboardInterrupt:
+ print("Exiting on user interrupt")
+ sys.exit(1)
--
2.1.0
9 years, 2 months
[pyparted] Two Python3-incompatible issues
by Vratislav Podzimek
With these changes and python3-pyparted installed, blivet tests using pyparted
work with Python 3. Whoohooo!
Vratislav Podzimek (2):
Replace filter() call with list comprehension
Don't blindly expect that everything is hashable
src/parted/alignment.py | 9 ++++++---
src/parted/cachedlist.py | 3 +++
src/parted/device.py | 9 ++++++---
src/parted/disk.py | 11 +++++++----
src/parted/filesystem.py | 9 ++++++---
src/parted/geometry.py | 9 ++++++---
src/parted/partition.py | 9 ++++++---
7 files changed, 40 insertions(+), 19 deletions(-)
--
2.1.0
9 years, 2 months
[PATCH/RHEL6-Branch] RHEL6 Basic Video Driver Install to Windows2012 VM Fails (#1083586)
by Robert Marshall
Installing RHEL on a windows 2012 Hypervisor using the
basic video driver causes a boot failure and x-server
crash. The issue pertains to anaconda forcing a set
to vesa after the X-server has already arranged the
fallback drivers so that fbdev loads before vesa. Patch
courtesy of Adam Jackson <ajax(a)redhat.com>.
Resolves: rhbz#1083586
---
bootdisk/i386/syslinux.cfg | 2 +-
bootdisk/x86_64/grub.conf | 2 +-
bootdisk/x86_64/syslinux.cfg | 2 +-
3 files changed, 3 insertions(+), 3 deletions(-)
diff --git a/bootdisk/i386/syslinux.cfg b/bootdisk/i386/syslinux.cfg
index f0e4046..f396169 100644
--- a/bootdisk/i386/syslinux.cfg
+++ b/bootdisk/i386/syslinux.cfg
@@ -23,7 +23,7 @@ label linux
label vesa
menu label Install system with ^basic video driver
kernel vmlinuz
- append initrd=initrd.img xdriver=vesa nomodeset
+ append initrd=initrd.img nomodeset
label rescue
menu label ^Rescue installed system
kernel vmlinuz
diff --git a/bootdisk/x86_64/grub.conf b/bootdisk/x86_64/grub.conf
index 3059df4..a2895ee 100644
--- a/bootdisk/x86_64/grub.conf
+++ b/bootdisk/x86_64/grub.conf
@@ -7,7 +7,7 @@ title @PRODUCT@ @VERSION@
kernel @KERNELPATH@
initrd @INITRDPATH@
title Install system with basic video driver
- kernel @KERNELPATH@ xdriver=vesa nomodeset askmethod
+ kernel @KERNELPATH@ nomodeset askmethod
initrd @INITRDPATH@
title rescue
kernel @KERNELPATH@ rescue askmethod
diff --git a/bootdisk/x86_64/syslinux.cfg b/bootdisk/x86_64/syslinux.cfg
index f0e4046..f396169 100644
--- a/bootdisk/x86_64/syslinux.cfg
+++ b/bootdisk/x86_64/syslinux.cfg
@@ -23,7 +23,7 @@ label linux
label vesa
menu label Install system with ^basic video driver
kernel vmlinuz
- append initrd=initrd.img xdriver=vesa nomodeset
+ append initrd=initrd.img nomodeset
label rescue
menu label ^Rescue installed system
kernel vmlinuz
--
1.8.3.1
9 years, 2 months
[anaconda][master/rhel7-branch/f22-branch] install.py: fix the 'is team device' check
by Adam Williamson
It's a method, not an attribute. We were only checking if the
method existed. This caused teamd to always be pulled in.
---
pyanaconda/install.py | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/pyanaconda/install.py b/pyanaconda/install.py
index a68e793..a0c6f7f 100644
--- a/pyanaconda/install.py
+++ b/pyanaconda/install.py
@@ -216,7 +216,7 @@ def doInstall(storage, payload, ksdata, instClass):
if willInstallBootloader:
packages += storage.bootloader.packages
- if network.is_using_team_device:
+ if network.is_using_team_device():
packages.append("teamd")
# don't try to install packages from the install class' ignored list and the
--
2.3.0
9 years, 2 months
[PATCH] fix inst.ks.sendmac for static ip=XXX (#826657)
by Will Woods
inst.ks.sendmac is supposed to make us send HTTP headers of the form:
X-RHN-Provisioning-MAC-1: <MAC ADDRESS OF NIC #1>
X-RHN-Provisioning-MAC-2: <MAC ADDRESS OF NIC #2>
[...]
along with the kickstart request.
This implies that we have to wait until after all modules are loaded
(i.e. all the NICs are visible) before we can add these headers and send
the kickstart request. So commit 35a93dd moved the header setup bit to
the `initqueue/settled` hook.
It turns out there's a race here: the actual kickstart fetch happens in
the `initqueue/online` hook, which runs as soon as a NIC comes online.
If you're using DHCP it takes a few network roundtrips before a NIC is
considered 'online', so this usually happens after udev is settled.
But: with a static IP config your NIC might be 'online' before udev is
settled. Which means we haven't set up the HTTP headers yet, and they
don't get sent.
This commit makes fetch-kickstart-net.sh actually just *schedule* the
kickstart to be fetched in the initqueue:
* if inst.ks.sendmac is enabled, it goes into initqueue/settled (where
it will happen after anaconda-ks-sendheaders.sh because they run in
alphanumeric order).
* otherwise, it is added to the normal initqueue, where it will run in
the next pass of the loop.
NOTE: it could be argued that we should move *any* HTTP operations after
anaconda-ks-sendheaders.sh, but AFAICT the documentation only specifies
that the request for the *kickstart* will contain these headers.
Resolves: rhbz#826657
---
dracut/fetch-kickstart-net.sh | 12 ++++++++++++
1 file changed, 12 insertions(+)
diff --git a/dracut/fetch-kickstart-net.sh b/dracut/fetch-kickstart-net.sh
index 4ec073b..f26ab25 100755
--- a/dracut/fetch-kickstart-net.sh
+++ b/dracut/fetch-kickstart-net.sh
@@ -41,6 +41,16 @@ case "$kickstart" in
nfs*/) kickstart="${kickstart}${new_ip_address}-kickstart" ;;
esac
+# If we're doing sendmac, we need to run after anaconda-ks-sendheaders.sh
+if getargbool 0 inst.ks.sendmac kssendmac; then
+ newjob=$hookdir/initqueue/settled/fetch-ks-${netif}.sh
+else
+ newjob=$hookdir/initqueue/fetch-ks-${netif}.sh
+fi
+
+cat > $newjob <<__EOT__
+. /lib/url-lib.sh
+. /lib/anaconda-lib.sh
info "anaconda fetching kickstart from $kickstart"
if fetch_url "$kickstart" /tmp/ks.cfg; then
parse_kickstart /tmp/ks.cfg
@@ -48,3 +58,5 @@ if fetch_url "$kickstart" /tmp/ks.cfg; then
else
warn "failed to fetch kickstart from $kickstart"
fi
+rm \$job # remove self from initqueue
+__EOT__
--
2.1.0
9 years, 2 months