Skip to content
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

Teleterm: Add listing kube resources endpoint #46753

Open
wants to merge 5 commits into
base: master
Choose a base branch
from

Conversation

kimlisa
Copy link
Contributor

@kimlisa kimlisa commented Sep 19, 2024

part of #46742

easier to review by commit

Adds a new grpc endpoint and related boilerplates for listing kube resources

if confused what is the difference between the other endpoint where we list kubes, kube resources refers to kube_cluster's sub resources:

// KubernetesResourcesKinds lists the supported Kubernetes resource kinds.

This comment was marked as resolved.

Comment on lines 192 to 199
// AppendKubeResource appends kube resource segment to the URI.
// Modeled after how access request constructs the resource ID:
// <teleport-cluster-name>/<subresource kind>/<kube_cluster name>/<subresource name>
func (r ResourceURI) AppendKubeResource(kubeResourceKind string, kubeClusterName string, kubeResourceName string) ResourceURI {
r.path = fmt.Sprintf("%v/%v/%v/%v", r.path, kubeResourceKind, kubeClusterName, kubeResourceName)
return r
}

Copy link
Contributor Author

Choose a reason for hiding this comment

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

i wasn't entirely sure what this was for, other than perhaps to uniquely identify resources?

Copy link
Contributor

Choose a reason for hiding this comment

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

Yeah, URIs are used for identifying resources.

fmt.Sprintf("%v/%v/%v/%v", r.path, kubeResourceKind, kubeClusterName, kubeResourceName)

I see some problems with this scheme. kubeResourceKind is an unknown string, so in theory, it could collide with other URIs. Additionally, we would not be able to identify if a given URI string is a kube resource URI without knowing kubeResourceKind.
A fix for this would be adding a known prefix in the URI, e.g:

"/clusters/teleport.sh/kube-resources/namespace/kube-cluster-name/namespace-name"

However, perhaps it would make more sense to treat a kube resource as a child of the kube cluster? I mean something like this:

var pathKubes = urlpath.New("/clusters/:cluster/kubes/:kubeName")
var pathKubeResources = urlpath.New("/clusters/:cluster/kubes/:kubeName/:subResourceKind/:subResourceName")

cc @ravicious

Copy link
Contributor Author

Choose a reason for hiding this comment

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

i went ahead and applied your first suggestion instead:

"/clusters/teleport.sh/kube-resources/namespace/kube-cluster-name/namespace-name"

Copy link
Member

Choose a reason for hiding this comment

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

If it's correct that kube subresources always belong to a specific kube resource, and I believe it's correct, then I'd definitely go with the second option that Grzegorz proposed.

If we currently support only namespaces within the app, then for now I'd make a definition only for namespaces. That would be:

  kubeResourceNamespace:
    '/clusters/:rootClusterId/(leaves)?/:leafClusterId?/kubes/:kubeId/namespaces/:kubeNamespaceId',
  kubeResourceNamespaceLeaf:
    '/clusters/:rootClusterId/leaves/:leafClusterId/kubes/:kubeId/namespaces/:kubeNameSpaceId',

This follows the existing conventions that we have while introducing a new one. Nested identifiers are prefixed with "parent's" name, e.g. it's :kubeNamespaceId, not :namespaceId.

This is mostly due to how matchPath works and how we implemented parseUri. You give it a bunch of possible identifiers and then pluck out what you need. So if we end up having two URIs, I think we'd rather have two different fields prefixed with the parent name, rather than reusing the same field name for two different purposes.

I wouldn't bother with KubeResourceNamespaceParam for now. If we wanted to have better types around this, we should refactor how routing.parseUri works and all the helper functions like routing.parseServerUri.


On the Go side, AppendKubeResourceNamespace as you have it is fine, we'd only have to change the actual URI it generates.

@kimlisa kimlisa added no-changelog Indicates that a PR does not require a changelog entry backport/branch/v16 labels Sep 19, 2024
Comment on lines 825 to 828
proxyGRPCClient, err := tc.NewKubernetesServiceClient(ctx, cluster.Name)
if err != nil {
return nil, trace.Wrap(err)
}
Copy link
Contributor

Choose a reason for hiding this comment

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

It seems to me this should be wrapped in clusters.AddMetadataToRetryableError too.

Comment on lines 844 to 848
if err != nil {
return trace.Wrap(err)
}

return nil
Copy link
Contributor

Choose a reason for hiding this comment

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

Suggested change
if err != nil {
return trace.Wrap(err)
}
return nil
return trace.Wrap(err)

Comment on lines 192 to 199
// AppendKubeResource appends kube resource segment to the URI.
// Modeled after how access request constructs the resource ID:
// <teleport-cluster-name>/<subresource kind>/<kube_cluster name>/<subresource name>
func (r ResourceURI) AppendKubeResource(kubeResourceKind string, kubeClusterName string, kubeResourceName string) ResourceURI {
r.path = fmt.Sprintf("%v/%v/%v/%v", r.path, kubeResourceKind, kubeClusterName, kubeResourceName)
return r
}

Copy link
Contributor

Choose a reason for hiding this comment

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

Yeah, URIs are used for identifying resources.

fmt.Sprintf("%v/%v/%v/%v", r.path, kubeResourceKind, kubeClusterName, kubeResourceName)

I see some problems with this scheme. kubeResourceKind is an unknown string, so in theory, it could collide with other URIs. Additionally, we would not be able to identify if a given URI string is a kube resource URI without knowing kubeResourceKind.
A fix for this would be adding a known prefix in the URI, e.g:

"/clusters/teleport.sh/kube-resources/namespace/kube-cluster-name/namespace-name"

However, perhaps it would make more sense to treat a kube resource as a child of the kube cluster? I mean something like this:

var pathKubes = urlpath.New("/clusters/:cluster/kubes/:kubeName")
var pathKubeResources = urlpath.New("/clusters/:cluster/kubes/:kubeName/:subResourceKind/:subResourceName")

cc @ravicious

web/packages/teleterm/src/ui/uri.ts Outdated Show resolved Hide resolved
Comment on lines 192 to 199
// AppendKubeResource appends kube resource segment to the URI.
// Modeled after how access request constructs the resource ID:
// <teleport-cluster-name>/<subresource kind>/<kube_cluster name>/<subresource name>
func (r ResourceURI) AppendKubeResource(kubeResourceKind string, kubeClusterName string, kubeResourceName string) ResourceURI {
r.path = fmt.Sprintf("%v/%v/%v/%v", r.path, kubeResourceKind, kubeClusterName, kubeResourceName)
return r
}

Copy link
Member

Choose a reason for hiding this comment

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

If it's correct that kube subresources always belong to a specific kube resource, and I believe it's correct, then I'd definitely go with the second option that Grzegorz proposed.

If we currently support only namespaces within the app, then for now I'd make a definition only for namespaces. That would be:

  kubeResourceNamespace:
    '/clusters/:rootClusterId/(leaves)?/:leafClusterId?/kubes/:kubeId/namespaces/:kubeNamespaceId',
  kubeResourceNamespaceLeaf:
    '/clusters/:rootClusterId/leaves/:leafClusterId/kubes/:kubeId/namespaces/:kubeNameSpaceId',

This follows the existing conventions that we have while introducing a new one. Nested identifiers are prefixed with "parent's" name, e.g. it's :kubeNamespaceId, not :namespaceId.

This is mostly due to how matchPath works and how we implemented parseUri. You give it a bunch of possible identifiers and then pluck out what you need. So if we end up having two URIs, I think we'd rather have two different fields prefixed with the parent name, rather than reusing the same field name for two different purposes.

I wouldn't bother with KubeResourceNamespaceParam for now. If we wanted to have better types around this, we should refactor how routing.parseUri works and all the helper functions like routing.parseServerUri.


On the Go side, AppendKubeResourceNamespace as you have it is fine, we'd only have to change the actual URI it generates.

}

message ListKubernetesResourcesResponse {
repeated KubeResource items = 1;
Copy link
Member

Choose a reason for hiding this comment

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

Should we call it resources perhaps? That's what ListUnifiedResources already does. I don't see any other RPC within this service that would use items as the field name.


message ListKubernetesResourcesResponse {
repeated KubeResource items = 1;
string start_key = 2;
Copy link
Member

Choose a reason for hiding this comment

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

This should probably be next_key, just to keep the convention started by unified resources.

"github.com/gravitational/teleport/lib/teleterm/clusters"
"github.com/gravitational/teleport/lib/web/ui"
Copy link
Member

Choose a reason for hiding this comment

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

I'd say let's avoid bringing lib/web into lib/teleterm. Grepping through lib/teleterm, it's not something that we do today.

If we need to reuse some functions between lib/web and lib/teleterm, I think a better option would to move them to a third package that can be used by both web and teleterm.

What do you think about creating lib/ui/labels.go and moving MakeUILabelsWithoutInternalPrefixes there? Then we could even drop UI from its name.

var proxyGRPCClient kubeproto.KubeServiceClient

err = clusters.AddMetadataToRetryableError(ctx, func() error {
proxyGRPCClient, err = tc.NewKubernetesServiceClient(ctx, cluster.Name)
Copy link
Member

Choose a reason for hiding this comment

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

Nit: We can put both calls under the same AddMetadataToRetryableError call, it results in the same behavior and it's slightly shorter.

Comment on lines 51 to 53
// note:
// this field will be blank if this resource "kind" is "namespace",
// refer to field "name" for the name of namespace
Copy link
Member

Choose a reason for hiding this comment

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

Suggested change
// note:
// this field will be blank if this resource "kind" is "namespace",
// refer to field "name" for the name of namespace
// note: this field will be blank if this resource "kind" is "namespace",
// refer to field "name" for the name of namespace

@kimlisa kimlisa force-pushed the lisa/teleterm-kube-resource-endpoint branch from 86815ca to 5ee774f Compare September 23, 2024 19:41
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
backport/branch/v16 no-changelog Indicates that a PR does not require a changelog entry size/md ui
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants