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
1=== modified file 'linaro-hwpack-install'
2--- linaro-hwpack-install 2011-01-28 19:50:48 +0000
3+++ linaro-hwpack-install 2011-01-29 19:21:18 +0000
4@@ -38,6 +38,11 @@
5 APT_GET_OPTIONS="Dir::Etc::SourceList=${SOURCES_LIST_FILE}"
6 SUPPORTED_FORMATS="1.0" # A space-separated list of hwpack formats.
7
8+sudo="sudo"
9+if [ $(id -u) -eq 0 ]; then
10+ sudo=""
11+fi
12+
13 die() {
14 echo -e "$@"
15 exit 1
16@@ -79,7 +84,7 @@
17 # Ensure our temp dir and apt sources are removed.
18 echo -n "Cleaning up ..."
19 rm -rf $TEMP_DIR
20- sudo apt-get update -qq
21+ $sudo apt-get update -qq
22 echo "Done"
23 }
24
25@@ -128,14 +133,14 @@
26 done < $stripped_file
27
28 if [ $should_install -eq 1 ]; then
29- sudo cp $file /etc/apt/sources.list.d/hwpack.$filename
30+ $sudo cp $file /etc/apt/sources.list.d/hwpack.$filename
31 fi
32 done
33
34 # Import the OpenPGP keys for the files installed above.
35 for filename in $(ls "${HWPACK_DIR}"/sources.list.d.gpg/); do
36 file="${HWPACK_DIR}"/sources.list.d.gpg/$filename
37- sudo apt-key add $file
38+ $sudo apt-key add $file
39 done
40
41 # Add one extra apt source for the packages included in the hwpack and make
42@@ -145,7 +150,7 @@
43 cat /etc/apt/sources.list >> "$SOURCES_LIST_FILE"
44
45 echo "Updating apt package lists ..."
46-sudo apt-get -o "$APT_GET_OPTIONS" update -q
47+$sudo apt-get -o "$APT_GET_OPTIONS" update -q
48
49 echo -n "Installing packages ..."
50
51@@ -199,11 +204,11 @@
52 done
53 fi
54
55-sudo apt-get $FORCE_OPTIONS -o "$APT_GET_OPTIONS" install ${packages}
56+$sudo apt-get $FORCE_OPTIONS -o "$APT_GET_OPTIONS" install ${packages}
57
58 if [ "$DEP_PACKAGE_PRESENT" == "yes" ]; then
59 if [ -n "${to_be_installed}" ]; then
60- sudo apt-get $FORCE_OPTIONS -o "$APT_GET_OPTIONS" markauto ${to_be_installed}
61+ $sudo apt-get $FORCE_OPTIONS -o "$APT_GET_OPTIONS" markauto ${to_be_installed}
62 fi
63 fi
64
65
66=== modified file 'linaro-media-create'
67--- linaro-media-create 2011-01-28 19:50:48 +0000
68+++ linaro-media-create 2011-01-29 19:21:18 +0000
69@@ -22,7 +22,6 @@
70 import os
71 import sys
72 import tempfile
73-from subprocess import Popen
74
75 from linaro_media_create.boards import (
76 board_configs,
77@@ -42,7 +41,10 @@
78 ensure_command,
79 is_arm_host,
80 )
81-from linaro_media_create import get_args_parser
82+from linaro_media_create import (
83+ cmd_runner,
84+ get_args_parser
85+ )
86
87 # Just define the global variables
88 TMP_DIR = None
89@@ -60,18 +62,20 @@
90 Before doing so, make sure BOOT_DISK and ROOT_DISK are not mounted.
91 """
92 devnull = open('/dev/null', 'w')
93- # Use raw subprocess.Popen as we don't want to stop in case the
94- # commands end with a non-zero return code.
95- if BOOT_DISK is not None:
96- Popen(['sudo', 'umount', BOOT_DISK],
97- stdout=devnull, stderr=devnull).wait()
98- if ROOT_DISK is not None:
99- Popen(['sudo', 'umount', ROOT_DISK],
100- stdout=devnull, stderr=devnull).wait()
101+ # ignore non-zero return codes
102+ try:
103+ if BOOT_DISK is not None:
104+ cmd_runner.Popen(['umount', BOOT_DISK],
105+ stdout=devnull, stderr=devnull, as_root=True).wait()
106+ if ROOT_DISK is not None:
107+ cmd_runner.Popen(['umount', ROOT_DISK],
108+ stdout=devnull, stderr=devnull, as_root=True).wait()
109+ except SubcommandNonZeroReturnValue:
110+ pass
111 # Remove TMP_DIR as root because some files written there are
112 # owned by root.
113 if TMP_DIR is not None:
114- Popen(['sudo', 'rm', '-rf', TMP_DIR]).wait()
115+ cmd_runner.Popen(['rm', '-rf', TMP_DIR], as_root=True).wait()
116
117
118 def ensure_required_commands(args):
119
120=== modified file 'linaro_media_create/cmd_runner.py'
121--- linaro_media_create/cmd_runner.py 2011-01-28 19:50:48 +0000
122+++ linaro_media_create/cmd_runner.py 2011-01-29 19:21:18 +0000
123@@ -37,10 +37,10 @@
124 """
125 assert isinstance(args, (list, tuple)), (
126 "The command to run must be a list or tuple, found: %s" % type(args))
127- # TODO: We might want to always use 'sudo -E' here to avoid problems like
128- # https://launchpad.net/bugs/673570
129- if as_root:
130+ if as_root and os.getuid() != 0:
131 args = args[:]
132+ # TODO: We might want to always use 'sudo -E' here to avoid problems
133+ # like https://launchpad.net/bugs/673570
134 args.insert(0, 'sudo')
135 return Popen(args, stdin=stdin, stdout=stdout, stderr=stderr)
136
137
138=== modified file 'linaro_media_create/tests/test_media_create.py'
139--- linaro_media_create/tests/test_media_create.py 2011-01-28 19:50:48 +0000
140+++ linaro_media_create/tests/test_media_create.py 2011-01-29 19:21:18 +0000
141@@ -412,11 +412,18 @@
142 self.assertEqual(0, proc.returncode)
143 self.assertEqual([['foo', 'bar', 'baz']], fixture.mock.calls)
144
145- def test_run_as_root(self):
146+ def test_run_as_root_with_sudo(self):
147 fixture = self.useFixture(MockCmdRunnerPopenFixture())
148+ self.useFixture(MockSomethingFixture(os, 'getuid', lambda: 1000))
149 cmd_runner.run(['foo', 'bar'], as_root=True).wait()
150 self.assertEqual([['sudo', 'foo', 'bar']], fixture.mock.calls)
151
152+ def test_run_as_root_as_root(self):
153+ fixture = self.useFixture(MockCmdRunnerPopenFixture())
154+ self.useFixture(MockSomethingFixture(os, 'getuid', lambda: 0))
155+ cmd_runner.run(['foo', 'bar'], as_root=True).wait()
156+ self.assertEqual([['foo', 'bar']], fixture.mock.calls)
157+
158 def test_run_succeeds_on_zero_return_code(self):
159 proc = cmd_runner.run(['true'])
160 # Need to wait() here as we're using the real Popen.

Subscribers

People subscribed via source and target branches