Merge lp:~mvo/snappy/snappy-snapfs-os-kernel into lp:~snappy-dev/snappy/snappy-moved-to-github

Proposed by Michael Vogt
Status: Needs review
Proposed branch: lp:~mvo/snappy/snappy-snapfs-os-kernel
Merge into: lp:~snappy-dev/snappy/snappy-moved-to-github
Prerequisite: lp:~mvo/snappy/snappy-snapfs-mount
Diff against target: 831 lines (+360/-54)
18 files modified
cmd/snappy/cmd_internal_unpack.go (+1/-1)
partition/assets.go (+1/-1)
partition/bootloader.go (+28/-8)
partition/bootloader_grub.go (+15/-15)
partition/bootloader_test.go (+4/-4)
partition/bootloader_uboot.go (+7/-3)
partition/migrate_grub.go (+1/-1)
partition/partition_test.go (+7/-4)
pkg/clickdeb/deb.go (+7/-3)
pkg/clickdeb/deb_test.go (+2/-2)
pkg/file.go (+1/-0)
pkg/types.go (+2/-0)
snappy/common_test.go (+19/-2)
snappy/kernel.go (+69/-0)
snappy/snapp.go (+51/-2)
snappy/snapp_snapfs_test.go (+143/-6)
snappy/systemimage.go (+1/-1)
snappy/systemimage_test.go (+1/-1)
To merge this branch: bzr merge lp:~mvo/snappy/snappy-snapfs-os-kernel
Reviewer Review Type Date Requested Status
John Lenton (community) Needs Fixing
Review via email: mp+274859@code.launchpad.net

This proposal supersedes a proposal from 2015-10-19.

Description of the change

Unpack kernel assets, setup bootloader vars for kernel/os snap. Combined with the updated initramfs-tools-ubuntu-core and a matching oem snap this will give us a booting system (but not much more :)

Lots of cleanup needed, but I want to avoid a gigantic branch so approaching it in steps.

To post a comment you must log in.
Revision history for this message
Michael Vogt (mvo) wrote :

Review would be great, I plan to add more tests later tonight/tomorrow morning only (i.e. kernel unpack tests).

772. By Michael Vogt

add assets unpack test

773. By Michael Vogt

mered lp:snappy

774. By Michael Vogt

fix tests

775. By Michael Vogt

go fmt

776. By Michael Vogt

partition/partition_test.go: fix bootloaderName

Revision history for this message
John Lenton (chipaca) wrote :

Mostly lint fixes. Some "you should probably play extra safe here" sync-after-everything fixes.

review: Needs Fixing
Revision history for this message
Michael Vogt (mvo) wrote :

Thanks John! I updated the branch based on your feedback (on github though).

Unmerged revisions

776. By Michael Vogt

partition/partition_test.go: fix bootloaderName

775. By Michael Vogt

go fmt

774. By Michael Vogt

fix tests

773. By Michael Vogt

mered lp:snappy

772. By Michael Vogt

add assets unpack test

771. By Michael Vogt

more FIXME

770. By Michael Vogt

improve fixme

769. By Michael Vogt

add missing tests

768. By Michael Vogt

do not reimplement normalizeKernelInitrdName but instead export it

767. By Michael Vogt

