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

provide client-go of keda #494

Closed
iyacontrol opened this issue Dec 3, 2019 · 20 comments
Closed

provide client-go of keda #494

iyacontrol opened this issue Dec 3, 2019 · 20 comments
Assignees
Labels
docs:pending All issues where docs are pending addition/update feature All issues for new features that have been committed to
Milestone

Comments

@iyacontrol
Copy link
Contributor

In some case, we need to create keda crd object by client-go of keda.

@tomkerkhove
Copy link
Member

Interesting - Could you elaborate on your scenario please?

@iyacontrol
Copy link
Contributor Author

iyacontrol commented Dec 3, 2019

thanks @tomkerkhove

I think we should add the client-go repo under the kedacore organization.

For example, when we use k8s, only our k8s administrators will use yaml. We developed a management platform based on k8s client-go. Now we are ready to integrate keda, so we need keda crd's client-go.

or should i use operator manager?

@tomkerkhove
Copy link
Member

So you want to programatically create the ScaledObjects rather than via Kubernetes itself - Is that correct?

@iyacontrol
Copy link
Contributor Author

yes. hi @tomkerkhove do you have a good idea?

@tomkerkhove
Copy link
Member

This is an interesting scenario, although I don't have experience with it.

/cc @jeffhollan @ahmelsayed

@n3wscott
Copy link

This is extremely common. I interact with resources via the generated client-go versions about 50% of my time in Kubernetes.

@zach-dunton-sf
Copy link
Contributor

This thread interested me so I have been playing with it for the last couple of days. Is this what you are looking for? smartfrog-oss@a47710b

If so I could figure out how to turn it into a PR. Mostly it's adding the tags for clientgen to the CRD objects and then running some generation scripts. https://blog.openshift.com/kubernetes-deep-dive-code-generation-customresources/

@zroubalik
Copy link
Member

@zach-dunton-sf looking good on the first look. It should be part of the CI as well

@iyacontrol
Copy link
Contributor Author

iyacontrol commented Dec 13, 2019

Thanks @zach-dunton-sf

great! code generation is one of ways to create client-go of keda.

I researched for a few days. we can also achieve the goal in the following ways:

1:use the client of operator-sdk
docs

my code is :

import (
	"gitlab.ushareit.me/sgt/devops/hulk/src/models"
	"k8s.io/apimachinery/pkg/runtime"
	"github.com/kedacore/keda/pkg/apis"
	"sigs.k8s.io/controller-runtime/pkg/client"
	ctrl "sigs.k8s.io/controller-runtime"
)

var scheme = runtime.NewScheme()

func init() {
	apis.AddToScheme(scheme)
}

func NewEventHpaClusterClient(cluster models.Cluster) (client.Client, error) {
	cfg, err := NewConfig(cluster.Name, cluster.Address, cluster.Token)
	if err != nil {
		return nil, err
	}

	options := ctrl.Options{Scheme:scheme}

	c, err := client.New(cfg, client.Options{Scheme: options.Scheme})
	if err !=nil {
		return nil, err
	}
	return c,nil
}

2:use restClient of k8s to implement client-go of keda

my code is :

package v1alpha1

import (
	"time"

	"github.com/kedacore/keda/pkg/apis/keda/v1alpha1"
	"k8s.io/apimachinery/pkg/watch"
	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
	"k8s.io/apimachinery/pkg/runtime/schema"
	"k8s.io/apimachinery/pkg/runtime/serializer"
	"k8s.io/client-go/kubernetes/scheme"
	"k8s.io/client-go/rest"
)

type Interface interface {
	Watch(opts metav1.ListOptions) (watch.Interface, error)
	List(opts metav1.ListOptions) (*v1alpha1.ScaledObjectList, error)
	Get(name string, options metav1.GetOptions) (*v1alpha1.ScaledObject, error)
	Create(*v1alpha1.ScaledObject) (*v1alpha1.ScaledObject, error)
	Update(*v1alpha1.ScaledObject) (*v1alpha1.ScaledObject, error)
	Delete(name string, options *metav1.DeleteOptions) error
}

type Clientset struct {
	restClient rest.Interface
	ns     string
}

func (c *Clientset) Watch(opts metav1.ListOptions) (watch.Interface, error) {
	var timeout time.Duration
	if opts.TimeoutSeconds != nil {
		timeout = time.Duration(*opts.TimeoutSeconds) * time.Second
	}

	opts.Watch = true
	return c.restClient.
		Get().
		Namespace(c.ns).
		Resource("scaledobjects").
		VersionedParams(&opts, scheme.ParameterCodec).
		Timeout(timeout).
		Watch()
}

func (c *Clientset) List(opts metav1.ListOptions) (*v1alpha1.ScaledObjectList, error) {
	var timeout time.Duration
	if opts.TimeoutSeconds != nil {
		timeout = time.Duration(*opts.TimeoutSeconds) * time.Second
	}

	result := v1alpha1.ScaledObjectList{}
	err := c.restClient.
		Get().
		Namespace(c.ns).
		Resource("scaledobjects").
		VersionedParams(&opts, scheme.ParameterCodec).
		Timeout(timeout).
		Do().
		Into(&result)

	return &result, err
}


func (c *Clientset)  Get(name string, opts metav1.GetOptions) (*v1alpha1.ScaledObject, error) {
	result := v1alpha1.ScaledObject{}

	err := c.restClient.
		Get().
		Namespace(c.ns).
		Resource("scaledobjects").
		VersionedParams(&opts, scheme.ParameterCodec).
		Do().
		Into(&result)

	return &result, err
}
func (c *Clientset) Create(scaledObject *v1alpha1.ScaledObject) (*v1alpha1.ScaledObject, error) {
	result := v1alpha1.ScaledObject{}
	err := c.restClient.
		Post().
		Namespace(c.ns).
		Resource("scaledobjects").
		Body(scaledObject).
		Do().
		Into(&result)

	return &result, err
}

func (c *Clientset) Update(scaledObject *v1alpha1.ScaledObject) (*v1alpha1.ScaledObject, error) {
	result := v1alpha1.ScaledObject{}
	err := c.restClient.
		Put().
		Namespace(c.ns).
		Resource("scaledobjects").
		Name(scaledObject.Name).
		Body(scaledObject).
		Do().
		Into(&result)

	return &result, err
}

func (c *Clientset) Delete(name string, options *metav1.DeleteOptions) error{
	return c.restClient.
	    Delete().
		Namespace(c.ns).
		Resource("scaledobjects").
		Name(name).
		Body(options).
		Do().
		Error()
}

func (c *Clientset) ScaledObject(namespace string) Interface {
	return &Clientset{
		restClient: c.restClient,
		ns:         namespace,
	}
}

func NewForConfig(c *rest.Config) (*Clientset, error) {
	config := *c
	config.ContentConfig.GroupVersion = &schema.GroupVersion{Group: "keda.k8s.io", Version: "v1alpha1"}
	config.APIPath = "/apis"
	config.NegotiatedSerializer = serializer.DirectCodecFactory{CodecFactory: scheme.Codecs}
	config.UserAgent = rest.DefaultKubernetesUserAgent()

	client, err := rest.RESTClientFor(&config)
	if err != nil {
		return nil, err
	}

	return &Clientset{restClient:client}, nil
}

Which way do others think is better?i like client of operator-sdk and code generation .

//EDIT: used markdown to display code blocks properly (@zroubalik)

aslom added a commit to aslom/eventing-sources that referenced this issue Feb 3, 2020
Warning: this is *experimental* and may be changed in future. Should
not be used in production. This is mainly for discussion and evolving
scaling in Knative eventing.

The code is using Unstructured and also imported KEDA API - this is for
discussion which version should be used (right now only Unstructured is
fully implemented).
KEDA to provide client-go support discussion knative#494
kedacore/keda#494
@aslom
Copy link

aslom commented Mar 27, 2020

Are there any updated on official KEDA client-go?

@tomkerkhove
Copy link
Member

It is covered here https://keda.sh/faq/, but that's it.

Hope that helps?

@aslom
Copy link

aslom commented Apr 8, 2020

That is what I am using - it is very low level and I was hoping for something KEDA specific API

@jeffhollan
Copy link
Member

@aslom sounds like it makes sense to track a feature request to build a first-class client-go integration with KEDA. I assume a few pieces of functionality that would be expected:

  • Create Scaled Object
  • Get Scaled Objects by Name
  • Get Trigger Authentication by Name
  • Create Trigger Authentication
  • Get HPA Name by Deployment Name

Does this look like what you were expecting?

@jeffhollan jeffhollan added the enhancement New feature or request label Apr 13, 2020
@aslom
Copy link

aslom commented Apr 15, 2020

@jeffhollan that is exactly what I was thinking about. Today I create ScaledObject using unstructured.Unstructured and map[string]interface{} and then manually Get/Create using DynamicClientSet

@zroubalik
Copy link
Member

@aslom if you use controller-runtime client, you don't have to mess with Unstructured, it's pretty straightforward. But I'll take a look, whether we can do something about it.

@zroubalik zroubalik self-assigned this Apr 17, 2020
@zroubalik zroubalik added this to the v2.0 milestone Apr 28, 2020
@zroubalik
Copy link
Member

@aslom we will expose KEDA client-go in our v2 release se #787

@zroubalik
Copy link
Member

Fixed in #787

@tomkerkhove
Copy link
Member

Can we get some docs on this?

@tomkerkhove tomkerkhove reopened this Aug 17, 2020
@tomkerkhove tomkerkhove added docs:pending All issues where docs are pending addition/update and removed enhancement New feature or request labels Aug 17, 2020
@tomkerkhove tomkerkhove added the feature All issues for new features that have been committed to label Aug 17, 2020
@zroubalik
Copy link
Member

I am not sure what exactly we should document here? It is a kubernetes Go client https://github.com/kubernetes/client-go/

@tomkerkhove
Copy link
Member

Might be my Go ignorance here as I thought the go client had to be pulled in and document what it enables but it's ok then.

preflightsiren pushed a commit to preflightsiren/keda that referenced this issue Nov 7, 2021
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
docs:pending All issues where docs are pending addition/update feature All issues for new features that have been committed to
Projects
None yet
Development

No branches or pull requests

7 participants