create mir interface #1299

Merged
merged 56 commits into from Aug 12, 2016
Commits
Jump to file or symbol
Failed to load files and symbols.
+290 −2
Split
@@ -153,6 +153,16 @@
click on the default printer and look at the queue. Ensure it contains the
new item.
+# Test Mir interface by running Mir kiosk snap examples
+
+1. Install Virtual Machine Manager
+2. Stitch together a new image
+3. Build both the mir-server and the mir-client snaps from lp:~mir-team/+junk/mir-server-snap and lp:~mir-team/+junk/snapcraft-mir-client
+4. Copy over the snaps and sideload install the mir-server snap, which should result in a mir-server launching black blank screen with a mouse available.
+5. Now install the mir-client snap.
+6. Manually connect mir-client:mir to mir-server:mir due to bug 1577897, then start the mir-client service manually.
+7. This should result in the Qt clock example app being displayed.
+
# Test serial-port interface using miniterm app
1. Using Ubuntu classic build and install a simple snap containing the Python
@@ -31,6 +31,7 @@ var allInterfaces = []interfaces.Interface{
&GpioInterface{},
&LocationControlInterface{},
&LocationObserveInterface{},
+ &MirInterface{},
&ModemManagerInterface{},
&MprisInterface{},
&NetworkManagerInterface{},
@@ -38,6 +38,7 @@ func (s *AllSuite) TestInterfaces(c *C) {
c.Check(all, Contains, &builtin.GpioInterface{})
c.Check(all, Contains, &builtin.LocationControlInterface{})
c.Check(all, Contains, &builtin.LocationObserveInterface{})
+ c.Check(all, Contains, &builtin.MirInterface{})
c.Check(all, Contains, &builtin.MprisInterface{})
c.Check(all, Contains, &builtin.SerialPortInterface{})
c.Check(all, Contains, &builtin.PulseAudioInterface{})
View
@@ -0,0 +1,158 @@
+// -*- 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 dtails.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.
+ *
+ */
+
+package builtin
+
+import (
+ "bytes"
+ "github.com/snapcore/snapd/interfaces"
+)
+
+var mirPermanentSlotAppArmor = []byte(`
+# Description: Allow operating as the Mir server. Reserved because this
+# gives privileged access to the system.
+# Usage: reserved
+# needed since Mir is the display server, to configure tty devices
+capability sys_tty_config,
+/dev/shm/\#* rw,
+/dev/tty[0-9]* rw,
+network netlink raw,
+/run/mir_socket rw,
+#NOTE: this allows reading and inserting all input events
+/dev/input/* rw,
+`)
+
+var mirPermanentSlotSecComp = []byte(`
+# Description: Allow operating as the mir server. Reserved because this
+# gives privileged access to the system.
+# Needed for server launch
+bind
+listen
+setsockopt
+getsockname
+# Needed by server upon client connect
+sendto
+accept
+shmctl
+open
+getsockopt
+recvmsg
+sendmsg
+`)
+
+var mirConnectedSlotAppArmor = []byte(`
+# Description: Permit clients to use Mir
+# Usage: reserved
+unix (receive, send) type=seqpacket addr=none peer=(label=###PLUG_SECURITY_TAGS###),
+`)
+
+var mirConnectedPlugAppArmor = []byte(`
+# Description: Permit clients to use Mir
+# Usage: common
+unix (receive, send) type=seqpacket addr=none peer=(label=###SLOT_SECURITY_TAGS###),
+/run/mir_socket rw,
+/run/user/[0-9]*/mir_socket rw,
+`)
+
+var mirConnectedPlugSecComp = []byte(`
+# Description: Permit clients to use Mir
+# Usage: common
+recvmsg
+sendmsg
+sendto
+`)
+
+type MirInterface struct{}
+
+func (iface *MirInterface) Name() string {
+ return "mir"
+}
+
+func (iface *MirInterface) PermanentPlugSnippet(
@zyga

zyga Jun 9, 2016

Contributor

Please run go fmt on this file.

@kgunnfront

kgunnfront Jun 15, 2016

ran go fmt on all files

+ plug *interfaces.Plug,
+ securitySystem interfaces.SecuritySystem) ([]byte, error) {
+ switch securitySystem {
+ case interfaces.SecurityAppArmor, interfaces.SecuritySecComp,
+ interfaces.SecurityUDev, interfaces.SecurityDBus,
+ interfaces.SecurityMount:
+ return nil, nil
+ default:
+ return nil, interfaces.ErrUnknownSecurity
+ }
+}
+
+func (iface *MirInterface) ConnectedPlugSnippet(
+ plug *interfaces.Plug,
+ slot *interfaces.Slot,
+ securitySystem interfaces.SecuritySystem) ([]byte, error) {
+ switch securitySystem {
+ case interfaces.SecurityAppArmor:
+ old := []byte("###SLOT_SECURITY_TAGS###")
+ new := slotAppLabelExpr(slot)
+ snippet := bytes.Replace(mirConnectedPlugAppArmor, old, new, -1)
+ return snippet, nil
+ case interfaces.SecuritySecComp:
+ return mirConnectedPlugSecComp, nil
+ case interfaces.SecurityUDev, interfaces.SecurityDBus, interfaces.SecurityMount:
+ return nil, nil
+ default:
+ return nil, interfaces.ErrUnknownSecurity
+ }
+}
+
+func (iface *MirInterface) PermanentSlotSnippet(
@zyga

zyga Jun 9, 2016

Contributor

Ditto, return the permanent snippets defined above here please.

+ slot *interfaces.Slot,
+ securitySystem interfaces.SecuritySystem) ([]byte, error) {
+ switch securitySystem {
+ case interfaces.SecurityAppArmor:
+ return mirPermanentSlotAppArmor, nil
+ case interfaces.SecuritySecComp:
+ return mirPermanentSlotSecComp, nil
+ case interfaces.SecurityUDev, interfaces.SecurityDBus, interfaces.SecurityMount:
+ return nil, nil
+ default:
+ return nil, interfaces.ErrUnknownSecurity
+ }
+}
+
+func (iface *MirInterface) ConnectedSlotSnippet(plug *interfaces.Plug, slot *interfaces.Slot, securitySystem interfaces.SecuritySystem) ([]byte, error) {
+ switch securitySystem {
+ case interfaces.SecurityAppArmor:
+ old := []byte("###PLUG_SECURITY_TAGS###")
+ new := plugAppLabelExpr(plug)
+ snippet := bytes.Replace(mirConnectedSlotAppArmor, old, new, -1)
+ return snippet, nil
+ case interfaces.SecuritySecComp, interfaces.SecurityUDev, interfaces.SecurityDBus, interfaces.SecurityMount:
+ return nil, nil
+ default:
+ return nil, interfaces.ErrUnknownSecurity
+ }
+}
+
+func (iface *MirInterface) SanitizePlug(plug *interfaces.Plug) error {
+ return nil
+}
+
+func (iface *MirInterface) SanitizeSlot(slot *interfaces.Slot) error {
+ return nil
+}
+
+func (iface *MirInterface) AutoConnect() bool {
@zyga

zyga Jun 9, 2016

Contributor

IMHO mir should auto connect.

@jdstrand

jdstrand Jun 9, 2016

Contributor

We've said the slot side should autoconnect, yes, and the plugs side of Mir is supposed to be safe for anyone, so yes, autoconnect.

@kgunnfront

kgunnfront Jun 16, 2016

changed autoconnect to true

+ return true
+}
@@ -0,0 +1,117 @@
+// -*- Mode: Go; indent-tabs-mode: t -*-
+
@zyga

zyga Jun 9, 2016

Contributor

I'll skip reviewing this until the mir.go itself is updated.

@kgunnfront

kgunnfront Jun 16, 2016

ok, zyga/jamie - i think it's probably ready for another round, spend large amount of today/y'day cleaning up

+/*
+ * 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 MirInterfaceSuite struct {
+ iface interfaces.Interface
+ slot *interfaces.Slot
+ plug *interfaces.Plug
+}
+
+var _ = Suite(&MirInterfaceSuite{
+ iface: &builtin.MirInterface{},
+ slot: &interfaces.Slot{
+ SlotInfo: &snap.SlotInfo{
+ Snap: &snap.Info{SuggestedName: "mir-server", Type: snap.TypeOS},
+ Name: "mir-server",
+ Interface: "mir",
+ },
+ },
+ plug: &interfaces.Plug{
+ PlugInfo: &snap.PlugInfo{
+ Snap: &snap.Info{SuggestedName: "other"},
+ Name: "mir-client",
+ Interface: "mir",
+ },
+ },
+})
+
+func (s *MirInterfaceSuite) TestName(c *C) {
+ c.Assert(s.iface.Name(), Equals, "mir")
+}
+
+func (s *MirInterfaceSuite) TestUnusedSecuritySystems(c *C) {
+ systems := [...]interfaces.SecuritySystem{interfaces.SecurityAppArmor,
+ interfaces.SecuritySecComp, interfaces.SecurityDBus,
+ interfaces.SecurityUDev}
+ for _, system := range systems {
+ snippet, err := s.iface.PermanentPlugSnippet(s.plug, system)
+ c.Assert(err, IsNil)
+ c.Assert(snippet, IsNil)
+ if system != interfaces.SecurityAppArmor {
+ snippet, err := s.iface.ConnectedSlotSnippet(s.plug, s.slot, system)
+ c.Assert(err, IsNil)
+ c.Assert(snippet, IsNil)
+ }
+ if system != interfaces.SecurityAppArmor && system != interfaces.SecuritySecComp {
+ snippet, err := s.iface.PermanentSlotSnippet(s.slot, system)
+ c.Assert(err, IsNil)
+ c.Assert(snippet, IsNil)
+ snippet, err = s.iface.ConnectedPlugSnippet(s.plug, s.slot, system)
+ c.Assert(err, IsNil)
+ c.Assert(snippet, IsNil)
+ }
+ }
+}
+
+func (s *MirInterfaceSuite) TestUsedSecuritySystems(c *C) {
+ systems := [...]interfaces.SecuritySystem{interfaces.SecurityAppArmor,
+ interfaces.SecuritySecComp}
+ for _, system := range systems {
+ snippet, err := s.iface.PermanentSlotSnippet(s.slot, system)
+ c.Assert(err, IsNil)
+ c.Assert(snippet, Not(IsNil))
+ snippet, err = s.iface.ConnectedPlugSnippet(s.plug, s.slot, system)
+ c.Assert(err, IsNil)
+ c.Assert(snippet, Not(IsNil))
+ if system != interfaces.SecuritySecComp {
+ snippet, err := s.iface.ConnectedSlotSnippet(s.plug, s.slot, system)
+ c.Assert(err, IsNil)
+ c.Assert(snippet, Not(IsNil))
+ }
+ }
+}
+
+func (s *MirInterfaceSuite) TestUnexpectedSecuritySystems(c *C) {
+ snippet, err := s.iface.PermanentPlugSnippet(s.plug, "foo")
+ c.Assert(err, Equals, interfaces.ErrUnknownSecurity)
+ c.Assert(snippet, IsNil)
+ snippet, err = s.iface.ConnectedPlugSnippet(s.plug, s.slot, "foo")
+ c.Assert(err, Equals, interfaces.ErrUnknownSecurity)
+ c.Assert(snippet, IsNil)
+ snippet, err = s.iface.PermanentSlotSnippet(s.slot, "foo")
+ c.Assert(err, Equals, interfaces.ErrUnknownSecurity)
+ c.Assert(snippet, IsNil)
+ snippet, err = s.iface.ConnectedSlotSnippet(s.plug, s.slot, "foo")
+ c.Assert(err, Equals, interfaces.ErrUnknownSecurity)
+ c.Assert(snippet, IsNil)
+}
@jdstrand

jdstrand Aug 11, 2016

Contributor

Can you add an AutoConnect test?

func (s *NetworkInterfaceSuite) TestAutoConnect(c *C) {
    c.Check(s.iface.AutoConnect(), Equals, true)
}
+
+func (s MirInterfaceSuite) TestAutoConnect(c *C) {
+ c.Check(s.iface.AutoConnect(), Equals, true)
+}
@@ -30,6 +30,7 @@ const openglConnectedPlugAppArmor = `
# specific gl libs
/var/lib/snapd/lib/gl/** rm,
+ /dev/dri/card0 rw,
# nvidia
@{PROC}/driver/nvidia/params r,
@{PROC}/modules r,
View
@@ -39,6 +39,7 @@ var implicitSlots = []string{
"network-bind",
"network-control",
"network-observe",
+ "opengl",
"ppp",
"process-control",
"snapd-control",
@@ -55,7 +56,6 @@ var implicitClassicSlots = []string{
"gsettings",
"modem-manager",
"network-manager",
- "opengl",
"optical-drive",
"pulseaudio",
"unity7",
View
@@ -42,7 +42,7 @@ func (s *InfoSnapYamlTestSuite) TestAddImplicitSlotsOutsideClassic(c *C) {
c.Assert(info.Slots["network"].Interface, Equals, "network")
c.Assert(info.Slots["network"].Name, Equals, "network")
c.Assert(info.Slots["network"].Snap, Equals, info)
- c.Assert(info.Slots, HasLen, 18)
+ c.Assert(info.Slots, HasLen, 19)
}
func (s *InfoSnapYamlTestSuite) TestAddImplicitSlotsOnClassic(c *C) {