unpack kernel assets and setup the right boot variables for kernel/os snaps

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'cmd/snappy/cmd_internal_unpack.go'
2--- cmd/snappy/cmd_internal_unpack.go 2015-10-07 15:47:01 +0000
3+++ cmd/snappy/cmd_internal_unpack.go 2015-10-20 08:17:22 +0000
4@@ -183,7 +183,7 @@
5 }
6 }
7
8- return d.Unpack(targetDir)
9+ return d.UnpackAll(targetDir)
10 }
11
12 func init() {
13
14=== modified file 'partition/assets.go'
15--- partition/assets.go 2015-06-11 13:08:19 +0000
16+++ partition/assets.go 2015-10-20 08:17:22 +0000
17@@ -34,7 +34,7 @@
18 Initrd string `yaml:"initrd"`
19 DtbDir string `yaml:"dtbs"`
20 PartitionLayout string `yaml:"partition-layout"`
21- Bootloader bootloaderName `yaml:"bootloader"`
22+ Bootloader BootloaderName `yaml:"bootloader"`
23 }
24
25 var (
26
27=== modified file 'partition/bootloader.go'
28--- partition/bootloader.go 2015-09-16 16:10:47 +0000
29+++ partition/bootloader.go 2015-10-20 08:17:22 +0000
30@@ -48,11 +48,12 @@
31 bootloaderSystemAB = "system-AB"
32 )
33
34-type bootloaderName string
35+type BootloaderName string
36
37-type bootLoader interface {
38+// FIXME: the interface of bootloader is too big
39+type BootLoader interface {
40 // Name of the bootloader
41- Name() bootloaderName
42+ Name() BootloaderName
43
44 // Switch bootloader configuration so that the "other" root
45 // filesystem partition will be used on next boot.
46@@ -70,6 +71,9 @@
47 // Return the value of the specified bootloader variable
48 GetBootVar(name string) (string, error)
49
50+ // Set the value of the specified bootloader variable
51+ SetBootVar(name, value string) error
52+
53 // Return the 1-character name corresponding to the
54 // rootfs that will be used on _next_ boot.
55 //
56@@ -88,10 +92,24 @@
57 BootDir() string
58 }
59
60+var Bootloader = BootloaderImpl
61+
62+func BootloaderImpl() (BootLoader, error) {
63+ p := New()
64+ if p == nil {
65+ return nil, ErrBootloader
66+ }
67+ b, err := bootloader(p)
68+ if err != nil {
69+ return nil, err
70+ }
71+ return b, nil
72+}
73+
74 // Factory method that returns a new bootloader for the given partition
75 var bootloader = bootloaderImpl
76
77-func bootloaderImpl(p *Partition) (bootLoader, error) {
78+func bootloaderImpl(p *Partition) (BootLoader, error) {
79 // try uboot
80 if uboot := newUboot(p); uboot != nil {
81 return uboot, nil
82@@ -176,8 +194,8 @@
83 return helpers.RSyncWithDelete(srcDir, destDir)
84 }
85
86-// noramlizeAssetName transforms like "vmlinuz-4.1.0" -> "vmlinuz"
87-func normalizeKernelInitrdName(name string) string {
88+// NoramlizeAssetName transforms like "vmlinuz-4.1.0" -> "vmlinuz"
89+func NormalizeKernelInitrdName(name string) string {
90 name = filepath.Base(name)
91 return strings.SplitN(name, "-", 2)[0]
92 }
93@@ -254,7 +272,7 @@
94 }
95 }()
96
97- target := filepath.Join(destDir, normalizeKernelInitrdName(file))
98+ target := filepath.Join(destDir, NormalizeKernelInitrdName(file))
99 if err := runCommand("/bin/cp", path, target); err != nil {
100 return err
101 }
102@@ -306,7 +324,9 @@
103
104 // BootloaderDir returns the full path to the (mounted and writable)
105 // bootloader-specific boot directory.
106-func BootloaderDir() string {
107+var BootloaderDir = BootloaderDirImpl
108+
109+func BootloaderDirImpl() string {
110 if helpers.FileExists(bootloaderUbootDir) {
111 return bootloaderUbootDir
112 } else if helpers.FileExists(bootloaderGrubDir) {
113
114=== modified file 'partition/bootloader_grub.go'
115--- partition/bootloader_grub.go 2015-07-23 11:54:14 +0000
116+++ partition/bootloader_grub.go 2015-10-20 08:17:22 +0000
117@@ -48,10 +48,10 @@
118 bootloaderType
119 }
120
121-const bootloaderNameGrub bootloaderName = "grub"
122+const bootloaderNameGrub BootloaderName = "grub"
123
124 // newGrub create a new Grub bootloader object
125-func newGrub(partition *Partition) bootLoader {
126+func newGrub(partition *Partition) BootLoader {
127 if !helpers.FileExists(bootloaderGrubConfigFile) {
128 return nil
129 }
130@@ -65,7 +65,7 @@
131 return &g
132 }
133
134-func (g *grub) Name() bootloaderName {
135+func (g *grub) Name() BootloaderName {
136 return bootloaderNameGrub
137 }
138
139@@ -76,14 +76,14 @@
140 // Update the grub configuration.
141 func (g *grub) ToggleRootFS(otherRootfs string) (err error) {
142
143- if err := g.setBootVar(bootloaderBootmodeVar, bootloaderBootmodeTry); err != nil {
144+ if err := g.SetBootVar(bootloaderBootmodeVar, bootloaderBootmodeTry); err != nil {
145 return err
146 }
147
148 // Record the partition that will be used for next boot. This
149 // isn't necessary for correct operation under grub, but allows
150 // us to query the next boot device easily.
151- return g.setBootVar(bootloaderRootfsVar, otherRootfs)
152+ return g.SetBootVar(bootloaderRootfsVar, otherRootfs)
153 }
154
155 func (g *grub) GetBootVar(name string) (value string, err error) {
156@@ -103,7 +103,7 @@
157 return cfg.Get("", name)
158 }
159
160-func (g *grub) setBootVar(name, value string) (err error) {
161+func (g *grub) SetBootVar(name, value string) (err error) {
162 // note that strings are not quoted since because
163 // RunCommand() does not use a shell and thus adding quotes
164 // stores them in the environment file (which is not desirable)
165@@ -117,15 +117,15 @@
166
167 func (g *grub) MarkCurrentBootSuccessful(currentRootfs string) (err error) {
168 // Clear the variable set on boot to denote a good boot.
169- if err := g.setBootVar(bootloaderTrialBootVar, "0"); err != nil {
170- return err
171- }
172-
173- if err := g.setBootVar(bootloaderRootfsVar, currentRootfs); err != nil {
174- return err
175- }
176-
177- return g.setBootVar(bootloaderBootmodeVar, bootloaderBootmodeSuccess)
178+ if err := g.SetBootVar(bootloaderTrialBootVar, "0"); err != nil {
179+ return err
180+ }
181+
182+ if err := g.SetBootVar(bootloaderRootfsVar, currentRootfs); err != nil {
183+ return err
184+ }
185+
186+ return g.SetBootVar(bootloaderBootmodeVar, bootloaderBootmodeSuccess)
187 }
188
189 func (g *grub) BootDir() string {
190
191=== modified file 'partition/bootloader_test.go'
192--- partition/bootloader_test.go 2015-08-24 15:36:30 +0000
193+++ partition/bootloader_test.go 2015-10-20 08:17:22 +0000
194@@ -24,8 +24,8 @@
195 )
196
197 func (s *PartitionTestSuite) TestNormalizeAssetsName(c *C) {
198- c.Check(normalizeKernelInitrdName("subdir/vmlinuz-3.14"), Equals, "vmlinuz")
199- c.Check(normalizeKernelInitrdName("vmlinuz-3.14"), Equals, "vmlinuz")
200- c.Check(normalizeKernelInitrdName("initrd.img-2.71"), Equals, "initrd.img")
201- c.Check(normalizeKernelInitrdName("x-y-z"), Equals, "x")
202+ c.Check(NormalizeKernelInitrdName("subdir/vmlinuz-3.14"), Equals, "vmlinuz")
203+ c.Check(NormalizeKernelInitrdName("vmlinuz-3.14"), Equals, "vmlinuz")
204+ c.Check(NormalizeKernelInitrdName("initrd.img-2.71"), Equals, "initrd.img")
205+ c.Check(NormalizeKernelInitrdName("x-y-z"), Equals, "x")
206 }
207
208=== modified file 'partition/bootloader_uboot.go'
209--- partition/bootloader_uboot.go 2015-07-24 12:00:01 +0000
210+++ partition/bootloader_uboot.go 2015-10-20 08:17:22 +0000
211@@ -60,7 +60,7 @@
212 atomicWriteFile = helpers.AtomicWriteFile
213 )
214
215-const bootloaderNameUboot bootloaderName = "u-boot"
216+const bootloaderNameUboot BootloaderName = "u-boot"
217
218 type uboot struct {
219 bootloaderType
220@@ -77,7 +77,7 @@
221 var getBootVar = func(name string) (string, error) { return "", nil }
222
223 // newUboot create a new Uboot bootloader object
224-func newUboot(partition *Partition) bootLoader {
225+func newUboot(partition *Partition) BootLoader {
226 if !helpers.FileExists(bootloaderUbootConfigFile) {
227 return nil
228 }
229@@ -99,7 +99,7 @@
230 return &u
231 }
232
233-func (u *uboot) Name() bootloaderName {
234+func (u *uboot) Name() BootloaderName {
235 return bootloaderNameUboot
236 }
237
238@@ -165,6 +165,10 @@
239 return getBootVar(name)
240 }
241
242+func (u *uboot) SetBootVar(name, value string) error {
243+ return setBootVar(name, value)
244+}
245+
246 func (u *uboot) GetNextBootRootFSName() (label string, err error) {
247 value, err := u.GetBootVar(bootloaderRootfsVar)
248 if err != nil {
249
250=== modified file 'partition/migrate_grub.go'
251--- partition/migrate_grub.go 2015-09-16 11:19:03 +0000
252+++ partition/migrate_grub.go 2015-10-20 08:17:22 +0000
253@@ -105,7 +105,7 @@
254 if len(matches) != 1 {
255 return fmt.Errorf("Incorrect matches for %v: %v", p, matches)
256 }
257- name := normalizeKernelInitrdName(filepath.Base(matches[0]))
258+ name := NormalizeKernelInitrdName(filepath.Base(matches[0]))
259 targetPath := filepath.Join(bootloaderGrubDir, grubTargetDir, name)
260 os.MkdirAll(filepath.Dir(targetPath), 0755)
261 // FIXME: valid?
262
263=== modified file 'partition/partition_test.go'
264--- partition/partition_test.go 2015-07-16 11:07:30 +0000
265+++ partition/partition_test.go 2015-10-20 08:17:22 +0000
266@@ -371,7 +371,7 @@
267 SyncBootFilesCalled bool
268 }
269
270-func (b *mockBootloader) Name() bootloaderName {
271+func (b *mockBootloader) Name() BootloaderName {
272 return "mocky"
273 }
274 func (b *mockBootloader) ToggleRootFS(otherRootfs string) error {
275@@ -389,6 +389,9 @@
276 func (b *mockBootloader) GetBootVar(name string) (string, error) {
277 return "", nil
278 }
279+func (b *mockBootloader) SetBootVar(name, value string) error {
280+ return nil
281+}
282 func (b *mockBootloader) GetNextBootRootFSName() (string, error) {
283 return "", nil
284 }
285@@ -403,7 +406,7 @@
286 func (s *PartitionTestSuite) TestToggleBootloaderRootfs(c *C) {
287 runCommand = mockRunCommand
288 b := &mockBootloader{}
289- bootloader = func(p *Partition) (bootLoader, error) {
290+ bootloader = func(p *Partition) (BootLoader, error) {
291 return b, nil
292 }
293
294@@ -422,7 +425,7 @@
295 func (s *PartitionTestSuite) TestMarkBootSuccessful(c *C) {
296 runCommand = mockRunCommand
297 b := &mockBootloader{}
298- bootloader = func(p *Partition) (bootLoader, error) {
299+ bootloader = func(p *Partition) (BootLoader, error) {
300 return b, nil
301 }
302
303@@ -437,7 +440,7 @@
304 func (s *PartitionTestSuite) TestSyncBootFiles(c *C) {
305 runCommand = mockRunCommand
306 b := &mockBootloader{}
307- bootloader = func(p *Partition) (bootLoader, error) {
308+ bootloader = func(p *Partition) (BootLoader, error) {
309 return b, nil
310 }
311
312
313=== modified file 'pkg/clickdeb/deb.go'
314--- pkg/clickdeb/deb.go 2015-10-20 08:17:22 +0000
315+++ pkg/clickdeb/deb.go 2015-10-20 08:17:22 +0000
316@@ -229,10 +229,14 @@
317 return ioutil.WriteFile(hashesFile, hashesData, 0644)
318 }
319
320-// Unpack unpacks the data.tar.{gz,bz2,xz} into the given target directory
321+func (d *ClickDeb) Unpack(src, dst string) error {
322+ return fmt.Errorf("clickdeb does not implement Unpack(src, dst)")
323+}
324+
325+// UnpackAll unpacks the data.tar.{gz,bz2,xz} into the given target directory
326 // with click specific verification, i.e. no files will be extracted outside
327 // of the targetdir (no ".." inside the data.tar is allowed)
328-func (d *ClickDeb) Unpack(targetDir string) error {
329+func (d *ClickDeb) UnpackAll(targetDir string) error {
330 var err error
331
332 if _, err := d.file.Seek(0, 0); err != nil {
333@@ -505,7 +509,7 @@
334 func (d *ClickDeb) UnpackWithDropPrivs(instDir, rootdir string) error {
335 // no need to drop privs, we are not root
336 if !helpers.ShouldDropPrivs() {
337- return d.Unpack(instDir)
338+ return d.UnpackAll(instDir)
339 }
340
341 cmd := exec.Command("snappy", "internal-unpack", d.Name(), instDir, rootdir)
342
343=== modified file 'pkg/clickdeb/deb_test.go'
344--- pkg/clickdeb/deb_test.go 2015-09-16 11:07:22 +0000
345+++ pkg/clickdeb/deb_test.go 2015-10-20 08:17:22 +0000
346@@ -147,14 +147,14 @@
347 c.Assert(err, Equals, ErrMemberNotFound)
348 }
349
350-func (s *ClickDebTestSuite) TestSnapDebUnpack(c *C) {
351+func (s *ClickDebTestSuite) TestSnapDebUnpackAll(c *C) {
352 targetDir := c.MkDir()
353
354 for _, comp := range []string{"gzip", "bzip2", "xz"} {
355 debName := makeTestDeb(c, comp)
356 d, err := Open(debName)
357 c.Assert(err, IsNil)
358- err = d.Unpack(targetDir)
359+ err = d.UnpackAll(targetDir)
360 c.Assert(err, IsNil)
361 expectedFile := filepath.Join(targetDir, "usr", "bin", "foo")
362 c.Assert(helpers.FileExists(expectedFile), Equals, true)
363
364=== modified file 'pkg/file.go'
365--- pkg/file.go 2015-10-20 08:17:22 +0000
366+++ pkg/file.go 2015-10-20 08:17:22 +0000
367@@ -34,6 +34,7 @@
368 Verify(allowUnauthenticated bool) error
369 Close() error
370 UnpackWithDropPrivs(targetDir, rootDir string) error
371+ Unpack(src, dstDir string) error
372 ControlMember(name string) ([]byte, error)
373 MetaMember(name string) ([]byte, error)
374 ExtractHashes(targetDir string) error
375
376=== modified file 'pkg/types.go'
377--- pkg/types.go 2015-05-19 19:34:13 +0000
378+++ pkg/types.go 2015-10-20 08:17:22 +0000
379@@ -34,6 +34,8 @@
380 TypeCore Type = "core"
381 TypeFramework Type = "framework"
382 TypeOem Type = "oem"
383+ TypeOS Type = "os"
384+ TypeKernel Type = "kernel"
385 )
386
387 // MarshalJSON returns *m as the JSON encoding of m.
388
389=== modified file 'snappy/common_test.go'
390--- snappy/common_test.go 2015-10-15 08:26:11 +0000
391+++ snappy/common_test.go 2015-10-20 08:17:22 +0000
392@@ -142,7 +142,15 @@
393 return makeTestSnapPackageFull(c, packageYamlContent, true)
394 }
395
396+func makeTestSnapPackageWithFiles(c *C, packageYamlContent string, files [][]string) (snapFile string) {
397+ return makeTestSnapPackageFullWithFiles(c, packageYamlContent, true, files)
398+}
399+
400 func makeTestSnapPackageFull(c *C, packageYamlContent string, makeLicense bool) (snapFile string) {
401+ return makeTestSnapPackageFullWithFiles(c, packageYamlContent, makeLicense, [][]string{})
402+}
403+
404+func makeTestSnapPackageFullWithFiles(c *C, packageYamlContent string, makeLicense bool, files [][]string) (snapFile string) {
405 tmpdir := c.MkDir()
406 // content
407 os.MkdirAll(filepath.Join(tmpdir, "bin"), 0755)
408@@ -164,14 +172,23 @@
409 ioutil.WriteFile(packageYaml, []byte(packageYamlContent), 0644)
410 readmeMd := filepath.Join(tmpdir, "meta", "readme.md")
411 content = "Random\nExample"
412- ioutil.WriteFile(readmeMd, []byte(content), 0644)
413+ err := ioutil.WriteFile(readmeMd, []byte(content), 0644)
414+ c.Assert(err, IsNil)
415 if makeLicense {
416 license := filepath.Join(tmpdir, "meta", "license.txt")
417 content = "WTFPL"
418 ioutil.WriteFile(license, []byte(content), 0644)
419 }
420+
421+ for _, filenameAndContent := range files {
422+ filename := filenameAndContent[0]
423+ content := filenameAndContent[1]
424+ err = ioutil.WriteFile(filepath.Join(tmpdir, filename), []byte(content), 0644)
425+ c.Assert(err, IsNil)
426+ }
427+
428 // build it
429- err := helpers.ChDir(tmpdir, func() error {
430+ err = helpers.ChDir(tmpdir, func() error {
431 var err error
432 snapFile, err = snapBuilderFunc(tmpdir, "")
433 c.Assert(err, IsNil)
434
435=== added file 'snappy/kernel.go'
436--- snappy/kernel.go 1970-01-01 00:00:00 +0000
437+++ snappy/kernel.go 2015-10-20 08:17:22 +0000
438@@ -0,0 +1,69 @@
439+package snappy
440+
441+// -*- Mode: Go; indent-tabs-mode: t -*-
442+
443+/*
444+ * Copyright (C) 2014-2015 Canonical Ltd
445+ *
446+ * This program is free software: you can redistribute it and/or modify
447+ * it under the terms of the GNU General Public License version 3 as
448+ * published by the Free Software Foundation.
449+ *
450+ * This program is distributed in the hope that it will be useful,
451+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
452+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
453+ * GNU General Public License for more details.
454+ *
455+ * You should have received a copy of the GNU General Public License
456+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
457+ *
458+ */
459+
460+import (
461+ "os"
462+ "path/filepath"
463+
464+ "launchpad.net/snappy/partition"
465+ "launchpad.net/snappy/pkg/snapfs"
466+)
467+
468+func unpackKernel(s *SnapPart) error {
469+ bootdir := partition.BootloaderDir()
470+ if err := os.MkdirAll(filepath.Join(bootdir, s.Version()), 0755); err !=
471+ nil {
472+ return err
473+ }
474+ blobName := filepath.Base(snapfs.BlobPath(s.basedir))
475+ dstDir := filepath.Join(bootdir, blobName)
476+ if s.m.Kernel != "" {
477+ src := s.m.Kernel
478+ if err := s.deb.Unpack(src, dstDir); err != nil {
479+ return err
480+ }
481+ src = filepath.Join(dstDir, s.m.Kernel)
482+ dst := filepath.Join(dstDir, partition.NormalizeKernelInitrdName(s.m.Kernel))
483+ if err := os.Rename(src, dst); err != nil {
484+ return err
485+ }
486+ }
487+ if s.m.Initrd != "" {
488+ src := s.m.Initrd
489+ if err := s.deb.Unpack(src, dstDir); err != nil {
490+ return err
491+ }
492+ src = filepath.Join(dstDir, s.m.Initrd)
493+ dst := filepath.Join(dstDir, partition.NormalizeKernelInitrdName(s.m.Initrd))
494+ if err := os.Rename(src, dst); err != nil {
495+ return err
496+ }
497+ }
498+ if s.m.Dtbs != "" {
499+ src := s.m.Dtbs
500+ dst := filepath.Join(dstDir, s.m.Dtbs)
501+ if err := s.deb.Unpack(src, dst); err != nil {
502+ return err
503+ }
504+ }
505+
506+ return nil
507+}
508
509=== modified file 'snappy/snapp.go'
510--- snappy/snapp.go 2015-10-20 08:17:22 +0000
511+++ snappy/snapp.go 2015-10-20 08:17:22 +0000
512@@ -42,6 +42,7 @@
513 "launchpad.net/snappy/helpers"
514 "launchpad.net/snappy/logger"
515 "launchpad.net/snappy/oauth"
516+ "launchpad.net/snappy/partition"
517 "launchpad.net/snappy/pkg"
518 "launchpad.net/snappy/pkg/remote"
519 "launchpad.net/snappy/pkg/snapfs"
520@@ -238,6 +239,11 @@
521
522 ExplicitLicenseAgreement bool `yaml:"explicit-license-agreement,omitempty"`
523 LicenseVersion string `yaml:"license-version,omitempty"`
524+
525+ // FIXME: move into a special kernel struct
526+ Kernel string `yaml:"kernel,omitempty"`
527+ Initrd string `yaml:"initrd,omitempty"`
528+ Dtbs string `yaml:"dtbs,omitempty"`
529 }
530
531 type searchResults struct {
532@@ -564,6 +570,8 @@
533 return nil, err
534 }
535
536+ // FIXME: make a special OemSnap that knows its install dir
537+ // instead of having this special case here
538 targetDir := dirs.SnapAppsDir
539 // the "oem" parts are special
540 if m.Type == pkg.TypeOem {
541@@ -577,12 +585,14 @@
542 fullName := m.qualifiedName(origin)
543 instDir := filepath.Join(targetDir, fullName, m.Version)
544
545- return &SnapPart{
546+ baseSnap := &SnapPart{
547 basedir: instDir,
548 origin: origin,
549 m: m,
550 deb: d,
551- }, nil
552+ }
553+
554+ return baseSnap, nil
555 }
556
557 // NewSnapPartFromYaml returns a new SnapPart from the given *packageYaml at yamlPath
558@@ -837,6 +847,20 @@
559 return "", err
560 }
561
562+ // FIXME: kill this check once we have only "snapfs" snaps
563+ if s.m.Type == pkg.TypeKernel || s.m.Type == pkg.TypeOS {
564+ if _, ok := s.deb.(*snapfs.Snap); !ok {
565+ return "", fmt.Errorf("kernel/os snap must be of type snapfs")
566+ }
567+ }
568+
569+ // FIXME: move into KernelSnap instead of poluting generic code
570+ if s.m.Type == pkg.TypeKernel {
571+ if err := unpackKernel(s); err != nil {
572+ return "", err
573+ }
574+ }
575+
576 // legacy, the hooks (e.g. apparmor) need this. Once we converted
577 // all hooks this can go away
578 clickMetaDir := filepath.Join(s.basedir, ".click", "info")
579@@ -1033,6 +1057,7 @@
580 if err := s.m.addPackageServices(s.basedir, inhibitHooks, inter); err != nil {
581 return err
582 }
583+ // update current symlink
584 if err := os.Remove(currentActiveSymlink); err != nil && !os.IsNotExist(err) {
585 logger.Noticef("Failed to remove %q: %v", currentActiveSymlink, err)
586 }
587@@ -1052,6 +1077,30 @@
588 return err
589 }
590
591+ // FIXME: create {Os,Kernel}Snap type instead of adding special
592+ // cases here
593+ if s.m.Type == pkg.TypeOS || s.m.Type == pkg.TypeKernel {
594+ b, err := partition.Bootloader()
595+ if err != nil {
596+ return err
597+ }
598+ var bootvar string
599+ switch s.m.Type {
600+ case pkg.TypeOS:
601+ bootvar = "snappy_os"
602+ case pkg.TypeKernel:
603+ bootvar = "snappy_kernel"
604+ }
605+ blobName := filepath.Base(snapfs.BlobPath(s.basedir))
606+ if err := b.SetBootVar(bootvar, blobName); err != nil {
607+ return err
608+ }
609+
610+ if err := b.SetBootVar("snappy_mode", "try"); err != nil {
611+ return err
612+ }
613+ }
614+
615 return os.Symlink(filepath.Base(s.basedir), currentDataSymlink)
616 }
617
618
619=== modified file 'snappy/snapp_snapfs_test.go'
620--- snappy/snapp_snapfs_test.go 2015-10-20 08:17:22 +0000
621+++ snappy/snapp_snapfs_test.go 2015-10-20 08:17:22 +0000
622@@ -26,13 +26,76 @@
623
624 "launchpad.net/snappy/dirs"
625 "launchpad.net/snappy/helpers"
626+ "launchpad.net/snappy/partition"
627 "launchpad.net/snappy/pkg/snapfs"
628 "launchpad.net/snappy/systemd"
629
630 . "gopkg.in/check.v1"
631 )
632
633+var mockb mockBootloader
634+
635+func newMockBootloader() (partition.BootLoader, error) {
636+ mockb = mockBootloader{}
637+ return &mockb, nil
638+}
639+
640+type mockBootloader struct {
641+ bootvars [][]string
642+}
643+
644+func (b *mockBootloader) Name() partition.BootloaderName {
645+ return ""
646+}
647+func (b *mockBootloader) ToggleRootFS(otherRootfs string) error {
648+ return nil
649+}
650+func (b *mockBootloader) SyncBootFiles(bootAssets map[string]string) error {
651+ return nil
652+}
653+func (b *mockBootloader) HandleAssets() error {
654+ return nil
655+}
656+func (b *mockBootloader) GetBootVar(name string) (string, error) {
657+ return "", nil
658+}
659+func (b *mockBootloader) SetBootVar(name, value string) error {
660+ b.bootvars = append(b.bootvars, []string{name, value})
661+ return nil
662+}
663+func (b *mockBootloader) GetNextBootRootFSName() (string, error) {
664+ return "", nil
665+}
666+func (b *mockBootloader) MarkCurrentBootSuccessful(currentRootfs string) error {
667+ return nil
668+}
669+func (b *mockBootloader) BootDir() string {
670+ return ""
671+}
672+
673+const packageHello = `name: hello-app
674+version: 1.10
675+vendor: Somebody
676+icon: meta/hello.svg
677+`
678+
679+const packageOS = `name: ubuntu-core
680+version: 15.10-1
681+type: os
682+vendor: Someone
683+`
684+
685+const packageKernel = `name: ubuntu-kernel
686+version: 4.0-1
687+type: kernel
688+vendor: Someone
689+
690+kernel: vmlinuz-4.2
691+initrd: initrd.img-4.2
692+`
693+
694 type SnapfsTestSuite struct {
695+ mockBootloaderDir string
696 }
697
698 func (s *SnapfsTestSuite) SetUpTest(c *C) {
699@@ -46,22 +109,27 @@
700 return []byte("ActiveState=inactive\n"), nil
701 }
702
703+ // mock bootloader
704+ partition.Bootloader = newMockBootloader
705+
706+ // and bootloader dir
707+ s.mockBootloaderDir = c.MkDir()
708+ partition.BootloaderDir = func() string {
709+ return s.mockBootloaderDir
710+ }
711+
712 // ensure we use the right builder func (snapfs)
713 snapBuilderFunc = BuildSnapfsSnap
714 }
715
716 func (s *SnapfsTestSuite) TearDownTest(c *C) {
717 snapBuilderFunc = BuildLegacySnap
718+ partition.Bootloader = partition.BootloaderImpl
719+ partition.BootloaderDir = partition.BootloaderDirImpl
720 }
721
722 var _ = Suite(&SnapfsTestSuite{})
723
724-const packageHello = `name: hello-app
725-version: 1.10
726-vendor: Somebody
727-icon: meta/hello.svg
728-`
729-
730 func (s *SnapfsTestSuite) TestMakeSnapMakesSnapfs(c *C) {
731 snapPkg := makeTestSnapPackage(c, packageHello)
732 part, err := NewSnapPartFromSnapFile(snapPkg, "origin", true)
733@@ -164,3 +232,72 @@
734 c.Assert(helpers.FileExists(filepath.Join(dirs.SnapBlobDir, "hello-app.origin_1.10.snap")), Equals, false)
735
736 }
737+
738+func (s *SnapfsTestSuite) TestInstallOsSnapWithDebFails(c *C) {
739+ // ensure we get a error when trying to install old style snap for OS
740+ snapBuilderFunc = BuildLegacySnap
741+
742+ snapPkg := makeTestSnapPackage(c, packageOS)
743+ part, err := NewSnapPartFromSnapFile(snapPkg, "origin", true)
744+ c.Assert(err, IsNil)
745+
746+ _, err = part.Install(&MockProgressMeter{}, 0)
747+ c.Assert(err, ErrorMatches, "kernel/os snap must be of type snapfs")
748+}
749+
750+func (s *SnapfsTestSuite) TestInstallOsSnapUpdatesBootloader(c *C) {
751+ snapPkg := makeTestSnapPackage(c, packageOS)
752+ part, err := NewSnapPartFromSnapFile(snapPkg, "origin", true)
753+ c.Assert(err, IsNil)
754+
755+ _, err = part.Install(&MockProgressMeter{}, 0)
756+ c.Assert(err, IsNil)
757+
758+ c.Assert(mockb.bootvars, DeepEquals, [][]string{
759+ {"snappy_os", "ubuntu-core.origin_15.10-1.snap"},
760+ {"snappy_mode", "try"},
761+ })
762+}
763+
764+func (s *SnapfsTestSuite) TestInstallKernelSnapUpdatesBootloader(c *C) {
765+ files := [][]string{
766+ {"vmlinuz-4.2", "I'm a kernel"},
767+ {"initrd.img-4.2", "...and I'm an initrd"},
768+ }
769+ snapPkg := makeTestSnapPackageWithFiles(c, packageKernel, files)
770+ part, err := NewSnapPartFromSnapFile(snapPkg, "origin", true)
771+ c.Assert(err, IsNil)
772+
773+ _, err = part.Install(&MockProgressMeter{}, 0)
774+ c.Assert(err, IsNil)
775+
776+ c.Assert(mockb.bootvars, DeepEquals, [][]string{
777+ {"snappy_kernel", "ubuntu-kernel.origin_4.0-1.snap"},
778+ {"snappy_mode", "try"},
779+ })
780+}
781+
782+func (s *SnapfsTestSuite) TestInstallKernelSnapUnpacksKernel(c *C) {
783+ files := [][]string{
784+ {"vmlinuz-4.2", "I'm a kernel"},
785+ {"initrd.img-4.2", "...and I'm an initrd"},
786+ }
787+ snapPkg := makeTestSnapPackageWithFiles(c, packageKernel, files)
788+ part, err := NewSnapPartFromSnapFile(snapPkg, "origin", true)
789+ c.Assert(err, IsNil)
790+
791+ _, err = part.Install(&MockProgressMeter{}, 0)
792+ c.Assert(err, IsNil)
793+
794+ // kernel is here and normalized
795+ vmlinuz := filepath.Join(s.mockBootloaderDir, "ubuntu-kernel.origin_4.0-1.snap", "vmlinuz")
796+ content, err := ioutil.ReadFile(vmlinuz)
797+ c.Assert(err, IsNil)
798+ c.Assert(string(content), Equals, files[0][1])
799+
800+ // and so is initrd
801+ initrd := filepath.Join(s.mockBootloaderDir, "ubuntu-kernel.origin_4.0-1.snap", "initrd.img")
802+ content, err = ioutil.ReadFile(initrd)
803+ c.Assert(err, IsNil)
804+ c.Assert(string(content), Equals, files[1][1])
805+}
806
807=== modified file 'snappy/systemimage.go'
808--- snappy/systemimage.go 2015-10-16 10:42:45 +0000
809+++ snappy/systemimage.go 2015-10-20 08:17:22 +0000
810@@ -42,7 +42,7 @@
811
812 // SystemImagePart have constant name, origin, and vendor.
813 const (
814- SystemImagePartName = "ubuntu-core"
815+ SystemImagePartName = "ubuntu-core-legacy"
816 // SystemImagePartOrigin is the origin of any system image part
817 SystemImagePartOrigin = "ubuntu"
818 // SystemImagePartVendor is the vendor of any system image part
819
820=== modified file 'snappy/systemimage_test.go'
821--- snappy/systemimage_test.go 2015-10-16 10:42:45 +0000
822+++ snappy/systemimage_test.go 2015-10-20 08:17:22 +0000
823@@ -138,7 +138,7 @@
824 parts, err := s.systemImage.Updates()
825 c.Assert(err, IsNil)
826 c.Assert(parts, HasLen, 1)
827- c.Assert(parts[0].Name(), Equals, "ubuntu-core")
828+ c.Assert(parts[0].Name(), Equals, SystemImagePartName)
829 c.Assert(parts[0].Version(), Equals, "2")
830 c.Assert(parts[0].DownloadSize(), Equals, int64(123166488))
831 }

Subscribers

People subscribed via source and target branches