Skip to content

Commit

Permalink
api/database: Add the ability to delete layers
Browse files Browse the repository at this point in the history
  • Loading branch information
Quentin-M committed Dec 4, 2015
1 parent cadc182 commit e444e93
Show file tree
Hide file tree
Showing 5 changed files with 119 additions and 1 deletion.
12 changes: 12 additions & 0 deletions api/logic/layers.go
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,18 @@ func POSTLayers(w http.ResponseWriter, r *http.Request, _ httprouter.Params) {
jsonhttp.Render(w, http.StatusCreated, struct{ Version string }{Version: strconv.Itoa(worker.Version)})
}

// DeleteLayer deletes the specified layer and any child layers that are
// dependent on the specified layer.
func DELETELayers(w http.ResponseWriter, r *http.Request, p httprouter.Params) {
err := database.DeleteLayer(p.ByName("id"))
if err != nil {
jsonhttp.RenderError(w, 0, err)
return
}

jsonhttp.Render(w, http.StatusNoContent, nil)
}

// GETLayersOS returns the operating system of a layer if it exists.
// It uses not only the specified layer but also its parent layers if necessary.
// An empty OS string is returned if no OS has been detected.
Expand Down
1 change: 1 addition & 0 deletions api/router.go
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,7 @@ func NewRouterV1(to time.Duration) *httprouter.Router {

// Layers
router.POST("/layers", wrap(logic.POSTLayers))
router.DELETE("/layers/:id", wrap(logic.DELETELayers))
router.GET("/layers/:id/os", wrap(logic.GETLayersOS))
router.GET("/layers/:id/parent", wrap(logic.GETLayersParent))
router.GET("/layers/:id/packages", wrap(logic.GETLayersPackages))
Expand Down
54 changes: 54 additions & 0 deletions database/layer.go
Original file line number Diff line number Diff line change
Expand Up @@ -131,6 +131,60 @@ func InsertLayer(layer *Layer) error {
return nil
}

// DeleteLayer deletes the specified layer and any child layers that are
// dependent on the specified layer.
func DeleteLayer(ID string) error {
layer, err := FindOneLayerByID(ID, []string{})
if err != nil {
return err
}
return deleteLayerTreeFrom(layer.Node, nil)
}

func deleteLayerTreeFrom(node string, t *graph.Transaction) error {
// Determine if that function call is the root call of the recursivity
// And create transaction if its the case.
root := (t == nil)
if root {
t = cayley.NewTransaction()
}

// Find layer.
layer, err := FindOneLayerByNode(node, FieldLayerAll)
if err != nil {
// Ignore missing layer.
return nil
}

// Remove all successor layers.
for _, succNode := range layer.SuccessorsNodes {
deleteLayerTreeFrom(succNode, t)
}

// Remove layer.
t.RemoveQuad(cayley.Quad(layer.Node, FieldIs, FieldLayerIsValue, ""))
t.RemoveQuad(cayley.Quad(layer.Node, FieldLayerID, layer.ID, ""))
t.RemoveQuad(cayley.Quad(layer.Node, FieldLayerParent, layer.ParentNode, ""))
t.RemoveQuad(cayley.Quad(layer.Node, FieldLayerOS, layer.OS, ""))
t.RemoveQuad(cayley.Quad(layer.Node, FieldLayerEngineVersion, strconv.Itoa(layer.EngineVersion), ""))
for _, pkg := range layer.InstalledPackagesNodes {
t.RemoveQuad(cayley.Quad(layer.Node, FieldLayerInstalledPackages, pkg, ""))
}
for _, pkg := range layer.RemovedPackagesNodes {
t.RemoveQuad(cayley.Quad(layer.Node, FieldLayerRemovedPackages, pkg, ""))
}

// Apply transaction if root call.
if root {
if err = store.ApplyTransaction(t); err != nil {
log.Errorf("failed transaction (deleteLayerTreeFrom): %s", err)
return ErrTransaction
}
}

return nil
}

// FindOneLayerByID finds and returns a single layer having the given ID,
// selecting the specified fields and hardcoding its ID
func FindOneLayerByID(ID string, selectedFields []string) (*Layer, error) {
Expand Down
17 changes: 16 additions & 1 deletion database/layer_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ import (
"testing"

"github.com/coreos/clair/utils"
cerrors "github.com/coreos/clair/utils/errors"
"github.com/stretchr/testify/assert"
)

Expand All @@ -38,7 +39,7 @@ func TestLayerSimple(t *testing.T) {
// Insert a layer and find it back
l1 := &Layer{ID: "l1", OS: "os1", InstalledPackagesNodes: []string{"p1", "p2"}, EngineVersion: 1}
if assert.Nil(t, InsertLayer(l1)) {
fl1, err := FindOneLayerByID("l1", FieldLayerAll)
fl1, err := FindOneLayerByID(l1.ID, FieldLayerAll)
if assert.Nil(t, err) && assert.NotNil(t, fl1) {
// Saved = found
assert.True(t, layerEqual(l1, fl1), "layers are not equal, expected %v, have %s", l1, fl1)
Expand Down Expand Up @@ -66,6 +67,12 @@ func TestLayerSimple(t *testing.T) {
if assert.Nil(t, err) && assert.Len(t, al1, 1) {
assert.Equal(t, al1[0].Node, l1.Node)
}

// Delete
if assert.Nil(t, DeleteLayer(l1.ID)) {
_, err := FindOneLayerByID(l1.ID, FieldLayerAll)
assert.Equal(t, cerrors.ErrNotFound, err)
}
}
}

Expand Down Expand Up @@ -119,6 +126,14 @@ func TestLayerTree(t *testing.T) {
fl4bpkg, err := flayers[4].AllPackages()
assert.Nil(t, err)
assert.Len(t, fl4bpkg, 0)

// Delete a layer in the middle of the tree.
if assert.Nil(t, DeleteLayer(flayers[1].ID)) {
for _, l := range layers[1:] {
_, err := FindOneLayerByID(l.ID, FieldLayerAll)
assert.Equal(t, cerrors.ErrNotFound, err)
}
}
}
}

Expand Down
36 changes: 36 additions & 0 deletions docs/API.md
Original file line number Diff line number Diff line change
Expand Up @@ -150,6 +150,41 @@ HTTP/1.1 400 Bad Request

It could also return a `415 Unsupported Media Type` response with a `Message` if the request content is not valid JSON.

## Delete a Layer

It deletes a layer from the database and any child layers that are dependent on the specified layer.

DELETE /v1/layers/{ID}

### Parameters

|Name|Type|Description|
|------|-----|-------------|
|ID|String|Unique ID of the Layer|

### Example

```
curl -s -X DELETE 127.0.0.1:6060/v1/layers/39bb80489af75406073b5364c9c326134015140e1f7976a370a8bd446889e6f8
```

### Success Response

```
HTTP/1.1 204 No Content
```

### Error Response

```
HTTP/1.1 404 Not Found
{
"Message": "the resource cannot be found"
}
```

//////////

## Get a Layer's operating system

It returns the operating system a given Layer.
Expand Down Expand Up @@ -210,6 +245,7 @@ HTTP/1.1 200 OK
```

### Error Response

```
HTTP/1.1 404 Not Found
{
Expand Down

0 comments on commit e444e93

Please sign in to comment.