interfaces: add new interface API #2613

Merged
merged 23 commits into from Jan 16, 2017
Commits
Jump to file or symbol
Failed to load files and symbols.
+396 −24
Split
@@ -55,8 +55,8 @@ import (
type Backend struct{}
// Name returns the name of the backend.
-func (b *Backend) Name() string {
- return "apparmor"
+func (b *Backend) Name() interfaces.SecuritySystem {
+ return interfaces.SecurityAppArmor
}
// Setup creates and loads apparmor profiles specific to a given snap.
@@ -205,3 +205,7 @@ func unloadProfiles(profiles []string) error {
}
return nil
}
+
+func (b *Backend) NewSpecification() interfaces.Specification {
+ panic(fmt.Errorf("%s is not using specifications yet", b.Name()))
@chipaca

chipaca Jan 16, 2017

Member

logger.Panicf(...) would probably be better

@zyga

zyga Jan 16, 2017

Contributor

I was about to fix it but I'll propose a change that actually implements this correctly next so I won't bother.

+}
@@ -105,7 +105,7 @@ func (s *backendSuite) TearDownTest(c *C) {
// Tests for Setup() and Remove()
func (s *backendSuite) TestName(c *C) {
- c.Check(s.Backend.Name(), Equals, "apparmor")
+ c.Check(s.Backend.Name(), Equals, interfaces.SecurityAppArmor)
}
func (s *backendSuite) TestInstallingSnapWritesAndLoadsProfiles(c *C) {
View
@@ -69,7 +69,7 @@ type ConfinementOptions struct {
type SecurityBackend interface {
// Name returns the name of the backend.
// This is intended for diagnostic messages.
- Name() string
+ Name() SecuritySystem
// Setup creates and loads security artefacts specific to a given snap.
// The snap can be in one of three kids onf confinement (strict mode,
@@ -84,4 +84,7 @@ type SecurityBackend interface {
//
// This method should be called during the process of removing a snap.
Remove(snapName string) error
+
+ // NewSpecification returns a new specification associated with this backend.
+ NewSpecification() Specification
}
View
@@ -157,6 +157,18 @@ type Interface interface {
AutoConnect(plug *Plug, slot *Slot) bool
}
+// Specification describes interactions between backends and interfaces.
+type Specification interface {
+ // AddPermanentSlot records side-effects of having a slot.
+ AddPermanentSlot(iface Interface, slot *Slot) error
+ // AddPermanentPlug records side-effects of having a plug.
+ AddPermanentPlug(iface Interface, plug *Plug) error
+ // AddConnectedSlot records side-effects of having a connected slot.
+ AddConnectedSlot(iface Interface, plug *Plug, slot *Slot) error
+ // AddConnectedPlug records side-effects of having a connected plug.
+ AddConnectedPlug(iface Interface, plug *Plug, slot *Slot) error
+}
+
// SecuritySystem is a name of a security system.
type SecuritySystem string
@@ -42,7 +42,7 @@ import (
type Backend struct{}
// Name returns the name of the backend.
-func (b *Backend) Name() string {
+func (b *Backend) Name() interfaces.SecuritySystem {
return "dbus"
}
@@ -131,3 +131,7 @@ func addContent(securityTag string, executableSnippets [][]byte, content map[str
Mode: 0644,
}
}
+
+func (b *Backend) NewSpecification() interfaces.Specification {
+ panic(fmt.Errorf("%s is not using specifications yet", b.Name()))
+}
@@ -61,7 +61,7 @@ func (s *backendSuite) TearDownTest(c *C) {
// Tests for Setup() and Remove()
func (s *backendSuite) TestName(c *C) {
- c.Check(s.Backend.Name(), Equals, "dbus")
+ c.Check(s.Backend.Name(), Equals, interfaces.SecurityDBus)
}
func (s *backendSuite) TestInstallingSnapWritesConfigFiles(c *C) {
@@ -45,7 +45,7 @@ type TestSetupCall struct {
}
// Name returns the name of the security backend.
-func (b *TestSecurityBackend) Name() string {
+func (b *TestSecurityBackend) Name() interfaces.SecuritySystem {
return "test"
}
@@ -66,3 +66,7 @@ func (b *TestSecurityBackend) Remove(snapName string) error {
}
return b.RemoveCallback(snapName)
}
+
+func (b *TestSecurityBackend) NewSpecification() interfaces.Specification {
+ return &Specification{}
+}
@@ -0,0 +1,80 @@
+// -*- Mode: Go; indent-tabs-mode: t -*-
+
+/*
+ * Copyright (C) 2017 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 ifacetest
+
+import (
+ "github.com/snapcore/snapd/interfaces"
+)
+
+// Specification is a specification intended for testing.
+type Specification struct {
+ Snippets []string
+}
+
+// AddSnippet appends a snippet to a list stored in the specification.
+func (spec *Specification) AddSnippet(snippet string) {
+ spec.Snippets = append(spec.Snippets, snippet)
+}
+
+// Implementation of methods required by interfaces.Specification
+
+// AddConnectedPlug records test side-effects of having a connected plug.
+func (spec *Specification) AddConnectedPlug(iface interfaces.Interface, plug *interfaces.Plug, slot *interfaces.Slot) error {
+ type definer interface {
+ TestConnectedPlug(spec *Specification, plug *interfaces.Plug, slot *interfaces.Slot) error
+ }
+ if iface, ok := iface.(definer); ok {
+ return iface.TestConnectedPlug(spec, plug, slot)
+ }
+ return nil
+}
+
+// AddConnectedSlot records test side-effects of having a connected slot.
+func (spec *Specification) AddConnectedSlot(iface interfaces.Interface, plug *interfaces.Plug, slot *interfaces.Slot) error {
+ type definer interface {
+ TestConnectedSlot(spec *Specification, plug *interfaces.Plug, slot *interfaces.Slot) error
+ }
+ if iface, ok := iface.(definer); ok {
+ return iface.TestConnectedSlot(spec, plug, slot)
+ }
+ return nil
+}
+
+// AddPermanentPlug records test side-effects of having a plug.
+func (spec *Specification) AddPermanentPlug(iface interfaces.Interface, plug *interfaces.Plug) error {
+ type definer interface {
+ TestPermanentPlug(spec *Specification, plug *interfaces.Plug) error
+ }
+ if iface, ok := iface.(definer); ok {
+ return iface.TestPermanentPlug(spec, plug)
+ }
+ return nil
+}
+
+// AddPermanentSlot records test side-effects of having a slot.
+func (spec *Specification) AddPermanentSlot(iface interfaces.Interface, slot *interfaces.Slot) error {
+ type definer interface {
+ TestPermanentSlot(spec *Specification, slot *interfaces.Slot) error
+ }
+ if iface, ok := iface.(definer); ok {
+ return iface.TestPermanentSlot(spec, slot)
+ }
+ return nil
+}
@@ -0,0 +1,93 @@
+// -*- Mode: Go; indent-tabs-mode: t -*-
+
+/*
+ * Copyright (C) 2015-2017 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 ifacetest_test
+
+import (
+ . "gopkg.in/check.v1"
+
+ "github.com/snapcore/snapd/interfaces"
+ "github.com/snapcore/snapd/interfaces/ifacetest"
+ "github.com/snapcore/snapd/snap"
+)
+
+type SpecificationSuite struct {
+ iface *ifacetest.TestInterface
+ spec *ifacetest.Specification
+ plug *interfaces.Plug
+ slot *interfaces.Slot
+}
+
+var _ = Suite(&SpecificationSuite{
+ iface: &ifacetest.TestInterface{
+ InterfaceName: "test",
+ TestConnectedPlugCallback: func(spec *ifacetest.Specification, plug *interfaces.Plug, slot *interfaces.Slot) error {
+ spec.AddSnippet("connected-plug")
+ return nil
+ },
+ TestConnectedSlotCallback: func(spec *ifacetest.Specification, plug *interfaces.Plug, slot *interfaces.Slot) error {
+ spec.AddSnippet("connected-slot")
+ return nil
+ },
+ TestPermanentPlugCallback: func(spec *ifacetest.Specification, plug *interfaces.Plug) error {
+ spec.AddSnippet("permanent-plug")
+ return nil
+ },
+ TestPermanentSlotCallback: func(spec *ifacetest.Specification, slot *interfaces.Slot) error {
+ spec.AddSnippet("permanent-slot")
+ return nil
+ },
+ },
+ plug: &interfaces.Plug{
+ PlugInfo: &snap.PlugInfo{
+ Snap: &snap.Info{SuggestedName: "snap"},
+ Name: "name",
+ Interface: "test",
+ },
+ },
+ slot: &interfaces.Slot{
+ SlotInfo: &snap.SlotInfo{
+ Snap: &snap.Info{SuggestedName: "snap"},
+ Name: "name",
+ Interface: "test",
+ },
+ },
+})
+
+func (s *SpecificationSuite) SetUpTest(c *C) {
+ s.spec = &ifacetest.Specification{}
+}
+
+// AddSnippet is not broken
+func (s *SpecificationSuite) TestAddSnippet(c *C) {
+ s.spec.AddSnippet("hello")
+ s.spec.AddSnippet("world")
+ c.Assert(s.spec.Snippets, DeepEquals, []string{"hello", "world"})
+}
+
+// The Specification can be used through the interfaces.Specification interface
+func (s *SpecificationSuite) SpecificationIface(c *C) {
+ var r interfaces.Specification = s.spec
+ c.Assert(r.AddConnectedPlug(s.iface, s.plug, s.slot), IsNil)
+ c.Assert(r.AddConnectedSlot(s.iface, s.plug, s.slot), IsNil)
+ c.Assert(r.AddPermanentPlug(s.iface, s.plug), IsNil)
+ c.Assert(r.AddPermanentSlot(s.iface, s.slot), IsNil)
+ c.Assert(s.spec.Snippets, DeepEquals, []string{
+ "connected-plug", "connected-slot", "permanent-plug", "permanent-slot"})
+}
@@ -1,7 +1,7 @@
// -*- Mode: Go; indent-tabs-mode: t -*-
/*
- * Copyright (C) 2015 Canonical Ltd
+ * Copyright (C) 2015-2017 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
@@ -44,6 +44,13 @@ type TestInterface struct {
PlugSnippetCallback func(plug *interfaces.Plug, slot *interfaces.Slot, securitySystem interfaces.SecuritySystem) ([]byte, error)
// PermanentPlugSnippetCallback is the callback invoked inside PermanentPlugSnippet()
PermanentPlugSnippetCallback func(plug *interfaces.Plug, securitySystem interfaces.SecuritySystem) ([]byte, error)
+
+ // Support for interacting with the test backend.
+
+ TestConnectedPlugCallback func(spec *Specification, plug *interfaces.Plug, slot *interfaces.Slot) error
+ TestConnectedSlotCallback func(spec *Specification, plug *interfaces.Plug, slot *interfaces.Slot) error
+ TestPermanentPlugCallback func(spec *Specification, plug *interfaces.Plug) error
+ TestPermanentSlotCallback func(spec *Specification, slot *interfaces.Slot) error
}
// String() returns the same value as Name().
@@ -123,3 +130,33 @@ func (t *TestInterface) AutoConnect(plug *interfaces.Plug, slot *interfaces.Slot
}
return true
}
+
+// Support for interacting with the test backend.
+
+func (t *TestInterface) TestConnectedPlug(spec *Specification, plug *interfaces.Plug, slot *interfaces.Slot) error {
+ if t.TestConnectedPlugCallback != nil {
+ return t.TestConnectedPlugCallback(spec, plug, slot)
+ }
+ return nil
+}
+
+func (t *TestInterface) TestConnectedSlot(spec *Specification, plug *interfaces.Plug, slot *interfaces.Slot) error {
+ if t.TestConnectedSlotCallback != nil {
+ return t.TestConnectedSlotCallback(spec, plug, slot)
+ }
+ return nil
+}
+
+func (t *TestInterface) TestPermanentPlug(spec *Specification, plug *interfaces.Plug) error {
+ if t.TestPermanentPlugCallback != nil {
+ return t.TestPermanentPlugCallback(spec, plug)
+ }
+ return nil
+}
+
+func (t *TestInterface) TestPermanentSlot(spec *Specification, slot *interfaces.Slot) error {
+ if t.TestPermanentSlotCallback != nil {
+ return t.TestPermanentSlotCallback(spec, slot)
+ }
+ return nil
+}
@@ -1,7 +1,7 @@
// -*- Mode: Go; indent-tabs-mode: t -*-
/*
- * Copyright (C) 2015 Canonical Ltd
+ * Copyright (C) 2015-2017 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
@@ -52,7 +52,7 @@ import (
type Backend struct{}
// Name returns the name of the backend.
-func (b *Backend) Name() string {
+func (b *Backend) Name() interfaces.SecuritySystem {
return "kmod"
}
@@ -150,3 +150,7 @@ func uniqueLines(lines []string) (deduplicated []string) {
}
return deduplicated
}
+
+func (b *Backend) NewSpecification() interfaces.Specification {
+ panic(fmt.Errorf("%s is not using specifications yet", b.Name()))
+}
@@ -64,7 +64,7 @@ func (s *backendSuite) TearDownTest(c *C) {
}
func (s *backendSuite) TestName(c *C) {
- c.Check(s.Backend.Name(), Equals, "kmod")
+ c.Check(s.Backend.Name(), Equals, interfaces.SecurityKMod)
}
func (s *backendSuite) TestUniqueLines(c *C) {
@@ -44,8 +44,8 @@ import (
type Backend struct{}
// Name returns the name of the backend.
-func (b *Backend) Name() string {
- return "mount"
+func (b *Backend) Name() interfaces.SecuritySystem {
+ return interfaces.SecurityMount
}
// Setup creates mount mount profile files specific to a given snap.
@@ -128,3 +128,7 @@ func addContent(securityTag string, executableSnippets [][]byte, content map[str
Mode: 0644,
}
}
+
+func (b *Backend) NewSpecification() interfaces.Specification {
+ panic(fmt.Errorf("%s is not using specifications yet", b.Name()))
+}
Oops, something went wrong.