-
Notifications
You must be signed in to change notification settings - Fork 706
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
use client-go to port-forward to dashboard #76
use client-go to port-forward to dashboard #76
Conversation
Now that we have updated to client-go v4.0.0, we can use the library to port-forward to the ingress controller.
- package: github.com/emicklei/go-restful-swagger12 | ||
version: dcef7f55730566d41eae5db10e7d6981829720f6 | ||
- package: github.com/go-openapi/spec | ||
version: 6aced65f8501fe1217321abf0749d354824ba2ff |
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.
I had to lock these as the new versions are causing compilation errors
cmd/dashboard.go
Outdated
// Open the Dashboard in a browser when the port-forward is established | ||
go func() { | ||
<-readyChannel | ||
openInBrowser(fmt.Sprintf("http://localhost:%d", localPort)) |
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.
we now open the dashboard in the browser after the port-forward connection is established, so this fixes #64
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.
👍
cmd/dashboard.go
Outdated
return nil, err | ||
} | ||
config.APIPath = "/api" | ||
config.GroupVersion = &v1.SchemeGroupVersion |
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.
We need to specifically set APIPath and GroupVersion otherwise the RestClient we get from this won't build the correct URL to port-forward.
cmd/dashboard.go
Outdated
} | ||
|
||
func openInBrowser(url string) error { | ||
fmt.Printf("Opening %s in your default browser...\n", url) |
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.
Thought this might be useful in case it doesn't open in the browser, the user can see what URL to go to.
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.
👍
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.
Overall it LGTM, I left a few minor comments/questions. We could add some unit tests to cover the newPortforwarder
(just to check that there are not any obvious error) but all this feature is calling for an end-to-end test at some point.
cmd/dashboard.go
Outdated
} | ||
|
||
func portforwardReqURL(config *rest.Config, podName string) (*url.URL, error) { | ||
restClient, err := rest.RESTClientFor(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.
the restClient
should be a parameter to make this function testable (even if you don't test it now). As a general rule, any function that creates a client
cannot be tested.
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.
+1 will change
cmd/dashboard.go
Outdated
return portforward.New(dialer, ports, stopChannel, readyChannel, os.Stdout, os.Stderr) | ||
} | ||
|
||
func restClientConfig() (*rest.Config, error) { |
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.
you should probably move this function to the root
file
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.
This is a very specific client config just for building the port-forward URI, so I think it should stay here.
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.
mm, I saw it generic, what is the specific part? maybe the config.NegotiatedSerializer
? If that is the case I would specify somewhere that this restClient is specific for doing port-forward (apart from defining that in this file) so other people don't misuse it. (Since this function is available for the whole cmd
package)
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.
It's not generic, we're specifying the api path and group version so we get URLs prefixed with api/v1
. I don't think we need to use this anywhere else do we? We should typically use the discovery API.
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.
I think this looks like a regular v1 config. Can we just use clientset.CoreV1().RESTClient()
(or whatever the correct function is) below?
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.
Ah, so I wanted to, since this is actually what kubectl
uses also, but @ngtuna suggested not using it in #41 (comment) to reduce the dependency. However, now that I think about it, I don't think this would be pulling in many more dependencies, it uses the same underlying stuff. @ngtuna what do you think about using clientset for both this and checking if the nginx-ingress pod is there too?
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.
Yah I am seeing no problem now for using clientset
as we generally used it in several functions. What I was saying meant that if we can do stuffs easily with the current-in-used resourceClient
then we should keep using it
cmd/dashboard.go
Outdated
} | ||
config.APIPath = "/api" | ||
config.GroupVersion = &v1.SchemeGroupVersion | ||
config.NegotiatedSerializer = serializer.DirectCodecFactory{CodecFactory: scheme.Codecs} |
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.
I am curious, what is the goal of this?
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.
No idea, it's a required field by RESTClientFor
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.
It's necessary to get the apimachinary code to do the correct serialisation/reserialising of objects.
cmd/dashboard.go
Outdated
return syscall.Exec(cmd, args, env) | ||
req := restClient.Post(). | ||
Resource("pods"). | ||
Namespace(ingressNamespace). |
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.
the "ingressNamespace" seems confusing, I know that it points to kubeapps
but it would be probably better if you make that var a parameter and call it podNamespace
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.
How about ingressPodNamespace
?
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.
you would be unnecessarily limiting the scope of the function to be used with ingress
pods, isn't it? As far as I can see you can use this to obtain the URL for any kind of pod.
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.
I feel like we're trying to generalise this for no reason. Seems like a pre-optimisation, what other port-forward calls do we expect to make?
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.
probably not, it is a generic suggestion
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.
OK, unless you feel strongly about it, I think we can leave as-is. If we want to use this in more places in the future we can move it out of this file and add a parameter. Sound good?
cmd/dashboard.go
Outdated
return nil, err | ||
} | ||
|
||
ports := []string{fmt.Sprintf("%d:80", localPort)} |
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.
shouldn't be 80
obtained somehow?
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.
Maybe, but given we know for sure it's going to be port 80, I think we can avoid the extra API call.
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.
well, other people (like me) may see it that obvious. For example you also know for sure what URL the port forward will use but anyway you are obtaining it just in case it changes (and for the sake of readability)
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.
I would argue the difference between building the port-forward request URL is that we control the ingress controller manifests. We don't control the Kubernetes API though, so that could easily change from version to version.
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.
I think Andres is just suggesting a comment, which seems reasonable. We don't want a future reader to have to work this out for themselves.
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.
yeah, I just didn't know where the 80
came from
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.
sorry I misunderstood, I thought you meant parsing the Service object to get the port. Will add 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.
yes, that's what I meant, but as far as it is clear where it comes from I am fine
R.E. unit tests, indeed it is quite difficult, but we may be able to test some of these functions. An end-to-end test is needed, I agree. |
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.
Lgtm overall, nice improvement.
cmd/dashboard.go
Outdated
return nil, err | ||
} | ||
|
||
ports := []string{fmt.Sprintf("%d:80", localPort)} |
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.
I think Andres is just suggesting a comment, which seems reasonable. We don't want a future reader to have to work this out for themselves.
cmd/dashboard.go
Outdated
} | ||
config.APIPath = "/api" | ||
config.GroupVersion = &v1.SchemeGroupVersion | ||
config.NegotiatedSerializer = serializer.DirectCodecFactory{CodecFactory: scheme.Codecs} |
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.
It's necessary to get the apimachinary code to do the correct serialisation/reserialising of objects.
cmd/dashboard.go
Outdated
return portforward.New(dialer, ports, stopChannel, readyChannel, os.Stdout, os.Stderr) | ||
} | ||
|
||
func restClientConfig() (*rest.Config, error) { |
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.
I think this looks like a regular v1 config. Can we just use clientset.CoreV1().RESTClient()
(or whatever the correct function is) below?
@ngtuna @andresmgot PTAL! |
@prydonius the last commit lgtm |
@@ -183,3 +186,34 @@ func generateEncodedRandomPassword(s int) (string, error) { | |||
pw := base64.URLEncoding.EncodeToString(b) | |||
return base64.URLEncoding.EncodeToString([]byte(pw)), nil | |||
} | |||
|
|||
func clientForGroupVersionKind(pool dynamic.ClientPool, disco discovery.DiscoveryInterface, gvk schema.GroupVersionKind, namespace string) (*dynamic.ResourceClient, error) { |
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.
seems that you are not using these functions any more, you can delete them
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.
No this func is still being used by others
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.
I moved it to root.go because they're being used, yep
- Added single instance view - Moved bindings list to single instance view
Now that we have updated to client-go v4.0.0, we can use the library to
port-forward to the ingress controller.
This implementation is based on what
kubectl
is doing (pre-spdy package). See https://github.com/kubernetes/kubernetes/blob/2612e0c78ad18ac87bbd200d547100cf99f36089/pkg/kubectl/cmd/portforward.go#L104fixes #64