-
Notifications
You must be signed in to change notification settings - Fork 755
feat: kubectl ray get token command #4218
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
Changes from 4 commits
3570c0d
0b2e6cc
56e2c7e
cbb7c83
25e438a
a3795dd
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,85 @@ | ||
| package get | ||
|
|
||
| import ( | ||
| "context" | ||
| "fmt" | ||
|
|
||
| "github.com/spf13/cobra" | ||
| v1 "k8s.io/apimachinery/pkg/apis/meta/v1" | ||
| "k8s.io/cli-runtime/pkg/genericclioptions" | ||
| cmdutil "k8s.io/kubectl/pkg/cmd/util" | ||
|
|
||
| "github.com/ray-project/kuberay/kubectl-plugin/pkg/util/client" | ||
| "github.com/ray-project/kuberay/kubectl-plugin/pkg/util/completion" | ||
| rayv1 "github.com/ray-project/kuberay/ray-operator/apis/ray/v1" | ||
| ) | ||
|
|
||
| type GetTokenOptions struct { | ||
| cmdFactory cmdutil.Factory | ||
| ioStreams *genericclioptions.IOStreams | ||
| namespace string | ||
| cluster string | ||
| } | ||
|
|
||
| func NewGetTokenOptions(cmdFactory cmdutil.Factory, streams genericclioptions.IOStreams) *GetTokenOptions { | ||
| return &GetTokenOptions{ | ||
| cmdFactory: cmdFactory, | ||
| ioStreams: &streams, | ||
| } | ||
| } | ||
|
|
||
| func NewGetTokenCommand(cmdFactory cmdutil.Factory, streams genericclioptions.IOStreams) *cobra.Command { | ||
| options := NewGetTokenOptions(cmdFactory, streams) | ||
|
|
||
| cmd := &cobra.Command{ | ||
| Use: "token [CLUSTER NAME]", | ||
| Aliases: []string{"token"}, | ||
| Short: "Get the auth token from the ray cluster.", | ||
| SilenceUsage: true, | ||
| ValidArgsFunction: completion.RayClusterCompletionFunc(cmdFactory), | ||
| Args: cobra.ExactArgs(1), | ||
| RunE: func(cmd *cobra.Command, args []string) error { | ||
| if err := options.Complete(args, cmd); err != nil { | ||
| return err | ||
| } | ||
| // running cmd.Execute or cmd.ExecuteE sets the context, which will be done by root | ||
| k8sClient, err := client.NewClient(cmdFactory) | ||
| if err != nil { | ||
| return fmt.Errorf("failed to create client: %w", err) | ||
| } | ||
| return options.Run(cmd.Context(), k8sClient) | ||
| }, | ||
| } | ||
| return cmd | ||
|
rueian marked this conversation as resolved.
|
||
| } | ||
|
|
||
| func (options *GetTokenOptions) Complete(args []string, cmd *cobra.Command) error { | ||
| namespace, err := cmd.Flags().GetString("namespace") | ||
| if err != nil { | ||
| return fmt.Errorf("failed to get namespace: %w", err) | ||
| } | ||
| options.namespace = namespace | ||
| if options.namespace == "" { | ||
| options.namespace = "default" | ||
| } | ||
| // guarded by cobra.ExactArgs(1) | ||
| options.cluster = args[0] | ||
| return nil | ||
| } | ||
|
|
||
| func (options *GetTokenOptions) Run(ctx context.Context, k8sClient client.Client) error { | ||
| cluster, err := k8sClient.RayClient().RayV1().RayClusters(options.namespace).Get(ctx, options.cluster, v1.GetOptions{}) | ||
| if err != nil { | ||
| return err | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. return fmt.Errorf("failed to get RayCluster %s/%s: %w", options.namespace, options.cluster, err) |
||
| } | ||
| if cluster.Spec.AuthOptions == nil || cluster.Spec.AuthOptions.Mode != rayv1.AuthModeToken { | ||
| return fmt.Errorf("no auth token for this cluster") | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. return fmt.Errorf("RayCluster was not configured to use authentication tokens") |
||
| } | ||
| // TODO: support custom token secret? | ||
| secret, err := k8sClient.KubernetesClient().CoreV1().Secrets(options.namespace).Get(ctx, options.cluster, v1.GetOptions{}) | ||
| if err != nil { | ||
| return err | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. return fmt.Errorf("failed to get secret %s/%s: %w", options.namespace, options.cluster, err) |
||
| } | ||
| _, err = fmt.Fprint(options.ioStreams.Out, string(secret.Data["auth_token"])) | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Check if |
||
| return err | ||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,61 @@ | ||
| package get | ||
|
|
||
| import ( | ||
| "testing" | ||
|
|
||
| "github.com/spf13/cobra" | ||
| "github.com/stretchr/testify/assert" | ||
| "github.com/stretchr/testify/require" | ||
| corev1 "k8s.io/api/core/v1" | ||
| v1 "k8s.io/apimachinery/pkg/apis/meta/v1" | ||
| "k8s.io/cli-runtime/pkg/genericclioptions" | ||
| kubefake "k8s.io/client-go/kubernetes/fake" | ||
| cmdutil "k8s.io/kubectl/pkg/cmd/util" | ||
|
|
||
| "github.com/ray-project/kuberay/kubectl-plugin/pkg/util/client" | ||
| rayv1 "github.com/ray-project/kuberay/ray-operator/apis/ray/v1" | ||
| rayClientFake "github.com/ray-project/kuberay/ray-operator/pkg/client/clientset/versioned/fake" | ||
| ) | ||
|
|
||
| // Tests the Run() step of the command and ensure that the output is as expected. | ||
| func TestTokenGetRun(t *testing.T) { | ||
| cmdFactory := cmdutil.NewFactory(genericclioptions.NewConfigFlags(true)) | ||
|
|
||
| testStreams, _, resBuf, _ := genericclioptions.NewTestIOStreams() | ||
| fakeTokenGetOptions := NewGetTokenOptions(cmdFactory, testStreams) | ||
|
|
||
| rayCluster := &rayv1.RayCluster{ | ||
| ObjectMeta: v1.ObjectMeta{ | ||
| Name: "raycluster-kuberay", | ||
| Namespace: "test", | ||
| }, | ||
| Spec: rayv1.RayClusterSpec{ | ||
| AuthOptions: &rayv1.AuthOptions{ | ||
| Mode: rayv1.AuthModeToken, | ||
| }, | ||
| }, | ||
| } | ||
|
|
||
| secret := &corev1.Secret{ | ||
| ObjectMeta: v1.ObjectMeta{ | ||
| Name: "raycluster-kuberay", | ||
| Namespace: "test", | ||
| }, | ||
| Data: map[string][]byte{ | ||
| "auth_token": []byte("token"), | ||
| }, | ||
| } | ||
|
|
||
| kubeClientSet := kubefake.NewClientset(secret) | ||
| rayClient := rayClientFake.NewSimpleClientset(rayCluster) | ||
| k8sClients := client.NewClientForTesting(kubeClientSet, rayClient) | ||
|
|
||
| cmd := &cobra.Command{} | ||
| cmd.Flags().StringVarP(&fakeTokenGetOptions.namespace, "namespace", "n", secret.Namespace, "") | ||
| err := fakeTokenGetOptions.Complete([]string{rayCluster.Name}, cmd) | ||
| require.NoError(t, err) | ||
| err = fakeTokenGetOptions.Run(t.Context(), k8sClients) | ||
| require.NoError(t, err) | ||
|
|
||
| assert.Equal(t, secret.Data["auth_token"], resBuf.Bytes()) | ||
| } |
Uh oh!
There was an error while loading. Please reload this page.