diff options
| author | Michael Vogt <mvo@ubuntu.com> | 2018-07-19 19:04:50 +0200 |
|---|---|---|
| committer | Michael Vogt <mvo@ubuntu.com> | 2018-07-19 19:04:50 +0200 |
| commit | 99a0c4e19350eed194ea46102391ab02ac939160 (patch) | |
| tree | c1a6eeadb28d80de2d122e83d377d872c75e19d5 | |
| parent | 68b834b8520342bf3e32cc14af60ab0261e35f12 (diff) | |
| parent | f95fcbd8d1a6f7e0882529a90ff0cc5b38615536 (diff) | |
Merge remote-tracking branch 'upstream/master' into no-degraded-bootno-degraded-boot
26 files changed, 629 insertions, 194 deletions
diff --git a/client/client.go b/client/client.go index 264285f97c..193ca6bb44 100644 --- a/client/client.go +++ b/client/client.go @@ -374,6 +374,7 @@ const ( ErrorKindTwoFactorRequired = "two-factor-required" ErrorKindTwoFactorFailed = "two-factor-failed" ErrorKindLoginRequired = "login-required" + ErrorKindInvalidAuthData = "invalid-auth-data" ErrorKindTermsNotAccepted = "terms-not-accepted" ErrorKindNoPaymentMethods = "no-payment-methods" ErrorKindPaymentDeclined = "payment-declined" @@ -382,6 +383,7 @@ const ( ErrorKindSnapAlreadyInstalled = "snap-already-installed" ErrorKindSnapNotInstalled = "snap-not-installed" ErrorKindSnapNotFound = "snap-not-found" + ErrorKindAppNotFound = "app-not-found" ErrorKindSnapLocal = "snap-local" ErrorKindSnapNeedsDevMode = "snap-needs-devmode" ErrorKindSnapNeedsClassic = "snap-needs-classic" @@ -396,9 +398,11 @@ const ( ErrorKindNotSnap = "snap-not-a-snap" - ErrorKindNetworkTimeout = "network-timeout" + ErrorKindNetworkTimeout = "network-timeout" + ErrorKindInterfacesUnchanged = "interfaces-unchanged" + ErrorKindBadQuery = "bad-query" ErrorKindConfigNoSuchOption = "option-not-found" ErrorKindSystemRestart = "system-restart" diff --git a/cmd/snap/cmd_interface.go b/cmd/snap/cmd_interface.go index 2a171f72c0..acb249c306 100644 --- a/cmd/snap/cmd_interface.go +++ b/cmd/snap/cmd_interface.go @@ -28,7 +28,6 @@ import ( "github.com/snapcore/snapd/client" "github.com/snapcore/snapd/i18n" - "github.com/snapcore/snapd/snap" "github.com/jessevdk/go-flags" ) @@ -122,9 +121,9 @@ func (x *cmdInterface) showOneInterface(iface *client.Interface) { labelPart = fmt.Sprintf(" (%s)", plug.Label) } if plug.Name == iface.Name { - fmt.Fprintf(w, " - %s%s", snap.UseNick(plug.Snap), labelPart) + fmt.Fprintf(w, " - %s%s", plug.Snap, labelPart) } else { - fmt.Fprintf(w, ` - %s:%s%s`, snap.UseNick(plug.Snap), plug.Name, labelPart) + fmt.Fprintf(w, ` - %s:%s%s`, plug.Snap, plug.Name, labelPart) } // Print a colon which will make the snap:plug element a key-value // yaml object so that we can write the attributes. @@ -144,9 +143,9 @@ func (x *cmdInterface) showOneInterface(iface *client.Interface) { labelPart = fmt.Sprintf(" (%s)", slot.Label) } if slot.Name == iface.Name { - fmt.Fprintf(w, " - %s%s", snap.UseNick(slot.Snap), labelPart) + fmt.Fprintf(w, " - %s%s", slot.Snap, labelPart) } else { - fmt.Fprintf(w, ` - %s:%s%s`, snap.UseNick(slot.Snap), slot.Name, labelPart) + fmt.Fprintf(w, ` - %s:%s%s`, slot.Snap, slot.Name, labelPart) } // Print a colon which will make the snap:slot element a key-value // yaml object so that we can write the attributes. diff --git a/cmd/snap/cmd_interface_test.go b/cmd/snap/cmd_interface_test.go index 043ddd3577..27ebb2011f 100644 --- a/cmd/snap/cmd_interface_test.go +++ b/cmd/snap/cmd_interface_test.go @@ -174,7 +174,7 @@ func (s *SnapSuite) TestInterfaceDetails(c *C) { {Snap: "deepin-music", Name: "network"}, {Snap: "http", Name: "network"}, }, - Slots: []client.Slot{{Snap: "core", Name: "network"}}, + Slots: []client.Slot{{Snap: "system", Name: "network"}}, }}, }) }) diff --git a/cmd/snap/cmd_interfaces.go b/cmd/snap/cmd_interfaces.go index ca0260738d..5946f84ee2 100644 --- a/cmd/snap/cmd_interfaces.go +++ b/cmd/snap/cmd_interfaces.go @@ -23,7 +23,6 @@ import ( "fmt" "github.com/snapcore/snapd/i18n" - "github.com/snapcore/snapd/snap" "github.com/jessevdk/go-flags" ) @@ -89,12 +88,12 @@ func (x *cmdInterfaces) Execute(args []string) error { for _, slot := range ifaces.Slots { if wantedSnap != "" { var ok bool - if wantedSnap == slot.Snap || wantedSnap == snap.UseNick(slot.Snap) { + if wantedSnap == slot.Snap { ok = true } for i := 0; i < len(slot.Connections) && !ok; i++ { - if wantedSnap == slot.Connections[i].Snap || wantedSnap == snap.UseNick(slot.Connections[i].Snap) { + if wantedSnap == slot.Connections[i].Snap { ok = true } } @@ -110,7 +109,7 @@ func (x *cmdInterfaces) Execute(args []string) error { } // The OS snap is special and enable abbreviated // display syntax on the slot-side of the connection. - if slot.Snap == "core" || slot.Snap == "ubuntu-core" || slot.Snap == snap.UseNick("core") { + if slot.Snap == "system" { fmt.Fprintf(w, ":%s\t", slot.Name) } else { fmt.Fprintf(w, "%s:%s\t", slot.Snap, slot.Name) @@ -135,7 +134,7 @@ func (x *cmdInterfaces) Execute(args []string) error { // plug, the loop below focuses on printing just the disconnected plugs. for _, plug := range ifaces.Plugs { if wantedSnap != "" { - if wantedSnap != plug.Snap && wantedSnap != snap.UseNick(plug.Snap) { + if wantedSnap != plug.Snap { continue } } diff --git a/cmd/snap/cmd_interfaces_test.go b/cmd/snap/cmd_interfaces_test.go index d58b2317b2..be70c107c3 100644 --- a/cmd/snap/cmd_interfaces_test.go +++ b/cmd/snap/cmd_interfaces_test.go @@ -278,7 +278,7 @@ func (s *SnapSuite) TestConnectionsOsSnapSlots(c *C) { "result": client.Connections{ Slots: []client.Slot{ { - Snap: "core", + Snap: "system", Name: "network-listening", Interface: "network-listening", Label: "Ability to be a network service", @@ -302,7 +302,7 @@ func (s *SnapSuite) TestConnectionsOsSnapSlots(c *C) { Label: "Ability to be a network service", Connections: []client.SlotRef{ { - Snap: "core", + Snap: "system", Name: "network-listening", }, }, @@ -314,7 +314,7 @@ func (s *SnapSuite) TestConnectionsOsSnapSlots(c *C) { Label: "Ability to be a network service", Connections: []client.SlotRef{ { - Snap: "core", + Snap: "system", Name: "network-listening", }, }, @@ -438,7 +438,7 @@ func (s *SnapSuite) TestConnectionsOfSystemNicknameSnap(c *C) { "result": client.Connections{ Slots: []client.Slot{ { - Snap: "core", + Snap: "system", Name: "core-support", Interface: "some-iface", Connections: []client.PlugRef{{Snap: "core", Name: "core-support-plug"}}, @@ -453,13 +453,13 @@ func (s *SnapSuite) TestConnectionsOfSystemNicknameSnap(c *C) { Snap: "core", Name: "core-support-plug", Interface: "some-iface", - Connections: []client.SlotRef{{Snap: "core", Name: "core-support"}}, + Connections: []client.SlotRef{{Snap: "system", Name: "core-support"}}, }, }, }, }) }) - rest, err := Parser().ParseArgs([]string{"interfaces", "core"}) + rest, err := Parser().ParseArgs([]string{"interfaces", "system"}) c.Assert(err, IsNil) c.Assert(rest, DeepEquals, []string{}) expectedStdout := "" + diff --git a/cmd/snap/main.go b/cmd/snap/main.go index 3fdf107f92..f6da78a05a 100644 --- a/cmd/snap/main.go +++ b/cmd/snap/main.go @@ -386,6 +386,19 @@ func (e *exitStatus) Error() string { return fmt.Sprintf("internal error: exitStatus{%d} being handled as normal error", e.code) } +var wrongDashes = string([]rune{ + 0x2010, // hyphen + 0x2011, // non-breaking hyphen + 0x2012, // figure dash + 0x2013, // en dash + 0x2014, // em dash + 0x2015, // horizontal bar + 0xfe58, // small em dash + 0x2015, // figure dash + 0x2e3a, // two-em dash + 0x2e3b, // three-em dash +}) + func run() error { parser := Parser() _, err := parser.Parse() @@ -404,6 +417,19 @@ func run() error { } msg, err := errorToCmdMessage("", err, nil) + + if cmdline := strings.Join(os.Args, " "); strings.ContainsAny(cmdline, wrongDashes) { + // TRANSLATORS: the %+q is the commandline (+q means quoted, with any non-ascii character called out). Please keep the lines to at most 80 characters. + fmt.Fprintf(Stderr, i18n.G(`Your command included some characters that look like dashes but are not: + %+q +in some situations you might find that when copying from an online source such +as a blog you need to replace “typographic” dashes and quotes with their ASCII +equivalent. Dashes in particular are homoglyphs on most terminals and in most +fixed-width fonts, so it can be hard to tell. + +`), cmdline) + } + if err != nil { return err } diff --git a/daemon/api.go b/daemon/api.go index 9a1ea19891..8b5823fb69 100644 --- a/daemon/api.go +++ b/daemon/api.go @@ -1649,7 +1649,7 @@ func splitQS(qs string) []string { func getSnapConf(c *Command, r *http.Request, user *auth.UserState) Response { vars := muxVars(r) - snapName := snap.DropNick(vars["name"]) + snapName := configstate.RemapSnapFromRequest(vars["name"]) keys := splitQS(r.URL.Query().Get("keys")) @@ -1700,7 +1700,7 @@ func getSnapConf(c *Command, r *http.Request, user *auth.UserState) Response { func setSnapConf(c *Command, r *http.Request, user *auth.UserState) Response { vars := muxVars(r) - snapName := snap.DropNick(vars["name"]) + snapName := configstate.RemapSnapFromRequest(vars["name"]) var patchValues map[string]interface{} if err := jsonutil.DecodeWithNumber(r.Body, &patchValues); err != nil { @@ -1745,7 +1745,7 @@ func getInterfaces(c *Command, r *http.Request, user *auth.UserState) Response { if pselect != "all" && pselect != "connected" { return BadRequest("unsupported select qualifier") } - var names []string + var names []string // Interface names namesStr := q.Get("names") if namesStr != "" { names = strings.Split(namesStr, ",") @@ -1760,12 +1760,13 @@ func getInterfaces(c *Command, r *http.Request, user *auth.UserState) Response { // Query the interface repository (this returns []*interface.Info). infos := c.d.overlord.InterfaceManager().Repository().Info(opts) infoJSONs := make([]*interfaceJSON, 0, len(infos)) + for _, info := range infos { // Convert interfaces.Info into interfaceJSON plugs := make([]*plugJSON, 0, len(info.Plugs)) for _, plug := range info.Plugs { plugs = append(plugs, &plugJSON{ - Snap: plug.Snap.InstanceName(), + Snap: ifacestate.RemapSnapToResponse(plug.Snap.InstanceName()), Name: plug.Name, Attrs: plug.Attrs, Label: plug.Label, @@ -1774,7 +1775,7 @@ func getInterfaces(c *Command, r *http.Request, user *auth.UserState) Response { slots := make([]*slotJSON, 0, len(info.Slots)) for _, slot := range info.Slots { slots = append(slots, &slotJSON{ - Snap: slot.Snap.InstanceName(), + Snap: ifacestate.RemapSnapToResponse(slot.Snap.InstanceName()), Name: slot.Name, Attrs: slot.Attrs, Label: slot.Label, @@ -1796,15 +1797,16 @@ func getLegacyConnections(c *Command, r *http.Request, user *auth.UserState) Res ifaces := repo.Interfaces() var ifjson interfaceJSON - plugConns := map[string][]interfaces.SlotRef{} slotConns := map[string][]interfaces.PlugRef{} - for _, conn := range ifaces.Connections { - plugRef := conn.PlugRef.String() - slotRef := conn.SlotRef.String() - plugConns[plugRef] = append(plugConns[plugRef], conn.SlotRef) - slotConns[slotRef] = append(slotConns[slotRef], conn.PlugRef) + for _, cref := range ifaces.Connections { + plugRef := interfaces.PlugRef{Snap: ifacestate.RemapSnapToResponse(cref.PlugRef.Snap), Name: cref.PlugRef.Name} + slotRef := interfaces.SlotRef{Snap: ifacestate.RemapSnapToResponse(cref.SlotRef.Snap), Name: cref.SlotRef.Name} + plugID := plugRef.String() + slotID := slotRef.String() + plugConns[plugID] = append(plugConns[plugID], slotRef) + slotConns[slotID] = append(slotConns[slotID], plugRef) } for _, plug := range ifaces.Plugs { @@ -1812,14 +1814,15 @@ func getLegacyConnections(c *Command, r *http.Request, user *auth.UserState) Res for _, app := range plug.Apps { apps = append(apps, app.Name) } + plugRef := interfaces.PlugRef{Snap: ifacestate.RemapSnapToResponse(plug.Snap.InstanceName()), Name: plug.Name} pj := &plugJSON{ - Snap: plug.Snap.InstanceName(), - Name: plug.Name, + Snap: plugRef.Snap, + Name: plugRef.Name, Interface: plug.Interface, Attrs: plug.Attrs, Apps: apps, Label: plug.Label, - Connections: plugConns[plug.String()], + Connections: plugConns[plugRef.String()], } ifjson.Plugs = append(ifjson.Plugs, pj) } @@ -1828,15 +1831,15 @@ func getLegacyConnections(c *Command, r *http.Request, user *auth.UserState) Res for _, app := range slot.Apps { apps = append(apps, app.Name) } - + slotRef := interfaces.SlotRef{Snap: ifacestate.RemapSnapToResponse(slot.Snap.InstanceName()), Name: slot.Name} sj := &slotJSON{ - Snap: slot.Snap.InstanceName(), - Name: slot.Name, + Snap: slotRef.Snap, + Name: slotRef.Name, Interface: slot.Interface, Attrs: slot.Attrs, Apps: apps, Label: slot.Label, - Connections: slotConns[slot.String()], + Connections: slotConns[slotRef.String()], } ifjson.Slots = append(ifjson.Slots, sj) } @@ -1895,10 +1898,10 @@ func changeInterfaces(c *Command, r *http.Request, user *auth.UserState) Respons defer st.Unlock() for i := range a.Plugs { - a.Plugs[i].Snap = snap.DropNick(a.Plugs[i].Snap) + a.Plugs[i].Snap = ifacestate.RemapSnapFromRequest(a.Plugs[i].Snap) } for i := range a.Slots { - a.Slots[i].Snap = snap.DropNick(a.Slots[i].Snap) + a.Slots[i].Snap = ifacestate.RemapSnapFromRequest(a.Slots[i].Snap) } switch a.Action { diff --git a/daemon/api_test.go b/daemon/api_test.go index eff7965beb..e0582317e1 100644 --- a/daemon/api_test.go +++ b/daemon/api_test.go @@ -3665,11 +3665,28 @@ func snapList(rawSnaps interface{}) []map[string]interface{} { return snaps } +// inverseCaseMapper implements SnapMapper to use lower case internally and upper case externally. +type inverseCaseMapper struct { + ifacestate.IdentityMapper // Embed the identity mapper to reuse empty state mapping functions. +} + +func (m *inverseCaseMapper) RemapSnapFromRequest(snapName string) string { + return strings.ToLower(snapName) +} + +func (m *inverseCaseMapper) RemapSnapToResponse(snapName string) string { + return strings.ToUpper(snapName) +} + // Tests for GET /v2/interfaces -func (s *apiSuite) TestInterfaces(c *check.C) { - revert := builtin.MockInterface(&ifacetest.TestInterface{InterfaceName: "test"}) - defer revert() +func (s *apiSuite) TestInterfacesLegacy(c *check.C) { + restore := builtin.MockInterface(&ifacetest.TestInterface{InterfaceName: "test"}) + defer restore() + // Install an inverse case mapper to exercise the interface mapping at the same time. + restore = ifacestate.MockSnapMapper(&inverseCaseMapper{}) + defer restore() + d := s.daemon(c) s.mockSnap(c, consumerYaml) @@ -3695,27 +3712,27 @@ func (s *apiSuite) TestInterfaces(c *check.C) { "result": map[string]interface{}{ "plugs": []interface{}{ map[string]interface{}{ - "snap": "consumer", + "snap": "CONSUMER", "plug": "plug", "interface": "test", "attrs": map[string]interface{}{"key": "value"}, "apps": []interface{}{"app"}, "label": "label", "connections": []interface{}{ - map[string]interface{}{"snap": "producer", "slot": "slot"}, + map[string]interface{}{"snap": "PRODUCER", "slot": "slot"}, }, }, }, "slots": []interface{}{ map[string]interface{}{ - "snap": "producer", + "snap": "PRODUCER", "slot": "slot", "interface": "test", "attrs": map[string]interface{}{"key": "value"}, "apps": []interface{}{"app"}, "label": "label", "connections": []interface{}{ - map[string]interface{}{"snap": "consumer", "plug": "plug"}, + map[string]interface{}{"snap": "CONSUMER", "plug": "plug"}, }, }, }, @@ -3726,93 +3743,58 @@ func (s *apiSuite) TestInterfaces(c *check.C) { }) } -/** -// Tests for GET /v2/interface (note: singular!) +func (s *apiSuite) TestInterfacesModern(c *check.C) { + restore := builtin.MockInterface(&ifacetest.TestInterface{InterfaceName: "test"}) + defer restore() + // Install an inverse case mapper to exercise the interface mapping at the same time. + restore = ifacestate.MockSnapMapper(&inverseCaseMapper{}) + defer restore() -func (s *apiSuite) TestInterfaceIndex(c *check.C) { d := s.daemon(c) - s.mockIface(c, &ifacetest.TestInterface{ - InterfaceName: "test", - InterfaceStaticInfo: interfaces.StaticInfo{ - Summary: "summary", - }, - }) s.mockSnap(c, consumerYaml) s.mockSnap(c, producerYaml) repo := d.overlord.InterfaceManager().Repository() - connRef := interfaces.ConnRef{ + connRef := &interfaces.ConnRef{ PlugRef: interfaces.PlugRef{Snap: "consumer", Name: "plug"}, SlotRef: interfaces.SlotRef{Snap: "producer", Name: "slot"}, } - c.Assert(repo.Connect(connRef), check.IsNil) - - req, err := http.NewRequest("GET", "/v2/interface", nil) + _, err := repo.Connect(connRef, nil, nil, nil) c.Assert(err, check.IsNil) - rec := httptest.NewRecorder() - interfaceIndexCmd.GET(interfaceIndexCmd, req, nil).ServeHTTP(rec, req) - c.Check(rec.Code, check.Equals, 200) - var body map[string]interface{} - err = json.Unmarshal(rec.Body.Bytes(), &body) - c.Check(err, check.IsNil) - // The body contains large number of interface names, ensure that just the - // test one, added above, exists. - c.Check(body["result"], testutil.DeepContains, map[string]interface{}{ - "name": "test", - "summary": "summary", - "used": true, - }) - c.Check(body["status"], check.Equals, "OK") - c.Check(body["status-code"], check.Equals, 200.0) - c.Check(body["type"], check.Equals, "sync") -} - -// Tests for GET /v2/interface/test - -func (s *apiSuite) TestInterfaceDetail(c *check.C) { - _ = s.daemon(c) - s.mockIface(c, &ifacetest.TestInterface{ - InterfaceName: "test", - InterfaceStaticInfo: interfaces.StaticInfo{ - Summary: "summary", - }, - }) - s.mockSnap(c, consumerYaml) - s.mockSnap(c, producerYaml) - - // NOTE: this is confusing, we must set s.vars manually, - s.vars = map[string]string{"name": "test"} - req, err := http.NewRequest("GET", "/v2/interface/test", nil) + req, err := http.NewRequest("GET", "/v2/interfaces?select=connected&doc=true&plugs=true&slots=true", nil) c.Assert(err, check.IsNil) rec := httptest.NewRecorder() - interfaceDetailCmd.GET(interfaceDetailCmd, req, nil).ServeHTTP(rec, req) + interfacesCmd.GET(interfacesCmd, req, nil).ServeHTTP(rec, req) c.Check(rec.Code, check.Equals, 200) var body map[string]interface{} err = json.Unmarshal(rec.Body.Bytes(), &body) c.Check(err, check.IsNil) c.Check(body, check.DeepEquals, map[string]interface{}{ - "result": map[string]interface{}{ - "name": "test", - "summary": "summary", - "plugs": []interface{}{ - map[string]interface{}{ - "snap": "consumer", - "plug": "plug", - "label": "label", - "attrs": map[string]interface{}{"key": "value"}, - }, - }, - "slots": []interface{}{ - map[string]interface{}{ - "snap": "producer", - "slot": "slot", - "label": "label", - "attrs": map[string]interface{}{"key": "value"}, + "result": []interface{}{ + map[string]interface{}{ + "name": "test", + "plugs": []interface{}{ + map[string]interface{}{ + "snap": "CONSUMER", + "plug": "plug", + "label": "label", + "attrs": map[string]interface{}{ + "key": "value", + }, + }}, + "slots": []interface{}{ + map[string]interface{}{ + "snap": "PRODUCER", + "slot": "slot", + "label": "label", + "attrs": map[string]interface{}{ + "key": "value", + }, + }, }, }, - "used": true, }, "status": "OK", "status-code": 200.0, @@ -3820,36 +3802,15 @@ func (s *apiSuite) TestInterfaceDetail(c *check.C) { }) } -func (s *apiSuite) TestInterfaceDetail404(c *check.C) { - _ = s.daemon(c) - - // NOTE: this is confusing, we must set s.vars manually, - s.vars = map[string]string{"name": "test"} - req, err := http.NewRequest("GET", "/v2/interface/test", nil) - c.Assert(err, check.IsNil) - rec := httptest.NewRecorder() - interfaceDetailCmd.GET(interfaceDetailCmd, req, nil).ServeHTTP(rec, req) - c.Check(rec.Code, check.Equals, 404) - var body map[string]interface{} - err = json.Unmarshal(rec.Body.Bytes(), &body) - c.Check(err, check.IsNil) - c.Check(body, check.DeepEquals, map[string]interface{}{ - "result": map[string]interface{}{ - "message": `cannot find interface named "test"`, - }, - "status": "Not Found", - "status-code": 404.0, - "type": "error", - }) -} - -**/ - // Test for POST /v2/interfaces func (s *apiSuite) TestConnectPlugSuccess(c *check.C) { - revert := builtin.MockInterface(&ifacetest.TestInterface{InterfaceName: "test"}) - defer revert() + restore := builtin.MockInterface(&ifacetest.TestInterface{InterfaceName: "test"}) + defer restore() + // Install an inverse case mapper to exercise the interface mapping at the same time. + restore = ifacestate.MockSnapMapper(&inverseCaseMapper{}) + defer restore() + d := s.daemon(c) s.mockSnap(c, consumerYaml) @@ -3860,8 +3821,8 @@ func (s *apiSuite) TestConnectPlugSuccess(c *check.C) { action := &interfaceAction{ Action: "connect", - Plugs: []plugJSON{{Snap: "consumer", Name: "plug"}}, - Slots: []slotJSON{{Snap: "producer", Name: "slot"}}, + Plugs: []plugJSON{{Snap: "CONSUMER", Name: "plug"}}, + Slots: []slotJSON{{Snap: "PRODUCER", Name: "slot"}}, } text, err := json.Marshal(action) c.Assert(err, check.IsNil) @@ -4059,8 +4020,11 @@ func (s *apiSuite) TestConnectCoreSystemAlias(c *check.C) { } func (s *apiSuite) testDisconnect(c *check.C, plugSnap, plugName, slotSnap, slotName string) { - revert := builtin.MockInterface(&ifacetest.TestInterface{InterfaceName: "test"}) - defer revert() + restore := builtin.MockInterface(&ifacetest.TestInterface{InterfaceName: "test"}) + defer restore() + // Install an inverse case mapper to exercise the interface mapping at the same time. + restore = ifacestate.MockSnapMapper(&inverseCaseMapper{}) + defer restore() d := s.daemon(c) s.mockSnap(c, consumerYaml) @@ -4113,15 +4077,15 @@ func (s *apiSuite) testDisconnect(c *check.C, plugSnap, plugName, slotSnap, slot } func (s *apiSuite) TestDisconnectPlugSuccess(c *check.C) { - s.testDisconnect(c, "consumer", "plug", "producer", "slot") + s.testDisconnect(c, "CONSUMER", "plug", "PRODUCER", "slot") } func (s *apiSuite) TestDisconnectPlugSuccessWithEmptyPlug(c *check.C) { - s.testDisconnect(c, "", "", "producer", "slot") + s.testDisconnect(c, "", "", "PRODUCER", "slot") } func (s *apiSuite) TestDisconnectPlugSuccessWithEmptySlot(c *check.C) { - s.testDisconnect(c, "consumer", "plug", "", "") + s.testDisconnect(c, "CONSUMER", "plug", "", "") } func (s *apiSuite) TestDisconnectPlugFailureNoSuchPlug(c *check.C) { diff --git a/overlord/configstate/configstate.go b/overlord/configstate/configstate.go index 8cd49fab2a..a5281d91eb 100644 --- a/overlord/configstate/configstate.go +++ b/overlord/configstate/configstate.go @@ -120,3 +120,19 @@ func Configure(st *state.State, snapName string, patch map[string]interface{}, f task := hookstate.HookTask(st, summary, hooksup, contextData) return state.NewTaskSet(task) } + +// RemapSnapFromRequest renames a snap as received from an API request +func RemapSnapFromRequest(snapName string) string { + if snapName == "system" { + return "core" + } + return snapName +} + +// RemapSnapToResponse renames a snap as about to be sent from an API response +func RemapSnapToResponse(snapName string) string { + if snapName == "core" { + return "system" + } + return snapName +} diff --git a/overlord/configstate/configstate_test.go b/overlord/configstate/configstate_test.go index 51f5b6cc6b..d78effb5b4 100644 --- a/overlord/configstate/configstate_test.go +++ b/overlord/configstate/configstate_test.go @@ -302,3 +302,20 @@ func (s *configcoreHijackSuite) TestHijack(c *C) { c.Check(chg.Err(), IsNil) c.Check(configcoreRan, Equals, true) } + +type miscSuite struct{} + +var _ = Suite(&miscSuite{}) + +func (s *miscSuite) TestRemappingFuncs(c *C) { + // We don't change those. + c.Assert(configstate.RemapSnapFromRequest("foo"), Equals, "foo") + c.Assert(configstate.RemapSnapFromRequest("snapd"), Equals, "snapd") + c.Assert(configstate.RemapSnapFromRequest("core"), Equals, "core") + c.Assert(configstate.RemapSnapToResponse("foo"), Equals, "foo") + c.Assert(configstate.RemapSnapToResponse("snapd"), Equals, "snapd") + + // This is the one we alter. + c.Assert(configstate.RemapSnapFromRequest("system"), Equals, "core") + c.Assert(configstate.RemapSnapToResponse("core"), Equals, "system") +} diff --git a/overlord/ifacestate/export_test.go b/overlord/ifacestate/export_test.go index 57eebed295..3f824f4ac4 100644 --- a/overlord/ifacestate/export_test.go +++ b/overlord/ifacestate/export_test.go @@ -32,6 +32,8 @@ var ( CheckConnectConflicts = checkConnectConflicts FindSymmetricAutoconnect = findSymmetricAutoconnect ConnectPriv = connect + GetConns = getConns + SetConns = setConns ) // AddForeignTaskHandlers registers handlers for tasks handled outside of the @@ -55,3 +57,11 @@ func MockContentLinkRetryTimeout(d time.Duration) (restore func()) { contentLinkRetryTimeout = d return func() { contentLinkRetryTimeout = old } } + +// UpperCaseConnState returns a canned connection state map. +// This allows us to keep connState private and still write some tests for it. +func UpperCaseConnState() map[string]connState { + return map[string]connState{ + "APP:network CORE:network": {Auto: true, Interface: "network"}, + } +} diff --git a/overlord/ifacestate/helpers.go b/overlord/ifacestate/helpers.go index e92fd5e81a..d19bc0660e 100644 --- a/overlord/ifacestate/helpers.go +++ b/overlord/ifacestate/helpers.go @@ -457,7 +457,9 @@ func getPlugAndSlotRefs(task *state.Task) (interfaces.PlugRef, interfaces.SlotRe return plugRef, slotRef, nil } -// Get information about connections from the state +// getConns returns information about connections from the state. +// +// Connections are transparently re-mapped according to remapIncomingConnRef func getConns(st *state.State) (conns map[string]connState, err error) { err = st.Get("conns", &conns) if err != nil && err != state.ErrNoState { @@ -466,11 +468,35 @@ func getConns(st *state.State) (conns map[string]connState, err error) { if conns == nil { conns = make(map[string]connState) } - return conns, nil + remapped := make(map[string]connState, len(conns)) + for id, cstate := range conns { + cref, err := interfaces.ParseConnRef(id) + if err != nil { + return nil, err + } + cref.PlugRef.Snap = RemapSnapFromState(cref.PlugRef.Snap) + cref.SlotRef.Snap = RemapSnapFromState(cref.SlotRef.Snap) + remapped[cref.ID()] = cstate + } + return remapped, nil } +// setConns sets information about connections in the state. +// +// Connections are transparently re-mapped according to remapOutgoingConnRef func setConns(st *state.State, conns map[string]connState) { - st.Set("conns", conns) + remapped := make(map[string]connState, len(conns)) + for id, cstate := range conns { + cref, err := interfaces.ParseConnRef(id) + if err != nil { + // We cannot fail here + panic(err) + } + cref.PlugRef.Snap = RemapSnapToState(cref.PlugRef.Snap) + cref.SlotRef.Snap = RemapSnapToState(cref.SlotRef.Snap) + remapped[cref.ID()] = cstate + } + st.Set("conns", remapped) } // snapsWithSecurityProfiles returns all snaps that have active @@ -529,7 +555,8 @@ func snapsWithSecurityProfiles(st *state.State) ([]*snap.Info, error) { func resolveSnapIDToName(st *state.State, snapID string) (name string, err error) { if snapID == "system" { - return snap.DropNick(snapID), nil + // Resolve the system nickname to a concrete snap. + return mapper.RemapSnapFromRequest(snapID), nil } decl, err := assertstate.SnapDeclaration(st, snapID) if asserts.IsNotFound(err) { @@ -541,6 +568,164 @@ func resolveSnapIDToName(st *state.State, snapID string) (name string, err error return decl.SnapName(), nil } +// SnapMapper offers APIs for re-mapping snap names in interfaces and the +// configuration system. The mapper is designed to apply transformations around +// the edges of snapd (state interactions and API interactions) to offer one +// view on the inside of snapd and another view on the outside. +type SnapMapper interface { + // re-map functions for loading and saving objects in the state. + RemapSnapFromState(snapName string) string + RemapSnapToState(snapName string) string + // re-map functions for API requests/responses. + RemapSnapFromRequest(snapName string) string + RemapSnapToResponse(snapName string) string +} + +// IdentityMapper implements SnapMapper and performs no transformations at all. +type IdentityMapper struct{} + +// RemapSnapFromState doesn't change the snap name in any way. +func (m *IdentityMapper) RemapSnapFromState(snapName string) string { + return snapName +} + +// RemapSnapToState doesn't change the snap name in any way. +func (m *IdentityMapper) RemapSnapToState(snapName string) string { + return snapName +} + +// RemapSnapFromRequest doesn't change the snap name in any way. +func (m *IdentityMapper) RemapSnapFromRequest(snapName string) string { + return snapName +} + +// RemapSnapToResponse doesn't change the snap name in any way. +func (m *IdentityMapper) RemapSnapToResponse(snapName string) string { + return snapName +} + +// CoreCoreSystemMapper implements SnapMapper and makes implicit slots +// appear to be on "core" in the state and in memory but as "system" in the API. +// +// NOTE: This mapper can be used to prepare, as an intermediate step, for the +// transition to "snapd" mapper. Using it the state and API layer will look +// exactly the same as with the "snapd" mapper. This can be used to make any +// necessary adjustments the test suite. +type CoreCoreSystemMapper struct { + IdentityMapper // Embedding the identity mapper allows us to cut on boilerplate. +} + +// RemapSnapFromRequest renames the "system" snap to the "core" snap. +// +// This allows us to accept connection and disconnection requests that +// explicitly refer to "core" or using the "system" nickname. +func (m *CoreCoreSystemMapper) RemapSnapFromRequest(snapName string) string { + if snapName == "system" { + return "core" + } + return snapName +} + +// RemapSnapToResponse renames the "core" snap to the "system" snap. +// +// This allows us to make all the implicitly defined slots, that are really +// associated with the "core" snap to seemingly occupy the "system" snap +// instead. +func (m *CoreCoreSystemMapper) RemapSnapToResponse(snapName string) string { + if snapName == "core" { + return "system" + } + return snapName +} + +// CoreSnapdSystemMapper implements SnapMapper and makes implicit slots +// appear to be on "core" in the state and on "system" in the API while they +// are on "snapd" in memory. +type CoreSnapdSystemMapper struct { + IdentityMapper // Embedding the identity mapper allows us to cut on boilerplate. +} + +// RemapSnapFromState renames the "core" snap to the "snapd" snap. +// +// This allows modern snapd to load an old state that remembers connections +// between slots on the "core" snap and other snaps. In memory we are actually +// using "snapd" snap for hosting those slots and this lets us stay compatible. +func (m *CoreSnapdSystemMapper) RemapSnapFromState(snapName string) string { + if snapName == "core" { + return "snapd" + } + return snapName +} + +// RemapSnapToState renames the "snapd" snap to the "core" snap. +// +// This allows the state to stay backwards compatible as all the connections +// seem to refer to the "core" snap, as in pre core{16,18} days where there was +// only one core snap. +func (m *CoreSnapdSystemMapper) RemapSnapToState(snapName string) string { + if snapName == "snapd" { + return "core" + } + return snapName +} + +// RemapSnapFromRequest renames the "core" or "system" snaps to the "snapd" snap. +// +// This allows us to accept connection and disconnection requests that +// explicitly refer to "core" or "system" even though we really want them to +// refer to "snapd". Note that this is not fully symmetric with +// RemapSnapToResponse as we explicitly always talk about "system" snap, +// even if the request used "core". +func (m *CoreSnapdSystemMapper) RemapSnapFromRequest(snapName string) string { + if snapName == "system" || snapName == "core" { + return "snapd" + } + return snapName +} + +// RemapSnapToResponse renames the "snapd" snap to the "system" snap. +// +// This allows us to make all the implicitly defined slots, that are really +// associated with the "snapd" snap to seemingly occupy the "system" snap +// instead. This ties into the concept of using "system" as a nickname (e.g. in +// gadget snap connections). +func (m *CoreSnapdSystemMapper) RemapSnapToResponse(snapName string) string { + if snapName == "snapd" { + return "system" + } + return snapName +} + +// mapper contains the currently active snap mapper. +var mapper SnapMapper = &CoreCoreSystemMapper{} + +// MockSnapMapper mocks the currently used snap mapper. +func MockSnapMapper(new SnapMapper) (restore func()) { + old := mapper + mapper = new + return func() { mapper = old } +} + +// RemapSnapFromState renames a snap when loaded from state according to the current mapper. +func RemapSnapFromState(snapName string) string { + return mapper.RemapSnapFromState(snapName) +} + +// RemapSnapToState renames a snap when saving to state according to the current mapper. +func RemapSnapToState(snapName string) string { + return mapper.RemapSnapToState(snapName) +} + +// RemapSnapFromRequest renames a snap as received from an API request according to the current mapper. +func RemapSnapFromRequest(snapName string) string { + return mapper.RemapSnapFromRequest(snapName) +} + +// RemapSnapToResponse renames a snap as about to be sent from an API response according to the current mapper. +func RemapSnapToResponse(snapName string) string { + return mapper.RemapSnapToResponse(snapName) +} + func connectDisconnectAffectedSnaps(t *state.Task) ([]string, error) { plugRef, slotRef, err := getPlugAndSlotRefs(t) if err != nil { diff --git a/overlord/ifacestate/helpers_test.go b/overlord/ifacestate/helpers_test.go new file mode 100644 index 0000000000..5d99913d7b --- /dev/null +++ b/overlord/ifacestate/helpers_test.go @@ -0,0 +1,162 @@ +// -*- 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 ifacestate_test + +import ( + "strings" + + . "gopkg.in/check.v1" + + "github.com/snapcore/snapd/overlord/ifacestate" + "github.com/snapcore/snapd/overlord/state" +) + +type helpersSuite struct { + st *state.State +} + +var _ = Suite(&helpersSuite{}) + +func (s *helpersSuite) SetUpTest(c *C) { + s.st = state.New(nil) +} + +func (s *helpersSuite) TestIdentityMapper(c *C) { + var m ifacestate.SnapMapper = &ifacestate.IdentityMapper{} + + // Nothing is altered. + c.Assert(m.RemapSnapFromState("example"), Equals, "example") + c.Assert(m.RemapSnapToState("example"), Equals, "example") + c.Assert(m.RemapSnapFromRequest("example"), Equals, "example") + c.Assert(m.RemapSnapToResponse("example"), Equals, "example") +} + +func (s *helpersSuite) TestCoreCoreSystemMapper(c *C) { + var m ifacestate.SnapMapper = &ifacestate.CoreCoreSystemMapper{} + + // Snaps are not renamed when interacting with the state. + c.Assert(m.RemapSnapFromState("core"), Equals, "core") + c.Assert(m.RemapSnapToState("core"), Equals, "core") + + // The "core" snap is renamed to the "system" in API response + // and back in the API requests. + c.Assert(m.RemapSnapFromRequest("system"), Equals, "core") + c.Assert(m.RemapSnapToResponse("core"), Equals, "system") + + // Other snap names are unchanged. + c.Assert(m.RemapSnapFromState("potato"), Equals, "potato") + c.Assert(m.RemapSnapToState("potato"), Equals, "potato") + c.Assert(m.RemapSnapFromRequest("potato"), Equals, "potato") + c.Assert(m.RemapSnapToResponse("potato"), Equals, "potato") +} + +func (s *helpersSuite) TestCoreSnapdSystemMapper(c *C) { + var m ifacestate.SnapMapper = &ifacestate.CoreSnapdSystemMapper{} + + // The "snapd" snap is renamed to the "core" in when saving the state + // and back when loading the state. + c.Assert(m.RemapSnapFromState("core"), Equals, "snapd") + c.Assert(m.RemapSnapToState("snapd"), Equals, "core") + + // The "snapd" snap is renamed to the "system" in API response and back in + // the API requests. + c.Assert(m.RemapSnapFromRequest("system"), Equals, "snapd") + c.Assert(m.RemapSnapToResponse("snapd"), Equals, "system") + + // The "core" snap is also renamed to "snapd" in API requests, for + // compatibility. + c.Assert(m.RemapSnapFromRequest("core"), Equals, "snapd") + + // Other snap names are unchanged. + c.Assert(m.RemapSnapFromState("potato"), Equals, "potato") + c.Assert(m.RemapSnapToState("potato"), Equals, "potato") + c.Assert(m.RemapSnapFromRequest("potato"), Equals, "potato") + c.Assert(m.RemapSnapToResponse("potato"), Equals, "potato") +} + +// caseMapper implements SnapMapper to use upper case internally and lower case externally. +type caseMapper struct{} + +func (m *caseMapper) RemapSnapFromState(snapName string) string { + return strings.ToUpper(snapName) +} + +func (m *caseMapper) RemapSnapToState(snapName string) string { + return strings.ToLower(snapName) +} + +func (m *caseMapper) RemapSnapFromRequest(snapName string) string { + return strings.ToUpper(snapName) +} + +func (m *caseMapper) RemapSnapToResponse(snapName string) string { + return strings.ToLower(snapName) +} + +func (s *helpersSuite) TestMappingFunctions(c *C) { + restore := ifacestate.MockSnapMapper(&caseMapper{}) + defer restore() + + c.Assert(ifacestate.RemapSnapFromState("example"), Equals, "EXAMPLE") + c.Assert(ifacestate.RemapSnapToState("EXAMPLE"), Equals, "example") + c.Assert(ifacestate.RemapSnapFromRequest("example"), Equals, "EXAMPLE") + c.Assert(ifacestate.RemapSnapToResponse("EXAMPLE"), Equals, "example") +} + +func (s *helpersSuite) TestGetConns(c *C) { + s.st.Lock() + defer s.st.Unlock() + s.st.Set("conns", map[string]interface{}{ + "app:network core:network": map[string]interface{}{ + "auto": true, + "interface": "network", + }, + }) + + restore := ifacestate.MockSnapMapper(&caseMapper{}) + defer restore() + + conns, err := ifacestate.GetConns(s.st) + c.Assert(err, IsNil) + for id, connState := range conns { + c.Assert(id, Equals, "APP:network CORE:network") + c.Assert(connState.Auto, Equals, true) + c.Assert(connState.Interface, Equals, "network") + } +} + +func (s *helpersSuite) TestSetConns(c *C) { + s.st.Lock() + defer s.st.Unlock() + + restore := ifacestate.MockSnapMapper(&caseMapper{}) + defer restore() + + // This has upper-case data internally, see export_test.go + ifacestate.SetConns(s.st, ifacestate.UpperCaseConnState()) + var conns map[string]interface{} + err := s.st.Get("conns", &conns) + c.Assert(err, IsNil) + c.Assert(conns, DeepEquals, map[string]interface{}{ + "app:network core:network": map[string]interface{}{ + "auto": true, + "interface": "network", + }}) +} diff --git a/packaging/arch/PKGBUILD b/packaging/arch/PKGBUILD index 239ba7f2d9..2a8b4e4b12 100644 --- a/packaging/arch/PKGBUILD +++ b/packaging/arch/PKGBUILD @@ -10,7 +10,7 @@ pkgname=snapd pkgdesc="Service and tools for management of snap packages." depends=('squashfs-tools' 'libseccomp' 'libsystemd') optdepends=('bash-completion: bash completion support') -pkgver=2.34 +pkgver=2.34.2 pkgrel=1 arch=('x86_64') url="https://github.com/snapcore/snapd" diff --git a/packaging/fedora/snapd.spec b/packaging/fedora/snapd.spec index f59848f33f..84c44906bb 100644 --- a/packaging/fedora/snapd.spec +++ b/packaging/fedora/snapd.spec @@ -73,7 +73,7 @@ %endif Name: snapd -Version: 2.34 +Version: 2.34.2 Release: 0%{?dist} Summary: A transactional software package manager Group: System Environment/Base @@ -733,6 +733,18 @@ fi %changelog +* Thu Jul 19 2018 Michael Vogt <mvo@ubuntu.com> + - packaging: fix bogus date in fedora snapd.spec + - tests: fix tests expecting old email address + +* Tue Jul 17 2018 Michael Vogt <mvo@ubuntu.com> + - tests: cherry-pick test fixes from master for 2.34 + - coreconfig: add support for `snap set system network.disable- + ipv6` + - debian: do not ship snapd.apparmor.service on ubuntu + - overlord/snapstate: dedupe default content providers + - interfaces/builtin: create can-bus interface + * Fri Jul 06 2018 Michael Vogt <mvo@ubuntu.com> - New upstream release 2.34 - store, daemon, client, cmd/snap: expose "scope", default to wide* @@ -1392,7 +1404,7 @@ fi UbuntuStore(Repository)? references - store: reorg auth refresh -* Tue May 16 2018 Michael Vogt <mvo@ubuntu.com> +* Wed May 16 2018 Michael Vogt <mvo@ubuntu.com> - New upstream release 2.32.9 - tests: run all spread tests inside GCE - tests: build spread in the autopkgtests with a more recent go diff --git a/packaging/opensuse/snapd.changes b/packaging/opensuse/snapd.changes index e809da5edf..573e91660c 100644 --- a/packaging/opensuse/snapd.changes +++ b/packaging/opensuse/snapd.changes @@ -1,4 +1,14 @@ ------------------------------------------------------------------- +Thu Jul 19 12:05:50 UTC 2018 - mvo@fastmail.fm + +- Update to upstream release 2.34.2 + +------------------------------------------------------------------- +Wed Jul 17 19:46:56 UTC 2018 - mvo@fastmail.fm + +- Update to upstream release 2.34.1 + +------------------------------------------------------------------- Fri Jul 06 16:08:17 UTC 2018 - mvo@fastmail.fm - Update to upstream release 2.34 @@ -17,7 +27,7 @@ Fri Jun 22 14:25:35 UTC 2018 - me@zygoon.pl - Load snap-confine apparmor profile in post, if apparmor is enabled - Adjust badness of polkit-untracked-privlege ------------------------------------------------------------------- -Fri Jun 21 17:37:56 UTC 2018 - mvo@fastmail.fm +Thu Jun 21 17:37:56 UTC 2018 - mvo@fastmail.fm - Update to upstream release 2.33.1 diff --git a/packaging/opensuse/snapd.spec b/packaging/opensuse/snapd.spec index 8db9b790a9..d502ef0a98 100644 --- a/packaging/opensuse/snapd.spec +++ b/packaging/opensuse/snapd.spec @@ -61,7 +61,7 @@ %global snap_mount_dir /snap Name: snapd -Version: 2.34 +Version: 2.34.2 Release: 0 Summary: Tools enabling systems to work with .snap files License: GPL-3.0 diff --git a/packaging/ubuntu-14.04/changelog b/packaging/ubuntu-14.04/changelog index 86ac5dda00..e62339ad5d 100644 --- a/packaging/ubuntu-14.04/changelog +++ b/packaging/ubuntu-14.04/changelog @@ -1,3 +1,23 @@ +snapd (2.34.2~14.04) trusty; urgency=medium + + * New upstream release, LP: #1779403 + - packaging: fix bogus date in fedora snapd.spec + - tests: fix tests expecting old email address + + -- Michael Vogt <michael.vogt@ubuntu.com> Thu, 19 Jul 2018 12:05:50 +0200 + +snapd (2.34.1~14.04) trusty; urgency=medium + + * New upstream release, LP: #1779403 + - tests: cherry-pick test fixes from master for 2.34 + - coreconfig: add support for `snap set system network.disable- + ipv6` + - debian: do not ship snapd.apparmor.service on ubuntu + - overlord/snapstate: dedupe default content providers + - interfaces/builtin: create can-bus interface + + -- Michael Vogt <michael.vogt@ubuntu.com> Tue, 17 Jul 2018 19:46:56 +0200 + snapd (2.34~14.04) trusty; urgency=medium * New upstream release, LP: #1779403 diff --git a/packaging/ubuntu-16.04/changelog b/packaging/ubuntu-16.04/changelog index a54c56598c..cdea1c6785 100644 --- a/packaging/ubuntu-16.04/changelog +++ b/packaging/ubuntu-16.04/changelog @@ -1,3 +1,23 @@ +snapd (2.34.2) xenial; urgency=medium + + * New upstream release, LP: #1779403 + - packaging: fix bogus date in fedora snapd.spec + - tests: fix tests expecting old email address + + -- Michael Vogt <michael.vogt@ubuntu.com> Thu, 19 Jul 2018 12:05:50 +0200 + +snapd (2.34.1) xenial; urgency=medium + + * New upstream release, LP: #1779403 + - tests: cherry-pick test fixes from master for 2.34 + - coreconfig: add support for `snap set system network.disable- + ipv6` + - debian: do not ship snapd.apparmor.service on ubuntu + - overlord/snapstate: dedupe default content providers + - interfaces/builtin: create can-bus interface + + -- Michael Vogt <michael.vogt@ubuntu.com> Tue, 17 Jul 2018 19:46:56 +0200 + snapd (2.34) xenial; urgency=medium * New upstream release, LP: #1779403 diff --git a/snap/info.go b/snap/info.go index b1ba386bf7..143e0969ea 100644 --- a/snap/info.go +++ b/snap/info.go @@ -999,24 +999,6 @@ func JoinSnapApp(snap, app string) string { return fmt.Sprintf("%s.%s", snap, app) } -// UseNick returns the nickname for given snap name. If there is none, returns -// the original name. -func UseNick(snapName string) string { - if snapName == "core" { - return "system" - } - return snapName -} - -// DropNick returns the snap name for given nickname. If there is none, returns -// the original name. -func DropNick(nick string) string { - if nick == "system" { - return "core" - } - return nick -} - // InstanceSnap splits the instance name and returns the name of the snap. func InstanceSnap(instanceName string) string { snapName, _ := SplitInstanceName(instanceName) diff --git a/snap/info_test.go b/snap/info_test.go index 35eaa78277..2856144c9b 100644 --- a/snap/info_test.go +++ b/snap/info_test.go @@ -1206,16 +1206,6 @@ func (s *infoSuite) TestStopModeTypeKillSignal(c *C) { } } -func (s *infoSuite) TestNickname(c *C) { - c.Check(snap.UseNick("core"), Equals, "system") - c.Check(snap.UseNick("system"), Equals, "system") - c.Check(snap.UseNick("foo"), Equals, "foo") - - c.Check(snap.DropNick("core"), Equals, "core") - c.Check(snap.DropNick("system"), Equals, "core") - c.Check(snap.DropNick("foo"), Equals, "foo") -} - func (s *infoSuite) TestSplitInstanceName(c *C) { snapName, instanceKey := snap.SplitInstanceName("foo_bar") c.Check(snapName, Equals, "foo") diff --git a/tests/lib/snaps/test-snapd-policy-app-provider-classic/meta/snap.yaml b/tests/lib/snaps/test-snapd-policy-app-provider-classic/meta/snap.yaml index d5d56f6562..37f2abbcaf 100644 --- a/tests/lib/snaps/test-snapd-policy-app-provider-classic/meta/snap.yaml +++ b/tests/lib/snaps/test-snapd-policy-app-provider-classic/meta/snap.yaml @@ -18,6 +18,7 @@ slots: interface: dbus bus: system name: test.system + fwupd: null location-control: null location-observe: null lxd: null @@ -48,6 +49,9 @@ apps: docker: command: bin/run slots: [ docker ] + fwupd: + command: bin/run + slots: [ fwupd ] location-control: command: bin/run slots: [ location-control ] diff --git a/tests/lib/snaps/test-snapd-policy-app-provider-core/meta/snap.yaml b/tests/lib/snaps/test-snapd-policy-app-provider-core/meta/snap.yaml index 9a46426528..9eed9f1a63 100644 --- a/tests/lib/snaps/test-snapd-policy-app-provider-core/meta/snap.yaml +++ b/tests/lib/snaps/test-snapd-policy-app-provider-core/meta/snap.yaml @@ -43,6 +43,8 @@ slots: unity8-calendar: null unity8-contacts: null upower-observe: null + wayland: null + x11: null apps: avahi-control: @@ -129,3 +131,9 @@ apps: upower-observe: command: bin/run slots: [ upower-observe ] + wayland: + command: bin/run + slots: [ wayland ] + x11: + command: bin/run + slots: [ x11 ] diff --git a/tests/main/install-errors/task.yaml b/tests/main/install-errors/task.yaml index aba8928ce2..399ff877f4 100644 --- a/tests/main/install-errors/task.yaml +++ b/tests/main/install-errors/task.yaml @@ -81,3 +81,10 @@ execute: | fi MATCH 'error: snap "pi2-kernel" is not available on stable for this architecture' < stderr.out fi + + echo "Install a snap with suspicious characters in its name" + if snap install atom ––classic 2>stderr.out; then + echo "snap install atom ––classic should have failed but did not" + exit 1 + fi + MATCH 'characters that look like dashes but are not' < stderr.out diff --git a/tests/main/snap-info/check.py b/tests/main/snap-info/check.py index 501ac2eaff..b406a2624b 100644 --- a/tests/main/snap-info/check.py +++ b/tests/main/snap-info/check.py @@ -73,7 +73,7 @@ check("basic-desktop", res[1], check("test-snapd-tools", res[2], ("name", equals, "test-snapd-tools"), ("publisher", equals, "canonical"), - ("contact", equals, "snappy-canonical-storeaccount@canonical.com"), + ("contact", equals, "snaps@canonical.com"), ("summary", equals, "Tools for testing the snapd application"), ("description", equals, "A tool to test snapd\n"), ("commands", exists), @@ -87,13 +87,13 @@ check("test-snapd-tools", res[2], ("edge", matches, verRevNotesRx("-")), ), ("snap-id", equals, snap_ids["test-snapd-tools"]), - ("license", equals, "unset"), # TODO: update once snap.yaml contains the right license + ("license", matches, r"(unknown|unset)"), # TODO: update once snap.yaml contains the right license ) check("test-snapd-devmode", res[3], ("name", equals, "test-snapd-devmode"), ("publisher", equals, "canonical"), - ("contact", equals, "snappy-canonical-storeaccount@canonical.com"), + ("contact", equals, "snaps@canonical.com"), ("summary", equals, "Basic snap with devmode confinement"), ("description", equals, "A basic buildable snap that asks for devmode confinement\n"), ("tracking", equals, "beta"), @@ -106,7 +106,7 @@ check("test-snapd-devmode", res[3], ("edge", matches, verRevNotesRx("devmode")), ), ("snap-id", equals, snap_ids["test-snapd-devmode"]), - ("license", equals, "unset"), # TODO: update once snap.yaml contains the right license + ("license", matches, r"(unknown|unset)"), # TODO: update once snap.yaml contains the right license ) check("core", res[4], @@ -124,7 +124,7 @@ check("core", res[4], # sideload "core" ("contact", maybe), ("snap-id", maybe), - ("license", equals, "unset"), # TODO: update once snap.yaml contains the right license + ("license", matches, r"(unknown|unset)"), # TODO: update once snap.yaml contains the right license ) check("error", res[5], @@ -135,7 +135,7 @@ check("error", res[5], check("test-snapd-python-webserver", res[6], ("name", equals, "test-snapd-python-webserver"), ("publisher", equals, "canonical"), - ("contact", equals, "snappy-canonical-storeaccount@canonical.com"), + ("contact", equals, "snaps@canonical.com"), ("summary", exists), ("description", exists), ("channels", exists), diff --git a/tests/main/snap-run-hook/task.yaml b/tests/main/snap-run-hook/task.yaml index 8616fcb9a8..37ebcb38b1 100644 --- a/tests/main/snap-run-hook/task.yaml +++ b/tests/main/snap-run-hook/task.yaml @@ -8,12 +8,9 @@ environment: ENVDUMP: /var/snap/basic-hooks/current/hooks-env prepare: | - echo "Build test hooks package" - snap pack $TESTSLIB/snaps/basic-hooks - snap install --dangerous basic-hooks_1.0_all.snap - -restore: | - rm -f basic-hooks_1.0_all.snap + #shellcheck source=tests/lib/snaps.sh + . $TESTSLIB/snaps.sh + install_local basic-hooks execute: | # Note that `snap run` doesn't exit non-zero if the hook is missing, so we |
