160 lines
6.0 KiB
Go
160 lines
6.0 KiB
Go
/*
|
|
Copyright 2023 The Kubernetes Authors.
|
|
|
|
Licensed under the Apache License, Version 2.0 (the "License");
|
|
you may not use this file except in compliance with the License.
|
|
You may obtain a copy of the License at
|
|
|
|
http://www.apache.org/licenses/LICENSE-2.0
|
|
|
|
Unless required by applicable law or agreed to in writing, software
|
|
distributed under the License is distributed on an "AS IS" BASIS,
|
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
See the License for the specific language governing permissions and
|
|
limitations under the License.
|
|
*/
|
|
|
|
package provreqclient
|
|
|
|
import (
|
|
"fmt"
|
|
"time"
|
|
|
|
apiv1 "k8s.io/api/core/v1"
|
|
"k8s.io/apimachinery/pkg/api/errors"
|
|
|
|
"k8s.io/apimachinery/pkg/labels"
|
|
"k8s.io/autoscaler/cluster-autoscaler/provisioningrequest/apis/autoscaling.x-k8s.io/v1beta1"
|
|
"k8s.io/autoscaler/cluster-autoscaler/provisioningrequest/client/clientset/versioned"
|
|
"k8s.io/autoscaler/cluster-autoscaler/provisioningrequest/client/informers/externalversions"
|
|
listers "k8s.io/autoscaler/cluster-autoscaler/provisioningrequest/client/listers/autoscaling.x-k8s.io/v1beta1"
|
|
"k8s.io/autoscaler/cluster-autoscaler/provisioningrequest/provreqwrapper"
|
|
"k8s.io/client-go/informers"
|
|
"k8s.io/client-go/kubernetes"
|
|
v1 "k8s.io/client-go/listers/core/v1"
|
|
"k8s.io/client-go/rest"
|
|
|
|
klog "k8s.io/klog/v2"
|
|
)
|
|
|
|
const (
|
|
provisioningRequestClientCallTimeout = 4 * time.Second
|
|
)
|
|
|
|
// ProvisioningRequestClientV1beta1 represents client for v1beta1 ProvReq CRD.
|
|
type ProvisioningRequestClientV1beta1 struct {
|
|
client versioned.Interface
|
|
provReqLister listers.ProvisioningRequestLister
|
|
podTemplLister v1.PodTemplateLister
|
|
}
|
|
|
|
// NewProvisioningRequestClient configures and returns a provisioningRequestClient.
|
|
func NewProvisioningRequestClient(kubeConfig *rest.Config) (*ProvisioningRequestClientV1beta1, error) {
|
|
prClient, err := newPRClient(kubeConfig)
|
|
if err != nil {
|
|
return nil, fmt.Errorf("Failed to create Provisioning Request client: %v", err)
|
|
}
|
|
|
|
provReqLister, err := newPRsLister(prClient, make(chan struct{}))
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
podTemplateClient, err := kubernetes.NewForConfig(kubeConfig)
|
|
if err != nil {
|
|
return nil, fmt.Errorf("Failed to create Pod Template client: %v", err)
|
|
}
|
|
|
|
podTemplLister, err := newPodTemplatesLister(podTemplateClient, make(chan struct{}))
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
return &ProvisioningRequestClientV1beta1{
|
|
client: prClient,
|
|
provReqLister: provReqLister,
|
|
podTemplLister: podTemplLister,
|
|
}, nil
|
|
}
|
|
|
|
// ProvisioningRequest gets a specific ProvisioningRequest CR.
|
|
func (c *ProvisioningRequestClientV1beta1) ProvisioningRequest(namespace, name string) (*provreqwrapper.ProvisioningRequest, error) {
|
|
v1Beta1PR, err := c.provReqLister.ProvisioningRequests(namespace).Get(name)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
podTemplates, err := c.FetchPodTemplates(v1Beta1PR)
|
|
if err != nil {
|
|
return nil, fmt.Errorf("while fetching pod templates for Get Provisioning Request %s/%s got error: %v", namespace, name, err)
|
|
}
|
|
return provreqwrapper.NewV1Beta1ProvisioningRequest(v1Beta1PR, podTemplates), nil
|
|
}
|
|
|
|
// ProvisioningRequests gets all ProvisioningRequest CRs.
|
|
func (c *ProvisioningRequestClientV1beta1) ProvisioningRequests() ([]*provreqwrapper.ProvisioningRequest, error) {
|
|
v1Beta1PRs, err := c.provReqLister.List(labels.Everything())
|
|
if err != nil {
|
|
return nil, fmt.Errorf("error fetching provisioningRequests: %w", err)
|
|
}
|
|
prs := make([]*provreqwrapper.ProvisioningRequest, 0, len(v1Beta1PRs))
|
|
for _, v1Beta1PR := range v1Beta1PRs {
|
|
podTemplates, errPodTemplates := c.FetchPodTemplates(v1Beta1PR)
|
|
if errPodTemplates != nil {
|
|
return nil, fmt.Errorf("while fetching pod templates for List Provisioning Request %s/%s got error: %v", v1Beta1PR.Namespace, v1Beta1PR.Name, errPodTemplates)
|
|
}
|
|
prs = append(prs, provreqwrapper.NewV1Beta1ProvisioningRequest(v1Beta1PR, podTemplates))
|
|
}
|
|
return prs, nil
|
|
}
|
|
|
|
// FetchPodTemplates fetches PodTemplates referenced by the Provisioning Request.
|
|
func (c *ProvisioningRequestClientV1beta1) FetchPodTemplates(pr *v1beta1.ProvisioningRequest) ([]*apiv1.PodTemplate, error) {
|
|
podTemplates := make([]*apiv1.PodTemplate, 0, len(pr.Spec.PodSets))
|
|
for _, podSpec := range pr.Spec.PodSets {
|
|
podTemplate, err := c.podTemplLister.PodTemplates(pr.Namespace).Get(podSpec.PodTemplateRef.Name)
|
|
if errors.IsNotFound(err) {
|
|
klog.Infof("While fetching Pod Template for Provisioning Request %s/%s received not found error", pr.Namespace, pr.Name)
|
|
continue
|
|
} else if err != nil {
|
|
return nil, err
|
|
}
|
|
podTemplates = append(podTemplates, podTemplate)
|
|
}
|
|
return podTemplates, nil
|
|
}
|
|
|
|
// newPRClient creates a new Provisioning Request client from the given config.
|
|
func newPRClient(kubeConfig *rest.Config) (*versioned.Clientset, error) {
|
|
return versioned.NewForConfig(kubeConfig)
|
|
}
|
|
|
|
// newPRsLister creates a lister for the Provisioning Requests in the cluster.
|
|
func newPRsLister(prClient versioned.Interface, stopChannel <-chan struct{}) (listers.ProvisioningRequestLister, error) {
|
|
factory := externalversions.NewSharedInformerFactory(prClient, 1*time.Hour)
|
|
provReqLister := factory.Autoscaling().V1beta1().ProvisioningRequests().Lister()
|
|
factory.Start(stopChannel)
|
|
informersSynced := factory.WaitForCacheSync(stopChannel)
|
|
for _, synced := range informersSynced {
|
|
if !synced {
|
|
return nil, fmt.Errorf("can't create Provisioning Request lister")
|
|
}
|
|
}
|
|
klog.V(2).Info("Successful initial Provisioning Request sync")
|
|
return provReqLister, nil
|
|
}
|
|
|
|
// newPodTemplatesLister creates a lister for the Pod Templates in the cluster.
|
|
func newPodTemplatesLister(client *kubernetes.Clientset, stopChannel <-chan struct{}) (v1.PodTemplateLister, error) {
|
|
factory := informers.NewSharedInformerFactory(client, 1*time.Hour)
|
|
podTemplLister := factory.Core().V1().PodTemplates().Lister()
|
|
factory.Start(stopChannel)
|
|
informersSynced := factory.WaitForCacheSync(stopChannel)
|
|
for _, synced := range informersSynced {
|
|
if !synced {
|
|
return nil, fmt.Errorf("can't create Pod Template lister")
|
|
}
|
|
}
|
|
klog.V(2).Info("Successful initial Pod Template sync")
|
|
return podTemplLister, nil
|
|
}
|