Merge lp:~mvo/snappy/snappy-lp1460152-workaround-15.04 into lp:~snappy-dev/snappy/snappy-moved-to-github

Proposed by Michael Vogt
Status: Superseded
Proposed branch: lp:~mvo/snappy/snappy-lp1460152-workaround-15.04
Merge into: lp:~snappy-dev/snappy/snappy-moved-to-github
Diff against target: 1022 lines (+690/-17) (has conflicts)
16 files modified
helpers/helpers.go (+186/-8)
helpers/helpers_test.go (+116/-0)
partition/bootloader_uboot.go (+1/-4)
partition/partition.go (+3/-0)
progress/progress.go (+6/-2)
progress/progress_test.go (+1/-1)
snappy/click.go (+260/-1)
snappy/dirs.go (+4/-0)
snappy/errors.go (+2/-1)
snappy/snapp.go (+17/-0)
snappy/snapp_test.go (+19/-0)
snappy/systemimage.go (+23/-0)
snappy/systemimage_native.go (+2/-0)
snappy/systemimage_test.go (+30/-0)
systemd/systemd.go (+14/-0)
systemd/systemd_test.go (+6/-0)
Text conflict in helpers/helpers.go
Text conflict in helpers/helpers_test.go
Text conflict in snappy/click.go
Text conflict in snappy/snapp.go
Text conflict in snappy/snapp_test.go
Text conflict in systemd/systemd.go
Text conflict in systemd/systemd_test.go
To merge this branch: bzr merge lp:~mvo/snappy/snappy-lp1460152-workaround-15.04
Reviewer Review Type Date Requested Status
Snappy Developers Pending
Review via email: mp+261147@code.launchpad.net

Description of the change

This is a cherry pick of the workaround for lp #1460152 for the 15.04
branch.

To post a comment you must log in.

Unmerged revisions

451. By Michael Vogt

cherry pick r486 from lp:~mvo/snappy/snappy-lp1460152-workaround

450. By Sergio Schvezov

Don't allow installation of packages with unsupported architectures (backported from trunk with bzr merge -c 484 from trunk) by sergiusens approved by chipaca

449. By Michael Terry

Allow ".." in file paths as long as it isn't an entire element. (i.e. allow "hello..you" or "...")

We call filepath.Clean right before our ".." check. So the only instances of ".." will be in the first element. That lets us simplify the check a lot.

This is a backport of r457 from trunk. by mterry approved by chipaca

448. By Michael Terry

Fix intermittent "permission denied" errors when installing snaps by making sure that we always unpack in the same OS thread that dropped its privileges.

This is a backport of r481 from trunk. by mterry approved by chipaca

447. By Michael Terry

Unify handling of app environment variables. Now hooks, binaries, and services all have the same variables (mostly).

This is a backport of r483 from trunk. by mterry approved by chipaca

446. By Sergio Schvezov

Backport revno 470 from trunk: Avoid writing to snappy-system.txt if not required by sergiusens approved by mvo

445. By Michael Vogt

Improve error reporting for failed hooks. by mvo approved by chipaca

444. By Michael Vogt

Only update changed files in SyncBootloader(). by mvo approved by chipaca

443. By David Callé

Sync markdown of docs/meta.md with trunk by davidc3 approved by mvo

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'clickdeb/deb.go'
2=== modified file 'clickdeb/deb_test.go'
3=== modified file 'cmd/snappy/cmd_build.go'
4=== modified file 'cmd/snappy/cmd_internal_unpack.go'
5=== modified file 'helpers/helpers.go'
6--- helpers/helpers.go 2015-06-04 12:55:54 +0000
7+++ helpers/helpers.go 2015-06-04 20:51:08 +0000
8@@ -26,6 +26,7 @@
9 "encoding/hex"
10 "fmt"
11 "io"
12+ "io/ioutil"
13 "math/rand"
14 "os"
15 "os/exec"
16@@ -197,14 +198,37 @@
17 }
18 }
19
20-// IsSupportedArchitecture returns true if the system architecture is in the
21-// list of architectures.
22-func IsSupportedArchitecture(architectures []string) bool {
23- systemArch := UbuntuArchitecture()
24-
25- for _, arch := range architectures {
26- if arch == "all" || arch == systemArch {
27- return true
28+<<<<<<< TREE
29+// IsSupportedArchitecture returns true if the system architecture is in the
30+// list of architectures.
31+func IsSupportedArchitecture(architectures []string) bool {
32+ systemArch := UbuntuArchitecture()
33+
34+ for _, arch := range architectures {
35+ if arch == "all" || arch == systemArch {
36+ return true
37+=======
38+// IsSupportedArchitecture returns true if the system architecture is in the
39+// list of architectures.
40+func IsSupportedArchitecture(architectures []string) bool {
41+ systemArch := UbuntuArchitecture()
42+
43+ for _, arch := range architectures {
44+ if arch == "all" || arch == systemArch {
45+ return true
46+ }
47+ }
48+
49+ return false
50+}
51+
52+// EnsureDir ensures that the given directory exists and if
53+// not creates it with the given permissions.
54+func EnsureDir(dir string, perm os.FileMode) (err error) {
55+ if _, err := os.Stat(dir); os.IsNotExist(err) {
56+ if err := os.MkdirAll(dir, perm); err != nil {
57+ return err
58+>>>>>>> MERGE-SOURCE
59 }
60 }
61
62@@ -345,6 +369,7 @@
63 return syscall.Getuid() == 0 || syscall.Getgid() == 0
64
65 }
66+<<<<<<< TREE
67
68 // MajorMinor returns the major/minor number of the given os.FileInfo
69 func MajorMinor(info os.FileInfo) (uint32, uint32, error) {
70@@ -436,3 +461,156 @@
71 "SNAPP_APP_USER_DATA_PATH={{.Home}}{{.AppPath}}",
72 })
73 }
74+=======
75+
76+func makeDirMap(dirName string) (map[string]struct{}, error) {
77+ dir, err := ioutil.ReadDir(dirName)
78+ if err != nil {
79+ return nil, err
80+ }
81+
82+ dirMap := make(map[string]struct{})
83+ for _, dent := range dir {
84+ if dent.IsDir() {
85+ return nil, fmt.Errorf("subdirs are not supported")
86+ }
87+ dirMap[dent.Name()] = struct{}{}
88+ }
89+
90+ return dirMap, nil
91+}
92+
93+// RSyncWithDelete syncs srcDir to destDir
94+func RSyncWithDelete(srcDirName, destDirName string) error {
95+
96+ // first remove everything thats not in srcdir
97+ err := filepath.Walk(destDirName, func(path string, info os.FileInfo, err error) error {
98+ if err != nil {
99+ return err
100+ }
101+
102+ // relative to the root "destDirName"
103+ relPath := path[len(destDirName):]
104+ if !FileExists(filepath.Join(srcDirName, relPath)) {
105+ if err := os.RemoveAll(path); err != nil {
106+ return err
107+ }
108+ if info.IsDir() {
109+ return filepath.SkipDir
110+ }
111+ }
112+ return nil
113+ })
114+ if err != nil {
115+ return err
116+ }
117+
118+ // then copy or update the data from srcdir to destdir
119+ err = filepath.Walk(srcDirName, func(path string, info os.FileInfo, err error) error {
120+ if err != nil {
121+ return err
122+ }
123+
124+ // relative to the root "srcDirName"
125+ relPath := path[len(srcDirName):]
126+ if info.IsDir() {
127+ return os.MkdirAll(filepath.Join(destDirName, relPath), info.Mode())
128+ }
129+ src := path
130+ dst := filepath.Join(destDirName, relPath)
131+ if !FilesAreEqual(src, dst) {
132+ // XXX: on snappy-trunk we can use CopyFile here
133+ output, err := exec.Command("cp", "-va", src, dst).CombinedOutput()
134+ if err != nil {
135+ fmt.Errorf("Failed to copy %s to %s (%s)", src, dst, output)
136+ }
137+ }
138+ return nil
139+ })
140+
141+ return err
142+}
143+
144+func fillSnapEnvVars(desc interface{}, vars []string) []string {
145+ for i, v := range vars {
146+ var templateOut bytes.Buffer
147+ t := template.Must(template.New("wrapper").Parse(v))
148+ if err := t.Execute(&templateOut, desc); err != nil {
149+ // this can never happen, except we forget a variable
150+ logger.LogAndPanic(err)
151+ }
152+ vars[i] = templateOut.String()
153+ }
154+ return vars
155+}
156+
157+// GetBasicSnapEnvVars returns the app-level environment variables for a snap.
158+// Despite this being a bit snap-specific, this is in helpers.go because it's
159+// used by so many other modules, we run into circular dependencies if it's
160+// somewhere more reasonable like the snappy module.
161+func GetBasicSnapEnvVars(desc interface{}) []string {
162+ return fillSnapEnvVars(desc, []string{
163+ "TMPDIR=/tmp/snaps/{{.UdevAppName}}/{{.Version}}/tmp",
164+ "TEMPDIR=/tmp/snaps/{{.UdevAppName}}/{{.Version}}/tmp",
165+ "SNAP_APP_PATH={{.AppPath}}",
166+ "SNAP_APP_DATA_PATH=/var/lib{{.AppPath}}",
167+ "SNAP_APP_TMPDIR=/tmp/snaps/{{.UdevAppName}}/{{.Version}}/tmp",
168+ "SNAP_NAME={{.AppName}}",
169+ "SNAP_VERSION={{.Version}}",
170+ "SNAP_ORIGIN={{.Namespace}}",
171+ "SNAP_FULLNAME={{.UdevAppName}}",
172+ "SNAP_ARCH={{.AppArch}}",
173+ })
174+}
175+
176+// GetUserSnapEnvVars returns the user-level environment variables for a snap.
177+// Despite this being a bit snap-specific, this is in helpers.go because it's
178+// used by so many other modules, we run into circular dependencies if it's
179+// somewhere more reasonable like the snappy module.
180+func GetUserSnapEnvVars(desc interface{}) []string {
181+ return fillSnapEnvVars(desc, []string{
182+ "SNAP_APP_USER_DATA_PATH={{.Home}}{{.AppPath}}",
183+ })
184+}
185+
186+// GetDeprecatedBasicSnapEnvVars returns the app-level deprecated environment
187+// variables for a snap.
188+// Despite this being a bit snap-specific, this is in helpers.go because it's
189+// used by so many other modules, we run into circular dependencies if it's
190+// somewhere more reasonable like the snappy module.
191+func GetDeprecatedBasicSnapEnvVars(desc interface{}) []string {
192+ return fillSnapEnvVars(desc, []string{
193+ "SNAPP_APP_PATH={{.AppPath}}",
194+ "SNAPP_APP_DATA_PATH=/var/lib{{.AppPath}}",
195+ "SNAPP_APP_TMPDIR=/tmp/snaps/{{.UdevAppName}}/{{.Version}}/tmp",
196+ "SNAPPY_APP_ARCH={{.AppArch}}",
197+ })
198+}
199+
200+// GetDeprecatedUserSnapEnvVars returns the user-level deprecated environment
201+// variables for a snap.
202+// Despite this being a bit snap-specific, this is in helpers.go because it's
203+// used by so many other modules, we run into circular dependencies if it's
204+// somewhere more reasonable like the snappy module.
205+func GetDeprecatedUserSnapEnvVars(desc interface{}) []string {
206+ return fillSnapEnvVars(desc, []string{
207+ "SNAPP_APP_USER_DATA_PATH={{.Home}}{{.AppPath}}",
208+ })
209+}
210+
211+// CleanDir cleans all regular files in the given directory
212+func CleanDir(dir string) error {
213+ dents, err := ioutil.ReadDir(dir)
214+ if err != nil {
215+ return err
216+ }
217+ for _, dent := range dents {
218+ if dent.Mode().IsRegular() {
219+ if err := os.Remove(filepath.Join(dir, dent.Name())); err != nil {
220+ return err
221+ }
222+ }
223+ }
224+ return nil
225+}
226+>>>>>>> MERGE-SOURCE
227
228=== modified file 'helpers/helpers_test.go'
229--- helpers/helpers_test.go 2015-06-04 12:55:54 +0000
230+++ helpers/helpers_test.go 2015-06-04 20:51:08 +0000
231@@ -21,6 +21,7 @@
232
233 import (
234 "compress/gzip"
235+ "fmt"
236 "io/ioutil"
237 "math/rand"
238 "os"
239@@ -270,6 +271,7 @@
240 c.Assert(err, IsNil)
241 c.Assert(home, Equals, oldHome)
242 }
243+<<<<<<< TREE
244
245 func skipOnMissingDevKmsg(c *C) {
246 _, err := os.Stat("/dev/kmsg")
247@@ -328,3 +330,117 @@
248 c.Assert(mknodWasCalled, Equals, true)
249
250 }
251+=======
252+
253+func makeTestFiles(c *C, srcDir, destDir string) {
254+ // a new file
255+ err := ioutil.WriteFile(filepath.Join(srcDir, "new"), []byte(nil), 0644)
256+ c.Assert(err, IsNil)
257+
258+ // a existing file that needs update
259+ err = ioutil.WriteFile(filepath.Join(destDir, "existing-update"), []byte("old-content"), 0644)
260+ c.Assert(err, IsNil)
261+ err = ioutil.WriteFile(filepath.Join(srcDir, "existing-update"), []byte("some-new-content"), 0644)
262+ c.Assert(err, IsNil)
263+
264+ // existing file that needs no update
265+ err = ioutil.WriteFile(filepath.Join(srcDir, "existing-unchanged"), []byte(nil), 0644)
266+ c.Assert(err, IsNil)
267+ err = exec.Command("cp", "-a", filepath.Join(srcDir, "existing-unchanged"), filepath.Join(destDir, "existing-unchanged")).Run()
268+ c.Assert(err, IsNil)
269+
270+ // a file that needs removal
271+ err = ioutil.WriteFile(filepath.Join(destDir, "to-be-deleted"), []byte(nil), 0644)
272+ c.Assert(err, IsNil)
273+}
274+
275+func compareDirs(c *C, srcDir, destDir string) {
276+ d1, err := exec.Command("ls", "-al", srcDir).CombinedOutput()
277+ c.Assert(err, IsNil)
278+ d2, err := exec.Command("ls", "-al", destDir).CombinedOutput()
279+ c.Assert(err, IsNil)
280+ c.Assert(string(d1), Equals, string(d2))
281+ // ensure content got updated
282+ c1, err := exec.Command("sh", "-c", fmt.Sprintf("find %s -type f |xargs cat", srcDir)).CombinedOutput()
283+ c.Assert(err, IsNil)
284+ c2, err := exec.Command("sh", "-c", fmt.Sprintf("find %s -type f |xargs cat", destDir)).CombinedOutput()
285+ c.Assert(err, IsNil)
286+ c.Assert(string(c1), Equals, string(c2))
287+}
288+
289+func (ts *HTestSuite) TestSyncDirs(c *C) {
290+
291+ for _, l := range [][2]string{
292+ [2]string{"src-short", "dst-loooooooooooong"},
293+ [2]string{"src-loooooooooooong", "dst-short"},
294+ [2]string{"src-eq", "dst-eq"},
295+ } {
296+
297+ // ensure we have src, dest dirs with different length
298+ srcDir := filepath.Join(c.MkDir(), l[0])
299+ err := os.MkdirAll(srcDir, 0755)
300+ c.Assert(err, IsNil)
301+ destDir := filepath.Join(c.MkDir(), l[1])
302+ err = os.MkdirAll(destDir, 0755)
303+ c.Assert(err, IsNil)
304+
305+ // add a src subdir
306+ subdir := filepath.Join(srcDir, "subdir")
307+ err = os.Mkdir(subdir, 0755)
308+ c.Assert(err, IsNil)
309+ makeTestFiles(c, subdir, destDir)
310+
311+ // add a dst subdir that needs to get deleted
312+ subdir2 := filepath.Join(destDir, "to-be-deleted-subdir")
313+ err = os.Mkdir(subdir2, 0755)
314+ subdir3 := filepath.Join(subdir2, "to-be-deleted-sub-subdir")
315+ err = os.Mkdir(subdir3, 0755)
316+
317+ // and a toplevel
318+ makeTestFiles(c, srcDir, destDir)
319+
320+ // do it
321+ err = RSyncWithDelete(srcDir, destDir)
322+ c.Assert(err, IsNil)
323+
324+ // ensure meta-data is identical
325+ compareDirs(c, srcDir, destDir)
326+ compareDirs(c, filepath.Join(srcDir, "subdir"), filepath.Join(destDir, "subdir"))
327+ }
328+}
329+
330+func (ts *HTestSuite) TestSyncDirFails(c *C) {
331+ srcDir := c.MkDir()
332+ err := os.MkdirAll(srcDir, 0755)
333+ c.Assert(err, IsNil)
334+
335+ destDir := c.MkDir()
336+ err = os.MkdirAll(destDir, 0755)
337+ c.Assert(err, IsNil)
338+
339+ err = ioutil.WriteFile(filepath.Join(destDir, "meep"), []byte(nil), 0644)
340+ c.Assert(err, IsNil)
341+
342+ // ensure remove fails
343+ err = os.Chmod(destDir, 0100)
344+ c.Assert(err, IsNil)
345+ // make tempdir cleanup work again
346+ defer os.Chmod(destDir, 0755)
347+
348+ // do it
349+ err = RSyncWithDelete(srcDir, destDir)
350+ c.Check(err, NotNil)
351+ c.Check(err, ErrorMatches, ".*permission denied.*")
352+}
353+
354+func (ts *HTestSuite) TestCleanDir(c *C) {
355+ d := c.MkDir()
356+ canary := filepath.Join(d, "foo")
357+ err := ioutil.WriteFile(canary, []byte(nil), 0644)
358+ c.Assert(err, IsNil)
359+
360+ err = CleanDir(d)
361+ c.Assert(err, IsNil)
362+ c.Assert(FileExists(canary), Equals, false)
363+}
364+>>>>>>> MERGE-SOURCE
365
366=== modified file 'partition/bootloader_uboot.go'
367--- partition/bootloader_uboot.go 2015-05-29 09:55:15 +0000
368+++ partition/bootloader_uboot.go 2015-06-04 20:51:08 +0000
369@@ -221,10 +221,7 @@
370 srcDir := u.currentBootPath
371 destDir := u.otherBootPath
372
373- // always start from scratch: all files here are owned by us.
374- os.RemoveAll(destDir)
375-
376- return runCommand("/bin/cp", "-a", srcDir, destDir)
377+ return helpers.RSyncWithDelete(srcDir, destDir)
378 }
379
380 func (u *uboot) HandleAssets() (err error) {
381
382=== modified file 'partition/bootloader_uboot_test.go'
383=== modified file 'partition/partition.go'
384--- partition/partition.go 2015-05-29 09:55:15 +0000
385+++ partition/partition.go 2015-06-04 20:51:08 +0000
386@@ -814,6 +814,9 @@
387 return err
388 }
389
390+ // XXX: first toggle roofs and then handle assets? that seems
391+ // wrong given that handleAssets may fails and we will
392+ // knowingly boot into a broken system
393 err = p.RunWithOther(RW, func(otherRoot string) (err error) {
394 return bootloader.ToggleRootFS()
395 })
396
397=== modified file 'progress/progress.go'
398--- progress/progress.go 2015-05-15 13:33:27 +0000
399+++ progress/progress.go 2015-06-04 20:51:08 +0000
400@@ -129,8 +129,9 @@
401 // Finished stops displaying the progress
402 func (t *TextProgress) Finished() {
403 if t.pbar != nil {
404- t.pbar.FinishPrint("Done")
405+ t.pbar.Finish()
406 }
407+ fmt.Println("Done")
408 }
409
410 // Write is there so that progress can implment a Writer and can be
411@@ -143,7 +144,10 @@
412 // that have a unknown duration
413 func (t *TextProgress) Spin(msg string) {
414 states := `|/-\`
415- fmt.Printf("\r%s[%c]", msg, states[t.spinStep])
416+
417+ // clear until end of line
418+ clearUntilEOL := "\033[K"
419+ fmt.Printf("\r%s[%c]%s", msg, states[t.spinStep], clearUntilEOL)
420 t.spinStep++
421 if t.spinStep >= len(states) {
422 t.spinStep = 0
423
424=== modified file 'progress/progress_test.go'
425--- progress/progress_test.go 2015-06-02 20:53:10 +0000
426+++ progress/progress_test.go 2015-06-04 20:51:08 +0000
427@@ -60,7 +60,7 @@
428 f.Seek(0, 0)
429 progress, err := ioutil.ReadAll(f)
430 c.Assert(err, IsNil)
431- c.Assert(string(progress), Equals, "\rm[|]\rm[/]\rm[-]\rm[\\]\rm[|]\rm[/]")
432+ c.Assert(string(progress), Equals, "\rm[|]\x1b[K\rm[/]\x1b[K\rm[-]\x1b[K\rm[\\]\x1b[K\rm[|]\x1b[K\rm[/]\x1b[K")
433 }
434
435 func (ts *ProgressTestSuite) testAgreed(answer string, value bool, c *C) {
436
437=== modified file 'snappy/click.go'
438--- snappy/click.go 2015-05-29 14:28:36 +0000
439+++ snappy/click.go 2015-06-04 20:51:08 +0000
440@@ -92,9 +92,10 @@
441 func execHook(execCmd string) (err error) {
442 // the spec says this is passed to the shell
443 cmd := exec.Command("sh", "-c", execCmd)
444- if err = cmd.Run(); err != nil {
445+ if output, err := cmd.CombinedOutput(); err != nil {
446 if exitCode, err := helpers.ExitCode(err); err == nil {
447 return &ErrHookFailed{cmd: execCmd,
448+ output: string(output),
449 exitCode: exitCode}
450 }
451 return err
452@@ -362,9 +363,15 @@
453 AppArch string
454 AppPath string
455 Version string
456+<<<<<<< TREE
457 UdevAppName string
458 Origin string
459 Home string
460+=======
461+ UdevAppName string
462+ Namespace string
463+ Home string
464+>>>>>>> MERGE-SOURCE
465 Target string
466 AaProfile string
467 OldAppVars string
468@@ -374,9 +381,15 @@
469 AppArch: helpers.UbuntuArchitecture(),
470 AppPath: pkgPath,
471 Version: m.Version,
472+<<<<<<< TREE
473 UdevAppName: udevPartName,
474 Origin: origin,
475 Home: "$HOME",
476+=======
477+ UdevAppName: udevPartName,
478+ Namespace: namespace,
479+ Home: "$HOME",
480+>>>>>>> MERGE-SOURCE
481 Target: actualBinPath,
482 AaProfile: aaProfile,
483 }
484@@ -761,6 +774,7 @@
485
486 func installClick(snapFile string, flags InstallFlags, inter progress.Meter, origin string) (name string, err error) {
487 allowUnauthenticated := (flags & AllowUnauthenticated) != 0
488+<<<<<<< TREE
489 part, err := NewSnapPartFromSnapFile(snapFile, origin, allowUnauthenticated)
490 if err != nil {
491 return "", err
492@@ -768,6 +782,251 @@
493 defer part.deb.Close()
494
495 return part.Install(inter, flags)
496+=======
497+ if err := auditClick(snapFile, allowUnauthenticated); err != nil {
498+ return "", err
499+ // ?
500+ //return SnapAuditError
501+ }
502+
503+ d, err := clickdeb.Open(snapFile)
504+ if err != nil {
505+ return "", err
506+ }
507+ defer d.Close()
508+
509+ manifestData, err := d.ControlMember("manifest")
510+ if err != nil {
511+ log.Printf("Snap inspect failed: %s", snapFile)
512+ return "", err
513+ }
514+
515+ manifest, err := readClickManifest([]byte(manifestData))
516+ if err != nil {
517+ return "", err
518+ }
519+
520+ yamlData, err := d.MetaMember("package.yaml")
521+ if err != nil {
522+ return "", err
523+ }
524+
525+ m, err := parsePackageYamlData(yamlData)
526+ if err != nil {
527+ return "", err
528+ }
529+
530+ if err := m.checkForPackageInstalled(namespace); err != nil {
531+ return "", err
532+ }
533+
534+ // verify we have a valid architecture
535+ if !helpers.IsSupportedArchitecture(m.Architectures) {
536+ return "", &ErrArchitectureNotSupported{m.Architectures}
537+ }
538+
539+ if err := m.checkForNameClashes(); err != nil {
540+ return "", err
541+ }
542+
543+ if err := m.checkForFrameworks(); err != nil {
544+ return "", err
545+ }
546+
547+ targetDir := snapAppsDir
548+ // the "oem" parts are special
549+ if manifest.Type == SnapTypeOem {
550+ targetDir = snapOemDir
551+
552+ // TODO do the following at a higher level once the store publishes snap types
553+ // this is horrible
554+ if allowOEM := (flags & AllowOEM) != 0; !allowOEM {
555+ if currentOEM, err := getOem(); err == nil {
556+ if currentOEM.Name != manifest.Name {
557+ fmt.Println(currentOEM.Name, manifest.Name)
558+ return "", ErrOEMPackageInstall
559+ }
560+ } else {
561+ // there should always be an oem package now
562+ return "", ErrOEMPackageInstall
563+ }
564+ }
565+
566+ if err := installOemHardwareUdevRules(m); err != nil {
567+ return "", err
568+ }
569+ }
570+
571+ fullName := manifest.Name
572+ // namespacing only applies to apps.
573+ if manifest.Type != SnapTypeFramework && manifest.Type != SnapTypeOem {
574+ fullName += "." + namespace
575+ }
576+ instDir := filepath.Join(targetDir, fullName, manifest.Version)
577+ currentActiveDir, _ := filepath.EvalSymlinks(filepath.Join(instDir, "..", "current"))
578+
579+ if err := m.checkLicenseAgreement(inter, d, currentActiveDir); err != nil {
580+ return "", err
581+ }
582+
583+ dataDir := filepath.Join(snapDataDir, fullName, manifest.Version)
584+
585+ if err := helpers.EnsureDir(instDir, 0755); err != nil {
586+ log.Printf("WARNING: Can not create %s", instDir)
587+ }
588+
589+ // if anything goes wrong here we cleanup
590+ defer func() {
591+ if err != nil {
592+ if e := os.RemoveAll(instDir); e != nil && !os.IsNotExist(e) {
593+ log.Printf("Warning: failed to remove %s: %s", instDir, e)
594+ }
595+ }
596+ }()
597+
598+ // we need to call the external helper so that we can reliable drop
599+ // privs
600+ if err := unpackWithDropPrivs(d, instDir); err != nil {
601+ return "", err
602+ }
603+
604+ // legacy, the hooks (e.g. apparmor) need this. Once we converted
605+ // all hooks this can go away
606+ clickMetaDir := path.Join(instDir, ".click", "info")
607+ if err := os.MkdirAll(clickMetaDir, 0755); err != nil {
608+ return "", err
609+ }
610+ if err := writeCompatManifestJSON(clickMetaDir, manifestData, namespace); err != nil {
611+ return "", err
612+ }
613+
614+ // write the hashes now
615+ if err := writeHashesFile(d, instDir); err != nil {
616+ return "", err
617+ }
618+
619+ inhibitHooks := (flags & InhibitHooks) != 0
620+
621+ // deal with the data:
622+ //
623+ // if there was a previous version, stop it
624+ // from being active so that it stops running and can no longer be
625+ // started then copy the data
626+ //
627+ // otherwise just create a empty data dir
628+ if currentActiveDir != "" {
629+ oldManifest, err := readClickManifestFromClickDir(currentActiveDir)
630+ if err != nil {
631+ return "", err
632+ }
633+
634+ // we need to stop making it active
635+ err = unsetActiveClick(currentActiveDir, inhibitHooks, inter)
636+ defer func() {
637+ if err != nil {
638+ if cerr := setActiveClick(currentActiveDir, inhibitHooks, inter); cerr != nil {
639+ log.Printf("setting old version back to active failed: %v", cerr)
640+ }
641+ }
642+ }()
643+ if err != nil {
644+ return "", err
645+ }
646+
647+ err = copySnapData(fullName, oldManifest.Version, manifest.Version)
648+ } else {
649+ err = helpers.EnsureDir(dataDir, 0755)
650+ }
651+
652+ defer func() {
653+ if err != nil {
654+ if cerr := removeSnapData(fullName, manifest.Version); cerr != nil {
655+ log.Printf("when clenaning up data for %s %s: %v", manifest.Name, manifest.Version, cerr)
656+ }
657+ }
658+ }()
659+
660+ if err != nil {
661+ return "", err
662+ }
663+
664+ // and finally make active
665+ err = setActiveClick(instDir, inhibitHooks, inter)
666+ defer func() {
667+ if err != nil && currentActiveDir != "" {
668+ if cerr := setActiveClick(currentActiveDir, inhibitHooks, inter); cerr != nil {
669+ log.Printf("when setting old %s version back to active: %v", manifest.Name, cerr)
670+ }
671+ }
672+ }()
673+ if err != nil {
674+ return "", err
675+ }
676+
677+ // oh, one more thing: refresh the security bits
678+ if !inhibitHooks {
679+ part, err := NewSnapPartFromYaml(filepath.Join(instDir, "meta", "package.yaml"), namespace, m)
680+ if err != nil {
681+ return "", err
682+ }
683+
684+ deps, err := part.Dependents()
685+ if err != nil {
686+ return "", err
687+ }
688+
689+ sysd := systemd.New(globalRootDir, inter)
690+ stopped := make(map[string]time.Duration)
691+ defer func() {
692+ if err != nil {
693+ for serviceName := range stopped {
694+ if e := sysd.Start(serviceName); e != nil {
695+ inter.Notify(fmt.Sprintf("unable to restart %s with the old %s: %s", serviceName, part.Name(), e))
696+ }
697+ }
698+ }
699+ }()
700+
701+ for _, dep := range deps {
702+ if !dep.IsActive() {
703+ continue
704+ }
705+ for _, svc := range dep.Services() {
706+ serviceName := filepath.Base(generateServiceFileName(dep.m, svc))
707+ timeout := time.Duration(svc.StopTimeout)
708+ if err = sysd.Stop(serviceName, timeout); err != nil {
709+ inter.Notify(fmt.Sprintf("unable to stop %s; aborting install: %s", serviceName, err))
710+ return "", err
711+ }
712+ stopped[serviceName] = timeout
713+ }
714+ }
715+
716+ if err := part.RefreshDependentsSecurity(currentActiveDir, inter); err != nil {
717+ return "", err
718+ }
719+
720+ started := make(map[string]time.Duration)
721+ defer func() {
722+ if err != nil {
723+ for serviceName, timeout := range started {
724+ if e := sysd.Stop(serviceName, timeout); e != nil {
725+ inter.Notify(fmt.Sprintf("unable to stop %s with the old %s: %s", serviceName, part.Name(), e))
726+ }
727+ }
728+ }
729+ }()
730+ for serviceName, timeout := range stopped {
731+ if err = sysd.Start(serviceName); err != nil {
732+ inter.Notify(fmt.Sprintf("unable to restart %s; aborting install: %s", serviceName, err))
733+ return "", err
734+ }
735+ started[serviceName] = timeout
736+ }
737+ }
738+
739+ return manifest.Name, nil
740+>>>>>>> MERGE-SOURCE
741 }
742
743 // removeSnapData removes the data for the given version of the given snap
744
745=== modified file 'snappy/click_test.go'
746=== modified file 'snappy/dirs.go'
747--- snappy/dirs.go 2015-05-15 13:33:27 +0000
748+++ snappy/dirs.go 2015-06-04 20:51:08 +0000
749@@ -33,6 +33,8 @@
750 snapSeccompDir string
751 snapUdevRulesDir string
752
753+ systemApparmorProfileCacheDir string
754+
755 snapBinariesDir string
756 snapServicesDir string
757 snapBusPolicyDir string
758@@ -62,4 +64,6 @@
759 cloudMetaDataFile = filepath.Join(rootdir, "/var/lib/cloud/seed/nocloud-net/meta-data")
760
761 snapUdevRulesDir = filepath.Join(rootdir, "/etc/udev/rules.d")
762+
763+ systemApparmorProfileCacheDir = filepath.Join(rootdir, "/etc/apparmor.d/cache")
764 }
765
766=== modified file 'snappy/errors.go'
767--- snappy/errors.go 2015-06-04 13:04:30 +0000
768+++ snappy/errors.go 2015-06-04 20:51:08 +0000
769@@ -166,11 +166,12 @@
770 // ErrHookFailed is returned if a hook command fails
771 type ErrHookFailed struct {
772 cmd string
773+ output string
774 exitCode int
775 }
776
777 func (e *ErrHookFailed) Error() string {
778- return fmt.Sprintf("hook command %v failed with exit status %d", e.cmd, e.exitCode)
779+ return fmt.Sprintf("hook command %v failed with exit status %d (output: '%s')", e.cmd, e.exitCode, e.output)
780 }
781
782 // ErrDataCopyFailed is returned if copying the snap data fialed
783
784=== modified file 'snappy/snapp.go'
785--- snappy/snapp.go 2015-06-04 12:55:54 +0000
786+++ snappy/snapp.go 2015-06-04 20:51:08 +0000
787@@ -1559,6 +1559,7 @@
788 // are required when calling a meta/hook/ script and that will override
789 // any already existing SNAP_* variables in os.Environment()
790 func makeSnapHookEnv(part *SnapPart) (env []string) {
791+<<<<<<< TREE
792 desc := struct {
793 AppName string
794 AppArch string
795@@ -1573,6 +1574,22 @@
796 part.Version(),
797 QualifiedName(part),
798 part.Origin(),
799+=======
800+ desc := struct {
801+ AppName string
802+ AppArch string
803+ AppPath string
804+ Version string
805+ UdevAppName string
806+ Namespace string
807+ }{
808+ part.Name(),
809+ helpers.UbuntuArchitecture(),
810+ part.basedir,
811+ part.Version(),
812+ Dirname(part),
813+ part.Namespace(),
814+>>>>>>> MERGE-SOURCE
815 }
816 snapEnv := helpers.MakeMapFromEnvList(helpers.GetBasicSnapEnvVars(desc))
817
818
819=== modified file 'snappy/snapp_test.go'
820--- snappy/snapp_test.go 2015-06-04 13:34:57 +0000
821+++ snappy/snapp_test.go 2015-06-04 20:51:08 +0000
822@@ -709,6 +709,7 @@
823 c.Check(p.notified[0], Matches, "Waiting for .* stop.")
824 }
825
826+<<<<<<< TREE
827 func (s *SnapTestSuite) TestErrorOnUnsupportedArchitecture(c *C) {
828 const packageHello = `name: hello-app
829 version: 1.10
830@@ -728,6 +729,24 @@
831 c.Assert(err.Error(), Equals, errorMsg)
832 }
833
834+=======
835+func (s *SnapTestSuite) TestErrorOnUnsupportedArchitecture(c *C) {
836+ const packageHello = `name: hello-app
837+version: 1.10
838+vendor: Somebody
839+icon: meta/hello.svg
840+architectures:
841+ - yadayada
842+ - blahblah
843+`
844+
845+ snapPkg := makeTestSnapPackage(c, packageHello)
846+ _, err := installClick(snapPkg, 0, nil, testNamespace)
847+ errorMsg := fmt.Sprintf("package's supported architectures (yadayada, blahblah) is incompatible with this system (%s)", helpers.UbuntuArchitecture())
848+ c.Assert(err.Error(), Equals, errorMsg)
849+}
850+
851+>>>>>>> MERGE-SOURCE
852 func (s *SnapTestSuite) TestRemoteSnapErrors(c *C) {
853 snap := RemoteSnapPart{}
854
855
856=== modified file 'snappy/systemimage.go'
857--- snappy/systemimage.go 2015-05-20 17:24:29 +0000
858+++ snappy/systemimage.go 2015-06-04 20:51:08 +0000
859@@ -198,6 +198,9 @@
860
861 // Ensure there is always a kernel + initrd to boot with, even
862 // if the update does not provide new versions.
863+ if pb != nil {
864+ pb.Notify("Syncing boot files")
865+ }
866 err = s.partition.SyncBootloaderFiles()
867 if err != nil {
868 return "", err
869@@ -226,12 +229,32 @@
870 return "", err
871 }
872
873+ // XXX: ToggleNextBoot() calls handleAssets() (but not SyncBootloader
874+ // files :/) - handleAssets() may copy kernel/initramfs to the
875+ // sync mounted /boot/uboot, so its very slow, tell the user
876+ // at least that something is going on
877+ if pb != nil {
878+ pb.Notify("Updating boot files")
879+ }
880+
881+ // this needs to go once we have a clean fix for #1460152
882+ if err := s.postUpgradeHacks(); err != nil {
883+ return "", err
884+ }
885+
886 if err = s.partition.ToggleNextBoot(); err != nil {
887 return "", err
888 }
889 return systemImagePartName, nil
890 }
891
892+// this makes me cry
893+func (s *SystemImagePart) postUpgradeHacks() error {
894+ // Apply HACK to deal with bug #1460152 where the apparmor
895+ // cache is confused after the upgrade
896+ return helpers.CleanDir(systemApparmorProfileCacheDir)
897+}
898+
899 // Ensure the expected version update was applied to the expected partition.
900 func (s *SystemImagePart) verifyUpgradeWasApplied() error {
901 // The upgrade has now been applied, so check that the expected
902
903=== modified file 'snappy/systemimage_native.go'
904--- snappy/systemimage_native.go 2015-05-15 13:33:27 +0000
905+++ snappy/systemimage_native.go 2015-06-04 20:51:08 +0000
906@@ -158,6 +158,8 @@
907 pb.Set(genericData.Now)
908 }
909 }
910+ // ugly: avoid Spin() artifacts
911+ pb.Notify("\nApply done")
912
913 if err := scanner.Err(); err != nil {
914 return err
915
916=== modified file 'snappy/systemimage_test.go'
917--- snappy/systemimage_test.go 2015-06-02 20:53:10 +0000
918+++ snappy/systemimage_test.go 2015-06-04 20:51:08 +0000
919@@ -58,6 +58,13 @@
920 // setup fake /other partition
921 makeFakeSystemImageChannelConfig(c, filepath.Join(tempdir, "other", systemImageChannelConfig), "2")
922
923+ // fake the apparmor.d/cache
924+ systemApparmorProfileCacheDir = filepath.Join(systemImageRoot, "etc", "apparmor.d", "cache")
925+ err := os.MkdirAll(systemApparmorProfileCacheDir, 0755)
926+ c.Assert(err, IsNil)
927+ err = ioutil.WriteFile(filepath.Join(systemApparmorProfileCacheDir, "some-cache"), []byte(nil), 0644)
928+ c.Assert(err, IsNil)
929+
930 // run test webserver instead of talking to the real one
931 //
932 // The mock webserver versions "1" and "2"
933@@ -192,6 +199,29 @@
934 c.Assert(pb.progress, DeepEquals, []float64{20.0, 40.0, 60.0, 80.0, 100.0})
935 }
936
937+func (s *SITestSuite) TestSystemImagePartInstalAppliesHackLp1460152(c *C) {
938+ // add a update
939+ mockSystemImageIndexJSON = fmt.Sprintf(mockSystemImageIndexJSONTemplate, "2")
940+ parts, err := s.systemImage.Updates()
941+
942+ sp := parts[0].(*SystemImagePart)
943+ mockPartition := MockPartition{}
944+ sp.partition = &mockPartition
945+
946+ dents, err := ioutil.ReadDir(systemApparmorProfileCacheDir)
947+ c.Assert(err, IsNil)
948+ c.Assert(dents, HasLen, 1)
949+
950+ pb := &MockProgressMeter{}
951+ // do the install
952+ _, err = sp.Install(pb, 0)
953+ c.Assert(err, IsNil)
954+
955+ dents, err = ioutil.ReadDir(systemApparmorProfileCacheDir)
956+ c.Assert(err, IsNil)
957+ c.Assert(dents, HasLen, 0)
958+}
959+
960 func (s *SITestSuite) TestSystemImagePartInstallUpdatesBroken(c *C) {
961 // fake a broken upgrade
962 scriptContent := `#!/bin/sh
963
964=== modified file 'systemd/systemd.go'
965--- systemd/systemd.go 2015-06-03 14:01:51 +0000
966+++ systemd/systemd.go 2015-06-04 20:51:08 +0000
967@@ -207,10 +207,17 @@
968 FullPathPostStop string
969 AppTriple string
970 ServiceSystemdTarget string
971+<<<<<<< TREE
972 Origin string
973 AppArch string
974 Home string
975 EnvVars string
976+=======
977+ Namespace string
978+ AppArch string
979+ Home string
980+ EnvVars string
981+>>>>>>> MERGE-SOURCE
982 }{
983 *desc,
984 filepath.Join(desc.AppPath, desc.Start),
985@@ -218,10 +225,17 @@
986 filepath.Join(desc.AppPath, desc.PostStop),
987 fmt.Sprintf("%s_%s_%s", desc.AppName, desc.ServiceName, desc.Version),
988 servicesSystemdTarget,
989+<<<<<<< TREE
990 origin,
991 helpers.UbuntuArchitecture(),
992 "%h",
993 "",
994+=======
995+ namespace,
996+ helpers.UbuntuArchitecture(),
997+ "%h",
998+ "",
999+>>>>>>> MERGE-SOURCE
1000 }
1001 allVars := helpers.GetBasicSnapEnvVars(wrapperData)
1002 allVars = append(allVars, helpers.GetUserSnapEnvVars(wrapperData)...)
1003
1004=== modified file 'systemd/systemd_test.go'
1005--- systemd/systemd_test.go 2015-06-03 14:03:45 +0000
1006+++ systemd/systemd_test.go 2015-06-04 20:51:08 +0000
1007@@ -26,9 +26,15 @@
1008 "testing"
1009 "time"
1010
1011+<<<<<<< TREE
1012 . "gopkg.in/check.v1"
1013
1014 "launchpad.net/snappy/helpers"
1015+=======
1016+ . "launchpad.net/gocheck"
1017+
1018+ "launchpad.net/snappy/helpers"
1019+>>>>>>> MERGE-SOURCE
1020 )
1021
1022 type testreporter struct {

Subscribers

People subscribed via source and target branches