-
Notifications
You must be signed in to change notification settings - Fork 2
feat: import kubectl get command #41
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
base: main
Are you sure you want to change the base?
feat: import kubectl get command #41
Conversation
|
@gianarb FYI I had to run $ go build -o datumctl .
go: updates to go.mod needed; to update it:
go mod tidy
$ go mod tidy
$ go build -o datumctl .
$ ./datumctl --help
A CLI for interacting with the Datum platform
... |
This commit replaces the datumctl `get` command that currently supports `organizations` only with the kubectl get command. ``` DATUMCTL_EXPERIMENTAL=true go run main.go get projects --organization-id personal-org-f9a87347 NAME READY AGE shippingbytes-jh601e True 87d ``` ``` DATUMCTL_EXPERIMENTAL=true go run main.go get domains --project-id shippingbytes-jh601e NAME DOMAIN NAME AGE VERIFIED hello-it hello.it 46h False ``` ``` DATUMCTL_EXPERIMENTAL=true go run main.go get organizationmemberships --all-namespaces NAME READY AGE shippingbytes-jh601e True 87d ``` It also adds support for `-v` the same used by the kubectl and for two new commands: `api-resources` and `api-versions` Signed-off-by: Gianluca Arbezzano <ciao@gianarb.it>
292e9f3 to
2dfabc0
Compare
|
Hey @gianarb, I was finally got around to playing around with this locally. Overall it seems to work great! I looked into the issue you were mentioning on Slack where it would only load resources from the I found I was able to remove the custom fork of client-go that resolved that issue if I apply the diff below to diff --git a/internal/client/factory.go b/internal/client/factory.go
index 97e0904..4a56f69 100644
--- a/internal/client/factory.go
+++ b/internal/client/factory.go
@@ -59,7 +59,7 @@ func (c *customConfigFlags) ToRawKubeConfigLoader() clientcmd.ClientConfig {
"inmemory": {
Cluster: "inmemory",
AuthInfo: "inmemory",
- Namespace: *c.Namespace,
+ Namespace: "",
},
},
CurrentContext: "inmemory",
@@ -73,8 +73,8 @@ func (c *customConfigFlags) ToRawKubeConfigLoader() clientcmd.ClientConfig {
overrides.CurrentContext = *c.Context
}
- if c.Namespace != nil {
- overrides.Context.Namespace = *c.Namespace
+ if c.ConfigFlags.Namespace != nil && *c.ConfigFlags.Namespace != "" {
+ overrides.Context.Namespace = *c.ConfigFlags.Namespace
}
// Apply cluster overrides if set
diff --git a/internal/cmd/get/v2/get.go b/internal/cmd/get/v2/get.go
index 388d0b6..0a4bf0d 100644
--- a/internal/cmd/get/v2/get.go
+++ b/internal/cmd/get/v2/get.go
@@ -13,15 +13,15 @@ import (
)
func Command(factory *client.MyFactory, ioStreams genericclioptions.IOStreams, projectID *string, organizationID *string) *cobra.Command {
- getCmd := get.NewCmdGet("datumctl", factory, ioStreams)
- getCmd.Run = func(cmd *cobra.Command, args []string) {
+ // Create a PreRun hook to configure the factory before kubectl's command runs
+ preRunFunc := func(cmd *cobra.Command, args []string) {
apiHostname, err := authutil.GetAPIHostname()
if err != nil {
panic(fmt.Errorf("get API hostname: %w", err))
}
restConfig, err := factory.ToRESTConfig()
if err != nil {
- panic(fmt.Errorf("get API hostname: %w", err))
+ panic(fmt.Errorf("get REST config: %w", err))
}
tknSrc, err := authutil.GetTokenSource(cmd.Context())
if err != nil {
@@ -41,8 +41,9 @@ func Command(factory *client.MyFactory, ioStreams genericclioptions.IOStreams, p
default:
panic(fmt.Errorf("exactly one of organizationID or projectID must be provided"))
}
- cmdInt := get.NewCmdGet("datumctl", factory, ioStreams)
- cmdInt.Run(cmd, args)
}
+
+ getCmd := get.NewCmdGet("datumctl", factory, ioStreams)
+ getCmd.PreRun = preRunFunc
return getCmd
}Here's the results of what I get when I try to get namespaced / all-namespace resources from the updated version of $ ./datumctl get domains --project-id=datum-cloud -n default
NAME DOMAIN NAME AGE VERIFIED
datum-staging-net-gvn6p datum-staging.net 48d True
$ ./datumctl get domains --project-id=datum-cloud -n default --all-namespaces
NAMESPACE NAME DOMAIN NAME AGE VERIFIED
default datum-staging-net-gvn6p datum-staging.net 48d TrueI'd also like to get your thoughts around some of the CLI flags that are exposed through the standard kubectl Datum Cloud users shouldn't have to deal with kubeconfig files since they're integrating with Datum Cloud's APIs and not individual kubernetes clusters. Ideally a user would be able to switch between projects / organizations easily without having to setup new contexts in a config file. Additionally users can't use client certificates to authenticate with Datum Cloud so the option being available could be misleading. Is there a way to hide or remove these flags? |
|
Great! Thanks I was feeling stuck and I am glad you figured out the right direction! Do you want to push such changes to my branch or send me a patch with your contacts that I can apply so it goes to you? I am disabling the flags you shared since datum won't make use of those. I have two questions my side that are left in order to mark this as done IMHO but feel free to leave your todo list for me if you have any items for this specific PR (I am trying to keep since under control in size)
|
Quote from @scotwells Datum Cloud users shouldn't have to deal with kubeconfig files since they're integrating with Datum Cloud's APIs and not individual kubernetes clusters. Ideally a user would be able to switch between projects / organizations easily without having to setup new contexts in a config file. Additionally users can't use client certificates to authenticate with Datum Cloud so the option being available could be misleading.
|
I don't mind if you push those changes directly. They don't need to be in my name.
|
|
About point two sorry but I did not get your desire. Do you want to have me figure out a way to make organization membership to map to an organization for the ctl or not?
Thanks
Il 29 dicembre 2025 21:33:02 CET, Scot Schuchert-Wells ***@***.***> ha scritto:
…scotwells left a comment (datum-cloud/datumctl#41)
I don't mind if you push those changes directly. They don't need to be in my name.
1. Let's make the breaking change and replace the existing command.
2. I like the idea of being able to map types to more ergonomic types to improve UX. The primary audience for this tool is external consumers so we should prioritize the UX for them. Eventually we'll have an API available that supports listing resources just the resources a user has access to so users can query for organizations and just get a filtered list.
--
Reply to this email directly or view it on GitHub:
#41 (comment)
You are receiving this because you were mentioned.
Message ID: ***@***.***>
|
|
@gianarb yes, let's have "get organizations" map to "get organizationmemberships" |
|
Ok great I will try to have this or ready before the new year!
Il 29 dicembre 2025 21:56:08 CET, Scot Schuchert-Wells ***@***.***> ha scritto:
…scotwells left a comment (datum-cloud/datumctl#41)
@gianarb yes, let's have "get organizations" map to "get organizationmemberships"
--
Reply to this email directly or view it on GitHub:
#41 (comment)
You are receiving this because you were mentioned.
Message ID: ***@***.***>
|
This commit contains a few things. Scot's suggestion to rollback to client-go. It implements a remap for organization to organization membership to keep compatibility with the current version of the CLI.
Scot suggested a breaking change is a good at this stage. This commit removes the need for `DATUMCTL_EXPERIMENTAL` and it replace the old `get` command with the new one
|
At the end I didn't manage to get this done before new year, but I feel like now it is ready for a review and merge eventually. My plan next is to the other commands useful for a crud operation like: |
scotwells
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looking great! Just some minor feedback so far.
| type MyFactory struct { | ||
| util.Factory | ||
| ConfigFlags *genericclioptions.ConfigFlags | ||
| RestConfig *rest.Config | ||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thoughts on naming this something like DatumCloudFactory since it's specific to building configs for interacting with Datum Cloud's APIs?
Are you thinking we'd use this factory to build the necessary configs in other locations we're building a kubeconfig? Example:
datumctl/internal/client/user_context.go
Lines 46 to 55 in 96772c1
| // Create Kubernetes client configuration with scheme | |
| config := &rest.Config{ | |
| Host: userContextAPI, | |
| WrapTransport: func(rt http.RoundTripper) http.RoundTripper { | |
| return &oauth2.Transport{ | |
| Source: tknSrc, | |
| Base: rt, | |
| } | |
| }, | |
| } |
| if c.BearerToken != nil && *c.BearerToken != "" { | ||
| config.BearerToken = *c.BearerToken | ||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Do we need to worry about passing this through since we will always need to override the bearer token with the access token stored in the user's keychain?
| tknSrc, err := authutil.GetTokenSource(cmd.Context()) | ||
| if err != nil { | ||
| return err | ||
| } | ||
| restConfig.WrapTransport = func(rt http.RoundTripper) http.RoundTripper { | ||
| return &oauth2.Transport{Source: tknSrc, Base: rt} | ||
| } | ||
| switch { | ||
| case (projectID == nil || *projectID == "") && (organizationID == nil || *organizationID == ""): | ||
| case (projectID == nil || *projectID == "") && (organizationID != nil || *organizationID != ""): | ||
| factory.RestConfig.Host = fmt.Sprintf("https://%s/apis/resourcemanager.miloapis.com/v1alpha1/organizations/%s/control-plane", | ||
| apiHostname, *organizationID) | ||
| case (projectID != nil || *projectID != "") && (organizationID == nil || *organizationID == ""): | ||
| factory.RestConfig.Host = fmt.Sprintf("https://%s/apis/resourcemanager.miloapis.com/v1alpha1/projects/%s/control-plane", | ||
| apiHostname, *projectID) | ||
| default: | ||
| return fmt.Errorf("exactly one of organizationID or projectID must be provided") | ||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should this be happening within the client configuration factory? This code would be used across any command that interacts with the API to make sure the correct control plane is used.
| // Add the verbose flag | ||
| LoginCmd.Flags().BoolVarP(&verbose, "verbose", "v", false, "Print the full ID token claims after successful login") |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Was this CLI flag removed because we support the generic -v short-hand used by kubectl? If so, I think we need to update the login flow to support using -v because now this change disables verbose output entirely.
What
This commit replaces the datumctl
getcommand that currently supportsorganizationsonly with the kubectl get command.It also adds support for
-vthe same used by the kubectl and for twonew commands:
api-resourcesandapi-versionsWhy
We want to offer a fimilar environment to interact with for users coming from
Kubernetes. No better way to achive that than using the kubectl code itself.
For Reviewer
I decied to open this PR now becuase I am working at it from a couple of days
and the features are there, I want other people to look at it.
The implementation is pretty rusty I am still not sure about how to properly
combine clientcmd.ConfigFlags an the Factory. I wrote Datum implementation to
see if I was able to get somewhere but I feel we can do better. Primarly
because I had to modify the clientcmd to support
--all-namespacesand itsounds pretty wrong!
I am open for suggesitions