1
0
mirror of https://github.com/rancher/steve.git synced 2025-04-28 03:10:32 +00:00
steve/pkg/client/factory.go
Ricardo Weir 23ae2d3abc Revert client change
Prior, table client configs were mistakenly swapped out for regular
client configs. This caused requests using these methods to no
longer return table column data under metadata.fields. Consequently,
table data was blank in the dashboard UI. Now, the client config
swap has been reverted and table fields should be populated in the
dashboard UI.
2023-02-13 16:36:43 -07:00

195 lines
6.4 KiB
Go

package client
import (
"fmt"
"net/http"
"time"
"github.com/rancher/apiserver/pkg/types"
"github.com/rancher/steve/pkg/attributes"
"k8s.io/apiserver/pkg/endpoints/request"
"k8s.io/client-go/dynamic"
"k8s.io/client-go/kubernetes"
"k8s.io/client-go/metadata"
"k8s.io/client-go/rest"
)
type Factory struct {
impersonate bool
tableClientCfg *rest.Config
tableWatchClientCfg *rest.Config
clientCfg *rest.Config
watchClientCfg *rest.Config
metadata metadata.Interface
dynamic dynamic.Interface
Config *rest.Config
}
type addQuery struct {
values map[string]string
next http.RoundTripper
}
func (a *addQuery) RoundTrip(req *http.Request) (*http.Response, error) {
q := req.URL.Query()
for k, v := range a.values {
q.Set(k, v)
}
req.Header.Set("Accept", "application/json;as=Table;v=v1;g=meta.k8s.io,application/json;as=Table;v=v1beta1;g=meta.k8s.io")
req.URL.RawQuery = q.Encode()
return a.next.RoundTrip(req)
}
func NewFactory(cfg *rest.Config, impersonate bool) (*Factory, error) {
clientCfg := rest.CopyConfig(cfg)
clientCfg.QPS = 10000
clientCfg.Burst = 100
watchClientCfg := rest.CopyConfig(clientCfg)
watchClientCfg.Timeout = 30 * time.Minute
setTable := func(rt http.RoundTripper) http.RoundTripper {
return &addQuery{
values: map[string]string{
"includeObject": "Object",
},
next: rt,
}
}
tableClientCfg := rest.CopyConfig(clientCfg)
tableClientCfg.Wrap(setTable)
tableClientCfg.AcceptContentTypes = "application/json;as=Table;v=v1;g=meta.k8s.io,application/json;as=Table;v=v1beta1;g=meta.k8s.io"
tableWatchClientCfg := rest.CopyConfig(watchClientCfg)
tableWatchClientCfg.Wrap(setTable)
tableWatchClientCfg.AcceptContentTypes = "application/json;as=Table;v=v1;g=meta.k8s.io,application/json;as=Table;v=v1beta1;g=meta.k8s.io"
md, err := metadata.NewForConfig(cfg)
if err != nil {
return nil, err
}
d, err := dynamic.NewForConfig(cfg)
if err != nil {
return nil, err
}
return &Factory{
dynamic: d,
metadata: md,
impersonate: impersonate,
tableClientCfg: tableClientCfg,
tableWatchClientCfg: tableWatchClientCfg,
clientCfg: clientCfg,
watchClientCfg: watchClientCfg,
Config: watchClientCfg,
}, nil
}
func (p *Factory) MetadataClient() metadata.Interface {
return p.metadata
}
func (p *Factory) AdminDynamicClient() dynamic.Interface {
return p.dynamic
}
func (p *Factory) IsImpersonating() bool {
return p.impersonate
}
func (p *Factory) K8sInterface(ctx *types.APIRequest) (kubernetes.Interface, error) {
cfg, err := setupConfig(ctx, p.clientCfg, p.impersonate)
if err != nil {
return nil, err
}
return kubernetes.NewForConfig(cfg)
}
func (p *Factory) AdminK8sInterface() (kubernetes.Interface, error) {
return kubernetes.NewForConfig(p.clientCfg)
}
func (p *Factory) DynamicClient(ctx *types.APIRequest, warningHandler rest.WarningHandler) (dynamic.Interface, error) {
return newDynamicClient(ctx, p.clientCfg, p.impersonate, warningHandler)
}
func (p *Factory) Client(ctx *types.APIRequest, s *types.APISchema, namespace string, warningHandler rest.WarningHandler) (dynamic.ResourceInterface, error) {
return newClient(ctx, p.clientCfg, s, namespace, p.impersonate, warningHandler)
}
func (p *Factory) AdminClient(ctx *types.APIRequest, s *types.APISchema, namespace string, warningHandler rest.WarningHandler) (dynamic.ResourceInterface, error) {
return newClient(ctx, p.clientCfg, s, namespace, false, warningHandler)
}
func (p *Factory) ClientForWatch(ctx *types.APIRequest, s *types.APISchema, namespace string, warningHandler rest.WarningHandler) (dynamic.ResourceInterface, error) {
return newClient(ctx, p.watchClientCfg, s, namespace, p.impersonate, warningHandler)
}
func (p *Factory) AdminClientForWatch(ctx *types.APIRequest, s *types.APISchema, namespace string, warningHandler rest.WarningHandler) (dynamic.ResourceInterface, error) {
return newClient(ctx, p.watchClientCfg, s, namespace, false, warningHandler)
}
func (p *Factory) TableClient(ctx *types.APIRequest, s *types.APISchema, namespace string, warningHandler rest.WarningHandler) (dynamic.ResourceInterface, error) {
if attributes.Table(s) {
return newClient(ctx, p.tableClientCfg, s, namespace, p.impersonate, warningHandler)
}
return p.Client(ctx, s, namespace, warningHandler)
}
func (p *Factory) TableAdminClient(ctx *types.APIRequest, s *types.APISchema, namespace string, warningHandler rest.WarningHandler) (dynamic.ResourceInterface, error) {
if attributes.Table(s) {
return newClient(ctx, p.tableClientCfg, s, namespace, false, warningHandler)
}
return p.AdminClient(ctx, s, namespace, warningHandler)
}
func (p *Factory) TableClientForWatch(ctx *types.APIRequest, s *types.APISchema, namespace string, warningHandler rest.WarningHandler) (dynamic.ResourceInterface, error) {
if attributes.Table(s) {
return newClient(ctx, p.tableWatchClientCfg, s, namespace, p.impersonate, warningHandler)
}
return p.ClientForWatch(ctx, s, namespace, warningHandler)
}
func (p *Factory) TableAdminClientForWatch(ctx *types.APIRequest, s *types.APISchema, namespace string, warningHandler rest.WarningHandler) (dynamic.ResourceInterface, error) {
if attributes.Table(s) {
return newClient(ctx, p.tableWatchClientCfg, s, namespace, false, warningHandler)
}
return p.AdminClientForWatch(ctx, s, namespace, warningHandler)
}
func setupConfig(ctx *types.APIRequest, cfg *rest.Config, impersonate bool) (*rest.Config, error) {
if impersonate {
user, ok := request.UserFrom(ctx.Context())
if !ok {
return nil, fmt.Errorf("user not found for impersonation")
}
cfg = rest.CopyConfig(cfg)
cfg.Impersonate.UserName = user.GetName()
cfg.Impersonate.Groups = user.GetGroups()
cfg.Impersonate.Extra = user.GetExtra()
}
return cfg, nil
}
func newDynamicClient(ctx *types.APIRequest, cfg *rest.Config, impersonate bool, warningHandler rest.WarningHandler) (dynamic.Interface, error) {
cfg, err := setupConfig(ctx, cfg, impersonate)
cfg.WarningHandler = warningHandler
if err != nil {
return nil, err
}
return dynamic.NewForConfig(cfg)
}
func newClient(ctx *types.APIRequest, cfg *rest.Config, s *types.APISchema, namespace string, impersonate bool, warningHandler rest.WarningHandler) (dynamic.ResourceInterface, error) {
client, err := newDynamicClient(ctx, cfg, impersonate, warningHandler)
if err != nil {
return nil, err
}
gvr := attributes.GVR(s)
return client.Resource(gvr).Namespace(namespace), nil
}