Skip to content

Commit

Permalink
snap: make AppInfo.ActivatesOn a slice of SlotInfos
Browse files Browse the repository at this point in the history
Also implicitly bind the named slot to the app.
  • Loading branch information
jhenstridge committed Jun 2, 2020
1 parent 9c307da commit cdfb1a2
Show file tree
Hide file tree
Showing 8 changed files with 81 additions and 41 deletions.
8 changes: 4 additions & 4 deletions interfaces/builtin/dbus.go
Expand Up @@ -356,8 +356,8 @@ func (iface *dbusInterface) DBusPermanentSlot(spec *dbus.Specification, slot *sn

// handle activatable services
for _, app := range slot.Apps {
for _, slotName := range app.ActivatesOn {
if slotName == slot.Name {
for _, s := range app.ActivatesOn {
if s == slot {
err = spec.AddService(bus, name, app)
if err != nil {
return err
Expand Down Expand Up @@ -444,8 +444,8 @@ func (iface *dbusInterface) BeforePrepareSlot(slot *snap.SlotInfo) error {

var apps []*snap.AppInfo
for _, app := range slot.Apps {
for _, slotName := range app.ActivatesOn {
if slotName == slot.Name {
for _, s := range app.ActivatesOn {
if s == slot {
apps = append(apps, app)
break
}
Expand Down
8 changes: 0 additions & 8 deletions interfaces/builtin/dbus_test.go
Expand Up @@ -137,14 +137,10 @@ apps:
test-session-activatable-provider:
daemon: dbus
daemon-scope: user
slots:
- test-session-activatable-slot
activates-on:
- test-session-activatable-slot
test-system-activatable-provider:
daemon: dbus
slots:
- test-system-activatable-slot
activates-on:
- test-system-activatable-slot
`, nil)
Expand Down Expand Up @@ -379,15 +375,11 @@ slots:
apps:
system-service:
daemon: simple
slots:
- dbus-session-service-slot
activates-on:
- dbus-session-service-slot
session-service:
daemon: simple
daemon-scope: user
slots:
- dbus-system-service-slot
activates-on:
- dbus-system-service-slot
`
Expand Down
2 changes: 1 addition & 1 deletion snap/info.go
Expand Up @@ -851,7 +851,7 @@ type AppInfo struct {
RefreshMode string
StopMode StopModeType

ActivatesOn []string
ActivatesOn []*SlotInfo

Plugs map[string]*PlugInfo
Slots map[string]*SlotInfo
Expand Down
15 changes: 14 additions & 1 deletion snap/info_snap_yaml.go
Expand Up @@ -357,7 +357,6 @@ func setAppsFromSnapYaml(y snapYaml, snap *Info, strk *scopedTracker) error {
PostStopCommand: yApp.PostStopCommand,
RestartCond: yApp.RestartCond,
RestartDelay: yApp.RestartDelay,
ActivatesOn: yApp.ActivatesOn,
CommonID: yApp.CommonID,
Environment: yApp.Environment,
Completer: yApp.Completer,
Expand All @@ -377,6 +376,9 @@ func setAppsFromSnapYaml(y snapYaml, snap *Info, strk *scopedTracker) error {
if len(yApp.Sockets) > 0 {
app.Sockets = make(map[string]*SocketInfo, len(yApp.Sockets))
}
if len(yApp.ActivatesOn) > 0 {
app.ActivatesOn = make([]*SlotInfo, 0, len(yApp.ActivatesOn))
}
// Daemons default to being system daemons
if app.Daemon != "" && app.DaemonScope == "" {
app.DaemonScope = SystemDaemon
Expand Down Expand Up @@ -437,6 +439,17 @@ func setAppsFromSnapYaml(y snapYaml, snap *Info, strk *scopedTracker) error {
Timer: yApp.Timer,
}
}
for _, slotName := range yApp.ActivatesOn {
slot, ok := snap.Slots[slotName]
if !ok {
return fmt.Errorf("invalid activates-on value %q on app %q: slot not found", slotName, appName)
}
app.ActivatesOn = append(app.ActivatesOn, slot)
// Implicitly add the slot to the app
strk.markSlot(slot)
app.Slots[slotName] = slot
slot.Apps[appName] = app
}
// collect all common IDs
if app.CommonID != "" {
snap.CommonIDs = append(snap.CommonIDs, app.CommonID)
Expand Down
62 changes: 58 additions & 4 deletions snap/info_snap_yaml_test.go
Expand Up @@ -1350,6 +1350,64 @@ slots:
app1.Name: app1, app2.Name: app2})
}

func (s *YamlSuite) TestUnmarshalActivatesOn(c *C) {
info, err := snap.InfoFromSnapYaml([]byte(`
name: snap
slots:
test-slot1:
test-slot2:
apps:
daemon:
activates-on: ["test-slot1", "test-slot2"]
foo:
`))
c.Assert(err, IsNil)
c.Check(info.InstanceName(), Equals, "snap")
c.Check(info.Plugs, HasLen, 0)
c.Check(info.Slots, HasLen, 2)
c.Check(info.Apps, HasLen, 2)
c.Check(info.Hooks, HasLen, 0)

app1 := info.Apps["daemon"]
app2 := info.Apps["foo"]
slot1 := info.Slots["test-slot1"]
slot2 := info.Slots["test-slot2"]

c.Assert(app1, Not(IsNil))
c.Check(app1.Name, Equals, "daemon")
c.Check(app1.ActivatesOn, DeepEquals, []*snap.SlotInfo{slot1, slot2})
// activates-on slots are implicitly added to the app
c.Check(app1.Slots, DeepEquals, map[string]*snap.SlotInfo{
slot1.Name: slot1, slot2.Name: slot2})

c.Assert(app2, Not(IsNil))
c.Check(app2.Name, Equals, "foo")
c.Check(app2.ActivatesOn, HasLen, 0)
// As slot has been bound to app1, it isn't implicitly applied here
c.Check(app2.Slots, HasLen, 0)

c.Assert(slot1, Not(IsNil))
c.Check(slot1.Name, Equals, "test-slot1")
c.Check(slot1.Apps, DeepEquals, map[string]*snap.AppInfo{
app1.Name: app1})

c.Assert(slot2, Not(IsNil))
c.Check(slot2.Name, Equals, "test-slot2")
c.Check(slot2.Apps, DeepEquals, map[string]*snap.AppInfo{
app1.Name: app1})
}

func (s *YamlSuite) TestUnmarshalActivatesOnUnknownSlot(c *C) {
info, err := snap.InfoFromSnapYaml([]byte(`
name: snap
apps:
daemon:
activates-on: ["test-slot"]
`))
c.Check(info, IsNil)
c.Check(err, ErrorMatches, `invalid activates-on value "test-slot" on app "daemon": slot not found`)
}

// type and architectures

func (s *YamlSuite) TestSnapYamlTypeDefault(c *C) {
Expand Down Expand Up @@ -1463,9 +1521,6 @@ apps:
stop-command: stop-cmd
post-stop-command: post-stop-cmd
restart-condition: on-abnormal
activates-on:
- slot1
- slot2
bus-name: busName
sockets:
sock1:
Expand All @@ -1486,7 +1541,6 @@ apps:
StartTimeout: timeout.Timeout(42 * time.Minute),
StopCommand: "stop-cmd",
PostStopCommand: "post-stop-cmd",
ActivatesOn: []string{"slot1", "slot2"},
Sockets: map[string]*snap.SocketInfo{},
}

Expand Down
8 changes: 3 additions & 5 deletions snap/validate.go
Expand Up @@ -666,11 +666,9 @@ func ValidateApp(app *AppInfo) error {
}

// ActivatesOn is a list of slot names that use the "dbus" type
for _, slotName := range app.ActivatesOn {
if slot, ok := app.Slots[slotName]; !ok {
return fmt.Errorf("invalid activates-on value %q: slot not found", slotName)
} else if slot.Interface != "dbus" {
return fmt.Errorf("invalid activates-on value %q: slot does not use dbus interface", slotName)
for _, slot := range app.ActivatesOn {
if slot.Interface != "dbus" {
return fmt.Errorf("invalid activates-on value %q: slot does not use dbus interface", slot.Name)
}
}

Expand Down
17 changes: 0 additions & 17 deletions snap/validate_test.go
Expand Up @@ -580,23 +580,6 @@ apps:
c.Check(ValidateApp(app), IsNil)
}

func (s *ValidateSuite) TestAppActivatesOnSlotNotFound(c *C) {
info, err := InfoFromSnapYaml([]byte(`name: foo
version: 1.0
slots:
dbus-slot:
interface: dbus
apps:
server:
activates-on: [dbus-slot]
other-server:
slots: [dbus-slot]
`))
c.Assert(err, IsNil)
app := info.Apps["server"]
c.Check(ValidateApp(app), ErrorMatches, `invalid activates-on value "dbus-slot": slot not found`)
}

func (s *ValidateSuite) TestAppActivatesOnSlotNotDbus(c *C) {
info, err := InfoFromSnapYaml([]byte(`name: foo
version: 1.0
Expand Down
2 changes: 1 addition & 1 deletion wrappers/services.go
Expand Up @@ -721,7 +721,7 @@ WantedBy={{.ServicesTarget}}

var busName string
if appInfo.Daemon == "dbus" && len(appInfo.ActivatesOn) > 0 {
slot := appInfo.Slots[appInfo.ActivatesOn[len(appInfo.ActivatesOn)-1]]
slot := appInfo.ActivatesOn[len(appInfo.ActivatesOn)-1]
if err := slot.Attr("name", &busName); err != nil {
logger.Noticef("Cannot get 'name' attribute of dbus slot %q: %v", slot.Name, err)
}
Expand Down

0 comments on commit cdfb1a2

Please sign in to comment.