Permalink
Switch branches/tags
Find file
Fetching contributors…
Cannot retrieve contributors at this time
117 lines (98 sloc) 3.61 KB
// -*- Mode: Go; indent-tabs-mode: t -*-
/*
* Copyright (C) 2016-2017 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 ifacestate
import (
"github.com/snapcore/snapd/interfaces"
"github.com/snapcore/snapd/interfaces/backends"
"github.com/snapcore/snapd/overlord/hookstate"
"github.com/snapcore/snapd/overlord/ifacestate/ifacerepo"
"github.com/snapcore/snapd/overlord/state"
)
// InterfaceManager is responsible for the maintenance of interfaces in
// the system state. It maintains interface connections, and also observes
// installed snaps to track the current set of available plugs and slots.
type InterfaceManager struct {
state *state.State
runner *state.TaskRunner
repo *interfaces.Repository
}
// Manager returns a new InterfaceManager.
// Extra interfaces can be provided for testing.
func Manager(s *state.State, hookManager *hookstate.HookManager, extraInterfaces []interfaces.Interface, extraBackends []interfaces.SecurityBackend) (*InterfaceManager, error) {
delayedCrossMgrInit()
// NOTE: hookManager is nil only when testing.
if hookManager != nil {
setupHooks(hookManager)
}
runner := state.NewTaskRunner(s)
m := &InterfaceManager{
state: s,
runner: runner,
repo: interfaces.NewRepository(),
}
if err := m.initialize(extraInterfaces, extraBackends); err != nil {
return nil, err
}
s.Lock()
ifacerepo.Replace(s, m.repo)
s.Unlock()
// interface tasks might touch more than the immediate task target snap, serialize them
runner.SetBlocked(func(_ *state.Task, running []*state.Task) bool {
return len(running) != 0
})
runner.AddHandler("connect", m.doConnect, nil)
runner.AddHandler("disconnect", m.doDisconnect, nil)
runner.AddHandler("setup-profiles", m.doSetupProfiles, m.undoSetupProfiles)
runner.AddHandler("remove-profiles", m.doRemoveProfiles, m.doSetupProfiles)
runner.AddHandler("discard-conns", m.doDiscardConns, m.undoDiscardConns)
// helper for ubuntu-core -> core
runner.AddHandler("transition-ubuntu-core", m.doTransitionUbuntuCore, m.undoTransitionUbuntuCore)
return m, nil
}
// Ensure implements StateManager.Ensure.
func (m *InterfaceManager) Ensure() error {
m.runner.Ensure()
return nil
}
// Wait implements StateManager.Wait.
func (m *InterfaceManager) Wait() {
m.runner.Wait()
}
// Stop implements StateManager.Stop.
func (m *InterfaceManager) Stop() {
m.runner.Stop()
}
// Repository returns the interface repository used internally by the manager.
//
// This method has two use-cases:
// - it is needed for setting up state in daemon tests
// - it is needed to return the set of known interfaces in the daemon api
//
// In the second case it is only informational and repository has internal
// locks to ensure consistency.
func (m *InterfaceManager) Repository() *interfaces.Repository {
return m.repo
}
// MockSecurityBackends mocks the list of security backends that are used for setting up security.
//
// This function is public because it is referenced in the daemon
func MockSecurityBackends(be []interfaces.SecurityBackend) func() {
old := backends.All
backends.All = be
return func() { backends.All = old }
}