From e99a881ebd500bc2352c4ce11c9b8ed0b9da8db0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alfonso=20S=C3=A1nchez-Beato?= Date: Wed, 6 Nov 2024 08:23:43 -0500 Subject: [PATCH] o/hookstate: allow snapctl model command for kernel snaps --- overlord/hookstate/ctlcmd/model.go | 7 +++--- overlord/hookstate/ctlcmd/model_test.go | 29 ++++++++++++++++++------- 2 files changed, 25 insertions(+), 11 deletions(-) diff --git a/overlord/hookstate/ctlcmd/model.go b/overlord/hookstate/ctlcmd/model.go index cc54331a39e..d8a7ebc6e15 100644 --- a/overlord/hookstate/ctlcmd/model.go +++ b/overlord/hookstate/ctlcmd/model.go @@ -153,11 +153,12 @@ func (c *modelCommand) getSnapInfoWithPublisher(st *state.State, snapName string // checkPermissions verifies that the snap described by snapInfo is allowed to // read the model assertion of deviceCtx. // We allow the usage of this command if one of the following is true -// 1. The requesting snap must be a gadget +// 1. The requesting snap must be of gadget or kernel type // 2. Come from the same brand as the device model assertion // 3. Have the snapd-control plug func (c *modelCommand) checkPermissions(st *state.State, deviceCtx snapstate.DeviceContext, snapInfo *snap.Info) error { - if snapType := snapInfo.Type(); snapType == snap.TypeGadget { + switch snapInfo.Type() { + case snap.TypeGadget, snap.TypeKernel: return nil } if snapInfo.Publisher.ID == deviceCtx.Model().BrandID() { @@ -170,7 +171,7 @@ func (c *modelCommand) checkPermissions(st *state.State, deviceCtx snapstate.Dev } c.reportError("cannot get model assertion for snap %q: "+ - "must be either a gadget snap, from the same publisher as the model "+ + "must be either a gadget or a kernel snap, from the same publisher as the model "+ "or have the snapd-control interface\n", snapInfo.SnapName()) return fmt.Errorf("insufficient permissions to get model assertion for snap %q", snapInfo.SnapName()) } diff --git a/overlord/hookstate/ctlcmd/model_test.go b/overlord/hookstate/ctlcmd/model_test.go index 1f6f49c7f36..35bc5b3caf3 100644 --- a/overlord/hookstate/ctlcmd/model_test.go +++ b/overlord/hookstate/ctlcmd/model_test.go @@ -192,6 +192,11 @@ type: base version: 1 ` +const snapKernelYaml = `name: kernel1 +type: kernel +version: 1 +` + const snapYaml = `name: snap1 base: snap1-base version: 1 @@ -239,7 +244,7 @@ func (s *modelSuite) TestUnhappyModelCommandInsufficientPermissions(c *C) { stdout, stderr, err := ctlcmd.Run(mockContext, []string{"model"}, 0) c.Check(err, ErrorMatches, "insufficient permissions to get model assertion for snap \"snap1\"") c.Check(string(stdout), Equals, "") - c.Check(string(stderr), Equals, "cannot get model assertion for snap \"snap1\": must be either a gadget snap, from the same publisher as the model or have the snapd-control interface\n") + c.Check(string(stderr), Equals, "cannot get model assertion for snap \"snap1\": must be either a gadget or a kernel snap, from the same publisher as the model or have the snapd-control interface\n") } func (s *modelSuite) TestHappyModelCommandIdenticalPublisher(c *C) { @@ -365,15 +370,23 @@ timestamp: %s c.Check(string(stderr), Equals, "") } -func (s *modelSuite) TestHappyModelCommandGadgetYaml(c *C) { +func (s *modelSuite) TestHappyModelCommandGadget(c *C) { + s.testHappyModelCommandForSnap(c, "gadget1", snapGadgetYaml) +} + +func (s *modelSuite) TestHappyModelCommandKernel(c *C) { + s.testHappyModelCommandForSnap(c, "kernel1", snapKernelYaml) +} + +func (s *modelSuite) testHappyModelCommandForSnap(c *C, snapName, snapYaml string) { // This tests verifies that a snap that is a gadget can be used to // get the model assertion, even if from a different publisher - s.addSnapDeclaration(c, "gadget1-id", "canonical", "gadget1") + s.addSnapDeclaration(c, snapName+"-id", "canonical", snapName) s.setupBrands() // set a model assertion s.state.Lock() - current := s.brands.Model("canonical", "pc-model", map[string]interface{}{ + current := s.brands.Model("my-brand", "pc-model", map[string]interface{}{ "architecture": "amd64", "kernel": "pc-kernel", "gadget": "pc", @@ -382,21 +395,21 @@ func (s *modelSuite) TestHappyModelCommandGadgetYaml(c *C) { err := assertstate.Add(s.state, current) c.Assert(err, IsNil) devicestatetest.SetDevice(s.state, &auth.DeviceState{ - Brand: "canonical", + Brand: "my-brand", Model: "pc-model", }) c.Assert(err, IsNil) task := s.state.NewTask("test-task", "my test task") - setup := &hookstate.HookSetup{Snap: "gadget1", Revision: snap.R(1), Hook: "test-hook"} + setup := &hookstate.HookSetup{Snap: snapName, Revision: snap.R(1), Hook: "test-hook"} mockContext, err := hookstate.NewContext(task, s.state, setup, s.mockHandler, "") c.Assert(err, IsNil) - mockInstalledSnap(c, s.state, snapGadgetYaml, "") + mockInstalledSnap(c, s.state, snapYaml, "") s.state.Unlock() stdout, stderr, err := ctlcmd.Run(mockContext, []string{"model"}, 0) c.Check(err, IsNil) - c.Check(string(stdout), Equals, fmt.Sprintf(`brand-id: canonical + c.Check(string(stdout), Equals, fmt.Sprintf(`brand-id: my-brand model: pc-model serial: -- (device not registered yet) architecture: amd64