Merge lp:~lool/linaro-image-tools/optional-sudo into lp:linaro-image-tools/11.11

Proposed by Loïc Minier
Status: Merged
Merged at revision: 279
Proposed branch: lp:~lool/linaro-image-tools/optional-sudo
Merge into: lp:linaro-image-tools/11.11
Diff against target: 160 lines (+37/-21)
4 files modified
linaro-hwpack-install (+11/-6)
linaro-media-create (+15/-11)
linaro_media_create/cmd_runner.py (+3/-3)
linaro_media_create/tests/test_media_create.py (+8/-1)
To merge this branch: bzr merge lp:~lool/linaro-image-tools/optional-sudo
Reviewer Review Type Date Requested Status
James Westby (community) Approve
Review via email: mp+47907@code.launchpad.net
To post a comment you must log in.
Revision history for this message
James Westby (james-w) wrote :

Hi,

I like the change, but it would be good to have a test if possible.

Thanks,

James

review: Approve
276. By Loïc Minier

Mock getuid() when testing cmd_runner and test both the sudo needed and sudo
not needed cases.

Revision history for this message
Loïc Minier (lool) wrote :

I update the cmd_runner tests in r276 now; I realize that we ought to change the whole testsuite to assume "regular user" (getuid() != 0), but changing the Popen mock class to mock os.getuid() required changing the MockSomething fixture in non-trivial ways, so I'd like to consult with salgado on doing this nicely.

We could either change cmd_runner to take a force_sudo/never_sudo flag if that's useful, or we could have a new type of mock class which allows mocking many things; in fact, I had started such a class a while ago, but it's not trivial to make something generic and elegant, notably distinguishing between args you want to mock as non-existent (delattr()) versus args you want to mock to None (setattr(None)). We'd need a slightly more complex interface that I'm comfortable to add without him.

Revision history for this message
Guilherme Salgado (salgado) wrote :

It's not clear to me why we ought to change the whole testsuite to assume "regular user". Is it because when building a package the tests will be executed as root and that would now cause the ones that use cmd_runner.Popen() to fail?

Revision history for this message
Loïc Minier (lool) wrote :

When building a package, the tests will be run as a regular user; perhaps under fakeroot, I didn't check.

But I think the uid of the calling user shouldn't matter, we should build the testsuite to work whatever the uid. I'm proposing we change the testsuite to setup things so that it looks like a regular user is running it so that we get the chance to include sudo in the expect commands; that way, we include the "this piece needs to be run as root" information in all the Popen tests.

So I'm suggesting that whatever the calling user, we should divert getuid() to return non-zero, and we should expect commands to look like:
[sudo command-requiring-root,
command-not-requiring-root]
etc.

Revision history for this message
Loïc Minier (lool) wrote :

