Merge lp:~elopio/snappy/failover-tests-merge-trunk into lp:~fgimenez/snappy/failover-tests
- failover-tests-merge-trunk
- Merge into failover-tests
Proposed by
Leo Arias
Status: | Merged |
---|---|
Approved by: | Federico Gimenez |
Approved revision: | 538 |
Merged at revision: | 530 |
Proposed branch: | lp:~elopio/snappy/failover-tests-merge-trunk |
Merge into: | lp:~fgimenez/snappy/failover-tests |
Diff against target: |
2260 lines (+642/-625) 32 files modified
_integration-tests/README (+0/-1) _integration-tests/main.go (+8/-26) _integration-tests/snappy-selftest (+4/-4) _integration-tests/tests/common_test.go (+4/-3) _integration-tests/tests/failover_test.go (+2/-2) _integration-tests/tests/install_test.go (+6/-5) cmd/snappy/cmd_internal_unpack.go (+3/-3) cmd/snappy/cmd_low_level_unpack_test.go (+5/-5) debian/control (+0/-7) debian/integration-tests/control (+1/-1) debian/rules (+0/-6) debian/ubuntu-snappy-tests.install (+0/-1) helpers/touch.go (+2/-0) partition/assets.go (+87/-0) partition/assets_test.go (+36/-0) partition/bootloader.go (+11/-61) partition/bootloader_grub.go (+6/-20) partition/bootloader_grub_test.go (+5/-14) partition/bootloader_uboot.go (+23/-30) partition/bootloader_uboot_test.go (+17/-27) partition/dirs.go (+41/-0) partition/mount.go (+153/-0) partition/mount_test.go (+64/-0) partition/partition.go (+66/-299) partition/partition_test.go (+50/-98) partition/utils.go (+19/-0) snappy/errors.go (+2/-0) snappy/install.go (+2/-2) snappy/security.go (+5/-0) snappy/security_test.go (+7/-0) snappy/systemimage.go (+8/-1) snappy/systemimage_test.go (+5/-9) |
To merge this branch: | bzr merge lp:~elopio/snappy/failover-tests-merge-trunk |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Federico Gimenez | Approve | ||
Review via email:
|
Commit message
Merged with trunk.
Changed the os.Unset to be compatible with go 1.3.
Do not move the test binary to tmp, because it will be removed after reboots.
Description of the change
To post a comment you must log in.
- 531. By Leo Arias
-
Added missing {
- 532. By Leo Arias
-
Fixed the call to execCommand.
- 533. By Leo Arias
-
Replace UnsetEnv for Setenv empty, because Unset was added in go 1.4
- 534. By Leo Arias
-
Recovered the string output.
- 535. By Leo Arias
-
Typo.
- 536. By Leo Arias
-
Updated the return value.
- 537. By Leo Arias
-
Updated the return value.
- 538. By Leo Arias
-
No need to cast to string.
Preview Diff
[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1 | === modified file '_integration-tests/README' |
2 | --- _integration-tests/README 2015-06-17 15:42:00 +0000 |
3 | +++ _integration-tests/README 2015-06-25 19:16:26 +0000 |
4 | @@ -19,4 +19,3 @@ |
5 | shell tests) with: |
6 | |
7 | $ go run _integration-test/main.go |
8 | - |
9 | |
10 | === modified file '_integration-tests/main.go' |
11 | --- _integration-tests/main.go 2015-06-19 05:01:44 +0000 |
12 | +++ _integration-tests/main.go 2015-06-25 19:16:26 +0000 |
13 | @@ -32,18 +32,18 @@ |
14 | debsTestBedPath = "/tmp/snappy-debs" |
15 | defaultRelease = "rolling" |
16 | defaultChannel = "edge" |
17 | - defaultArch = "amd64" |
18 | ) |
19 | |
20 | var ( |
21 | debsDir = filepath.Join(baseDir, "debs") |
22 | + testsDir = filepath.Join(baseDir, "tests") |
23 | imageDir = filepath.Join(baseDir, "image") |
24 | outputDir = filepath.Join(baseDir, "output") |
25 | imageTarget = filepath.Join(imageDir, "snappy.img") |
26 | ) |
27 | |
28 | func execCommand(cmds ...string) { |
29 | - cmd := exec.Command(cmds[0], cmds[1:len(cmds)]...) |
30 | + cmd := exec.Command(cmds[0], cmds[1:]...) |
31 | cmd.Stdout = os.Stdout |
32 | cmd.Stderr = os.Stderr |
33 | if err := cmd.Run(); err != nil { |
34 | @@ -51,15 +51,11 @@ |
35 | } |
36 | } |
37 | |
38 | -func buildDebs(rootPath string) { |
39 | - fmt.Println("Building debs...") |
40 | - prepareTargetDir(debsDir) |
41 | - execCommand( |
42 | - "bzr", "bd", |
43 | - fmt.Sprintf("--result-dir=%s", debsDir), |
44 | - "--split", |
45 | - rootPath, |
46 | - "--", "-uc", "-us") |
47 | +func buildTests() { |
48 | + fmt.Println("Building tests") |
49 | + prepareTargetDir(testsDir) |
50 | + execCommand("go", "test", "-c", "./_integration-tests/tests") |
51 | + os.Rename("tests.test", "snappy.tests") |
52 | } |
53 | |
54 | func createImage(release, channel string) { |
55 | @@ -80,15 +76,9 @@ |
56 | "adt-run", |
57 | "-B", |
58 | "--setup-commands", "touch /run/autopkgtest_no_reboot.stamp", |
59 | - "--setup-commands", "mount -o remount,rw /", |
60 | - "--setup-commands", |
61 | - fmt.Sprintf("dpkg -i %s/*deb", debsTestBedPath), |
62 | - "--setup-commands", |
63 | - "sync; sleep 2; mount -o remount,ro /", |
64 | "--override-control", "debian/integration-tests/control", |
65 | "--built-tree", rootPath, |
66 | "--output-dir", outputDir, |
67 | - fmt.Sprintf("--copy=%s:%s", debsDir, debsTestBedPath), |
68 | "---", |
69 | "ssh", "-s", "/usr/share/autopkgtest/ssh-setup/snappy", |
70 | "--", "-i", imageTarget) |
71 | @@ -110,18 +100,10 @@ |
72 | return dir |
73 | } |
74 | |
75 | -func getArchForImage() string { |
76 | - return fmt.Sprintf("generic-%s", defaultArch) |
77 | -} |
78 | - |
79 | func main() { |
80 | rootPath := getRootPath() |
81 | |
82 | - if len(os.Args) == 2 { |
83 | - debsDir = os.Args[1] |
84 | - } else { |
85 | - buildDebs(rootPath) |
86 | - } |
87 | + buildTests() |
88 | |
89 | createImage(defaultRelease, defaultChannel) |
90 | |
91 | |
92 | === modified file '_integration-tests/snappy-selftest' |
93 | --- _integration-tests/snappy-selftest 2015-06-16 06:47:24 +0000 |
94 | +++ _integration-tests/snappy-selftest 2015-06-25 19:16:26 +0000 |
95 | @@ -4,7 +4,7 @@ |
96 | |
97 | MYDIR=$(dirname $0) |
98 | |
99 | -. $MYDIR/tests/framework |
100 | +. "$MYDIR"/tests/framework |
101 | |
102 | SNAPPY=snappy |
103 | |
104 | @@ -15,9 +15,9 @@ |
105 | exit 1 |
106 | fi |
107 | |
108 | -. $MYDIR/tests/settings |
109 | +. "$MYDIR"/tests/settings |
110 | |
111 | -. $MYDIR/tests/common.sh |
112 | +. "$MYDIR"/tests/common.sh |
113 | |
114 | # prepare the environment |
115 | if [ -z "$ADT_REBOOT_MARK" ]; then |
116 | @@ -27,7 +27,7 @@ |
117 | sudo snappy remove xkcd-webserver 2>&1 || true |
118 | fi |
119 | |
120 | -for test in $MYDIR/tests/*_test_*[!~#]; do |
121 | +for test in "$MYDIR"/tests/*_test_*[!~#]; do |
122 | CURRENT_TEST=$(basename $test) |
123 | |
124 | # after a reboot, skip ahead to the test that triggered it |
125 | |
126 | === modified file '_integration-tests/tests/common_test.go' |
127 | --- _integration-tests/tests/common_test.go 2015-06-22 09:31:21 +0000 |
128 | +++ _integration-tests/tests/common_test.go 2015-06-25 19:16:26 +0000 |
129 | @@ -33,11 +33,12 @@ |
130 | // Hook up gocheck into the "go test" runner |
131 | func Test(t *testing.T) { TestingT(t) } |
132 | |
133 | -func execCommand(c *C, cmds ...string) []byte { |
134 | +func execCommand(c *C, cmds ...string) string { |
135 | cmd := exec.Command(cmds[0], cmds[1:len(cmds)]...) |
136 | output, err := cmd.CombinedOutput() |
137 | - c.Assert(err, IsNil, Commentf("Error: %v", string(output))) |
138 | - return output |
139 | + stringOutput := string(output) |
140 | + c.Assert(err, IsNil, Commentf("Error: %v", stringOutput)) |
141 | + return stringOutput |
142 | } |
143 | |
144 | func execCommandToFile(c *C, filename string, cmds ...string) { |
145 | |
146 | === modified file '_integration-tests/tests/failover_test.go' |
147 | --- _integration-tests/tests/failover_test.go 2015-06-22 09:31:21 +0000 |
148 | +++ _integration-tests/tests/failover_test.go 2015-06-25 19:16:26 +0000 |
149 | @@ -76,7 +76,7 @@ |
150 | } |
151 | |
152 | func removeRebootMark(c *C) { |
153 | - err := os.Unsetenv("ADT_REBOOT_MARK") |
154 | + err := os.Setenv("ADT_REBOOT_MARK", "") |
155 | c.Assert(err, IsNil, Commentf("Error unsetting ADT_REBOOT_MARK")) |
156 | } |
157 | |
158 | @@ -89,7 +89,7 @@ |
159 | output := execCommand(c, "snappy", "list") |
160 | pattern := "(?mU)^ubuntu-core (.*)$" |
161 | re := regexp.MustCompile(pattern) |
162 | - match := re.FindStringSubmatch(string(output)) |
163 | + match := re.FindStringSubmatch(output) |
164 | c.Assert(match, NotNil, Commentf("Version not found in %s", output)) |
165 | |
166 | // match is like "ubuntu-core 2015-06-18 93 ubuntu" |
167 | |
168 | === modified file '_integration-tests/tests/install_test.go' |
169 | --- _integration-tests/tests/install_test.go 2015-06-22 09:31:21 +0000 |
170 | +++ _integration-tests/tests/install_test.go 2015-06-25 19:16:26 +0000 |
171 | @@ -27,7 +27,7 @@ |
172 | CommonSuite |
173 | } |
174 | |
175 | -func installSnap(c *C, packageName string) []byte { |
176 | +func installSnap(c *C, packageName string) string { |
177 | return execCommand(c, "sudo", "snappy", "install", packageName) |
178 | } |
179 | |
180 | @@ -44,7 +44,7 @@ |
181 | ".*\n" + |
182 | "hello-world .* .* canonical \n" + |
183 | ".*\n" |
184 | - c.Assert(string(installOutput), Matches, expected) |
185 | + c.Assert(installOutput, Matches, expected) |
186 | } |
187 | |
188 | func (s *InstallSuite) TestCallBinaryFromInstalledSnap(c *C) { |
189 | @@ -52,14 +52,15 @@ |
190 | |
191 | echoOutput := execCommand(c, "hello-world.echo") |
192 | |
193 | - c.Assert(string(echoOutput), Equals, "Hello World!\n") |
194 | + c.Assert(echoOutput, Equals, "Hello World!\n") |
195 | } |
196 | |
197 | func (s *InstallSuite) TestInfoMustPrintInstalledPackageInformation(c *C) { |
198 | installSnap(c, "hello-world") |
199 | |
200 | - infoOutput := execCommand(c, "sudo", "snappy", "info") |
201 | + infoOutput := execCommand(c, "snappy", "info") |
202 | |
203 | expected := "(?ms).*^apps: hello-world\n" |
204 | - c.Assert(string(infoOutput), Matches, expected) |
205 | + |
206 | + c.Assert(infoOutput, Matches, expected) |
207 | } |
208 | |
209 | === modified file 'cmd/snappy/cmd_internal_unpack.go' |
210 | --- cmd/snappy/cmd_internal_unpack.go 2015-06-08 13:03:35 +0000 |
211 | +++ cmd/snappy/cmd_internal_unpack.go 2015-06-25 19:16:26 +0000 |
212 | @@ -70,7 +70,7 @@ |
213 | return filepath.Join("/etc/", file) |
214 | } |
215 | |
216 | -func readUid(user, passwdFile string) (uid int, err error) { |
217 | +func readUID(user, passwdFile string) (uid int, err error) { |
218 | f, err := os.Open(passwdFile) |
219 | if err != nil { |
220 | return -1, err |
221 | @@ -125,13 +125,13 @@ |
222 | if helpers.ShouldDropPrivs() { |
223 | |
224 | passFile := passwdFile(rootDir, "passwd") |
225 | - uid, err := readUid(dropPrivsUser, passFile) |
226 | + uid, err := readUID(dropPrivsUser, passFile) |
227 | if err != nil { |
228 | return err |
229 | } |
230 | |
231 | groupFile := passwdFile(rootDir, "group") |
232 | - gid, err := readUid(dropPrivsUser, groupFile) |
233 | + gid, err := readUID(dropPrivsUser, groupFile) |
234 | if err != nil { |
235 | return err |
236 | } |
237 | |
238 | === modified file 'cmd/snappy/cmd_low_level_unpack_test.go' |
239 | --- cmd/snappy/cmd_low_level_unpack_test.go 2015-06-02 20:46:07 +0000 |
240 | +++ cmd/snappy/cmd_low_level_unpack_test.go 2015-06-25 19:16:26 +0000 |
241 | @@ -42,7 +42,7 @@ |
242 | clickpkg:x:101:104::/nonexistent:/bin/false |
243 | `) |
244 | |
245 | - uid, err := readUid("clickpkg", f.Name()) |
246 | + uid, err := readUID("clickpkg", f.Name()) |
247 | c.Assert(err, IsNil) |
248 | c.Assert(uid, Equals, 101) |
249 | } |
250 | @@ -53,7 +53,7 @@ |
251 | clickpkg:x:104: |
252 | `) |
253 | |
254 | - gid, err := readUid("clickpkg", f.Name()) |
255 | + gid, err := readUID("clickpkg", f.Name()) |
256 | c.Assert(err, IsNil) |
257 | c.Assert(gid, Equals, 104) |
258 | } |
259 | @@ -66,7 +66,7 @@ |
260 | `) |
261 | defer os.Remove(f.Name()) |
262 | |
263 | - uid, err := readUid("clickpkg", f.Name()) |
264 | + uid, err := readUID("clickpkg", f.Name()) |
265 | c.Assert(err, IsNil) |
266 | c.Assert(uid, Equals, 102) |
267 | } |
268 | @@ -77,7 +77,7 @@ |
269 | clickpkg:x: |
270 | `) |
271 | |
272 | - _, err := readUid("clickpkg", f.Name()) |
273 | + _, err := readUID("clickpkg", f.Name()) |
274 | c.Assert(err, NotNil) |
275 | } |
276 | |
277 | @@ -86,6 +86,6 @@ |
278 | daemon: |
279 | `) |
280 | |
281 | - _, err := readUid("clickpkg", f.Name()) |
282 | + _, err := readUID("clickpkg", f.Name()) |
283 | c.Assert(err, NotNil) |
284 | } |
285 | |
286 | === modified file 'debian/control' |
287 | --- debian/control 2015-06-16 15:06:45 +0000 |
288 | +++ debian/control 2015-06-25 19:16:26 +0000 |
289 | @@ -51,10 +51,3 @@ |
290 | Built-Using: ${misc:Built-Using} |
291 | Description: Tool to interact with Ubuntu Core Snappy. |
292 | Manage an Ubuntu system with snappy. |
293 | - |
294 | -Package: ubuntu-snappy-tests |
295 | -Architecture: any |
296 | -Depends: ubuntu-snappy-cli (= ${binary:Version}), |
297 | - ${misc:Depends} |
298 | -Description: snappy selftests |
299 | - Installs snappy selftests binary |
300 | |
301 | === modified file 'debian/integration-tests/control' |
302 | --- debian/integration-tests/control 2015-06-16 04:52:54 +0000 |
303 | +++ debian/integration-tests/control 2015-06-25 19:16:26 +0000 |
304 | @@ -1,4 +1,4 @@ |
305 | -Test-Command: snappy.test -gocheck.vv -test.outputdir=$ADT_ARTIFACTS |
306 | +Test-Command: ./snappy.tests -gocheck.vv -test.outputdir=$ADT_ARTIFACTS |
307 | Restrictions: allow-stderr |
308 | Depends: ubuntu-snappy-tests |
309 | |
310 | |
311 | === modified file 'debian/rules' |
312 | --- debian/rules 2015-06-17 12:06:39 +0000 |
313 | +++ debian/rules 2015-06-25 19:16:26 +0000 |
314 | @@ -4,7 +4,6 @@ |
315 | #export DH_VERBOSE=1 |
316 | export DH_OPTIONS |
317 | export DH_GOPKG := launchpad.net/snappy |
318 | -DH_BUILDDIR = obj-$(shell dpkg-architecture -qDEB_HOST_GNU_TYPE) |
319 | |
320 | %: |
321 | dh $@ --buildsystem=golang --with=golang --fail-missing --with systemd |
322 | @@ -51,11 +50,6 @@ |
323 | -pubuntu-snappy \ |
324 | snappy-autopilot.service |
325 | |
326 | -override_dh_auto_build: |
327 | - dh_auto_build |
328 | - GOPATH=$$PWD/$(DH_BUILDDIR) go test -c ./_integration-tests/tests |
329 | - mv tests.test $$PWD/$(DH_BUILDDIR)/bin/snappy.test |
330 | - |
331 | override_dh_auto_install: |
332 | dh_auto_install -O--buildsystem=golang |
333 | # Making the packages private |
334 | |
335 | === removed file 'debian/ubuntu-snappy-tests.install' |
336 | --- debian/ubuntu-snappy-tests.install 2015-06-13 18:10:49 +0000 |
337 | +++ debian/ubuntu-snappy-tests.install 1970-01-01 00:00:00 +0000 |
338 | @@ -1,1 +0,0 @@ |
339 | -/usr/bin/snappy.test |
340 | |
341 | === modified file 'helpers/touch.go' |
342 | --- helpers/touch.go 2015-05-15 13:33:27 +0000 |
343 | +++ helpers/touch.go 2015-06-25 19:16:26 +0000 |
344 | @@ -38,6 +38,8 @@ |
345 | "unsafe" |
346 | ) |
347 | |
348 | +// ErrNotAbsPath is returned when an absolute path is needed but the received |
349 | +// path is not. |
350 | var ErrNotAbsPath = errors.New("not an absolute path") |
351 | |
352 | // UpdateTimestamp updates the timestamp of the file at pathname. It does not |
353 | |
354 | === added file 'partition/assets.go' |
355 | --- partition/assets.go 1970-01-01 00:00:00 +0000 |
356 | +++ partition/assets.go 2015-06-25 19:16:26 +0000 |
357 | @@ -0,0 +1,87 @@ |
358 | +// -*- Mode: Go; indent-tabs-mode: t -*- |
359 | + |
360 | +/* |
361 | + * Copyright (C) 2014-2015 Canonical Ltd |
362 | + * |
363 | + * This program is free software: you can redistribute it and/or modify |
364 | + * it under the terms of the GNU General Public License version 3 as |
365 | + * published by the Free Software Foundation. |
366 | + * |
367 | + * This program is distributed in the hope that it will be useful, |
368 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of |
369 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
370 | + * GNU General Public License for more details. |
371 | + * |
372 | + * You should have received a copy of the GNU General Public License |
373 | + * along with this program. If not, see <http://www.gnu.org/licenses/>. |
374 | + * |
375 | + */ |
376 | + |
377 | +package partition |
378 | + |
379 | +import ( |
380 | + "errors" |
381 | + "io/ioutil" |
382 | + "os" |
383 | + "path/filepath" |
384 | + |
385 | + "gopkg.in/yaml.v2" |
386 | +) |
387 | + |
388 | +// Representation of the yaml in the hardwareSpecFile |
389 | +type hardwareSpecType struct { |
390 | + Kernel string `yaml:"kernel"` |
391 | + Initrd string `yaml:"initrd"` |
392 | + DtbDir string `yaml:"dtbs"` |
393 | + PartitionLayout string `yaml:"partition-layout"` |
394 | + Bootloader bootloaderName `yaml:"bootloader"` |
395 | +} |
396 | + |
397 | +var ( |
398 | + // ErrNoHardwareYaml is returned when no hardware yaml is found in |
399 | + // the update, this means that there is nothing to process with regards |
400 | + // to device parts. |
401 | + ErrNoHardwareYaml = errors.New("no hardware.yaml") |
402 | + |
403 | + // Declarative specification of the type of system which specifies such |
404 | + // details as: |
405 | + // |
406 | + // - the location of initrd+kernel within the system-image archive. |
407 | + // - the location of hardware-specific .dtb files within the |
408 | + // system-image archive. |
409 | + // - the type of bootloader that should be used for this system. |
410 | + // - expected system partition layout (single or dual rootfs's). |
411 | + hardwareSpecFileReal = filepath.Join(cacheDir, "hardware.yaml") |
412 | + |
413 | + // useful to override in the tests |
414 | + hardwareSpecFile = hardwareSpecFileReal |
415 | + |
416 | + // Directory that _may_ get automatically created on unpack that |
417 | + // contains updated hardware-specific boot assets (such as initrd, |
418 | + // kernel) |
419 | + assetsDir = filepath.Join(cacheDir, "assets") |
420 | + |
421 | + // Directory that _may_ get automatically created on unpack that |
422 | + // contains updated hardware-specific assets that require flashing |
423 | + // to the disk (such as uBoot, MLO) |
424 | + flashAssetsDir = filepath.Join(cacheDir, "flashtool-assets") |
425 | +) |
426 | + |
427 | +func readHardwareSpec() (*hardwareSpecType, error) { |
428 | + var h hardwareSpecType |
429 | + |
430 | + data, err := ioutil.ReadFile(hardwareSpecFile) |
431 | + // if hardware.yaml does not exist it just means that there was no |
432 | + // device part in the update. |
433 | + if os.IsNotExist(err) { |
434 | + return nil, ErrNoHardwareYaml |
435 | + } else if err != nil { |
436 | + return nil, err |
437 | + } |
438 | + |
439 | + if err := yaml.Unmarshal([]byte(data), &h); err != nil { |
440 | + return nil, err |
441 | + } |
442 | + |
443 | + return &h, nil |
444 | +} |
445 | |
446 | === added file 'partition/assets_test.go' |
447 | --- partition/assets_test.go 1970-01-01 00:00:00 +0000 |
448 | +++ partition/assets_test.go 2015-06-25 19:16:26 +0000 |
449 | @@ -0,0 +1,36 @@ |
450 | +// -*- Mode: Go; indent-tabs-mode: t -*- |
451 | + |
452 | +/* |
453 | + * Copyright (C) 2014-2015 Canonical Ltd |
454 | + * |
455 | + * This program is free software: you can redistribute it and/or modify |
456 | + * it under the terms of the GNU General Public License version 3 as |
457 | + * published by the Free Software Foundation. |
458 | + * |
459 | + * This program is distributed in the hope that it will be useful, |
460 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of |
461 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
462 | + * GNU General Public License for more details. |
463 | + * |
464 | + * You should have received a copy of the GNU General Public License |
465 | + * along with this program. If not, see <http://www.gnu.org/licenses/>. |
466 | + * |
467 | + */ |
468 | + |
469 | +package partition |
470 | + |
471 | +import ( |
472 | + . "gopkg.in/check.v1" |
473 | +) |
474 | + |
475 | +func (s *PartitionTestSuite) TestHardwareSpec(c *C) { |
476 | + |
477 | + hardwareSpecFile = makeHardwareYaml(c, "") |
478 | + hw, err := readHardwareSpec() |
479 | + c.Assert(err, IsNil) |
480 | + c.Assert(hw.Kernel, Equals, "assets/vmlinuz") |
481 | + c.Assert(hw.Initrd, Equals, "assets/initrd.img") |
482 | + c.Assert(hw.DtbDir, Equals, "assets/dtbs") |
483 | + c.Assert(hw.PartitionLayout, Equals, bootloaderSystemAB) |
484 | + c.Assert(hw.Bootloader, Equals, bootloaderNameUboot) |
485 | +} |
486 | |
487 | === modified file 'partition/bootloader.go' |
488 | --- partition/bootloader.go 2015-06-09 17:43:20 +0000 |
489 | +++ partition/bootloader.go 2015-06-25 19:16:26 +0000 |
490 | @@ -45,7 +45,7 @@ |
491 | |
492 | // Switch bootloader configuration so that the "other" root |
493 | // filesystem partition will be used on next boot. |
494 | - ToggleRootFS() error |
495 | + ToggleRootFS(otherRootfs string) error |
496 | |
497 | // Hook function called before system-image starts downloading |
498 | // and applying archives that allows files to be copied between |
499 | @@ -60,14 +60,6 @@ |
500 | GetBootVar(name string) (string, error) |
501 | |
502 | // Return the 1-character name corresponding to the |
503 | - // rootfs currently being used. |
504 | - GetRootFSName() string |
505 | - |
506 | - // Return the 1-character name corresponding to the |
507 | - // other rootfs. |
508 | - GetOtherRootFSName() string |
509 | - |
510 | - // Return the 1-character name corresponding to the |
511 | // rootfs that will be used on _next_ boot. |
512 | // |
513 | // XXX: Note the distinction between this method and |
514 | @@ -78,7 +70,7 @@ |
515 | |
516 | // Update the bootloader configuration to mark the |
517 | // currently-booted rootfs as having booted successfully. |
518 | - MarkCurrentBootSuccessful() error |
519 | + MarkCurrentBootSuccessful(currentRootfs string) error |
520 | |
521 | // Return the additional required chroot bind mounts for this bootloader |
522 | AdditionalBindMounts() []string |
523 | @@ -88,15 +80,6 @@ |
524 | BootDir() string |
525 | } |
526 | |
527 | -type bootloaderType struct { |
528 | - partition *Partition |
529 | - |
530 | - // each rootfs partition has a corresponding u-boot directory named |
531 | - // from the last character of the partition name ('a' or 'b'). |
532 | - currentRootfs string |
533 | - otherRootfs string |
534 | -} |
535 | - |
536 | // Factory method that returns a new bootloader for the given partition |
537 | var bootloader = bootloaderImpl |
538 | |
539 | @@ -115,46 +98,13 @@ |
540 | return nil, ErrBootloader |
541 | } |
542 | |
543 | -func newBootLoader(partition *Partition) *bootloaderType { |
544 | - b := new(bootloaderType) |
545 | - |
546 | - b.partition = partition |
547 | - |
548 | - currentLabel := partition.rootPartition().name |
549 | - |
550 | - // FIXME: is this the right thing to do? i.e. what should we do |
551 | - // on a single partition system? |
552 | - if partition.otherRootPartition() == nil { |
553 | - return nil |
554 | - } |
555 | - otherLabel := partition.otherRootPartition().name |
556 | - |
557 | - b.currentRootfs = string(currentLabel[len(currentLabel)-1]) |
558 | - b.otherRootfs = string(otherLabel[len(otherLabel)-1]) |
559 | - |
560 | - return b |
561 | -} |
562 | - |
563 | -// Return true if the next boot will use the other rootfs |
564 | -// partition. |
565 | -func isNextBootOther(bootloader bootLoader) bool { |
566 | - value, err := bootloader.GetBootVar(bootloaderBootmodeVar) |
567 | - if err != nil { |
568 | - return false |
569 | - } |
570 | - |
571 | - if value != bootloaderBootmodeTry { |
572 | - return false |
573 | - } |
574 | - |
575 | - fsname, err := bootloader.GetNextBootRootFSName() |
576 | - if err != nil { |
577 | - return false |
578 | - } |
579 | - |
580 | - if fsname == bootloader.GetOtherRootFSName() { |
581 | - return true |
582 | - } |
583 | - |
584 | - return false |
585 | +// BootloaderDir returns the full path to the (mounted and writable) |
586 | +// bootloader-specific boot directory. |
587 | +func BootloaderDir() string { |
588 | + b, err := bootloader(nil) |
589 | + if err != nil { |
590 | + return "" |
591 | + } |
592 | + |
593 | + return b.BootDir() |
594 | } |
595 | |
596 | === modified file 'partition/bootloader_grub.go' |
597 | --- partition/bootloader_grub.go 2015-06-09 17:22:59 +0000 |
598 | +++ partition/bootloader_grub.go 2015-06-25 19:16:26 +0000 |
599 | @@ -49,7 +49,6 @@ |
600 | ) |
601 | |
602 | type grub struct { |
603 | - *bootloaderType |
604 | } |
605 | |
606 | const bootloaderNameGrub bootloaderName = "grub" |
607 | @@ -59,13 +58,8 @@ |
608 | if !helpers.FileExists(bootloaderGrubConfigFile) || !helpers.FileExists(bootloaderGrubUpdateCmd) { |
609 | return nil |
610 | } |
611 | - b := newBootLoader(partition) |
612 | - if b == nil { |
613 | - return nil |
614 | - } |
615 | - g := &grub{bootloaderType: b} |
616 | |
617 | - return g |
618 | + return &grub{} |
619 | } |
620 | |
621 | func (g *grub) Name() bootloaderName { |
622 | @@ -77,10 +71,10 @@ |
623 | // Approach: |
624 | // |
625 | // Update the grub configuration. |
626 | -func (g *grub) ToggleRootFS() (err error) { |
627 | +func (g *grub) ToggleRootFS(otherRootfs string) (err error) { |
628 | |
629 | // create the grub config |
630 | - if err := runInChroot(g.partition.MountTarget(), bootloaderGrubUpdateCmd); err != nil { |
631 | + if err := runInChroot(mountTarget, bootloaderGrubUpdateCmd); err != nil { |
632 | return err |
633 | } |
634 | |
635 | @@ -91,7 +85,7 @@ |
636 | // Record the partition that will be used for next boot. This |
637 | // isn't necessary for correct operation under grub, but allows |
638 | // us to query the next boot device easily. |
639 | - return g.setBootVar(bootloaderRootfsVar, g.otherRootfs) |
640 | + return g.setBootVar(bootloaderRootfsVar, otherRootfs) |
641 | } |
642 | |
643 | func (g *grub) GetBootVar(name string) (value string, err error) { |
644 | @@ -127,22 +121,14 @@ |
645 | return g.GetBootVar(bootloaderRootfsVar) |
646 | } |
647 | |
648 | -func (g *grub) GetRootFSName() string { |
649 | - return g.currentRootfs |
650 | -} |
651 | - |
652 | -func (g *grub) GetOtherRootFSName() string { |
653 | - return g.otherRootfs |
654 | -} |
655 | - |
656 | -func (g *grub) MarkCurrentBootSuccessful() (err error) { |
657 | +func (g *grub) MarkCurrentBootSuccessful(currentRootfs string) (err error) { |
658 | // Clear the variable set by grub on boot to denote a good |
659 | // boot. |
660 | if err := g.unsetBootVar(bootloaderGrubTrialBootVar); err != nil { |
661 | return err |
662 | } |
663 | |
664 | - if err := g.setBootVar(bootloaderRootfsVar, g.currentRootfs); err != nil { |
665 | + if err := g.setBootVar(bootloaderRootfsVar, currentRootfs); err != nil { |
666 | return err |
667 | } |
668 | |
669 | |
670 | === modified file 'partition/bootloader_grub_test.go' |
671 | --- partition/bootloader_grub_test.go 2015-06-09 17:43:20 +0000 |
672 | +++ partition/bootloader_grub_test.go 2015-06-25 19:16:26 +0000 |
673 | @@ -63,15 +63,6 @@ |
674 | c.Assert(g.Name(), Equals, bootloaderNameGrub) |
675 | } |
676 | |
677 | -func (s *PartitionTestSuite) TestNewGrubSinglePartition(c *C) { |
678 | - runLsblk = mockRunLsblkSingleRootSnappy |
679 | - s.makeFakeGrubEnv(c) |
680 | - |
681 | - partition := New() |
682 | - g := newGrub(partition) |
683 | - c.Assert(g, IsNil) |
684 | -} |
685 | - |
686 | type singleCommand []string |
687 | |
688 | var allCommands = []singleCommand{} |
689 | @@ -88,14 +79,14 @@ |
690 | partition := New() |
691 | g := newGrub(partition) |
692 | c.Assert(g, NotNil) |
693 | - err := g.ToggleRootFS() |
694 | + err := g.ToggleRootFS("b") |
695 | c.Assert(err, IsNil) |
696 | |
697 | // this is always called |
698 | - mp := singleCommand{"/bin/mountpoint", "/writable/cache/system"} |
699 | + mp := singleCommand{"/bin/mountpoint", mountTarget} |
700 | c.Assert(allCommands[0], DeepEquals, mp) |
701 | |
702 | - expectedGrubUpdate := singleCommand{"/usr/sbin/chroot", "/writable/cache/system", bootloaderGrubUpdateCmd} |
703 | + expectedGrubUpdate := singleCommand{"/usr/sbin/chroot", mountTarget, bootloaderGrubUpdateCmd} |
704 | c.Assert(allCommands[1], DeepEquals, expectedGrubUpdate) |
705 | |
706 | expectedGrubSet := singleCommand{bootloaderGrubEnvCmd, bootloaderGrubEnvFile, "set", "snappy_mode=try"} |
707 | @@ -141,11 +132,11 @@ |
708 | partition := New() |
709 | g := newGrub(partition) |
710 | c.Assert(g, NotNil) |
711 | - err := g.MarkCurrentBootSuccessful() |
712 | + err := g.MarkCurrentBootSuccessful("a") |
713 | c.Assert(err, IsNil) |
714 | |
715 | // this is always called |
716 | - mp := singleCommand{"/bin/mountpoint", "/writable/cache/system"} |
717 | + mp := singleCommand{"/bin/mountpoint", mountTarget} |
718 | c.Assert(allCommands[0], DeepEquals, mp) |
719 | |
720 | expectedGrubSet := singleCommand{bootloaderGrubEnvCmd, bootloaderGrubEnvFile, "unset", "snappy_trial_boot"} |
721 | |
722 | === modified file 'partition/bootloader_uboot.go' |
723 | --- partition/bootloader_uboot.go 2015-06-09 17:22:59 +0000 |
724 | +++ partition/bootloader_uboot.go 2015-06-25 19:16:26 +0000 |
725 | @@ -58,8 +58,6 @@ |
726 | const bootloaderNameUboot bootloaderName = "u-boot" |
727 | |
728 | type uboot struct { |
729 | - *bootloaderType |
730 | - |
731 | // full path to rootfs-specific assets on boot partition |
732 | currentBootPath string |
733 | otherBootPath string |
734 | @@ -78,13 +76,13 @@ |
735 | return nil |
736 | } |
737 | |
738 | - b := newBootLoader(partition) |
739 | - if b == nil { |
740 | - return nil |
741 | - } |
742 | - u := uboot{bootloaderType: b} |
743 | - u.currentBootPath = filepath.Join(bootloaderUbootDir, u.currentRootfs) |
744 | - u.otherBootPath = filepath.Join(bootloaderUbootDir, u.otherRootfs) |
745 | + u := uboot{} |
746 | + |
747 | + currentRootfs := partition.rootPartition().shortName |
748 | + u.currentBootPath = filepath.Join(bootloaderUbootDir, currentRootfs) |
749 | + |
750 | + otherRootfs := partition.otherRootPartition().shortName |
751 | + u.otherBootPath = filepath.Join(bootloaderUbootDir, otherRootfs) |
752 | |
753 | return &u |
754 | } |
755 | @@ -103,7 +101,7 @@ |
756 | // - Copy the "other" rootfs's kernel+initrd to the boot partition, |
757 | // renaming them in the process to ensure the next boot uses the |
758 | // correct versions. |
759 | -func (u *uboot) ToggleRootFS() (err error) { |
760 | +func (u *uboot) ToggleRootFS(otherRootfs string) (err error) { |
761 | |
762 | // If the file exists, update it. Otherwise create it. |
763 | // |
764 | @@ -112,7 +110,7 @@ |
765 | // recreate to allow the system to boot! |
766 | changes := []configFileChange{ |
767 | configFileChange{Name: bootloaderRootfsVar, |
768 | - Value: string(u.otherRootfs), |
769 | + Value: string(otherRootfs), |
770 | }, |
771 | configFileChange{Name: bootloaderBootmodeVar, |
772 | Value: bootloaderBootmodeTry, |
773 | @@ -142,14 +140,6 @@ |
774 | return value, nil |
775 | } |
776 | |
777 | -func (u *uboot) GetRootFSName() string { |
778 | - return u.currentRootfs |
779 | -} |
780 | - |
781 | -func (u *uboot) GetOtherRootFSName() string { |
782 | - return u.otherRootfs |
783 | -} |
784 | - |
785 | // FIXME: put into utils package |
786 | func readLines(path string) (lines []string, err error) { |
787 | |
788 | @@ -200,13 +190,13 @@ |
789 | return file.Sync() |
790 | } |
791 | |
792 | -func (u *uboot) MarkCurrentBootSuccessful() (err error) { |
793 | +func (u *uboot) MarkCurrentBootSuccessful(currentRootfs string) (err error) { |
794 | changes := []configFileChange{ |
795 | configFileChange{Name: bootloaderBootmodeVar, |
796 | Value: bootloaderBootmodeSuccess, |
797 | }, |
798 | configFileChange{Name: bootloaderRootfsVar, |
799 | - Value: string(u.currentRootfs), |
800 | + Value: string(currentRootfs), |
801 | }, |
802 | } |
803 | |
804 | @@ -227,14 +217,18 @@ |
805 | func (u *uboot) HandleAssets() (err error) { |
806 | // check if we have anything, if there is no hardware yaml, there is nothing |
807 | // to process. |
808 | - hardware, err := u.partition.hardwareSpec() |
809 | + hardware, err := readHardwareSpec() |
810 | if err == ErrNoHardwareYaml { |
811 | return nil |
812 | } else if err != nil { |
813 | return err |
814 | } |
815 | - // ensure to remove the file once we are done |
816 | - defer os.Remove(u.partition.hardwareSpecFile) |
817 | + // ensure to remove the file once we are done (and all was good) |
818 | + defer func() { |
819 | + if err == nil { |
820 | + os.Remove(hardwareSpecFile) |
821 | + } |
822 | + }() |
823 | |
824 | // validate bootloader |
825 | if hardware.Bootloader != u.Name() { |
826 | @@ -244,8 +238,9 @@ |
827 | hardware.Bootloader) |
828 | } |
829 | |
830 | - // validate partition layout |
831 | - if u.partition.dualRootPartitions() && hardware.PartitionLayout != bootloaderSystemAB { |
832 | + // validate partition layout, we ONLY support bootloaderSystemAB |
833 | + // currently |
834 | + if hardware.PartitionLayout != bootloaderSystemAB { |
835 | return fmt.Errorf("hardware spec requires dual root partitions") |
836 | } |
837 | |
838 | @@ -263,7 +258,7 @@ |
839 | } |
840 | |
841 | // expand path |
842 | - path := filepath.Join(u.partition.cacheDir(), file) |
843 | + path := filepath.Join(cacheDir, file) |
844 | |
845 | if !helpers.FileExists(path) { |
846 | return fmt.Errorf("can not find file %s", path) |
847 | @@ -281,7 +276,7 @@ |
848 | // fully speced |
849 | |
850 | // install .dtb files |
851 | - dtbSrcDir := filepath.Join(u.partition.cacheDir(), hardware.DtbDir) |
852 | + dtbSrcDir := filepath.Join(cacheDir, hardware.DtbDir) |
853 | if helpers.FileExists(dtbSrcDir) { |
854 | // ensure we cleanup the source dir |
855 | defer os.RemoveAll(dtbSrcDir) |
856 | @@ -303,8 +298,6 @@ |
857 | } |
858 | } |
859 | |
860 | - flashAssetsDir := u.partition.flashAssetsDir() |
861 | - |
862 | if helpers.FileExists(flashAssetsDir) { |
863 | // FIXME: we don't currently do anything with the |
864 | // MLO + uImage files since they are not specified in |
865 | |
866 | === modified file 'partition/bootloader_uboot_test.go' |
867 | --- partition/bootloader_uboot_test.go 2015-06-12 05:23:40 +0000 |
868 | +++ partition/bootloader_uboot_test.go 2015-06-25 19:16:26 +0000 |
869 | @@ -89,15 +89,6 @@ |
870 | c.Assert(u.Name(), Equals, bootloaderNameUboot) |
871 | } |
872 | |
873 | -func (s *PartitionTestSuite) TestNewUbootSinglePartition(c *C) { |
874 | - runLsblk = mockRunLsblkSingleRootSnappy |
875 | - s.makeFakeUbootEnv(c) |
876 | - |
877 | - partition := New() |
878 | - u := newUboot(partition) |
879 | - c.Assert(u, IsNil) |
880 | -} |
881 | - |
882 | func (s *PartitionTestSuite) TestUbootGetBootVar(c *C) { |
883 | s.makeFakeUbootEnv(c) |
884 | |
885 | @@ -111,7 +102,7 @@ |
886 | c.Assert(nextBoot, Equals, "a") |
887 | |
888 | // ensure that nextBootIsOther works too |
889 | - c.Assert(isNextBootOther(u), Equals, false) |
890 | + c.Assert(partition.IsNextBootOther(), Equals, false) |
891 | } |
892 | |
893 | func (s *PartitionTestSuite) TestUbootToggleRootFS(c *C) { |
894 | @@ -121,7 +112,7 @@ |
895 | u := newUboot(partition) |
896 | c.Assert(u, NotNil) |
897 | |
898 | - err := u.ToggleRootFS() |
899 | + err := u.ToggleRootFS("b") |
900 | c.Assert(err, IsNil) |
901 | |
902 | nextBoot, err := u.GetBootVar(bootloaderRootfsVar) |
903 | @@ -129,7 +120,7 @@ |
904 | c.Assert(nextBoot, Equals, "b") |
905 | |
906 | // ensure that nextBootIsOther works too |
907 | - c.Assert(isNextBootOther(u), Equals, true) |
908 | + c.Assert(partition.IsNextBootOther(), Equals, true) |
909 | } |
910 | |
911 | func (s *PartitionTestSuite) TestUbootGetEnvVar(c *C) { |
912 | @@ -158,7 +149,7 @@ |
913 | |
914 | func makeMockAssetsDir(c *C) { |
915 | for _, f := range []string{"assets/vmlinuz", "assets/initrd.img", "assets/dtbs/foo.dtb", "assets/dtbs/bar.dtb"} { |
916 | - p := filepath.Join(defaultCacheDir, f) |
917 | + p := filepath.Join(cacheDir, f) |
918 | os.MkdirAll(filepath.Dir(p), 0755) |
919 | err := ioutil.WriteFile(p, []byte(f), 0644) |
920 | c.Assert(err, IsNil) |
921 | @@ -172,8 +163,8 @@ |
922 | c.Assert(err, IsNil) |
923 | |
924 | // mock the hardwareYaml and the cacheDir |
925 | - p.hardwareSpecFile = makeHardwareYaml(c, "") |
926 | - defaultCacheDir = c.MkDir() |
927 | + hardwareSpecFile = makeHardwareYaml(c, "") |
928 | + cacheDir = c.MkDir() |
929 | |
930 | // create mock assets/ |
931 | makeMockAssetsDir(c) |
932 | @@ -192,8 +183,8 @@ |
933 | } |
934 | |
935 | // ensure nothing left behind |
936 | - c.Assert(helpers.FileExists(filepath.Join(defaultCacheDir, "assets")), Equals, false) |
937 | - c.Assert(helpers.FileExists(p.hardwareSpecFile), Equals, false) |
938 | + c.Assert(helpers.FileExists(filepath.Join(cacheDir, "assets")), Equals, false) |
939 | + c.Assert(helpers.FileExists(hardwareSpecFile), Equals, false) |
940 | } |
941 | |
942 | func (s *PartitionTestSuite) TestHandleAssetsVerifyBootloader(c *C) { |
943 | @@ -203,7 +194,8 @@ |
944 | c.Assert(err, IsNil) |
945 | |
946 | // mock the hardwareYaml and the cacheDir |
947 | - p.hardwareSpecFile = makeHardwareYaml(c, "bootloader: grub") |
948 | + hardwareSpecFile = makeHardwareYaml(c, "bootloader: grub") |
949 | + cacheDir = c.MkDir() |
950 | |
951 | err = bootloader.HandleAssets() |
952 | c.Assert(err, NotNil) |
953 | @@ -216,18 +208,16 @@ |
954 | c.Assert(err, IsNil) |
955 | |
956 | // mock the hardwareYaml and the cacheDir |
957 | - p.hardwareSpecFile = makeHardwareYaml(c, ` |
958 | + hardwareSpecFile = makeHardwareYaml(c, ` |
959 | bootloader: u-boot |
960 | partition-layout: inplace |
961 | `) |
962 | - |
963 | err = bootloader.HandleAssets() |
964 | c.Assert(err, NotNil) |
965 | } |
966 | |
967 | func (s *PartitionTestSuite) TestHandleAssetsNoHardwareYaml(c *C) { |
968 | s.makeFakeUbootEnv(c) |
969 | - defaultCacheDir = c.MkDir() |
970 | |
971 | p := New() |
972 | bootloader, err := bootloader(p) |
973 | @@ -242,7 +232,7 @@ |
974 | bootloader, err := bootloader(p) |
975 | c.Assert(err, IsNil) |
976 | |
977 | - p.hardwareSpecFile = makeHardwareYaml(c, ` |
978 | + hardwareSpecFile = makeHardwareYaml(c, ` |
979 | bootloader u-boot |
980 | `) |
981 | |
982 | @@ -268,7 +258,7 @@ |
983 | // enter "try" mode so that we check to ensure that snappy |
984 | // correctly modifies the snappy_mode variable from "try" to |
985 | // "regular" to denote a good boot. |
986 | - err = u.ToggleRootFS() |
987 | + err = u.ToggleRootFS("b") |
988 | c.Assert(err, IsNil) |
989 | |
990 | c.Assert(helpers.FileExists(bootloaderUbootEnvFile), Equals, true) |
991 | @@ -278,7 +268,7 @@ |
992 | c.Assert(strings.Contains(string(bytes), "snappy_mode=regular"), Equals, false) |
993 | c.Assert(strings.Contains(string(bytes), "snappy_ab=b"), Equals, true) |
994 | |
995 | - err = u.MarkCurrentBootSuccessful() |
996 | + err = u.MarkCurrentBootSuccessful("b") |
997 | c.Assert(err, IsNil) |
998 | |
999 | c.Assert(helpers.FileExists(bootloaderUbootStampFile), Equals, false) |
1000 | @@ -288,7 +278,7 @@ |
1001 | c.Assert(err, IsNil) |
1002 | c.Assert(strings.Contains(string(bytes), "snappy_mode=try"), Equals, false) |
1003 | c.Assert(strings.Contains(string(bytes), "snappy_mode=regular"), Equals, true) |
1004 | - c.Assert(strings.Contains(string(bytes), "snappy_ab=a"), Equals, true) |
1005 | + c.Assert(strings.Contains(string(bytes), "snappy_ab=b"), Equals, true) |
1006 | } |
1007 | |
1008 | func (s *PartitionTestSuite) TestNoWriteNotNeeded(c *C) { |
1009 | @@ -301,7 +291,7 @@ |
1010 | u := newUboot(partition) |
1011 | c.Assert(u, NotNil) |
1012 | |
1013 | - c.Check(u.MarkCurrentBootSuccessful(), IsNil) |
1014 | + c.Check(u.MarkCurrentBootSuccessful("a"), IsNil) |
1015 | c.Assert(atomiCall, Equals, false) |
1016 | } |
1017 | |
1018 | @@ -318,7 +308,7 @@ |
1019 | u := newUboot(partition) |
1020 | c.Assert(u, NotNil) |
1021 | |
1022 | - c.Check(u.MarkCurrentBootSuccessful(), IsNil) |
1023 | + c.Check(u.MarkCurrentBootSuccessful("a"), IsNil) |
1024 | c.Assert(atomiCall, Equals, true) |
1025 | |
1026 | bytes, err := ioutil.ReadFile(bootloaderUbootEnvFile) |
1027 | |
1028 | === added file 'partition/dirs.go' |
1029 | --- partition/dirs.go 1970-01-01 00:00:00 +0000 |
1030 | +++ partition/dirs.go 2015-06-25 19:16:26 +0000 |
1031 | @@ -0,0 +1,41 @@ |
1032 | +// -*- Mode: Go; indent-tabs-mode: t -*- |
1033 | + |
1034 | +/* |
1035 | + * Copyright (C) 2014-2015 Canonical Ltd |
1036 | + * |
1037 | + * This program is free software: you can redistribute it and/or modify |
1038 | + * it under the terms of the GNU General Public License version 3 as |
1039 | + * published by the Free Software Foundation. |
1040 | + * |
1041 | + * This program is distributed in the hope that it will be useful, |
1042 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of |
1043 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
1044 | + * GNU General Public License for more details. |
1045 | + * |
1046 | + * You should have received a copy of the GNU General Public License |
1047 | + * along with this program. If not, see <http://www.gnu.org/licenses/>. |
1048 | + * |
1049 | + */ |
1050 | + |
1051 | +package partition |
1052 | + |
1053 | +import ( |
1054 | + "path/filepath" |
1055 | +) |
1056 | + |
1057 | +// The full path to the cache directory, which is used as a |
1058 | +// scratch pad, for downloading new images to and bind mounting the |
1059 | +// rootfs. |
1060 | +const cacheDirReal = "/writable/cache" |
1061 | + |
1062 | +var ( |
1063 | + // useful for overwriting in the tests |
1064 | + cacheDir = cacheDirReal |
1065 | + |
1066 | + // Directory to mount writable root filesystem below the cache |
1067 | + // diretory. |
1068 | + mountTargetReal = filepath.Join(cacheDir, "system") |
1069 | + |
1070 | + // useful to override in tests |
1071 | + mountTarget = mountTargetReal |
1072 | +) |
1073 | |
1074 | === added file 'partition/mount.go' |
1075 | --- partition/mount.go 1970-01-01 00:00:00 +0000 |
1076 | +++ partition/mount.go 2015-06-25 19:16:26 +0000 |
1077 | @@ -0,0 +1,153 @@ |
1078 | +// -*- Mode: Go; indent-tabs-mode: t -*- |
1079 | + |
1080 | +/* |
1081 | + * Copyright (C) 2014-2015 Canonical Ltd |
1082 | + * |
1083 | + * This program is free software: you can redistribute it and/or modify |
1084 | + * it under the terms of the GNU General Public License version 3 as |
1085 | + * published by the Free Software Foundation. |
1086 | + * |
1087 | + * This program is distributed in the hope that it will be useful, |
1088 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of |
1089 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
1090 | + * GNU General Public License for more details. |
1091 | + * |
1092 | + * You should have received a copy of the GNU General Public License |
1093 | + * along with this program. If not, see <http://www.gnu.org/licenses/>. |
1094 | + * |
1095 | + */ |
1096 | + |
1097 | +package partition |
1098 | + |
1099 | +import ( |
1100 | + "fmt" |
1101 | + "sort" |
1102 | +) |
1103 | + |
1104 | +// MountOption represents how the partition should be mounted, currently |
1105 | +// RO (read-only) and RW (read-write) are supported |
1106 | +type MountOption int |
1107 | + |
1108 | +const ( |
1109 | + // RO mounts the partition read-only |
1110 | + RO MountOption = iota |
1111 | + // RW mounts the partition read-only |
1112 | + RW |
1113 | +) |
1114 | + |
1115 | +// mountEntry represents a mount this package has created. |
1116 | +type mountEntry struct { |
1117 | + source string |
1118 | + target string |
1119 | + |
1120 | + options string |
1121 | + |
1122 | + // true if target refers to a bind mount. We could derive this |
1123 | + // from options, but this field saves the effort. |
1124 | + bindMount bool |
1125 | +} |
1126 | + |
1127 | +// mountEntryArray represents an array of mountEntry objects. |
1128 | +type mountEntryArray []mountEntry |
1129 | + |
1130 | +// current mounts that this package has created. |
1131 | +var mounts mountEntryArray |
1132 | + |
1133 | +// Len is part of the sort interface, required to allow sort to work |
1134 | +// with an array of Mount objects. |
1135 | +func (mounts mountEntryArray) Len() int { |
1136 | + return len(mounts) |
1137 | +} |
1138 | + |
1139 | +// Less is part of the sort interface, required to allow sort to work |
1140 | +// with an array of Mount objects. |
1141 | +func (mounts mountEntryArray) Less(i, j int) bool { |
1142 | + return mounts[i].target < mounts[j].target |
1143 | +} |
1144 | + |
1145 | +// Swap is part of the sort interface, required to allow sort to work |
1146 | +// with an array of Mount objects. |
1147 | +func (mounts mountEntryArray) Swap(i, j int) { |
1148 | + mounts[i], mounts[j] = mounts[j], mounts[i] |
1149 | +} |
1150 | + |
1151 | +// removeMountByTarget removes the Mount specified by the target from |
1152 | +// the global mounts array. |
1153 | +func removeMountByTarget(mnts mountEntryArray, target string) (results mountEntryArray) { |
1154 | + |
1155 | + for _, m := range mnts { |
1156 | + if m.target != target { |
1157 | + results = append(results, m) |
1158 | + } |
1159 | + } |
1160 | + |
1161 | + return results |
1162 | +} |
1163 | + |
1164 | +// undoMounts unmounts all mounts this package has mounted optionally |
1165 | +// only unmounting bind mounts and leaving all remaining mounts. |
1166 | +func undoMounts(bindMountsOnly bool) error { |
1167 | + |
1168 | + mountsCopy := make(mountEntryArray, len(mounts), cap(mounts)) |
1169 | + copy(mountsCopy, mounts) |
1170 | + |
1171 | + // reverse sort to ensure unmounts are handled in the correct |
1172 | + // order. |
1173 | + sort.Sort(sort.Reverse(mountsCopy)) |
1174 | + |
1175 | + // Iterate backwards since we want a reverse-sorted list of |
1176 | + // mounts to ensure we can unmount in order. |
1177 | + for _, mount := range mountsCopy { |
1178 | + if bindMountsOnly && !mount.bindMount { |
1179 | + continue |
1180 | + } |
1181 | + |
1182 | + if err := unmountAndRemoveFromGlobalMountList(mount.target); err != nil { |
1183 | + return err |
1184 | + } |
1185 | + } |
1186 | + |
1187 | + return nil |
1188 | +} |
1189 | + |
1190 | +// FIXME: use syscall.Mount() here |
1191 | +func mount(source, target, options string) (err error) { |
1192 | + var args []string |
1193 | + |
1194 | + args = append(args, "/bin/mount") |
1195 | + if options != "" { |
1196 | + args = append(args, fmt.Sprintf("-o%s", options)) |
1197 | + } |
1198 | + |
1199 | + args = append(args, source) |
1200 | + args = append(args, target) |
1201 | + |
1202 | + return runCommand(args...) |
1203 | +} |
1204 | + |
1205 | +// Mount the given directory and add it to the global mounts slice |
1206 | +func mountAndAddToGlobalMountList(m mountEntry) (err error) { |
1207 | + |
1208 | + err = mount(m.source, m.target, m.options) |
1209 | + if err == nil { |
1210 | + mounts = append(mounts, m) |
1211 | + } |
1212 | + |
1213 | + return err |
1214 | +} |
1215 | + |
1216 | +// Unmount the given directory and remove it from the global "mounts" slice |
1217 | +func unmountAndRemoveFromGlobalMountList(target string) (err error) { |
1218 | + err = runCommand("/bin/umount", target) |
1219 | + if err != nil { |
1220 | + return err |
1221 | + |
1222 | + } |
1223 | + |
1224 | + results := removeMountByTarget(mounts, target) |
1225 | + |
1226 | + // Update global |
1227 | + mounts = results |
1228 | + |
1229 | + return nil |
1230 | +} |
1231 | |
1232 | === added file 'partition/mount_test.go' |
1233 | --- partition/mount_test.go 1970-01-01 00:00:00 +0000 |
1234 | +++ partition/mount_test.go 2015-06-25 19:16:26 +0000 |
1235 | @@ -0,0 +1,64 @@ |
1236 | +// -*- Mode: Go; indent-tabs-mode: t -*- |
1237 | + |
1238 | +/* |
1239 | + * Copyright (C) 2014-2015 Canonical Ltd |
1240 | + * |
1241 | + * This program is free software: you can redistribute it and/or modify |
1242 | + * it under the terms of the GNU General Public License version 3 as |
1243 | + * published by the Free Software Foundation. |
1244 | + * |
1245 | + * This program is distributed in the hope that it will be useful, |
1246 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of |
1247 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
1248 | + * GNU General Public License for more details. |
1249 | + * |
1250 | + * You should have received a copy of the GNU General Public License |
1251 | + * along with this program. If not, see <http://www.gnu.org/licenses/>. |
1252 | + * |
1253 | + */ |
1254 | + |
1255 | +package partition |
1256 | + |
1257 | +import ( |
1258 | + . "gopkg.in/check.v1" |
1259 | +) |
1260 | + |
1261 | +func (s *PartitionTestSuite) TestMountEntryArray(c *C) { |
1262 | + mea := mountEntryArray{} |
1263 | + |
1264 | + c.Assert(mea.Len(), Equals, 0) |
1265 | + |
1266 | + me := mountEntry{source: "/dev", |
1267 | + target: "/dev", |
1268 | + options: "bind", |
1269 | + bindMount: true} |
1270 | + |
1271 | + mea = append(mea, me) |
1272 | + c.Assert(mea.Len(), Equals, 1) |
1273 | + |
1274 | + me = mountEntry{source: "/foo", |
1275 | + target: "/foo", |
1276 | + options: "", |
1277 | + bindMount: false} |
1278 | + |
1279 | + mea = append(mea, me) |
1280 | + c.Assert(mea.Len(), Equals, 2) |
1281 | + |
1282 | + c.Assert(mea.Less(0, 1), Equals, true) |
1283 | + c.Assert(mea.Less(1, 0), Equals, false) |
1284 | + |
1285 | + mea.Swap(0, 1) |
1286 | + c.Assert(mea.Less(0, 1), Equals, false) |
1287 | + c.Assert(mea.Less(1, 0), Equals, true) |
1288 | + |
1289 | + results := removeMountByTarget(mea, "invalid") |
1290 | + |
1291 | + // No change expected |
1292 | + c.Assert(results, DeepEquals, mea) |
1293 | + |
1294 | + results = removeMountByTarget(mea, "/dev") |
1295 | + |
1296 | + c.Assert(len(results), Equals, 1) |
1297 | + c.Assert(results[0], Equals, mountEntry{source: "/foo", |
1298 | + target: "/foo", options: "", bindMount: false}) |
1299 | +} |
1300 | |
1301 | === modified file 'partition/partition.go' |
1302 | --- partition/partition.go 2015-06-09 17:43:20 +0000 |
1303 | +++ partition/partition.go 2015-06-25 19:16:26 +0000 |
1304 | @@ -23,50 +23,37 @@ |
1305 | import ( |
1306 | "errors" |
1307 | "fmt" |
1308 | - "io/ioutil" |
1309 | "os" |
1310 | "os/signal" |
1311 | "path/filepath" |
1312 | "regexp" |
1313 | - "sort" |
1314 | "strings" |
1315 | + "sync" |
1316 | "syscall" |
1317 | |
1318 | - "gopkg.in/yaml.v2" |
1319 | - |
1320 | "launchpad.net/snappy/logger" |
1321 | ) |
1322 | |
1323 | -var signalHandlerRegistered = false |
1324 | - |
1325 | -// Name of writable user data partition label as created by |
1326 | -// ubuntu-device-flash(1). |
1327 | -const writablePartitionLabel = "writable" |
1328 | - |
1329 | -// Name of primary root filesystem partition label as created by |
1330 | -// ubuntu-device-flash(1). |
1331 | -const rootfsAlabel = "system-a" |
1332 | - |
1333 | -// Name of primary root filesystem partition label as created by |
1334 | -// ubuntu-device-flash(1). Note that this partition will |
1335 | -// only be present if this is an A/B upgrade system. |
1336 | -const rootfsBlabel = "system-b" |
1337 | - |
1338 | -// name of boot partition label as created by ubuntu-device-flash(1). |
1339 | -const bootPartitionLabel = "system-boot" |
1340 | - |
1341 | -// its useful to override this in tests |
1342 | -const realDefaultCacheDir = "/writable/cache" |
1343 | - |
1344 | -// FIXME: Should query system-image-cli (see bug LP:#1380574). |
1345 | -var defaultCacheDir = realDefaultCacheDir |
1346 | - |
1347 | -// Directory to mount writable root filesystem below the cache |
1348 | -// diretory. |
1349 | -const mountTarget = "system" |
1350 | - |
1351 | -// File creation mode used when any directories are created |
1352 | -const dirMode = 0750 |
1353 | +const ( |
1354 | + // Name of writable user data partition label as created by |
1355 | + // ubuntu-device-flash(1). |
1356 | + writablePartitionLabel = "writable" |
1357 | + |
1358 | + // Name of primary root filesystem partition label as created by |
1359 | + // ubuntu-device-flash(1). |
1360 | + rootfsAlabel = "system-a" |
1361 | + |
1362 | + // Name of primary root filesystem partition label as created by |
1363 | + // ubuntu-device-flash(1). Note that this partition will |
1364 | + // only be present if this is an A/B upgrade system. |
1365 | + rootfsBlabel = "system-b" |
1366 | + |
1367 | + // name of boot partition label as created by ubuntu-device-flash(1). |
1368 | + bootPartitionLabel = "system-boot" |
1369 | + |
1370 | + // File creation mode used when any directories are created |
1371 | + dirMode = 0750 |
1372 | +) |
1373 | |
1374 | var ( |
1375 | // ErrBootloader is returned if the bootloader can not be determined |
1376 | @@ -79,41 +66,6 @@ |
1377 | // ErrNoDualPartition is returned if you try to use a dual |
1378 | // partition feature on a single partition |
1379 | ErrNoDualPartition = errors.New("No dual partition") |
1380 | - |
1381 | - // ErrNoHardwareYaml is returned when no hardware yaml is found in |
1382 | - // the update, this means that there is nothing to process with regards |
1383 | - // to device parts. |
1384 | - ErrNoHardwareYaml = errors.New("no hardware.yaml") |
1385 | -) |
1386 | - |
1387 | -// Declarative specification of the type of system which specifies such |
1388 | -// details as: |
1389 | -// |
1390 | -// - the location of initrd+kernel within the system-image archive. |
1391 | -// - the location of hardware-specific .dtb files within the |
1392 | -// system-image archive. |
1393 | -// - the type of bootloader that should be used for this system. |
1394 | -// - expected system partition layout (single or dual rootfs's). |
1395 | -const hardwareSpecFile = "hardware.yaml" |
1396 | - |
1397 | -// Directory that _may_ get automatically created on unpack that |
1398 | -// contains updated hardware-specific boot assets (such as initrd, kernel) |
1399 | -const assetsDir = "assets" |
1400 | - |
1401 | -// Directory that _may_ get automatically created on unpack that |
1402 | -// contains updated hardware-specific assets that require flashing |
1403 | -// to the disk (such as uBoot, MLO) |
1404 | -const flashAssetsDir = "flashtool-assets" |
1405 | - |
1406 | -// MountOption represents how the partition should be mounted, currently |
1407 | -// RO (read-only) and RW (read-write) are supported |
1408 | -type MountOption int |
1409 | - |
1410 | -const ( |
1411 | - // RO mounts the partition read-only |
1412 | - RO MountOption = iota |
1413 | - // RW mounts the partition read-only |
1414 | - RW |
1415 | ) |
1416 | |
1417 | // Interface provides the interface to interact with a partition |
1418 | @@ -128,29 +80,7 @@ |
1419 | |
1420 | // run the function f with the otherRoot mounted |
1421 | RunWithOther(rw MountOption, f func(otherRoot string) (err error)) (err error) |
1422 | - |
1423 | - // Returns the full path to the (mounted and writable) |
1424 | - // bootloader-specific boot directory. |
1425 | - BootloaderDir() string |
1426 | -} |
1427 | - |
1428 | -// mountEntry represents a mount this package has created. |
1429 | -type mountEntry struct { |
1430 | - source string |
1431 | - target string |
1432 | - |
1433 | - options string |
1434 | - |
1435 | - // true if target refers to a bind mount. We could derive this |
1436 | - // from options, but this field saves the effort. |
1437 | - bindMount bool |
1438 | -} |
1439 | - |
1440 | -// mountEntryArray represents an array of mountEntry objects. |
1441 | -type mountEntryArray []mountEntry |
1442 | - |
1443 | -// current mounts that this package has created. |
1444 | -var mounts mountEntryArray |
1445 | +} |
1446 | |
1447 | // Partition is the type to interact with the partition |
1448 | type Partition struct { |
1449 | @@ -159,14 +89,15 @@ |
1450 | |
1451 | // just root partitions |
1452 | roots []string |
1453 | - |
1454 | - hardwareSpecFile string |
1455 | } |
1456 | |
1457 | type blockDevice struct { |
1458 | // label for partition |
1459 | name string |
1460 | |
1461 | + // the last char of the partition label |
1462 | + shortName string |
1463 | + |
1464 | // full path to device on which partition exists |
1465 | // (for example "/dev/sda3") |
1466 | device string |
1467 | @@ -178,77 +109,10 @@ |
1468 | mountpoint string |
1469 | } |
1470 | |
1471 | -// Representation of HARDWARE_SPEC_FILE |
1472 | -type hardwareSpecType struct { |
1473 | - Kernel string `yaml:"kernel"` |
1474 | - Initrd string `yaml:"initrd"` |
1475 | - DtbDir string `yaml:"dtbs"` |
1476 | - PartitionLayout string `yaml:"partition-layout"` |
1477 | - Bootloader bootloaderName `yaml:"bootloader"` |
1478 | -} |
1479 | - |
1480 | -// Len is part of the sort interface, required to allow sort to work |
1481 | -// with an array of Mount objects. |
1482 | -func (mounts mountEntryArray) Len() int { |
1483 | - return len(mounts) |
1484 | -} |
1485 | - |
1486 | -// Less is part of the sort interface, required to allow sort to work |
1487 | -// with an array of Mount objects. |
1488 | -func (mounts mountEntryArray) Less(i, j int) bool { |
1489 | - return mounts[i].target < mounts[j].target |
1490 | -} |
1491 | - |
1492 | -// Swap is part of the sort interface, required to allow sort to work |
1493 | -// with an array of Mount objects. |
1494 | -func (mounts mountEntryArray) Swap(i, j int) { |
1495 | - mounts[i], mounts[j] = mounts[j], mounts[i] |
1496 | -} |
1497 | - |
1498 | -// removeMountByTarget removes the Mount specified by the target from |
1499 | -// the global mounts array. |
1500 | -func removeMountByTarget(mnts mountEntryArray, target string) (results mountEntryArray) { |
1501 | - |
1502 | - for _, m := range mnts { |
1503 | - if m.target != target { |
1504 | - results = append(results, m) |
1505 | - } |
1506 | - } |
1507 | - |
1508 | - return results |
1509 | -} |
1510 | +var once sync.Once |
1511 | |
1512 | func init() { |
1513 | - if !signalHandlerRegistered { |
1514 | - setupSignalHandler() |
1515 | - signalHandlerRegistered = true |
1516 | - } |
1517 | -} |
1518 | - |
1519 | -// undoMounts unmounts all mounts this package has mounted optionally |
1520 | -// only unmounting bind mounts and leaving all remaining mounts. |
1521 | -func undoMounts(bindMountsOnly bool) error { |
1522 | - |
1523 | - mountsCopy := make(mountEntryArray, len(mounts), cap(mounts)) |
1524 | - copy(mountsCopy, mounts) |
1525 | - |
1526 | - // reverse sort to ensure unmounts are handled in the correct |
1527 | - // order. |
1528 | - sort.Sort(sort.Reverse(mountsCopy)) |
1529 | - |
1530 | - // Iterate backwards since we want a reverse-sorted list of |
1531 | - // mounts to ensure we can unmount in order. |
1532 | - for _, mount := range mountsCopy { |
1533 | - if bindMountsOnly && !mount.bindMount { |
1534 | - continue |
1535 | - } |
1536 | - |
1537 | - if err := unmountAndRemoveFromGlobalMountList(mount.target); err != nil { |
1538 | - return err |
1539 | - } |
1540 | - } |
1541 | - |
1542 | - return nil |
1543 | + once.Do(setupSignalHandler) |
1544 | } |
1545 | |
1546 | func signalHandler(sig os.Signal) { |
1547 | @@ -291,66 +155,6 @@ |
1548 | return labels |
1549 | } |
1550 | |
1551 | -func mount(source, target, options string) (err error) { |
1552 | - var args []string |
1553 | - |
1554 | - args = append(args, "/bin/mount") |
1555 | - if options != "" { |
1556 | - args = append(args, fmt.Sprintf("-o%s", options)) |
1557 | - } |
1558 | - |
1559 | - args = append(args, source) |
1560 | - args = append(args, target) |
1561 | - |
1562 | - return runCommand(args...) |
1563 | -} |
1564 | - |
1565 | -// Mount the given directory and add it to the global mounts slice |
1566 | -func mountAndAddToGlobalMountList(m mountEntry) (err error) { |
1567 | - |
1568 | - err = mount(m.source, m.target, m.options) |
1569 | - if err == nil { |
1570 | - mounts = append(mounts, m) |
1571 | - } |
1572 | - |
1573 | - return err |
1574 | -} |
1575 | - |
1576 | -// Unmount the given directory and remove it from the global "mounts" slice |
1577 | -func unmountAndRemoveFromGlobalMountList(target string) (err error) { |
1578 | - err = runCommand("/bin/umount", target) |
1579 | - if err != nil { |
1580 | - return err |
1581 | - |
1582 | - } |
1583 | - |
1584 | - results := removeMountByTarget(mounts, target) |
1585 | - |
1586 | - // Update global |
1587 | - mounts = results |
1588 | - |
1589 | - return nil |
1590 | -} |
1591 | - |
1592 | -// Run fsck(8) on specified device. |
1593 | -func fsck(device string) (err error) { |
1594 | - return runCommand( |
1595 | - "/sbin/fsck", |
1596 | - "-M", // Paranoia - don't fsck if already mounted |
1597 | - "-av", device) |
1598 | -} |
1599 | - |
1600 | -// Returns the position of the string in the given slice or -1 if its not found |
1601 | -func stringInSlice(slice []string, value string) int { |
1602 | - for i, s := range slice { |
1603 | - if s == value { |
1604 | - return i |
1605 | - } |
1606 | - } |
1607 | - |
1608 | - return -1 |
1609 | -} |
1610 | - |
1611 | var runLsblk = func() (out []string, err error) { |
1612 | output, err := runCommandWithStdout( |
1613 | "/bin/lsblk", |
1614 | @@ -430,8 +234,10 @@ |
1615 | continue |
1616 | } |
1617 | */ |
1618 | + shortName := string(name[len(name)-1]) |
1619 | bd := blockDevice{ |
1620 | name: fields["LABEL"], |
1621 | + shortName: shortName, |
1622 | device: device, |
1623 | mountpoint: fields["MOUNTPOINT"], |
1624 | parentName: disk, |
1625 | @@ -443,20 +249,11 @@ |
1626 | return partitions, nil |
1627 | } |
1628 | |
1629 | -var makeDirectory = func(path string, mode os.FileMode) error { |
1630 | - return os.MkdirAll(path, mode) |
1631 | -} |
1632 | - |
1633 | -func (p *Partition) makeMountPoint() (err error) { |
1634 | - return makeDirectory(p.MountTarget(), dirMode) |
1635 | -} |
1636 | - |
1637 | // New creates a new partition type |
1638 | func New() *Partition { |
1639 | p := new(Partition) |
1640 | |
1641 | p.getPartitionDetails() |
1642 | - p.hardwareSpecFile = filepath.Join(p.cacheDir(), hardwareSpecFile) |
1643 | |
1644 | return p |
1645 | } |
1646 | @@ -500,7 +297,7 @@ |
1647 | }() |
1648 | } |
1649 | |
1650 | - err = f(p.MountTarget()) |
1651 | + err = f(mountTarget) |
1652 | return err |
1653 | } |
1654 | |
1655 | @@ -529,7 +326,8 @@ |
1656 | return err |
1657 | } |
1658 | |
1659 | - return bootloader.MarkCurrentBootSuccessful() |
1660 | + currentRootfs := p.rootPartition().shortName |
1661 | + return bootloader.MarkCurrentBootSuccessful(currentRootfs) |
1662 | } |
1663 | |
1664 | // IsNextBootOther return true if the next boot will use the other rootfs |
1665 | @@ -539,48 +337,27 @@ |
1666 | if err != nil { |
1667 | return false |
1668 | } |
1669 | - return isNextBootOther(bootloader) |
1670 | -} |
1671 | - |
1672 | -// Returns the full path to the cache directory, which is used as a |
1673 | -// scratch pad, for downloading new images to and bind mounting the |
1674 | -// rootfs. |
1675 | -func (p *Partition) cacheDir() string { |
1676 | - return defaultCacheDir |
1677 | -} |
1678 | - |
1679 | -func (p *Partition) hardwareSpec() (hardwareSpecType, error) { |
1680 | - h := hardwareSpecType{} |
1681 | - |
1682 | - data, err := ioutil.ReadFile(p.hardwareSpecFile) |
1683 | - // if hardware.yaml does not exist it just means that there was no |
1684 | - // device part in the update. |
1685 | - if os.IsNotExist(err) { |
1686 | - return h, ErrNoHardwareYaml |
1687 | - } else if err != nil { |
1688 | - return h, err |
1689 | - } |
1690 | - |
1691 | - if err := yaml.Unmarshal([]byte(data), &h); err != nil { |
1692 | - return h, err |
1693 | - } |
1694 | - |
1695 | - return h, nil |
1696 | -} |
1697 | - |
1698 | -// Return full path to the main assets directory |
1699 | -func (p *Partition) assetsDir() string { |
1700 | - return filepath.Join(p.cacheDir(), assetsDir) |
1701 | -} |
1702 | - |
1703 | -// Return the full path to the hardware-specific flash assets directory. |
1704 | -func (p *Partition) flashAssetsDir() string { |
1705 | - return filepath.Join(p.cacheDir(), flashAssetsDir) |
1706 | -} |
1707 | - |
1708 | -// MountTarget gets the full path to the mount target directory |
1709 | -func (p *Partition) MountTarget() string { |
1710 | - return filepath.Join(p.cacheDir(), mountTarget) |
1711 | + |
1712 | + value, err := bootloader.GetBootVar(bootloaderBootmodeVar) |
1713 | + if err != nil { |
1714 | + return false |
1715 | + } |
1716 | + |
1717 | + if value != bootloaderBootmodeTry { |
1718 | + return false |
1719 | + } |
1720 | + |
1721 | + fsname, err := bootloader.GetNextBootRootFSName() |
1722 | + if err != nil { |
1723 | + return false |
1724 | + } |
1725 | + |
1726 | + otherRootfs := p.otherRootPartition().shortName |
1727 | + if fsname == otherRootfs { |
1728 | + return true |
1729 | + } |
1730 | + |
1731 | + return false |
1732 | } |
1733 | |
1734 | func (p *Partition) getPartitionDetails() (err error) { |
1735 | @@ -676,11 +453,13 @@ |
1736 | func (p *Partition) mountOtherRootfs(readOnly bool) (err error) { |
1737 | var other *blockDevice |
1738 | |
1739 | - p.makeMountPoint() |
1740 | + if err := os.MkdirAll(mountTarget, dirMode); err != nil { |
1741 | + return err |
1742 | + } |
1743 | |
1744 | other = p.otherRootPartition() |
1745 | |
1746 | - m := mountEntry{source: other.device, target: p.MountTarget()} |
1747 | + m := mountEntry{source: other.device, target: mountTarget} |
1748 | |
1749 | if readOnly { |
1750 | m.options = "ro" |
1751 | @@ -707,9 +486,7 @@ |
1752 | |
1753 | // Ensure the other partition is mounted read-only. |
1754 | func (p *Partition) ensureOtherMountedRO() (err error) { |
1755 | - mountpoint := p.MountTarget() |
1756 | - |
1757 | - if err = runCommand("/bin/mountpoint", mountpoint); err == nil { |
1758 | + if err = runCommand("/bin/mountpoint", mountTarget); err == nil { |
1759 | // already mounted |
1760 | return err |
1761 | } |
1762 | @@ -741,14 +518,14 @@ |
1763 | |
1764 | return mountAndAddToGlobalMountList(mountEntry{ |
1765 | source: other.device, |
1766 | - target: p.MountTarget()}) |
1767 | + target: mountTarget}) |
1768 | } |
1769 | // r/w -> r/o: no fsck required. |
1770 | - return mount(other.device, p.MountTarget(), "remount,ro") |
1771 | + return mount(other.device, mountTarget, "remount,ro") |
1772 | } |
1773 | |
1774 | func (p *Partition) unmountOtherRootfs() (err error) { |
1775 | - return unmountAndRemoveFromGlobalMountList(p.MountTarget()) |
1776 | + return unmountAndRemoveFromGlobalMountList(mountTarget) |
1777 | } |
1778 | |
1779 | // The bootloader requires a few filesystems to be mounted when |
1780 | @@ -773,7 +550,7 @@ |
1781 | } |
1782 | |
1783 | for _, fs := range requiredChrootMounts { |
1784 | - target := filepath.Join(p.MountTarget(), fs) |
1785 | + target := filepath.Join(mountTarget, fs) |
1786 | |
1787 | err := mountAndAddToGlobalMountList(mountEntry{source: fs, |
1788 | target: target, |
1789 | @@ -787,11 +564,11 @@ |
1790 | // Grub also requires access to both rootfs's when run from |
1791 | // within a chroot (to allow it to create menu entries for |
1792 | // both), so bindmount the real rootfs. |
1793 | - targetInChroot := filepath.Join(p.MountTarget(), p.MountTarget()) |
1794 | + targetInChroot := filepath.Join(mountTarget, mountTarget) |
1795 | |
1796 | // FIXME: we should really remove this after the unmount |
1797 | |
1798 | - if err = makeDirectory(targetInChroot, dirMode); err != nil { |
1799 | + if err = os.MkdirAll(targetInChroot, dirMode); err != nil { |
1800 | return err |
1801 | } |
1802 | |
1803 | @@ -822,7 +599,8 @@ |
1804 | // wrong given that handleAssets may fails and we will |
1805 | // knowingly boot into a broken system |
1806 | err = p.RunWithOther(RW, func(otherRoot string) (err error) { |
1807 | - return bootloader.ToggleRootFS() |
1808 | + otherRootfs := p.otherRootPartition().shortName |
1809 | + return bootloader.ToggleRootFS(otherRootfs) |
1810 | }) |
1811 | |
1812 | if err != nil { |
1813 | @@ -831,14 +609,3 @@ |
1814 | |
1815 | return bootloader.HandleAssets() |
1816 | } |
1817 | - |
1818 | -// BootloaderDir returns the full path to the (mounted and writable) |
1819 | -// bootloader-specific boot directory. |
1820 | -func (p *Partition) BootloaderDir() string { |
1821 | - bootloader, err := bootloader(p) |
1822 | - if err != nil { |
1823 | - return "" |
1824 | - } |
1825 | - |
1826 | - return bootloader.BootDir() |
1827 | -} |
1828 | |
1829 | === modified file 'partition/partition_test.go' |
1830 | --- partition/partition_test.go 2015-06-09 17:43:20 +0000 |
1831 | +++ partition/partition_test.go 2015-06-25 19:16:26 +0000 |
1832 | @@ -44,14 +44,13 @@ |
1833 | return err |
1834 | } |
1835 | |
1836 | -func mockMakeDirectory(path string, mode os.FileMode) error { |
1837 | - return nil |
1838 | -} |
1839 | - |
1840 | func (s *PartitionTestSuite) SetUpTest(c *C) { |
1841 | s.tempdir = c.MkDir() |
1842 | runLsblk = mockRunLsblkDualSnappy |
1843 | |
1844 | + // custom mount target |
1845 | + mountTarget = c.MkDir() |
1846 | + |
1847 | // setup fake paths for grub |
1848 | bootloaderGrubDir = filepath.Join(s.tempdir, "boot", "grub") |
1849 | bootloaderGrubConfigFile = filepath.Join(bootloaderGrubDir, "grub.cfg") |
1850 | @@ -72,8 +71,10 @@ |
1851 | |
1852 | // always restore what we might have mocked away |
1853 | runCommand = runCommandImpl |
1854 | - defaultCacheDir = realDefaultCacheDir |
1855 | bootloader = bootloaderImpl |
1856 | + cacheDir = cacheDirReal |
1857 | + hardwareSpecFile = hardwareSpecFileReal |
1858 | + mountTarget = mountTargetReal |
1859 | |
1860 | // grub vars |
1861 | bootloaderGrubConfigFile = bootloaderGrubConfigFileReal |
1862 | @@ -109,20 +110,6 @@ |
1863 | return tmp.Name() |
1864 | } |
1865 | |
1866 | -func (s *PartitionTestSuite) TestHardwareSpec(c *C) { |
1867 | - p := New() |
1868 | - c.Assert(p, NotNil) |
1869 | - |
1870 | - p.hardwareSpecFile = makeHardwareYaml(c, "") |
1871 | - hw, err := p.hardwareSpec() |
1872 | - c.Assert(err, IsNil) |
1873 | - c.Assert(hw.Kernel, Equals, "assets/vmlinuz") |
1874 | - c.Assert(hw.Initrd, Equals, "assets/initrd.img") |
1875 | - c.Assert(hw.DtbDir, Equals, "assets/dtbs") |
1876 | - c.Assert(hw.PartitionLayout, Equals, bootloaderSystemAB) |
1877 | - c.Assert(hw.Bootloader, Equals, bootloaderNameUboot) |
1878 | -} |
1879 | - |
1880 | func mockRunLsblkDualSnappy() (output []string, err error) { |
1881 | dualData := ` |
1882 | NAME="sda" LABEL="" PKNAME="" MOUNTPOINT="" |
1883 | @@ -136,46 +123,6 @@ |
1884 | return strings.Split(dualData, "\n"), err |
1885 | } |
1886 | |
1887 | -func (s *PartitionTestSuite) TestMountEntryArray(c *C) { |
1888 | - mea := mountEntryArray{} |
1889 | - |
1890 | - c.Assert(mea.Len(), Equals, 0) |
1891 | - |
1892 | - me := mountEntry{source: "/dev", |
1893 | - target: "/dev", |
1894 | - options: "bind", |
1895 | - bindMount: true} |
1896 | - |
1897 | - mea = append(mea, me) |
1898 | - c.Assert(mea.Len(), Equals, 1) |
1899 | - |
1900 | - me = mountEntry{source: "/foo", |
1901 | - target: "/foo", |
1902 | - options: "", |
1903 | - bindMount: false} |
1904 | - |
1905 | - mea = append(mea, me) |
1906 | - c.Assert(mea.Len(), Equals, 2) |
1907 | - |
1908 | - c.Assert(mea.Less(0, 1), Equals, true) |
1909 | - c.Assert(mea.Less(1, 0), Equals, false) |
1910 | - |
1911 | - mea.Swap(0, 1) |
1912 | - c.Assert(mea.Less(0, 1), Equals, false) |
1913 | - c.Assert(mea.Less(1, 0), Equals, true) |
1914 | - |
1915 | - results := removeMountByTarget(mea, "invalid") |
1916 | - |
1917 | - // No change expected |
1918 | - c.Assert(results, DeepEquals, mea) |
1919 | - |
1920 | - results = removeMountByTarget(mea, "/dev") |
1921 | - |
1922 | - c.Assert(len(results), Equals, 1) |
1923 | - c.Assert(results[0], Equals, mountEntry{source: "/foo", |
1924 | - target: "/foo", options: "", bindMount: false}) |
1925 | -} |
1926 | - |
1927 | func (s *PartitionTestSuite) TestSnappyDualRoot(c *C) { |
1928 | p := New() |
1929 | c.Assert(p.dualRootPartitions(), Equals, true) |
1930 | @@ -218,14 +165,13 @@ |
1931 | return nil |
1932 | }) |
1933 | c.Assert(err, IsNil) |
1934 | - c.Assert(reportedRoot, Equals, (&Partition{}).MountTarget()) |
1935 | + c.Assert(reportedRoot, Equals, mountTarget) |
1936 | } |
1937 | |
1938 | func (s *PartitionTestSuite) TestRunWithOtherDualParitionRWFuncErr(c *C) { |
1939 | c.Assert(mounts, DeepEquals, mountEntryArray(nil)) |
1940 | |
1941 | runCommand = mockRunCommand |
1942 | - makeDirectory = mockMakeDirectory |
1943 | |
1944 | p := New() |
1945 | err := p.RunWithOther(RW, func(otherRoot string) (err error) { |
1946 | @@ -239,8 +185,12 @@ |
1947 | // ensure cleanup happend |
1948 | |
1949 | // FIXME: mounts are global |
1950 | - expected := mountEntry{source: "/dev/sda4", |
1951 | - target: "/writable/cache/system", options: "", bindMount: false} |
1952 | + expected := mountEntry{ |
1953 | + source: "/dev/sda4", |
1954 | + target: mountTarget, |
1955 | + options: "", |
1956 | + bindMount: false, |
1957 | + } |
1958 | |
1959 | // At program exit, "other" should still be mounted |
1960 | c.Assert(mounts, DeepEquals, mountEntryArray{expected}) |
1961 | @@ -295,8 +245,12 @@ |
1962 | c.Assert(p, NotNil) |
1963 | |
1964 | p.mountOtherRootfs(false) |
1965 | - expected := mountEntry{source: "/dev/sda4", |
1966 | - target: "/writable/cache/system", options: "", bindMount: false} |
1967 | + expected := mountEntry{ |
1968 | + source: "/dev/sda4", |
1969 | + target: mountTarget, |
1970 | + options: "", |
1971 | + bindMount: false, |
1972 | + } |
1973 | |
1974 | c.Assert(mounts, DeepEquals, mountEntryArray{expected}) |
1975 | |
1976 | @@ -313,26 +267,26 @@ |
1977 | |
1978 | p.bindmountRequiredFilesystems() |
1979 | c.Assert(mounts, DeepEquals, mountEntryArray{ |
1980 | - mountEntry{source: "/dev", target: p.MountTarget() + "/dev", |
1981 | - options: "bind", bindMount: true}, |
1982 | - |
1983 | - mountEntry{source: "/proc", target: p.MountTarget() + "/proc", |
1984 | - options: "bind", bindMount: true}, |
1985 | - |
1986 | - mountEntry{source: "/sys", target: p.MountTarget() + "/sys", |
1987 | - options: "bind", bindMount: true}, |
1988 | - mountEntry{source: "/boot/efi", target: p.MountTarget() + "/boot/efi", |
1989 | + mountEntry{source: "/dev", target: mountTarget + "/dev", |
1990 | + options: "bind", bindMount: true}, |
1991 | + |
1992 | + mountEntry{source: "/proc", target: mountTarget + "/proc", |
1993 | + options: "bind", bindMount: true}, |
1994 | + |
1995 | + mountEntry{source: "/sys", target: mountTarget + "/sys", |
1996 | + options: "bind", bindMount: true}, |
1997 | + mountEntry{source: "/boot/efi", target: mountTarget + "/boot/efi", |
1998 | options: "bind", bindMount: true}, |
1999 | |
2000 | // this comes from the grub bootloader via AdditionalBindMounts |
2001 | - mountEntry{source: "/boot/grub", target: p.MountTarget() + "/boot/grub", |
2002 | + mountEntry{source: "/boot/grub", target: mountTarget + "/boot/grub", |
2003 | options: "bind", bindMount: true}, |
2004 | |
2005 | // Required to allow grub inside the chroot to access |
2006 | // the "current" rootfs outside the chroot (used |
2007 | // to generate the grub menuitems). |
2008 | mountEntry{source: "/", |
2009 | - target: p.MountTarget() + p.MountTarget(), |
2010 | + target: mountTarget + mountTarget, |
2011 | options: "bind,ro", bindMount: true}, |
2012 | }) |
2013 | p.unmountRequiredFilesystems() |
2014 | @@ -351,23 +305,23 @@ |
2015 | p.bindmountRequiredFilesystems() |
2016 | c.Assert(mounts, DeepEquals, mountEntryArray{ |
2017 | |
2018 | - mountEntry{source: "/dev/sda4", target: "/writable/cache/system", |
2019 | + mountEntry{source: "/dev/sda4", target: mountTarget, |
2020 | options: "", bindMount: false}, |
2021 | |
2022 | - mountEntry{source: "/dev", target: p.MountTarget() + "/dev", |
2023 | - options: "bind", bindMount: true}, |
2024 | - |
2025 | - mountEntry{source: "/proc", target: p.MountTarget() + "/proc", |
2026 | - options: "bind", bindMount: true}, |
2027 | - |
2028 | - mountEntry{source: "/sys", target: p.MountTarget() + "/sys", |
2029 | - options: "bind", bindMount: true}, |
2030 | - |
2031 | - mountEntry{source: "/boot/efi", target: p.MountTarget() + "/boot/efi", |
2032 | + mountEntry{source: "/dev", target: mountTarget + "/dev", |
2033 | + options: "bind", bindMount: true}, |
2034 | + |
2035 | + mountEntry{source: "/proc", target: mountTarget + "/proc", |
2036 | + options: "bind", bindMount: true}, |
2037 | + |
2038 | + mountEntry{source: "/sys", target: mountTarget + "/sys", |
2039 | + options: "bind", bindMount: true}, |
2040 | + |
2041 | + mountEntry{source: "/boot/efi", target: mountTarget + "/boot/efi", |
2042 | options: "bind", bindMount: true}, |
2043 | |
2044 | mountEntry{source: "/", |
2045 | - target: p.MountTarget() + p.MountTarget(), |
2046 | + target: mountTarget + mountTarget, |
2047 | options: "bind,ro", bindMount: true}, |
2048 | }) |
2049 | |
2050 | @@ -375,8 +329,12 @@ |
2051 | undoMounts(true) |
2052 | |
2053 | c.Assert(mounts, DeepEquals, mountEntryArray{ |
2054 | - mountEntry{source: "/dev/sda4", target: "/writable/cache/system", |
2055 | - options: "", bindMount: false}, |
2056 | + mountEntry{ |
2057 | + source: "/dev/sda4", |
2058 | + target: mountTarget, |
2059 | + options: "", |
2060 | + bindMount: false, |
2061 | + }, |
2062 | }) |
2063 | |
2064 | // should unmount everything |
2065 | @@ -421,7 +379,7 @@ |
2066 | func (b *mockBootloader) Name() bootloaderName { |
2067 | return "mocky" |
2068 | } |
2069 | -func (b *mockBootloader) ToggleRootFS() error { |
2070 | +func (b *mockBootloader) ToggleRootFS(otherRootfs string) error { |
2071 | b.ToggleRootFSCalled = true |
2072 | return nil |
2073 | } |
2074 | @@ -436,16 +394,10 @@ |
2075 | func (b *mockBootloader) GetBootVar(name string) (string, error) { |
2076 | return "", nil |
2077 | } |
2078 | -func (b *mockBootloader) GetRootFSName() string { |
2079 | - return "" |
2080 | -} |
2081 | -func (b *mockBootloader) GetOtherRootFSName() string { |
2082 | - return "" |
2083 | -} |
2084 | func (b *mockBootloader) GetNextBootRootFSName() (string, error) { |
2085 | return "", nil |
2086 | } |
2087 | -func (b *mockBootloader) MarkCurrentBootSuccessful() error { |
2088 | +func (b *mockBootloader) MarkCurrentBootSuccessful(currentRootfs string) error { |
2089 | b.MarkCurrentBootSuccessfulCalled = true |
2090 | return nil |
2091 | } |
2092 | |
2093 | === modified file 'partition/utils.go' |
2094 | --- partition/utils.go 2015-05-19 14:09:19 +0000 |
2095 | +++ partition/utils.go 2015-06-25 19:16:26 +0000 |
2096 | @@ -69,3 +69,22 @@ |
2097 | |
2098 | // This is a var instead of a function to making mocking in the tests easier |
2099 | var runCommandWithStdout = runCommandWithStdoutImpl |
2100 | + |
2101 | +// Run fsck(8) on specified device. |
2102 | +func fsck(device string) (err error) { |
2103 | + return runCommand( |
2104 | + "/sbin/fsck", |
2105 | + "-M", // Paranoia - don't fsck if already mounted |
2106 | + "-av", device) |
2107 | +} |
2108 | + |
2109 | +// Returns the position of the string in the given slice or -1 if its not found |
2110 | +func stringInSlice(slice []string, value string) int { |
2111 | + for i, s := range slice { |
2112 | + if s == value { |
2113 | + return i |
2114 | + } |
2115 | + } |
2116 | + |
2117 | + return -1 |
2118 | +} |
2119 | |
2120 | === modified file 'snappy/errors.go' |
2121 | --- snappy/errors.go 2015-06-04 22:21:51 +0000 |
2122 | +++ snappy/errors.go 2015-06-25 19:16:26 +0000 |
2123 | @@ -140,6 +140,8 @@ |
2124 | |
2125 | // ErrInvalidSeccompPolicy is returned when policy-version and policy-vender are not set together |
2126 | ErrInvalidSeccompPolicy = errors.New("policy-version and policy-vendor must be specified together") |
2127 | + // ErrNoSeccompPolicy is returned when an expected seccomp policy is not provided. |
2128 | + ErrNoSeccompPolicy = errors.New("no seccomp policy provided") |
2129 | ) |
2130 | |
2131 | // ErrArchitectureNotSupported is returned when trying to install a snappy package that |
2132 | |
2133 | === modified file 'snappy/install.go' |
2134 | --- snappy/install.go 2015-06-11 06:33:42 +0000 |
2135 | +++ snappy/install.go 2015-06-25 19:16:26 +0000 |
2136 | @@ -25,6 +25,7 @@ |
2137 | "sort" |
2138 | |
2139 | "launchpad.net/snappy/logger" |
2140 | + "launchpad.net/snappy/partition" |
2141 | "launchpad.net/snappy/progress" |
2142 | "launchpad.net/snappy/provisioning" |
2143 | ) |
2144 | @@ -96,8 +97,7 @@ |
2145 | // FIXME: this is terrible, we really need a single |
2146 | // bootloader dir like /boot or /boot/loader |
2147 | // instead of having to query the partition code |
2148 | - p := newPartition() |
2149 | - if provisioning.InDeveloperMode(p.BootloaderDir()) { |
2150 | + if provisioning.InDeveloperMode(partition.BootloaderDir()) { |
2151 | flags |= AllowUnauthenticated |
2152 | } |
2153 | |
2154 | |
2155 | === modified file 'snappy/security.go' |
2156 | --- snappy/security.go 2015-06-02 16:31:01 +0000 |
2157 | +++ snappy/security.go 2015-06-25 19:16:26 +0000 |
2158 | @@ -151,6 +151,11 @@ |
2159 | syscalls := []string{} |
2160 | |
2161 | if sd.SecurityOverride != nil { |
2162 | + if sd.SecurityOverride.Seccomp == "" { |
2163 | + logger.Noticef("No seccomp policy found") |
2164 | + return nil, ErrNoSeccompPolicy |
2165 | + } |
2166 | + |
2167 | fn := filepath.Join(baseDir, sd.SecurityOverride.Seccomp) |
2168 | var s securitySeccompOverride |
2169 | err := readSeccompOverride(fn, &s) |
2170 | |
2171 | === modified file 'snappy/security_test.go' |
2172 | --- snappy/security_test.go 2015-06-08 16:26:25 +0000 |
2173 | +++ snappy/security_test.go 2015-06-25 19:16:26 +0000 |
2174 | @@ -58,6 +58,13 @@ |
2175 | c.Assert(string(content), Equals, expected) |
2176 | } |
2177 | |
2178 | +func (a *SecurityTestSuite) TestSnappyNoSeccompOverrideEntry(c *C) { |
2179 | + sd := SecurityDefinitions{SecurityOverride: &SecurityOverrideDefinition{}} |
2180 | + |
2181 | + _, err := generateSeccompPolicy(c.MkDir(), "appName", sd) |
2182 | + c.Assert(err, Equals, ErrNoSeccompPolicy) |
2183 | +} |
2184 | + |
2185 | // no special security settings generate the default |
2186 | func (a *SecurityTestSuite) TestSnappyHandleApparmorSecurityDefault(c *C) { |
2187 | sec := &SecurityDefinitions{} |
2188 | |
2189 | === modified file 'snappy/systemimage.go' |
2190 | --- snappy/systemimage.go 2015-06-10 13:38:01 +0000 |
2191 | +++ snappy/systemimage.go 2015-06-25 19:16:26 +0000 |
2192 | @@ -169,9 +169,16 @@ |
2193 | return s.partition.ToggleNextBoot() |
2194 | } |
2195 | |
2196 | +// override in tests |
2197 | +var bootloaderDir = bootloaderDirImpl |
2198 | + |
2199 | +func bootloaderDirImpl() string { |
2200 | + return partition.BootloaderDir() |
2201 | +} |
2202 | + |
2203 | // Install installs the snap |
2204 | func (s *SystemImagePart) Install(pb progress.Meter, flags InstallFlags) (name string, err error) { |
2205 | - if provisioning.IsSideLoaded(s.partition.BootloaderDir()) { |
2206 | + if provisioning.IsSideLoaded(bootloaderDir()) { |
2207 | return "", ErrSideLoaded |
2208 | } |
2209 | |
2210 | |
2211 | === modified file 'snappy/systemimage_test.go' |
2212 | --- snappy/systemimage_test.go 2015-06-09 17:43:20 +0000 |
2213 | +++ snappy/systemimage_test.go 2015-06-25 19:16:26 +0000 |
2214 | @@ -28,7 +28,7 @@ |
2215 | "strings" |
2216 | "testing" |
2217 | |
2218 | - partition "launchpad.net/snappy/partition" |
2219 | + "launchpad.net/snappy/partition" |
2220 | "launchpad.net/snappy/provisioning" |
2221 | |
2222 | . "gopkg.in/check.v1" |
2223 | @@ -72,6 +72,7 @@ |
2224 | func (s *SITestSuite) TearDownTest(c *C) { |
2225 | s.mockSystemImageWebServer.Close() |
2226 | systemImageRoot = "/" |
2227 | + bootloaderDir = bootloaderDirImpl |
2228 | } |
2229 | |
2230 | func makeMockSystemImageCli(c *C, tempdir string) string { |
2231 | @@ -390,18 +391,16 @@ |
2232 | device-part: /some/path/file.tgz |
2233 | developer-mode: true |
2234 | ` |
2235 | - tempBootDir, err = ioutil.TempDir("", "") |
2236 | - c.Assert(err, IsNil) |
2237 | - |
2238 | + tempBootDir := c.MkDir() |
2239 | parts, err := s.systemImage.Updates() |
2240 | |
2241 | sp := parts[0].(*SystemImagePart) |
2242 | mockPartition := MockPartition{} |
2243 | sp.partition = &mockPartition |
2244 | |
2245 | - bootDir := sp.partition.BootloaderDir() |
2246 | + bootloaderDir = func() string { return tempBootDir } |
2247 | |
2248 | - sideLoaded := filepath.Join(bootDir, provisioning.InstallYamlFile) |
2249 | + sideLoaded := filepath.Join(tempBootDir, provisioning.InstallYamlFile) |
2250 | |
2251 | err = os.MkdirAll(filepath.Dir(sideLoaded), 0775) |
2252 | c.Assert(err, IsNil) |
2253 | @@ -414,7 +413,4 @@ |
2254 | // Ensure the install fails if the system is sideloaded |
2255 | _, err = sp.Install(pb, 0) |
2256 | c.Assert(err, Equals, ErrSideLoaded) |
2257 | - |
2258 | - os.Remove(tempBootDir) |
2259 | - tempBootDir = "" |
2260 | } |
Thanks a lot :)