mirror of https://github.com/knative/client.git
feat(wait): add sync revision delete operation
This commit is contained in:
parent
a49748c4bf
commit
9bb60ac25e
|
|
@ -21,8 +21,11 @@ kn revision delete NAME [flags]
|
||||||
### Options
|
### Options
|
||||||
|
|
||||||
```
|
```
|
||||||
|
--async DEPRECATED: please use --no-wait instead. Delete revision and don't wait for it to be deleted.
|
||||||
-h, --help help for delete
|
-h, --help help for delete
|
||||||
-n, --namespace string Specify the namespace to operate in.
|
-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
|
### Options inherited from parent commands
|
||||||
|
|
|
||||||
|
|
@ -17,6 +17,7 @@ package revision
|
||||||
import (
|
import (
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"time"
|
||||||
|
|
||||||
"github.com/spf13/cobra"
|
"github.com/spf13/cobra"
|
||||||
|
|
||||||
|
|
@ -25,6 +26,8 @@ import (
|
||||||
|
|
||||||
// NewRevisionDeleteCommand represent 'revision delete' command
|
// NewRevisionDeleteCommand represent 'revision delete' command
|
||||||
func NewRevisionDeleteCommand(p *commands.KnParams) *cobra.Command {
|
func NewRevisionDeleteCommand(p *commands.KnParams) *cobra.Command {
|
||||||
|
var waitFlags commands.WaitFlags
|
||||||
|
|
||||||
RevisionDeleteCommand := &cobra.Command{
|
RevisionDeleteCommand := &cobra.Command{
|
||||||
Use: "delete NAME",
|
Use: "delete NAME",
|
||||||
Short: "Delete a revision.",
|
Short: "Delete a revision.",
|
||||||
|
|
@ -45,7 +48,11 @@ func NewRevisionDeleteCommand(p *commands.KnParams) *cobra.Command {
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, name := range args {
|
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 {
|
if err != nil {
|
||||||
fmt.Fprintf(cmd.OutOrStdout(), "%s.\n", err)
|
fmt.Fprintf(cmd.OutOrStdout(), "%s.\n", err)
|
||||||
} else {
|
} else {
|
||||||
|
|
@ -56,5 +63,6 @@ func NewRevisionDeleteCommand(p *commands.KnParams) *cobra.Command {
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
commands.AddNamespaceFlags(RevisionDeleteCommand.Flags(), false)
|
commands.AddNamespaceFlags(RevisionDeleteCommand.Flags(), false)
|
||||||
|
waitFlags.AddConditionWaitFlags(RevisionDeleteCommand, commands.WaitDefaultTimeout, "Delete", "revision", "deleted")
|
||||||
return RevisionDeleteCommand
|
return RevisionDeleteCommand
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -15,14 +15,19 @@
|
||||||
package revision
|
package revision
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"errors"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"gotest.tools/assert"
|
"gotest.tools/assert"
|
||||||
|
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||||
"k8s.io/apimachinery/pkg/runtime"
|
"k8s.io/apimachinery/pkg/runtime"
|
||||||
|
"k8s.io/apimachinery/pkg/watch"
|
||||||
clienttesting "k8s.io/client-go/testing"
|
clienttesting "k8s.io/client-go/testing"
|
||||||
|
|
||||||
"knative.dev/client/pkg/kn/commands"
|
"knative.dev/client/pkg/kn/commands"
|
||||||
"knative.dev/client/pkg/util"
|
"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) {
|
func fakeRevisionDelete(args []string) (action clienttesting.Action, name string, output string, err error) {
|
||||||
|
|
@ -35,6 +40,17 @@ func fakeRevisionDelete(args []string) (action clienttesting.Action, name string
|
||||||
name = deleteAction.GetName()
|
name = deleteAction.GetName()
|
||||||
return true, nil, nil
|
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)
|
cmd.SetArgs(args)
|
||||||
err = cmd.Execute()
|
err = cmd.Execute()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
@ -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", revName2, "deleted", "namespace", commands.FakeNamespace))
|
||||||
assert.Check(t, util.ContainsAll(output, "Revision", revName3, "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}}},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -89,7 +89,7 @@ type KnServingClient interface {
|
||||||
ListRevisions(opts ...ListConfig) (*servingv1.RevisionList, error)
|
ListRevisions(opts ...ListConfig) (*servingv1.RevisionList, error)
|
||||||
|
|
||||||
// Delete a revision
|
// Delete a revision
|
||||||
DeleteRevision(name string) error
|
DeleteRevision(name string, timeout time.Duration) error
|
||||||
|
|
||||||
// Get a route by its unique name
|
// Get a route by its unique name
|
||||||
GetRoute(name string) (*servingv1.Route, error)
|
GetRoute(name string) (*servingv1.Route, error)
|
||||||
|
|
@ -177,6 +177,11 @@ func (cl *knServingClient) WatchService(name string, timeout time.Duration) (wat
|
||||||
cl.client.RESTClient(), cl.namespace, "services", name, timeout)
|
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
|
// List services
|
||||||
func (cl *knServingClient) ListServices(config ...ListConfig) (*servingv1.ServiceList, error) {
|
func (cl *knServingClient) ListServices(config ...ListConfig) (*servingv1.ServiceList, error) {
|
||||||
serviceList, err := cl.client.Services(cl.namespace).List(ListConfigs(config).toListOptions())
|
serviceList, err := cl.client.Services(cl.namespace).List(ListConfigs(config).toListOptions())
|
||||||
|
|
@ -370,7 +375,25 @@ func getBaseRevision(cl KnServingClient, service *servingv1.Service) (*servingv1
|
||||||
}
|
}
|
||||||
|
|
||||||
// Delete a revision by name
|
// 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{})
|
err := cl.client.Revisions(cl.namespace).Delete(name, &v1.DeleteOptions{})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return clienterrors.GetError(err)
|
return clienterrors.GetError(err)
|
||||||
|
|
|
||||||
|
|
@ -146,12 +146,12 @@ func (c *MockKnServingClient) ListRevisions(opts ...ListConfig) (*servingv1.Revi
|
||||||
}
|
}
|
||||||
|
|
||||||
// Delete a revision
|
// Delete a revision
|
||||||
func (sr *ServingRecorder) DeleteRevision(name interface{}, err error) {
|
func (sr *ServingRecorder) DeleteRevision(name, timeout interface{}, err error) {
|
||||||
sr.r.Add("DeleteRevision", []interface{}{name}, []interface{}{err})
|
sr.r.Add("DeleteRevision", []interface{}{name, timeout}, []interface{}{err})
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *MockKnServingClient) DeleteRevision(name string) error {
|
func (c *MockKnServingClient) DeleteRevision(name string, timeout time.Duration) error {
|
||||||
call := c.recorder.r.VerifyCall("DeleteRevision", name)
|
call := c.recorder.r.VerifyCall("DeleteRevision", name, timeout)
|
||||||
return mock.ErrorOrNil(call.Result[0])
|
return mock.ErrorOrNil(call.Result[0])
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -40,7 +40,7 @@ func TestMockKnClient(t *testing.T) {
|
||||||
recorder.WaitForService("hello", time.Duration(10)*time.Second, wait.NoopMessageCallback(), nil, 10*time.Second)
|
recorder.WaitForService("hello", time.Duration(10)*time.Second, wait.NoopMessageCallback(), nil, 10*time.Second)
|
||||||
recorder.GetRevision("hello", nil, nil)
|
recorder.GetRevision("hello", nil, nil)
|
||||||
recorder.ListRevisions(mock.Any(), 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.GetRoute("hello", nil, nil)
|
||||||
recorder.ListRoutes(mock.Any(), nil, nil)
|
recorder.ListRoutes(mock.Any(), nil, nil)
|
||||||
recorder.GetConfiguration("hello", nil, nil)
|
recorder.GetConfiguration("hello", nil, nil)
|
||||||
|
|
@ -54,7 +54,7 @@ func TestMockKnClient(t *testing.T) {
|
||||||
client.WaitForService("hello", time.Duration(10)*time.Second, wait.NoopMessageCallback())
|
client.WaitForService("hello", time.Duration(10)*time.Second, wait.NoopMessageCallback())
|
||||||
client.GetRevision("hello")
|
client.GetRevision("hello")
|
||||||
client.ListRevisions(WithName("blub"))
|
client.ListRevisions(WithName("blub"))
|
||||||
client.DeleteRevision("hello")
|
client.DeleteRevision("hello", time.Duration(10)*time.Second)
|
||||||
client.GetRoute("hello")
|
client.GetRoute("hello")
|
||||||
client.ListRoutes(WithName("blub"))
|
client.ListRoutes(WithName("blub"))
|
||||||
client.GetConfiguration("hello")
|
client.GetConfiguration("hello")
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue