Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

istioctl: add a flag to delete all waypoints in a namespace #47818

Merged
merged 4 commits into from
Nov 15, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
107 changes: 75 additions & 32 deletions istioctl/pkg/waypoint/waypoint.go
Original file line number Diff line number Diff line change
Expand Up @@ -38,13 +38,16 @@ import (
"istio.io/istio/pkg/config/constants"
"istio.io/istio/pkg/config/protocol"
"istio.io/istio/pkg/config/schema/gvk"
"istio.io/istio/pkg/kube"
"istio.io/istio/pkg/slices"
)

var (
revision = ""

allNamespaces bool

deleteAll bool
)

func Cmd(ctx cli.Context) *cobra.Command {
Expand Down Expand Up @@ -147,6 +150,7 @@ func Cmd(ctx cli.Context) *cobra.Command {
return nil
},
}

waypointDeleteCmd := &cobra.Command{
Use: "delete",
Short: "Delete a waypoint configuration",
Expand All @@ -158,12 +162,38 @@ func Cmd(ctx cli.Context) *cobra.Command {
istioctl x waypoint delete --service-account something --namespace default

# Delete a waypoint by name, which can obtain from istioctl x waypoint list
istioctl x waypoint delete waypoint-name --namespace default`,
istioctl x waypoint delete waypoint-name --namespace default

# Delete several waypoints by name
istioctl x waypoint delete waypoint-name1 waypoint-name2 --namespace default

# Delete all waypoints in a specific namespace
istioctl x waypoint delete --all --namespace default`,
GregHanson marked this conversation as resolved.
Show resolved Hide resolved
Args: func(cmd *cobra.Command, args []string) error {
if deleteAll && len(args) > 0 {
return fmt.Errorf("cannot specify waypoint names when deleting all waypoints")
}
if deleteAll && waypointServiceAccount != "" {
return fmt.Errorf("cannot specify service account when deleting all waypoints")
}
if len(args) > 0 && waypointServiceAccount != "" {
return fmt.Errorf("cannot specify service account when deleting by name")
}
return nil
},
RunE: func(cmd *cobra.Command, args []string) error {
kubeClient, err := ctx.CLIClient()
if err != nil {
return fmt.Errorf("failed to create Kubernetes client: %v", err)
}
ns := ctx.NamespaceOrDefault(ctx.Namespace())

// Delete all waypoints if the --all flag is set
if deleteAll {
return deleteWaypoints(cmd, kubeClient, ns, nil)
}

// Delete waypoints by service account if provided
if len(args) == 0 {
gw := makeGateway(true)
if err = kubeClient.GatewayAPI().GatewayV1beta1().Gateways(gw.Namespace).
Expand All @@ -173,40 +203,13 @@ func Cmd(ctx cli.Context) *cobra.Command {
fmt.Fprintf(cmd.OutOrStdout(), "waypoint %v/%v deleted\n", gw.Namespace, gw.Name)
return nil
}
ns := ctx.NamespaceOrDefault(ctx.Namespace())

wg := sync.WaitGroup{}
var mu sync.Mutex
multiErr := &multierror.Error{}
for _, name := range args {
wg.Add(1)
go func(name string) {
defer wg.Done()
gw, err := kubeClient.GatewayAPI().GatewayV1beta1().Gateways(ns).Get(context.Background(), name, metav1.GetOptions{})
if err != nil {
if errors.IsNotFound(err) {
fmt.Fprintf(cmd.OutOrStdout(), "waypoint %v/%v not found\n", ns, name)
return
}
mu.Lock()
multiErr = multierror.Append(multiErr, err)
mu.Unlock()
return
}
if err := kubeClient.GatewayAPI().GatewayV1beta1().Gateways(ns).
Delete(context.Background(), gw.Name, metav1.DeleteOptions{}); err != nil {
mu.Lock()
multiErr = multierror.Append(multiErr, err)
mu.Unlock()
return
}
fmt.Fprintf(cmd.OutOrStdout(), "waypoint %v/%v deleted\n", ns, name)
}(name)
}
wg.Wait()
return multiErr.ErrorOrNil()
// Delete waypoints by names if provided
return deleteWaypoints(cmd, kubeClient, ns, args)
},
}
waypointDeleteCmd.Flags().BoolVar(&deleteAll, "all", false, "Delete all waypoints in the namespace")

waypointListCmd := &cobra.Command{
Use: "list",
Short: "List managed waypoint configurations",
Expand Down Expand Up @@ -322,3 +325,43 @@ func Cmd(ctx cli.Context) *cobra.Command {

return waypointCmd
}

// deleteWaypoints handles the deletion of waypoints based on the provided names, or all if names is nil
func deleteWaypoints(cmd *cobra.Command, kubeClient kube.CLIClient, namespace string, names []string) error {
var multiErr *multierror.Error
if names == nil {
// If names is nil, delete all waypoints
waypoints, err := kubeClient.GatewayAPI().GatewayV1beta1().Gateways(namespace).
List(context.Background(), metav1.ListOptions{})
if err != nil {
return err
}
for _, gw := range waypoints.Items {
names = append(names, gw.Name)
}
}

var wg sync.WaitGroup
var mu sync.Mutex
for _, name := range names {
wg.Add(1)
go func(name string) {
defer wg.Done()
if err := kubeClient.GatewayAPI().GatewayV1beta1().Gateways(namespace).
Delete(context.Background(), name, metav1.DeleteOptions{}); err != nil {
if errors.IsNotFound(err) {
fmt.Fprintf(cmd.OutOrStdout(), "waypoint %v/%v not found\n", namespace, name)
} else {
mu.Lock()
multiErr = multierror.Append(multiErr, err)
mu.Unlock()
}
} else {
fmt.Fprintf(cmd.OutOrStdout(), "waypoint %v/%v deleted\n", namespace, name)
}
}(name)
}

wg.Wait()
return multiErr.ErrorOrNil()
}
6 changes: 6 additions & 0 deletions releasenotes/notes/47818.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
apiVersion: release-notes/v2
kind: feature
area: istioctl
releaseNotes:
- |
**Added** a flag `--all` to `istioctl experimental waypoint delete` to delete all Waypoint resources in a given namespace.
19 changes: 19 additions & 0 deletions tests/integration/ambient/waypoint_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -179,6 +179,25 @@ func TestWaypoint(t *testing.T) {
}
return nil
}, retry.Timeout(15*time.Second), retry.BackoffDelay(time.Millisecond*100))

// delete all waypoints in namespace, so sa3 should be deleted
istioctl.NewOrFail(t, t, istioctl.Config{}).InvokeOrFail(t, []string{
"x",
"waypoint",
"-n",
nsConfig.Name(),
"delete",
"--all",
})
retry.UntilSuccessOrFail(t, func() error {
if err := checkWaypointIsReady(t, nsConfig.Name(), "sa3"); err != nil {
if errors.Is(err, kubetest.ErrNoPodsFetched) {
return nil
}
return fmt.Errorf("failed to check gateway status: %v", err)
}
return fmt.Errorf("failed to clean up gateway in namespace: %s", nsConfig.Name())
}, retry.Timeout(15*time.Second), retry.BackoffDelay(time.Millisecond*100))
})
}

Expand Down