Skip to content

Commit

Permalink
Add list and delete commands in policy recommendation CLI
Browse files Browse the repository at this point in the history
Signed-off-by: Yongming Ding <dyongming@vmware.com>
  • Loading branch information
dreamtalen committed Jun 27, 2022
1 parent 076529a commit 8f35eb8
Show file tree
Hide file tree
Showing 6 changed files with 499 additions and 15 deletions.
31 changes: 30 additions & 1 deletion docs/networkpolicy-recommendation.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@
- [Run a policy recommendation job](#run-a-policy-recommendation-job)
- [Check the status of a policy recommendation job](#check-the-status-of-a-policy-recommendation-job)
- [Retrieve the result of a policy recommendation job](#retrieve-the-result-of-a-policy-recommendation-job)
- [List all policy recommendation jobs](#list-all-policy-recommendation-jobs)
- [Delete a policy recommendation job](#delete-a-policy-recommendation-job)
<!-- /toc -->

## Introduction
Expand Down Expand Up @@ -36,17 +38,21 @@ CLI. `theia` is the command-line tool which provides access to Theia network
flow visibility capabilities. To get more information about `theia`, please
refer to its [user guide](theia-cli.md).

There are 3 `theia` commands for the NetworkPolicy Recommendation feature:
There are 5 `theia` commands for the NetworkPolicy Recommendation feature:

- `theia policy-recommendation run`
- `theia policy-recommendation status`
- `theia policy-recommendation retrieve`
- `theia policy-recommendation list`
- `theia policy-recommendation delete`

Or you could use `pr` as a short alias of `policy-recommendation`:

- `theia pr run`
- `theia pr status`
- `theia pr retrieve`
- `theia pr list`
- `theia pr delete`

To see all options and usage examples of these commands, you may run
`theia policy-recommendation [subcommand] --help`.
Expand Down Expand Up @@ -134,3 +140,26 @@ policies to a YAML file and apply it using `kubectl`:
theia policy-recommendation retrieve e998433e-accb-4888-9fc8-06563f073e86 -f recommended_policies.yml
kubectl apply -f recommended_policies.yml
```

### List all policy recommendation jobs

The `theia policy-recommendation list` command lists all policy recommendation
jobs. `CreateTime`, `CompleteTime`, `ID` and `Status` of each policy
recommendation job will be displayed in the form of a table. For example:

```bash
> theia policy-recommendation list
CreateTime CompleteTime ID Status
2022-06-17 18:33:15 N/A 2cf13427-cbe5-454c-b9d3-e1124af7baa2 RUNNING
2022-06-17 18:06:56 2022-06-17 18:08:37 e998433e-accb-4888-9fc8-06563f073e86 COMPLETED
```

### Delete a policy recommendation job

The `theia policy-recommendation delete` command is used to delete a policy
recommendation job. To delete the policy recommendation job created above, run:

```bash
$ theia policy-recommendation delete e998433e-accb-4888-9fc8-06563f073e86
Successfully deleted policy recommendation job with ID e998433e-accb-4888-9fc8-06563f073e86
```
4 changes: 3 additions & 1 deletion docs/theia-cli.md
Original file line number Diff line number Diff line change
Expand Up @@ -37,11 +37,13 @@ theia help
## Usage

To see the list of available commands and options, run `theia help`. Currently,
we have 3 commands for the NetworkPolicy Recommendation feature:
we have 5 commands for the NetworkPolicy Recommendation feature:

- `theia policy-recommendation run`
- `theia policy-recommendation status`
- `theia policy-recommendation retrieve`
- `theia policy-recommendation list`
- `theia policy-recommendation delete`

For details, please refer to [NetworkPolicy recommendation doc](
networkpolicy-recommendation.md)
190 changes: 190 additions & 0 deletions pkg/theia/commands/policy_recommendation_delete.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,190 @@
// Copyright 2022 Antrea Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package commands

import (
"context"
"fmt"
"net/url"

"github.com/google/uuid"
"github.com/spf13/cobra"
"k8s.io/client-go/kubernetes"

sparkv1 "antrea.io/theia/third_party/sparkoperator/v1beta2"
)

// policyRecommendationDeleteCmd represents the policy-recommendation delete command
var policyRecommendationDeleteCmd = &cobra.Command{
Use: "delete",
Short: "Delete a policy recommendation Spark job",
Long: `Delete a policy recommendation Spark job by ID.`,
Aliases: []string{"del"},
Args: cobra.RangeArgs(0, 1),
Example: `
Delete the policy recommendation job with ID e998433e-accb-4888-9fc8-06563f073e86
$ theia policy-recommendation delete e998433e-accb-4888-9fc8-06563f073e86
`,
RunE: func(cmd *cobra.Command, args []string) error {
recoID, err := cmd.Flags().GetString("id")
if err != nil {
return err
}
if recoID == "" && len(args) == 1 {
recoID = args[0]
}
_, err = uuid.Parse(recoID)
if err != nil {
return fmt.Errorf("failed to decode input id %s into a UUID, err: %v", recoID, err)
}
kubeconfig, err := ResolveKubeConfig(cmd)
if err != nil {
return err
}
endpoint, err := cmd.Flags().GetString("clickhouse-endpoint")
if err != nil {
return err
}
if endpoint != "" {
_, err := url.ParseRequestURI(endpoint)
if err != nil {
return fmt.Errorf("failed to decode input endpoint %s into a url, err: %v", endpoint, err)
}
}
useClusterIP, err := cmd.Flags().GetBool("use-cluster-ip")
if err != nil {
return err
}

clientset, err := CreateK8sClient(kubeconfig)
if err != nil {
return fmt.Errorf("couldn't create k8s client using given kubeconfig, %v", err)
}

idMap, err := getPolicyRecommendationIdMap(clientset, kubeconfig, endpoint, useClusterIP)
if err != nil {
return fmt.Errorf("err when get policy recommendation ID map, %v", err)
}

if _, ok := idMap[recoID]; !ok {
return fmt.Errorf("could not find the policy recommendation job with given ID")
}

clientset.CoreV1().RESTClient().Delete().
AbsPath("/apis/sparkoperator.k8s.io/v1beta2").
Namespace(flowVisibilityNS).
Resource("sparkapplications").
Name("pr-" + recoID).
Do(context.TODO())

err = deletePolicyRecommendationResult(clientset, kubeconfig, endpoint, useClusterIP, recoID)
if err != nil {
return err
}

fmt.Printf("Successfully deleted policy recommendation job with ID %s\n", recoID)
return nil
},
}

func getPolicyRecommendationIdMap(clientset kubernetes.Interface, kubeconfig string, endpoint string, useClusterIP bool) (idMap map[string]bool, err error) {
idMap = make(map[string]bool)
sparkApplicationList := &sparkv1.SparkApplicationList{}
err = clientset.CoreV1().RESTClient().Get().
AbsPath("/apis/sparkoperator.k8s.io/v1beta2").
Namespace(flowVisibilityNS).
Resource("sparkapplications").
Do(context.TODO()).Into(sparkApplicationList)
if err != nil {
return idMap, err
}
for _, sparkApplication := range sparkApplicationList.Items {
id := sparkApplication.ObjectMeta.Name[3:]
idMap[id] = true
}
completedPolicyRecommendationList, err := getCompletedPolicyRecommendationList(clientset, kubeconfig, endpoint, useClusterIP)
if err != nil {
return idMap, err
}
for _, completedPolicyRecommendation := range completedPolicyRecommendationList {
idMap[completedPolicyRecommendation.id] = true
}
return idMap, nil
}

func deletePolicyRecommendationResult(clientset kubernetes.Interface, kubeconfig string, endpoint string, useClusterIP bool, recoID string) (err error) {
if endpoint == "" {
service := "clickhouse-clickhouse"
if useClusterIP {
serviceIP, servicePort, err := GetServiceAddr(clientset, service)
if err != nil {
return fmt.Errorf("error when getting the ClickHouse Service address: %v", err)
}
endpoint = fmt.Sprintf("tcp://%s:%d", serviceIP, servicePort)
} else {
listenAddress := "localhost"
listenPort := 9000
_, servicePort, err := GetServiceAddr(clientset, service)
if err != nil {
return fmt.Errorf("error when getting the ClickHouse Service port: %v", err)
}
// Forward the ClickHouse service port
pf, err := StartPortForward(kubeconfig, service, servicePort, listenAddress, listenPort)
if err != nil {
return fmt.Errorf("error when forwarding port: %v", err)
}
defer pf.Stop()
endpoint = fmt.Sprintf("tcp://%s:%d", listenAddress, listenPort)
}
}

// Connect to ClickHouse and get the result
username, password, err := getClickHouseSecret(clientset)
if err != nil {
return err
}
url := fmt.Sprintf("%s?debug=false&username=%s&password=%s", endpoint, username, password)
connect, err := connectClickHouse(clientset, url)
if err != nil {
return fmt.Errorf("error when connecting to ClickHouse, %v", err)
}
query := "ALTER TABLE recommendations DELETE WHERE id = (?);"
_, err = connect.Exec(query, recoID)
if err != nil {
return fmt.Errorf("failed to delete recommendation result with id %s: %v", recoID, err)
}
return nil
}

func init() {
policyRecommendationCmd.AddCommand(policyRecommendationDeleteCmd)
policyRecommendationDeleteCmd.Flags().StringP(
"id",
"i",
"",
"ID of the policy recommendation Spark job.",
)
policyRecommendationDeleteCmd.Flags().String(
"clickhouse-endpoint",
"",
"The ClickHouse service endpoint.",
)
policyRecommendationDeleteCmd.Flags().Bool(
"use-cluster-ip",
false,
`Enable this option will use Service ClusterIP instead of port forwarding when connecting to the ClickHouse service.
It can only be used when running theia in cluster.`,
)
}
Loading

0 comments on commit 8f35eb8

Please sign in to comment.