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
=== modified file 'clickdeb/deb.go'
=== modified file 'clickdeb/deb_test.go'
=== modified file 'cmd/snappy/cmd_build.go'
=== modified file 'cmd/snappy/cmd_internal_unpack.go'
=== modified file 'helpers/helpers.go'
--- helpers/helpers.go 2015-06-04 12:55:54 +0000
+++ helpers/helpers.go 2015-06-04 20:51:08 +0000
@@ -26,6 +26,7 @@
26 "encoding/hex"26 "encoding/hex"
27 "fmt"27 "fmt"
28 "io"28 "io"
29 "io/ioutil"
29 "math/rand"30 "math/rand"
30 "os"31 "os"
31 "os/exec"32 "os/exec"
@@ -197,14 +198,37 @@
197 }198 }
198}199}
199200
200// IsSupportedArchitecture returns true if the system architecture is in the201<<<<<<< TREE
201// list of architectures.202// IsSupportedArchitecture returns true if the system architecture is in the
202func IsSupportedArchitecture(architectures []string) bool {203// list of architectures.
203 systemArch := UbuntuArchitecture()204func IsSupportedArchitecture(architectures []string) bool {
204205 systemArch := UbuntuArchitecture()
205 for _, arch := range architectures {206
206 if arch == "all" || arch == systemArch {207 for _, arch := range architectures {
207 return true208 if arch == "all" || arch == systemArch {
209 return true
210=======
211// IsSupportedArchitecture returns true if the system architecture is in the
212// list of architectures.
213func IsSupportedArchitecture(architectures []string) bool {
214 systemArch := UbuntuArchitecture()
215
216 for _, arch := range architectures {
217 if arch == "all" || arch == systemArch {
218 return true
219 }
220 }
221
222 return false
223}
224
225// EnsureDir ensures that the given directory exists and if
226// not creates it with the given permissions.
227func EnsureDir(dir string, perm os.FileMode) (err error) {
228 if _, err := os.Stat(dir); os.IsNotExist(err) {
229 if err := os.MkdirAll(dir, perm); err != nil {
230 return err
231>>>>>>> MERGE-SOURCE
208 }232 }
209 }233 }
210234
@@ -345,6 +369,7 @@
345 return syscall.Getuid() == 0 || syscall.Getgid() == 0369 return syscall.Getuid() == 0 || syscall.Getgid() == 0
346370
347}371}
372<<<<<<< TREE
348373
349// MajorMinor returns the major/minor number of the given os.FileInfo374// MajorMinor returns the major/minor number of the given os.FileInfo
350func MajorMinor(info os.FileInfo) (uint32, uint32, error) {375func MajorMinor(info os.FileInfo) (uint32, uint32, error) {
@@ -436,3 +461,156 @@
436 "SNAPP_APP_USER_DATA_PATH={{.Home}}{{.AppPath}}",461 "SNAPP_APP_USER_DATA_PATH={{.Home}}{{.AppPath}}",
437 })462 })
438}463}
464=======
465
466func makeDirMap(dirName string) (map[string]struct{}, error) {
467 dir, err := ioutil.ReadDir(dirName)
468 if err != nil {
469 return nil, err
470 }
471
472 dirMap := make(map[string]struct{})
473 for _, dent := range dir {
474 if dent.IsDir() {
475 return nil, fmt.Errorf("subdirs are not supported")
476 }
477 dirMap[dent.Name()] = struct{}{}
478 }
479
480 return dirMap, nil
481}
482
483// RSyncWithDelete syncs srcDir to destDir
484func RSyncWithDelete(srcDirName, destDirName string) error {
485
486 // first remove everything thats not in srcdir
487 err := filepath.Walk(destDirName, func(path string, info os.FileInfo, err error) error {
488 if err != nil {
489 return err
490 }
491
492 // relative to the root "destDirName"
493 relPath := path[len(destDirName):]
494 if !FileExists(filepath.Join(srcDirName, relPath)) {
495 if err := os.RemoveAll(path); err != nil {
496 return err
497 }
498 if info.IsDir() {
499 return filepath.SkipDir
500 }
501 }
502 return nil
503 })
504 if err != nil {
505 return err
506 }
507
508 // then copy or update the data from srcdir to destdir
509 err = filepath.Walk(srcDirName, func(path string, info os.FileInfo, err error) error {
510 if err != nil {
511 return err
512 }
513
514 // relative to the root "srcDirName"
515 relPath := path[len(srcDirName):]
516 if info.IsDir() {
517 return os.MkdirAll(filepath.Join(destDirName, relPath), info.Mode())
518 }
519 src := path
520 dst := filepath.Join(destDirName, relPath)
521 if !FilesAreEqual(src, dst) {
522 // XXX: on snappy-trunk we can use CopyFile here
523 output, err := exec.Command("cp", "-va", src, dst).CombinedOutput()
524 if err != nil {
525 fmt.Errorf("Failed to copy %s to %s (%s)", src, dst, output)
526 }
527 }
528 return nil
529 })
530
531 return err
532}
533
534func fillSnapEnvVars(desc interface{}, vars []string) []string {
535 for i, v := range vars {
536 var templateOut bytes.Buffer
537 t := template.Must(template.New("wrapper").Parse(v))
538 if err := t.Execute(&templateOut, desc); err != nil {
539 // this can never happen, except we forget a variable
540 logger.LogAndPanic(err)
541 }
542 vars[i] = templateOut.String()
543 }
544 return vars
545}
546
547// GetBasicSnapEnvVars returns the app-level environment variables for a snap.
548// Despite this being a bit snap-specific, this is in helpers.go because it's
549// used by so many other modules, we run into circular dependencies if it's
550// somewhere more reasonable like the snappy module.
551func GetBasicSnapEnvVars(desc interface{}) []string {
552 return fillSnapEnvVars(desc, []string{
553 "TMPDIR=/tmp/snaps/{{.UdevAppName}}/{{.Version}}/tmp",
554 "TEMPDIR=/tmp/snaps/{{.UdevAppName}}/{{.Version}}/tmp",
555 "SNAP_APP_PATH={{.AppPath}}",
556 "SNAP_APP_DATA_PATH=/var/lib{{.AppPath}}",
557 "SNAP_APP_TMPDIR=/tmp/snaps/{{.UdevAppName}}/{{.Version}}/tmp",
558 "SNAP_NAME={{.AppName}}",
559 "SNAP_VERSION={{.Version}}",
560 "SNAP_ORIGIN={{.Namespace}}",
561 "SNAP_FULLNAME={{.UdevAppName}}",
562 "SNAP_ARCH={{.AppArch}}",
563 })
564}
565
566// GetUserSnapEnvVars returns the user-level environment variables for a snap.
567// Despite this being a bit snap-specific, this is in helpers.go because it's
568// used by so many other modules, we run into circular dependencies if it's
569// somewhere more reasonable like the snappy module.
570func GetUserSnapEnvVars(desc interface{}) []string {
571 return fillSnapEnvVars(desc, []string{
572 "SNAP_APP_USER_DATA_PATH={{.Home}}{{.AppPath}}",
573 })
574}
575
576// GetDeprecatedBasicSnapEnvVars returns the app-level deprecated environment
577// variables for a snap.
578// Despite this being a bit snap-specific, this is in helpers.go because it's
579// used by so many other modules, we run into circular dependencies if it's
580// somewhere more reasonable like the snappy module.
581func GetDeprecatedBasicSnapEnvVars(desc interface{}) []string {
582 return fillSnapEnvVars(desc, []string{
583 "SNAPP_APP_PATH={{.AppPath}}",
584 "SNAPP_APP_DATA_PATH=/var/lib{{.AppPath}}",
585 "SNAPP_APP_TMPDIR=/tmp/snaps/{{.UdevAppName}}/{{.Version}}/tmp",
586 "SNAPPY_APP_ARCH={{.AppArch}}",
587 })
588}
589
590// GetDeprecatedUserSnapEnvVars returns the user-level deprecated environment
591// variables for a snap.
592// Despite this being a bit snap-specific, this is in helpers.go because it's
593// used by so many other modules, we run into circular dependencies if it's
594// somewhere more reasonable like the snappy module.
595func GetDeprecatedUserSnapEnvVars(desc interface{}) []string {
596 return fillSnapEnvVars(desc, []string{
597 "SNAPP_APP_USER_DATA_PATH={{.Home}}{{.AppPath}}",
598 })
599}
600
601// CleanDir cleans all regular files in the given directory
602func CleanDir(dir string) error {
603 dents, err := ioutil.ReadDir(dir)
604 if err != nil {
605 return err
606 }
607 for _, dent := range dents {
608 if dent.Mode().IsRegular() {
609 if err := os.Remove(filepath.Join(dir, dent.Name())); err != nil {
610 return err
611 }
612 }
613 }
614 return nil
615}
616>>>>>>> MERGE-SOURCE
439617
=== modified file 'helpers/helpers_test.go'
--- helpers/helpers_test.go 2015-06-04 12:55:54 +0000
+++ helpers/helpers_test.go 2015-06-04 20:51:08 +0000
@@ -21,6 +21,7 @@
2121
22import (22import (
23 "compress/gzip"23 "compress/gzip"
24 "fmt"
24 "io/ioutil"25 "io/ioutil"
25 "math/rand"26 "math/rand"
26 "os"27 "os"
@@ -270,6 +271,7 @@
270 c.Assert(err, IsNil)271 c.Assert(err, IsNil)
271 c.Assert(home, Equals, oldHome)272 c.Assert(home, Equals, oldHome)
272}273}
274<<<<<<< TREE
273275
274func skipOnMissingDevKmsg(c *C) {276func skipOnMissingDevKmsg(c *C) {
275 _, err := os.Stat("/dev/kmsg")277 _, err := os.Stat("/dev/kmsg")
@@ -328,3 +330,117 @@
328 c.Assert(mknodWasCalled, Equals, true)330 c.Assert(mknodWasCalled, Equals, true)
329331
330}332}
333=======
334
335func makeTestFiles(c *C, srcDir, destDir string) {
336 // a new file
337 err := ioutil.WriteFile(filepath.Join(srcDir, "new"), []byte(nil), 0644)
338 c.Assert(err, IsNil)
339
340 // a existing file that needs update
341 err = ioutil.WriteFile(filepath.Join(destDir, "existing-update"), []byte("old-content"), 0644)
342 c.Assert(err, IsNil)
343 err = ioutil.WriteFile(filepath.Join(srcDir, "existing-update"), []byte("some-new-content"), 0644)
344 c.Assert(err, IsNil)
345
346 // existing file that needs no update
347 err = ioutil.WriteFile(filepath.Join(srcDir, "existing-unchanged"), []byte(nil), 0644)
348 c.Assert(err, IsNil)
349 err = exec.Command("cp", "-a", filepath.Join(srcDir, "existing-unchanged"), filepath.Join(destDir, "existing-unchanged")).Run()
350 c.Assert(err, IsNil)
351
352 // a file that needs removal
353 err = ioutil.WriteFile(filepath.Join(destDir, "to-be-deleted"), []byte(nil), 0644)
354 c.Assert(err, IsNil)
355}
356
357func compareDirs(c *C, srcDir, destDir string) {
358 d1, err := exec.Command("ls", "-al", srcDir).CombinedOutput()
359 c.Assert(err, IsNil)
360 d2, err := exec.Command("ls", "-al", destDir).CombinedOutput()
361 c.Assert(err, IsNil)
362 c.Assert(string(d1), Equals, string(d2))
363 // ensure content got updated
364 c1, err := exec.Command("sh", "-c", fmt.Sprintf("find %s -type f |xargs cat", srcDir)).CombinedOutput()
365 c.Assert(err, IsNil)
366 c2, err := exec.Command("sh", "-c", fmt.Sprintf("find %s -type f |xargs cat", destDir)).CombinedOutput()
367 c.Assert(err, IsNil)
368 c.Assert(string(c1), Equals, string(c2))
369}
370
371func (ts *HTestSuite) TestSyncDirs(c *C) {
372
373 for _, l := range [][2]string{
374 [2]string{"src-short", "dst-loooooooooooong"},
375 [2]string{"src-loooooooooooong", "dst-short"},
376 [2]string{"src-eq", "dst-eq"},
377 } {
378
379 // ensure we have src, dest dirs with different length
380 srcDir := filepath.Join(c.MkDir(), l[0])
381 err := os.MkdirAll(srcDir, 0755)
382 c.Assert(err, IsNil)
383 destDir := filepath.Join(c.MkDir(), l[1])
384 err = os.MkdirAll(destDir, 0755)
385 c.Assert(err, IsNil)
386
387 // add a src subdir
388 subdir := filepath.Join(srcDir, "subdir")
389 err = os.Mkdir(subdir, 0755)
390 c.Assert(err, IsNil)
391 makeTestFiles(c, subdir, destDir)
392
393 // add a dst subdir that needs to get deleted
394 subdir2 := filepath.Join(destDir, "to-be-deleted-subdir")
395 err = os.Mkdir(subdir2, 0755)
396 subdir3 := filepath.Join(subdir2, "to-be-deleted-sub-subdir")
397 err = os.Mkdir(subdir3, 0755)
398
399 // and a toplevel
400 makeTestFiles(c, srcDir, destDir)
401
402 // do it
403 err = RSyncWithDelete(srcDir, destDir)
404 c.Assert(err, IsNil)
405
406 // ensure meta-data is identical
407 compareDirs(c, srcDir, destDir)
408 compareDirs(c, filepath.Join(srcDir, "subdir"), filepath.Join(destDir, "subdir"))
409 }
410}
411
412func (ts *HTestSuite) TestSyncDirFails(c *C) {
413 srcDir := c.MkDir()
414 err := os.MkdirAll(srcDir, 0755)
415 c.Assert(err, IsNil)
416
417 destDir := c.MkDir()
418 err = os.MkdirAll(destDir, 0755)
419 c.Assert(err, IsNil)
420
421 err = ioutil.WriteFile(filepath.Join(destDir, "meep"), []byte(nil), 0644)
422 c.Assert(err, IsNil)
423
424 // ensure remove fails
425 err = os.Chmod(destDir, 0100)
426 c.Assert(err, IsNil)
427 // make tempdir cleanup work again
428 defer os.Chmod(destDir, 0755)
429
430 // do it
431 err = RSyncWithDelete(srcDir, destDir)
432 c.Check(err, NotNil)
433 c.Check(err, ErrorMatches, ".*permission denied.*")
434}
435
436func (ts *HTestSuite) TestCleanDir(c *C) {
437 d := c.MkDir()
438 canary := filepath.Join(d, "foo")
439 err := ioutil.WriteFile(canary, []byte(nil), 0644)
440 c.Assert(err, IsNil)
441
442 err = CleanDir(d)
443 c.Assert(err, IsNil)
444 c.Assert(FileExists(canary), Equals, false)
445}
446>>>>>>> MERGE-SOURCE
331447
=== modified file 'partition/bootloader_uboot.go'
--- partition/bootloader_uboot.go 2015-05-29 09:55:15 +0000
+++ partition/bootloader_uboot.go 2015-06-04 20:51:08 +0000
@@ -221,10 +221,7 @@
221 srcDir := u.currentBootPath221 srcDir := u.currentBootPath
222 destDir := u.otherBootPath222 destDir := u.otherBootPath
223223
224 // always start from scratch: all files here are owned by us.224 return helpers.RSyncWithDelete(srcDir, destDir)
225 os.RemoveAll(destDir)
226
227 return runCommand("/bin/cp", "-a", srcDir, destDir)
228}225}
229226
230func (u *uboot) HandleAssets() (err error) {227func (u *uboot) HandleAssets() (err error) {
231228
=== modified file 'partition/bootloader_uboot_test.go'
=== modified file 'partition/partition.go'
--- partition/partition.go 2015-05-29 09:55:15 +0000
+++ partition/partition.go 2015-06-04 20:51:08 +0000
@@ -814,6 +814,9 @@
814 return err814 return err
815 }815 }
816816
817 // XXX: first toggle roofs and then handle assets? that seems
818 // wrong given that handleAssets may fails and we will
819 // knowingly boot into a broken system
817 err = p.RunWithOther(RW, func(otherRoot string) (err error) {820 err = p.RunWithOther(RW, func(otherRoot string) (err error) {
818 return bootloader.ToggleRootFS()821 return bootloader.ToggleRootFS()
819 })822 })
820823
=== modified file 'progress/progress.go'
--- progress/progress.go 2015-05-15 13:33:27 +0000
+++ progress/progress.go 2015-06-04 20:51:08 +0000
@@ -129,8 +129,9 @@
129// Finished stops displaying the progress129// Finished stops displaying the progress
130func (t *TextProgress) Finished() {130func (t *TextProgress) Finished() {
131 if t.pbar != nil {131 if t.pbar != nil {
132 t.pbar.FinishPrint("Done")132 t.pbar.Finish()
133 }133 }
134 fmt.Println("Done")
134}135}
135136
136// Write is there so that progress can implment a Writer and can be137// Write is there so that progress can implment a Writer and can be
@@ -143,7 +144,10 @@
143// that have a unknown duration144// that have a unknown duration
144func (t *TextProgress) Spin(msg string) {145func (t *TextProgress) Spin(msg string) {
145 states := `|/-\`146 states := `|/-\`
146 fmt.Printf("\r%s[%c]", msg, states[t.spinStep])147
148 // clear until end of line
149 clearUntilEOL := "\033[K"
150 fmt.Printf("\r%s[%c]%s", msg, states[t.spinStep], clearUntilEOL)
147 t.spinStep++151 t.spinStep++
148 if t.spinStep >= len(states) {152 if t.spinStep >= len(states) {
149 t.spinStep = 0153 t.spinStep = 0
150154
=== modified file 'progress/progress_test.go'
--- progress/progress_test.go 2015-06-02 20:53:10 +0000
+++ progress/progress_test.go 2015-06-04 20:51:08 +0000
@@ -60,7 +60,7 @@
60 f.Seek(0, 0)60 f.Seek(0, 0)
61 progress, err := ioutil.ReadAll(f)61 progress, err := ioutil.ReadAll(f)
62 c.Assert(err, IsNil)62 c.Assert(err, IsNil)
63 c.Assert(string(progress), Equals, "\rm[|]\rm[/]\rm[-]\rm[\\]\rm[|]\rm[/]")63 c.Assert(string(progress), Equals, "\rm[|]\x1b[K\rm[/]\x1b[K\rm[-]\x1b[K\rm[\\]\x1b[K\rm[|]\x1b[K\rm[/]\x1b[K")
64}64}
6565
66func (ts *ProgressTestSuite) testAgreed(answer string, value bool, c *C) {66func (ts *ProgressTestSuite) testAgreed(answer string, value bool, c *C) {
6767
=== modified file 'snappy/click.go'
--- snappy/click.go 2015-05-29 14:28:36 +0000
+++ snappy/click.go 2015-06-04 20:51:08 +0000
@@ -92,9 +92,10 @@
92func execHook(execCmd string) (err error) {92func execHook(execCmd string) (err error) {
93 // the spec says this is passed to the shell93 // the spec says this is passed to the shell
94 cmd := exec.Command("sh", "-c", execCmd)94 cmd := exec.Command("sh", "-c", execCmd)
95 if err = cmd.Run(); err != nil {95 if output, err := cmd.CombinedOutput(); err != nil {
96 if exitCode, err := helpers.ExitCode(err); err == nil {96 if exitCode, err := helpers.ExitCode(err); err == nil {
97 return &ErrHookFailed{cmd: execCmd,97 return &ErrHookFailed{cmd: execCmd,
98 output: string(output),
98 exitCode: exitCode}99 exitCode: exitCode}
99 }100 }
100 return err101 return err
@@ -362,9 +363,15 @@
362 AppArch string363 AppArch string
363 AppPath string364 AppPath string
364 Version string365 Version string
366<<<<<<< TREE
365 UdevAppName string367 UdevAppName string
366 Origin string368 Origin string
367 Home string369 Home string
370=======
371 UdevAppName string
372 Namespace string
373 Home string
374>>>>>>> MERGE-SOURCE
368 Target string375 Target string
369 AaProfile string376 AaProfile string
370 OldAppVars string377 OldAppVars string
@@ -374,9 +381,15 @@
374 AppArch: helpers.UbuntuArchitecture(),381 AppArch: helpers.UbuntuArchitecture(),
375 AppPath: pkgPath,382 AppPath: pkgPath,
376 Version: m.Version,383 Version: m.Version,
384<<<<<<< TREE
377 UdevAppName: udevPartName,385 UdevAppName: udevPartName,
378 Origin: origin,386 Origin: origin,
379 Home: "$HOME",387 Home: "$HOME",
388=======
389 UdevAppName: udevPartName,
390 Namespace: namespace,
391 Home: "$HOME",
392>>>>>>> MERGE-SOURCE
380 Target: actualBinPath,393 Target: actualBinPath,
381 AaProfile: aaProfile,394 AaProfile: aaProfile,
382 }395 }
@@ -761,6 +774,7 @@
761774
762func installClick(snapFile string, flags InstallFlags, inter progress.Meter, origin string) (name string, err error) {775func installClick(snapFile string, flags InstallFlags, inter progress.Meter, origin string) (name string, err error) {
763 allowUnauthenticated := (flags & AllowUnauthenticated) != 0776 allowUnauthenticated := (flags & AllowUnauthenticated) != 0
777<<<<<<< TREE
764 part, err := NewSnapPartFromSnapFile(snapFile, origin, allowUnauthenticated)778 part, err := NewSnapPartFromSnapFile(snapFile, origin, allowUnauthenticated)
765 if err != nil {779 if err != nil {
766 return "", err780 return "", err
@@ -768,6 +782,251 @@
768 defer part.deb.Close()782 defer part.deb.Close()
769783
770 return part.Install(inter, flags)784 return part.Install(inter, flags)
785=======
786 if err := auditClick(snapFile, allowUnauthenticated); err != nil {
787 return "", err
788 // ?
789 //return SnapAuditError
790 }
791
792 d, err := clickdeb.Open(snapFile)
793 if err != nil {
794 return "", err
795 }
796 defer d.Close()
797
798 manifestData, err := d.ControlMember("manifest")
799 if err != nil {
800 log.Printf("Snap inspect failed: %s", snapFile)
801 return "", err
802 }
803
804 manifest, err := readClickManifest([]byte(manifestData))
805 if err != nil {
806 return "", err
807 }
808
809 yamlData, err := d.MetaMember("package.yaml")
810 if err != nil {
811 return "", err
812 }
813
814 m, err := parsePackageYamlData(yamlData)
815 if err != nil {
816 return "", err
817 }
818
819 if err := m.checkForPackageInstalled(namespace); err != nil {
820 return "", err
821 }
822
823 // verify we have a valid architecture
824 if !helpers.IsSupportedArchitecture(m.Architectures) {
825 return "", &ErrArchitectureNotSupported{m.Architectures}
826 }
827
828 if err := m.checkForNameClashes(); err != nil {
829 return "", err
830 }
831
832 if err := m.checkForFrameworks(); err != nil {
833 return "", err
834 }
835
836 targetDir := snapAppsDir
837 // the "oem" parts are special
838 if manifest.Type == SnapTypeOem {
839 targetDir = snapOemDir
840
841 // TODO do the following at a higher level once the store publishes snap types
842 // this is horrible
843 if allowOEM := (flags & AllowOEM) != 0; !allowOEM {
844 if currentOEM, err := getOem(); err == nil {
845 if currentOEM.Name != manifest.Name {
846 fmt.Println(currentOEM.Name, manifest.Name)
847 return "", ErrOEMPackageInstall
848 }
849 } else {
850 // there should always be an oem package now
851 return "", ErrOEMPackageInstall
852 }
853 }
854
855 if err := installOemHardwareUdevRules(m); err != nil {
856 return "", err
857 }
858 }
859
860 fullName := manifest.Name
861 // namespacing only applies to apps.
862 if manifest.Type != SnapTypeFramework && manifest.Type != SnapTypeOem {
863 fullName += "." + namespace
864 }
865 instDir := filepath.Join(targetDir, fullName, manifest.Version)
866 currentActiveDir, _ := filepath.EvalSymlinks(filepath.Join(instDir, "..", "current"))
867
868 if err := m.checkLicenseAgreement(inter, d, currentActiveDir); err != nil {
869 return "", err
870 }
871
872 dataDir := filepath.Join(snapDataDir, fullName, manifest.Version)
873
874 if err := helpers.EnsureDir(instDir, 0755); err != nil {
875 log.Printf("WARNING: Can not create %s", instDir)
876 }
877
878 // if anything goes wrong here we cleanup
879 defer func() {
880 if err != nil {
881 if e := os.RemoveAll(instDir); e != nil && !os.IsNotExist(e) {
882 log.Printf("Warning: failed to remove %s: %s", instDir, e)
883 }
884 }
885 }()
886
887 // we need to call the external helper so that we can reliable drop
888 // privs
889 if err := unpackWithDropPrivs(d, instDir); err != nil {
890 return "", err
891 }
892
893 // legacy, the hooks (e.g. apparmor) need this. Once we converted
894 // all hooks this can go away
895 clickMetaDir := path.Join(instDir, ".click", "info")
896 if err := os.MkdirAll(clickMetaDir, 0755); err != nil {
897 return "", err
898 }
899 if err := writeCompatManifestJSON(clickMetaDir, manifestData, namespace); err != nil {
900 return "", err
901 }
902
903 // write the hashes now
904 if err := writeHashesFile(d, instDir); err != nil {
905 return "", err
906 }
907
908 inhibitHooks := (flags & InhibitHooks) != 0
909
910 // deal with the data:
911 //
912 // if there was a previous version, stop it
913 // from being active so that it stops running and can no longer be
914 // started then copy the data
915 //
916 // otherwise just create a empty data dir
917 if currentActiveDir != "" {
918 oldManifest, err := readClickManifestFromClickDir(currentActiveDir)
919 if err != nil {
920 return "", err
921 }
922
923 // we need to stop making it active
924 err = unsetActiveClick(currentActiveDir, inhibitHooks, inter)
925 defer func() {
926 if err != nil {
927 if cerr := setActiveClick(currentActiveDir, inhibitHooks, inter); cerr != nil {
928 log.Printf("setting old version back to active failed: %v", cerr)
929 }
930 }
931 }()
932 if err != nil {
933 return "", err
934 }
935
936 err = copySnapData(fullName, oldManifest.Version, manifest.Version)
937 } else {
938 err = helpers.EnsureDir(dataDir, 0755)
939 }
940
941 defer func() {
942 if err != nil {
943 if cerr := removeSnapData(fullName, manifest.Version); cerr != nil {
944 log.Printf("when clenaning up data for %s %s: %v", manifest.Name, manifest.Version, cerr)
945 }
946 }
947 }()
948
949 if err != nil {
950 return "", err
951 }
952
953 // and finally make active
954 err = setActiveClick(instDir, inhibitHooks, inter)
955 defer func() {
956 if err != nil && currentActiveDir != "" {
957 if cerr := setActiveClick(currentActiveDir, inhibitHooks, inter); cerr != nil {
958 log.Printf("when setting old %s version back to active: %v", manifest.Name, cerr)
959 }
960 }
961 }()
962 if err != nil {
963 return "", err
964 }
965
966 // oh, one more thing: refresh the security bits
967 if !inhibitHooks {
968 part, err := NewSnapPartFromYaml(filepath.Join(instDir, "meta", "package.yaml"), namespace, m)
969 if err != nil {
970 return "", err
971 }
972
973 deps, err := part.Dependents()
974 if err != nil {
975 return "", err
976 }
977
978 sysd := systemd.New(globalRootDir, inter)
979 stopped := make(map[string]time.Duration)
980 defer func() {
981 if err != nil {
982 for serviceName := range stopped {
983 if e := sysd.Start(serviceName); e != nil {
984 inter.Notify(fmt.Sprintf("unable to restart %s with the old %s: %s", serviceName, part.Name(), e))
985 }
986 }
987 }
988 }()
989
990 for _, dep := range deps {
991 if !dep.IsActive() {
992 continue
993 }
994 for _, svc := range dep.Services() {
995 serviceName := filepath.Base(generateServiceFileName(dep.m, svc))
996 timeout := time.Duration(svc.StopTimeout)
997 if err = sysd.Stop(serviceName, timeout); err != nil {
998 inter.Notify(fmt.Sprintf("unable to stop %s; aborting install: %s", serviceName, err))
999 return "", err
1000 }
1001 stopped[serviceName] = timeout
1002 }
1003 }
1004
1005 if err := part.RefreshDependentsSecurity(currentActiveDir, inter); err != nil {
1006 return "", err
1007 }
1008
1009 started := make(map[string]time.Duration)
1010 defer func() {
1011 if err != nil {
1012 for serviceName, timeout := range started {
1013 if e := sysd.Stop(serviceName, timeout); e != nil {
1014 inter.Notify(fmt.Sprintf("unable to stop %s with the old %s: %s", serviceName, part.Name(), e))
1015 }
1016 }
1017 }
1018 }()
1019 for serviceName, timeout := range stopped {
1020 if err = sysd.Start(serviceName); err != nil {
1021 inter.Notify(fmt.Sprintf("unable to restart %s; aborting install: %s", serviceName, err))
1022 return "", err
1023 }
1024 started[serviceName] = timeout
1025 }
1026 }
1027
1028 return manifest.Name, nil
1029>>>>>>> MERGE-SOURCE
771}1030}
7721031
773// removeSnapData removes the data for the given version of the given snap1032// removeSnapData removes the data for the given version of the given snap
7741033
=== modified file 'snappy/click_test.go'
=== modified file 'snappy/dirs.go'
--- snappy/dirs.go 2015-05-15 13:33:27 +0000
+++ snappy/dirs.go 2015-06-04 20:51:08 +0000
@@ -33,6 +33,8 @@
33 snapSeccompDir string33 snapSeccompDir string
34 snapUdevRulesDir string34 snapUdevRulesDir string
3535
36 systemApparmorProfileCacheDir string
37
36 snapBinariesDir string38 snapBinariesDir string
37 snapServicesDir string39 snapServicesDir string
38 snapBusPolicyDir string40 snapBusPolicyDir string
@@ -62,4 +64,6 @@
62 cloudMetaDataFile = filepath.Join(rootdir, "/var/lib/cloud/seed/nocloud-net/meta-data")64 cloudMetaDataFile = filepath.Join(rootdir, "/var/lib/cloud/seed/nocloud-net/meta-data")
6365
64 snapUdevRulesDir = filepath.Join(rootdir, "/etc/udev/rules.d")66 snapUdevRulesDir = filepath.Join(rootdir, "/etc/udev/rules.d")
67
68 systemApparmorProfileCacheDir = filepath.Join(rootdir, "/etc/apparmor.d/cache")
65}69}
6670
=== modified file 'snappy/errors.go'
--- snappy/errors.go 2015-06-04 13:04:30 +0000
+++ snappy/errors.go 2015-06-04 20:51:08 +0000
@@ -166,11 +166,12 @@
166// ErrHookFailed is returned if a hook command fails166// ErrHookFailed is returned if a hook command fails
167type ErrHookFailed struct {167type ErrHookFailed struct {
168 cmd string168 cmd string
169 output string
169 exitCode int170 exitCode int
170}171}
171172
172func (e *ErrHookFailed) Error() string {173func (e *ErrHookFailed) Error() string {
173 return fmt.Sprintf("hook command %v failed with exit status %d", e.cmd, e.exitCode)174 return fmt.Sprintf("hook command %v failed with exit status %d (output: '%s')", e.cmd, e.exitCode, e.output)
174}175}
175176
176// ErrDataCopyFailed is returned if copying the snap data fialed177// ErrDataCopyFailed is returned if copying the snap data fialed
177178
=== modified file 'snappy/snapp.go'
--- snappy/snapp.go 2015-06-04 12:55:54 +0000
+++ snappy/snapp.go 2015-06-04 20:51:08 +0000
@@ -1559,6 +1559,7 @@
1559// are required when calling a meta/hook/ script and that will override1559// are required when calling a meta/hook/ script and that will override
1560// any already existing SNAP_* variables in os.Environment()1560// any already existing SNAP_* variables in os.Environment()
1561func makeSnapHookEnv(part *SnapPart) (env []string) {1561func makeSnapHookEnv(part *SnapPart) (env []string) {
1562<<<<<<< TREE
1562 desc := struct {1563 desc := struct {
1563 AppName string1564 AppName string
1564 AppArch string1565 AppArch string
@@ -1573,6 +1574,22 @@
1573 part.Version(),1574 part.Version(),
1574 QualifiedName(part),1575 QualifiedName(part),
1575 part.Origin(),1576 part.Origin(),
1577=======
1578 desc := struct {
1579 AppName string
1580 AppArch string
1581 AppPath string
1582 Version string
1583 UdevAppName string
1584 Namespace string
1585 }{
1586 part.Name(),
1587 helpers.UbuntuArchitecture(),
1588 part.basedir,
1589 part.Version(),
1590 Dirname(part),
1591 part.Namespace(),
1592>>>>>>> MERGE-SOURCE
1576 }1593 }
1577 snapEnv := helpers.MakeMapFromEnvList(helpers.GetBasicSnapEnvVars(desc))1594 snapEnv := helpers.MakeMapFromEnvList(helpers.GetBasicSnapEnvVars(desc))
15781595
15791596
=== modified file 'snappy/snapp_test.go'
--- snappy/snapp_test.go 2015-06-04 13:34:57 +0000
+++ snappy/snapp_test.go 2015-06-04 20:51:08 +0000
@@ -709,6 +709,7 @@
709 c.Check(p.notified[0], Matches, "Waiting for .* stop.")709 c.Check(p.notified[0], Matches, "Waiting for .* stop.")
710}710}
711711
712<<<<<<< TREE
712func (s *SnapTestSuite) TestErrorOnUnsupportedArchitecture(c *C) {713func (s *SnapTestSuite) TestErrorOnUnsupportedArchitecture(c *C) {
713 const packageHello = `name: hello-app714 const packageHello = `name: hello-app
714version: 1.10715version: 1.10
@@ -728,6 +729,24 @@
728 c.Assert(err.Error(), Equals, errorMsg)729 c.Assert(err.Error(), Equals, errorMsg)
729}730}
730731
732=======
733func (s *SnapTestSuite) TestErrorOnUnsupportedArchitecture(c *C) {
734 const packageHello = `name: hello-app
735version: 1.10
736vendor: Somebody
737icon: meta/hello.svg
738architectures:
739 - yadayada
740 - blahblah
741`
742
743 snapPkg := makeTestSnapPackage(c, packageHello)
744 _, err := installClick(snapPkg, 0, nil, testNamespace)
745 errorMsg := fmt.Sprintf("package's supported architectures (yadayada, blahblah) is incompatible with this system (%s)", helpers.UbuntuArchitecture())
746 c.Assert(err.Error(), Equals, errorMsg)
747}
748
749>>>>>>> MERGE-SOURCE
731func (s *SnapTestSuite) TestRemoteSnapErrors(c *C) {750func (s *SnapTestSuite) TestRemoteSnapErrors(c *C) {
732 snap := RemoteSnapPart{}751 snap := RemoteSnapPart{}
733752
734753
=== modified file 'snappy/systemimage.go'
--- snappy/systemimage.go 2015-05-20 17:24:29 +0000
+++ snappy/systemimage.go 2015-06-04 20:51:08 +0000
@@ -198,6 +198,9 @@
198198
199 // Ensure there is always a kernel + initrd to boot with, even199 // Ensure there is always a kernel + initrd to boot with, even
200 // if the update does not provide new versions.200 // if the update does not provide new versions.
201 if pb != nil {
202 pb.Notify("Syncing boot files")
203 }
201 err = s.partition.SyncBootloaderFiles()204 err = s.partition.SyncBootloaderFiles()
202 if err != nil {205 if err != nil {
203 return "", err206 return "", err
@@ -226,12 +229,32 @@
226 return "", err229 return "", err
227 }230 }
228231
232 // XXX: ToggleNextBoot() calls handleAssets() (but not SyncBootloader
233 // files :/) - handleAssets() may copy kernel/initramfs to the
234 // sync mounted /boot/uboot, so its very slow, tell the user
235 // at least that something is going on
236 if pb != nil {
237 pb.Notify("Updating boot files")
238 }
239
240 // this needs to go once we have a clean fix for #1460152
241 if err := s.postUpgradeHacks(); err != nil {
242 return "", err
243 }
244
229 if err = s.partition.ToggleNextBoot(); err != nil {245 if err = s.partition.ToggleNextBoot(); err != nil {
230 return "", err246 return "", err
231 }247 }
232 return systemImagePartName, nil248 return systemImagePartName, nil
233}249}
234250
251// this makes me cry
252func (s *SystemImagePart) postUpgradeHacks() error {
253 // Apply HACK to deal with bug #1460152 where the apparmor
254 // cache is confused after the upgrade
255 return helpers.CleanDir(systemApparmorProfileCacheDir)
256}
257
235// Ensure the expected version update was applied to the expected partition.258// Ensure the expected version update was applied to the expected partition.
236func (s *SystemImagePart) verifyUpgradeWasApplied() error {259func (s *SystemImagePart) verifyUpgradeWasApplied() error {
237 // The upgrade has now been applied, so check that the expected260 // The upgrade has now been applied, so check that the expected
238261
=== modified file 'snappy/systemimage_native.go'
--- snappy/systemimage_native.go 2015-05-15 13:33:27 +0000
+++ snappy/systemimage_native.go 2015-06-04 20:51:08 +0000
@@ -158,6 +158,8 @@
158 pb.Set(genericData.Now)158 pb.Set(genericData.Now)
159 }159 }
160 }160 }
161 // ugly: avoid Spin() artifacts
162 pb.Notify("\nApply done")
161163
162 if err := scanner.Err(); err != nil {164 if err := scanner.Err(); err != nil {
163 return err165 return err
164166
=== modified file 'snappy/systemimage_test.go'
--- snappy/systemimage_test.go 2015-06-02 20:53:10 +0000
+++ snappy/systemimage_test.go 2015-06-04 20:51:08 +0000
@@ -58,6 +58,13 @@
58 // setup fake /other partition58 // setup fake /other partition
59 makeFakeSystemImageChannelConfig(c, filepath.Join(tempdir, "other", systemImageChannelConfig), "2")59 makeFakeSystemImageChannelConfig(c, filepath.Join(tempdir, "other", systemImageChannelConfig), "2")
6060
61 // fake the apparmor.d/cache
62 systemApparmorProfileCacheDir = filepath.Join(systemImageRoot, "etc", "apparmor.d", "cache")
63 err := os.MkdirAll(systemApparmorProfileCacheDir, 0755)
64 c.Assert(err, IsNil)
65 err = ioutil.WriteFile(filepath.Join(systemApparmorProfileCacheDir, "some-cache"), []byte(nil), 0644)
66 c.Assert(err, IsNil)
67
61 // run test webserver instead of talking to the real one68 // run test webserver instead of talking to the real one
62 //69 //
63 // The mock webserver versions "1" and "2"70 // The mock webserver versions "1" and "2"
@@ -192,6 +199,29 @@
192 c.Assert(pb.progress, DeepEquals, []float64{20.0, 40.0, 60.0, 80.0, 100.0})199 c.Assert(pb.progress, DeepEquals, []float64{20.0, 40.0, 60.0, 80.0, 100.0})
193}200}
194201
202func (s *SITestSuite) TestSystemImagePartInstalAppliesHackLp1460152(c *C) {
203 // add a update
204 mockSystemImageIndexJSON = fmt.Sprintf(mockSystemImageIndexJSONTemplate, "2")
205 parts, err := s.systemImage.Updates()
206
207 sp := parts[0].(*SystemImagePart)
208 mockPartition := MockPartition{}
209 sp.partition = &mockPartition
210
211 dents, err := ioutil.ReadDir(systemApparmorProfileCacheDir)
212 c.Assert(err, IsNil)
213 c.Assert(dents, HasLen, 1)
214
215 pb := &MockProgressMeter{}
216 // do the install
217 _, err = sp.Install(pb, 0)
218 c.Assert(err, IsNil)
219
220 dents, err = ioutil.ReadDir(systemApparmorProfileCacheDir)
221 c.Assert(err, IsNil)
222 c.Assert(dents, HasLen, 0)
223}
224
195func (s *SITestSuite) TestSystemImagePartInstallUpdatesBroken(c *C) {225func (s *SITestSuite) TestSystemImagePartInstallUpdatesBroken(c *C) {
196 // fake a broken upgrade226 // fake a broken upgrade
197 scriptContent := `#!/bin/sh227 scriptContent := `#!/bin/sh
198228
=== modified file 'systemd/systemd.go'
--- systemd/systemd.go 2015-06-03 14:01:51 +0000
+++ systemd/systemd.go 2015-06-04 20:51:08 +0000
@@ -207,10 +207,17 @@
207 FullPathPostStop string207 FullPathPostStop string
208 AppTriple string208 AppTriple string
209 ServiceSystemdTarget string209 ServiceSystemdTarget string
210<<<<<<< TREE
210 Origin string211 Origin string
211 AppArch string212 AppArch string
212 Home string213 Home string
213 EnvVars string214 EnvVars string
215=======
216 Namespace string
217 AppArch string
218 Home string
219 EnvVars string
220>>>>>>> MERGE-SOURCE
214 }{221 }{
215 *desc,222 *desc,
216 filepath.Join(desc.AppPath, desc.Start),223 filepath.Join(desc.AppPath, desc.Start),
@@ -218,10 +225,17 @@
218 filepath.Join(desc.AppPath, desc.PostStop),225 filepath.Join(desc.AppPath, desc.PostStop),
219 fmt.Sprintf("%s_%s_%s", desc.AppName, desc.ServiceName, desc.Version),226 fmt.Sprintf("%s_%s_%s", desc.AppName, desc.ServiceName, desc.Version),
220 servicesSystemdTarget,227 servicesSystemdTarget,
228<<<<<<< TREE
221 origin,229 origin,
222 helpers.UbuntuArchitecture(),230 helpers.UbuntuArchitecture(),
223 "%h",231 "%h",
224 "",232 "",
233=======
234 namespace,
235 helpers.UbuntuArchitecture(),
236 "%h",
237 "",
238>>>>>>> MERGE-SOURCE
225 }239 }
226 allVars := helpers.GetBasicSnapEnvVars(wrapperData)240 allVars := helpers.GetBasicSnapEnvVars(wrapperData)
227 allVars = append(allVars, helpers.GetUserSnapEnvVars(wrapperData)...)241 allVars = append(allVars, helpers.GetUserSnapEnvVars(wrapperData)...)
228242
=== modified file 'systemd/systemd_test.go'
--- systemd/systemd_test.go 2015-06-03 14:03:45 +0000
+++ systemd/systemd_test.go 2015-06-04 20:51:08 +0000
@@ -26,9 +26,15 @@
26 "testing"26 "testing"
27 "time"27 "time"
2828
29<<<<<<< TREE
29 . "gopkg.in/check.v1"30 . "gopkg.in/check.v1"
3031
31 "launchpad.net/snappy/helpers"32 "launchpad.net/snappy/helpers"
33=======
34 . "launchpad.net/gocheck"
35
36 "launchpad.net/snappy/helpers"
37>>>>>>> MERGE-SOURCE
32)38)
3339
34type testreporter struct {40type testreporter struct {

Subscribers

People subscribed via source and target branches