Skip to content

Commit

Permalink
many: support user-daemons in QueryDisabledServices
Browse files Browse the repository at this point in the history
  • Loading branch information
Meulengracht committed Apr 22, 2024
1 parent f2c7b3f commit 521e904
Show file tree
Hide file tree
Showing 9 changed files with 242 additions and 42 deletions.
6 changes: 3 additions & 3 deletions overlord/snapstate/autorefresh.go
Original file line number Diff line number Diff line change
Expand Up @@ -905,9 +905,9 @@ func maybeAddRefreshInhibitNotice(st *state.State) error {
// inhibited snaps was changed since the last notice.
//
// The warning is recorded only if:
// 1. There is at least 1 inhibited snap.
// 2. The "refresh-app-awareness-ux" experimental flag is enabled.
// 3. No snap exists with the marker "snap-refresh-observe" interface connected.
// 1. There is at least 1 inhibited snap.
// 2. The "refresh-app-awareness-ux" experimental flag is enabled.
// 3. No snap exists with the marker "snap-refresh-observe" interface connected.
//
// Note: If no snaps are inhibited then existing inhibition warning
// will be removed.
Expand Down
5 changes: 3 additions & 2 deletions overlord/snapstate/backend.go
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ import (
"github.com/snapcore/snapd/snap/naming"
"github.com/snapcore/snapd/store"
"github.com/snapcore/snapd/timings"
"github.com/snapcore/snapd/wrappers"
)

// A StoreService can find, list available updates and download snaps.
Expand Down Expand Up @@ -80,9 +81,9 @@ type managerBackend interface {
SetupSnapSaveData(info *snap.Info, dev snap.Device, meter progress.Meter) error
LinkSnap(info *snap.Info, dev snap.Device, linkCtx backend.LinkContext, tm timings.Measurer) (rebootInfo boot.RebootInfo, err error)
LinkComponent(cpi snap.ContainerPlaceInfo, snapRev snap.Revision) error
StartServices(svcs []*snap.AppInfo, disabledSvcs []string, meter progress.Meter, tm timings.Measurer) error
StartServices(svcs []*snap.AppInfo, disabledSvcs *wrappers.DisabledServices, meter progress.Meter, tm timings.Measurer) error
StopServices(svcs []*snap.AppInfo, reason snap.ServiceStopReason, meter progress.Meter, tm timings.Measurer) error
QueryDisabledServices(info *snap.Info, pb progress.Meter) ([]string, error)
QueryDisabledServices(info *snap.Info, pb progress.Meter) (*wrappers.DisabledServices, error)

// the undoers for install
UndoSetupSnap(s snap.PlaceInfo, typ snap.Type, installRecord *backend.InstallRecord, dev snap.Device, meter progress.Meter) error
Expand Down
4 changes: 2 additions & 2 deletions overlord/snapstate/backend/link.go
Original file line number Diff line number Diff line change
Expand Up @@ -211,7 +211,7 @@ func (b Backend) LinkComponent(cpi snap.ContainerPlaceInfo, snapRev snap.Revisio
return osutil.AtomicSymlink(linkTarget, linkPath)
}

func (b Backend) StartServices(apps []*snap.AppInfo, disabledSvcs []string, meter progress.Meter, tm timings.Measurer) error {
func (b Backend) StartServices(apps []*snap.AppInfo, disabledSvcs *wrappers.DisabledServices, meter progress.Meter, tm timings.Measurer) error {
flags := &wrappers.StartServicesFlags{Enable: true}
return wrappers.StartServices(apps, disabledSvcs, flags, meter, tm)
}
Expand Down Expand Up @@ -358,7 +358,7 @@ func (b Backend) UnlinkSnap(info *snap.Info, linkCtx LinkContext, meter progress
return firstErr(err0, err1, err2)
}

func (b Backend) QueryDisabledServices(info *snap.Info, pb progress.Meter) ([]string, error) {
func (b Backend) QueryDisabledServices(info *snap.Info, pb progress.Meter) (*wrappers.DisabledServices, error) {
return wrappers.QueryDisabledServices(info, pb)
}

Expand Down
13 changes: 8 additions & 5 deletions overlord/snapstate/backend_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@ import (
"github.com/snapcore/snapd/store/storetest"
"github.com/snapcore/snapd/strutil"
"github.com/snapcore/snapd/timings"
"github.com/snapcore/snapd/wrappers"
)

type fakeOp struct {
Expand Down Expand Up @@ -1192,7 +1193,7 @@ func svcSnapMountDir(svcs []*snap.AppInfo) string {
return svcs[0].Snap.MountDir()
}

func (f *fakeSnappyBackend) StartServices(svcs []*snap.AppInfo, disabledSvcs []string, meter progress.Meter, tm timings.Measurer) error {
func (f *fakeSnappyBackend) StartServices(svcs []*snap.AppInfo, disabledSvcs *wrappers.DisabledServices, meter progress.Meter, tm timings.Measurer) error {
services := make([]string, 0, len(svcs))
for _, svc := range svcs {
services = append(services, svc.Name)
Expand All @@ -1203,8 +1204,8 @@ func (f *fakeSnappyBackend) StartServices(svcs []*snap.AppInfo, disabledSvcs []s
services: services,
}
// only add the services to the op if there's something to add
if len(disabledSvcs) != 0 {
op.disabledServices = disabledSvcs
if disabledSvcs != nil && len(disabledSvcs.SystemServices) != 0 {
op.disabledServices = disabledSvcs.SystemServices
}
f.appendOp(&op)
return f.maybeErrForLastOp()
Expand All @@ -1218,7 +1219,7 @@ func (f *fakeSnappyBackend) StopServices(svcs []*snap.AppInfo, reason snap.Servi
return f.maybeErrForLastOp()
}

func (f *fakeSnappyBackend) QueryDisabledServices(info *snap.Info, meter progress.Meter) ([]string, error) {
func (f *fakeSnappyBackend) QueryDisabledServices(info *snap.Info, meter progress.Meter) (*wrappers.DisabledServices, error) {
var l []string

// return the disabled services as disabled and nothing else
Expand All @@ -1238,7 +1239,9 @@ func (f *fakeSnappyBackend) QueryDisabledServices(info *snap.Info, meter progres
disabledServices: f.servicesCurrentlyDisabled,
})

return l, f.maybeErrForLastOp()
return &wrappers.DisabledServices{
SystemServices: l,
}, f.maybeErrForLastOp()
}

func (f *fakeSnappyBackend) UndoSetupSnap(s snap.PlaceInfo, typ snap.Type, installRecord *backend.InstallRecord, dev snap.Device, p progress.Meter) error {
Expand Down
12 changes: 7 additions & 5 deletions overlord/snapstate/handlers.go
Original file line number Diff line number Diff line change
Expand Up @@ -1324,7 +1324,7 @@ func (m *SnapManager) undoMountSnap(t *state.Task, _ *tomb.Tomb) error {
// Note this function takes a snap info rather than snapst because there are
// situations where we want to call this on non-current snap infos, i.e. in the
// undo handlers, see undoLinkSnap for an example.
func (m *SnapManager) queryDisabledServices(info *snap.Info, pb progress.Meter) ([]string, error) {
func (m *SnapManager) queryDisabledServices(info *snap.Info, pb progress.Meter) (*wrappers.DisabledServices, error) {
return m.backend.QueryDisabledServices(info, pb)
}

Expand Down Expand Up @@ -3055,7 +3055,9 @@ func (m *SnapManager) startSnapServices(t *state.Task, _ *tomb.Tomb) error {
pb := NewTaskProgressAdapterUnlocked(t)

st.Unlock()
err = m.backend.StartServices(startupOrdered, svcsToDisable, pb, perfTimings)
err = m.backend.StartServices(startupOrdered, &wrappers.DisabledServices{
SystemServices: svcsToDisable,
}, pb, perfTimings)
st.Lock()

return err
Expand Down Expand Up @@ -3169,7 +3171,7 @@ func (m *SnapManager) stopSnapServices(t *state.Task, _ *tomb.Tomb) error {
// no longer present.
snapst.LastActiveDisabledServices = append(
snapst.LastActiveDisabledServices,
disabledServices...,
disabledServices.SystemServices...,
)

// reset services tracked by operations from hooks
Expand Down Expand Up @@ -3215,13 +3217,13 @@ func (m *SnapManager) undoStopSnapServices(t *state.Task, _ *tomb.Tomb) error {
snapst.LastActiveDisabledServices = lastActiveDisabled
Set(st, snapsup.InstanceName(), snapst)

var disabledServices []string
var disabledServices wrappers.DisabledServices
if err := t.Get("disabled-services", &disabledServices); err != nil && !errors.Is(err, state.ErrNoState) {
return err
}

st.Unlock()
err = m.backend.StartServices(startupOrdered, disabledServices, progress.Null, perfTimings)
err = m.backend.StartServices(startupOrdered, &disabledServices, progress.Null, perfTimings)
st.Lock()
if err != nil {
return err
Expand Down
6 changes: 4 additions & 2 deletions overlord/snapstate/snapstate_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -7484,9 +7484,11 @@ func (s *snapmgrTestSuite) TestStopSnapServicesUndo(c *C) {
c.Check(t.Get("old-last-active-disabled-services", &oldDisabledSvcs), IsNil)
c.Check(oldDisabledSvcs, DeepEquals, []string{"old-svc"})

var disabled []string
var disabled wrappers.DisabledServices
c.Check(t.Get("disabled-services", &disabled), IsNil)
c.Check(disabled, DeepEquals, []string{"svc1"})
c.Check(disabled, DeepEquals, wrappers.DisabledServices{
SystemServices: []string{"svc1"},
})
}

func (s *snapmgrTestSuite) TestStopSnapServicesErrInUndo(c *C) {
Expand Down
1 change: 0 additions & 1 deletion usersession/client/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -465,7 +465,6 @@ func (us *ServiceUnitStatus) SystemdUnitStatus() *systemd.UnitStatus {
func (client *Client) ServiceStatus(ctx context.Context, services []string) (map[int][]ServiceUnitStatus, map[int][]ServiceFailure, error) {
q := make(url.Values)
q.Add("services", strings.Join(services, ","))

responses, err := client.doMany(ctx, "GET", "/v1/service-status", q, nil, nil)
if err != nil {
return nil, nil, err
Expand Down
61 changes: 44 additions & 17 deletions wrappers/services.go
Original file line number Diff line number Diff line change
Expand Up @@ -223,7 +223,7 @@ type StartServicesFlags struct {
// StartServices starts service units for the applications from the snap which
// are services. Service units will be started in the order provided by the
// caller.
func StartServices(apps []*snap.AppInfo, disabledSvcs []string, flags *StartServicesFlags, inter Interacter, tm timings.Measurer) (err error) {
func StartServices(apps []*snap.AppInfo, disabledSvcs *DisabledServices, flags *StartServicesFlags, inter Interacter, tm timings.Measurer) (err error) {
if flags == nil {
flags = &StartServicesFlags{}
}
Expand Down Expand Up @@ -289,6 +289,11 @@ func StartServices(apps []*snap.AppInfo, disabledSvcs []string, flags *StartServ
toEnableUser = append(toEnableUser, svcs...)
}
}

isSystemSvcDisabled := func(name string) bool {
return disabledSvcs != nil && strutil.ListContains(disabledSvcs.SystemServices, name)
}

// first, gather all socket and timer units
for _, app := range apps {
if !app.IsService() {
Expand All @@ -298,7 +303,7 @@ func StartServices(apps []*snap.AppInfo, disabledSvcs []string, flags *StartServ
if !flags.Scope.matches(app.DaemonScope) {
continue
}
if strutil.ListContains(disabledSvcs, app.Name) {
if isSystemSvcDisabled(app.Name) {
continue
}
// Get all units for the service, but we only deal with
Expand Down Expand Up @@ -326,7 +331,7 @@ func StartServices(apps []*snap.AppInfo, disabledSvcs []string, flags *StartServ
if serviceIsActivated(app) {
continue
}
if strutil.ListContains(disabledSvcs, app.Name) {
if isSystemSvcDisabled(app.Name) {
continue
}
svcName := app.ServiceName()
Expand Down Expand Up @@ -1213,28 +1218,50 @@ func RestartServices(apps []*snap.AppInfo, explicitServices []string,
return nil
}

// DisabledServices represents an overview of which services in a snap
// are currently disabled, both of system services and user services.
// User services are indexed by the system uid as user services may run
// in one instance per user.
type DisabledServices struct {
SystemServices []string
UserServices map[int][]string
}

func disabledServiceNames(sts []*internal.ServiceStatus) []string {
// add all disabled services to the list
var names []string
for _, st := range sts {
if !st.IsEnabled() {
names = append(names, st.Name())
}
}

// sort for easier testing
sort.Strings(names)
return names
}

// QueryDisabledServices returns a list of all currently disabled snap services
// in the snap.
func QueryDisabledServices(info *snap.Info, pb progress.Meter) ([]string, error) {
func QueryDisabledServices(info *snap.Info, pb progress.Meter) (*DisabledServices, error) {
sysd := systemd.New(systemd.SystemMode, pb)

// TODO: support user-daemons being reported back here, as it will be possible
// for services to have different enablement status on different users.
sts, _, err := internal.QueryServiceStatusMany(info.Services(), sysd)
ssts, usts, err := internal.QueryServiceStatusMany(info.Services(), sysd)
if err != nil {
return nil, err
}

// add all disabled services to the list
disabledSnapSvcs := []string{}
for _, st := range sts {
if !st.IsEnabled() {
disabledSnapSvcs = append(disabledSnapSvcs, st.Name())
// Build a new map of the disabled service strings instead
// of the internal service status objects
var userSvcs map[int][]string
if len(usts) > 0 {
userSvcs = make(map[int][]string, len(usts))
for uid, sts := range usts {
userSvcs[uid] = disabledServiceNames(sts)
}
}

// sort for easier testing
sort.Strings(disabledSnapSvcs)

return disabledSnapSvcs, nil
return &DisabledServices{
SystemServices: disabledServiceNames(ssts),
UserServices: userSvcs,
}, nil
}
Loading

0 comments on commit 521e904

Please sign in to comment.