In some case, we need to create keda crd object by client-go of keda.
Interesting - Could you elaborate on your scenario please?
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?
So you want to programatically create the ScaledObjects rather than via Kubernetes itself - Is that correct?
yes. hi @tomkerkhove do you have a good idea?
This is an interesting scenario, although I don't have experience with it.
/cc @jeffhollan @ahmelsayed
This is extremely common. I interact with resources via the generated client-go versions about 50% of my time in Kubernetes.
This thread interested me so I have been playing with it for the last couple of days. Is this what you are looking for? https://github.com/smartfrog-oss/keda/commit/a47710bd98ece9e32b4a34fef3622a60c2f3f9d4
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/
@zach-dunton-sf looking good on the first look. It should be part of the CI as well
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)
Are there any updated on official KEDA client-go?
It is covered here https://keda.sh/faq/, but that's it.
Hope that helps?
That is what I am using - it is very low level and I was hoping for something KEDA specific API
@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:
Does this look like what you were expecting?
@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
@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.
@aslom we will expose KEDA client-go in our v2 release se #787
Fixed in #787
Can we get some docs on this?
I am not sure what exactly we should document here? It is a kubernetes Go client https://github.com/kubernetes/client-go/
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.
Most helpful comment
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.