mirror of https://github.com/knative/client.git
refactor(service): Removed io.writer from of KnClient.WaitForService() (#248)
This puts all the console output to the command, where it belongs too. One could add a ProgressHandler for more fine granular feedback (like suggested in #234) but for now this is not needed.
This commit is contained in:
parent
98184eafbc
commit
2ae037f3be
|
|
@ -6,8 +6,9 @@ Knative client
|
||||||
|
|
||||||
Manage your Knative building blocks:
|
Manage your Knative building blocks:
|
||||||
|
|
||||||
* [Serving](https://github.com/knative/serving/tree/master): Manage your services and release new software to them.
|
Serving: Manage your services and release new software to them.
|
||||||
* [Eventing](https://github.com/knative/eventing/tree/master): Manage event subscriptions and channels. Connect event sources.
|
Build: Create builds and keep track of their results.
|
||||||
|
Eventing: Manage event subscriptions and channels. Connect up event sources.
|
||||||
|
|
||||||
### Options
|
### Options
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -104,10 +104,16 @@ func NewServiceCreateCommand(p *commands.KnParams) *cobra.Command {
|
||||||
}
|
}
|
||||||
|
|
||||||
if !waitFlags.Async {
|
if !waitFlags.Async {
|
||||||
err := client.WaitForService(name, time.Duration(waitFlags.TimeoutInSeconds)*time.Second, cmd.OutOrStdout())
|
out := cmd.OutOrStdout()
|
||||||
|
fmt.Fprintf(out, "Waiting for service '%s' to become ready ... ", name)
|
||||||
|
flush(out)
|
||||||
|
|
||||||
|
err := client.WaitForService(name, time.Duration(waitFlags.TimeoutInSeconds)*time.Second)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
fmt.Fprintln(out)
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
fmt.Fprintln(out, "OK")
|
||||||
return showUrl(client, name, namespace, cmd.OutOrStdout())
|
return showUrl(client, name, namespace, cmd.OutOrStdout())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -120,6 +126,17 @@ func NewServiceCreateCommand(p *commands.KnParams) *cobra.Command {
|
||||||
return serviceCreateCommand
|
return serviceCreateCommand
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Duck type for writers having a flush
|
||||||
|
type flusher interface {
|
||||||
|
Flush() error
|
||||||
|
}
|
||||||
|
|
||||||
|
func flush(out io.Writer) {
|
||||||
|
if flusher, ok := out.(flusher); ok {
|
||||||
|
flusher.Flush()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func createService(client v1alpha1.KnClient, service *serving_v1alpha1_api.Service, namespace string, out io.Writer) error {
|
func createService(client v1alpha1.KnClient, service *serving_v1alpha1_api.Service, namespace string, out io.Writer) error {
|
||||||
err := client.CreateService(service)
|
err := client.CreateService(service)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
|
||||||
|
|
@ -16,7 +16,6 @@ package v1alpha1
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/knative/pkg/apis"
|
"github.com/knative/pkg/apis"
|
||||||
|
|
@ -53,7 +52,7 @@ type KnClient interface {
|
||||||
DeleteService(name string) error
|
DeleteService(name string) error
|
||||||
|
|
||||||
// Wait for a service to become ready, but not longer than provided timeout
|
// Wait for a service to become ready, but not longer than provided timeout
|
||||||
WaitForService(name string, timeout time.Duration, out io.Writer) error
|
WaitForService(name string, timeout time.Duration) error
|
||||||
|
|
||||||
// Get a revision by name
|
// Get a revision by name
|
||||||
GetRevision(name string) (*v1alpha1.Revision, error)
|
GetRevision(name string) (*v1alpha1.Revision, error)
|
||||||
|
|
@ -188,9 +187,9 @@ func (cl *knClient) DeleteService(serviceName string) error {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Wait for a service to become ready, but not longer than provided timeout
|
// Wait for a service to become ready, but not longer than provided timeout
|
||||||
func (cl *knClient) WaitForService(name string, timeout time.Duration, out io.Writer) error {
|
func (cl *knClient) WaitForService(name string, timeout time.Duration) error {
|
||||||
waitForReady := newServiceWaitForReady(cl.client.Services(cl.namespace).Watch)
|
waitForReady := newServiceWaitForReady(cl.client.Services(cl.namespace).Watch)
|
||||||
return waitForReady.Wait(name, timeout, out)
|
return waitForReady.Wait(name, timeout)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get a revision by name
|
// Get a revision by name
|
||||||
|
|
|
||||||
|
|
@ -15,7 +15,6 @@
|
||||||
package v1alpha1
|
package v1alpha1
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"bytes"
|
|
||||||
"fmt"
|
"fmt"
|
||||||
"testing"
|
"testing"
|
||||||
"time"
|
"time"
|
||||||
|
|
@ -357,8 +356,7 @@ func TestWaitForService(t *testing.T) {
|
||||||
})
|
})
|
||||||
|
|
||||||
t.Run("wait on a service to become ready with success", func(t *testing.T) {
|
t.Run("wait on a service to become ready with success", func(t *testing.T) {
|
||||||
buf := new(bytes.Buffer)
|
err := client.WaitForService(serviceName, 60*time.Second)
|
||||||
err := client.WaitForService(serviceName, 60*time.Second, buf)
|
|
||||||
assert.NilError(t, err)
|
assert.NilError(t, err)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -16,7 +16,6 @@ package wait
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/knative/pkg/apis"
|
"github.com/knative/pkg/apis"
|
||||||
|
|
@ -40,7 +39,7 @@ type WaitForReady interface {
|
||||||
|
|
||||||
// Wait on resource the resource with this name until a given timeout
|
// Wait on resource the resource with this name until a given timeout
|
||||||
// and write status out on writer
|
// and write status out on writer
|
||||||
Wait(name string, timeout time.Duration, out io.Writer) error
|
Wait(name string, timeout time.Duration) error
|
||||||
}
|
}
|
||||||
|
|
||||||
// Create watch which is used when waiting for Ready condition
|
// Create watch which is used when waiting for Ready condition
|
||||||
|
|
@ -62,21 +61,17 @@ func NewWaitForReady(kind string, watchFunc WatchFunc, extractor ConditionsExtra
|
||||||
// `watchFunc` creates the actual watch, `kind` is the type what your are watching for
|
// `watchFunc` creates the actual watch, `kind` is the type what your are watching for
|
||||||
// (e.g. "service"), `timeout` is a timeout after which the watch should be cancelled if no
|
// (e.g. "service"), `timeout` is a timeout after which the watch should be cancelled if no
|
||||||
// target state has been entered yet and `out` is used for printing out status messages
|
// target state has been entered yet and `out` is used for printing out status messages
|
||||||
func (w *waitForReadyConfig) Wait(name string, timeout time.Duration, out io.Writer) error {
|
func (w *waitForReadyConfig) Wait(name string, timeout time.Duration) error {
|
||||||
opts := v1.ListOptions{
|
opts := v1.ListOptions{
|
||||||
FieldSelector: fields.OneTermEqualSelector("metadata.name", name).String(),
|
FieldSelector: fields.OneTermEqualSelector("metadata.name", name).String(),
|
||||||
}
|
}
|
||||||
addWatchTimeout(&opts, timeout)
|
addWatchTimeout(&opts, timeout)
|
||||||
|
|
||||||
fmt.Fprintf(out, "Waiting for %s '%s' to become ready ... ", w.kind, name)
|
|
||||||
flush(out)
|
|
||||||
|
|
||||||
floatingTimeout := timeout
|
floatingTimeout := timeout
|
||||||
for {
|
for {
|
||||||
start := time.Now()
|
start := time.Now()
|
||||||
retry, timeoutReached, err := w.waitForReadyCondition(opts, name, floatingTimeout)
|
retry, timeoutReached, err := w.waitForReadyCondition(opts, name, floatingTimeout)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
fmt.Fprintln(out)
|
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
floatingTimeout = floatingTimeout - time.Since(start)
|
floatingTimeout = floatingTimeout - time.Since(start)
|
||||||
|
|
@ -88,8 +83,6 @@ func (w *waitForReadyConfig) Wait(name string, timeout time.Duration, out io.Wri
|
||||||
// restart loop
|
// restart loop
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
fmt.Fprintln(out, "OK")
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -105,17 +98,6 @@ func addWatchTimeout(opts *v1.ListOptions, timeout time.Duration) {
|
||||||
opts.TimeoutSeconds = &timeOutWatchSeconds
|
opts.TimeoutSeconds = &timeOutWatchSeconds
|
||||||
}
|
}
|
||||||
|
|
||||||
// Duck type for writers having a flush
|
|
||||||
type flusher interface {
|
|
||||||
Flush() error
|
|
||||||
}
|
|
||||||
|
|
||||||
func flush(out io.Writer) {
|
|
||||||
if flusher, ok := out.(flusher); ok {
|
|
||||||
flusher.Flush()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (w *waitForReadyConfig) waitForReadyCondition(opts v1.ListOptions, name string, timeout time.Duration) (bool, bool, error) {
|
func (w *waitForReadyConfig) waitForReadyCondition(opts v1.ListOptions, name string, timeout time.Duration) (bool, bool, error) {
|
||||||
|
|
||||||
watcher, err := w.watchFunc(opts)
|
watcher, err := w.watchFunc(opts)
|
||||||
|
|
|
||||||
|
|
@ -15,8 +15,6 @@
|
||||||
package wait
|
package wait
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"bytes"
|
|
||||||
"strings"
|
|
||||||
"testing"
|
"testing"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
|
@ -32,14 +30,12 @@ type waitForReadyTestCase struct {
|
||||||
events []watch.Event
|
events []watch.Event
|
||||||
timeout time.Duration
|
timeout time.Duration
|
||||||
errorExpected bool
|
errorExpected bool
|
||||||
messageContent []string
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestAddWaitForReady(t *testing.T) {
|
func TestAddWaitForReady(t *testing.T) {
|
||||||
|
|
||||||
for i, tc := range prepareTestCases("test-service") {
|
for i, tc := range prepareTestCases("test-service") {
|
||||||
fakeWatchApi := NewFakeWatch(tc.events)
|
fakeWatchApi := NewFakeWatch(tc.events)
|
||||||
outBuffer := new(bytes.Buffer)
|
|
||||||
|
|
||||||
waitForReady := NewWaitForReady(
|
waitForReady := NewWaitForReady(
|
||||||
"blub",
|
"blub",
|
||||||
|
|
@ -50,7 +46,7 @@ func TestAddWaitForReady(t *testing.T) {
|
||||||
return apis.Conditions(obj.(*v1alpha1.Service).Status.Conditions), nil
|
return apis.Conditions(obj.(*v1alpha1.Service).Status.Conditions), nil
|
||||||
})
|
})
|
||||||
fakeWatchApi.Start()
|
fakeWatchApi.Start()
|
||||||
err := waitForReady.Wait("foobar", tc.timeout, outBuffer)
|
err := waitForReady.Wait("foobar", tc.timeout)
|
||||||
close(fakeWatchApi.eventChan)
|
close(fakeWatchApi.eventChan)
|
||||||
|
|
||||||
if !tc.errorExpected && err != nil {
|
if !tc.errorExpected && err != nil {
|
||||||
|
|
@ -60,16 +56,6 @@ func TestAddWaitForReady(t *testing.T) {
|
||||||
if tc.errorExpected && err == nil {
|
if tc.errorExpected && err == nil {
|
||||||
t.Errorf("%d: No error but expected one", i)
|
t.Errorf("%d: No error but expected one", i)
|
||||||
}
|
}
|
||||||
txtToCheck := outBuffer.String()
|
|
||||||
if err != nil {
|
|
||||||
txtToCheck = err.Error()
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, msg := range tc.messageContent {
|
|
||||||
if !strings.Contains(txtToCheck, msg) {
|
|
||||||
t.Errorf("%d: '%s' does not contain expected part %s", i, txtToCheck, msg)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if fakeWatchApi.StopCalled != 1 {
|
if fakeWatchApi.StopCalled != 1 {
|
||||||
t.Errorf("%d: Exactly one 'stop' should be called, but got %d", i, fakeWatchApi.StopCalled)
|
t.Errorf("%d: Exactly one 'stop' should be called, but got %d", i, fakeWatchApi.StopCalled)
|
||||||
|
|
@ -81,10 +67,10 @@ func TestAddWaitForReady(t *testing.T) {
|
||||||
// Test cases which consists of a series of events to send and the expected behaviour.
|
// Test cases which consists of a series of events to send and the expected behaviour.
|
||||||
func prepareTestCases(name string) []waitForReadyTestCase {
|
func prepareTestCases(name string) []waitForReadyTestCase {
|
||||||
return []waitForReadyTestCase{
|
return []waitForReadyTestCase{
|
||||||
{peNormal(name), time.Second, false, []string{"OK", "foobar", "blub"}},
|
{peNormal(name), time.Second, false},
|
||||||
{peError(name), time.Second, true, []string{"FakeError"}},
|
{peError(name), time.Second, true},
|
||||||
{peTimeout(name), time.Second, true, []string{"timeout"}},
|
{peTimeout(name), time.Second, true},
|
||||||
{peWrongGeneration(name), time.Second, true, []string{"timeout"}},
|
{peWrongGeneration(name), time.Second, true},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue