interfaces/builtin: rework for avahi interface #3624

Merged
merged 15 commits into from Aug 8, 2017

Conversation

Projects
None yet
5 participants
Contributor

kubiko commented Jul 26, 2017

rework for avahi-observe

  • removing classic only restriction
  • adding slot declaration which can be now implemented by application snaps.
    Adding new avahi-control for control level of capabilities

kubiko added some commits Jun 14, 2017

Reworking avahi-observe interface
- removing classic system only restriction
- adding ability for slot declaration by app snap

Signed-off-by: Ondrej Kubik <ondrej.kubik@canonical.com>
Adding avahi-control interface declaration
- build on top of avahi-observe, adding capabilities to also control

Signed-off-by: Ondrej Kubik <ondrej.kubik@canonical.com>
Adding tests for avahi-observe and avahi-control interfaces
- fixing dbus test fail once release.OnClassic is used in avahi test suite

Signed-off-by: Ondrej Kubik <ondrej.kubik@canonical.com>
Contributor

zyga commented Jul 26, 2017

Hey. Is there any forum discussion on the background of this change?

@zyga zyga requested review from jdstrand and zyga Jul 26, 2017

Contributor

kubiko commented Jul 26, 2017

@zyga not really, something I hit when snapping various projects. Also avahi snap as it exists now is quite limited compare to what avahi delivers on classic system. So this is just evening behaviour between UC and Classic on observer part of the interface. And control is just to go all the way on avahi interface. @jdstrand suggested to split it into observe and control parts which sounds reasonable.

Additionally avahi is often used when building bridges to Apple ecosystem, so common thing in IOT. homebridge project is good example.

Happy to create forum post though

Some early feedback. Let's iterate on this together.

One of the helpers I mentioned are not merged yet, I'll get them in ASAP.

interfaces/builtin/avahi_control.go
+// -*- Mode: Go; indent-tabs-mode: t -*-
+
+/*
+ * Copyright (C) 2016 Canonical Ltd
@zyga

zyga Jul 26, 2017

Contributor

2017

interfaces/builtin/avahi_control.go
+ on-classic: false
+`
+
+const avahiControlSummary = `allows control over local domains, hostnames and services`
@zyga

zyga Jul 26, 2017

Contributor

The summary doesn't really say this is about mDNS and service discovery.

interfaces/builtin/avahi_control.go
+func (iface *avahiControlInterface) AppArmorConnectedPlug(spec *apparmor.Specification, plug *interfaces.Plug, plugAttrs map[string]interface{}, slot *interfaces.Slot, slotAttrs map[string]interface{}) error {
+ old := "###SLOT_SECURITY_TAGS###"
+ var new string
+ if release.OnClassic {
@zyga

zyga Jul 26, 2017

Contributor

Nice

interfaces/builtin/avahi_control.go
+ return nil
+}
+
+func (iface *avahiControlInterface) SanitizePlug(plug *interfaces.Plug) error {
@zyga

zyga Jul 26, 2017

Contributor

Can you please ensurePlugIfaceMatch here?

interfaces/builtin/avahi_control.go
+}
+
+func (iface *avahiControlInterface) SanitizeSlot(slot *interfaces.Slot) error {
+ return nil
@zyga

zyga Jul 26, 2017

Contributor

Can you please use ensureSlotIfaceMatch here?

interfaces/builtin/avahi_control_test.go
+}
+
+// The label glob when all apps are bound to the avahi slot
+func (s *AvahiControlInterfaceSuite) TestConnectedPlugSnippetUsesSlotLabelAll(c *C) {
@zyga

zyga Jul 26, 2017

Contributor

Can you please use snaptest.MockInfo and extract those from the resulting snap.Info instead?

interfaces/builtin/avahi_control_test.go
+ Apps: map[string]*snap.AppInfo{"app1": app1, "app2": app2},
+ },
+ }
+ release.OnClassic = false
@zyga

zyga Jul 26, 2017

Contributor

Please use release.MockOnClassic here

interfaces/builtin/avahi_control_test.go
+
+// The label glob when all apps are bound to the avahi slot
+func (s *AvahiControlInterfaceSuite) TestConnectedPlugSnippetUsesSlotLabelSome(c *C) {
+ app1 := &snap.AppInfo{Name: "app1"}
@zyga

zyga Jul 26, 2017

Contributor

Same here

interfaces/builtin/avahi_control_test.go
+ Apps: map[string]*snap.AppInfo{"app1": app1, "app2": app2},
+ },
+ }
+ release.OnClassic = false
@zyga

zyga Jul 26, 2017

Contributor

Please use release.MockOnClassic here

interfaces/builtin/avahi_control_test.go
+
+// The label glob when all apps are bound to the avahi slot
+func (s *AvahiControlInterfaceSuite) TestConnectedPlugSnippetUsesSlotLabelOne(c *C) {
+ app := &snap.AppInfo{Name: "app"}
@zyga

zyga Jul 26, 2017

Contributor

And here

interfaces/builtin/avahi_control_test.go
+ Apps: map[string]*snap.AppInfo{"app": app},
+ },
+ }
+ release.OnClassic = false
@zyga

zyga Jul 26, 2017

Contributor

Please use release.MockOnClassic here

interfaces/builtin/avahi_control_test.go
+ }
+ release.OnClassic = false
+
+ apparmorSpec := &apparmor.Specification{}
@zyga

zyga Jul 26, 2017

Contributor

Just say spec here, it's shorter. If you need multiple split those to individual tests. This will also clean up the problem of mocking the right data and you can move that up to the top of the file / into the suite type.

interfaces/builtin/avahi_control_test.go
+
+func (s *AvahiControlInterfaceSuite) TestConnectedPlugSnippedUsesUnconfinedLabelOnClassic(c *C) {
+ slot := &interfaces.Slot{}
+ release.OnClassic = true
@zyga

zyga Jul 26, 2017

Contributor

Please use release.MockOnClassic here

interfaces/builtin/avahi_observe.go
+}
+
+func (iface *avahiObserveInterface) SanitizePlug(plug *interfaces.Plug) error {
+ return nil
@zyga

zyga Jul 26, 2017

Contributor

Same as above (use one of the new helpers).

interfaces/builtin/avahi_observe.go
+}
+
+func (iface *avahiObserveInterface) SanitizeSlot(slot *interfaces.Slot) error {
+ return nil
@zyga

zyga Jul 26, 2017

Contributor

Same as above (use one of the new helpers).

interfaces/builtin/avahi_observe_test.go
version: 1.0
apps:
- app:
+ app2:
@zyga

zyga Jul 26, 2017

Contributor

Why is this change necessary?

interfaces/builtin/avahi_observe_test.go
+ Apps: map[string]*snap.AppInfo{"app1": app1, "app2": app2},
+ },
+ }
+ release.OnClassic = false
@zyga

zyga Jul 26, 2017

Contributor

Please use the right mocking helper here.

interfaces/builtin/avahi_observe_test.go
+ Apps: map[string]*snap.AppInfo{"app": app},
+ },
+ }
+ release.OnClassic = false
@zyga

zyga Jul 26, 2017

Contributor

Please use the right mocking helper here.

interfaces/builtin/avahi_observe_test.go
+
+func (s *AvahiObserveInterfaceSuite) TestConnectedPlugSnippedUsesUnconfinedLabelOnClassic(c *C) {
+ slot := &interfaces.Slot{}
+ release.OnClassic = true
@zyga

zyga Jul 26, 2017

Contributor

Please use the right mocking helper here.

interfaces/builtin/dbus_test.go
@@ -292,6 +292,7 @@ plugs:
func (s *DbusInterfaceSuite) TestPermanentSlotAppArmorSession(c *C) {
apparmorSpec := &apparmor.Specification{}
+ release.OnClassic = true
@zyga

zyga Jul 26, 2017

Contributor

Please use release.MockOnClassic

interfaces/builtin/dbus_test.go
@@ -341,6 +342,7 @@ func (s *DbusInterfaceSuite) TestPermanentSlotAppArmorSessionClassic(c *C) {
func (s *DbusInterfaceSuite) TestPermanentSlotAppArmorSystem(c *C) {
apparmorSpec := &apparmor.Specification{}
+ release.OnClassic = true
@zyga

zyga Jul 26, 2017

Contributor

Please use release.MockOnClassic

Contributor

zyga commented Jul 28, 2017

I'll push some cleanups into this PR, please don't close it

Contributor

zyga commented Jul 28, 2017

I merged master and resolved API breaking conflicts. Let's please iterate on this branch to address remaining points and one @jdstrand is happy, land it.

Fixes to PR based on review
- replacing release.OnClassic = false
- fixing date in header
- renaming app2 to app
- updated summary for control interface

Signed-off-by: Ondrej Kubik <ondrej.kubik@canonical.com>

@pedronis pedronis changed the title from rework for avahi interface to interfaces/builtin: rework for avahi interface Aug 3, 2017

zyga added some commits Aug 4, 2017

interfaces: tweak tests for avahi interfaces
This patch also introduces new helpers, Mock{Plug,Slot} that I'd like to
use to cut the amount of test boilerplate even further.

Signed-off-by: Zygmunt Krynicki <zygmunt.krynicki@canonical.com>
interfaces: update base policy tests for avahi
Signed-off-by: Zygmunt Krynicki <zygmunt.krynicki@canonical.com>

zyga approved these changes Aug 4, 2017

interfaces: add more tests for avahi
Signed-off-by: Zygmunt Krynicki <zygmunt.krynicki@canonical.com>

Actually, I just noticed one more thing to fix. Give me a moment.

zyga added some commits Aug 4, 2017

interfaces: clarify some avahi-{control,observe} snippets
There's some code sharing done between avahi-observe and avahi-control
and I'm not sure if there is still some accidental copy-paste bug there.
This patch corrects one entry that looks definitely wrong and adds
comments to other sites that share.

Signed-off-by: Zygmunt Krynicki <zygmunt.krynicki@canonical.com>
interfaces: add extra tests for avahi
Signed-off-by: Zygmunt Krynicki <zygmunt.krynicki@canonical.com>

zyga approved these changes Aug 4, 2017

codecov-io commented Aug 4, 2017

Codecov Report

Merging #3624 into master will increase coverage by 0.06%.
The diff coverage is 100%.

Impacted file tree graph

@@            Coverage Diff             @@
##           master    #3624      +/-   ##
==========================================
+ Coverage   75.16%   75.22%   +0.06%     
==========================================
  Files         388      389       +1     
  Lines       33655    33725      +70     
==========================================
+ Hits        25297    25371      +74     
+ Misses       6539     6536       -3     
+ Partials     1819     1818       -1
Impacted Files Coverage Δ
interfaces/builtin/avahi_observe.go 100% <100%> (ø) ⬆️
interfaces/builtin/avahi_control.go 100% <100%> (ø)
interfaces/sorting.go 98.71% <0%> (-1.29%) ⬇️
release/release.go 89.18% <0%> (-0.15%) ⬇️
overlord/ifacestate/helpers.go 62.33% <0%> (ø) ⬆️
cmd/cmd.go 83.87% <0%> (ø) ⬆️
snap/snapenv/snapenv.go 97.1% <0%> (+0.22%) ⬆️
interfaces/builtin/common.go 65.57% <0%> (+3.27%) ⬆️
interfaces/builtin/broadcom_asic_control.go 100% <0%> (+8.82%) ⬆️

Continue to review full report at Codecov.

Legend - Click here to learn more
Δ = absolute <relative> (impact), ø = not affected, ? = missing data
Powered by Codecov. Last update 653f17c...5b096df. Read the comment docs.

Contributor

zyga commented Aug 4, 2017

I think this is ready for review. @jdstrand please note that the two interfaces, avahi-{observe,control} share some snippets. I would perhaps rather have them explicitly shared (e.g. using a common 3rd snipped) or just copy-paste the relevant parts to the primary snippets. Please advise on how you'd like to see this.

@kubiko I updated the PR and re-worked tests (have a look). I cut tests that were just checking the slot/plug app pattern generator and instead focused on testing where and what kind of snippets do we generate. I also tweaked how tests are prepared, how variables and snap apps are named, all for readability and (hopefully) some more consistency with other interfaces. This is constantly evolving but I'm trying my best to cut the amount of useless code and signal/noise ratio.

interfaces: neuter avahi slots on classic, add tests
On classic, where avahi itself comes from the system package and is not
confined, we should not generate and snippets for slots (connected or
otherwise). This kind-of de-facto happened because core has no apps but
it was not done explicitly.

Signed-off-by: Zygmunt Krynicki <zygmunt.krynicki@canonical.com>

check two comments I have, I'm not sure about those two changes

interfaces/builtin/avahi_control.go
@@ -124,25 +124,29 @@ func (iface *avahiControlInterface) AppArmorConnectedPlug(spec *apparmor.Specifi
} else {
new = slotAppLabelExpr(slot)
}
- snippet := strings.Replace(avahiObserveConnectedPlugAppArmor+avahiControlConnectedPlugAppArmor, old, new, -1)
+ snippet := strings.Replace(avahiControlConnectedPlugAppArmor+avahiControlConnectedPlugAppArmor, old, new, -1)
@kubiko

kubiko Aug 4, 2017

Contributor

are you sure about this? Idea here is that control also includes observe part.
avahiControlConnectedPlugAppArmor + avahiControlConnectedPlugAppArmor seems odd to me

@zyga

zyga Aug 4, 2017

Contributor

Well, this is avahi_control and otherwise the control snippet was just unused. Perhaps the rules need tweaking but this was a clear mistake IMO.

interfaces/builtin/avahi_control.go
spec.AddSnippet(avahiObservePermanentSlotAppArmor)
return nil
}
func (iface *avahiControlInterface) AppArmorConnectedSlot(spec *apparmor.Specification, plug *interfaces.Plug, plugAttrs map[string]interface{}, slot *interfaces.Slot, slotAttrs map[string]interface{}) error {
old := "###PLUG_SECURITY_TAGS###"
new := plugAppLabelExpr(plug)
- snippet := strings.Replace(avahiObserveConnectedSlotAppArmor+avahiControlConnectedSlotAppArmor, old, new, -1)
+ snippet := strings.Replace(avahiControlConnectedSlotAppArmor+avahiControlConnectedSlotAppArmor, old, new, -1)
@kubiko

kubiko Aug 4, 2017

Contributor

same here

@zyga

zyga Aug 4, 2017

Contributor

Same as above.

chanfing used of snippets definition for connected plug and slots
Signed-off-by: Ondrej Kubik <ondrej.kubik@canonical.com>

This looks really good, thanks! :)

Just a few small things and I think it will be ready to merge.

+
+const avahiControlSummary = `allows control over service discovery on a local network via the mDNS/DNS-SD protocol suite`
+
+const avahiControlConnectedSlotAppArmor = `
@jdstrand

jdstrand Aug 4, 2017

Contributor

It would be nice to have a comment here. Eg:

# Description: allows configuration of service discovery via mDNS/DNS-SD
@kubiko

kubiko Aug 7, 2017

Contributor

Done

interfaces/builtin/avahi_control.go
+ } else {
+ new = slotAppLabelExpr(slot)
+ }
+ snippet := strings.Replace(avahiObserveConnectedPlugAppArmor, old, new, -1)
@jdstrand

jdstrand Aug 4, 2017

Contributor

I think it is fine to re-use this variable, but can you make a comment here. I suggest:

# avahi-control implies avahi-observe, so add snippets for both here
@kubiko

kubiko Aug 7, 2017

Contributor

Done

interfaces/builtin/avahi_control.go
+ if !release.OnClassic {
+ old := "###PLUG_SECURITY_TAGS###"
+ new := plugAppLabelExpr(plug)
+ snippet := strings.Replace(avahiObserveConnectedSlotAppArmor, old, new, -1)
@jdstrand

jdstrand Aug 4, 2017

Contributor

Same here:

# avahi-control implies avahi-observe, so add snippets for both here
@kubiko

kubiko Aug 7, 2017

Contributor

Done

interfaces/builtin/avahi_observe.go
+ "github.com/snapcore/snapd/interfaces/dbus"
+ "github.com/snapcore/snapd/release"
+)
+
const avahiObserveSummary = `allows discovering local domains, hostnames and services`
@jdstrand

jdstrand Aug 4, 2017

Contributor

Let's update the summary to be in line with the control summary. I suggest:

const avahiObserveSummary = `allows discovery on a local network via the mDNS/DNS-SD protocol suite`
@kubiko

kubiko Aug 7, 2017

Contributor

Done

- core
deny-auto-connection: true
+ deny-connection:
+ on-classic: false
@jdstrand

jdstrand Aug 4, 2017

Contributor

The base declaration looks good for both control and observe.

interfaces/builtin/avahi_observe.go
+ peer=(label=unconfined),
+`
+
+const avahiObserveConnectedSlotAppArmor = `
@jdstrand

jdstrand Aug 4, 2017

Contributor

Also, since avahiObserveConnectedSlotAppArmor is used in avahi-control, let's mention that above avahiObserveConnectedSlotAppArmor:

# Note: avahiObserveConnectedSlotAppArmor is also used by avahi-control in AppArmorConnectedSlot
@kubiko

kubiko Aug 7, 2017

Contributor

Done

interfaces/builtin/avahi_observe.go
+ peer=(name=org.freedesktop.Avahi, label=###PLUG_SECURITY_TAGS###),
+`
+
+const avahiObservePermanentSlotDBus = `
@jdstrand

jdstrand Aug 4, 2017

Contributor

And here:

# Note: avahiObservePermanentSlotDBus is used by avahi-control in DBusPermanentSlot
@kubiko

kubiko Aug 7, 2017

Contributor

Done

interfaces/builtin/avahi_observe.go
+<policy group="netdev">
+ <allow send_destination="org.freedesktop.Avahi"/>
+ <allow receive_sender="org.freedesktop.Avahi"/>
+</policy>
@jdstrand

jdstrand Aug 4, 2017

Contributor

I realize you (essentially) copied upstream's bus policy, but I wonder how applicable the 'netdev' policy is here on Ubuntu Core. I suggest either removing it or commenting it out with a comment as to why.

@kubiko

kubiko Aug 7, 2017

Contributor

Good find, indeed makes no sense here.
I removed the policy and added comment about it there.

interfaces/builtin/avahi_observe.go
+<policy user="root">
+ <allow send_destination="org.freedesktop.Avahi"/>
+ <allow receive_sender="org.freedesktop.Avahi"/>
+</policy>
`
const avahiObserveConnectedPlugAppArmor = `
@jdstrand

jdstrand Aug 4, 2017

Contributor

Can you adjust this comment:

# Description: allows domain browsing, service browsing and service resolving

to be:

# Description: allows domain, record, service, and service type browsing
# as well as address, host and service resolving
@kubiko

kubiko Aug 7, 2017

Contributor

Done

interfaces/builtin/avahi_observe.go
+<policy user="root">
+ <allow send_destination="org.freedesktop.Avahi"/>
+ <allow receive_sender="org.freedesktop.Avahi"/>
+</policy>
`
const avahiObserveConnectedPlugAppArmor = `
@jdstrand

jdstrand Aug 4, 2017

Contributor

Same here for avahiObserveConnectedPlugAppArmor:

# Note: avahiObserveConnectedPlugAppArmor is also used by avahi-control in AppArmorConnectedPlug
@kubiko

kubiko Aug 7, 2017

Contributor

Done

dbus (send)
bus=system
path=/
interface=org.freedesktop.Avahi.Server
- member=Get*
- peer=(name=org.freedesktop.Avahi,label=unconfined),
+ member={Get*,Resolve*,IsNSSSupportAvailable}
@jdstrand

jdstrand Aug 4, 2017

Contributor

Can you comment on the addition of Resolve* and IsNSSSupportAvailable? It seems like Resolve* should be listed below....

@kubiko

kubiko Aug 7, 2017

Contributor

when I was testing it with third party apps, some are using instead of {Host/Address/Domain}Resolver direct resolve functions (ResolveHostName, ResolveAddress, ResolveService, ….). Then I was split to either use separate rules and add it under each respective resolving section, or to add it to existing Get* rule all at once. Similar for IsNSSSupportAvailable which did not fit anywhere. I did not have strong opinion here, smaller amounts of rules won eventually.
But happy to split them and add each to respective sections, if that improves readability.

@jdstrand

jdstrand Aug 7, 2017

Contributor

I think it is fine to leave them combined, but perhaps add this comment:

# Allow accessing DBus properties and resolving
interfaces/builtin/avahi_observe.go
+ member={Get*,Resolve*,IsNSSSupportAvailable}
+ peer=(name=org.freedesktop.Avahi,label=###SLOT_SECURITY_TAGS###),
+
+dbus (receive)
@jdstrand

jdstrand Aug 4, 2017

Contributor

Can you add a comment above this rule:

# Allow receiving anything from the slot server
@kubiko

kubiko Aug 7, 2017

Contributor

Done

+ c.Assert(spec.AddConnectedPlug(s.iface, s.plug, nil, s.appSlot, nil), IsNil)
+ c.Assert(spec.SecurityTags(), DeepEquals, []string{"snap.consumer.app"})
+ c.Assert(spec.SnippetForTag("snap.consumer.app"), testutil.Contains, "name=org.freedesktop.Avahi")
+ c.Assert(spec.SnippetForTag("snap.consumer.app"), testutil.Contains, `peer=(label="snap.producer.app"),`)
@jdstrand

jdstrand Aug 4, 2017

Contributor

It might be nice to verify a specific rule from avahi-observe and from avahi-control for AddConnectedPlug and AddConnectedSlot since avahi-control pulls in both.

@kubiko

kubiko Aug 7, 2017

Contributor

Tests are now improved for both observe and control to check if observe does not include control and if control includes observe

Contributor

kubiko commented Aug 7, 2017

@jdstrand I now pushed changes in, let me know if you want me to split
member={Get*,Resolve*,IsNSSSupportAvailable}
and include each rule in respective sections. Rational behind is explained in comment above, again I have no strong opinion either way, so whatever fits better with other interfaces implementation :)
Rest of the comments should be addressed in commit

Contributor

zyga commented Aug 7, 2017

@kubiko I suggest that you install some plugin for your editor to go fmt the code on each save.

Formatting wrong in following files:
/tmp/static-unit-tests/src/github.com/snapcore/snapd/interfaces/builtin/avahi_control_test.go
/tmp/static-unit-tests/src/github.com/snapcore/snapd/interfaces/builtin/avahi_observe.go
/tmp/static-unit-tests/src/github.com/snapcore/snapd/interfaces/builtin/avahi_observe_test.go
/tmp/static-unit-tests/src/github.com/snapcore/snapd/interfaces/builtin/avahi_control_test.go
/tmp/static-unit-tests/src/github.com/snapcore/snapd/interfaces/builtin/avahi_observe.go
/tmp/static-unit-tests/src/github.com/snapcore/snapd/interfaces/builtin/avahi_observe_test.go
improvement changes based on pull request reviews
Signed-off-by: Ondrej Kubik <ondrej.kubik@canonical.com>
Contributor

kubiko commented Aug 7, 2017

formating now fixed as well

Thanks for all the updates! Approving, though please consider adding a comment for the 'Get*/Resolve*' as mentioned earlier today.

Adding comment to avahi_observe about dbus properties for connected plug
Signed-off-by: Ondrej Kubik <ondrej.kubik@canonical.com>
Contributor

kubiko commented Aug 7, 2017

@jdstrand thanks you
I now added comment you mentioned.

@zyga zyga merged commit af4cc96 into snapcore:master Aug 8, 2017

7 checks passed

artful-amd64 autopkgtest finished (success)
Details
continuous-integration/travis-ci/pr The Travis CI build passed
Details
xenial-amd64 autopkgtest finished (success)
Details
xenial-i386 autopkgtest finished (success)
Details
xenial-ppc64el autopkgtest finished (success)
Details
yakkety-amd64 autopkgtest finished (success)
Details
zesty-amd64 autopkgtest finished (success)
Details
Contributor

niemeyer commented Aug 8, 2017

Great collaboration in this PR. Thanks to all involved.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment