kubernetes / client-go

Go client for Kubernetes.
Apache License 2.0
8.78k stars 2.9k forks source link

Examples Wanted: Using RESTClient to Operate CRD. #1308

Closed Electronic-Waste closed 3 months ago

Electronic-Waste commented 8 months ago

As is shown in k8s official doc, we can't access a CRD with clientset generated by client-go library.

So I decided to fetch my CRD by RESTClient.

I spent a lot of hours working it out, finding that there are so limited examples on Internet that developers often get confused about various error messages produced by their code, for example no kind "xxx" is registered for the internal version of group "xxx" in scheme "pkg/runtime/scheme.go:100" in #193 .

I also encountered with this problem. My former code:

Some code in package sdnv1:

type Route struct {...}

type RouteList struct {...}

var (
    // GroupVersion is group version used to register these objects
    GroupVersion = schema.GroupVersion{Group: "xxx", Version: "v1"}

    // SchemeBuilder is used to add go types to the GroupVersionKind scheme
    SchemeBuilder = &scheme.Builder{GroupVersion: GroupVersion}

    // AddToScheme adds the types in this group-version to the given scheme.
    AddToScheme = SchemeBuilder.AddToScheme
)

func init() {
    SchemeBuilder.Register(&Route{}, &RouteList{})
}

In /pkg/util/client.go

import (
    "flag"
    "fmt"
    "path/filepath"
    "strings"

    "k8s.io/client-go/kubernetes/scheme"
    "k8s.io/client-go/rest"
    "k8s.io/client-go/tools/clientcmd"
    "k8s.io/client-go/util/homedir"

    sdnv1 "xx/xxxxx/api/v1"   // I define my CRD type in this package
)

var (
    kubeconfig *string = nil
    routeclient *rest.RESTClient = nil
)

func init() {
    if home := homedir.HomeDir(); home != "" {
        kubeconfig = flag.String("kubeconfig", filepath.Join(home, ".kube", "config"), "(optional) absolute path to the kubeconfig file")
    } else {
        kubeconfig = flag.String("kubeconfig", "", "absolute path to the kubeconfig file")
    }
    flag.Parse()

    sdnv1.AddToScheme(scheme.Scheme)
}

func GetRouteClient() (*rest.RESTClient, error){
    // If RouteClient is not empty, return RouteClient
    if routeclient != nil {
        return routeclient, nil
    }
    // use the current context in kubeconfig
    config, err := clientcmd.BuildConfigFromFlags("", *kubeconfig)
    if err != nil {
        return nil, fmt.Errorf("CONFIG ERROR: %v", err)
    }

    config.APIPath = "/apis"
    config.ContentConfig.GroupVersion = &sdnv1.GroupVersion
    config.NegotiatedSerializer = scheme.Codecs
    config.UserAgent = rest.DefaultKubernetesUserAgent()

    routeclient, err = rest.RESTClientFor(config)
    return routeclient, err
}

When I use this RESTClient to create CRD:

restClient, err := util.GetRouteClient()
if err != nil {
    return fmt.Errorf("CONFIG ERROR: %v", err)
}

...

err := restClient.Post().
    Namespace(namespace).
    Resource("routes").
    Body(&route).
    Do(context.TODO()).
    into(nil)
if err != nil {
    return fmt.Errorf("APPLY ROUTE FAILURE: %v", err)
}

The error no kind "xxx" is registered for the internal version of group "xxx" in scheme "pkg/runtime/scheme.go:100" occurred.

But after I changed /pkg/util/client.go

config.NegotiatedSerializer = scheme.Codecs

to

config.NegotiatedSerializer = scheme.Codecs.WithoutConversion()

The program runs correctly.

I don't know why this program can run correctly, but I think more developers can prevent themselves from getting confused by such bugs if there were more examples.

Electronic-Waste commented 8 months ago

Also, the code above provides a example for operating CRDs with RESTClient

k8s-triage-robot commented 5 months ago

The Kubernetes project currently lacks enough contributors to adequately respond to all issues.

This bot triages un-triaged issues according to the following rules:

You can:

Please send feedback to sig-contributor-experience at kubernetes/community.

/lifecycle stale

k8s-triage-robot commented 4 months ago

The Kubernetes project currently lacks enough active contributors to adequately respond to all issues.

This bot triages un-triaged issues according to the following rules:

You can:

Please send feedback to sig-contributor-experience at kubernetes/community.

/lifecycle rotten

k8s-triage-robot commented 3 months ago

The Kubernetes project currently lacks enough active contributors to adequately respond to all issues and PRs.

This bot triages issues according to the following rules:

You can:

Please send feedback to sig-contributor-experience at kubernetes/community.

/close not-planned

k8s-ci-robot commented 3 months ago

@k8s-triage-robot: Closing this issue, marking it as "Not Planned".

In response to [this](https://github.com/kubernetes/client-go/issues/1308#issuecomment-2028443617): >The Kubernetes project currently lacks enough active contributors to adequately respond to all issues and PRs. > >This bot triages issues according to the following rules: >- After 90d of inactivity, `lifecycle/stale` is applied >- After 30d of inactivity since `lifecycle/stale` was applied, `lifecycle/rotten` is applied >- After 30d of inactivity since `lifecycle/rotten` was applied, the issue is closed > >You can: >- Reopen this issue with `/reopen` >- Mark this issue as fresh with `/remove-lifecycle rotten` >- Offer to help out with [Issue Triage][1] > >Please send feedback to sig-contributor-experience at [kubernetes/community](https://github.com/kubernetes/community). > >/close not-planned > >[1]: https://www.kubernetes.dev/docs/guide/issue-triage/ Instructions for interacting with me using PR comments are available [here](https://git.k8s.io/community/contributors/guide/pull-requests.md). If you have questions or suggestions related to my behavior, please file an issue against the [kubernetes/test-infra](https://github.com/kubernetes/test-infra/issues/new?title=Prow%20issue:) repository.
nmindz commented 2 weeks ago

@Electronic-Waste Thank you for this. You were the only drop of sanity that actually showed a way out of the completely non-intuitive way how things have been implemented (and not documented) on how to operate with RESTClient on CRDs.

This was exactly what I needed. And while bashing my head against what (would seem to be a sensible working implementation) would return me the most generic and unhelpful forbidden: User "system:serviceaccount:xxx:yyy" cannot patch path "zzz" (despite the fact the ServiceAccount/CRB had full privileges).

nmindz commented 2 weeks ago

/remove-lifecycle rotten

nmindz commented 2 weeks ago

/reopen

k8s-ci-robot commented 2 weeks ago

@nmindz: You can't reopen an issue/PR unless you authored it or you are a collaborator.

In response to [this](https://github.com/kubernetes/client-go/issues/1308#issuecomment-2181840194): >/reopen Instructions for interacting with me using PR comments are available [here](https://git.k8s.io/community/contributors/guide/pull-requests.md). If you have questions or suggestions related to my behavior, please file an issue against the [kubernetes-sigs/prow](https://github.com/kubernetes-sigs/prow/issues/new?title=Prow%20issue:) repository.