Plug/slot declaration rules: greedy plugs

When processing auto-connection, plug and slot rules from snap-declarations are used as constraints/predicates to find candidate plug/slot pairs.

While for slots we allow both for auto-connection and in general any number of connected plugs, for plugs we auto-connect only if there is a single/unique candidate slot for a given plug.

But we have use cases (with themes for example and the content interface) where we would like and it makes sense to allow a plug to connect to all relevant available slots on the system.

We would like a way to request for this different behavior through plug and slot rules. It should be noted that this a different kind of constraint on the whole set of candidates, not on each pair.

We need a way to request this from either the plug side or slot side of rules.

In general for a given snap and interface we might not want to switch to the different behavior for all the slots or plugs but only some.

Syntax

First let’s remember in the rule subtree in a deny-*/allow-* stanza, all lists represent ORed constraints and maps are ANDed constraints. The top level is a possibly degenerate OR. When we check the constraints we short-circuit at the first succeeding map of constraints. So for a succeeding allow-* constraint there is exactly one relevant plug-snap-type/.../plug-attributes/slot-attributes/... constraints map.

For constraints maps under allow-[auto-]connection (not deny-* or *-installation ) we will introduce optional slots-per-plug and plugs-per-slot keys, at the moment the following values would be accepted syntactically:

  • an integer >= 1
  • * to mean any number of

The keys are not additional constraints on pairs, but if the overall allow-[auto-]connection succeeds because of the constraint the keys are in, then they are constraints on the cardinality of the candidate sets as a whole.

Every candidate plug and slot pair will have associated values for these keys, with the following defaults:

allow-connection:
  slots-per-plug: "*"
  plugs-per-slot: "*"

allow-auto-connection:
  slots-per-plug: 1
  plugs-per-slot: "*"

Where * means any (number of), and 1 means zero to one.

Expected behavior

For now syntactically valid values different from the defaults will be ignored, except for:

allow-auto-connection:
  slots-per-plug: "*"

For a given plug when we look at all the candidate pairs it is in, if they have different slots-per-plug values we have ambiguity and no auto-connection will occur.

If the slots-per-plug values are 1 we get the current behaviour, we auto-connect only if there is exactly one candidate pair in the set.

If the slots-per-plug values are *, all the candidate pairs will be auto-connected.

In the future we might support more non-default values and possibly range values for these candidate set constraints, but we do not have yet clear use cases for those.

Use cases/examples

If we turn the camera interface to be purely hotplug based, we can then still grant a snap access to all cameras by doing:

plugs:
  camera:
    allow-auto-connection:
      slots-per-plug: "*"

Allow greedy content plugs for given slots:

slots:
  content:
    allow-auto-connection:
      -
        plug-attributes:
          content: $SLOT(content)
        slot-attributes:
          content: themes
        slots-per-plug: "*"
3 Likes

see

https://github.com/snapcore/snapd/pull/7652

1 Like

@pedronis - this should be this:

slots:
  content:
    allow-auto-connection:
      -
        plug-attributes:
          content: $SLOT(content)
        slot-attributes: 
          content: themes
        slots-per-plug: *

no? (ie, ‘allow-auto-connection’ was at the wrong level if this is meant to represent the snap declaration)

1 Like

I think I missed this post when the thread was made visible last month.

In general, this seems like a reasonable start, although I think eventually I’d want to be able to encode some of this policy into my snapcraft.yaml, since ability to correctly handle greedy connection is often going to be a feature of the snap itself rather than something to be tweaked after the fact.

This is particularly true when we have plugs or slots introduced by Snapcraft extensions: ideally if a developer makes use of an extension, then their snap should end up with the correct policy without further action on their part.

Presumably that would still be possible with the snap declaration system described here through the use of $PLUG(attr) or $SLOT(attr). For example, if the base declaration for the content interface read something like:

slots:
  content:
    ...
    allow-auto-connection:
      slots-per-plug: $SLOT(slots-per-plug)

Then the slot definition in gtk-common-themes and any other theme snaps could read something like:

slots:
  gtk-3-themes:
    interface: content
    source:
      ...
    slots-per-plug: *

For the content interface specifically, the presence of the source attribute on the slot is probably the real marker that it supports greedy connection. I’m not sure how you’d feed that into the base declaration though.

This is very unlikely to be implemented in the medium term. I recommend instead of using different/new content tags to distinguish which behavior is acceptable.

@jamesh this aspect needs to be taken into account as well, having different producer snaps with the same content tag but different slots-per-plug settings will just result in non auto-connection.

@jamesh also notice that this is possible already:

slots:
  content:
    allow-auto-connection:
      -
        plug-attributes:
           content: optional-greedy
           greedy: true
        slots-per-plug: *
      -
        plug-attributes:
          content: optional-greedy
          greedy: $MISSING

But see my previous remark about to which extent it is viable.

We’ve now got some snaps with the slots-per-plug attribute set through store assertions, and it looks like this is all working as expected:

Great work!

1 Like