diff options
| -rw-r--r-- | interfaces/apparmor/template.go | 2 | ||||
| -rw-r--r-- | interfaces/builtin/all.go | 3 | ||||
| -rw-r--r-- | interfaces/builtin/all_test.go | 2 | ||||
| -rw-r--r-- | interfaces/builtin/basedeclaration.go | 16 | ||||
| -rw-r--r-- | interfaces/builtin/basedeclaration_test.go | 4 | ||||
| -rw-r--r-- | interfaces/builtin/bootconfig.go | 39 | ||||
| -rw-r--r-- | interfaces/builtin/bootconfig_test.go | 74 | ||||
| -rw-r--r-- | interfaces/builtin/libvirt.go | 3 | ||||
| -rw-r--r-- | interfaces/builtin/openvswitch.go | 46 | ||||
| -rw-r--r-- | interfaces/builtin/openvswitch_support.go | 37 | ||||
| -rw-r--r-- | interfaces/builtin/openvswitch_support_test.go | 86 | ||||
| -rw-r--r-- | interfaces/builtin/openvswitch_test.go | 90 | ||||
| -rw-r--r-- | interfaces/builtin/process_control.go | 3 | ||||
| -rw-r--r-- | interfaces/systemd/backend.go | 10 | ||||
| -rw-r--r-- | interfaces/systemd/backend_test.go | 30 | ||||
| -rw-r--r-- | overlord/managers_test.go | 68 | ||||
| -rw-r--r-- | overlord/snapstate/aliases.go | 116 | ||||
| -rw-r--r-- | overlord/snapstate/aliases_test.go | 376 | ||||
| -rw-r--r-- | snap/implicit.go | 2 | ||||
| -rw-r--r-- | systemd/systemd.go | 14 | ||||
| -rw-r--r-- | systemd/systemd_test.go | 12 | ||||
| -rwxr-xr-x | tests/lib/prepare.sh | 1 |
22 files changed, 909 insertions, 125 deletions
diff --git a/interfaces/apparmor/template.go b/interfaces/apparmor/template.go index aaa1385d4e..f8c07714a8 100644 --- a/interfaces/apparmor/template.go +++ b/interfaces/apparmor/template.go @@ -152,6 +152,7 @@ var defaultTemplate = []byte(` /{,usr/}bin/rev ixr, /{,usr/}bin/rm ixr, /{,usr/}bin/rmdir ixr, + /{,usr/}bin/run-parts ixr, /{,usr/}bin/sed ixr, /{,usr/}bin/seq ixr, /{,usr/}bin/sha{1,224,256,384,512}sum ixr, @@ -235,6 +236,7 @@ var defaultTemplate = []byte(` # match until AppArmor kernel var is available to solve this properly (see # LP: #1546825 for details) owner @{PROC}/@{pid}/cmdline r, + owner @{PROC}/@{pid}/comm r, # Miscellaneous accesses /dev/{,u}random w, diff --git a/interfaces/builtin/all.go b/interfaces/builtin/all.go index 4563064fe4..d74c2fc5d7 100644 --- a/interfaces/builtin/all.go +++ b/interfaces/builtin/all.go @@ -50,6 +50,7 @@ var allInterfaces = []interfaces.Interface{ NewAlsaInterface(), NewAvahiObserveInterface(), NewBluetoothControlInterface(), + NewBootConfigInterface(), NewCameraInterface(), NewCupsControlInterface(), NewDcdbasControlInterface(), @@ -69,6 +70,8 @@ var allInterfaces = []interfaces.Interface{ NewNetworkObserveInterface(), NewNetworkSetupObserveInterface(), NewOpenglInterface(), + NewOpenvSwitchInterface(), + NewOpenvSwitchSupportInterface(), NewOpticalDriveInterface(), NewProcessControlInterface(), NewRawUsbInterface(), diff --git a/interfaces/builtin/all_test.go b/interfaces/builtin/all_test.go index 4411ec5c7d..53b6733c09 100644 --- a/interfaces/builtin/all_test.go +++ b/interfaces/builtin/all_test.go @@ -68,6 +68,8 @@ func (s *AllSuite) TestInterfaces(c *C) { c.Check(all, DeepContains, builtin.NewNetworkInterface()) c.Check(all, DeepContains, builtin.NewNetworkObserveInterface()) c.Check(all, DeepContains, builtin.NewOpenglInterface()) + c.Check(all, DeepContains, builtin.NewOpenvSwitchInterface()) + c.Check(all, DeepContains, builtin.NewOpenvSwitchSupportInterface()) c.Check(all, DeepContains, builtin.NewOpticalDriveInterface()) c.Check(all, DeepContains, builtin.NewProcessControlInterface()) c.Check(all, DeepContains, builtin.NewRawUsbInterface()) diff --git a/interfaces/builtin/basedeclaration.go b/interfaces/builtin/basedeclaration.go index 02abc20cf0..6823757e13 100644 --- a/interfaces/builtin/basedeclaration.go +++ b/interfaces/builtin/basedeclaration.go @@ -178,6 +178,12 @@ slots: - core - gadget deny-auto-connection: true + boot-config: + allow-installation: + slot-snap-type: + - gadget + deny-connection: true + deny-auto-connection: true browser-support: allow-installation: slot-snap-type: @@ -376,6 +382,16 @@ slots: allow-installation: slot-snap-type: - core + openvswitch: + allow-installation: + slot-snap-type: + - core + deny-auto-connection: true + openvswitch-support: + allow-installation: + slot-snap-type: + - core + deny-auto-connection: true optical-drive: allow-installation: slot-snap-type: diff --git a/interfaces/builtin/basedeclaration_test.go b/interfaces/builtin/basedeclaration_test.go index 675cfc71c0..3bc6694eb6 100644 --- a/interfaces/builtin/basedeclaration_test.go +++ b/interfaces/builtin/basedeclaration_test.go @@ -155,7 +155,7 @@ func (s *baseDeclSuite) TestAutoConnection(c *C) { continue } expected := autoconnect[iface.Name()] - comm := Commentf(iface.Name()) + comm := Commentf("%s: %v", iface.Name(), expected) // check base declaration cand := s.connectCand(c, iface.Name(), "", "") @@ -347,6 +347,7 @@ var ( // other "bluez": {"app"}, "bool-file": {"core", "gadget"}, + "boot-config": {"gadget"}, "browser-support": {"core"}, "content": {"app", "gadget"}, "docker-support": {"core"}, @@ -467,6 +468,7 @@ func (s *baseDeclSuite) TestConnection(c *C) { // case-by-case basis noconnect := map[string]bool{ "bluez": true, + "boot-config": true, "docker": true, "fwupd": true, "location-control": true, diff --git a/interfaces/builtin/bootconfig.go b/interfaces/builtin/bootconfig.go new file mode 100644 index 0000000000..5b1c4dcecb --- /dev/null +++ b/interfaces/builtin/bootconfig.go @@ -0,0 +1,39 @@ +// -*- Mode: Go; indent-tabs-mode: t -*- + +/* + * Copyright (C) 2016 Canonical Ltd + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 3 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + * + */ + +package builtin + +import ( + "github.com/snapcore/snapd/interfaces" +) + +const bootConfigConnectedPlugAppArmor = ` +# Description: Can access boot config files amd brick the system +# Usage: reserved (very much so!) + +# Allow read/write access to the pi2 boot config.txt +owner /boot/uboot/config.txt rwk, +` + +func NewBootConfigInterface() interfaces.Interface { + return &commonInterface{ + name: "boot-config", + connectedPlugAppArmor: bootConfigConnectedPlugAppArmor, + } +} diff --git a/interfaces/builtin/bootconfig_test.go b/interfaces/builtin/bootconfig_test.go new file mode 100644 index 0000000000..190dcde624 --- /dev/null +++ b/interfaces/builtin/bootconfig_test.go @@ -0,0 +1,74 @@ +// -*- Mode: Go; indent-tabs-mode: t -*- + +/* + * Copyright (C) 2016 Canonical Ltd + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 3 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + * + */ + +package builtin_test + +import ( + . "gopkg.in/check.v1" + + "github.com/snapcore/snapd/interfaces" + "github.com/snapcore/snapd/interfaces/builtin" + "github.com/snapcore/snapd/snap" + "github.com/snapcore/snapd/testutil" +) + +type bootConfigInterfaceSuite struct { + iface interfaces.Interface + slot *interfaces.Slot + plug *interfaces.Plug +} + +var _ = Suite(&bootConfigInterfaceSuite{ + iface: builtin.NewBootConfigInterface(), + slot: &interfaces.Slot{ + SlotInfo: &snap.SlotInfo{ + Snap: &snap.Info{SuggestedName: "pi2", Type: snap.TypeGadget}, + Name: "boot-config", + Interface: "boot-config", + }, + }, + plug: &interfaces.Plug{ + PlugInfo: &snap.PlugInfo{ + Snap: &snap.Info{SuggestedName: "other"}, + Name: "boot-config", + Interface: "boot-config", + }, + }, +}) + +func (s *bootConfigInterfaceSuite) TestName(c *C) { + c.Assert(s.iface.Name(), Equals, "boot-config") +} + +func (s *bootConfigInterfaceSuite) TestUsedSecuritySystems(c *C) { + // connected plugs have a non-nil security snippet for apparmor + snippet, err := s.iface.ConnectedPlugSnippet(s.plug, s.slot, interfaces.SecurityAppArmor) + c.Assert(err, IsNil) + c.Assert(string(snippet), testutil.Contains, "/boot/uboot/config.txt") +} + +func (s *bootConfigInterfaceSuite) TestSanitizeSlot(c *C) { + err := s.iface.SanitizeSlot(s.slot) + c.Assert(err, IsNil) +} + +func (s *bootConfigInterfaceSuite) TestSanitizePlug(c *C) { + err := s.iface.SanitizePlug(s.plug) + c.Assert(err, IsNil) +} diff --git a/interfaces/builtin/libvirt.go b/interfaces/builtin/libvirt.go index 93ae32d7bb..bcf7c0a05a 100644 --- a/interfaces/builtin/libvirt.go +++ b/interfaces/builtin/libvirt.go @@ -23,6 +23,7 @@ import "github.com/snapcore/snapd/interfaces" const libvirtConnectedPlugAppArmor = ` /run/libvirt/libvirt-sock rw, +/etc/libvirt/* r, ` const libvirtConnectedPlugSecComp = ` @@ -35,6 +36,8 @@ sendto sendmsg socket socketpair +listen +accept ` func NewLibvirtInterface() interfaces.Interface { diff --git a/interfaces/builtin/openvswitch.go b/interfaces/builtin/openvswitch.go new file mode 100644 index 0000000000..847b70eb03 --- /dev/null +++ b/interfaces/builtin/openvswitch.go @@ -0,0 +1,46 @@ +// -*- Mode: Go; indent-tabs-mode: t -*- + +/* + * Copyright (C) 2016 Canonical Ltd + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 3 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + * + */ + +package builtin + +import "github.com/snapcore/snapd/interfaces" + +const openvswitchConnectedPlugAppArmor = ` +/run/openvswitch/db.sock rw, +` + +const openvswitchConnectedPlugSecComp = ` +connect +recv +recvmsg +send +sendto +sendmsg +socket +socketpair +` + +func NewOpenvSwitchInterface() interfaces.Interface { + return &commonInterface{ + name: "openvswitch", + connectedPlugAppArmor: openvswitchConnectedPlugAppArmor, + connectedPlugSecComp: openvswitchConnectedPlugSecComp, + reservedForOS: true, + } +} diff --git a/interfaces/builtin/openvswitch_support.go b/interfaces/builtin/openvswitch_support.go new file mode 100644 index 0000000000..3d57ed623b --- /dev/null +++ b/interfaces/builtin/openvswitch_support.go @@ -0,0 +1,37 @@ +// -*- Mode: Go; indent-tabs-mode: t -*- + +/* + * Copyright (C) 2016 Canonical Ltd + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 3 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + * + */ + +package builtin + +import ( + "github.com/snapcore/snapd/interfaces" +) + +const openvswitchSupportConnectedPlugKmod = ` +openvswitch +` + +// NewOpenvSwitchSupportInterface returns a new "openvswitch-support" interface. +func NewOpenvSwitchSupportInterface() interfaces.Interface { + return &commonInterface{ + name: "openvswitch-support", + connectedPlugKMod: openvswitchSupportConnectedPlugKmod, + reservedForOS: true, + } +} diff --git a/interfaces/builtin/openvswitch_support_test.go b/interfaces/builtin/openvswitch_support_test.go new file mode 100644 index 0000000000..3d5f502455 --- /dev/null +++ b/interfaces/builtin/openvswitch_support_test.go @@ -0,0 +1,86 @@ +// -*- Mode: Go; indent-tabs-mode: t -*- + +/* + * Copyright (C) 2016 Canonical Ltd + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 3 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + * + */ + +package builtin_test + +import ( + . "gopkg.in/check.v1" + + "github.com/snapcore/snapd/interfaces" + "github.com/snapcore/snapd/interfaces/builtin" + "github.com/snapcore/snapd/snap" +) + +type OpenvSwitchSupportInterfaceSuite struct { + iface interfaces.Interface + slot *interfaces.Slot + plug *interfaces.Plug +} + +var _ = Suite(&OpenvSwitchSupportInterfaceSuite{ + iface: builtin.NewOpenvSwitchSupportInterface(), + slot: &interfaces.Slot{ + SlotInfo: &snap.SlotInfo{ + Snap: &snap.Info{SuggestedName: "core", Type: snap.TypeOS}, + Name: "openvswitch-support", + Interface: "openvswitch-support", + }, + }, + plug: &interfaces.Plug{ + PlugInfo: &snap.PlugInfo{ + Snap: &snap.Info{SuggestedName: "other"}, + Name: "openvswitch-support", + Interface: "openvswitch-support", + }, + }, +}) + +func (s *OpenvSwitchSupportInterfaceSuite) TestName(c *C) { + c.Assert(s.iface.Name(), Equals, "openvswitch-support") +} + +func (s *OpenvSwitchSupportInterfaceSuite) TestSanitizeSlot(c *C) { + err := s.iface.SanitizeSlot(s.slot) + c.Assert(err, IsNil) + err = s.iface.SanitizeSlot(&interfaces.Slot{SlotInfo: &snap.SlotInfo{ + Snap: &snap.Info{SuggestedName: "some-snap"}, + Name: "openvswitch-support", + Interface: "openvswitch-support", + }}) + c.Assert(err, ErrorMatches, "openvswitch-support slots are reserved for the operating system snap") +} + +func (s *OpenvSwitchSupportInterfaceSuite) TestSanitizePlug(c *C) { + err := s.iface.SanitizePlug(s.plug) + c.Assert(err, IsNil) +} + +func (s *OpenvSwitchSupportInterfaceSuite) TestSanitizeIncorrectInterface(c *C) { + c.Assert(func() { s.iface.SanitizeSlot(&interfaces.Slot{SlotInfo: &snap.SlotInfo{Interface: "other"}}) }, + PanicMatches, `slot is not of interface "openvswitch-support"`) + c.Assert(func() { s.iface.SanitizePlug(&interfaces.Plug{PlugInfo: &snap.PlugInfo{Interface: "other"}}) }, + PanicMatches, `plug is not of interface "openvswitch-support"`) +} + +func (s *OpenvSwitchSupportInterfaceSuite) TestUsedSecuritySystems(c *C) { + // connected plugs have a non-nil security snippet for kmod + snippet, err := s.iface.ConnectedPlugSnippet(s.plug, s.slot, interfaces.SecurityKMod) + c.Assert(err, IsNil) + c.Assert(snippet, Not(IsNil)) +} diff --git a/interfaces/builtin/openvswitch_test.go b/interfaces/builtin/openvswitch_test.go new file mode 100644 index 0000000000..18ae434731 --- /dev/null +++ b/interfaces/builtin/openvswitch_test.go @@ -0,0 +1,90 @@ +// -*- Mode: Go; indent-tabs-mode: t -*- + +/* + * Copyright (C) 2016 Canonical Ltd + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 3 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + * + */ + +package builtin_test + +import ( + . "gopkg.in/check.v1" + + "github.com/snapcore/snapd/interfaces" + "github.com/snapcore/snapd/interfaces/builtin" + "github.com/snapcore/snapd/snap" +) + +type OpenvSwitchInterfaceSuite struct { + iface interfaces.Interface + slot *interfaces.Slot + plug *interfaces.Plug +} + +var _ = Suite(&OpenvSwitchInterfaceSuite{ + iface: builtin.NewOpenvSwitchInterface(), + slot: &interfaces.Slot{ + SlotInfo: &snap.SlotInfo{ + Snap: &snap.Info{SuggestedName: "core", Type: snap.TypeOS}, + Name: "openvswitch", + Interface: "openvswitch", + }, + }, + plug: &interfaces.Plug{ + PlugInfo: &snap.PlugInfo{ + Snap: &snap.Info{SuggestedName: "other"}, + Name: "openvswitch", + Interface: "openvswitch", + }, + }, +}) + +func (s *OpenvSwitchInterfaceSuite) TestName(c *C) { + c.Assert(s.iface.Name(), Equals, "openvswitch") +} + +func (s *OpenvSwitchInterfaceSuite) TestSanitizeSlot(c *C) { + err := s.iface.SanitizeSlot(s.slot) + c.Assert(err, IsNil) + err = s.iface.SanitizeSlot(&interfaces.Slot{SlotInfo: &snap.SlotInfo{ + Snap: &snap.Info{SuggestedName: "some-snap"}, + Name: "openvswitch", + Interface: "openvswitch", + }}) + c.Assert(err, ErrorMatches, "openvswitch slots are reserved for the operating system snap") +} + +func (s *OpenvSwitchInterfaceSuite) TestSanitizePlug(c *C) { + err := s.iface.SanitizePlug(s.plug) + c.Assert(err, IsNil) +} + +func (s *OpenvSwitchInterfaceSuite) TestSanitizeIncorrectInterface(c *C) { + c.Assert(func() { s.iface.SanitizeSlot(&interfaces.Slot{SlotInfo: &snap.SlotInfo{Interface: "other"}}) }, + PanicMatches, `slot is not of interface "openvswitch"`) + c.Assert(func() { s.iface.SanitizePlug(&interfaces.Plug{PlugInfo: &snap.PlugInfo{Interface: "other"}}) }, + PanicMatches, `plug is not of interface "openvswitch"`) +} + +func (s *OpenvSwitchInterfaceSuite) TestUsedSecuritySystems(c *C) { + // connected plugs have a non-nil security snippet for apparmor + snippet, err := s.iface.ConnectedPlugSnippet(s.plug, s.slot, interfaces.SecurityAppArmor) + c.Assert(err, IsNil) + c.Assert(snippet, Not(IsNil)) + // connected plugs have a non-nil security snippet for seccomp + snippet, err = s.iface.ConnectedPlugSnippet(s.plug, s.slot, interfaces.SecuritySecComp) + c.Assert(err, IsNil) + c.Assert(snippet, Not(IsNil)) +} diff --git a/interfaces/builtin/process_control.go b/interfaces/builtin/process_control.go index 265cbac191..8e1e3e5d30 100644 --- a/interfaces/builtin/process_control.go +++ b/interfaces/builtin/process_control.go @@ -29,6 +29,9 @@ const processControlConnectedPlugAppArmor = ` # all processes under root or processes running under the same UID otherwise. # Usage: reserved +/{,usr/}bin/nice ixr, + +capability sys_resource, capability sys_nice, signal, diff --git a/interfaces/systemd/backend.go b/interfaces/systemd/backend.go index 3d0f33c783..a202b671a9 100644 --- a/interfaces/systemd/backend.go +++ b/interfaces/systemd/backend.go @@ -55,9 +55,12 @@ func disableRemovedServices(systemd sysd.Systemd, dir, glob string, content map[ for _, path := range paths { service := filepath.Base(path) if content[service] == nil { - if err := systemd.DisableNow(service); err != nil { + if err := systemd.Disable(service); err != nil { logger.Noticef("cannot disable service %q: %s", service, err) } + if err := systemd.Stop(service, 5*time.Second); err != nil { + logger.Noticef("cannot stop service %q: %s", service, err) + } } } return nil @@ -122,9 +125,12 @@ func (b *Backend) Remove(snapName string) error { glob := interfaces.InterfaceServiceName(snapName, "*") _, removed, errEnsure := osutil.EnsureDirState(dirs.SnapServicesDir, glob, nil) for _, service := range removed { - if err := systemd.DisableNow(service); err != nil { + if err := systemd.Disable(service); err != nil { logger.Noticef("cannot disable service %q: %s", service, err) } + if err := systemd.Stop(service, 5*time.Second); err != nil { + logger.Noticef("cannot stop service %q: %s", service, err) + } } // Reload systemd whenever something is removed if len(removed) > 0 { diff --git a/interfaces/systemd/backend_test.go b/interfaces/systemd/backend_test.go index a28b1cfeb5..21805c28c2 100644 --- a/interfaces/systemd/backend_test.go +++ b/interfaces/systemd/backend_test.go @@ -52,7 +52,7 @@ var testedConfinementOpts = []interfaces.ConfinementOptions{ func (s *backendSuite) SetUpTest(c *C) { s.BackendSuite.SetUpTest(c) s.Backend = &systemd.Backend{} - s.systemctlCmd = testutil.MockCommand(c, "systemctl", "") + s.systemctlCmd = testutil.MockCommand(c, "systemctl", "echo ActiveState=inactive") } func (s *backendSuite) TearDownTest(c *C) { @@ -196,14 +196,12 @@ func (s *backendSuite) TestRemovingSnapRemovesAndStopsServices(c *C) { _, err := os.Stat(service) c.Check(os.IsNotExist(err), Equals, true) // the service was stopped - calls := s.systemctlCmd.Calls() - c.Check(calls[0], DeepEquals, []string{"systemctl", "--root", dirs.GlobalRootDir, "--now", "disable", "snap.samba.interface.foo.service"}) - for i, call := range calls { - if i > 0 && i < len(calls)-1 { - c.Check(call, DeepEquals, []string{"systemctl", "show", "--property=ActiveState", "snap.samba.interface.foo.service"}) - } - } - c.Check(calls[len(calls)-1], DeepEquals, []string{"systemctl", "daemon-reload"}) + c.Check(s.systemctlCmd.Calls(), DeepEquals, [][]string{ + {"systemctl", "--root", dirs.GlobalRootDir, "disable", "snap.samba.interface.foo.service"}, + {"systemctl", "stop", "snap.samba.interface.foo.service"}, + {"systemctl", "show", "--property=ActiveState", "snap.samba.interface.foo.service"}, + {"systemctl", "daemon-reload"}, + }) } } @@ -228,12 +226,10 @@ func (s *backendSuite) TestSettingUpSecurityWithFewerServices(c *C) { // Update over to the same snap to regenerate security s.UpdateSnap(c, snapInfo, interfaces.ConfinementOptions{}, backendtest.SambaYamlV1, 0) // The bar service should have been stopped - calls := s.systemctlCmd.Calls() - c.Check(calls[0], DeepEquals, []string{"systemctl", "--root", dirs.GlobalRootDir, "--now", "disable", "snap.samba.interface.bar.service"}) - c.Check(calls[1], DeepEquals, []string{"systemctl", "daemon-reload"}) - for i, call := range calls { - if i > 1 { - c.Check(call, DeepEquals, []string{"systemctl", "show", "--property=ActiveState", "snap.samba.interface.bar.service"}) - } - } + c.Check(s.systemctlCmd.Calls(), DeepEquals, [][]string{ + {"systemctl", "--root", dirs.GlobalRootDir, "disable", "snap.samba.interface.bar.service"}, + {"systemctl", "stop", "snap.samba.interface.bar.service"}, + {"systemctl", "show", "--property=ActiveState", "snap.samba.interface.bar.service"}, + {"systemctl", "daemon-reload"}, + }) } diff --git a/overlord/managers_test.go b/overlord/managers_test.go index e2cd5403d4..2ed329af29 100644 --- a/overlord/managers_test.go +++ b/overlord/managers_test.go @@ -1032,6 +1032,74 @@ apps: c.Check(allAliases, HasLen, 0) } +func (ms *mgrsSuite) TestHappyUnalias(c *C) { + st := ms.o.State() + st.Lock() + defer st.Unlock() + + fooYaml := `name: foo +version: 1.0 +apps: + foo: + command: bin/foo + aliases: [foo_] +` + ms.installLocalTestSnap(c, fooYaml) + + ts, err := snapstate.Alias(st, "foo", []string{"foo_"}) + c.Assert(err, IsNil) + chg := st.NewChange("alias", "...") + chg.AddAll(ts) + + st.Unlock() + err = ms.o.Settle() + st.Lock() + c.Assert(err, IsNil) + + c.Assert(chg.Err(), IsNil) + c.Assert(chg.Status(), Equals, state.DoneStatus, Commentf("alias change failed with: %v", chg.Err())) + + foo_Alias := filepath.Join(dirs.SnapBinariesDir, "foo_") + dest, err := os.Readlink(foo_Alias) + c.Assert(err, IsNil) + + c.Check(dest, Equals, "foo") + + var allAliases map[string]map[string]string + err = st.Get("aliases", &allAliases) + c.Assert(err, IsNil) + c.Check(allAliases, DeepEquals, map[string]map[string]string{ + "foo": { + "foo_": "enabled", + }, + }) + + ts, err = snapstate.Unalias(st, "foo", []string{"foo_"}) + c.Assert(err, IsNil) + chg = st.NewChange("unalias", "...") + chg.AddAll(ts) + + st.Unlock() + err = ms.o.Settle() + st.Lock() + c.Assert(err, IsNil) + + c.Assert(chg.Err(), IsNil) + c.Assert(chg.Status(), Equals, state.DoneStatus, Commentf("unalias change failed with: %v", chg.Err())) + + c.Check(osutil.IsSymlink(foo_Alias), Equals, false) + + allAliases = nil + + err = st.Get("aliases", &allAliases) + c.Assert(err, IsNil) + c.Check(allAliases, DeepEquals, map[string]map[string]string{ + "foo": { + "foo_": "disabled", + }, + }) +} + type authContextSetupSuite struct { o *overlord.Overlord ac auth.AuthContext diff --git a/overlord/snapstate/aliases.go b/overlord/snapstate/aliases.go index 94ac54de33..4782e652ef 100644 --- a/overlord/snapstate/aliases.go +++ b/overlord/snapstate/aliases.go @@ -105,6 +105,38 @@ func Alias(st *state.State, snapName string, aliases []string) (*state.TaskSet, return state.NewTaskSet(alias), nil } +// Unalias explicitly disables the provided aliases for the snap with the given name. +func Unalias(st *state.State, snapName string, aliases []string) (*state.TaskSet, error) { + var snapst SnapState + err := Get(st, snapName, &snapst) + if err == state.ErrNoState { + return nil, fmt.Errorf("cannot find snap %q", snapName) + } + if err != nil { + return nil, err + } + if !snapst.Active { + return nil, fmt.Errorf("disabling aliases for disabled snap %q not supported", snapName) + } + if err := checkChangeConflict(st, snapName, nil); err != nil { + return nil, err + } + + snapsup := &SnapSetup{ + SideInfo: &snap.SideInfo{RealName: snapName}, + } + + alias := st.NewTask("alias", fmt.Sprintf(i18n.G("Disable aliases for snap %q"), snapsup.Name())) + alias.Set("snap-setup", &snapsup) + toDisable := map[string]string{} + for _, alias := range aliases { + toDisable[alias] = "disabled" + } + alias.Set("aliases", toDisable) + + return state.NewTaskSet(alias), nil +} + func (m *SnapManager) doAlias(t *state.Task, _ *tomb.Tomb) error { st := t.State() st.Lock() @@ -113,8 +145,8 @@ func (m *SnapManager) doAlias(t *state.Task, _ *tomb.Tomb) error { if err != nil { return err } - var toEnable map[string]string - err = t.Get("aliases", &toEnable) + var changes map[string]string + err = t.Get("aliases", &changes) if err != nil { return err } @@ -132,27 +164,43 @@ func (m *SnapManager) doAlias(t *state.Task, _ *tomb.Tomb) error { aliasStatuses = make(map[string]string) } var add []*backend.Alias - for alias := range toEnable { + var remove []*backend.Alias + for alias, newStatus := range changes { aliasApp := curInfo.Aliases[alias] if aliasApp == nil { - return fmt.Errorf("cannot enable alias %q for %q, no such alias", alias, snapName) + var action string + switch newStatus { + case "enabled": + action = "enable" + case "disabled": + action = "disable" + } + return fmt.Errorf("cannot %s alias %q for %q, no such alias", action, alias, snapName) } - if aliasStatuses[alias] == "enabled" { + if aliasStatuses[alias] == newStatus { // nothing to do continue } - err := checkAliasConflict(st, snapName, alias) - if err != nil { - return err - } - aliasStatuses[alias] = "enabled" - add = append(add, &backend.Alias{ + beAlias := &backend.Alias{ Name: alias, Target: filepath.Base(aliasApp.WrapperPath()), - }) + } + switch newStatus { + case "enabled": + err := checkAliasConflict(st, snapName, alias) + if err != nil { + return err + } + add = append(add, beAlias) + case "disabled": + if aliasStatuses[alias] != "" { + remove = append(remove, beAlias) + } + } + aliasStatuses[alias] = newStatus } st.Unlock() - err = m.backend.UpdateAliases(add, nil) + err = m.backend.UpdateAliases(add, remove) st.Lock() if err != nil { return err @@ -174,8 +222,8 @@ func (m *SnapManager) undoAlias(t *state.Task, _ *tomb.Tomb) error { if err != nil { return err } - var toEnable map[string]string - err = t.Get("aliases", &toEnable) + var changes map[string]string + err = t.Get("aliases", &changes) if err != nil { return err } @@ -184,21 +232,41 @@ func (m *SnapManager) undoAlias(t *state.Task, _ *tomb.Tomb) error { if err != nil { return err } + var add []*backend.Alias var remove []*backend.Alias - for alias := range toEnable { - if oldStatuses[alias] == "enabled" { +Next: + for alias, newStatus := range changes { + if oldStatuses[alias] == newStatus { // nothing to undo continue } aliasApp := curInfo.Aliases[alias] if aliasApp == nil { // unexpected - return fmt.Errorf("internal error: cannot re-disable alias %q for %q, no such alias", alias, snapName) + return fmt.Errorf("internal error: cannot re-toggle alias %q for %q, no such alias", alias, snapName) } - remove = append(remove, &backend.Alias{ + beAlias := &backend.Alias{ Name: alias, Target: filepath.Base(aliasApp.WrapperPath()), - }) + } + switch newStatus { + case "enabled": + remove = append(remove, beAlias) + case "disabled": + if oldStatuses[alias] != "" { + // can actually be reinstated only if it doesn't conflict + err := checkAliasConflict(st, snapName, alias) + if err != nil { + if _, ok := err.(*aliasConflictError); ok { + delete(oldStatuses, alias) + t.Errorf("%v", err) + continue Next + } + return err + } + add = append(add, beAlias) + } + } } st.Unlock() remove, err = m.backend.MatchingAliases(remove) @@ -207,7 +275,13 @@ func (m *SnapManager) undoAlias(t *state.Task, _ *tomb.Tomb) error { return fmt.Errorf("cannot list aliases for snap %q: %v", snapName, err) } st.Unlock() - err = m.backend.UpdateAliases(nil, remove) + add, err = m.backend.MissingAliases(add) + st.Lock() + if err != nil { + return fmt.Errorf("cannot list aliases for snap %q: %v", snapName, err) + } + st.Unlock() + err = m.backend.UpdateAliases(add, remove) st.Lock() if err != nil { return err diff --git a/overlord/snapstate/aliases_test.go b/overlord/snapstate/aliases_test.go index e96e578926..42fbc66bca 100644 --- a/overlord/snapstate/aliases_test.go +++ b/overlord/snapstate/aliases_test.go @@ -211,7 +211,7 @@ func (s *snapmgrTestSuite) TestUpdateAliasChangeConflict(c *C) { c.Assert(err, ErrorMatches, `snap "some-snap" has changes in progress`) } -func (s *snapmgrTestSuite) TestAliasUpdateChangeConflict(c *C) { +func (s *snapmgrTestSuite) TestUpdateUnaliasChangeConflict(c *C) { s.state.Lock() defer s.state.Unlock() @@ -222,76 +222,33 @@ func (s *snapmgrTestSuite) TestAliasUpdateChangeConflict(c *C) { SnapType: "app", }) - ts, err := snapstate.Alias(s.state, "some-snap", []string{"alias1"}) + ts, err := snapstate.Update(s.state, "some-snap", "some-channel", snap.R(0), s.user.ID, snapstate.Flags{}) c.Assert(err, IsNil) // need a change to make the tasks visible - s.state.NewChange("alias", "...").AddAll(ts) + s.state.NewChange("update", "...").AddAll(ts) - _, err = snapstate.Update(s.state, "some-snap", "some-channel", snap.R(0), s.user.ID, snapstate.Flags{}) + _, err = snapstate.Unalias(s.state, "some-snap", []string{"alias1"}) c.Assert(err, ErrorMatches, `snap "some-snap" has changes in progress`) } -func (s *snapmgrTestSuite) TestAliasTotalUndoRunthrough(c *C) { +func (s *snapmgrTestSuite) TestAliasUpdateChangeConflict(c *C) { s.state.Lock() defer s.state.Unlock() - snapstate.Set(s.state, "alias-snap", &snapstate.SnapState{ - Sequence: []*snap.SideInfo{ - {RealName: "alias-snap", Revision: snap.R(11)}, - }, - Current: snap.R(11), - Active: true, - }) - s.state.Set("aliases", map[string]map[string]string{ - "other-snap": {"alias7": "enabled"}, + snapstate.Set(s.state, "some-snap", &snapstate.SnapState{ + Active: true, + Sequence: []*snap.SideInfo{{RealName: "some-snap", SnapID: "some-snap-id", Revision: snap.R(7)}}, + Current: snap.R(7), + SnapType: "app", }) - chg := s.state.NewChange("alias", "enable an alias") - ts, err := snapstate.Alias(s.state, "alias-snap", []string{"alias1"}) + ts, err := snapstate.Alias(s.state, "some-snap", []string{"alias1"}) c.Assert(err, IsNil) - chg.AddAll(ts) - - tasks := ts.Tasks() - last := tasks[len(tasks)-1] - - terr := s.state.NewTask("error-trigger", "provoking total undo") - terr.WaitFor(last) - chg.AddTask(terr) - - s.state.Unlock() - - for i := 0; i < 3; i++ { - s.snapmgr.Ensure() - s.snapmgr.Wait() - } - - s.state.Lock() - - c.Check(chg.Status(), Equals, state.ErrorStatus, Commentf("%v", chg.Err())) - expected := fakeOps{ - { - op: "update-aliases", - aliases: []*backend.Alias{{"alias1", "alias-snap.cmd1"}}, - }, - { - op: "matching-aliases", - aliases: []*backend.Alias{{"alias1", "alias-snap.cmd1"}}, - }, - { - op: "update-aliases", - rmAliases: []*backend.Alias{{"alias1", "alias-snap.cmd1"}}, - }, - } - // start with an easier-to-read error if this fails: - c.Assert(s.fakeBackend.ops.Ops(), DeepEquals, expected.Ops()) - c.Check(s.fakeBackend.ops, DeepEquals, expected) + // need a change to make the tasks visible + s.state.NewChange("alias", "...").AddAll(ts) - var allAliases map[string]map[string]string - err = s.state.Get("aliases", &allAliases) - c.Assert(err, IsNil) - c.Check(allAliases, DeepEquals, map[string]map[string]string{ - "other-snap": {"alias7": "enabled"}, - }) + _, err = snapstate.Update(s.state, "some-snap", "some-channel", snap.R(0), s.user.ID, snapstate.Flags{}) + c.Assert(err, ErrorMatches, `snap "some-snap" has changes in progress`) } func (s *snapmgrTestSuite) TestAliasNoAlias(c *C) { @@ -538,3 +495,306 @@ func (s *snapmgrTestSuite) TestDoUndoClearAliasesConflict(c *C) { c.Check(t.Log(), HasLen, 1) c.Check(t.Log()[0], Matches, `.* ERROR cannot enable alias "alias9" for "alias-snap", already enabled for "other-snap"`) } + +var statusesMatrix = []struct { + beforeStatus string + action string + status string + mutation string +}{ + {"", "alias", "enabled", "add"}, + {"enabled", "alias", "enabled", "-"}, + {"disabled", "alias", "enabled", "add"}, + {"", "unalias", "disabled", "-"}, + {"enabled", "unalias", "disabled", "rm"}, + {"disabled", "unalias", "disabled", "-"}, +} + +func (s *snapmgrTestSuite) TestAliasMatrixRunThrough(c *C) { + s.state.Lock() + defer s.state.Unlock() + + snapstate.Set(s.state, "alias-snap", &snapstate.SnapState{ + Sequence: []*snap.SideInfo{ + {RealName: "alias-snap", Revision: snap.R(11)}, + }, + Current: snap.R(11), + Active: true, + }) + + defer s.snapmgr.Stop() + for _, scenario := range statusesMatrix { + if scenario.beforeStatus != "" { + s.state.Set("aliases", map[string]map[string]string{ + "alias-snap": { + "alias1": scenario.beforeStatus, + }, + }) + } else { + s.state.Set("aliases", nil) + } + + chg := s.state.NewChange("scenario", "...") + var err error + var ts *state.TaskSet + switch scenario.action { + case "alias": + ts, err = snapstate.Alias(s.state, "alias-snap", []string{"alias1"}) + case "unalias": + ts, err = snapstate.Unalias(s.state, "alias-snap", []string{"alias1"}) + } + c.Assert(err, IsNil) + + chg.AddAll(ts) + + s.state.Unlock() + s.settle() + s.state.Lock() + + c.Assert(chg.Status(), Equals, state.DoneStatus, Commentf("%#v: %v", scenario, chg.Err())) + var aliases []*backend.Alias + var rmAliases []*backend.Alias + switch scenario.mutation { + case "-": + case "add": + aliases = []*backend.Alias{{"alias1", "alias-snap.cmd1"}} + case "rm": + rmAliases = []*backend.Alias{{"alias1", "alias-snap.cmd1"}} + } + + comm := Commentf("%#v", scenario) + expected := fakeOps{ + { + op: "update-aliases", + aliases: aliases, + rmAliases: rmAliases, + }, + } + // start with an easier-to-read error if this fails: + c.Assert(s.fakeBackend.ops.Ops(), DeepEquals, expected.Ops(), comm) + c.Assert(s.fakeBackend.ops, DeepEquals, expected, comm) + + var allAliases map[string]map[string]string + err = s.state.Get("aliases", &allAliases) + c.Assert(err, IsNil) + if scenario.status != "" { + c.Check(allAliases, DeepEquals, map[string]map[string]string{ + "alias-snap": {"alias1": scenario.status}, + }, comm) + } else { + c.Check(allAliases, HasLen, 0, Commentf("%#v", scenario), comm) + } + + s.fakeBackend.ops = nil + } +} + +func (s *snapmgrTestSuite) TestAliasMatrixTotalUndoRunThrough(c *C) { + s.state.Lock() + defer s.state.Unlock() + + snapstate.Set(s.state, "alias-snap", &snapstate.SnapState{ + Sequence: []*snap.SideInfo{ + {RealName: "alias-snap", Revision: snap.R(11)}, + }, + Current: snap.R(11), + Active: true, + }) + + defer s.snapmgr.Stop() + for _, scenario := range statusesMatrix { + if scenario.beforeStatus != "" { + s.state.Set("aliases", map[string]map[string]string{ + "alias-snap": { + "alias1": scenario.beforeStatus, + }, + }) + } else { + s.state.Set("aliases", nil) + } + + chg := s.state.NewChange("scenario", "...") + var err error + var ts *state.TaskSet + switch scenario.action { + case "alias": + ts, err = snapstate.Alias(s.state, "alias-snap", []string{"alias1"}) + case "unalias": + ts, err = snapstate.Unalias(s.state, "alias-snap", []string{"alias1"}) + } + c.Assert(err, IsNil) + + chg.AddAll(ts) + + tasks := ts.Tasks() + last := tasks[len(tasks)-1] + + terr := s.state.NewTask("error-trigger", "provoking total undo") + terr.WaitFor(last) + chg.AddTask(terr) + + s.state.Unlock() + for i := 0; i < 3; i++ { + s.snapmgr.Ensure() + s.snapmgr.Wait() + } + s.state.Lock() + + c.Assert(chg.Status(), Equals, state.ErrorStatus, Commentf("%#v: %v", scenario, chg.Err())) + var aliases []*backend.Alias + var rmAliases []*backend.Alias + switch scenario.mutation { + case "-": + case "add": + aliases = []*backend.Alias{{"alias1", "alias-snap.cmd1"}} + case "rm": + rmAliases = []*backend.Alias{{"alias1", "alias-snap.cmd1"}} + } + + comm := Commentf("%#v", scenario) + expected := fakeOps{ + { + op: "update-aliases", + aliases: aliases, + rmAliases: rmAliases, + }, + { + op: "matching-aliases", + aliases: aliases, + }, + { + op: "missing-aliases", + aliases: rmAliases, + }, + { + op: "update-aliases", + aliases: rmAliases, + rmAliases: aliases, + }, + } + // start with an easier-to-read error if this fails: + c.Assert(s.fakeBackend.ops.Ops(), DeepEquals, expected.Ops(), comm) + c.Assert(s.fakeBackend.ops, DeepEquals, expected, comm) + + var allAliases map[string]map[string]string + err = s.state.Get("aliases", &allAliases) + c.Assert(err, IsNil) + if scenario.beforeStatus != "" { + c.Check(allAliases, DeepEquals, map[string]map[string]string{ + "alias-snap": {"alias1": scenario.beforeStatus}, + }, comm) + } else { + c.Check(allAliases, HasLen, 0, comm) + } + + s.fakeBackend.ops = nil + } +} + +func (s *snapmgrTestSuite) TestUnliasTotalUndoRunThroughAliasConflict(c *C) { + s.state.Lock() + defer s.state.Unlock() + + snapstate.Set(s.state, "alias-snap", &snapstate.SnapState{ + Sequence: []*snap.SideInfo{ + {RealName: "alias-snap", Revision: snap.R(11)}, + }, + Current: snap.R(11), + Active: true, + }) + + defer s.snapmgr.Stop() + s.state.Set("aliases", map[string]map[string]string{ + "alias-snap": { + "alias1": "enabled", + }, + }) + + chg := s.state.NewChange("scenario", "...") + ts, err := snapstate.Unalias(s.state, "alias-snap", []string{"alias1"}) + c.Assert(err, IsNil) + + chg.AddAll(ts) + + tasks := ts.Tasks() + last := tasks[len(tasks)-1] + + grabAlias1 := func(t *state.Task, _ *tomb.Tomb) error { + st := t.State() + st.Lock() + defer st.Unlock() + + var allAliases map[string]map[string]string + err := st.Get("aliases", &allAliases) + c.Assert(err, IsNil) + c.Assert(allAliases, DeepEquals, map[string]map[string]string{ + "alias-snap": { + "alias1": "disabled", + }, + }) + + st.Set("aliases", map[string]map[string]string{ + "alias-snap": { + "alias1": "disabled", + }, + "other-snap": { + "alias1": "enabled", + }, + }) + return nil + } + + s.snapmgr.AddAdhocTaskHandler("grab-alias1", grabAlias1, nil) + + tgrab1 := s.state.NewTask("grab-alias1", "grab alias1 for other-snap") + tgrab1.WaitFor(last) + chg.AddTask(tgrab1) + + terr := s.state.NewTask("error-trigger", "provoking total undo") + terr.WaitFor(tgrab1) + chg.AddTask(terr) + + s.state.Unlock() + + for i := 0; i < 5; i++ { + s.snapmgr.Ensure() + s.snapmgr.Wait() + } + + s.state.Lock() + + c.Assert(chg.Status(), Equals, state.ErrorStatus, Commentf("%v", chg.Err())) + rmAliases := []*backend.Alias{{"alias1", "alias-snap.cmd1"}} + + expected := fakeOps{ + { + op: "update-aliases", + rmAliases: rmAliases, + }, + { + op: "matching-aliases", + }, + { + op: "missing-aliases", + }, + { + op: "update-aliases", + }, + } + // start with an easier-to-read error if this fails: + c.Assert(s.fakeBackend.ops.Ops(), DeepEquals, expected.Ops()) + c.Assert(s.fakeBackend.ops, DeepEquals, expected) + + var allAliases map[string]map[string]string + err = s.state.Get("aliases", &allAliases) + c.Assert(err, IsNil) + c.Check(allAliases, DeepEquals, map[string]map[string]string{ + "other-snap": { + "alias1": "enabled", + }, + }) + + c.Check(last.Log(), HasLen, 1) + c.Check(last.Log()[0], Matches, `.* ERROR cannot enable alias "alias1" for "alias-snap", already enabled for "other-snap"`) + +} diff --git a/snap/implicit.go b/snap/implicit.go index af9e87da67..b24bbd1b90 100644 --- a/snap/implicit.go +++ b/snap/implicit.go @@ -48,6 +48,7 @@ var implicitSlots = []string{ "network-observe", "network-setup-observe", "opengl", + "openvswitch-support", "ppp", "process-control", "raw-usb", @@ -71,6 +72,7 @@ var implicitClassicSlots = []string{ "modem-manager", "network-manager", "ofono", + "openvswitch", "optical-drive", "pulseaudio", "screen-inhibit-control", diff --git a/systemd/systemd.go b/systemd/systemd.go index 309ccc5bb2..366d40569a 100644 --- a/systemd/systemd.go +++ b/systemd/systemd.go @@ -86,9 +86,7 @@ var JournalctlCmd = jctl type Systemd interface { DaemonReload() error Enable(service string) error - EnableNow(service string) error Disable(service string) error - DisableNow(service string) error Start(service string) error Stop(service string, timeout time.Duration) error Kill(service, signal string) error @@ -186,24 +184,12 @@ func (s *systemd) Enable(serviceName string) error { return err } -// Enable the given service and start it -func (s *systemd) EnableNow(serviceName string) error { - _, err := SystemctlCmd("--root", s.rootDir, "--now", "enable", serviceName) - return err -} - // Disable the given service func (s *systemd) Disable(serviceName string) error { _, err := SystemctlCmd("--root", s.rootDir, "disable", serviceName) return err } -// Disable the given service and stop it -func (s *systemd) DisableNow(serviceName string) error { - _, err := SystemctlCmd("--root", s.rootDir, "--now", "disable", serviceName) - return err -} - // Start the given service func (*systemd) Start(serviceName string) error { _, err := SystemctlCmd("start", serviceName) diff --git a/systemd/systemd_test.go b/systemd/systemd_test.go index 88713cdc27..30643fd630 100644 --- a/systemd/systemd_test.go +++ b/systemd/systemd_test.go @@ -191,24 +191,12 @@ func (s *SystemdTestSuite) TestDisable(c *C) { c.Check(s.argses, DeepEquals, [][]string{{"--root", "xyzzy", "disable", "foo"}}) } -func (s *SystemdTestSuite) TestDisableNow(c *C) { - err := New("xyzzy", s.rep).DisableNow("foo") - c.Assert(err, IsNil) - c.Check(s.argses, DeepEquals, [][]string{{"--root", "xyzzy", "--now", "disable", "foo"}}) -} - func (s *SystemdTestSuite) TestEnable(c *C) { err := New("xyzzy", s.rep).Enable("foo") c.Assert(err, IsNil) c.Check(s.argses, DeepEquals, [][]string{{"--root", "xyzzy", "enable", "foo"}}) } -func (s *SystemdTestSuite) TestEnableNow(c *C) { - err := New("xyzzy", s.rep).EnableNow("foo") - c.Assert(err, IsNil) - c.Check(s.argses, DeepEquals, [][]string{{"--root", "xyzzy", "--now", "enable", "foo"}}) -} - func (s *SystemdTestSuite) TestRestart(c *C) { restore := MockStopDelays(time.Millisecond, 25*time.Second) defer restore() diff --git a/tests/lib/prepare.sh b/tests/lib/prepare.sh index b2bd69dec2..631c1a8c20 100755 --- a/tests/lib/prepare.sh +++ b/tests/lib/prepare.sh @@ -138,6 +138,7 @@ setup_reflash_magic() { # the image # unpack our freshly build snapd into the new core snap dpkg-deb -x ${SPREAD_PATH}/../snapd_*.deb $UNPACKD + dpkg-deb -x ${SPREAD_PATH}/../snap-confine_*.deb $UNPACKD # add a gpio slot cat >> $UNPACKD/meta/snap.yaml <<-EOF |
