Repository: skupperproject/skupper
Pull request #1809 (2024-11-29 20:46:09)

add wait flag for link, listener and connector commands
Continuation of the work done in https://github.com/skupperproject/skupper/pull/1795




Patch:
diff --git a/internal/cmd/skupper/common/flags.go b/internal/cmd/skupper/common/flags.go
index 97a291e2..c20ecaf9 100644
--- a/internal/cmd/skupper/common/flags.go
+++ b/internal/cmd/skupper/common/flags.go
@@ -118,10 +118,12 @@ type CommandLinkUpdateFlags struct {
 	Cost           string
 	Output         string
 	Timeout        time.Duration
+	Wait           string
 }
 
 type CommandLinkDeleteFlags struct {
 	Timeout time.Duration
+	Wait    bool
 }
 type CommandLinkStatusFlags struct {
 	Output string
@@ -148,6 +150,7 @@ type CommandConnectorCreateFlags struct {
 	Workload            string
 	Timeout             time.Duration
 	Output              string
+	Wait                string
 }
 
 type CommandConnectorUpdateFlags struct {
@@ -161,10 +164,12 @@ type CommandConnectorUpdateFlags struct {
 	IncludeNotReadyPods bool
 	Timeout             time.Duration
 	Output              string
+	Wait                string
 }
 
 type CommandConnectorDeleteFlags struct {
 	Timeout time.Duration
+	Wait    bool
 }
 
 type CommandConnectorStatusFlags struct {
@@ -178,6 +183,7 @@ type CommandListenerCreateFlags struct {
 	ListenerType   string
 	Timeout        time.Duration
 	Output         string
+	Wait           string
 }
 
 type CommandListenerUpdateFlags struct {
@@ -188,6 +194,7 @@ type CommandListenerUpdateFlags struct {
 	Timeout        time.Duration
 	Port           int
 	Output         string
+	Wait           string
 }
 
 type CommandListenerStatusFlags struct {
@@ -196,6 +203,7 @@ type CommandListenerStatusFlags struct {
 
 type CommandListenerDeleteFlags struct {
 	Timeout time.Duration
+	Wait    bool
 }
 
 type CommandVersionFlags struct {
diff --git a/internal/cmd/skupper/connector/connector.go b/internal/cmd/skupper/connector/connector.go
index 703dd34f..a526b110 100644
--- a/internal/cmd/skupper/connector/connector.go
+++ b/internal/cmd/skupper/connector/connector.go
@@ -54,6 +54,7 @@ skupper connector create backend 8080 --workload deployment/backend`,
 	cmd.Flags().StringVarP(&cmdFlags.Workload, common.FlagNameWorkload, "w", "", common.FlagDescWorkload)
 	cmd.Flags().DurationVar(&cmdFlags.Timeout, common.FlagNameTimeout, 60*time.Second, common.FlagDescTimeout)
 	cmd.Flags().StringVarP(&cmdFlags.Output, common.FlagNameOutput, "o", "", common.FlagDescOutput)
+	cmd.Flags().StringVar(&cmdFlags.Wait, common.FlagNameWait, "configured", common.FlagDescWait)
 
 	kubeCommand.CobraCmd = cmd
 	kubeCommand.Flags = &cmdFlags
@@ -64,6 +65,8 @@ skupper connector create backend 8080 --workload deployment/backend`,
 		cmd.Flags().MarkHidden(common.FlagNameIncludeNotReadyPods)
 		cmd.Flags().MarkHidden(common.FlagNameSelector)
 		cmd.Flags().MarkHidden(common.FlagNameWorkload)
+		cmd.Flags().MarkHidden(common.FlagNameTimeout)
+		cmd.Flags().MarkHidden(common.FlagNameWait)
 	}
 
 	return cmd
@@ -119,6 +122,7 @@ func CmdConnectorUpdateFactory(configuredPlatform types.Platform) *cobra.Command
 	cmd.Flags().DurationVar(&cmdFlags.Timeout, common.FlagNameTimeout, 60*time.Second, common.FlagDescTimeout)
 	cmd.Flags().StringVarP(&cmdFlags.Output, common.FlagNameOutput, "o", "", common.FlagDescOutput)
 	cmd.Flags().IntVar(&cmdFlags.Port, common.FlagNameConnectorPort, 0, common.FlagDescConnectorPort)
+	cmd.Flags().StringVar(&cmdFlags.Wait, common.FlagNameWait, "configured", common.FlagDescWait)
 
 	kubeCommand.CobraCmd = cmd
 	kubeCommand.Flags = &cmdFlags
@@ -129,6 +133,8 @@ func CmdConnectorUpdateFactory(configuredPlatform types.Platform) *cobra.Command
 		cmd.Flags().MarkHidden(common.FlagNameIncludeNotReadyPods)
 		cmd.Flags().MarkHidden(common.FlagNameSelector)
 		cmd.Flags().MarkHidden(common.FlagNameWorkload)
+		cmd.Flags().MarkHidden(common.FlagNameTimeout)
+		cmd.Flags().MarkHidden(common.FlagNameWait)
 	}
 
 	return cmd
@@ -149,6 +155,7 @@ func CmdConnectorDeleteFactory(configuredPlatform types.Platform) *cobra.Command
 
 	cmdFlags := common.CommandConnectorDeleteFlags{}
 	cmd.Flags().DurationVarP(&cmdFlags.Timeout, common.FlagNameTimeout, "t", 60*time.Second, common.FlagDescTimeout)
+	cmd.Flags().BoolVar(&cmdFlags.Wait, common.FlagNameWait, true, common.FlagDescDeleteWait)
 
 	kubeCommand.CobraCmd = cmd
 	kubeCommand.Flags = &cmdFlags
diff --git a/internal/cmd/skupper/connector/kube/connector_create.go b/internal/cmd/skupper/connector/kube/connector_create.go
index 411b9644..c2d3c5e7 100644
--- a/internal/cmd/skupper/connector/kube/connector_create.go
+++ b/internal/cmd/skupper/connector/kube/connector_create.go
@@ -3,6 +3,7 @@ package kube
 import (
 	"context"
 	"fmt"
+	"k8s.io/apimachinery/pkg/api/meta"
 	"strconv"
 	"time"
 
@@ -36,6 +37,7 @@ type CmdConnectorCreate struct {
 	includeNotReadyPods bool
 	timeout             time.Duration
 	KubeClient          kubernetes.Interface
+	status              string
 }
 
 func NewCmdConnectorCreate() *CmdConnectorCreate {
@@ -61,6 +63,7 @@ func (cmd *CmdConnectorCreate) ValidateInput(args []string) []error {
 	timeoutValidator := validator.NewTimeoutInSecondsValidator()
 	workloadStringValidator := validator.NewWorkloadStringValidator(common.WorkloadTypes)
 	selectorStringValidator := validator.NewSelectorStringValidator()
+	statusValidator := validator.NewOptionValidator(common.WaitStatusTypes)
 
 	// Validate arguments name and port
 	if len(args) < 2 {
@@ -203,6 +206,14 @@ func (cmd *CmdConnectorCreate) ValidateInput(args []string) []error {
 			validationErrors = append(validationErrors, fmt.Errorf("output type is not valid: %s", err))
 		}
 	}
+
+	if cmd.Flags != nil && cmd.Flags.Wait != "" {
+		ok, err := statusValidator.Evaluate(cmd.Flags.Wait)
+		if !ok {
+			validationErrors = append(validationErrors, fmt.Errorf("status is not valid: %s", err))
+		}
+	}
+
 	return validationErrors
 }
 
@@ -231,6 +242,7 @@ func (cmd *CmdConnectorCreate) InputToOptions() {
 	cmd.connectorType = cmd.Flags.ConnectorType
 	cmd.output = cmd.Flags.Output
 	cmd.includeNotReadyPods = cmd.Flags.IncludeNotReadyPods
+	cmd.status = cmd.Flags.Wait
 }
 
 func (cmd *CmdConnectorCreate) Run() error {
@@ -271,7 +283,14 @@ func (cmd *CmdConnectorCreate) WaitUntil() error {
 		return nil
 	}
 
+	if cmd.status == "none" {
+		return nil
+	}
+
 	waitTime := int(cmd.timeout.Seconds())
+
+	var connectorCondition *metav1.Condition
+
 	err := utils.NewSpinnerWithTimeout("Waiting for create to complete...", waitTime, func() error {
 
 		resource, err := cmd.client.Connectors(cmd.namespace).Get(context.TODO(), cmd.name, metav1.GetOptions{})
@@ -279,17 +298,39 @@ func (cmd *CmdConnectorCreate) WaitUntil() error {
 			return err
 		}
 
-		if resource != nil && resource.IsConfigured() {
+		isConditionFound := false
+		isConditionTrue := false
+
+		switch cmd.status {
+		case "ready":
+			connectorCondition = meta.FindStatusCondition(resource.Status.Conditions, v2alpha1.CONDITION_TYPE_READY)
+		default:
+			connectorCondition = meta.FindStatusCondition(resource.Status.Conditions, v2alpha1.CONDITION_TYPE_CONFIGURED)
+
+		}
+
+		if connectorCondition != nil {
+			isConditionFound = true
+			isConditionTrue = connectorCondition.Status == metav1.ConditionTrue
+		}
+
+		if resource != nil && isConditionFound && isConditionTrue {
 			return nil
 		}
 
+		if resource != nil && isConditionFound && !isConditionTrue {
+			return fmt.Errorf("error in the condition")
+		}
+
 		return fmt.Errorf("error getting the resource")
 	})
 
-	if err != nil {
-		return fmt.Errorf("Connector %q not ready yet, check the status for more information\n", cmd.name)
+	if err != nil && connectorCondition == nil {
+		return fmt.Errorf("Connector %q is not %s yet, check the status for more information\n", cmd.name, cmd.status)
+	} else if err != nil && connectorCondition.Status == metav1.ConditionFalse {
+		return fmt.Errorf("Connector %q is %s with errors, check the status for more information\n", cmd.name, cmd.status)
 	}
 
-	fmt.Printf("Connector %q is ready\n", cmd.name)
+	fmt.Printf("Connector %q is %s.\n", cmd.name, cmd.status)
 	return nil
 }
diff --git a/internal/cmd/skupper/connector/kube/connector_delete.go b/internal/cmd/skupper/connector/kube/connector_delete.go
index 013d242d..527cd943 100644
--- a/internal/cmd/skupper/connector/kube/connector_delete.go
+++ b/internal/cmd/skupper/connector/kube/connector_delete.go
@@ -20,6 +20,7 @@ type CmdConnectorDelete struct {
 	Flags     *common.CommandConnectorDeleteFlags
 	namespace string
 	name      string
+	wait      bool
 }
 
 func NewCmdConnectorDelete() *CmdConnectorDelete {
@@ -79,23 +80,29 @@ func (cmd *CmdConnectorDelete) Run() error {
 }
 
 func (cmd *CmdConnectorDelete) WaitUntil() error {
-	waitTime := int(cmd.Flags.Timeout.Seconds())
-	err := utils.NewSpinnerWithTimeout("Waiting for deletion to complete...", waitTime, func() error {
 
-		resource, err := cmd.client.Connectors(cmd.namespace).Get(context.TODO(), cmd.name, metav1.GetOptions{})
-		if err == nil && resource != nil {
-			return fmt.Errorf("error deleting the resource")
-		} else {
-			return nil
+	if cmd.wait {
+		waitTime := int(cmd.Flags.Timeout.Seconds())
+		err := utils.NewSpinnerWithTimeout("Waiting for deletion to complete...", waitTime, func() error {
+
+			resource, err := cmd.client.Connectors(cmd.namespace).Get(context.TODO(), cmd.name, metav1.GetOptions{})
+			if err == nil && resource != nil {
+				return fmt.Errorf("error deleting the resource")
+			} else {
+				return nil
+			}
+		})
+
+		if err != nil {
+			return fmt.Errorf("Connector %q not deleted yet, check the status for more information %s\n", cmd.name, err)
 		}
-	})
 
-	if err != nil {
-		return fmt.Errorf("Connector %q not deleted yet, check the status for more information %s\n", cmd.name, err)
-	}
+		fmt.Printf("Connector %q deleted\n", cmd.name)
 
-	fmt.Printf("Connector %q deleted\n", cmd.name)
+	}
 	return nil
 }
 
-func (cmd *CmdConnectorDelete) InputToOptions() {}
+func (cmd *CmdConnectorDelete) InputToOptions() {
+	cmd.wait = cmd.Flags.Wait
+}
diff --git a/internal/cmd/skupper/connector/kube/connector_update.go b/internal/cmd/skupper/connector/kube/connector_update.go
index 3551c166..b15a2360 100644
--- a/internal/cmd/skupper/connector/kube/connector_update.go
+++ b/internal/cmd/skupper/connector/kube/connector_update.go
@@ -3,6 +3,7 @@ package kube
 import (
 	"context"
 	"fmt"
+	"k8s.io/apimachinery/pkg/api/meta"
 	"time"
 
 	"github.com/skupperproject/skupper/internal/cmd/skupper/common"
@@ -43,6 +44,7 @@ type CmdConnectorUpdate struct {
 	existingHost     string
 	existingSelector string
 	KubeClient       kubernetes.Interface
+	status           string
 }
 
 func NewCmdConnectorUpdate() *CmdConnectorUpdate {
@@ -69,6 +71,7 @@ func (cmd *CmdConnectorUpdate) ValidateInput(args []string) []error {
 	timeoutValidator := validator.NewTimeoutInSecondsValidator()
 	workloadStringValidator := validator.NewWorkloadStringValidator(common.WorkloadTypes)
 	selectorStringValidator := validator.NewSelectorStringValidator()
+	statusValidator := validator.NewOptionValidator(common.WaitStatusTypes)
 
 	// Validate arguments name
 	if len(args) < 1 {
@@ -235,6 +238,14 @@ func (cmd *CmdConnectorUpdate) ValidateInput(args []string) []error {
 			cmd.newSettings.output = cmd.Flags.Output
 		}
 	}
+
+	if cmd.Flags != nil && cmd.Flags.Wait != "" {
+		ok, err := statusValidator.Evaluate(cmd.Flags.Wait)
+		if !ok {
+			validationErrors = append(validationErrors, fmt.Errorf("status is not valid: %s", err))
+		}
+	}
+
 	return validationErrors
 }
 
@@ -278,7 +289,12 @@ func (cmd *CmdConnectorUpdate) WaitUntil() error {
 		return nil
 	}
 
+	if cmd.status == "none" {
+		return nil
+	}
+
 	waitTime := int(cmd.Flags.Timeout.Seconds())
+	var connectorCondition *metav1.Condition
 	err := utils.NewSpinnerWithTimeout("Waiting for update to complete...", waitTime, func() error {
 
 		resource, err := cmd.client.Connectors(cmd.namespace).Get(context.TODO(), cmd.name, metav1.GetOptions{})
@@ -286,19 +302,43 @@ func (cmd *CmdConnectorUpdate) WaitUntil() error {
 			return err
 		}
 
-		if resource != nil && resource.IsConfigured() {
+		isConditionFound := false
+		isConditionTrue := false
+
+		switch cmd.status {
+		case "ready":
+			connectorCondition = meta.FindStatusCondition(resource.Status.Conditions, v2alpha1.CONDITION_TYPE_READY)
+		default:
+			connectorCondition = meta.FindStatusCondition(resource.Status.Conditions, v2alpha1.CONDITION_TYPE_CONFIGURED)
+
+		}
+
+		if connectorCondition != nil {
+			isConditionFound = true
+			isConditionTrue = connectorCondition.Status == metav1.ConditionTrue
+		}
+
+		if resource != nil && isConditionFound && isConditionTrue {
 			return nil
 		}
 
+		if resource != nil && isConditionFound && !isConditionTrue {
+			return fmt.Errorf("error in the condition")
+		}
+
 		return fmt.Errorf("error getting the resource")
 	})
 
-	if err != nil {
-		return fmt.Errorf("Connector %q not ready yet, check the status for more information\n", cmd.name)
+	if err != nil && connectorCondition == nil {
+		return fmt.Errorf("Connector %q is not %s yet, check the status for more information\n", cmd.name, cmd.status)
+	} else if err != nil && connectorCondition.Status == metav1.ConditionFalse {
+		return fmt.Errorf("Connector %q is %s with errors, check the status for more information\n", cmd.name, cmd.status)
 	}
 
-	fmt.Printf("Connector %q is ready\n", cmd.name)
+	fmt.Printf("Connector %q is %s.\n", cmd.name, cmd.status)
 	return nil
 }
 
-func (cmd *CmdConnectorUpdate) InputToOptions() {}
+func (cmd *CmdConnectorUpdate) InputToOptions() {
+	cmd.status = cmd.Flags.Wait
+}
diff --git a/internal/cmd/skupper/link/kube/link_delete.go b/internal/cmd/skupper/link/kube/link_delete.go
index 5d8a2060..f722c676 100644
--- a/internal/cmd/skupper/link/kube/link_delete.go
+++ b/internal/cmd/skupper/link/kube/link_delete.go
@@ -20,6 +20,7 @@ type CmdLinkDelete struct {
 	Flags     *common.CommandLinkDeleteFlags
 	linkName  string
 	timeout   time.Duration
+	wait      bool
 }
 
 func NewCmdLinkDelete() *CmdLinkDelete {
@@ -66,6 +67,7 @@ func (cmd *CmdLinkDelete) ValidateInput(args []string) []error {
 }
 func (cmd *CmdLinkDelete) InputToOptions() {
 	cmd.timeout = cmd.Flags.Timeout
+	cmd.wait = cmd.Flags.Wait
 }
 
 func (cmd *CmdLinkDelete) Run() error {
@@ -73,24 +75,27 @@ func (cmd *CmdLinkDelete) Run() error {
 	return err
 }
 func (cmd *CmdLinkDelete) WaitUntil() error {
-	waitTime := int(cmd.timeout.Seconds())
-	err := utils.NewSpinnerWithTimeout("Waiting for deletion to complete...", waitTime, func() error {
 
-		resource, err := cmd.Client.Links(cmd.Namespace).Get(context.TODO(), cmd.linkName, metav1.GetOptions{})
+	if cmd.wait {
+		waitTime := int(cmd.timeout.Seconds())
+		err := utils.NewSpinnerWithTimeout("Waiting for deletion to complete...", waitTime, func() error {
 
-		if err == nil && resource != nil {
-			return fmt.Errorf("error deleting the resource")
-		} else {
-			return nil
-		}
+			resource, err := cmd.Client.Links(cmd.Namespace).Get(context.TODO(), cmd.linkName, metav1.GetOptions{})
 
-	})
+			if err == nil && resource != nil {
+				return fmt.Errorf("error deleting the resource")
+			} else {
+				return nil
+			}
 
-	if err != nil {
-		return fmt.Errorf("Link %q not deleted yet, check the status for more information\n", cmd.linkName)
-	}
+		})
 
-	fmt.Printf("Link %q is deleted\n", cmd.linkName)
+		if err != nil {
+			return fmt.Errorf("Link %q not deleted yet, check the status for more information\n", cmd.linkName)
+		}
+
+		fmt.Printf("Link %q is deleted\n", cmd.linkName)
+	}
 
 	return nil
 }
diff --git a/internal/cmd/skupper/link/kube/link_update.go b/internal/cmd/skupper/link/kube/link_update.go
index 7378fcc9..2ba3d753 100644
--- a/internal/cmd/skupper/link/kube/link_update.go
+++ b/internal/cmd/skupper/link/kube/link_update.go
@@ -13,6 +13,7 @@ import (
 	skupperv2alpha1 "github.com/skupperproject/skupper/pkg/generated/client/clientset/versioned/typed/skupper/v2alpha1"
 	"github.com/skupperproject/skupper/pkg/utils/validator"
 	"github.com/spf13/cobra"
+	"k8s.io/apimachinery/pkg/api/meta"
 	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
 	"k8s.io/client-go/kubernetes"
 	"strconv"
@@ -30,6 +31,7 @@ type CmdLinkUpdate struct {
 	cost           int
 	output         string
 	timeout        time.Duration
+	status         string
 }
 
 func NewCmdLinkUpdate() *CmdLinkUpdate {
@@ -51,6 +53,7 @@ func (cmd *CmdLinkUpdate) ValidateInput(args []string) []error {
 	numberValidator := validator.NewNumberValidator()
 	timeoutValidator := validator.NewTimeoutInSecondsValidator()
 	outputTypeValidator := validator.NewOptionValidator(common.OutputTypes)
+	statusValidator := validator.NewOptionValidator(common.WaitStatusTypes)
 
 	//Validate if there is already a site defined in the namespace
 	siteList, _ := cmd.Client.Sites(cmd.Namespace).List(context.TODO(), metav1.ListOptions{})
@@ -98,6 +101,13 @@ func (cmd *CmdLinkUpdate) ValidateInput(args []string) []error {
 		validationErrors = append(validationErrors, fmt.Errorf("timeout is not valid: %s", err))
 	}
 
+	if cmd.Flags != nil && cmd.Flags.Wait != "" {
+		ok, err := statusValidator.Evaluate(cmd.Flags.Wait)
+		if !ok {
+			validationErrors = append(validationErrors, fmt.Errorf("status is not valid: %s", err))
+		}
+	}
+
 	return validationErrors
 }
 
@@ -107,6 +117,7 @@ func (cmd *CmdLinkUpdate) InputToOptions() {
 	cmd.tlsCredentials = cmd.Flags.TlsCredentials
 	cmd.output = cmd.Flags.Output
 	cmd.timeout = cmd.Flags.Timeout
+	cmd.status = cmd.Flags.Wait
 
 }
 
@@ -165,7 +176,12 @@ func (cmd *CmdLinkUpdate) WaitUntil() error {
 		return nil
 	}
 
+	if cmd.status == "none" {
+		return nil
+	}
+
 	waitTime := int(cmd.timeout.Seconds())
+	var linkCondition *metav1.Condition
 	err := utils.NewSpinnerWithTimeout("Waiting for update to complete...", waitTime, func() error {
 
 		resource, err := cmd.Client.Links(cmd.Namespace).Get(context.TODO(), cmd.linkName, metav1.GetOptions{})
@@ -173,15 +189,36 @@ func (cmd *CmdLinkUpdate) WaitUntil() error {
 			return err
 		}
 
-		if resource != nil && resource.IsConfigured() {
+		isConditionFound := false
+		isConditionTrue := false
+
+		switch cmd.status {
+		case "configured":
+			linkCondition = meta.FindStatusCondition(resource.Status.Conditions, v2alpha1.CONDITION_TYPE_CONFIGURED)
+		default:
+			linkCondition = meta.FindStatusCondition(resource.Status.Conditions, v2alpha1.CONDITION_TYPE_READY)
+		}
+
+		if linkCondition != nil {
+			isConditionFound = true
+			isConditionTrue = linkCondition.Status == metav1.ConditionTrue
+		}
+
+		if resource != nil && isConditionFound && isConditionTrue {
 			return nil
 		}
 
+		if resource != nil && isConditionFound && !isConditionTrue {
+			return fmt.Errorf("error in the condition")
+		}
+
 		return fmt.Errorf("error getting the resource")
 	})
 
-	if err != nil {
-		return fmt.Errorf("Link %q not updated yet, check the status for more information\n", cmd.linkName)
+	if err != nil && linkCondition == nil {
+		return fmt.Errorf("Link %q is not %s yet, check the status for more information\n", cmd.linkName, cmd.status)
+	} else if err != nil && linkCondition.Status == metav1.ConditionFalse {
+		return fmt.Errorf("Link %q is %s with errors, check the status for more information\n", cmd.linkName, cmd.status)
 	}
 
 	fmt.Printf("Link %q is updated\n", cmd.linkName)
diff --git a/internal/cmd/skupper/link/link.go b/internal/cmd/skupper/link/link.go
index 5b698067..6661daf6 100644
--- a/internal/cmd/skupper/link/link.go
+++ b/internal/cmd/skupper/link/link.go
@@ -72,12 +72,17 @@ func CmdLinkUpdateFactory(configuredPlatform types.Platform) *cobra.Command {
 	cmd.Flags().StringVar(&cmdFlags.Cost, common.FlagNameCost, "1", common.FlagDescCost)
 	cmd.Flags().DurationVar(&cmdFlags.Timeout, common.FlagNameTimeout, 60*time.Second, common.FlagDescTimeout)
 	cmd.Flags().StringVarP(&cmdFlags.Output, common.FlagNameOutput, "o", "", common.FlagDescOutput)
+	cmd.Flags().StringVar(&cmdFlags.Wait, common.FlagNameWait, "ready", common.FlagDescWait)
 
 	kubeCommand.CobraCmd = cmd
 	kubeCommand.Flags = &cmdFlags
 	nonKubeCommand.CobraCmd = cmd
 	nonKubeCommand.Flags = &cmdFlags
 
+	if configuredPlatform != types.PlatformKubernetes {
+		cmd.Flags().MarkHidden(common.FlagNameWait)
+	}
+
 	return cmd
 }
 
@@ -118,11 +123,16 @@ func CmdLinkDeleteFactory(configuredPlatform types.Platform) *cobra.Command {
 	cmd := common.ConfigureCobraCommand(configuredPlatform, cmdLinkDeleteDesc, kubeCommand, nonKubeCommand)
 	cmdFlags := common.CommandLinkDeleteFlags{}
 	cmd.Flags().DurationVar(&cmdFlags.Timeout, common.FlagNameTimeout, 60*time.Second, common.FlagDescTimeout)
+	cmd.Flags().BoolVar(&cmdFlags.Wait, common.FlagNameWait, true, common.FlagDescDeleteWait)
 
 	kubeCommand.CobraCmd = cmd
 	kubeCommand.Flags = &cmdFlags
 	nonKubeCommand.CobraCmd = cmd
 	nonKubeCommand.Flags = &cmdFlags
 
+	if configuredPlatform != types.PlatformKubernetes {
+		cmd.Flags().MarkHidden(common.FlagNameWait)
+	}
+
 	return cmd
 }
diff --git a/internal/cmd/skupper/listener/kube/listener_create.go b/internal/cmd/skupper/listener/kube/listener_create.go
index 07b947c9..6574f923 100644
--- a/internal/cmd/skupper/listener/kube/listener_create.go
+++ b/internal/cmd/skupper/listener/kube/listener_create.go
@@ -3,6 +3,7 @@ package kube
 import (
 	"context"
 	"fmt"
+	"k8s.io/apimachinery/pkg/api/meta"
 	"strconv"
 	"time"
 
@@ -33,6 +34,7 @@ type CmdListenerCreate struct {
 	timeout        time.Duration
 	output         string
 	KubeClient     kubernetes.Interface
+	status         string
 }
 
 func NewCmdListenerCreate() *CmdListenerCreate {
@@ -57,6 +59,7 @@ func (cmd *CmdListenerCreate) ValidateInput(args []string) []error {
 	listenerTypeValidator := validator.NewOptionValidator(common.ListenerTypes)
 	outputTypeValidator := validator.NewOptionValidator(common.OutputTypes)
 	timeoutValidator := validator.NewTimeoutInSecondsValidator()
+	statusValidator := validator.NewOptionValidator(common.WaitStatusTypes)
 
 	// Validate arguments name and port
 	if len(args) < 2 {
@@ -129,6 +132,14 @@ func (cmd *CmdListenerCreate) ValidateInput(args []string) []error {
 			validationErrors = append(validationErrors, fmt.Errorf("output type is not valid: %s", err))
 		}
 	}
+
+	if cmd.Flags != nil && cmd.Flags.Wait != "" {
+		ok, err := statusValidator.Evaluate(cmd.Flags.Wait)
+		if !ok {
+			validationErrors = append(validationErrors, fmt.Errorf("status is not valid: %s", err))
+		}
+	}
+
 	return validationErrors
 }
 
@@ -148,6 +159,7 @@ func (cmd *CmdListenerCreate) InputToOptions() {
 	cmd.tlsCredentials = cmd.Flags.TlsCredentials
 	cmd.listenerType = cmd.Flags.ListenerType
 	cmd.output = cmd.Flags.Output
+	cmd.status = cmd.Flags.Wait
 }
 
 func (cmd *CmdListenerCreate) Run() error {
@@ -186,7 +198,13 @@ func (cmd *CmdListenerCreate) WaitUntil() error {
 		return nil
 	}
 
+	if cmd.status == "none" {
+		return nil
+	}
+
 	waitTime := int(cmd.timeout.Seconds())
+	var listenerCondition *metav1.Condition
+
 	err := utils.NewSpinnerWithTimeout("Waiting for create to complete...", waitTime, func() error {
 
 		resource, err := cmd.client.Listeners(cmd.namespace).Get(context.TODO(), cmd.name, metav1.GetOptions{})
@@ -194,17 +212,38 @@ func (cmd *CmdListenerCreate) WaitUntil() error {
 			return err
 		}
 
-		if resource != nil && resource.IsConfigured() {
+		isConditionFound := false
+		isConditionTrue := false
+
+		switch cmd.status {
+		case "ready":
+			listenerCondition = meta.FindStatusCondition(resource.Status.Conditions, v2alpha1.CONDITION_TYPE_READY)
+		default:
+			listenerCondition = meta.FindStatusCondition(resource.Status.Conditions, v2alpha1.CONDITION_TYPE_CONFIGURED)
+		}
+
+		if listenerCondition != nil {
+			isConditionFound = true
+			isConditionTrue = listenerCondition.Status == metav1.ConditionTrue
+		}
+
+		if resource != nil && isConditionFound && isConditionTrue {
 			return nil
 		}
 
+		if resource != nil && isConditionFound && !isConditionTrue {
+			return fmt.Errorf("error in the condition")
+		}
+
 		return fmt.Errorf("error getting the resource")
 	})
 
-	if err != nil {
-		return fmt.Errorf("Listener %q not ready yet, check the status for more information\n", cmd.name)
+	if err != nil && listenerCondition == nil {
+		return fmt.Errorf("Listener %q is not %s yet, check the status for more information\n", cmd.name, cmd.status)
+	} else if err != nil && listenerCondition.Status == metav1.ConditionFalse {
+		return fmt.Errorf("Listener %q is %s with errors, check the status for more information\n", cmd.name, cmd.status)
 	}
 
-	fmt.Printf("Listener %q is ready\n", cmd.name)
+	fmt.Printf("Listener %q is %s.\n", cmd.name, cmd.status)
 	return nil
 }
diff --git a/internal/cmd/skupper/listener/kube/listener_delete.go b/internal/cmd/skupper/listener/kube/listener_delete.go
index e35df2fb..38e8bfa1 100644
--- a/internal/cmd/skupper/listener/kube/listener_delete.go
+++ b/internal/cmd/skupper/listener/kube/listener_delete.go
@@ -20,6 +20,7 @@ type CmdListenerDelete struct {
 	Flags     *common.CommandListenerDeleteFlags
 	namespace string
 	name      string
+	wait      bool
 }
 
 func NewCmdListenerDelete() *CmdListenerDelete {
@@ -80,23 +81,28 @@ func (cmd *CmdListenerDelete) Run() error {
 }
 
 func (cmd *CmdListenerDelete) WaitUntil() error {
-	waitTime := int(cmd.Flags.Timeout.Seconds())
-	err := utils.NewSpinnerWithTimeout("Waiting for deletion to complete...", waitTime, func() error {
 
-		resource, err := cmd.client.Listeners(cmd.namespace).Get(context.TODO(), cmd.name, metav1.GetOptions{})
-		if err == nil && resource != nil {
-			return fmt.Errorf("error deleting the resource")
-		} else {
-			return nil
+	if cmd.wait {
+		waitTime := int(cmd.Flags.Timeout.Seconds())
+		err := utils.NewSpinnerWithTimeout("Waiting for deletion to complete...", waitTime, func() error {
+
+			resource, err := cmd.client.Listeners(cmd.namespace).Get(context.TODO(), cmd.name, metav1.GetOptions{})
+			if err == nil && resource != nil {
+				return fmt.Errorf("error deleting the resource")
+			} else {
+				return nil
+			}
+		})
+
+		if err != nil {
+			return fmt.Errorf("Listener %q not deleted yet, check the status for more information %s\n", cmd.name, err)
 		}
-	})
 
-	if err != nil {
-		return fmt.Errorf("Listener %q not deleted yet, check the status for more information %s\n", cmd.name, err)
+		fmt.Printf("Listener %q deleted\n", cmd.name)
 	}
-
-	fmt.Printf("Listener %q deleted\n", cmd.name)
 	return nil
 }
 
-func (cmd *CmdListenerDelete) InputToOptions() {}
+func (cmd *CmdListenerDelete) InputToOptions() {
+	cmd.wait = cmd.Flags.Wait
+}
diff --git a/internal/cmd/skupper/listener/kube/listener_update.go b/internal/cmd/skupper/listener/kube/listener_update.go
index abb576df..ca829296 100644
--- a/internal/cmd/skupper/listener/kube/listener_update.go
+++ b/internal/cmd/skupper/listener/kube/listener_update.go
@@ -3,6 +3,7 @@ package kube
 import (
 	"context"
 	"fmt"
+	"k8s.io/apimachinery/pkg/api/meta"
 	"time"
 
 	"github.com/skupperproject/skupper/internal/cmd/skupper/common"
@@ -36,6 +37,7 @@ type CmdListenerUpdate struct {
 	resourceVersion string
 	newSettings     ListenerUpdates
 	KubeClient      kubernetes.Interface
+	status          string
 }
 
 func NewCmdListenerUpdate() *CmdListenerUpdate {
@@ -59,6 +61,7 @@ func (cmd *CmdListenerUpdate) ValidateInput(args []string) []error {
 	listenerTypeValidator := validator.NewOptionValidator(common.ListenerTypes)
 	outputTypeValidator := validator.NewOptionValidator(common.OutputTypes)
 	timeoutValidator := validator.NewTimeoutInSecondsValidator()
+	statusValidator := validator.NewOptionValidator(common.WaitStatusTypes)
 
 	// Validate arguments name
 	if len(args) < 1 {
@@ -143,6 +146,13 @@ func (cmd *CmdListenerUpdate) ValidateInput(args []string) []error {
 		}
 	}
 
+	if cmd.Flags != nil && cmd.Flags.Wait != "" {
+		ok, err := statusValidator.Evaluate(cmd.Flags.Wait)
+		if !ok {
+			validationErrors = append(validationErrors, fmt.Errorf("status is not valid: %s", err))
+		}
+	}
+
 	return validationErrors
 }
 
@@ -183,27 +193,54 @@ func (cmd *CmdListenerUpdate) WaitUntil() error {
 		return nil
 	}
 
+	if cmd.status == "none" {
+		return nil
+	}
+
 	waitTime := int(cmd.Flags.Timeout.Seconds())
+	var listenerCondition *metav1.Condition
 	err := utils.NewSpinnerWithTimeout("Waiting for update to complete...", waitTime, func() error {
 
 		resource, err := cmd.client.Listeners(cmd.namespace).Get(context.TODO(), cmd.name, metav1.GetOptions{})
 		if err != nil {
 			return err
 		}
+		isConditionFound := false
+		isConditionTrue := false
+
+		switch cmd.status {
+		case "ready":
+			listenerCondition = meta.FindStatusCondition(resource.Status.Conditions, v2alpha1.CONDITION_TYPE_READY)
+		default:
+			listenerCondition = meta.FindStatusCondition(resource.Status.Conditions, v2alpha1.CONDITION_TYPE_CONFIGURED)
+		}
+
+		if listenerCondition != nil {
+			isConditionFound = true
+			isConditionTrue = listenerCondition.Status == metav1.ConditionTrue
+		}
 
-		if resource != nil && resource.IsConfigured() {
+		if resource != nil && isConditionFound && isConditionTrue {
 			return nil
 		}
 
+		if resource != nil && isConditionFound && !isConditionTrue {
+			return fmt.Errorf("error in the condition")
+		}
+
 		return fmt.Errorf("error getting the resource")
 	})
 
-	if err != nil {
-		return fmt.Errorf("Listener %q not ready yet, check the status for more information\n", cmd.name)
+	if err != nil && listenerCondition == nil {
+		return fmt.Errorf("Listener %q is not %s yet, check the status for more information\n", cmd.name, cmd.status)
+	} else if err != nil && listenerCondition.Status == metav1.ConditionFalse {
+		return fmt.Errorf("Listener %q is %s with errors, check the status for more information\n", cmd.name, cmd.status)
 	}
 
-	fmt.Printf("Listener %q is ready\n", cmd.name)
+	fmt.Printf("Listener %q is updated\n", cmd.name)
 	return nil
 }
 
-func (cmd *CmdListenerUpdate) InputToOptions() {}
+func (cmd *CmdListenerUpdate) InputToOptions() {
+	cmd.status = cmd.Flags.Wait
+}
diff --git a/internal/cmd/skupper/listener/listener.go b/internal/cmd/skupper/listener/listener.go
index 6675ee60..3215f561 100644
--- a/internal/cmd/skupper/listener/listener.go
+++ b/internal/cmd/skupper/listener/listener.go
@@ -50,12 +50,18 @@ func CmdListenerCreateFactory(configuredPlatform types.Platform) *cobra.Command
 	cmd.Flags().StringVar(&cmdFlags.ListenerType, common.FlagNameListenerType, "tcp", common.FlagDescListenerType)
 	cmd.Flags().DurationVar(&cmdFlags.Timeout, common.FlagNameTimeout, 60*time.Second, common.FlagDescTimeout)
 	cmd.Flags().StringVarP(&cmdFlags.Output, common.FlagNameOutput, "o", "", common.FlagDescOutput)
+	cmd.Flags().StringVar(&cmdFlags.Wait, common.FlagNameWait, "configured", common.FlagDescWait)
 
 	kubeCommand.CobraCmd = cmd
 	kubeCommand.Flags = &cmdFlags
 	nonKubeCommand.CobraCmd = cmd
 	nonKubeCommand.Flags = &cmdFlags
 
+	if configuredPlatform != types.PlatformKubernetes {
+		cmd.Flags().MarkHidden(common.FlagNameTimeout)
+		cmd.Flags().MarkHidden(common.FlagNameWait)
+	}
+
 	return cmd
 }
 
@@ -82,12 +88,18 @@ func CmdListenerUpdateFactory(configuredPlatform types.Platform) *cobra.Command
 	cmd.Flags().DurationVar(&cmdFlags.Timeout, common.FlagNameTimeout, 60*time.Second, common.FlagDescTimeout)
 	cmd.Flags().IntVar(&cmdFlags.Port, common.FlagNameListenerPort, 0, common.FlagDescListenerPort)
 	cmd.Flags().StringVarP(&cmdFlags.Output, common.FlagNameOutput, "o", "", common.FlagDescOutput)
+	cmd.Flags().StringVar(&cmdFlags.Wait, common.FlagNameWait, "configured", common.FlagDescWait)
 
 	kubeCommand.CobraCmd = cmd
 	kubeCommand.Flags = &cmdFlags
 	nonKubeCommand.CobraCmd = cmd
 	nonKubeCommand.Flags = &cmdFlags
 
+	if configuredPlatform != types.PlatformKubernetes {
+		cmd.Flags().MarkHidden(common.FlagNameTimeout)
+		cmd.Flags().MarkHidden(common.FlagNameWait)
+	}
+
 	return cmd
 }
 
@@ -132,11 +144,17 @@ func CmdListenerDeleteFactory(configuredPlatform types.Platform) *cobra.Command
 	cmdFlags := common.CommandListenerDeleteFlags{}
 
 	cmd.Flags().DurationVarP(&cmdFlags.Timeout, common.FlagNameTimeout, "t", 60*time.Second, common.FlagDescTimeout)
+	cmd.Flags().BoolVar(&cmdFlags.Wait, common.FlagNameWait, true, common.FlagDescDeleteWait)
 
 	kubeCommand.CobraCmd = cmd
 	kubeCommand.Flags = &cmdFlags
 	nonKubeCommand.CobraCmd = cmd
 	nonKubeCommand.Flags = &cmdFlags
 
+	if configuredPlatform != types.PlatformKubernetes {
+		cmd.Flags().MarkHidden(common.FlagNameTimeout)
+		cmd.Flags().MarkHidden(common.FlagNameWait)
+	}
+
 	return cmd
 }
diff --git a/internal/cmd/skupper/site/kube/site_create.go b/internal/cmd/skupper/site/kube/site_create.go
index a65d8c08..6e8f4571 100644
--- a/internal/cmd/skupper/site/kube/site_create.go
+++ b/internal/cmd/skupper/site/kube/site_create.go
@@ -226,7 +226,7 @@ func (cmd *CmdSiteCreate) WaitUntil() error {
 
 	if err != nil && siteCondition == nil {
 		return fmt.Errorf("Site %q is not %s yet, check the status for more information\n", cmd.siteName, cmd.status)
-	} else if err != nil {
+	} else if err != nil && siteCondition.Status == metav1.ConditionFalse {
 		return fmt.Errorf("Site %q is %s with errors, check the status for more information\n", cmd.siteName, cmd.status)
 	}
 
diff --git a/internal/cmd/skupper/site/kube/site_delete.go b/internal/cmd/skupper/site/kube/site_delete.go
index 584b694c..1779161d 100644
--- a/internal/cmd/skupper/site/kube/site_delete.go
+++ b/internal/cmd/skupper/site/kube/site_delete.go
@@ -86,6 +86,7 @@ func (cmd *CmdSiteDelete) ValidateInput(args []string) []error {
 }
 func (cmd *CmdSiteDelete) InputToOptions() {
 	cmd.timeout = cmd.Flags.Timeout
+	cmd.wait = cmd.Flags.Wait
 }
 
 func (cmd *CmdSiteDelete) Run() error {
diff --git a/internal/cmd/skupper/site/kube/site_update.go b/internal/cmd/skupper/site/kube/site_update.go
index f8ef43f3..c5a22a2e 100644
--- a/internal/cmd/skupper/site/kube/site_update.go
+++ b/internal/cmd/skupper/site/kube/site_update.go
@@ -245,7 +245,7 @@ func (cmd *CmdSiteUpdate) WaitUntil() error {
 
 	if err != nil && siteCondition == nil {
 		return fmt.Errorf("Site %q is not %s yet, check the status for more information\n", cmd.siteName, cmd.status)
-	} else if err != nil {
+	} else if err != nil && siteCondition.Status == metav1.ConditionFalse {
 		return fmt.Errorf("Site %q is %s with errors, check the status for more information\n", cmd.siteName, cmd.status)
 	}
 
diff --git a/pkg/apis/skupper/v2alpha1/types.go b/pkg/apis/skupper/v2alpha1/types.go
index 5394298a..785390f2 100644
--- a/pkg/apis/skupper/v2alpha1/types.go
+++ b/pkg/apis/skupper/v2alpha1/types.go
@@ -596,13 +596,14 @@ type LinkStatus struct {
 type AccessToken struct {
 	v1.TypeMeta   `json:",inline"`
 	v1.ObjectMeta `json:"metadata,omitempty"`
-	Spec          AccessTokenSpec `json:"spec,omitempty"`
-	Status        Status          `json:"status,omitempty"`
+	Spec          AccessTokenSpec   `json:"spec,omitempty"`
+	Status        AccessTokenStatus `json:"status,omitempty"`
 }
 
 func (t *AccessToken) SetRedeemed(err error) bool {
 	state := ErrorOrReadyCondition(err)
 	if t.Status.SetCondition(CONDITION_TYPE_REDEEMED, ErrorOrReadyCondition(err), t.ObjectMeta.Generation) {
+		t.Status.Redeemed = t.IsRedeemed()
 		t.Status.StatusType = state.Reason
 		t.Status.Message = state.Message
 		return true
diff --git a/pkg/kube/grants/redeem.go b/pkg/kube/grants/redeem.go
index 3f8397db..202f4a36 100644
--- a/pkg/kube/grants/redeem.go
+++ b/pkg/kube/grants/redeem.go
@@ -49,17 +49,17 @@ func postTokenRequest(token *skupperv2alpha1.AccessToken, site *skupperv2alpha1.
 	}
 	request, err := http.NewRequest(http.MethodPost, token.Spec.Url, bytes.NewReader([]byte(token.Spec.Code)))
 	if err != nil {
-		return nil, err
+		return nil, fmt.Errorf("Controller got error: %s", err)
 	}
 	request.Header.Add("name", token.Name)
 	request.Header.Add("subject", string(site.ObjectMeta.UID))
 	response, err := client.Do(request)
 	if err != nil {
-		return nil, err
+		return nil, fmt.Errorf("Controller got error: %s", err)
 	}
 	if response.StatusCode != http.StatusOK {
 		body, _ := io.ReadAll(response.Body)
-		return nil, fmt.Errorf("%d (%s) %s", response.StatusCode, http.StatusText(response.StatusCode), strings.TrimSpace(string(body)))
+		return nil, fmt.Errorf("Controller got failed response: %d (%s) %s", response.StatusCode, http.StatusText(response.StatusCode), strings.TrimSpace(string(body)))
 	}
 	return response.Body, nil
 }
@@ -68,7 +68,7 @@ func handleTokenResponse(body io.Reader, token *skupperv2alpha1.AccessToken, sit
 	decoder := newLinkDecoder(body)
 	if err := decoder.decodeAll(); err != nil {
 		log.Printf("Could not decode response for AccessToken %s/%s: %s", token.Namespace, token.Name, err)
-		return updateAccessTokenStatus(token, errors.New("Could not decode response"), clients)
+		return updateAccessTokenStatus(token, errors.New("Controller could not decode response"), clients)
 	}
 	refs := []metav1.OwnerReference{
 		{
@@ -80,7 +80,7 @@ func handleTokenResponse(body io.Reader, token *skupperv2alpha1.AccessToken, sit
 	}
 	decoder.secret.ObjectMeta.OwnerReferences = refs
 	if _, err := clients.GetKubeClient().CoreV1().Secrets(token.ObjectMeta.Namespace).Create(context.TODO(), &decoder.secret, metav1.CreateOptions{}); err != nil {
-		return updateAccessTokenStatus(token, fmt.Errorf("Could not create received secret: %s", err), clients)
+		return updateAccessTokenStatus(token, fmt.Errorf("Controller could not create received secret: %s", err), clients)
 	}
 	for _, link := range decoder.links {
 		link.ObjectMeta.OwnerReferences = refs
@@ -88,7 +88,7 @@ func handleTokenResponse(body io.Reader, token *skupperv2alpha1.AccessToken, sit
 			link.Spec.Cost = token.Spec.LinkCost
 		}
 		if _, err := clients.GetSkupperClient().SkupperV2alpha1().Links(token.ObjectMeta.Namespace).Create(context.TODO(), &link, metav1.CreateOptions{}); err != nil {
-			return updateAccessTokenStatus(token, fmt.Errorf("Could not create received link: %s", err), clients)
+			return updateAccessTokenStatus(token, fmt.Errorf("Controller could not create received link: %s", err), clients)
 		}
 	}
 


Test patch:
diff --git a/internal/cmd/skupper/connector/connector_test.go b/internal/cmd/skupper/connector/connector_test.go
index c88ddb1e..bd79a342 100644
--- a/internal/cmd/skupper/connector/connector_test.go
+++ b/internal/cmd/skupper/connector/connector_test.go
@@ -32,6 +32,7 @@ func TestCmdConnectorFactory(t *testing.T) {
 				common.FlagNameWorkload:            "",
 				common.FlagNameOutput:              "",
 				common.FlagNameTimeout:             "1m0s",
+				common.FlagNameWait:                "configured",
 			},
 			command: CmdConnectorCreateFactory(types.PlatformKubernetes),
 		},
@@ -48,6 +49,7 @@ func TestCmdConnectorFactory(t *testing.T) {
 				common.FlagNameOutput:              "",
 				common.FlagNameTimeout:             "1m0s",
 				common.FlagNameConnectorPort:       "0",
+				common.FlagNameWait:                "configured",
 			},
 			command: CmdConnectorUpdateFactory(types.PlatformKubernetes),
 		},
@@ -62,6 +64,7 @@ func TestCmdConnectorFactory(t *testing.T) {
 			name: "CmdConnectorDeleteFactory",
 			expectedFlagsWithDefaultValue: map[string]interface{}{
 				common.FlagNameTimeout: "1m0s",
+				common.FlagNameWait:    "true",
 			},
 			command: CmdConnectorDeleteFactory(types.PlatformKubernetes),
 		},
diff --git a/internal/cmd/skupper/connector/kube/connector_create_test.go b/internal/cmd/skupper/connector/kube/connector_create_test.go
index 6904347b..0d60839c 100644
--- a/internal/cmd/skupper/connector/kube/connector_create_test.go
+++ b/internal/cmd/skupper/connector/kube/connector_create_test.go
@@ -540,6 +540,14 @@ func TestCmdConnectorCreate_ValidateWorkload(t *testing.T) {
 			expectedErrors:   []string{},
 			expectedSelector: "app=backend",
 		},
+		{
+			name:  "wait status is not valid",
+			args:  []string{"workload-deployment", "1234"},
+			flags: common.CommandConnectorCreateFlags{Timeout: time.Minute, Wait: "created"},
+			expectedErrors: []string{
+				"status is not valid: value created not allowed. It should be one of this options: [ready configured none]",
+			},
+		},
 	}
 
 	for _, test := range testTable {
@@ -575,12 +583,13 @@ func TestCmdConnectorCreate_InputToOptions(t *testing.T) {
 		expectedConnectorType  string
 		expectedOutput         string
 		expectedTimeout        time.Duration
+		expectedStatus         string
 	}
 
 	testTable := []test{
 		{
 			name:                   "test1",
-			flags:                  common.CommandConnectorCreateFlags{"backend", "", "app=backend", "secret", "tcp", true, "", 20 * time.Second, "json"},
+			flags:                  common.CommandConnectorCreateFlags{"backend", "", "app=backend", "secret", "tcp", true, "", 20 * time.Second, "json", "ready"},
 			expectedTlsCredentials: "secret",
 			expectedHost:           "",
 			expectedRoutingKey:     "backend",
@@ -588,10 +597,11 @@ func TestCmdConnectorCreate_InputToOptions(t *testing.T) {
 			expectedConnectorType:  "tcp",
 			expectedOutput:         "json",
 			expectedSelector:       "app=backend",
+			expectedStatus:         "ready",
 		},
 		{
 			name:                   "test2",
-			flags:                  common.CommandConnectorCreateFlags{"backend", "backend", "", "secret", "tcp", true, "", 20 * time.Second, "json"},
+			flags:                  common.CommandConnectorCreateFlags{"backend", "backend", "", "secret", "tcp", true, "", 20 * time.Second, "json", "configured"},
 			expectedTlsCredentials: "secret",
 			expectedHost:           "backend",
 			expectedRoutingKey:     "backend",
@@ -599,10 +609,11 @@ func TestCmdConnectorCreate_InputToOptions(t *testing.T) {
 			expectedConnectorType:  "tcp",
 			expectedOutput:         "json",
 			expectedSelector:       "",
+			expectedStatus:         "configured",
 		},
 		{
 			name:                   "test3",
-			flags:                  common.CommandConnectorCreateFlags{"", "", "", "secret", "tcp", false, "", 30 * time.Second, "yaml"},
+			flags:                  common.CommandConnectorCreateFlags{"", "", "", "secret", "tcp", false, "", 30 * time.Second, "yaml", "none"},
 			expectedTlsCredentials: "secret",
 			expectedHost:           "",
 			expectedRoutingKey:     "test3",
@@ -610,6 +621,7 @@ func TestCmdConnectorCreate_InputToOptions(t *testing.T) {
 			expectedConnectorType:  "tcp",
 			expectedOutput:         "yaml",
 			expectedSelector:       "app=test3",
+			expectedStatus:         "none",
 		},
 	}
 
@@ -631,6 +643,7 @@ func TestCmdConnectorCreate_InputToOptions(t *testing.T) {
 			assert.Check(t, cmd.timeout == test.expectedTimeout)
 			assert.Check(t, cmd.selector == test.expectedSelector)
 			assert.Check(t, cmd.connectorType == test.expectedConnectorType)
+			assert.Check(t, cmd.status == test.expectedStatus)
 		})
 	}
 }
@@ -703,6 +716,7 @@ func TestCmdConnectorCreate_WaitUntil(t *testing.T) {
 	type test struct {
 		name                string
 		output              string
+		status              string
 		k8sObjects          []runtime.Object
 		skupperObjects      []runtime.Object
 		skupperErrorMessage string
@@ -728,7 +742,8 @@ func TestCmdConnectorCreate_WaitUntil(t *testing.T) {
 			expectError: true,
 		},
 		{
-			name: "connector is ready",
+			name:   "connector is ready",
+			status: "ready",
 			skupperObjects: []runtime.Object{
 				&v2alpha1.Connector{
 					ObjectMeta: v1.ObjectMeta{
@@ -739,7 +754,7 @@ func TestCmdConnectorCreate_WaitUntil(t *testing.T) {
 						Status: v2alpha1.Status{
 							Conditions: []v1.Condition{
 								{
-									Type:   "Configured",
+									Type:   "Ready",
 									Status: "True",
 								},
 							},
@@ -772,6 +787,87 @@ func TestCmdConnectorCreate_WaitUntil(t *testing.T) {
 			},
 			expectError: false,
 		},
+		{
+			name:       "connector is not ready yet, but user waits for configured",
+			status:     "configured",
+			k8sObjects: nil,
+			skupperObjects: []runtime.Object{
+				&v2alpha1.Connector{
+					ObjectMeta: v1.ObjectMeta{
+						Name:      "my-connector",
+						Namespace: "test",
+					},
+					Status: v2alpha1.ConnectorStatus{
+						Status: v2alpha1.Status{
+							Conditions: []v1.Condition{
+								{
+									Message:            "OK",
+									ObservedGeneration: 1,
+									Reason:             "OK",
+									Status:             "True",
+									Type:               "Configured",
+								},
+							},
+						},
+					},
+				},
+			},
+			expectError: false,
+		},
+		{
+			name:       "user does not wait",
+			status:     "none",
+			k8sObjects: nil,
+			skupperObjects: []runtime.Object{
+				&v2alpha1.Connector{
+					ObjectMeta: v1.ObjectMeta{
+						Name:      "my-connector",
+						Namespace: "test",
+					},
+					Status: v2alpha1.ConnectorStatus{
+						Status: v2alpha1.Status{
+							Conditions: []v1.Condition{
+								{
+									Message:            "OK",
+									ObservedGeneration: 1,
+									Reason:             "OK",
+									Status:             "True",
+									Type:               "Configured",
+								},
+							},
+						},
+					},
+				},
+			},
+			expectError: false,
+		},
+		{
+			name:       "user waits for configured, but site had some errors while being configured",
+			status:     "configured",
+			k8sObjects: nil,
+			skupperObjects: []runtime.Object{
+				&v2alpha1.Connector{
+					ObjectMeta: v1.ObjectMeta{
+						Name:      "my-connector",
+						Namespace: "test",
+					},
+					Status: v2alpha1.ConnectorStatus{
+						Status: v2alpha1.Status{
+							Conditions: []v1.Condition{
+								{
+									Message:            "Error",
+									ObservedGeneration: 1,
+									Reason:             "Error",
+									Status:             "False",
+									Type:               "Configured",
+								},
+							},
+						},
+					},
+				},
+			},
+			expectError: true,
+		},
 	}
 
 	for _, test := range testTable {
@@ -782,6 +878,7 @@ func TestCmdConnectorCreate_WaitUntil(t *testing.T) {
 		cmd.output = test.output
 		cmd.timeout = 1 * time.Second
 		cmd.namespace = "test"
+		cmd.status = test.status
 
 		t.Run(test.name, func(t *testing.T) {
 
diff --git a/internal/cmd/skupper/connector/kube/connector_delete_test.go b/internal/cmd/skupper/connector/kube/connector_delete_test.go
index e21ea838..c54a0b32 100644
--- a/internal/cmd/skupper/connector/kube/connector_delete_test.go
+++ b/internal/cmd/skupper/connector/kube/connector_delete_test.go
@@ -140,6 +140,7 @@ func TestCmdConnectorDelete_Run(t *testing.T) {
 func TestCmdConnectorDelete_WaitUntil(t *testing.T) {
 	type test struct {
 		name                string
+		wait                bool
 		k8sObjects          []runtime.Object
 		skupperObjects      []runtime.Object
 		skupperErrorMessage string
@@ -149,6 +150,7 @@ func TestCmdConnectorDelete_WaitUntil(t *testing.T) {
 	testTable := []test{
 		{
 			name: "error deleting connector",
+			wait: true,
 			skupperObjects: []runtime.Object{
 				&v2alpha1.Connector{
 					ObjectMeta: v1.ObjectMeta{
@@ -171,6 +173,30 @@ func TestCmdConnectorDelete_WaitUntil(t *testing.T) {
 		},
 		{
 			name:        "connector is deleted",
+			wait:        true,
+			expectError: false,
+		},
+		{
+			name: "connector is not deleted but user does not want to wait",
+			wait: false,
+			skupperObjects: []runtime.Object{
+				&v2alpha1.Connector{
+					ObjectMeta: v1.ObjectMeta{
+						Name:      "my-connector",
+						Namespace: "test",
+					},
+					Status: v2alpha1.ConnectorStatus{
+						Status: v2alpha1.Status{
+							Conditions: []v1.Condition{
+								{
+									Type:   "Configured",
+									Status: "True",
+								},
+							},
+						},
+					},
+				},
+			},
 			expectError: false,
 		},
 	}
@@ -182,6 +208,7 @@ func TestCmdConnectorDelete_WaitUntil(t *testing.T) {
 		cmd.name = "my-connector"
 		cmd.Flags = &common.CommandConnectorDeleteFlags{Timeout: 1 * time.Second}
 		cmd.namespace = "test"
+		cmd.wait = test.wait
 
 		t.Run(test.name, func(t *testing.T) {
 
@@ -195,6 +222,33 @@ func TestCmdConnectorDelete_WaitUntil(t *testing.T) {
 	}
 }
 
+func TestCmdConnectorDelete_InputToOptions(t *testing.T) {
+
+	type test struct {
+		name         string
+		flags        *common.CommandConnectorDeleteFlags
+		expectedWait bool
+	}
+
+	testTable := []test{
+		{
+			name:         "wait for connector to be deleted",
+			flags:        &common.CommandConnectorDeleteFlags{Wait: true},
+			expectedWait: true,
+		},
+	}
+
+	for _, test := range testTable {
+		t.Run(test.name, func(t *testing.T) {
+			command := &CmdConnectorDelete{}
+			command.Flags = test.flags
+			command.InputToOptions()
+
+			assert.Check(t, command.wait == test.expectedWait)
+		})
+	}
+}
+
 // --- helper methods
 
 func newCmdConnectorDeleteWithMocks(namespace string, k8sObjects []runtime.Object, skupperObjects []runtime.Object, fakeSkupperError string) (*CmdConnectorDelete, error) {
diff --git a/internal/cmd/skupper/connector/kube/connector_update_test.go b/internal/cmd/skupper/connector/kube/connector_update_test.go
index 80960bd5..130df872 100644
--- a/internal/cmd/skupper/connector/kube/connector_update_test.go
+++ b/internal/cmd/skupper/connector/kube/connector_update_test.go
@@ -400,6 +400,32 @@ func TestCmdConnectorUpdate_ValidateInput(t *testing.T) {
 			},
 			expectedErrors: []string{},
 		},
+		{
+			name:  "wait status is not valid",
+			args:  []string{"backend-connector"},
+			flags: common.CommandConnectorUpdateFlags{Timeout: time.Minute, Wait: "created"},
+			skupperObjects: []runtime.Object{
+				&v2alpha1.Connector{
+					ObjectMeta: v1.ObjectMeta{
+						Name:      "backend-connector",
+						Namespace: "test",
+					},
+					Status: v2alpha1.ConnectorStatus{
+						Status: v2alpha1.Status{
+							Conditions: []v1.Condition{
+								{
+									Type:   "Configured",
+									Status: "True",
+								},
+							},
+						},
+					},
+				},
+			},
+			expectedErrors: []string{
+				"status is not valid: value created not allowed. It should be one of this options: [ready configured none]",
+			},
+		},
 	}
 
 	for _, test := range testTable {
@@ -429,6 +455,7 @@ func TestCmdConnectorUpdate_ValidateWorkload(t *testing.T) {
 		skupperObjects   []runtime.Object
 		expectedErrors   []string
 		expectedSelector string
+		expectedStatus   string
 	}
 
 	testTable := []test{
@@ -1027,6 +1054,7 @@ func TestCmdConnectorUpdate_WaitUntil(t *testing.T) {
 	type test struct {
 		name                string
 		output              string
+		status              string
 		k8sObjects          []runtime.Object
 		skupperObjects      []runtime.Object
 		skupperErrorMessage string
@@ -1052,7 +1080,8 @@ func TestCmdConnectorUpdate_WaitUntil(t *testing.T) {
 			expectError: true,
 		},
 		{
-			name: "connector is ready",
+			name:   "connector is ready",
+			status: "ready",
 			skupperObjects: []runtime.Object{
 				&v2alpha1.Connector{
 					ObjectMeta: v1.ObjectMeta{
@@ -1063,7 +1092,7 @@ func TestCmdConnectorUpdate_WaitUntil(t *testing.T) {
 						Status: v2alpha1.Status{
 							Conditions: []v1.Condition{
 								{
-									Type:   "Configured",
+									Type:   "Ready",
 									Status: "True",
 								},
 							},
@@ -1096,6 +1125,87 @@ func TestCmdConnectorUpdate_WaitUntil(t *testing.T) {
 			},
 			expectError: false,
 		},
+		{
+			name:       "connector is not ready yet, but user waits for configured",
+			status:     "configured",
+			k8sObjects: nil,
+			skupperObjects: []runtime.Object{
+				&v2alpha1.Connector{
+					ObjectMeta: v1.ObjectMeta{
+						Name:      "my-connector",
+						Namespace: "test",
+					},
+					Status: v2alpha1.ConnectorStatus{
+						Status: v2alpha1.Status{
+							Conditions: []v1.Condition{
+								{
+									Message:            "OK",
+									ObservedGeneration: 1,
+									Reason:             "OK",
+									Status:             "True",
+									Type:               "Configured",
+								},
+							},
+						},
+					},
+				},
+			},
+			expectError: false,
+		},
+		{
+			name:       "user does not wait",
+			status:     "none",
+			k8sObjects: nil,
+			skupperObjects: []runtime.Object{
+				&v2alpha1.Connector{
+					ObjectMeta: v1.ObjectMeta{
+						Name:      "my-connector",
+						Namespace: "test",
+					},
+					Status: v2alpha1.ConnectorStatus{
+						Status: v2alpha1.Status{
+							Conditions: []v1.Condition{
+								{
+									Message:            "OK",
+									ObservedGeneration: 1,
+									Reason:             "OK",
+									Status:             "True",
+									Type:               "Connector",
+								},
+							},
+						},
+					},
+				},
+			},
+			expectError: false,
+		},
+		{
+			name:       "user waits for configured, but site had some errors while being configured",
+			status:     "configured",
+			k8sObjects: nil,
+			skupperObjects: []runtime.Object{
+				&v2alpha1.Connector{
+					ObjectMeta: v1.ObjectMeta{
+						Name:      "my-connector",
+						Namespace: "test",
+					},
+					Status: v2alpha1.ConnectorStatus{
+						Status: v2alpha1.Status{
+							Conditions: []v1.Condition{
+								{
+									Message:            "Error",
+									ObservedGeneration: 1,
+									Reason:             "Error",
+									Status:             "False",
+									Type:               "Configured",
+								},
+							},
+						},
+					},
+				},
+			},
+			expectError: true,
+		},
 	}
 
 	for _, test := range testTable {
@@ -1109,6 +1219,7 @@ func TestCmdConnectorUpdate_WaitUntil(t *testing.T) {
 		}
 		cmd.namespace = "test"
 		cmd.newSettings.output = cmd.Flags.Output
+		cmd.status = test.status
 
 		t.Run(test.name, func(t *testing.T) {
 
@@ -1122,6 +1233,36 @@ func TestCmdConnectorUpdate_WaitUntil(t *testing.T) {
 	}
 }
 
+func TestCmdConnectorUpdate_InputToOptions(t *testing.T) {
+
+	type test struct {
+		name           string
+		args           []string
+		flags          common.CommandConnectorUpdateFlags
+		expectedStatus string
+	}
+
+	testTable := []test{
+		{
+			name:           "options with waiting status",
+			args:           []string{"backend-listener"},
+			flags:          common.CommandConnectorUpdateFlags{Wait: "configured"},
+			expectedStatus: "configured",
+		},
+	}
+
+	for _, test := range testTable {
+		t.Run(test.name, func(t *testing.T) {
+			command := &CmdConnectorUpdate{}
+			command.Flags = &test.flags
+
+			command.InputToOptions()
+
+			assert.Check(t, command.status == test.expectedStatus)
+		})
+	}
+}
+
 // --- helper methods
 
 func newCmdConnectorUpdateWithMocks(namespace string, k8sObjects []runtime.Object, skupperObjects []runtime.Object, fakeSkupperError string) (*CmdConnectorUpdate, error) {
diff --git a/internal/cmd/skupper/connector/nonkube/connector_create_test.go b/internal/cmd/skupper/connector/nonkube/connector_create_test.go
index 08472dd2..bb095a87 100644
--- a/internal/cmd/skupper/connector/nonkube/connector_create_test.go
+++ b/internal/cmd/skupper/connector/nonkube/connector_create_test.go
@@ -164,7 +164,7 @@ func TestNonKubeCmdConnectorCreate_InputToOptions(t *testing.T) {
 	testTable := []test{
 		{
 			name:                   "test1",
-			flags:                  common.CommandConnectorCreateFlags{"backend", "", "", "secret", "tcp", false, "", 0, "json"},
+			flags:                  common.CommandConnectorCreateFlags{"backend", "", "", "secret", "tcp", false, "", 0, "json", "none"},
 			expectedTlsCredentials: "secret",
 			expectedHost:           "",
 			expectedRoutingKey:     "backend",
@@ -175,7 +175,7 @@ func TestNonKubeCmdConnectorCreate_InputToOptions(t *testing.T) {
 		{
 			name:                   "test2",
 			namespace:              "test",
-			flags:                  common.CommandConnectorCreateFlags{"backend", "1.2.3.4", "", "secret", "tcp", false, "", 0, "json"},
+			flags:                  common.CommandConnectorCreateFlags{"backend", "1.2.3.4", "", "secret", "tcp", false, "", 0, "json", "configured"},
 			expectedTlsCredentials: "secret",
 			expectedHost:           "1.2.3.4",
 			expectedRoutingKey:     "backend",
@@ -186,7 +186,7 @@ func TestNonKubeCmdConnectorCreate_InputToOptions(t *testing.T) {
 		{
 			name:                   "test3",
 			namespace:              "test",
-			flags:                  common.CommandConnectorCreateFlags{"", "", "", "secret", "tcp", false, "", 0, "yaml"},
+			flags:                  common.CommandConnectorCreateFlags{"", "", "", "secret", "tcp", false, "", 0, "yaml", "ready"},
 			expectedTlsCredentials: "secret",
 			expectedHost:           "",
 			expectedRoutingKey:     "my-Connector",
diff --git a/internal/cmd/skupper/link/kube/link_delete_test.go b/internal/cmd/skupper/link/kube/link_delete_test.go
index 029a243a..918287b7 100644
--- a/internal/cmd/skupper/link/kube/link_delete_test.go
+++ b/internal/cmd/skupper/link/kube/link_delete_test.go
@@ -156,13 +156,15 @@ func TestCmdLinkDelete_InputToOptions(t *testing.T) {
 		name            string
 		flags           common.CommandLinkDeleteFlags
 		expectedTimeout time.Duration
+		expectedWait    bool
 	}
 
 	testTable := []test{
 		{
 			name:            "check options",
-			flags:           common.CommandLinkDeleteFlags{time.Minute},
+			flags:           common.CommandLinkDeleteFlags{Timeout: time.Minute, Wait: false},
 			expectedTimeout: time.Minute,
+			expectedWait:    false,
 		},
 	}
 
@@ -176,6 +178,7 @@ func TestCmdLinkDelete_InputToOptions(t *testing.T) {
 			cmd.InputToOptions()
 
 			assert.Check(t, cmd.timeout == test.expectedTimeout)
+			assert.Check(t, cmd.wait == test.expectedWait)
 		})
 	}
 }
@@ -230,6 +233,7 @@ func TestCmdLinkDelete_WaitUntil(t *testing.T) {
 	type test struct {
 		name           string
 		timeout        time.Duration
+		wait           bool
 		skupperObjects []runtime.Object
 		expectError    bool
 	}
@@ -267,6 +271,34 @@ func TestCmdLinkDelete_WaitUntil(t *testing.T) {
 			timeout:     time.Second,
 			expectError: false,
 		},
+		{
+			name: "link is not deleted but user does not want to wait",
+			wait: false,
+			skupperObjects: []runtime.Object{
+				&v2alpha1.Link{
+					ObjectMeta: v1.ObjectMeta{
+						Name:      "my-link",
+						Namespace: "test",
+					},
+					Status: v2alpha1.LinkStatus{
+						Status: v2alpha1.Status{
+							Message: "OK",
+							Conditions: []v1.Condition{
+								{
+									Message:            "OK",
+									ObservedGeneration: 1,
+									Reason:             "OK",
+									Status:             "True",
+									Type:               "Configured",
+								},
+							},
+						},
+					},
+				},
+			},
+			timeout:     time.Second,
+			expectError: false,
+		},
 	}
 
 	for _, test := range testTable {
@@ -274,6 +306,7 @@ func TestCmdLinkDelete_WaitUntil(t *testing.T) {
 		assert.Assert(t, err)
 		cmd.linkName = "my-link"
 		cmd.timeout = test.timeout
+		cmd.wait = test.wait
 		t.Run(test.name, func(t *testing.T) {
 
 			err := cmd.WaitUntil()
diff --git a/internal/cmd/skupper/link/kube/link_update_test.go b/internal/cmd/skupper/link/kube/link_update_test.go
index 6717eaff..9ff6fcb9 100644
--- a/internal/cmd/skupper/link/kube/link_update_test.go
+++ b/internal/cmd/skupper/link/kube/link_update_test.go
@@ -264,6 +264,33 @@ func TestCmdLinkUpdate_ValidateInput(t *testing.T) {
 				"timeout is not valid: duration must not be less than 10s; got 0s",
 			},
 		},
+		{
+			name:       "wait status is not valid",
+			args:       []string{"east-link"},
+			flags:      common.CommandLinkUpdateFlags{Cost: "1", Timeout: time.Minute, Wait: "created"},
+			k8sObjects: nil,
+			skupperObjects: []runtime.Object{
+				&v2alpha1.SiteList{
+					Items: []v2alpha1.Site{
+						{
+							ObjectMeta: v1.ObjectMeta{
+								Name:      "the-site",
+								Namespace: "test",
+							},
+						},
+					},
+				},
+				&v2alpha1.Link{
+					ObjectMeta: v1.ObjectMeta{
+						Name:      "east-link",
+						Namespace: "test",
+					},
+				},
+			},
+			expectedErrors: []string{
+				"status is not valid: value created not allowed. It should be one of this options: [ready configured none]",
+			},
+		},
 	}
 
 	for _, test := range testTable {
@@ -294,17 +321,19 @@ func TestCmdLinkUpdate_InputToOptions(t *testing.T) {
 		expectedCost           int
 		expectedOutput         string
 		expectedTimeout        time.Duration
+		expectedStatus         string
 	}
 
 	testTable := []test{
 		{
 			name:                   "check options",
 			args:                   []string{"my-link"},
-			flags:                  common.CommandLinkUpdateFlags{"secret", "1", "json", time.Minute},
+			flags:                  common.CommandLinkUpdateFlags{TlsCredentials: "secret", Cost: "1", Output: "json", Timeout: time.Minute, Wait: "ready"},
 			expectedCost:           1,
 			expectedTlsCredentials: "secret",
 			expectedOutput:         "json",
 			expectedTimeout:        time.Minute,
+			expectedStatus:         "ready",
 		},
 	}
 
@@ -321,6 +350,7 @@ func TestCmdLinkUpdate_InputToOptions(t *testing.T) {
 			assert.Check(t, cmd.tlsCredentials == test.expectedTlsCredentials)
 			assert.Check(t, cmd.cost == test.expectedCost)
 			assert.Check(t, cmd.timeout == test.expectedTimeout)
+			assert.Check(t, cmd.status == test.expectedStatus)
 		})
 	}
 }
@@ -417,6 +447,7 @@ func TestCmdLinkUpdate_Run(t *testing.T) {
 func TestCmdLinkUpdate_WaitUntil(t *testing.T) {
 	type test struct {
 		name                string
+		status              string
 		k8sObjects          []runtime.Object
 		skupperObjects      []runtime.Object
 		skupperErrorMessage string
@@ -428,7 +459,8 @@ func TestCmdLinkUpdate_WaitUntil(t *testing.T) {
 
 	testTable := []test{
 		{
-			name: "link is not configured",
+			name:   "link is not configured",
+			status: "configured",
 			skupperObjects: []runtime.Object{
 				&v2alpha1.Link{
 					ObjectMeta: v1.ObjectMeta{
@@ -456,7 +488,8 @@ func TestCmdLinkUpdate_WaitUntil(t *testing.T) {
 			expectError: false,
 		},
 		{
-			name: "link is configured",
+			name:   "link is ready",
+			status: "ready",
 			skupperObjects: []runtime.Object{
 				&v2alpha1.Link{
 					ObjectMeta: v1.ObjectMeta{
@@ -472,7 +505,7 @@ func TestCmdLinkUpdate_WaitUntil(t *testing.T) {
 									ObservedGeneration: 1,
 									Reason:             "OK",
 									Status:             "True",
-									Type:               "Configured",
+									Type:               "Ready",
 								},
 							},
 						},
@@ -483,6 +516,96 @@ func TestCmdLinkUpdate_WaitUntil(t *testing.T) {
 			timeout:     time.Second,
 			expectError: false,
 		},
+		{
+			name:       "link is not ready yet, but user waits for configured",
+			status:     "configured",
+			timeout:    time.Second,
+			k8sObjects: nil,
+			skupperObjects: []runtime.Object{
+				&v2alpha1.Link{
+					ObjectMeta: v1.ObjectMeta{
+						Name:      "my-link",
+						Namespace: "test",
+					},
+					Status: v2alpha1.LinkStatus{
+						Status: v2alpha1.Status{
+							Message: "OK",
+							Conditions: []v1.Condition{
+								{
+									Message:            "OK",
+									ObservedGeneration: 1,
+									Reason:             "OK",
+									Status:             "True",
+									Type:               "Configured",
+								},
+							},
+						},
+					},
+				},
+			},
+			linkName:    "my-link",
+			expectError: false,
+		},
+		{
+			name:       "user does not wait",
+			status:     "none",
+			timeout:    time.Second,
+			k8sObjects: nil,
+			skupperObjects: []runtime.Object{
+				&v2alpha1.Link{
+					ObjectMeta: v1.ObjectMeta{
+						Name:      "my-link",
+						Namespace: "test",
+					},
+					Status: v2alpha1.LinkStatus{
+						Status: v2alpha1.Status{
+							Message: "OK",
+							Conditions: []v1.Condition{
+								{
+									Message:            "OK",
+									ObservedGeneration: 1,
+									Reason:             "OK",
+									Status:             "True",
+									Type:               "Configured",
+								},
+							},
+						},
+					},
+				},
+			},
+			linkName:    "my-link",
+			expectError: false,
+		},
+		{
+			name:       "user waits for configured, but link had some errors while being configured",
+			status:     "configured",
+			timeout:    time.Second,
+			k8sObjects: nil,
+			skupperObjects: []runtime.Object{
+				&v2alpha1.Link{
+					ObjectMeta: v1.ObjectMeta{
+						Name:      "my-link",
+						Namespace: "test",
+					},
+					Status: v2alpha1.LinkStatus{
+						Status: v2alpha1.Status{
+							Message: "OK",
+							Conditions: []v1.Condition{
+								{
+									Message:            "Error",
+									ObservedGeneration: 1,
+									Reason:             "Error",
+									Status:             "False",
+									Type:               "Configured",
+								},
+							},
+						},
+					},
+				},
+			},
+			linkName:    "my-link",
+			expectError: true,
+		},
 	}
 
 	for _, test := range testTable {
@@ -491,6 +614,7 @@ func TestCmdLinkUpdate_WaitUntil(t *testing.T) {
 		cmd.linkName = test.linkName
 		cmd.output = test.output
 		cmd.timeout = test.timeout
+		cmd.status = test.status
 
 		t.Run(test.name, func(t *testing.T) {
 
diff --git a/internal/cmd/skupper/link/link_test.go b/internal/cmd/skupper/link/link_test.go
index 5b92e516..b0889d6b 100644
--- a/internal/cmd/skupper/link/link_test.go
+++ b/internal/cmd/skupper/link/link_test.go
@@ -37,6 +37,7 @@ func TestCmdLinkFactory(t *testing.T) {
 				common.FlagNameCost:           "1",
 				common.FlagNameOutput:         "",
 				common.FlagNameTimeout:        "1m0s",
+				common.FlagNameWait:           "ready",
 			},
 			command: CmdLinkUpdateFactory(types.PlatformKubernetes),
 		},
@@ -51,6 +52,7 @@ func TestCmdLinkFactory(t *testing.T) {
 			name: "CmdLinkDeleteFactory",
 			expectedFlagsWithDefaultValue: map[string]interface{}{
 				common.FlagNameTimeout: "1m0s",
+				common.FlagNameWait:    "true",
 			},
 			command: CmdLinkDeleteFactory(types.PlatformKubernetes),
 		},
diff --git a/internal/cmd/skupper/listener/kube/listener_create_test.go b/internal/cmd/skupper/listener/kube/listener_create_test.go
index 8d4f5f69..38e2c445 100644
--- a/internal/cmd/skupper/listener/kube/listener_create_test.go
+++ b/internal/cmd/skupper/listener/kube/listener_create_test.go
@@ -193,6 +193,14 @@ func TestCmdListenerCreate_ValidateInput(t *testing.T) {
 			},
 			expectedErrors: []string{},
 		},
+		{
+			name:  "wait status is not valid",
+			args:  []string{"my-listener-tls", "8080"},
+			flags: common.CommandListenerCreateFlags{Timeout: time.Minute, Wait: "created"},
+			expectedErrors: []string{
+				"status is not valid: value created not allowed. It should be one of this options: [ready configured none]",
+			},
+		},
 	}
 
 	for _, test := range testTable {
@@ -225,28 +233,31 @@ func TestCmdListenerCreate_InputToOptions(t *testing.T) {
 		expectedListenerType   string
 		expectedOutput         string
 		expectedTimeout        time.Duration
+		expectedStatus         string
 	}
 
 	testTable := []test{
 		{
 			name:                   "test1",
-			flags:                  common.CommandListenerCreateFlags{"backend", "backend", "secret", "tcp", 20 * time.Second, "json"},
+			flags:                  common.CommandListenerCreateFlags{"backend", "backend", "secret", "tcp", 20 * time.Second, "json", "configured"},
 			expectedTlsCredentials: "secret",
 			expectedHost:           "backend",
 			expectedRoutingKey:     "backend",
 			expectedTimeout:        20 * time.Second,
 			expectedListenerType:   "tcp",
 			expectedOutput:         "json",
+			expectedStatus:         "configured",
 		},
 		{
 			name:                   "test2",
-			flags:                  common.CommandListenerCreateFlags{"", "", "secret", "tcp", 30 * time.Second, "yaml"},
+			flags:                  common.CommandListenerCreateFlags{"", "", "secret", "tcp", 30 * time.Second, "yaml", "configured"},
 			expectedTlsCredentials: "secret",
 			expectedHost:           "test2",
 			expectedRoutingKey:     "test2",
 			expectedTimeout:        30 * time.Second,
 			expectedListenerType:   "tcp",
 			expectedOutput:         "yaml",
+			expectedStatus:         "configured",
 		},
 	}
 
@@ -268,6 +279,7 @@ func TestCmdListenerCreate_InputToOptions(t *testing.T) {
 			assert.Check(t, cmd.timeout == test.expectedTimeout)
 			assert.Check(t, cmd.output == test.expectedOutput)
 			assert.Check(t, cmd.listenerType == test.expectedListenerType)
+			assert.Check(t, cmd.status == test.expectedStatus)
 		})
 	}
 }
@@ -334,10 +346,12 @@ func TestCmdListenerCreate_WaitUntil(t *testing.T) {
 	type test struct {
 		name                string
 		output              string
+		status              string
 		k8sObjects          []runtime.Object
 		skupperObjects      []runtime.Object
 		skupperErrorMessage string
 		expectError         bool
+		expectedStatus      string
 	}
 
 	testTable := []test{
@@ -361,7 +375,8 @@ func TestCmdListenerCreate_WaitUntil(t *testing.T) {
 			expectError: true,
 		},
 		{
-			name: "listener is ready",
+			name:   "listener is ready",
+			status: "ready",
 			skupperObjects: []runtime.Object{
 				&v2alpha1.Listener{
 					ObjectMeta: v1.ObjectMeta{
@@ -372,7 +387,7 @@ func TestCmdListenerCreate_WaitUntil(t *testing.T) {
 						Status: v2alpha1.Status{
 							Conditions: []v1.Condition{
 								{
-									Type:   "Configured",
+									Type:   "Ready",
 									Status: "True",
 								},
 							},
@@ -383,7 +398,7 @@ func TestCmdListenerCreate_WaitUntil(t *testing.T) {
 			expectError: false,
 		},
 		{
-			name:   "listener is ready yaml output",
+			name:   "listener is configured yaml output",
 			output: "yaml",
 			skupperObjects: []runtime.Object{
 				&v2alpha1.Listener{
@@ -405,6 +420,57 @@ func TestCmdListenerCreate_WaitUntil(t *testing.T) {
 			},
 			expectError: false,
 		},
+		{
+			name:       "user does not wait",
+			status:     "none",
+			k8sObjects: nil,
+			skupperObjects: []runtime.Object{
+				&v2alpha1.Listener{
+					ObjectMeta: v1.ObjectMeta{
+						Name:      "my-listener",
+						Namespace: "test",
+					},
+					Status: v2alpha1.ListenerStatus{
+						Status: v2alpha1.Status{
+							Conditions: []v1.Condition{
+								{
+									Type:   "Configured",
+									Status: "True",
+								},
+							},
+						},
+					},
+				},
+			},
+			expectError: false,
+		},
+		{
+			name:       "user waits for configured, but listener had some errors while being configured",
+			status:     "configured",
+			k8sObjects: nil,
+			skupperObjects: []runtime.Object{
+				&v2alpha1.Listener{
+					ObjectMeta: v1.ObjectMeta{
+						Name:      "my-listener",
+						Namespace: "test",
+					},
+					Status: v2alpha1.ListenerStatus{
+						Status: v2alpha1.Status{
+							Conditions: []v1.Condition{
+								{
+									Message:            "Error",
+									ObservedGeneration: 1,
+									Reason:             "Error",
+									Status:             "False",
+									Type:               "Configured",
+								},
+							},
+						},
+					},
+				},
+			},
+			expectError: true,
+		},
 	}
 
 	for _, test := range testTable {
@@ -416,6 +482,7 @@ func TestCmdListenerCreate_WaitUntil(t *testing.T) {
 		cmd.output = test.output
 		cmd.timeout = 1 * time.Second
 		cmd.namespace = "test"
+		cmd.status = test.status
 
 		t.Run(test.name, func(t *testing.T) {
 
diff --git a/internal/cmd/skupper/listener/kube/listener_delete_test.go b/internal/cmd/skupper/listener/kube/listener_delete_test.go
index 8849e705..495ace8e 100644
--- a/internal/cmd/skupper/listener/kube/listener_delete_test.go
+++ b/internal/cmd/skupper/listener/kube/listener_delete_test.go
@@ -100,6 +100,33 @@ func TestCmdListenerDelete_ValidateInput(t *testing.T) {
 	}
 }
 
+func TestCmdListenerDelete_InputToOptions(t *testing.T) {
+
+	type test struct {
+		name         string
+		flags        *common.CommandListenerDeleteFlags
+		expectedWait bool
+	}
+
+	testTable := []test{
+		{
+			name:         "wait for site enabled",
+			flags:        &common.CommandListenerDeleteFlags{Wait: true},
+			expectedWait: true,
+		},
+	}
+
+	for _, test := range testTable {
+		t.Run(test.name, func(t *testing.T) {
+			command := &CmdListenerDelete{}
+			command.Flags = test.flags
+			command.InputToOptions()
+
+			assert.Check(t, command.wait == test.expectedWait)
+		})
+	}
+}
+
 func TestCmdListenerDelete_Run(t *testing.T) {
 	type test struct {
 		name                string
@@ -163,6 +190,7 @@ func TestCmdListenerDelete_Run(t *testing.T) {
 func TestCmdListenerDelete_WaitUntil(t *testing.T) {
 	type test struct {
 		name                string
+		wait                bool
 		k8sObjects          []runtime.Object
 		skupperObjects      []runtime.Object
 		skupperErrorMessage string
@@ -172,6 +200,7 @@ func TestCmdListenerDelete_WaitUntil(t *testing.T) {
 	testTable := []test{
 		{
 			name: "error deleting listener",
+			wait: true,
 			skupperObjects: []runtime.Object{
 				&v2alpha1.Listener{
 					ObjectMeta: v1.ObjectMeta{
@@ -194,6 +223,31 @@ func TestCmdListenerDelete_WaitUntil(t *testing.T) {
 		},
 		{
 			name:        "listener is deleted",
+			wait:        true,
+			expectError: false,
+		},
+		{
+			name:       "listener is not deleted but user does not want to wait",
+			k8sObjects: nil,
+			wait:       false,
+			skupperObjects: []runtime.Object{
+				&v2alpha1.Listener{
+					ObjectMeta: v1.ObjectMeta{
+						Name:      "my-listener",
+						Namespace: "test",
+					},
+					Status: v2alpha1.ListenerStatus{
+						Status: v2alpha1.Status{
+							Conditions: []v1.Condition{
+								{
+									Type:   "Configured",
+									Status: "True",
+								},
+							},
+						},
+					},
+				},
+			},
 			expectError: false,
 		},
 	}
@@ -205,6 +259,7 @@ func TestCmdListenerDelete_WaitUntil(t *testing.T) {
 		cmd.name = "my-listener"
 		cmd.Flags = &common.CommandListenerDeleteFlags{Timeout: 1 * time.Second}
 		cmd.namespace = "test"
+		cmd.wait = test.wait
 
 		t.Run(test.name, func(t *testing.T) {
 
diff --git a/internal/cmd/skupper/listener/kube/listener_update_test.go b/internal/cmd/skupper/listener/kube/listener_update_test.go
index cbd3b4c1..2fe680be 100644
--- a/internal/cmd/skupper/listener/kube/listener_update_test.go
+++ b/internal/cmd/skupper/listener/kube/listener_update_test.go
@@ -257,6 +257,33 @@ func TestCmdListenerUpdate_ValidateInput(t *testing.T) {
 			},
 			expectedErrors: []string{},
 		},
+		{
+			name:       "wait status is not valid",
+			args:       []string{"backend-listener"},
+			flags:      common.CommandListenerUpdateFlags{Timeout: time.Second * 30, Wait: "created"},
+			k8sObjects: nil,
+			skupperObjects: []runtime.Object{
+				&v2alpha1.Listener{
+					ObjectMeta: v1.ObjectMeta{
+						Name:      "backend-listener",
+						Namespace: "test",
+					},
+					Status: v2alpha1.ListenerStatus{
+						Status: v2alpha1.Status{
+							Conditions: []v1.Condition{
+								{
+									Type:   "Configured",
+									Status: "True",
+								},
+							},
+						},
+					},
+				},
+			},
+			expectedErrors: []string{
+				"status is not valid: value created not allowed. It should be one of this options: [ready configured none]",
+			},
+		},
 	}
 
 	for _, test := range testTable {
@@ -277,6 +304,36 @@ func TestCmdListenerUpdate_ValidateInput(t *testing.T) {
 	}
 }
 
+func TestCmdListenerUpdate_InputToOptions(t *testing.T) {
+
+	type test struct {
+		name           string
+		args           []string
+		flags          common.CommandListenerUpdateFlags
+		expectedStatus string
+	}
+
+	testTable := []test{
+		{
+			name:           "options with waiting status",
+			args:           []string{"backend-listener"},
+			flags:          common.CommandListenerUpdateFlags{Wait: "configured"},
+			expectedStatus: "configured",
+		},
+	}
+
+	for _, test := range testTable {
+		t.Run(test.name, func(t *testing.T) {
+			command := &CmdListenerUpdate{}
+			command.Flags = &test.flags
+
+			command.InputToOptions()
+
+			assert.Check(t, command.status == test.expectedStatus)
+		})
+	}
+}
+
 func TestCmdListenerUpdate_Run(t *testing.T) {
 	type test struct {
 		name                string
@@ -379,15 +436,18 @@ func TestCmdListenerUpdate_WaitUntil(t *testing.T) {
 	type test struct {
 		name                string
 		output              string
+		status              string
 		k8sObjects          []runtime.Object
 		skupperObjects      []runtime.Object
 		skupperErrorMessage string
 		expectError         bool
+		errorMessage        string
 	}
 
 	testTable := []test{
 		{
-			name: "listener is not ready",
+			name:   "listener is not ready",
+			status: "ready",
 			skupperObjects: []runtime.Object{
 				&v2alpha1.Listener{
 					ObjectMeta: v1.ObjectMeta{
@@ -399,14 +459,18 @@ func TestCmdListenerUpdate_WaitUntil(t *testing.T) {
 					},
 				},
 			},
-			expectError: true,
+			expectError:  true,
+			errorMessage: "Listener \"my-listener\" is not ready yet, check the status for more information\n",
 		},
 		{
-			name:        "listener is not returned",
-			expectError: true,
+			name:         "listener is not returned",
+			status:       "ready",
+			expectError:  true,
+			errorMessage: "Listener \"my-listener\" is not ready yet, check the status for more information\n",
 		},
 		{
-			name: "listener is ready",
+			name:   "listener is ready",
+			status: "ready",
 			skupperObjects: []runtime.Object{
 				&v2alpha1.Listener{
 					ObjectMeta: v1.ObjectMeta{
@@ -417,7 +481,7 @@ func TestCmdListenerUpdate_WaitUntil(t *testing.T) {
 						Status: v2alpha1.Status{
 							Conditions: []v1.Condition{
 								{
-									Type:   "Configured",
+									Type:   "Ready",
 									Status: "True",
 								},
 							},
@@ -450,6 +514,82 @@ func TestCmdListenerUpdate_WaitUntil(t *testing.T) {
 			},
 			expectError: false,
 		},
+		{
+			name:       "listener is not ready yet, but user waits for configured",
+			status:     "configured",
+			k8sObjects: nil,
+			skupperObjects: []runtime.Object{
+				&v2alpha1.Listener{
+					ObjectMeta: v1.ObjectMeta{
+						Name:      "my-listener",
+						Namespace: "test",
+					},
+					Status: v2alpha1.ListenerStatus{
+						Status: v2alpha1.Status{
+							Conditions: []v1.Condition{
+								{
+									Type:   "Configured",
+									Status: "True",
+								},
+							},
+						},
+					},
+				},
+			},
+			expectError: false,
+		},
+		{
+			name:       "user does not wait",
+			status:     "none",
+			k8sObjects: nil,
+			skupperObjects: []runtime.Object{
+				&v2alpha1.Listener{
+					ObjectMeta: v1.ObjectMeta{
+						Name:      "my-listener",
+						Namespace: "test",
+					},
+					Status: v2alpha1.ListenerStatus{
+						Status: v2alpha1.Status{
+							Conditions: []v1.Condition{
+								{
+									Type:   "Ready",
+									Status: "True",
+								},
+							},
+						},
+					},
+				},
+			},
+			expectError: false,
+		},
+		{
+			name:       "user waits for configured, but site had some errors while being configured",
+			status:     "configured",
+			k8sObjects: nil,
+			skupperObjects: []runtime.Object{
+				&v2alpha1.Listener{
+					ObjectMeta: v1.ObjectMeta{
+						Name:      "my-listener",
+						Namespace: "test",
+					},
+					Status: v2alpha1.ListenerStatus{
+						Status: v2alpha1.Status{
+							Conditions: []v1.Condition{
+								{
+									Message:            "Error",
+									ObservedGeneration: 1,
+									Reason:             "Error",
+									Status:             "False",
+									Type:               "Configured",
+								},
+							},
+						},
+					},
+				},
+			},
+			expectError:  true,
+			errorMessage: "Listener \"my-listener\" is configured with errors, check the status for more information\n",
+		},
 	}
 
 	for _, test := range testTable {
@@ -463,11 +603,13 @@ func TestCmdListenerUpdate_WaitUntil(t *testing.T) {
 		}
 		cmd.namespace = "test"
 		cmd.newSettings.output = cmd.Flags.Output
+		cmd.status = test.status
 
 		t.Run(test.name, func(t *testing.T) {
 			err := cmd.WaitUntil()
 			if test.expectError {
 				assert.Check(t, err != nil)
+				assert.Equal(t, test.errorMessage, err.Error())
 			} else {
 				assert.Assert(t, err)
 			}
diff --git a/internal/cmd/skupper/listener/listener_test.go b/internal/cmd/skupper/listener/listener_test.go
index dbf0c0eb..79a276c7 100644
--- a/internal/cmd/skupper/listener/listener_test.go
+++ b/internal/cmd/skupper/listener/listener_test.go
@@ -10,7 +10,7 @@ import (
 	"testing"
 )
 
-func TestCmdLinkFactory(t *testing.T) {
+func TestCmdListenerFactory(t *testing.T) {
 
 	type test struct {
 		name                          string
@@ -28,6 +28,7 @@ func TestCmdLinkFactory(t *testing.T) {
 				common.FlagNameListenerType:   "tcp",
 				common.FlagNameOutput:         "",
 				common.FlagNameTimeout:        "1m0s",
+				common.FlagNameWait:           "configured",
 			},
 			command: CmdListenerCreateFactory(types.PlatformKubernetes),
 		},
@@ -41,6 +42,7 @@ func TestCmdLinkFactory(t *testing.T) {
 				common.FlagNameOutput:         "",
 				common.FlagNameTimeout:        "1m0s",
 				common.FlagNameListenerPort:   "0",
+				common.FlagNameWait:           "configured",
 			},
 			command: CmdListenerUpdateFactory(types.PlatformKubernetes),
 		},
@@ -55,6 +57,7 @@ func TestCmdLinkFactory(t *testing.T) {
 			name: "CmdListenerDeleteFactory",
 			expectedFlagsWithDefaultValue: map[string]interface{}{
 				common.FlagNameTimeout: "1m0s",
+				common.FlagNameWait:    "true",
 			},
 			command: CmdListenerDeleteFactory(types.PlatformKubernetes),
 		},
diff --git a/internal/cmd/skupper/site/kube/site_delete_test.go b/internal/cmd/skupper/site/kube/site_delete_test.go
index 76ad588b..6006e550 100644
--- a/internal/cmd/skupper/site/kube/site_delete_test.go
+++ b/internal/cmd/skupper/site/kube/site_delete_test.go
@@ -275,6 +275,7 @@ func TestCmdSiteDelete_InputToOptions(t *testing.T) {
 			command.InputToOptions()
 
 			assert.Check(t, command.timeout == test.expectedTimeout)
+			assert.Check(t, command.wait == test.expectedWait)
 		})
 	}
 }
diff --git a/internal/cmd/skupper/token/kube/token_redeem_test.go b/internal/cmd/skupper/token/kube/token_redeem_test.go
index 59de2fb1..c0ec2cb3 100644
--- a/internal/cmd/skupper/token/kube/token_redeem_test.go
+++ b/internal/cmd/skupper/token/kube/token_redeem_test.go
@@ -321,11 +321,13 @@ func TestCmdTokenRedeem_Run(t *testing.T) {
 						Name:      "my-token",
 						Namespace: "test",
 					},
-					Status: v2alpha1.Status{
-						Conditions: []v1.Condition{
-							{
-								Type:   "Redeemed",
-								Status: "True",
+					Status: v2alpha1.AccessTokenStatus{
+						Status: v2alpha1.Status{
+							Conditions: []v1.Condition{
+								{
+									Type:   "Redeemed",
+									Status: "True",
+								},
 							},
 						},
 					},
@@ -377,7 +379,7 @@ func TestCmdTokenRedeem_WaitUntil(t *testing.T) {
 						Name:      "my-grant",
 						Namespace: "test",
 					},
-					Status: v2alpha1.Status{},
+					Status: v2alpha1.AccessTokenStatus{},
 				},
 			},
 			expectError: true,
@@ -395,11 +397,13 @@ func TestCmdTokenRedeem_WaitUntil(t *testing.T) {
 						Name:      "my-grant",
 						Namespace: "test",
 					},
-					Status: v2alpha1.Status{
-						Conditions: []v1.Condition{
-							{
-								Type:   "Redeemed",
-								Status: "True",
+					Status: v2alpha1.AccessTokenStatus{
+						Status: v2alpha1.Status{
+							Conditions: []v1.Condition{
+								{
+									Type:   "Redeemed",
+									Status: "True",
+								},
 							},
 						},
 					},
diff --git a/pkg/kube/grants/redeem_test.go b/pkg/kube/grants/redeem_test.go
index 6ffb3ed8..b16db041 100644
--- a/pkg/kube/grants/redeem_test.go
+++ b/pkg/kube/grants/redeem_test.go
@@ -138,7 +138,7 @@ func Test_handleTokenResponse(t *testing.T) {
 			name:           "no data",
 			token:          tf.token("my-token", "test", "http://foo/xyz", "mycode", ""),
 			site:           tf.site("my-site", "test"),
-			expectedStatus: "Could not decode response",
+			expectedStatus: "Controller could not decode response",
 		},
 		{
 			name:  "failed read",
@@ -156,7 +156,7 @@ func Test_handleTokenResponse(t *testing.T) {
 				},
 			},
 			failReadAt:     1025,
-			expectedStatus: "Could not decode response",
+			expectedStatus: "Controller could not decode response",
 		},
 		{
 			name:  "secret collision",
@@ -173,7 +173,7 @@ func Test_handleTokenResponse(t *testing.T) {
 					}, "my-token"),
 				},
 			},
-			expectedStatus:  "Could not create received secret: secrets \"my-token\" already exists",
+			expectedStatus:  "Controller could not create received secret: secrets \"my-token\" already exists",
 			extraK8sObjects: []runtime.Object{tf.secret("my-token", "test", "Another Subject", nil)},
 		},
 		{
@@ -191,7 +191,7 @@ func Test_handleTokenResponse(t *testing.T) {
 					}, "my-token"),
 				},
 			},
-			expectedStatus:      "Could not create received link: links.skupper.io \"my-token\" already exists",
+			expectedStatus:      "Controller could not create received link: links.skupper.io \"my-token\" already exists",
 			extraSkupperObjects: []runtime.Object{tf.link("my-token", "test", nil, "")},
 		},
 		{
@@ -365,21 +365,21 @@ func Test_RedeemAccessToken(t *testing.T) {
 			scheme:         "https",
 			tokenName:      "my-token",
 			grantUID:       "a40fbe84-f276-4755-bf22-5ba980ab1661",
-			expectedStatus: "404 (Not Found) No such claim",
+			expectedStatus: "Controller got failed response: 404 (Not Found) No such claim",
 			expectRedeemed: false,
 		},
 		{
 			name:           "no resolved endpoints",
 			scheme:         "https",
 			tokenName:      "my-token",
-			expectedStatus: "500 (Internal Server Error) Could not resolve any endpoints for requested link",
+			expectedStatus: "Controller got failed response: 500 (Internal Server Error) Could not resolve any endpoints for requested link",
 		},
 		{
 			name:           "bad default issuer",
 			scheme:         "https",
 			tokenName:      "my-token",
 			defaultIssuer:  "i-dont-exist",
-			expectedStatus: "500 (Internal Server Error) Could not get issuer for requested certficate",
+			expectedStatus: "Controller got failed response: 500 (Internal Server Error) Could not get issuer for requested certficate",
 		},
 	}
 	for _, tt := range tests {