-
Notifications
You must be signed in to change notification settings - Fork 562
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
interfaces/hotplug: add hotplug Specification and HotplugDeviceInfo #5416
Merged
Merged
Changes from all commits
Commits
Show all changes
22 commits
Select commit
Hold shift + click to select a range
275f7ad
Added hotplug Specification and HotplugDeviceInfo.
stolowski 280ed48
Merge branch 'master' into hotplug-device-info
stolowski 8163720
Merge branch 'master' into hotplug-device-info
stolowski 1edbf70
Review feedback.
stolowski 9a5f9da
Removed type HotplugDeviceHandler type definition for now.
stolowski 63b33d0
Updated HotPlugSpec.
stolowski 07adf32
Merge branch 'master' into hotplug-device-info
stolowski 7dd7efe
Merge branch 'master' into hotplug-device-info
stolowski e408116
Merge branch 'master' into hotplug-device-info
stolowski e3adc77
Merge branch 'master' into hotplug-device-info
stolowski 23e8ec6
Merge branch 'master' into hotplug-device-info
stolowski 06eb95c
Sort slots.
stolowski 4c637dd
Review comments.
stolowski 4c23113
More comments.
stolowski ee9c8b6
Made data private, added generic Attribute getter.
stolowski dc6a005
Added Definer type.
stolowski 4bff39a
Merge branch 'master' into hotplug-device-info
stolowski 7ceb603
Merge branch 'master' into hotplug-device-info
stolowski 9c027cf
Validate interface name in the hotplug spec.
stolowski 8d1b22d
Drop Object attribute from HotplugDeviceInfo. Use snap.ValidateSlotName.
stolowski 00276aa
Reverted the addition of ValidateName.
stolowski 237c82b
Check that DEVPATH exists.
stolowski File filter
Filter by extension
Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,87 @@ | ||
// -*- Mode: Go; indent-tabs-mode: t -*- | ||
|
||
/* | ||
* Copyright (C) 2018 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 hotplug | ||
|
||
import ( | ||
"fmt" | ||
"path/filepath" | ||
|
||
"github.com/snapcore/snapd/dirs" | ||
) | ||
|
||
// HotplugDeviceInfo carries information about added/removed device detected at runtime. | ||
type HotplugDeviceInfo struct { | ||
// map of all attributes returned for given uevent. | ||
data map[string]string | ||
} | ||
|
||
// NewHotplugDeviceInfo creates HotplugDeviceInfo structure related to udev add or remove event. | ||
func NewHotplugDeviceInfo(env map[string]string) (*HotplugDeviceInfo, error) { | ||
if _, ok := env["DEVPATH"]; !ok { | ||
return nil, fmt.Errorf("missing device path attribute") | ||
} | ||
return &HotplugDeviceInfo{ | ||
data: env, | ||
}, nil | ||
} | ||
|
||
// Returns the value of "SUBSYSTEM" attribute of the udev event associated with the device, e.g. "usb". | ||
// Subsystem value is always present. | ||
func (h *HotplugDeviceInfo) Subsystem() string { | ||
return h.data["SUBSYSTEM"] | ||
} | ||
|
||
// Returns full device path under /sysfs, e.g /sys/devices/pci0000:00/0000:00:14.0/usb1/1-2. | ||
// The path is derived from DEVPATH attribute of the udev event. | ||
func (h *HotplugDeviceInfo) DevicePath() string { | ||
// DEVPATH is guaranteed to exist (checked in the ctor). | ||
path, _ := h.Attribute("DEVPATH") | ||
return filepath.Join(dirs.SysfsDir, path) | ||
} | ||
|
||
// Returns the value of "MINOR" attribute of the udev event associated with the device. | ||
// The Minor value may be empty. | ||
func (h *HotplugDeviceInfo) Minor() string { | ||
return h.data["MINOR"] | ||
} | ||
|
||
// Returns the value of "MAJOR" attribute of the udev event associated with the device. | ||
// The Major value may be empty. | ||
func (h *HotplugDeviceInfo) Major() string { | ||
return h.data["MAJOR"] | ||
} | ||
|
||
// Returns the value of "DEVNAME" attribute of the udev event associated with the device, e.g. "ttyUSB0". | ||
// The DeviceName value may be empty. | ||
func (h *HotplugDeviceInfo) DeviceName() string { | ||
return h.data["DEVNAME"] | ||
} | ||
|
||
// Returns the value of "DEVTYPE" attribute of the udev event associated with the device, e.g. "usb_device". | ||
// The DeviceType value may be empty. | ||
func (h *HotplugDeviceInfo) DeviceType() string { | ||
return h.data["DEVTYPE"] | ||
} | ||
|
||
// Generic method for getting arbitrary attribute from the uevent data. | ||
func (h *HotplugDeviceInfo) Attribute(name string) (string, bool) { | ||
val, ok := h.data[name] | ||
return val, ok | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,98 @@ | ||
// -*- Mode: Go; indent-tabs-mode: t -*- | ||
|
||
/* | ||
* Copyright (C) 2018 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 hotplug | ||
|
||
import ( | ||
"path/filepath" | ||
"testing" | ||
|
||
. "gopkg.in/check.v1" | ||
|
||
"github.com/snapcore/snapd/dirs" | ||
"github.com/snapcore/snapd/testutil" | ||
) | ||
|
||
func Test(t *testing.T) { TestingT(t) } | ||
|
||
type hotplugSuite struct { | ||
testutil.BaseTest | ||
} | ||
|
||
var _ = Suite(&hotplugSuite{}) | ||
|
||
func (s *hotplugSuite) SetUpTest(c *C) { | ||
s.BaseTest.SetUpTest(c) | ||
dirs.SetRootDir(c.MkDir()) | ||
} | ||
|
||
func (s *hotplugSuite) TearDownTest(c *C) { | ||
s.BaseTest.TearDownTest(c) | ||
dirs.SetRootDir("") | ||
} | ||
|
||
func (s *hotplugSuite) TestBasicProperties(c *C) { | ||
env := map[string]string{ | ||
"DEVPATH": "/devices/pci0000:00/0000:00:14.0/usb2/2-3", "DEVNAME": "bus/usb/002/003", | ||
"DEVTYPE": "usb_device", | ||
"PRODUCT": "1d50/6108/0", "DEVNUM": "003", | ||
"SEQNUM": "4053", | ||
"ACTION": "add", "SUBSYSTEM": "usb", | ||
"MAJOR": "189", "MINOR": "130", | ||
"TYPE": "0/0/0", "BUSNUM": "002", | ||
} | ||
|
||
di, err := NewHotplugDeviceInfo(env) | ||
c.Assert(err, IsNil) | ||
|
||
c.Assert(di.DeviceName(), Equals, "bus/usb/002/003") | ||
c.Assert(di.DeviceType(), Equals, "usb_device") | ||
c.Assert(di.DevicePath(), Equals, filepath.Join(dirs.SysfsDir, "/devices/pci0000:00/0000:00:14.0/usb2/2-3")) | ||
c.Assert(di.Subsystem(), Equals, "usb") | ||
c.Assert(di.Major(), Equals, "189") | ||
c.Assert(di.Minor(), Equals, "130") | ||
|
||
minor, ok := di.Attribute("MINOR") | ||
c.Assert(ok, Equals, true) | ||
c.Assert(minor, Equals, "130") | ||
|
||
_, ok = di.Attribute("FOO") | ||
c.Assert(ok, Equals, false) | ||
} | ||
|
||
func (s *hotplugSuite) TestPropertiesMissing(c *C) { | ||
env := map[string]string{ | ||
"DEVPATH": "/devices/pci0000:00/0000:00:14.0/usb2/2-3", | ||
"ACTION": "add", "SUBSYSTEM": "usb", | ||
} | ||
|
||
di, err := NewHotplugDeviceInfo(map[string]string{}) | ||
c.Assert(err, NotNil) | ||
c.Assert(err, ErrorMatches, `missing device path attribute`) | ||
|
||
di, err = NewHotplugDeviceInfo(env) | ||
c.Assert(err, IsNil) | ||
|
||
c.Assert(di.DeviceName(), Equals, "") | ||
c.Assert(di.DeviceType(), Equals, "") | ||
c.Assert(di.DevicePath(), Equals, filepath.Join(dirs.SysfsDir, "/devices/pci0000:00/0000:00:14.0/usb2/2-3")) | ||
c.Assert(di.Subsystem(), Equals, "usb") | ||
c.Assert(di.Major(), Equals, "") | ||
c.Assert(di.Minor(), Equals, "") | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,93 @@ | ||
// -*- Mode: Go; indent-tabs-mode: t -*- | ||
|
||
/* | ||
* Copyright (C) 2018 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 hotplug | ||
|
||
import ( | ||
"fmt" | ||
"sort" | ||
|
||
"github.com/snapcore/snapd/interfaces/utils" | ||
"github.com/snapcore/snapd/snap" | ||
) | ||
|
||
// Definer can be implemented by interfaces that need to create slots in response to hotplug events | ||
type Definer interface { | ||
HotplugDeviceDetected(di *HotplugDeviceInfo, spec *Specification) error | ||
} | ||
|
||
// SlotSpec is a definition of the slot to create in response to udev event. | ||
type SlotSpec struct { | ||
// XXX: Name is the name the interface wants to give to the slot; we | ||
// might want to mediate this though (e.g. generate automatically), so this | ||
// may change/go away. | ||
Name string | ||
Label string | ||
Attrs map[string]interface{} | ||
} | ||
|
||
// Specification contains data about all slots that a hotplug interface wants to have created in response to uevent. | ||
type Specification struct { | ||
// slots are indexed by slot name to ensure unique names | ||
slots map[string]*SlotSpec | ||
} | ||
|
||
// NewSpecification creates an empty hotplug Specification. | ||
func NewSpecification() *Specification { | ||
return &Specification{ | ||
slots: make(map[string]*SlotSpec), | ||
} | ||
} | ||
|
||
// AddSlot adds a specification of a slot. | ||
func (h *Specification) AddSlot(slotSpec *SlotSpec) error { | ||
if _, ok := h.slots[slotSpec.Name]; ok { | ||
return fmt.Errorf("slot %q already exists", slotSpec.Name) | ||
} | ||
if err := snap.ValidateSlotName(slotSpec.Name); err != nil { | ||
return err | ||
} | ||
attrs := slotSpec.Attrs | ||
if attrs == nil { | ||
attrs = make(map[string]interface{}) | ||
} else { | ||
attrs = utils.CopyAttributes(slotSpec.Attrs) | ||
} | ||
h.slots[slotSpec.Name] = &SlotSpec{ | ||
Name: slotSpec.Name, | ||
Label: slotSpec.Label, | ||
Attrs: utils.NormalizeInterfaceAttributes(attrs).(map[string]interface{}), | ||
} | ||
return nil | ||
} | ||
|
||
// Slots returns specifications of all slots created by given interface. | ||
func (h *Specification) Slots() []*SlotSpec { | ||
keys := make([]string, 0, len(h.slots)) | ||
for k := range h.slots { | ||
keys = append(keys, k) | ||
} | ||
sort.Strings(keys) | ||
|
||
slots := make([]*SlotSpec, 0, len(h.slots)) | ||
for _, k := range keys { | ||
slots = append(slots, h.slots[k]) | ||
} | ||
return slots | ||
} |
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Do these need to be sorted or is it just to get a stable output for the tests?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It's about making it test friendly only.