client,cmd/snap: rename skills to interfaces (part 2) #523

Merged
merged 3 commits into from Feb 26, 2016
Jump to file or symbol
Failed to load files and symbols.
+284 −280
Split
View
@@ -0,0 +1,150 @@
+// -*- Mode: Go; indent-tabs-mode: t -*-
+
+/*
+ * Copyright (C) 2016 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 client
+
+import (
+ "bytes"
+ "encoding/json"
+)
+
+// Plug represents a capacity offered by a snap.
+type Plug struct {
+ Name string `json:"name"`
+ Snap string `json:"snap"`
+ // NOTE: json format intentionally using old "skill" terminology
@niemeyer

niemeyer Feb 25, 2016

Contributor

If the intention is to fix it in stages, that sounds fine, but the note should be:

// TODO Fix terminology in JSON.

As it is it sounds like a design decision.

@zyga

zyga Feb 26, 2016

Contributor

Yes, This is fixed in a later branch already.

+ Interface string `json:"type,omitempty"`
+ Attrs map[string]interface{} `json:"attrs,omitempty"`
+ Apps []string `json:"apps,omitempty"`
+ Label string `json:"label,omitempty"`
+}
+
+// Slot represents the potential of a given snap to connect to a given plug.
+type Slot struct {
+ Name string `json:"name"`
+ Snap string `json:"snap"`
+ // NOTE: json format intentionally using old "skill" terminology
+ Interface string `json:"type,omitempty"`
+ Attrs map[string]interface{} `json:"attrs,omitempty"`
+ Apps []string `json:"apps,omitempty"`
+ Label string `json:"label,omitempty"`
+}
+
+// PlugConnections represents a single plug and slots that are connected to it.
+type PlugConnections struct {
@niemeyer

niemeyer Feb 25, 2016

Contributor

The name is slightly awkward.. this is really a Plug. Do we need two types? What if we simply added Connections to Plug above?

@zyga

zyga Feb 26, 2016

Contributor

I'll look into it.

+ Plug
+ // NOTE: json format intentionally using old "skill" terminology
+ Connections []Slot `json:"granted_to"`
@niemeyer

niemeyer Feb 25, 2016

Contributor

This is not actually a Slot, though, as it misses pretty much all details. It should be something like SlotRef.

Fine to do that in the future, rather than during rename.

@zyga

zyga Feb 26, 2016

Contributor

Noted, I'll make that happen

+}
+
+// InterfaceAction represents an action performed on the interface system.
+type InterfaceAction struct {
+ Action string `json:"action"`
+ // NOTE: json format intentionally using old "skill" terminology
+ Plug *Plug `json:"skill,omitempty"`
+ Slot *Slot `json:"slot,omitempty"`
+}
+
+// AllPlugs returns information about all the plugs and their connections.
+func (client *Client) AllPlugs() (connections []PlugConnections, err error) {
+ err = client.doSync("GET", "/2.0/skills", nil, nil, &connections)
+ return
+}
+
+// performInterfaceAction performs a single action on the interface system.
+func (client *Client) performInterfaceAction(sa *InterfaceAction) error {
+ b, err := json.Marshal(sa)
+ if err != nil {
+ return err
+ }
+ var rsp interface{}
+ if err := client.doSync("POST", "/2.0/skills", nil, bytes.NewReader(b), &rsp); err != nil {
+ return err
+ }
+ return nil
+}
+
+// Connect establishes a connection between a plug and a slot.
+// The plug and the slot must have the same interface.
+func (client *Client) Connect(plugSnapName, plugName, slotSnapName, slotName string) error {
+ return client.performInterfaceAction(&InterfaceAction{
+ Action: "grant",
+ Plug: &Plug{
+ Snap: plugSnapName,
+ Name: plugName,
+ },
+ Slot: &Slot{
+ Snap: slotSnapName,
+ Name: slotName,
+ },
+ })
+}
+
+// Disconnect breaks the connection between a plug and a slot.
+func (client *Client) Disconnect(plugSnapName, plugName, slotSnapName, slotName string) error {
+ return client.performInterfaceAction(&InterfaceAction{
+ Action: "revoke",
+ Plug: &Plug{
+ Snap: plugSnapName,
+ Name: plugName,
+ },
+ Slot: &Slot{
+ Snap: slotSnapName,
+ Name: slotName,
+ },
+ })
+}
+
+// AddPlug adds a plug to the interface system.
+func (client *Client) AddPlug(plug *Plug) error {
+ return client.performInterfaceAction(&InterfaceAction{
+ Action: "add-skill",
+ Plug: plug,
+ })
+}
+
+// RemovePlug removes a plug from the interface system.
+func (client *Client) RemovePlug(snapName, plugName string) error {
+ return client.performInterfaceAction(&InterfaceAction{
+ Action: "remove-skill",
+ Plug: &Plug{
+ Snap: snapName,
+ Name: plugName,
+ },
+ })
+}
+
+// AddSlot adds a slot to the system.
+func (client *Client) AddSlot(slot *Slot) error {
+ return client.performInterfaceAction(&InterfaceAction{
+ Action: "add-slot",
+ Slot: slot,
+ })
+}
+
+// RemoveSlot removes a slot from the system.
+func (client *Client) RemoveSlot(snapName, slotName string) error {
+ return client.performInterfaceAction(&InterfaceAction{
+ Action: "remove-slot",
+ Slot: &Slot{
+ Snap: snapName,
+ Name: slotName,
+ },
+ })
+}
@@ -27,13 +27,13 @@ import (
"github.com/ubuntu-core/snappy/client"
)
-func (cs *clientSuite) TestClientAllSkillsCallsEndpoint(c *check.C) {
- _, _ = cs.cli.AllSkills()
+func (cs *clientSuite) TestClientAllPlugsCallsEndpoint(c *check.C) {
+ _, _ = cs.cli.AllPlugs()
c.Check(cs.req.Method, check.Equals, "GET")
c.Check(cs.req.URL.Path, check.Equals, "/2.0/skills")
}
-func (cs *clientSuite) TestClientAllSkills(c *check.C) {
+func (cs *clientSuite) TestClientAllPlugs(c *check.C) {
cs.rsp = `{
"type": "sync",
"result": [
@@ -48,17 +48,17 @@ func (cs *clientSuite) TestClientAllSkills(c *check.C) {
}
]
}`
- skills, err := cs.cli.AllSkills()
+ skills, err := cs.cli.AllPlugs()
c.Assert(err, check.IsNil)
- c.Check(skills, check.DeepEquals, []client.SkillGrants{
+ c.Check(skills, check.DeepEquals, []client.PlugConnections{
{
- Skill: client.Skill{
- Snap: "canonical-pi2",
- Name: "pin-13",
- Type: "bool-file",
- Label: "Pin 13",
+ Plug: client.Plug{
+ Snap: "canonical-pi2",
+ Name: "pin-13",
+ Interface: "bool-file",
+ Label: "Pin 13",
},
- GrantedTo: []client.Slot{
+ Connections: []client.Slot{
{
Snap: "keyboard-lights",
Name: "capslock-led",
@@ -68,18 +68,18 @@ func (cs *clientSuite) TestClientAllSkills(c *check.C) {
})
}
-func (cs *clientSuite) TestClientGrantCallsEndpoint(c *check.C) {
- _ = cs.cli.Grant("producer", "skill", "consumer", "slot")
+func (cs *clientSuite) TestClientConnectCallsEndpoint(c *check.C) {
+ _ = cs.cli.Connect("producer", "skill", "consumer", "slot")
c.Check(cs.req.Method, check.Equals, "POST")
c.Check(cs.req.URL.Path, check.Equals, "/2.0/skills")
}
-func (cs *clientSuite) TestClientGrant(c *check.C) {
+func (cs *clientSuite) TestClientConnect(c *check.C) {
cs.rsp = `{
"type": "sync",
"result": { }
}`
- err := cs.cli.Grant("producer", "skill", "consumer", "slot")
+ err := cs.cli.Connect("producer", "skill", "consumer", "slot")
c.Check(err, check.IsNil)
var body map[string]interface{}
decoder := json.NewDecoder(cs.req.Body)
@@ -98,18 +98,18 @@ func (cs *clientSuite) TestClientGrant(c *check.C) {
})
}
-func (cs *clientSuite) TestClientRevokeCallsEndpoint(c *check.C) {
- _ = cs.cli.Revoke("producer", "skill", "consumer", "slot")
+func (cs *clientSuite) TestClientDisconnectCallsEndpoint(c *check.C) {
+ _ = cs.cli.Disconnect("producer", "skill", "consumer", "slot")
c.Check(cs.req.Method, check.Equals, "POST")
c.Check(cs.req.URL.Path, check.Equals, "/2.0/skills")
}
-func (cs *clientSuite) TestClientRevoke(c *check.C) {
+func (cs *clientSuite) TestClientDisconnect(c *check.C) {
cs.rsp = `{
"type": "sync",
"result": { }
}`
- err := cs.cli.Revoke("producer", "skill", "consumer", "slot")
+ err := cs.cli.Disconnect("producer", "skill", "consumer", "slot")
c.Check(err, check.IsNil)
var body map[string]interface{}
decoder := json.NewDecoder(cs.req.Body)
@@ -128,21 +128,21 @@ func (cs *clientSuite) TestClientRevoke(c *check.C) {
})
}
-func (cs *clientSuite) TestClientAddSkillCallsEndpoint(c *check.C) {
- _ = cs.cli.AddSkill(&client.Skill{})
+func (cs *clientSuite) TestClientAddPlugCallsEndpoint(c *check.C) {
+ _ = cs.cli.AddPlug(&client.Plug{})
c.Check(cs.req.Method, check.Equals, "POST")
c.Check(cs.req.URL.Path, check.Equals, "/2.0/skills")
}
-func (cs *clientSuite) TestClientAddSkill(c *check.C) {
+func (cs *clientSuite) TestClientAddPlug(c *check.C) {
cs.rsp = `{
"type": "sync",
"result": { }
}`
- err := cs.cli.AddSkill(&client.Skill{
- Snap: "snap",
- Name: "name",
- Type: "type",
+ err := cs.cli.AddPlug(&client.Plug{
+ Snap: "snap",
+ Name: "name",
+ Interface: "type",
Attrs: map[string]interface{}{
"attr": "value",
},
@@ -169,18 +169,18 @@ func (cs *clientSuite) TestClientAddSkill(c *check.C) {
})
}
-func (cs *clientSuite) TestClientRemoveSkillCallsEndpoint(c *check.C) {
- _ = cs.cli.RemoveSkill("snap", "name")
+func (cs *clientSuite) TestClientRemovePlugCallsEndpoint(c *check.C) {
+ _ = cs.cli.RemovePlug("snap", "name")
c.Check(cs.req.Method, check.Equals, "POST")
c.Check(cs.req.URL.Path, check.Equals, "/2.0/skills")
}
-func (cs *clientSuite) TestClientRemoveSkill(c *check.C) {
+func (cs *clientSuite) TestClientRemovePlug(c *check.C) {
cs.rsp = `{
"type": "sync",
"result": { }
}`
- err := cs.cli.RemoveSkill("snap", "name")
+ err := cs.cli.RemovePlug("snap", "name")
c.Check(err, check.IsNil)
var body map[string]interface{}
decoder := json.NewDecoder(cs.req.Body)
@@ -207,9 +207,9 @@ func (cs *clientSuite) TestClientAddSlot(c *check.C) {
"result": { }
}`
err := cs.cli.AddSlot(&client.Slot{
- Snap: "snap",
- Name: "name",
- Type: "type",
+ Snap: "snap",
+ Name: "name",
+ Interface: "type",
Attrs: map[string]interface{}{
"attr": "value",
},
Oops, something went wrong.