I just found a stronger argument for avoiding sudo: this allows strace-ing the whole of linaro-media-create: first become root, then strace. strace doesn't work across sudo because it's setuid.

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
=== modified file 'linaro-hwpack-install'
--- linaro-hwpack-install 2011-01-28 19:50:48 +0000
+++ linaro-hwpack-install 2011-01-29 19:21:18 +0000
@@ -38,6 +38,11 @@
38APT_GET_OPTIONS="Dir::Etc::SourceList=${SOURCES_LIST_FILE}"38APT_GET_OPTIONS="Dir::Etc::SourceList=${SOURCES_LIST_FILE}"
39SUPPORTED_FORMATS="1.0" # A space-separated list of hwpack formats.39SUPPORTED_FORMATS="1.0" # A space-separated list of hwpack formats.
4040
41sudo="sudo"
42if [ $(id -u) -eq 0 ]; then
43 sudo=""
44fi
45
41die() {46die() {
42 echo -e "$@"47 echo -e "$@"
43 exit 148 exit 1
@@ -79,7 +84,7 @@
79 # Ensure our temp dir and apt sources are removed.84 # Ensure our temp dir and apt sources are removed.
80 echo -n "Cleaning up ..."85 echo -n "Cleaning up ..."
81 rm -rf $TEMP_DIR86 rm -rf $TEMP_DIR
82 sudo apt-get update -qq87 $sudo apt-get update -qq
83 echo "Done"88 echo "Done"
84}89}
8590
@@ -128,14 +133,14 @@
128 done < $stripped_file133 done < $stripped_file
129134
130 if [ $should_install -eq 1 ]; then135 if [ $should_install -eq 1 ]; then
131 sudo cp $file /etc/apt/sources.list.d/hwpack.$filename136 $sudo cp $file /etc/apt/sources.list.d/hwpack.$filename
132 fi137 fi
133done138done
134139
135# Import the OpenPGP keys for the files installed above.140# Import the OpenPGP keys for the files installed above.
136for filename in $(ls "${HWPACK_DIR}"/sources.list.d.gpg/); do141for filename in $(ls "${HWPACK_DIR}"/sources.list.d.gpg/); do
137 file="${HWPACK_DIR}"/sources.list.d.gpg/$filename142 file="${HWPACK_DIR}"/sources.list.d.gpg/$filename
138 sudo apt-key add $file143 $sudo apt-key add $file
139done144done
140145
141# Add one extra apt source for the packages included in the hwpack and make146# Add one extra apt source for the packages included in the hwpack and make
@@ -145,7 +150,7 @@
145cat /etc/apt/sources.list >> "$SOURCES_LIST_FILE"150cat /etc/apt/sources.list >> "$SOURCES_LIST_FILE"
146151
147echo "Updating apt package lists ..."152echo "Updating apt package lists ..."
148sudo apt-get -o "$APT_GET_OPTIONS" update -q153$sudo apt-get -o "$APT_GET_OPTIONS" update -q
149154
150echo -n "Installing packages ..."155echo -n "Installing packages ..."
151156
@@ -199,11 +204,11 @@
199 done204 done
200fi205fi
201206
202sudo apt-get $FORCE_OPTIONS -o "$APT_GET_OPTIONS" install ${packages}207$sudo apt-get $FORCE_OPTIONS -o "$APT_GET_OPTIONS" install ${packages}
203208
204if [ "$DEP_PACKAGE_PRESENT" == "yes" ]; then209if [ "$DEP_PACKAGE_PRESENT" == "yes" ]; then
205 if [ -n "${to_be_installed}" ]; then210 if [ -n "${to_be_installed}" ]; then
206 sudo apt-get $FORCE_OPTIONS -o "$APT_GET_OPTIONS" markauto ${to_be_installed}211 $sudo apt-get $FORCE_OPTIONS -o "$APT_GET_OPTIONS" markauto ${to_be_installed}
207 fi212 fi
208fi213fi
209214
210215
=== modified file 'linaro-media-create'
--- linaro-media-create 2011-01-28 19:50:48 +0000
+++ linaro-media-create 2011-01-29 19:21:18 +0000
@@ -22,7 +22,6 @@
22import os22import os
23import sys23import sys
24import tempfile24import tempfile
25from subprocess import Popen
2625
27from linaro_media_create.boards import (26from linaro_media_create.boards import (
28 board_configs,27 board_configs,
@@ -42,7 +41,10 @@
42 ensure_command,41 ensure_command,
43 is_arm_host,42 is_arm_host,
44 )43 )
45from linaro_media_create import get_args_parser44from linaro_media_create import (
45 cmd_runner,
46 get_args_parser
47 )
4648
47# Just define the global variables49# Just define the global variables
48TMP_DIR = None50TMP_DIR = None
@@ -60,18 +62,20 @@
60 Before doing so, make sure BOOT_DISK and ROOT_DISK are not mounted.62 Before doing so, make sure BOOT_DISK and ROOT_DISK are not mounted.
61 """63 """
62 devnull = open('/dev/null', 'w')64 devnull = open('/dev/null', 'w')
63 # Use raw subprocess.Popen as we don't want to stop in case the65 # ignore non-zero return codes
64 # commands end with a non-zero return code.66 try:
65 if BOOT_DISK is not None:67 if BOOT_DISK is not None:
66 Popen(['sudo', 'umount', BOOT_DISK],68 cmd_runner.Popen(['umount', BOOT_DISK],
67 stdout=devnull, stderr=devnull).wait()69 stdout=devnull, stderr=devnull, as_root=True).wait()
68 if ROOT_DISK is not None:70 if ROOT_DISK is not None:
69 Popen(['sudo', 'umount', ROOT_DISK],71 cmd_runner.Popen(['umount', ROOT_DISK],
70 stdout=devnull, stderr=devnull).wait()72 stdout=devnull, stderr=devnull, as_root=True).wait()
73 except SubcommandNonZeroReturnValue:
74 pass
71 # Remove TMP_DIR as root because some files written there are75 # Remove TMP_DIR as root because some files written there are
72 # owned by root.76 # owned by root.
73 if TMP_DIR is not None:77 if TMP_DIR is not None:
74 Popen(['sudo', 'rm', '-rf', TMP_DIR]).wait()78 cmd_runner.Popen(['rm', '-rf', TMP_DIR], as_root=True).wait()
7579
7680
77def ensure_required_commands(args):81def ensure_required_commands(args):
7882
=== modified file 'linaro_media_create/cmd_runner.py'
--- linaro_media_create/cmd_runner.py 2011-01-28 19:50:48 +0000
+++ linaro_media_create/cmd_runner.py 2011-01-29 19:21:18 +0000
@@ -37,10 +37,10 @@
37 """37 """
38 assert isinstance(args, (list, tuple)), (38 assert isinstance(args, (list, tuple)), (
39 "The command to run must be a list or tuple, found: %s" % type(args))39 "The command to run must be a list or tuple, found: %s" % type(args))
40 # TODO: We might want to always use 'sudo -E' here to avoid problems like40 if as_root and os.getuid() != 0:
41 # https://launchpad.net/bugs/673570
42 if as_root:
43 args = args[:]41 args = args[:]
42 # TODO: We might want to always use 'sudo -E' here to avoid problems
43 # like https://launchpad.net/bugs/673570
44 args.insert(0, 'sudo')44 args.insert(0, 'sudo')
45 return Popen(args, stdin=stdin, stdout=stdout, stderr=stderr)45 return Popen(args, stdin=stdin, stdout=stdout, stderr=stderr)
4646
4747
=== modified file 'linaro_media_create/tests/test_media_create.py'
--- linaro_media_create/tests/test_media_create.py 2011-01-28 19:50:48 +0000
+++ linaro_media_create/tests/test_media_create.py 2011-01-29 19:21:18 +0000
@@ -412,11 +412,18 @@
412 self.assertEqual(0, proc.returncode)412 self.assertEqual(0, proc.returncode)
413 self.assertEqual([['foo', 'bar', 'baz']], fixture.mock.calls)413 self.assertEqual([['foo', 'bar', 'baz']], fixture.mock.calls)
414414
415 def test_run_as_root(self):415 def test_run_as_root_with_sudo(self):
416 fixture = self.useFixture(MockCmdRunnerPopenFixture())416 fixture = self.useFixture(MockCmdRunnerPopenFixture())
417 self.useFixture(MockSomethingFixture(os, 'getuid', lambda: 1000))
417 cmd_runner.run(['foo', 'bar'], as_root=True).wait()418 cmd_runner.run(['foo', 'bar'], as_root=True).wait()
418 self.assertEqual([['sudo', 'foo', 'bar']], fixture.mock.calls)419 self.assertEqual([['sudo', 'foo', 'bar']], fixture.mock.calls)
419420
421 def test_run_as_root_as_root(self):
422 fixture = self.useFixture(MockCmdRunnerPopenFixture())
423 self.useFixture(MockSomethingFixture(os, 'getuid', lambda: 0))
424 cmd_runner.run(['foo', 'bar'], as_root=True).wait()
425 self.assertEqual([['foo', 'bar']], fixture.mock.calls)
426
420 def test_run_succeeds_on_zero_return_code(self):427 def test_run_succeeds_on_zero_return_code(self):
421 proc = cmd_runner.run(['true'])428 proc = cmd_runner.run(['true'])
422 # Need to wait() here as we're using the real Popen.429 # Need to wait() here as we're using the real Popen.

Subscribers

People subscribed via source and target branches