diff options
| author | Michael Vogt <michael.vogt@gmail.com> | 2015-12-03 16:11:24 +0100 |
|---|---|---|
| committer | Michael Vogt <michael.vogt@gmail.com> | 2015-12-03 16:11:24 +0100 |
| commit | 83acb8febd24d88e0191edb29767a592f264d782 (patch) | |
| tree | 8c03a2403073717925225f5b83d1a3fbd303b1b5 | |
| parent | abb061b83b8041bd00a75f464daac0536543f7b9 (diff) | |
| parent | e661aae17453c7f34aa3649f1da2c98b744de2ad (diff) | |
Merge pull request #211 from zyga/caps-api-remove-capability
Caps api remove capability
| -rw-r--r-- | caps/repo.go | 12 | ||||
| -rw-r--r-- | caps/repo_test.go | 7 | ||||
| -rw-r--r-- | client/caps.go | 16 | ||||
| -rw-r--r-- | client/client_test.go | 32 | ||||
| -rw-r--r-- | cmd/snap/cmd_remove_cap.go | 50 | ||||
| -rw-r--r-- | daemon/api.go | 19 | ||||
| -rw-r--r-- | daemon/api_test.go | 34 | ||||
| -rw-r--r-- | po/snappy.pot | 8 |
8 files changed, 177 insertions, 1 deletions
diff --git a/caps/repo.go b/caps/repo.go index 534e4d5f73..3e3cdf8c16 100644 --- a/caps/repo.go +++ b/caps/repo.go @@ -84,6 +84,9 @@ func (r *Repository) hasType(t *Type) bool { // Type finds and returns the Type with the given name or nil if // it's not found func (r *Repository) Type(name string) *Type { + r.m.Lock() + defer r.m.Unlock() + for _, t := range r.types { if t.Name == name { return t @@ -92,6 +95,15 @@ func (r *Repository) Type(name string) *Type { return nil } +// Capability finds and returns the Capability with the given name or nil if it +// is not found. +func (r *Repository) Capability(name string) *Capability { + r.m.Lock() + defer r.m.Unlock() + + return r.caps[name] +} + // AddType adds a capability type to the repository. // It's an error to add the same capability type more than once. func (r *Repository) AddType(t *Type) error { diff --git a/caps/repo_test.go b/caps/repo_test.go index 069de6fe4f..9776471244 100644 --- a/caps/repo_test.go +++ b/caps/repo_test.go @@ -152,6 +152,13 @@ func (s *RepositorySuite) TestType(c *C) { c.Assert(s.testRepo.Type(testType.Name), Equals, testType) } +func (s *RepositorySuite) TestCapability(c *C) { + err := s.testRepo.Add(testCapability) + c.Assert(err, IsNil) + c.Assert(s.emptyRepo.Capability(testCapability.Name), IsNil) + c.Assert(s.testRepo.Capability(testCapability.Name), Equals, testCapability) +} + func (s *RepositorySuite) TestHasType(c *C) { // hasType works as expected when the object is exactly the one that was // added earlier. diff --git a/client/caps.go b/client/caps.go index bd4fa4c66e..da6e3aea74 100644 --- a/client/caps.go +++ b/client/caps.go @@ -83,3 +83,19 @@ func (client *Client) AddCapability(c *Capability) error { } return nil } + +// RemoveCapability removes one capability from the system +func (client *Client) RemoveCapability(name string) error { + errPrefix := "cannot remove capability" + var rsp response + if err := client.do("DELETE", fmt.Sprintf("/1.0/capabilities/%s", name), nil, &rsp); err != nil { + return err + } + if err := rsp.err(); err != nil { + return err + } + if rsp.Type != "sync" { + return fmt.Errorf("%s: expected sync response, got %q", errPrefix, rsp.Type) + } + return nil +} diff --git a/client/client_test.go b/client/client_test.go index 639da3a265..421cc57638 100644 --- a/client/client_test.go +++ b/client/client_test.go @@ -155,6 +155,8 @@ func (cs *clientSuite) TestClientCapabilities(c *check.C) { Attrs: map[string]string{"k": "v"}, }, }) + c.Check(cs.req.Method, check.Equals, "GET") + c.Check(cs.req.URL.Path, check.Equals, "/1.0/capabilities") } func (cs *clientSuite) TestClientAddCapability(c *check.C) { @@ -183,4 +185,34 @@ func (cs *clientSuite) TestClientAddCapability(c *check.C) { "k": "v", }, }) + c.Check(cs.req.Method, check.Equals, "POST") + c.Check(cs.req.URL.Path, check.Equals, "/1.0/capabilities") +} + +func (cs *clientSuite) TestClientRemoveCapabilityOk(c *check.C) { + cs.rsp = `{ + "type": "sync", + "result": { } + }` + err := cs.cli.RemoveCapability("n") + c.Check(err, check.IsNil) + c.Check(cs.req.Body, check.IsNil) + c.Check(cs.req.Method, check.Equals, "DELETE") + c.Check(cs.req.URL.Path, check.Equals, "/1.0/capabilities/n") +} + +func (cs *clientSuite) TestClientRemoveCapabilityNotFound(c *check.C) { + cs.rsp = `{ + "status": "Not Found", + "status_code": 404, + "type": "error", + "result": { + "str": "can't remove capability \"n\", no such capability" + } + }` + err := cs.cli.RemoveCapability("n") + c.Check(err, check.ErrorMatches, `can't remove capability \"n\", no such capability`) + c.Check(cs.req.Body, check.IsNil) + c.Check(cs.req.Method, check.Equals, "DELETE") + c.Check(cs.req.URL.Path, check.Equals, "/1.0/capabilities/n") } diff --git a/cmd/snap/cmd_remove_cap.go b/cmd/snap/cmd_remove_cap.go new file mode 100644 index 0000000000..4c6403ead3 --- /dev/null +++ b/cmd/snap/cmd_remove_cap.go @@ -0,0 +1,50 @@ +// -*- Mode: Go; indent-tabs-mode: t -*- + +/* + * Copyright (C) 2014-2015 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 main + +import ( + "github.com/ubuntu-core/snappy/client" + "github.com/ubuntu-core/snappy/i18n" + "github.com/ubuntu-core/snappy/logger" +) + +type removeCapOptions struct { + Name string `positional-arg-name:"name" description:"unique capability name"` +} + +type cmdRemoveCap struct { + removeCapOptions `positional-args:"true" required:"true"` +} + +var ( + shortRemoveCapHelp = i18n.G("Remove a capability from the system") + longRemoveCapHelp = i18n.G("This command removes a capability from the system") +) + +func init() { + _, err := parser.AddCommand("remove-cap", shortRemoveCapHelp, longRemoveCapHelp, &cmdRemoveCap{}) + if err != nil { + logger.Panicf("unable to add remove-cap command: %v", err) + } +} + +func (x *cmdRemoveCap) Execute(args []string) error { + return client.New().RemoveCapability(x.Name) +} diff --git a/daemon/api.go b/daemon/api.go index 6a214a24f1..535a47f5f6 100644 --- a/daemon/api.go +++ b/daemon/api.go @@ -61,6 +61,7 @@ var api = []*Command{ packageSvcLogsCmd, operationCmd, capabilitiesCmd, + capabilityCmd, } var ( @@ -140,6 +141,11 @@ var ( GET: getCapabilities, POST: addCapability, } + + capabilityCmd = &Command{ + Path: "/1.0/capabilities/{name}", + DELETE: deleteCapability, + } ) func v1Get(c *Command, r *http.Request) Response { @@ -950,3 +956,16 @@ func addCapability(c *Command, r *http.Request) Response { }, } } + +func deleteCapability(c *Command, r *http.Request) Response { + name := muxVars(r)["name"] + err := c.d.capRepo.Remove(name) + switch err.(type) { + case nil: + return SyncResponse(nil) + case *caps.NotFoundError: + return NotFound(err, "can't remove capability") + default: + return InternalError(err, "") + } +} diff --git a/daemon/api_test.go b/daemon/api_test.go index 4e37238ec8..fb2f1033fa 100644 --- a/daemon/api_test.go +++ b/daemon/api_test.go @@ -1325,3 +1325,37 @@ func (s *apiSuite) TestAddCapabilitiesNotACapability(c *check.C) { // Verify (internal) c.Check(d.capRepo.All(), check.HasLen, 0) } + +func (s *apiSuite) TestDeleteCapabilityGood(c *check.C) { + // Setup + d := newTestDaemon() + t := &caps.Type{Name: "test"} + err := d.capRepo.AddType(t) + c.Assert(err, check.IsNil) + cap := &caps.Capability{Name: "name", Type: t} + err = d.capRepo.Add(cap) + c.Assert(err, check.IsNil) + s.vars = map[string]string{"name": "name"} + // Execute + rsp := deleteCapability(capabilityCmd, nil).Self(nil, nil).(*resp) + // Verify (external) + c.Check(rsp.Type, check.Equals, ResponseTypeSync) + c.Check(rsp.Status, check.Equals, http.StatusOK) + // Verify (internal) + c.Check(d.capRepo.Capability(cap.Name), check.IsNil) +} + +func (s *apiSuite) TestDeleteCapabilityNotFound(c *check.C) { + // Setup + d := newTestDaemon() + before := d.capRepo.All() + s.vars = map[string]string{"name": "name"} + // Execute + rsp := deleteCapability(capabilityCmd, nil).Self(nil, nil).(*resp) + // Verify (external) + c.Check(rsp.Type, check.Equals, ResponseTypeError) + c.Check(rsp.Status, check.Equals, http.StatusNotFound) + // Verify (internal) + after := d.capRepo.All() + c.Check(before, check.DeepEquals, after) +} diff --git a/po/snappy.pot b/po/snappy.pot index 374f836df4..46cbee0919 100644 --- a/po/snappy.pot +++ b/po/snappy.pot @@ -7,7 +7,7 @@ msgid "" msgstr "Project-Id-Version: snappy\n" "Report-Msgid-Bugs-To: snappy-devel@lists.ubuntu.com\n" - "POT-Creation-Date: 2015-12-02 09:28+0100\n" + "POT-Creation-Date: 2015-12-02 11:46+0100\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME <EMAIL@ADDRESS>\n" "Language-Team: LANGUAGE <LL@li.org>\n" @@ -249,6 +249,9 @@ msgstr "" msgid "Rebooting to satisfy updates for %s\n" msgstr "" +msgid "Remove a capability from the system" +msgstr "" + msgid "Remove a snapp part" msgstr "" @@ -376,6 +379,9 @@ msgstr "" msgid "This command logs the given username into the store" msgstr "" +msgid "This command removes a capability from the system" +msgstr "" + msgid "This command removes access of a specific hardware device (e.g. /dev/ttyUSB0) for an installed package." msgstr "" |
