diff options
| author | Pawel Stolowski <stolowski@gmail.com> | 2018-10-31 14:33:40 +0100 |
|---|---|---|
| committer | Pawel Stolowski <stolowski@gmail.com> | 2018-10-31 14:33:40 +0100 |
| commit | 3f5dc8c390da42d049369e4d571bf8eaa7b6d16f (patch) | |
| tree | aa156d7fd0f60d7a385a8a678abac52825b1bb46 | |
| parent | 0bb1673eca985d42e7ef00e45e4924ec147a7a74 (diff) | |
Hadle by-hotplug flag in Disconnect and mark connections removed by hotplug with hotplug-gone.disconnect-by-hotplug
| -rw-r--r-- | overlord/ifacestate/export_test.go | 5 | ||||
| -rw-r--r-- | overlord/ifacestate/handlers.go | 17 | ||||
| -rw-r--r-- | overlord/ifacestate/ifacestate.go | 4 | ||||
| -rw-r--r-- | overlord/ifacestate/ifacestate_test.go | 50 |
4 files changed, 74 insertions, 2 deletions
diff --git a/overlord/ifacestate/export_test.go b/overlord/ifacestate/export_test.go index a9a1ff947f..442db53eb2 100644 --- a/overlord/ifacestate/export_test.go +++ b/overlord/ifacestate/export_test.go @@ -31,6 +31,7 @@ var ( CheckAutoconnectConflicts = checkAutoconnectConflicts FindSymmetricAutoconnectTask = findSymmetricAutoconnectTask ConnectPriv = connect + DisconnectPriv = disconnectTasks GetConns = getConns SetConns = setConns DefaultDeviceKey = defaultDeviceKey @@ -49,6 +50,10 @@ func NewConnectOptsWithAutoSet() connectOpts { return connectOpts{AutoConnect: true, ByGadget: false} } +func NewDisconnectOptsWithByHotplugSet() disconnectOpts { + return disconnectOpts{ByHotplug: true} +} + func MockRemoveStaleConnections(f func(st *state.State) error) (restore func()) { old := removeStaleConnections removeStaleConnections = f diff --git a/overlord/ifacestate/handlers.go b/overlord/ifacestate/handlers.go index c3efcc2f84..cdb49742b8 100644 --- a/overlord/ifacestate/handlers.go +++ b/overlord/ifacestate/handlers.go @@ -504,17 +504,30 @@ func (m *InterfaceManager) doDisconnect(task *state.Task, _ *tomb.Tomb) error { if err := task.Get("auto-disconnect", &autoDisconnect); err != nil && err != state.ErrNoState { return fmt.Errorf("internal error: failed to read 'auto-disconnect' flag: %s", err) } - if conn.Auto && !autoDisconnect { + + // "by-hotplug" flag indicates it's a disconnect triggered by hotplug remove event; + // we want to keep information of the connection and just mark it as hotplug-gone. + var byHotplug bool + if err := task.Get("by-hotplug", &byHotplug); err != nil && err != state.ErrNoState { + return fmt.Errorf("internal error: cannot read 'by-hotplug' flag: %s", err) + } + + switch { + case byHotplug: + conn.HotplugGone = true + conns[cref.ID()] = conn + case conn.Auto && !autoDisconnect: conn.Undesired = true conn.DynamicPlugAttrs = nil conn.DynamicSlotAttrs = nil conn.StaticPlugAttrs = nil conn.StaticSlotAttrs = nil conns[cref.ID()] = conn - } else { + default: delete(conns, cref.ID()) } setConns(st, conns) + return nil } diff --git a/overlord/ifacestate/ifacestate.go b/overlord/ifacestate/ifacestate.go index dca0f577c5..8bd5a8734d 100644 --- a/overlord/ifacestate/ifacestate.go +++ b/overlord/ifacestate/ifacestate.go @@ -299,6 +299,7 @@ func Disconnect(st *state.State, conn *interfaces.Connection) (*state.TaskSet, e type disconnectOpts struct { AutoDisconnect bool + ByHotplug bool } // disconnectTasks creates a set of tasks for disconnect, including hooks, but does not do any conflict checking. @@ -330,6 +331,9 @@ func disconnectTasks(st *state.State, conn *interfaces.Connection, flags disconn if flags.AutoDisconnect { disconnectTask.Set("auto-disconnect", true) } + if flags.ByHotplug { + disconnectTask.Set("by-hotplug", true) + } ts := state.NewTaskSet() var prev *state.Task diff --git a/overlord/ifacestate/ifacestate_test.go b/overlord/ifacestate/ifacestate_test.go index cd68a858f2..677823e677 100644 --- a/overlord/ifacestate/ifacestate_test.go +++ b/overlord/ifacestate/ifacestate_test.go @@ -2951,6 +2951,56 @@ func (s *interfaceManagerSuite) TestDisconnectDisablesAutoConnect(c *C) { }) } +func (s *interfaceManagerSuite) TestDisconnectByHotplug(c *C) { + s.mockIfaces(c, &ifacetest.TestInterface{InterfaceName: "test"}) + consumerInfo := s.mockSnap(c, consumerYaml) + s.mockSnap(c, coreSnapYaml) + + s.state.Lock() + s.state.Set("conns", map[string]interface{}{ + "consumer:plug core:slot": map[string]interface{}{"interface": "test"}, + "consumer:plug core:slot2": map[string]interface{}{"interface": "test"}, + }) + s.state.Set("hotplug-slots", map[string]interface{}{ + "slot": map[string]interface{}{ + "name": "slot", + "interface": "test", + "hotplug-key": "1234", + }}) + s.state.Unlock() + + s.manager(c) + + s.state.Lock() + conn := &interfaces.Connection{ + Plug: interfaces.NewConnectedPlug(consumerInfo.Plugs["plug"], nil, nil), + Slot: interfaces.NewConnectedSlot(&snap.SlotInfo{Snap: &snap.Info{SuggestedName: "core"}, Name: "slot"}, nil, nil), + } + + ts, err := ifacestate.DisconnectPriv(s.state, conn, ifacestate.NewDisconnectOptsWithByHotplugSet()) + c.Assert(err, IsNil) + + change := s.state.NewChange("disconnect", "") + change.AddAll(ts) + s.state.Unlock() + + s.settle(c) + + s.state.Lock() + defer s.state.Unlock() + + c.Assert(change.Err(), IsNil) + c.Check(change.Status(), Equals, state.DoneStatus) + + var conns map[string]interface{} + err = s.state.Get("conns", &conns) + c.Assert(err, IsNil) + c.Check(conns, DeepEquals, map[string]interface{}{ + "consumer:plug core:slot": map[string]interface{}{"interface": "test", "hotplug-gone": true}, + "consumer:plug core:slot2": map[string]interface{}{"interface": "test"}, + }) +} + func (s *interfaceManagerSuite) TestManagerReloadsConnections(c *C) { s.mockIfaces(c, &ifacetest.TestInterface{InterfaceName: "test"}, &ifacetest.TestInterface{InterfaceName: "test2"}) s.mockSnap(c, consumerYaml) |
