Skip to content

Commit

Permalink
feat(wait): add sync revision delete operation
Browse files Browse the repository at this point in the history
  • Loading branch information
dsimansk committed Feb 24, 2020
1 parent a49748c commit 9bb60ac
Show file tree
Hide file tree
Showing 6 changed files with 67 additions and 9 deletions.
3 changes: 3 additions & 0 deletions docs/cmd/kn_revision_delete.md
Original file line number Diff line number Diff line change
Expand Up @@ -21,8 +21,11 @@ kn revision delete NAME [flags]
### Options

```
--async DEPRECATED: please use --no-wait instead. Delete revision and don't wait for it to be deleted.
-h, --help help for delete
-n, --namespace string Specify the namespace to operate in.
--no-wait Delete revision and don't wait for it to be deleted.
--wait-timeout int Seconds to wait before giving up on waiting for revision to be deleted. (default 600)
```

### Options inherited from parent commands
Expand Down
10 changes: 9 additions & 1 deletion pkg/kn/commands/revision/delete.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ package revision
import (
"errors"
"fmt"
"time"

"github.com/spf13/cobra"

Expand All @@ -25,6 +26,8 @@ import (

// NewRevisionDeleteCommand represent 'revision delete' command
func NewRevisionDeleteCommand(p *commands.KnParams) *cobra.Command {
var waitFlags commands.WaitFlags

RevisionDeleteCommand := &cobra.Command{
Use: "delete NAME",
Short: "Delete a revision.",
Expand All @@ -45,7 +48,11 @@ func NewRevisionDeleteCommand(p *commands.KnParams) *cobra.Command {
}

for _, name := range args {
err = client.DeleteRevision(name)
timeout := time.Duration(0)
if !waitFlags.NoWait {
timeout = time.Duration(waitFlags.TimeoutInSeconds) * time.Second
}
err = client.DeleteRevision(name, timeout)
if err != nil {
fmt.Fprintf(cmd.OutOrStdout(), "%s.\n", err)
} else {
Expand All @@ -56,5 +63,6 @@ func NewRevisionDeleteCommand(p *commands.KnParams) *cobra.Command {
},
}
commands.AddNamespaceFlags(RevisionDeleteCommand.Flags(), false)
waitFlags.AddConditionWaitFlags(RevisionDeleteCommand, commands.WaitDefaultTimeout, "Delete", "revision", "deleted")
return RevisionDeleteCommand
}
24 changes: 24 additions & 0 deletions pkg/kn/commands/revision/delete_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,14 +15,19 @@
package revision

import (
"errors"
"testing"

"gotest.tools/assert"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/runtime"
"k8s.io/apimachinery/pkg/watch"
clienttesting "k8s.io/client-go/testing"

"knative.dev/client/pkg/kn/commands"
"knative.dev/client/pkg/util"
"knative.dev/client/pkg/wait"
servingv1 "knative.dev/serving/pkg/apis/serving/v1"
)

func fakeRevisionDelete(args []string) (action clienttesting.Action, name string, output string, err error) {
Expand All @@ -35,6 +40,17 @@ func fakeRevisionDelete(args []string) (action clienttesting.Action, name string
name = deleteAction.GetName()
return true, nil, nil
})
fakeServing.AddWatchReactor("revisions",
func(a clienttesting.Action) (bool, watch.Interface, error) {
watchAction := a.(clienttesting.WatchAction)
_, found := watchAction.GetWatchRestrictions().Fields.RequiresExactMatch("metadata.name")
if !found {
return true, nil, errors.New("no field selector on metadata.name found")
}
w := wait.NewFakeWatch(getRevisionDeleteEvents("test-revision"))
w.Start()
return true, w, nil
})
cmd.SetArgs(args)
err = cmd.Execute()
if err != nil {
Expand Down Expand Up @@ -79,3 +95,11 @@ func TestMultipleRevisionDelete(t *testing.T) {
assert.Check(t, util.ContainsAll(output, "Revision", revName2, "deleted", "namespace", commands.FakeNamespace))
assert.Check(t, util.ContainsAll(output, "Revision", revName3, "deleted", "namespace", commands.FakeNamespace))
}

func getRevisionDeleteEvents(name string) []watch.Event {
return []watch.Event{
{watch.Added, &servingv1.Revision{ObjectMeta: metav1.ObjectMeta{Name: name}}},
{watch.Modified, &servingv1.Revision{ObjectMeta: metav1.ObjectMeta{Name: name}}},
{watch.Deleted, &servingv1.Revision{ObjectMeta: metav1.ObjectMeta{Name: name}}},
}
}
27 changes: 25 additions & 2 deletions pkg/serving/v1/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -89,7 +89,7 @@ type KnServingClient interface {
ListRevisions(opts ...ListConfig) (*servingv1.RevisionList, error)

// Delete a revision
DeleteRevision(name string) error
DeleteRevision(name string, timeout time.Duration) error

// Get a route by its unique name
GetRoute(name string) (*servingv1.Route, error)
Expand Down Expand Up @@ -177,6 +177,11 @@ func (cl *knServingClient) WatchService(name string, timeout time.Duration) (wat
cl.client.RESTClient(), cl.namespace, "services", name, timeout)
}

func (cl *knServingClient) WatchRevision(name string, timeout time.Duration) (watch.Interface, error) {
return wait.NewWatcher(cl.client.Revisions(cl.namespace).Watch,
cl.client.RESTClient(), cl.namespace, "revision", name, timeout)
}

// List services
func (cl *knServingClient) ListServices(config ...ListConfig) (*servingv1.ServiceList, error) {
serviceList, err := cl.client.Services(cl.namespace).List(ListConfigs(config).toListOptions())
Expand Down Expand Up @@ -370,7 +375,25 @@ func getBaseRevision(cl KnServingClient, service *servingv1.Service) (*servingv1
}

// Delete a revision by name
func (cl *knServingClient) DeleteRevision(name string) error {
func (cl *knServingClient) DeleteRevision(name string, timeout time.Duration) error {
if timeout == 0 {
return cl.deleteRevision(name)
}
waitC := make(chan error)
go func() {
waitForEvent := wait.NewWaitForEvent("revision", cl.WatchRevision, func(evt *watch.Event) bool { return evt.Type == watch.Deleted })
err, _ := waitForEvent.Wait(name, timeout, wait.NoopMessageCallback())
waitC <- err
}()
err := cl.deleteRevision(name)
if err != nil {
return clienterrors.GetError(err)
}

return <-waitC
}

func (cl *knServingClient) deleteRevision(name string) error {
err := cl.client.Revisions(cl.namespace).Delete(name, &v1.DeleteOptions{})
if err != nil {
return clienterrors.GetError(err)
Expand Down
8 changes: 4 additions & 4 deletions pkg/serving/v1/client_mock.go
Original file line number Diff line number Diff line change
Expand Up @@ -146,12 +146,12 @@ func (c *MockKnServingClient) ListRevisions(opts ...ListConfig) (*servingv1.Revi
}

// Delete a revision
func (sr *ServingRecorder) DeleteRevision(name interface{}, err error) {
sr.r.Add("DeleteRevision", []interface{}{name}, []interface{}{err})
func (sr *ServingRecorder) DeleteRevision(name, timeout interface{}, err error) {
sr.r.Add("DeleteRevision", []interface{}{name, timeout}, []interface{}{err})
}

func (c *MockKnServingClient) DeleteRevision(name string) error {
call := c.recorder.r.VerifyCall("DeleteRevision", name)
func (c *MockKnServingClient) DeleteRevision(name string, timeout time.Duration) error {
call := c.recorder.r.VerifyCall("DeleteRevision", name, timeout)
return mock.ErrorOrNil(call.Result[0])
}

Expand Down
4 changes: 2 additions & 2 deletions pkg/serving/v1/client_mock_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ func TestMockKnClient(t *testing.T) {
recorder.WaitForService("hello", time.Duration(10)*time.Second, wait.NoopMessageCallback(), nil, 10*time.Second)
recorder.GetRevision("hello", nil, nil)
recorder.ListRevisions(mock.Any(), nil, nil)
recorder.DeleteRevision("hello", nil)
recorder.DeleteRevision("hello", time.Duration(10)*time.Second, nil)
recorder.GetRoute("hello", nil, nil)
recorder.ListRoutes(mock.Any(), nil, nil)
recorder.GetConfiguration("hello", nil, nil)
Expand All @@ -54,7 +54,7 @@ func TestMockKnClient(t *testing.T) {
client.WaitForService("hello", time.Duration(10)*time.Second, wait.NoopMessageCallback())
client.GetRevision("hello")
client.ListRevisions(WithName("blub"))
client.DeleteRevision("hello")
client.DeleteRevision("hello", time.Duration(10)*time.Second)
client.GetRoute("hello")
client.ListRoutes(WithName("blub"))
client.GetConfiguration("hello")
Expand Down

0 comments on commit 9bb60ac

Please sign in to comment.