Skip to content
Open
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
76 changes: 43 additions & 33 deletions ctl/authz/authz.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,6 @@ import (
"fmt"
"io"
"net/http"
"os"
"text/tabwriter"

"github.com/spf13/cobra"
Expand Down Expand Up @@ -59,10 +58,13 @@ func NewEnableCmd() *cobra.Command {
Short: "Enable xdp authz eBPF program for Kmesh's authz offloading",
Example: "kmeshctl authz enable\nkmeshctl authz enable pod1 pod2",
Args: cobra.ArbitraryArgs,
Run: func(cmd *cobra.Command, args []string) {
RunE: func(cmd *cobra.Command, args []string) error {
// If no pod names are given, apply to all kmesh daemon pods.
SetAuthzForPods(args, "true")
log.Info("Authorization has been enabled.")
if err := SetAuthzForPods(args, "true"); err != nil {
return err
}
cmd.Println("Authorization has been enabled.")
return nil
},
}
return cmd
Expand All @@ -75,9 +77,12 @@ func NewDisableCmd() *cobra.Command {
Short: "Disable xdp authz eBPF program for Kmesh's authz offloading",
Example: "kmeshctl authz disable\nkmeshctl authz disable pod1 pod2",
Args: cobra.ArbitraryArgs,
Run: func(cmd *cobra.Command, args []string) {
SetAuthzForPods(args, "false")
log.Info("Authorization has been disabled.")
RunE: func(cmd *cobra.Command, args []string) error {
if err := SetAuthzForPods(args, "false"); err != nil {
return err
}
cmd.Println("Authorization has been disabled.")
return nil
},
}
return cmd
Expand All @@ -90,20 +95,18 @@ func NewStatusCmd() *cobra.Command {
Short: "Display the current authorization status",
Example: "kmeshctl authz status\nkmeshctl authz status pod1 pod2",
Args: cobra.ArbitraryArgs,
Run: func(cmd *cobra.Command, args []string) {
RunE: func(cmd *cobra.Command, args []string) error {
cli, err := utils.CreateKubeClient()
if err != nil {
log.Errorf("failed to create cli client: %v", err)
os.Exit(1)
return fmt.Errorf("failed to create cli client: %v", err)
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

high

Throughout this file, fmt.Errorf is used with %v to wrap errors, which contradicts the PR's goal of using %w for proper error wrapping. This prevents error inspection with errors.Is or errors.As. Please change %v to %w in the following locations:

  • line 101
  • line 109
  • line 155
  • line 162
  • line 185
  • line 188
  • line 200
  • line 207
  • line 237
  • line 244
  • line 254
Suggested change
return fmt.Errorf("failed to create cli client: %v", err)
return fmt.Errorf("failed to create cli client: %w", err)

}

// Determine which pods to query.
var podNames []string
if len(args) == 0 {
podList, err := cli.PodsForSelector(context.TODO(), utils.KmeshNamespace, utils.KmeshLabel)
if err != nil {
log.Errorf("failed to get kmesh podList: %v", err)
os.Exit(1)
return fmt.Errorf("failed to get kmesh podList: %v", err)
}
for _, pod := range podList.Items {
podNames = append(podNames, pod.GetName())
Expand Down Expand Up @@ -137,74 +140,78 @@ func NewStatusCmd() *cobra.Command {
fmt.Fprintf(tw, "%s\t%s\n", s.Pod, s.Status)
}
tw.Flush()
fmt.Print(buf.String())
cmd.Print(buf.String())
return nil
},
}
return cmd
}

// SetAuthzForPods applies the authz setting (enable/disable) for the given pod(s).
// If no pod names are specified, it applies the setting to all kmesh daemon pods.
func SetAuthzForPods(podNames []string, info string) {
func SetAuthzForPods(podNames []string, info string) error {
cli, err := utils.CreateKubeClient()
if err != nil {
log.Errorf("failed to create cli client: %v", err)
os.Exit(1)
return fmt.Errorf("failed to create cli client: %v", err)
}

if len(podNames) == 0 {
// Apply to all kmesh daemon pods.
podList, err := cli.PodsForSelector(context.TODO(), utils.KmeshNamespace, utils.KmeshLabel)
if err != nil {
log.Errorf("failed to get kmesh podList: %v", err)
os.Exit(1)
return fmt.Errorf("failed to get kmesh podList: %v", err)
}
for _, pod := range podList.Items {
SetAuthzPerKmeshDaemon(cli, pod.GetName(), info)
if err := SetAuthzPerKmeshDaemon(cli, pod.GetName(), info); err != nil {
return err
}
}
} else {
// Process for specified pods.
for _, podName := range podNames {
SetAuthzPerKmeshDaemon(cli, podName, info)
if err := SetAuthzPerKmeshDaemon(cli, podName, info); err != nil {
return err
}
}
}
return nil
}

// SetAuthzPerKmeshDaemon sends a POST request to a specific kmesh daemon pod
// to set the authz flag based on the info parameter ("true" or "false").
func SetAuthzPerKmeshDaemon(cli kube.CLIClient, podName, info string) {
func SetAuthzPerKmeshDaemon(cli kube.CLIClient, podName, info string) error {
fw, err := utils.CreateKmeshPortForwarder(cli, podName)
if err != nil {
log.Errorf("failed to create port forwarder for Kmesh daemon pod %s: %v", podName, err)
os.Exit(1)
return fmt.Errorf("failed to create port forwarder for Kmesh daemon pod %s: %v", podName, err)
}
if err := fw.Start(); err != nil {
log.Errorf("failed to start port forwarder for Kmesh daemon pod %s: %v", podName, err)
os.Exit(1)
return fmt.Errorf("failed to start port forwarder for Kmesh daemon pod %s: %v", podName, err)
}
defer fw.Close()

url := fmt.Sprintf("http://%s%s?enable=%s", fw.Address(), patternAuthz, info)
return SetAuthz(url)
}

// SetAuthz sends a POST request to the specified URL to set the authz flag.
func SetAuthz(url string) error {
req, err := http.NewRequest(http.MethodPost, url, nil)
if err != nil {
log.Errorf("Error creating request: %v", err)
return
return fmt.Errorf("error creating request: %v", err)
}

req.Header.Set("Content-Type", "application/json")
client := &http.Client{}
resp, err := client.Do(req)
if err != nil {
log.Errorf("failed to make HTTP request: %v", err)
return
return fmt.Errorf("failed to make HTTP request: %v", err)
}
defer resp.Body.Close()

if resp.StatusCode != http.StatusOK {
log.Errorf("Error: received status code %d", resp.StatusCode)
return
return fmt.Errorf("received status code %d", resp.StatusCode)
}
return nil
}

// fetchAuthzStatus sends a GET request to a specific kmesh daemon pod
Expand All @@ -220,7 +227,11 @@ func fetchAuthzStatus(cli kube.CLIClient, podName string) (string, error) {
defer fw.Close()

url := fmt.Sprintf("http://%s%s", fw.Address(), patternAuthz)
return GetAuthzStatus(url)
}

// GetAuthzStatus sends a GET request to the specified URL to retrieve the current authz status.
func GetAuthzStatus(url string) (string, error) {
req, err := http.NewRequest(http.MethodGet, url, nil)
if err != nil {
return "", fmt.Errorf("error creating request: %v", err)
Expand All @@ -243,6 +254,5 @@ func fetchAuthzStatus(cli kube.CLIClient, podName string) (string, error) {
return "", fmt.Errorf("failed to read response body: %v", err)
}

status := string(bodyBytes)
return status, nil
return string(bodyBytes), nil
}
95 changes: 95 additions & 0 deletions ctl/authz/authz_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
/*
* Copyright The Kmesh 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 authz

import (
"net/http"
"net/http/httptest"
"testing"
)

func TestNewCmd(t *testing.T) {
cmd := NewCmd()
if cmd.Use != "authz" {
t.Fatalf("Use = %q, want %q", cmd.Use, "authz")
}

got := map[string]bool{}
for _, sub := range cmd.Commands() {
got[sub.Name()] = true
}
for _, want := range []string{"enable", "disable", "status"} {
if !got[want] {
t.Errorf("subcommand %q not registered", want)
}
}
}

func TestNewEnableCmd(t *testing.T) {
cmd := NewEnableCmd()
if cmd.Use != "enable [podNames...]" {
t.Fatalf("Use = %q, want %q", cmd.Use, "enable [podNames...]")
}
}

func TestNewDisableCmd(t *testing.T) {
cmd := NewDisableCmd()
if cmd.Use != "disable [podNames...]" {
t.Fatalf("Use = %q, want %q", cmd.Use, "disable [podNames...]")
}
}

func TestNewStatusCmd(t *testing.T) {
cmd := NewStatusCmd()
if cmd.Use != "status [podNames...]" {
t.Fatalf("Use = %q, want %q", cmd.Use, "status [podNames...]")
}
}

func TestSetAuthz(t *testing.T) {
ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
if r.Method != http.MethodPost {
t.Errorf("Method = %q, want %q", r.Method, http.MethodPost)
}
w.WriteHeader(http.StatusOK)
}))
defer ts.Close()

if err := SetAuthz(ts.URL); err != nil {
t.Errorf("SetAuthz() failed: %v", err)
}
}

func TestGetAuthzStatus(t *testing.T) {
want := "enabled"
ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
if r.Method != http.MethodGet {
t.Errorf("Method = %q, want %q", r.Method, http.MethodGet)
}
w.WriteHeader(http.StatusOK)
w.Write([]byte(want))
}))
defer ts.Close()

got, err := GetAuthzStatus(ts.URL)
if err != nil {
t.Errorf("GetAuthzStatus() failed: %v", err)
}
if got != want {
t.Errorf("GetAuthzStatus() = %q, want %q", got, want)
}
}
45 changes: 45 additions & 0 deletions ctl/common/common_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
/*
* Copyright The Kmesh 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 common

import (
"testing"
)

func TestGetRootCommand(t *testing.T) {
root := GetRootCommand()
if root.Use != "kmeshctl" {
t.Fatalf("Use = %q, want %q", root.Use, "kmeshctl")
}

want := map[string]bool{
"log": false, "dump": false, "waypoint": false, "version": false,
"monitoring": false, "authz": false, "secret": false,
}

for _, cmd := range root.Commands() {
if _, ok := want[cmd.Name()]; ok {
want[cmd.Name()] = true
}
}

for name, found := range want {
if !found {
t.Errorf("subcommand %q not registered", name)
}
}
}
Loading
Loading