github.com/hugh712/snapd@v0.0.0-20200910133618-1a99902bd583/overlord/snapstate/check_snap_test.go (about) 1 // -*- Mode: Go; indent-tabs-mode: t -*- 2 3 /* 4 * Copyright (C) 2016 Canonical Ltd 5 * 6 * This program is free software: you can redistribute it and/or modify 7 * it under the terms of the GNU General Public License version 3 as 8 * published by the Free Software Foundation. 9 * 10 * This program is distributed in the hope that it will be useful, 11 * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 * GNU General Public License for more details. 14 * 15 * You should have received a copy of the GNU General Public License 16 * along with this program. If not, see <http://www.gnu.org/licenses/>. 17 * 18 */ 19 20 package snapstate_test 21 22 import ( 23 "errors" 24 "fmt" 25 26 . "gopkg.in/check.v1" 27 28 "github.com/snapcore/snapd/arch" 29 "github.com/snapcore/snapd/dirs" 30 "github.com/snapcore/snapd/osutil" 31 "github.com/snapcore/snapd/overlord/state" 32 "github.com/snapcore/snapd/release" 33 seccomp_compiler "github.com/snapcore/snapd/sandbox/seccomp" 34 "github.com/snapcore/snapd/snap" 35 "github.com/snapcore/snapd/snap/snaptest" 36 "github.com/snapcore/snapd/snapdtool" 37 "github.com/snapcore/snapd/testutil" 38 39 "github.com/snapcore/snapd/overlord/snapstate" 40 "github.com/snapcore/snapd/overlord/snapstate/snapstatetest" 41 ) 42 43 type checkSnapSuite struct { 44 testutil.BaseTest 45 st *state.State 46 deviceCtx snapstate.DeviceContext 47 } 48 49 var _ = Suite(&checkSnapSuite{}) 50 51 func (s *checkSnapSuite) SetUpTest(c *C) { 52 s.BaseTest.SetUpTest(c) 53 dirs.SetRootDir(c.MkDir()) 54 s.st = state.New(nil) 55 s.BaseTest.AddCleanup(snap.MockSanitizePlugsSlots(func(snapInfo *snap.Info) {})) 56 s.deviceCtx = &snapstatetest.TrivialDeviceContext{DeviceModel: MakeModel(map[string]interface{}{ 57 "kernel": "kernel", 58 "gadget": "gadget", 59 })} 60 } 61 62 func (s *checkSnapSuite) TearDownTest(c *C) { 63 s.BaseTest.TearDownTest(c) 64 dirs.SetRootDir("") 65 } 66 67 func emptyContainer(c *C) snap.Container { 68 return snaptest.MockContainer(c, nil) 69 } 70 71 func (s *checkSnapSuite) TestCheckSnapErrorOnUnsupportedArchitecture(c *C) { 72 const yaml = `name: hello 73 version: 1.10 74 architectures: 75 - yadayada 76 - blahblah 77 ` 78 info, err := snap.InfoFromSnapYaml([]byte(yaml)) 79 c.Assert(err, IsNil) 80 81 var openSnapFile = func(path string, si *snap.SideInfo) (*snap.Info, snap.Container, error) { 82 c.Check(path, Equals, "snap-path") 83 c.Check(si, IsNil) 84 return info, emptyContainer(c), nil 85 } 86 restore := snapstate.MockOpenSnapFile(openSnapFile) 87 defer restore() 88 89 err = snapstate.CheckSnap(s.st, "snap-path", "hello", nil, nil, snapstate.Flags{}, nil) 90 91 errorMsg := fmt.Sprintf(`snap "hello" supported architectures (yadayada, blahblah) are incompatible with this system (%s)`, arch.DpkgArchitecture()) 92 c.Assert(err.Error(), Equals, errorMsg) 93 } 94 95 var assumesTests = []struct { 96 version string 97 assumes string 98 classic bool 99 error string 100 }{{ 101 assumes: "[common-data-dir]", 102 }, { 103 assumes: "[f1, f2]", 104 error: `snap "foo" assumes unsupported features: f1, f2 \(try to refresh the core or snapd snaps\)`, 105 }, { 106 assumes: "[f1, f2]", 107 classic: true, 108 error: `snap "foo" assumes unsupported features: f1, f2 \(try to update snapd and refresh the core snap\)`, 109 }, { 110 assumes: "[snapd2.15]", 111 version: "unknown", 112 }, { 113 assumes: "[snapdnono]", 114 version: "unknown", 115 error: `.* unsupported features: snapdnono .*`, 116 }, { 117 assumes: "[snapd2.15nono]", 118 version: "unknown", 119 error: `.* unsupported features: snapd2.15nono .*`, 120 }, { 121 assumes: "[snapd2.15]", 122 version: "2.15", 123 }, { 124 assumes: "[snapd2.15]", 125 version: "2.15.1", 126 }, { 127 assumes: "[snapd2.15]", 128 version: "2.15+git", 129 }, { 130 assumes: "[snapd2.15]", 131 version: "2.16", 132 }, { 133 assumes: "[snapd2.15.1]", 134 version: "2.16", 135 }, { 136 assumes: "[snapd2.15.2]", 137 version: "2.16.1", 138 }, { 139 assumes: "[snapd3]", 140 version: "3.1", 141 }, { 142 assumes: "[snapd2.16]", 143 version: "2.15", 144 error: `.* unsupported features: snapd2\.16 .*`, 145 }, { 146 assumes: "[snapd2.15.1]", 147 version: "2.15", 148 error: `.* unsupported features: snapd2\.15\.1 .*`, 149 }, { 150 assumes: "[snapd2.15.1]", 151 version: "2.15.0", 152 error: `.* unsupported features: snapd2\.15\.1 .*`, 153 }, { 154 // Note that this is different from how strconv.VersionCompare 155 // (dpkg version numbering) would behave - it would error here 156 assumes: "[snapd2.15]", 157 version: "2.15~pre1", 158 }, { 159 assumes: "[command-chain]", 160 }} 161 162 func (s *checkSnapSuite) TestCheckSnapAssumes(c *C) { 163 restore := snapdtool.MockVersion("2.15") 164 defer restore() 165 166 restore = release.MockOnClassic(false) 167 defer restore() 168 169 for _, test := range assumesTests { 170 snapdtool.Version = test.version 171 if snapdtool.Version == "" { 172 snapdtool.Version = "2.15" 173 } 174 release.OnClassic = test.classic 175 176 yaml := fmt.Sprintf("name: foo\nversion: 1.0\nassumes: %s\n", test.assumes) 177 178 info, err := snap.InfoFromSnapYaml([]byte(yaml)) 179 c.Assert(err, IsNil) 180 181 var openSnapFile = func(path string, si *snap.SideInfo) (*snap.Info, snap.Container, error) { 182 return info, emptyContainer(c), nil 183 } 184 restore := snapstate.MockOpenSnapFile(openSnapFile) 185 defer restore() 186 err = snapstate.CheckSnap(s.st, "snap-path", "foo", nil, nil, snapstate.Flags{}, nil) 187 if test.error != "" { 188 c.Check(err, ErrorMatches, test.error) 189 } else { 190 c.Assert(err, IsNil) 191 } 192 } 193 } 194 195 func (s *checkSnapSuite) TestCheckSnapCheckCallbackOK(c *C) { 196 const yaml = `name: foo 197 version: 1.0` 198 199 si := &snap.SideInfo{ 200 SnapID: "snap-id", 201 } 202 203 var openSnapFile = func(path string, si *snap.SideInfo) (*snap.Info, snap.Container, error) { 204 info := snaptest.MockInfo(c, yaml, si) 205 cont := snaptest.MockContainer(c, [][]string{{"canary", "canary"}}) 206 return info, cont, nil 207 } 208 r1 := snapstate.MockOpenSnapFile(openSnapFile) 209 defer r1() 210 211 checkCbCalled := false 212 checkCb := func(st *state.State, s, cur *snap.Info, sf snap.Container, flags snapstate.Flags, deviceCtx snapstate.DeviceContext) error { 213 c.Assert(sf, NotNil) 214 data, err := sf.ReadFile("canary") 215 c.Assert(err, IsNil) 216 c.Assert(data, DeepEquals, []byte("canary")) 217 c.Assert(s.InstanceName(), Equals, "foo") 218 c.Assert(s.SnapID, Equals, "snap-id") 219 checkCbCalled = true 220 return nil 221 } 222 r2 := snapstate.MockCheckSnapCallbacks([]snapstate.CheckSnapCallback{checkCb}) 223 defer r2() 224 225 err := snapstate.CheckSnap(s.st, "snap-path", "foo", si, nil, snapstate.Flags{}, nil) 226 c.Check(err, IsNil) 227 228 c.Check(checkCbCalled, Equals, true) 229 } 230 231 func (s *checkSnapSuite) TestCheckSnapCheckCallbackFail(c *C) { 232 const yaml = `name: foo 233 version: 1.0` 234 235 info, err := snap.InfoFromSnapYaml([]byte(yaml)) 236 c.Assert(err, IsNil) 237 238 var openSnapFile = func(path string, si *snap.SideInfo) (*snap.Info, snap.Container, error) { 239 return info, emptyContainer(c), nil 240 } 241 restore := snapstate.MockOpenSnapFile(openSnapFile) 242 defer restore() 243 244 fail := errors.New("bad snap") 245 checkCb := func(st *state.State, s, cur *snap.Info, _ snap.Container, flags snapstate.Flags, deviceCtx snapstate.DeviceContext) error { 246 return fail 247 } 248 r2 := snapstate.MockCheckSnapCallbacks(nil) 249 defer r2() 250 snapstate.AddCheckSnapCallback(checkCb) 251 252 err = snapstate.CheckSnap(s.st, "snap-path", "foo", nil, nil, snapstate.Flags{}, nil) 253 c.Check(err, Equals, fail) 254 } 255 256 func (s *checkSnapSuite) TestCheckSnapGadgetUpdate(c *C) { 257 reset := release.MockOnClassic(false) 258 defer reset() 259 260 st := state.New(nil) 261 st.Lock() 262 defer st.Unlock() 263 264 si := &snap.SideInfo{RealName: "gadget", Revision: snap.R(2), SnapID: "gadget-id"} 265 snaptest.MockSnap(c, ` 266 name: gadget 267 type: gadget 268 version: 1 269 `, si) 270 snapstate.Set(st, "gadget", &snapstate.SnapState{ 271 SnapType: "gadget", 272 Active: true, 273 Sequence: []*snap.SideInfo{si}, 274 Current: si.Revision, 275 }) 276 277 const yaml = `name: gadget 278 type: gadget 279 version: 2 280 ` 281 282 info, err := snap.InfoFromSnapYaml([]byte(yaml)) 283 info.SnapID = "gadget-id" 284 c.Assert(err, IsNil) 285 286 var openSnapFile = func(path string, si *snap.SideInfo) (*snap.Info, snap.Container, error) { 287 return info, emptyContainer(c), nil 288 } 289 restore := snapstate.MockOpenSnapFile(openSnapFile) 290 defer restore() 291 292 st.Unlock() 293 err = snapstate.CheckSnap(st, "snap-path", "gadget", nil, nil, snapstate.Flags{}, s.deviceCtx) 294 st.Lock() 295 c.Check(err, IsNil) 296 } 297 298 func (s *checkSnapSuite) TestCheckSnapGadgetUpdateLocal(c *C) { 299 reset := release.MockOnClassic(false) 300 defer reset() 301 302 st := state.New(nil) 303 st.Lock() 304 defer st.Unlock() 305 306 si := &snap.SideInfo{RealName: "gadget", Revision: snap.R(2)} 307 snaptest.MockSnap(c, ` 308 name: gadget 309 type: gadget 310 version: 1 311 `, si) 312 snapstate.Set(st, "gadget", &snapstate.SnapState{ 313 SnapType: "gadget", 314 Active: true, 315 Sequence: []*snap.SideInfo{si}, 316 Current: si.Revision, 317 }) 318 319 const yaml = `name: gadget 320 type: gadget 321 version: 2 322 ` 323 324 info, err := snap.InfoFromSnapYaml([]byte(yaml)) 325 // no SnapID => local! 326 c.Assert(err, IsNil) 327 328 var openSnapFile = func(path string, si *snap.SideInfo) (*snap.Info, snap.Container, error) { 329 return info, emptyContainer(c), nil 330 } 331 restore := snapstate.MockOpenSnapFile(openSnapFile) 332 defer restore() 333 334 st.Unlock() 335 err = snapstate.CheckSnap(st, "snap-path", "gadget", nil, nil, snapstate.Flags{}, s.deviceCtx) 336 st.Lock() 337 c.Check(err, IsNil) 338 } 339 340 func (s *checkSnapSuite) TestCheckSnapGadgetUpdateToUnassertedProhibited(c *C) { 341 reset := release.MockOnClassic(false) 342 defer reset() 343 344 st := state.New(nil) 345 st.Lock() 346 defer st.Unlock() 347 348 si := &snap.SideInfo{RealName: "gadget", Revision: snap.R(2), SnapID: "gadget-id"} 349 snaptest.MockSnap(c, ` 350 name: gadget 351 type: gadget 352 version: 1 353 `, si) 354 snapstate.Set(st, "gadget", &snapstate.SnapState{ 355 SnapType: "gadget", 356 Active: true, 357 Sequence: []*snap.SideInfo{si}, 358 Current: si.Revision, 359 }) 360 361 const yaml = `name: gadget 362 type: gadget 363 version: 2 364 ` 365 366 info, err := snap.InfoFromSnapYaml([]byte(yaml)) 367 c.Assert(err, IsNil) 368 369 var openSnapFile = func(path string, si *snap.SideInfo) (*snap.Info, snap.Container, error) { 370 return info, emptyContainer(c), nil 371 } 372 restore := snapstate.MockOpenSnapFile(openSnapFile) 373 defer restore() 374 375 st.Unlock() 376 err = snapstate.CheckSnap(st, "snap-path", "gadget", nil, nil, snapstate.Flags{}, s.deviceCtx) 377 st.Lock() 378 c.Check(err, ErrorMatches, `cannot replace signed gadget snap with an unasserted one`) 379 } 380 381 func (s *checkSnapSuite) TestCheckSnapGadgetAdditionProhibited(c *C) { 382 reset := release.MockOnClassic(false) 383 defer reset() 384 385 st := state.New(nil) 386 st.Lock() 387 defer st.Unlock() 388 389 si := &snap.SideInfo{RealName: "gadget", Revision: snap.R(2)} 390 snaptest.MockSnap(c, ` 391 name: gadget 392 type: gadget 393 version: 1 394 `, si) 395 snapstate.Set(st, "gadget", &snapstate.SnapState{ 396 SnapType: "gadget", 397 Active: true, 398 Sequence: []*snap.SideInfo{si}, 399 Current: si.Revision, 400 }) 401 402 const yaml = `name: zgadget 403 type: gadget 404 version: 2 405 ` 406 407 info, err := snap.InfoFromSnapYaml([]byte(yaml)) 408 c.Assert(err, IsNil) 409 410 var openSnapFile = func(path string, si *snap.SideInfo) (*snap.Info, snap.Container, error) { 411 return info, emptyContainer(c), nil 412 } 413 restore := snapstate.MockOpenSnapFile(openSnapFile) 414 defer restore() 415 416 st.Unlock() 417 err = snapstate.CheckSnap(st, "snap-path", "gadget", nil, nil, snapstate.Flags{}, s.deviceCtx) 418 st.Lock() 419 c.Check(err, ErrorMatches, "cannot replace gadget snap with a different one") 420 } 421 422 func (s *checkSnapSuite) TestCheckSnapGadgetAdditionProhibitedBySnapID(c *C) { 423 reset := release.MockOnClassic(false) 424 defer reset() 425 426 st := state.New(nil) 427 st.Lock() 428 defer st.Unlock() 429 430 si := &snap.SideInfo{RealName: "gadget", Revision: snap.R(2), SnapID: "gadget-id"} 431 snaptest.MockSnap(c, ` 432 name: gadget 433 type: gadget 434 version: 1 435 `, si) 436 snapstate.Set(st, "gadget", &snapstate.SnapState{ 437 SnapType: "gadget", 438 Active: true, 439 Sequence: []*snap.SideInfo{si}, 440 Current: si.Revision, 441 }) 442 443 const yaml = `name: zgadget 444 type: gadget 445 version: 2 446 ` 447 448 info, err := snap.InfoFromSnapYaml([]byte(yaml)) 449 info.SnapID = "zgadget-id" 450 c.Assert(err, IsNil) 451 452 var openSnapFile = func(path string, si *snap.SideInfo) (*snap.Info, snap.Container, error) { 453 return info, emptyContainer(c), nil 454 } 455 restore := snapstate.MockOpenSnapFile(openSnapFile) 456 defer restore() 457 458 st.Unlock() 459 err = snapstate.CheckSnap(st, "snap-path", "gadget", nil, nil, snapstate.Flags{}, s.deviceCtx) 460 st.Lock() 461 c.Check(err, ErrorMatches, "cannot replace gadget snap with a different one") 462 } 463 464 func (s *checkSnapSuite) TestCheckSnapGadgetNoPrior(c *C) { 465 reset := release.MockOnClassic(false) 466 defer reset() 467 468 st := state.New(nil) 469 st.Lock() 470 defer st.Unlock() 471 st.Set("seeded", true) 472 473 const yaml = `name: gadget 474 type: gadget 475 version: 1 476 ` 477 info, err := snap.InfoFromSnapYaml([]byte(yaml)) 478 c.Assert(err, IsNil) 479 480 var openSnapFile = func(path string, si *snap.SideInfo) (*snap.Info, snap.Container, error) { 481 return info, emptyContainer(c), nil 482 } 483 restore := snapstate.MockOpenSnapFile(openSnapFile) 484 defer restore() 485 486 st.Unlock() 487 err = snapstate.CheckSnap(st, "snap-path", "gadget", nil, nil, snapstate.Flags{}, nil) 488 st.Lock() 489 c.Check(err, IsNil) 490 } 491 492 func (s *checkSnapSuite) TestCheckSnapErrorOnDevModeDisallowed(c *C) { 493 const yaml = `name: hello 494 version: 1.10 495 confinement: devmode 496 ` 497 info, err := snap.InfoFromSnapYaml([]byte(yaml)) 498 c.Assert(err, IsNil) 499 500 var openSnapFile = func(path string, si *snap.SideInfo) (*snap.Info, snap.Container, error) { 501 c.Check(path, Equals, "snap-path") 502 c.Check(si, IsNil) 503 return info, emptyContainer(c), nil 504 } 505 restore := snapstate.MockOpenSnapFile(openSnapFile) 506 defer restore() 507 508 err = snapstate.CheckSnap(s.st, "snap-path", "hello", nil, nil, snapstate.Flags{}, nil) 509 510 c.Assert(err, ErrorMatches, ".* requires devmode or confinement override") 511 } 512 513 func (s *checkSnapSuite) TestCheckSnapErrorOnClassicDisallowed(c *C) { 514 const yaml = `name: hello 515 version: 1.10 516 confinement: classic 517 ` 518 info, err := snap.InfoFromSnapYaml([]byte(yaml)) 519 c.Assert(err, IsNil) 520 521 var openSnapFile = func(path string, si *snap.SideInfo) (*snap.Info, snap.Container, error) { 522 c.Check(path, Equals, "snap-path") 523 c.Check(si, IsNil) 524 return info, emptyContainer(c), nil 525 } 526 restore := snapstate.MockOpenSnapFile(openSnapFile) 527 defer restore() 528 529 restore = release.MockOnClassic(true) 530 defer restore() 531 532 err = snapstate.CheckSnap(s.st, "snap-path", "hello", nil, nil, snapstate.Flags{}, nil) 533 534 c.Assert(err, ErrorMatches, ".* requires classic confinement") 535 } 536 537 func (s *checkSnapSuite) TestCheckSnapErrorClassicOnCoreDisallowed(c *C) { 538 const yaml = `name: hello 539 version: 1.10 540 confinement: classic 541 ` 542 info, err := snap.InfoFromSnapYaml([]byte(yaml)) 543 c.Assert(err, IsNil) 544 545 var openSnapFile = func(path string, si *snap.SideInfo) (*snap.Info, snap.Container, error) { 546 c.Check(path, Equals, "snap-path") 547 c.Check(si, IsNil) 548 return info, emptyContainer(c), nil 549 } 550 restore := snapstate.MockOpenSnapFile(openSnapFile) 551 defer restore() 552 553 restore = release.MockOnClassic(false) 554 defer restore() 555 556 err = snapstate.CheckSnap(s.st, "snap-path", "hello", nil, nil, snapstate.Flags{Classic: true}, nil) 557 558 c.Assert(err, ErrorMatches, ".* requires classic confinement which is only available on classic systems") 559 } 560 561 func (s *checkSnapSuite) TestCheckSnapErrorClassicModeForStrictOrDevmode(c *C) { 562 const yaml = `name: hello 563 version: 1.10 564 confinement: strict 565 ` 566 info, err := snap.InfoFromSnapYaml([]byte(yaml)) 567 c.Assert(err, IsNil) 568 569 var openSnapFile = func(path string, si *snap.SideInfo) (*snap.Info, snap.Container, error) { 570 c.Check(path, Equals, "snap-path") 571 c.Check(si, IsNil) 572 return info, emptyContainer(c), nil 573 } 574 restore := snapstate.MockOpenSnapFile(openSnapFile) 575 defer restore() 576 577 err = snapstate.CheckSnap(s.st, "snap-path", "hello", nil, nil, snapstate.Flags{Classic: true}, nil) 578 579 c.Assert(err, ErrorMatches, `snap "hello" is not a classic confined snap`) 580 } 581 582 func (s *checkSnapSuite) TestCheckSnapKernelUpdate(c *C) { 583 reset := release.MockOnClassic(false) 584 defer reset() 585 586 st := state.New(nil) 587 st.Lock() 588 defer st.Unlock() 589 590 si := &snap.SideInfo{RealName: "kernel", Revision: snap.R(2), SnapID: "kernel-id"} 591 snaptest.MockSnap(c, ` 592 name: kernel 593 type: kernel 594 version: 1 595 `, si) 596 snapstate.Set(st, "kernel", &snapstate.SnapState{ 597 SnapType: "kernel", 598 Active: true, 599 Sequence: []*snap.SideInfo{si}, 600 Current: si.Revision, 601 }) 602 603 const yaml = `name: kernel 604 type: kernel 605 version: 2 606 ` 607 608 info, err := snap.InfoFromSnapYaml([]byte(yaml)) 609 info.SnapID = "kernel-id" 610 c.Assert(err, IsNil) 611 612 var openSnapFile = func(path string, si *snap.SideInfo) (*snap.Info, snap.Container, error) { 613 return info, emptyContainer(c), nil 614 } 615 restore := snapstate.MockOpenSnapFile(openSnapFile) 616 defer restore() 617 618 st.Unlock() 619 err = snapstate.CheckSnap(st, "snap-path", "kernel", nil, nil, snapstate.Flags{}, s.deviceCtx) 620 st.Lock() 621 c.Check(err, IsNil) 622 } 623 624 func (s *checkSnapSuite) TestCheckSnapKernelAdditionProhibitedBySnapID(c *C) { 625 reset := release.MockOnClassic(false) 626 defer reset() 627 628 st := state.New(nil) 629 st.Lock() 630 defer st.Unlock() 631 632 si := &snap.SideInfo{RealName: "kernel", Revision: snap.R(2), SnapID: "kernel-id"} 633 snaptest.MockSnap(c, ` 634 name: kernel 635 type: kernel 636 version: 1 637 `, si) 638 snapstate.Set(st, "kernel", &snapstate.SnapState{ 639 SnapType: "kernel", 640 Active: true, 641 Sequence: []*snap.SideInfo{si}, 642 Current: si.Revision, 643 }) 644 645 const yaml = `name: zkernel 646 type: kernel 647 version: 2 648 ` 649 650 info, err := snap.InfoFromSnapYaml([]byte(yaml)) 651 info.SnapID = "zkernel-id" 652 c.Assert(err, IsNil) 653 654 var openSnapFile = func(path string, si *snap.SideInfo) (*snap.Info, snap.Container, error) { 655 return info, emptyContainer(c), nil 656 } 657 restore := snapstate.MockOpenSnapFile(openSnapFile) 658 defer restore() 659 660 st.Unlock() 661 err = snapstate.CheckSnap(st, "snap-path", "kernel", nil, nil, snapstate.Flags{}, s.deviceCtx) 662 st.Lock() 663 c.Check(err, ErrorMatches, "cannot replace kernel snap with a different one") 664 } 665 666 func (s *checkSnapSuite) TestCheckSnapNoStateInfoInternalError(c *C) { 667 reset := release.MockOnClassic(false) 668 defer reset() 669 670 st := state.New(nil) 671 st.Lock() 672 defer st.Unlock() 673 674 si := &snap.SideInfo{RealName: "other-kernel", Revision: snap.R(2), SnapID: "kernel-id"} 675 snaptest.MockSnap(c, ` 676 name: other-kernel 677 type: kernel 678 version: 1 679 `, si) 680 // we have a state information for snap of type kernel, but it's a 681 // different snap 682 snapstate.Set(st, "other-kernel", &snapstate.SnapState{ 683 SnapType: "kernel", 684 Active: true, 685 Sequence: []*snap.SideInfo{si}, 686 Current: si.Revision, 687 }) 688 689 const yaml = `name: kernel 690 type: kernel 691 version: 2 692 ` 693 694 info, err := snap.InfoFromSnapYaml([]byte(yaml)) 695 info.SnapID = "kernel-id" 696 c.Assert(err, IsNil) 697 698 var openSnapFile = func(path string, si *snap.SideInfo) (*snap.Info, snap.Container, error) { 699 return info, emptyContainer(c), nil 700 } 701 restore := snapstate.MockOpenSnapFile(openSnapFile) 702 defer restore() 703 704 st.Unlock() 705 err = snapstate.CheckSnap(st, "snap-path", "kernel", nil, nil, snapstate.Flags{}, s.deviceCtx) 706 st.Lock() 707 c.Check(err, ErrorMatches, "internal error: no state for kernel snap \"kernel\"") 708 } 709 710 func (s *checkSnapSuite) TestCheckSnapBasesErrorsIfMissing(c *C) { 711 st := state.New(nil) 712 st.Lock() 713 defer st.Unlock() 714 715 const yaml = `name: requires-base 716 version: 1 717 base: some-base 718 ` 719 720 info, err := snap.InfoFromSnapYaml([]byte(yaml)) 721 c.Assert(err, IsNil) 722 723 var openSnapFile = func(path string, si *snap.SideInfo) (*snap.Info, snap.Container, error) { 724 return info, emptyContainer(c), nil 725 } 726 restore := snapstate.MockOpenSnapFile(openSnapFile) 727 defer restore() 728 729 st.Unlock() 730 err = snapstate.CheckSnap(st, "snap-path", "requires-base", nil, nil, snapstate.Flags{}, nil) 731 st.Lock() 732 c.Check(err, ErrorMatches, "cannot find required base \"some-base\"") 733 } 734 735 func (s *checkSnapSuite) TestCheckSnapBasesNoneHappy(c *C) { 736 st := state.New(nil) 737 st.Lock() 738 defer st.Unlock() 739 740 const yaml = `name: use-base-none 741 version: 1 742 base: none 743 ` 744 info, err := snap.InfoFromSnapYaml([]byte(yaml)) 745 c.Assert(err, IsNil) 746 747 var openSnapFile = func(path string, si *snap.SideInfo) (*snap.Info, snap.Container, error) { 748 return info, emptyContainer(c), nil 749 } 750 restore := snapstate.MockOpenSnapFile(openSnapFile) 751 defer restore() 752 753 st.Unlock() 754 err = snapstate.CheckSnap(st, "snap-path", "use-base-none", nil, nil, snapstate.Flags{}, nil) 755 st.Lock() 756 c.Check(err, IsNil) 757 } 758 759 func (s *checkSnapSuite) TestCheckSnapBasesHappy(c *C) { 760 st := state.New(nil) 761 st.Lock() 762 defer st.Unlock() 763 764 si := &snap.SideInfo{RealName: "some-base", Revision: snap.R(1), SnapID: "some-base-id"} 765 snaptest.MockSnap(c, ` 766 name: some-base 767 type: base 768 version: 1 769 `, si) 770 snapstate.Set(st, "some-base", &snapstate.SnapState{ 771 SnapType: "base", 772 Active: true, 773 Sequence: []*snap.SideInfo{si}, 774 Current: si.Revision, 775 }) 776 777 const yaml = `name: requires-base 778 version: 1 779 base: some-base 780 ` 781 782 info, err := snap.InfoFromSnapYaml([]byte(yaml)) 783 c.Assert(err, IsNil) 784 785 var openSnapFile = func(path string, si *snap.SideInfo) (*snap.Info, snap.Container, error) { 786 return info, emptyContainer(c), nil 787 } 788 restore := snapstate.MockOpenSnapFile(openSnapFile) 789 defer restore() 790 791 st.Unlock() 792 err = snapstate.CheckSnap(st, "snap-path", "requires-base", nil, nil, snapstate.Flags{}, nil) 793 st.Lock() 794 c.Check(err, IsNil) 795 } 796 797 func (s *checkSnapSuite) TestCheckSnapInstanceName(c *C) { 798 st := state.New(nil) 799 st.Lock() 800 defer st.Unlock() 801 802 si := &snap.SideInfo{RealName: "foo", Revision: snap.R(1), SnapID: "some-base-id"} 803 info := snaptest.MockSnap(c, ` 804 name: foo 805 version: 1 806 `, si) 807 snapstate.Set(st, "foo", &snapstate.SnapState{ 808 Active: true, 809 Sequence: []*snap.SideInfo{si}, 810 Current: si.Revision, 811 }) 812 813 var openSnapFile = func(path string, si *snap.SideInfo) (*snap.Info, snap.Container, error) { 814 return info, emptyContainer(c), nil 815 } 816 restore := snapstate.MockOpenSnapFile(openSnapFile) 817 defer restore() 818 819 st.Unlock() 820 err := snapstate.CheckSnap(st, "snap-path", "foo_instance", nil, nil, snapstate.Flags{}, nil) 821 st.Lock() 822 c.Check(err, IsNil) 823 824 st.Unlock() 825 err = snapstate.CheckSnap(st, "snap-path", "bar_instance", nil, nil, snapstate.Flags{}, nil) 826 st.Lock() 827 c.Check(err, ErrorMatches, `cannot install snap "foo" using instance name "bar_instance"`) 828 829 st.Unlock() 830 err = snapstate.CheckSnap(st, "snap-path", "other-name", nil, nil, snapstate.Flags{}, nil) 831 st.Lock() 832 c.Check(err, ErrorMatches, `cannot install snap "foo" using instance name "other-name"`) 833 } 834 835 func (s *checkSnapSuite) TestCheckSnapCheckCallInstanceKeySet(c *C) { 836 const yaml = `name: foo 837 version: 1.0` 838 839 si := &snap.SideInfo{ 840 SnapID: "snap-id", 841 } 842 843 var openSnapFile = func(path string, si *snap.SideInfo) (*snap.Info, snap.Container, error) { 844 info := snaptest.MockInfo(c, yaml, si) 845 return info, emptyContainer(c), nil 846 } 847 r1 := snapstate.MockOpenSnapFile(openSnapFile) 848 defer r1() 849 850 checkCbCalled := false 851 checkCb := func(st *state.State, s, cur *snap.Info, sf snap.Container, flags snapstate.Flags, deviceCtx snapstate.DeviceContext) error { 852 c.Assert(sf, NotNil) 853 c.Assert(s.InstanceName(), Equals, "foo_instance") 854 c.Assert(s.SnapName(), Equals, "foo") 855 c.Assert(s.SnapID, Equals, "snap-id") 856 checkCbCalled = true 857 return nil 858 } 859 r2 := snapstate.MockCheckSnapCallbacks([]snapstate.CheckSnapCallback{checkCb}) 860 defer r2() 861 862 err := snapstate.CheckSnap(s.st, "snap-path", "foo_instance", si, nil, snapstate.Flags{}, nil) 863 c.Check(err, IsNil) 864 865 c.Check(checkCbCalled, Equals, true) 866 } 867 868 func (s *checkSnapSuite) TestCheckSnapCheckEpochLocal(c *C) { 869 si := &snap.SideInfo{ 870 SnapID: "snap-id", 871 } 872 873 var openSnapFile = func(path string, si *snap.SideInfo) (*snap.Info, snap.Container, error) { 874 info := snaptest.MockInfo(c, "{name: foo, version: 1.0, epoch: 13}", si) 875 return info, emptyContainer(c), nil 876 } 877 r1 := snapstate.MockOpenSnapFile(openSnapFile) 878 defer r1() 879 880 err := snapstate.CheckSnap(s.st, "snap-path", "foo", si, &snap.Info{}, snapstate.Flags{}, nil) 881 c.Check(err, ErrorMatches, `cannot refresh "foo" to local snap with epoch 13, because it can't read the current epoch of 0`) 882 } 883 884 func (s *checkSnapSuite) TestCheckSnapCheckEpochNonLocal(c *C) { 885 si := &snap.SideInfo{ 886 SnapID: "snap-id", 887 Revision: snap.R(42), 888 } 889 890 var openSnapFile = func(path string, si *snap.SideInfo) (*snap.Info, snap.Container, error) { 891 info := snaptest.MockInfo(c, "{name: foo, version: 1.0, epoch: 13}", si) 892 return info, emptyContainer(c), nil 893 } 894 r1 := snapstate.MockOpenSnapFile(openSnapFile) 895 defer r1() 896 897 err := snapstate.CheckSnap(s.st, "snap-path", "foo", si, &snap.Info{}, snapstate.Flags{}, nil) 898 c.Check(err, ErrorMatches, `cannot refresh "foo" to new revision 42 with epoch 13, because it can't read the current epoch of 0`) 899 } 900 901 func (s *checkSnapSuite) TestCheckSnapBasesCoreCanBeUsedAsCore16(c *C) { 902 st := state.New(nil) 903 st.Lock() 904 defer st.Unlock() 905 906 si := &snap.SideInfo{RealName: "core", Revision: snap.R(1), SnapID: "core-id"} 907 snaptest.MockSnap(c, ` 908 name: core 909 type: os 910 version: 1 911 `, si) 912 snapstate.Set(st, "core", &snapstate.SnapState{ 913 SnapType: "os", 914 Active: true, 915 Sequence: []*snap.SideInfo{si}, 916 Current: si.Revision, 917 }) 918 919 const yaml = `name: requires-core16 920 version: 1 921 base: core16 922 ` 923 924 info, err := snap.InfoFromSnapYaml([]byte(yaml)) 925 c.Assert(err, IsNil) 926 927 var openSnapFile = func(path string, si *snap.SideInfo) (*snap.Info, snap.Container, error) { 928 return info, emptyContainer(c), nil 929 } 930 restore := snapstate.MockOpenSnapFile(openSnapFile) 931 defer restore() 932 933 st.Unlock() 934 err = snapstate.CheckSnap(st, "snap-path", "requires-core16", nil, nil, snapstate.Flags{}, nil) 935 st.Lock() 936 c.Check(err, IsNil) 937 } 938 939 func (s *checkSnapSuite) TestCheckSnapdHappy(c *C) { 940 st := state.New(nil) 941 st.Lock() 942 defer st.Unlock() 943 944 for _, t := range []struct { 945 yaml string 946 errStr string 947 }{ 948 {"name: snapd\nversion: 1\ntype: snapd", ""}, 949 {"name: some-snap\nversion: 1\ntype: snapd", `cannot install snap "some-snap" of type "snapd" with a name other than "snapd"`}, 950 {"name: snapd_instance\nversion: 1\ntype: snapd", `cannot install snap "snapd_instance" of type "snapd" with a name other than "snapd"`}, 951 } { 952 info, err := snap.InfoFromSnapYaml([]byte(t.yaml)) 953 c.Assert(err, IsNil) 954 955 var openSnapFile = func(path string, si *snap.SideInfo) (*snap.Info, snap.Container, error) { 956 return info, emptyContainer(c), nil 957 } 958 restore := snapstate.MockOpenSnapFile(openSnapFile) 959 defer restore() 960 961 st.Unlock() 962 err = snapstate.CheckSnap(st, "snap-path", "snapd", nil, nil, snapstate.Flags{}, nil) 963 st.Lock() 964 if t.errStr == "" { 965 c.Check(err, IsNil) 966 } else { 967 c.Check(err, ErrorMatches, t.errStr) 968 } 969 } 970 } 971 972 // Note, invalid usernames checked in snap/info_snap_yaml.go 973 var systemUsernamesTests = []struct { 974 sysIDs string 975 classic bool 976 noRangeUser bool 977 noUser bool 978 scVer string 979 error string 980 }{{ 981 sysIDs: "snap_daemon: shared", 982 scVer: "dead 2.4.1 deadbeef bpf-actlog", 983 }, { 984 sysIDs: "snap_daemon:\n scope: shared", 985 scVer: "dead 2.4.1 deadbeef bpf-actlog", 986 }, { 987 sysIDs: "snap_daemon:\n scope: private", 988 scVer: "dead 2.4.1 deadbeef bpf-actlog", 989 error: `snap "foo" requires unsupported user scope "private" for this version of snapd`, 990 }, { 991 sysIDs: "snap_daemon:\n scope: external", 992 scVer: "dead 2.4.1 deadbeef bpf-actlog", 993 error: `snap "foo" requires unsupported user scope "external" for this version of snapd`, 994 }, { 995 sysIDs: "snap_daemon:\n scope: other", 996 scVer: "dead 2.4.1 deadbeef bpf-actlog", 997 error: `snap "foo" requires unsupported user scope "other"`, 998 }, { 999 sysIDs: "snap_daemon: shared", 1000 scVer: "dead 2.4.1 deadbeef bpf-actlog", 1001 classic: true, 1002 }, { 1003 sysIDs: "snap_daemon:\n scope: shared", 1004 scVer: "dead 2.4.1 deadbeef bpf-actlog", 1005 classic: true, 1006 }, { 1007 sysIDs: "snap_daemon:\n scope: private", 1008 scVer: "dead 2.4.1 deadbeef bpf-actlog", 1009 classic: true, 1010 error: `snap "foo" requires unsupported user scope "private" for this version of snapd`, 1011 }, { 1012 sysIDs: "snap_daemon:\n scope: external", 1013 scVer: "dead 2.4.1 deadbeef bpf-actlog", 1014 classic: true, 1015 error: `snap "foo" requires unsupported user scope "external" for this version of snapd`, 1016 }, { 1017 sysIDs: "snap_daemon:\n scope: other", 1018 scVer: "dead 2.4.1 deadbeef bpf-actlog", 1019 classic: true, 1020 error: `snap "foo" requires unsupported user scope "other"`, 1021 }, { 1022 sysIDs: "snap_daemon: shared\n allowed-not: shared", 1023 scVer: "dead 2.4.1 deadbeef bpf-actlog", 1024 error: `snap "foo" requires unsupported system username "allowed-not"`, 1025 }, { 1026 sysIDs: "allowed-not: shared\n snap_daemon: shared", 1027 scVer: "dead 2.4.1 deadbeef bpf-actlog", 1028 classic: true, 1029 error: `snap "foo" requires unsupported system username "allowed-not"`, 1030 }, { 1031 sysIDs: "snap_daemon: shared", 1032 noUser: true, 1033 scVer: "dead 2.4.1 deadbeef bpf-actlog", 1034 error: `cannot ensure users for snap "foo" required system username "snap_daemon": cannot add user/group "snap_daemon", group exists and user does not`, 1035 }, { 1036 sysIDs: "snap_daemon: shared", 1037 classic: true, 1038 noUser: true, 1039 scVer: "dead 2.4.1 deadbeef bpf-actlog", 1040 error: `cannot ensure users for snap "foo" required system username "snap_daemon": cannot add user/group "snap_daemon", group exists and user does not`, 1041 }, { 1042 sysIDs: "snap_daemon: shared", 1043 scVer: "dead 2.3.3 deadbeef bpf-actlog", 1044 error: `snap "foo" system usernames require a snapd built against libseccomp >= 2.4`, 1045 }, { 1046 sysIDs: "snap_daemon: shared", 1047 classic: true, 1048 scVer: "dead 2.3.3 deadbeef bpf-actlog", 1049 error: `snap "foo" system usernames require a snapd built against libseccomp >= 2.4`, 1050 }, { 1051 sysIDs: "snap_daemon: shared", 1052 scVer: "dead 3.0.0 deadbeef bpf-actlog", 1053 }, { 1054 sysIDs: "snap_daemon: shared", 1055 classic: true, 1056 scVer: "dead 3.0.0 deadbeef bpf-actlog", 1057 }, { 1058 sysIDs: "snap_daemon: shared", 1059 scVer: "dead 2.4.1 deadbeef -", 1060 error: `snap "foo" system usernames require a snapd built against golang-seccomp >= 0.9.1`, 1061 }, { 1062 sysIDs: "snap_daemon: shared", 1063 classic: true, 1064 scVer: "dead 2.4.1 deadbeef -", 1065 error: `snap "foo" system usernames require a snapd built against golang-seccomp >= 0.9.1`, 1066 }, { 1067 sysIDs: "snap_daemon: shared", 1068 noRangeUser: true, 1069 scVer: "dead 2.4.1 deadbeef bpf-actlog", 1070 error: `cannot ensure users for snap "foo" required system username "snap_daemon": cannot add user/group "snapd-range-524288-root", group exists and user does not`, 1071 }, { 1072 sysIDs: "snap_daemon: shared", 1073 classic: true, 1074 noRangeUser: true, 1075 scVer: "dead 2.4.1 deadbeef bpf-actlog", 1076 error: `cannot ensure users for snap "foo" required system username "snap_daemon": cannot add user/group "snapd-range-524288-root", group exists and user does not`, 1077 }, { 1078 sysIDs: "snap_daemon: shared\n daemon: shared", 1079 classic: true, 1080 scVer: "dead 2.4.1 deadbeef bpf-actlog", 1081 error: `snap "foo" requires unsupported system username "daemon"`, 1082 }, 1083 } 1084 1085 func (s *checkSnapSuite) TestCheckSnapSystemUsernames(c *C) { 1086 for _, test := range systemUsernamesTests { 1087 restore := seccomp_compiler.MockCompilerVersionInfo(test.scVer) 1088 defer restore() 1089 1090 restore = release.MockOnClassic(test.classic) 1091 defer restore() 1092 1093 var osutilEnsureUserGroupCalls int 1094 if test.noRangeUser { 1095 restore = snapstate.MockOsutilEnsureUserGroup(func(name string, id uint32, extraUsers bool) error { 1096 return fmt.Errorf(`cannot add user/group "%s", group exists and user does not`, name) 1097 }) 1098 } else if test.noUser { 1099 restore = snapstate.MockOsutilEnsureUserGroup(func(name string, id uint32, extraUsers bool) error { 1100 if name == "snapd-range-524288-root" { 1101 return nil 1102 } 1103 return fmt.Errorf(`cannot add user/group "%s", group exists and user does not`, name) 1104 }) 1105 } else { 1106 restore = snapstate.MockOsutilEnsureUserGroup(func(name string, id uint32, extraUsers bool) error { 1107 osutilEnsureUserGroupCalls++ 1108 return nil 1109 }) 1110 } 1111 defer restore() 1112 1113 yaml := fmt.Sprintf("name: foo\nsystem-usernames:\n %s\n", test.sysIDs) 1114 1115 info, err := snap.InfoFromSnapYaml([]byte(yaml)) 1116 c.Assert(err, IsNil) 1117 1118 var openSnapFile = func(path string, si *snap.SideInfo) (*snap.Info, snap.Container, error) { 1119 return info, emptyContainer(c), nil 1120 } 1121 restore = snapstate.MockOpenSnapFile(openSnapFile) 1122 defer restore() 1123 err = snapstate.CheckSnap(s.st, "snap-path", "foo", nil, nil, snapstate.Flags{}, nil) 1124 if test.error != "" { 1125 c.Check(err, ErrorMatches, test.error) 1126 c.Check(osutilEnsureUserGroupCalls, Equals, 0) 1127 } else { 1128 c.Assert(err, IsNil) 1129 // one call for the range user, one for the system user 1130 c.Check(osutilEnsureUserGroupCalls, Equals, 2) 1131 } 1132 } 1133 } 1134 1135 func (s *checkSnapSuite) TestCheckSnapSystemUsernamesCalls(c *C) { 1136 // FIXME: this test fails on machines where the user was already 1137 // created by the system snapd 1138 _, err := osutil.FindUid("snapd-range-524288-root") 1139 if err == nil { 1140 c.Skip("FIXME") 1141 } 1142 falsePath := osutil.LookPathDefault("false", "/bin/false") 1143 for _, classic := range []bool{false, true} { 1144 restore := release.MockOnClassic(classic) 1145 defer restore() 1146 1147 restore = seccomp_compiler.MockCompilerVersionInfo("dead 2.4.1 deadbeef bpf-actlog") 1148 defer restore() 1149 1150 const yaml = `name: foo 1151 version: 1.0 1152 system-usernames: 1153 snap_daemon: shared` 1154 1155 info, err := snap.InfoFromSnapYaml([]byte(yaml)) 1156 c.Assert(err, IsNil) 1157 1158 var openSnapFile = func(path string, si *snap.SideInfo) (*snap.Info, snap.Container, error) { 1159 return info, emptyContainer(c), nil 1160 } 1161 restore = snapstate.MockOpenSnapFile(openSnapFile) 1162 defer restore() 1163 1164 mockGroupAdd := testutil.MockCommand(c, "groupadd", "") 1165 defer mockGroupAdd.Restore() 1166 1167 mockUserAdd := testutil.MockCommand(c, "useradd", "") 1168 defer mockUserAdd.Restore() 1169 1170 err = snapstate.CheckSnap(s.st, "snap-path", "foo", nil, nil, snapstate.Flags{}, nil) 1171 c.Assert(err, IsNil) 1172 if classic { 1173 c.Check(mockGroupAdd.Calls(), DeepEquals, [][]string{ 1174 {"groupadd", "--system", "--gid", "524288", "snapd-range-524288-root"}, 1175 {"groupadd", "--system", "--gid", "584788", "snap_daemon"}, 1176 }) 1177 c.Check(mockUserAdd.Calls(), DeepEquals, [][]string{ 1178 {"useradd", "--system", "--home-dir", "/nonexistent", "--no-create-home", "--shell", falsePath, "--gid", "524288", "--no-user-group", "--uid", "524288", "snapd-range-524288-root"}, 1179 {"useradd", "--system", "--home-dir", "/nonexistent", "--no-create-home", "--shell", falsePath, "--gid", "584788", "--no-user-group", "--uid", "584788", "snap_daemon"}, 1180 }) 1181 } else { 1182 c.Check(mockGroupAdd.Calls(), DeepEquals, [][]string{ 1183 {"groupadd", "--system", "--gid", "524288", "--extrausers", "snapd-range-524288-root"}, 1184 {"groupadd", "--system", "--gid", "584788", "--extrausers", "snap_daemon"}, 1185 }) 1186 c.Check(mockUserAdd.Calls(), DeepEquals, [][]string{ 1187 {"useradd", "--system", "--home-dir", "/nonexistent", "--no-create-home", "--shell", falsePath, "--gid", "524288", "--no-user-group", "--uid", "524288", "--extrausers", "snapd-range-524288-root"}, 1188 {"useradd", "--system", "--home-dir", "/nonexistent", "--no-create-home", "--shell", falsePath, "--gid", "584788", "--no-user-group", "--uid", "584788", "--extrausers", "snap_daemon"}, 1189 }) 1190 1191 } 1192 } 1193 } 1194 1195 func (s *checkSnapSuite) TestCheckSnapRemodelKernel(c *C) { 1196 reset := release.MockOnClassic(false) 1197 defer reset() 1198 1199 st := state.New(nil) 1200 st.Lock() 1201 defer st.Unlock() 1202 1203 si := &snap.SideInfo{RealName: "kernel", Revision: snap.R(2), SnapID: "kernel-id"} 1204 snaptest.MockSnap(c, ` 1205 name: kernel 1206 type: kernel 1207 version: 1 1208 `, si) 1209 snapstate.Set(st, "kernel", &snapstate.SnapState{ 1210 SnapType: "kernel", 1211 Active: true, 1212 Sequence: []*snap.SideInfo{si}, 1213 Current: si.Revision, 1214 }) 1215 1216 const yaml = `name: new-kernel 1217 type: kernel 1218 version: 2 1219 ` 1220 1221 info, err := snap.InfoFromSnapYaml([]byte(yaml)) 1222 info.SnapID = "new-kernel-id" 1223 c.Assert(err, IsNil) 1224 1225 var openSnapFile = func(path string, si *snap.SideInfo) (*snap.Info, snap.Container, error) { 1226 return info, emptyContainer(c), nil 1227 } 1228 restore := snapstate.MockOpenSnapFile(openSnapFile) 1229 defer restore() 1230 1231 // happy case, the new-kernel matches the model 1232 deviceCtx := &snapstatetest.TrivialDeviceContext{ 1233 Remodeling: true, 1234 DeviceModel: MakeModel(map[string]interface{}{ 1235 "kernel": "new-kernel", 1236 "gadget": "gadget", 1237 }), 1238 } 1239 1240 st.Unlock() 1241 err = snapstate.CheckSnap(st, "snap-path", "new-kernel", nil, nil, snapstate.Flags{}, deviceCtx) 1242 st.Lock() 1243 c.Check(err, IsNil) 1244 } 1245 1246 func (s *checkSnapSuite) TestCheckSnapRemodelGadget(c *C) { 1247 reset := release.MockOnClassic(false) 1248 defer reset() 1249 1250 st := state.New(nil) 1251 st.Lock() 1252 defer st.Unlock() 1253 1254 si := &snap.SideInfo{RealName: "gadget", Revision: snap.R(2), SnapID: "gadget-id"} 1255 snaptest.MockSnap(c, ` 1256 name: gadget 1257 type: gadget 1258 version: 1 1259 `, si) 1260 snapstate.Set(st, "gadget", &snapstate.SnapState{ 1261 SnapType: "gadget", 1262 Active: true, 1263 Sequence: []*snap.SideInfo{si}, 1264 Current: si.Revision, 1265 }) 1266 1267 const yaml = `name: new-gadget 1268 type: gadget 1269 version: 2 1270 ` 1271 1272 info, err := snap.InfoFromSnapYaml([]byte(yaml)) 1273 info.SnapID = "new-gadget-id" 1274 c.Assert(err, IsNil) 1275 1276 var openSnapFile = func(path string, si *snap.SideInfo) (*snap.Info, snap.Container, error) { 1277 return info, emptyContainer(c), nil 1278 } 1279 restore := snapstate.MockOpenSnapFile(openSnapFile) 1280 defer restore() 1281 1282 // happy case, the new-gadget matches the model but we do not 1283 // support this yet 1284 deviceCtx := &snapstatetest.TrivialDeviceContext{ 1285 Remodeling: true, 1286 DeviceModel: MakeModel(map[string]interface{}{ 1287 "kernel": "kernel", 1288 "gadget": "new-gadget", 1289 }), 1290 } 1291 1292 st.Unlock() 1293 err = snapstate.CheckSnap(st, "snap-path", "new-gadget", nil, nil, snapstate.Flags{}, deviceCtx) 1294 st.Lock() 1295 c.Check(err, IsNil) 1296 }