armada-operator/pkg/kube/client.go
Ruslan Aliev 16b2953b21 Improve logic of pre update objects deletion
Details:
 * delete propagation policy set to foreground
 * added verification of resources deletion
 * go version update 1.20 => 1.21
 * k8s version update 1.28 => 1.29

Change-Id: I63e0b94bf6635768c12f114caa6445ab479e5254
Signed-off-by: Ruslan Aliev <raliev@mirantis.com>
2024-03-07 02:10:59 -06:00

223 lines
6.6 KiB
Go

/*
Copyright 2023.
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 kube
import (
"fmt"
"sync"
"k8s.io/apimachinery/pkg/api/meta"
"k8s.io/client-go/discovery"
"k8s.io/client-go/discovery/cached/memory"
"k8s.io/client-go/rest"
"k8s.io/client-go/restmapper"
"k8s.io/client-go/tools/clientcmd"
ctrl "sigs.k8s.io/controller-runtime"
)
// Option is a function that configures an MemoryRESTClientGetter.
type Option func(*MemoryRESTClientGetter)
// WithNamespace sets the namespace to use for the client.
func WithNamespace(namespace string) Option {
return func(c *MemoryRESTClientGetter) {
c.namespace = namespace
}
}
// WithPersistent sets whether the client should persist the underlying client
// config, REST mapper, and discovery client.
func WithPersistent(persist bool) Option {
return func(c *MemoryRESTClientGetter) {
c.persistent = persist
}
}
// WithWarningHandler sets warning handler fn for REST mapper
func WithWarningHandler(wh func(string)) Option {
return func(c *MemoryRESTClientGetter) {
c.warningHandler = wh
}
}
// MemoryRESTClientGetter is a resource.RESTClientGetter that uses an
// in-memory REST config, REST mapper, and discovery client.
// If configured, the client config, REST mapper, and discovery client are
// lazily initialized, and cached for subsequent calls.
type MemoryRESTClientGetter struct {
// namespace is the namespace to use for the client.
namespace string
// impersonate is the username to use for the client.
impersonate string
// persistent indicates whether the client should persist the restMapper,
// clientCfg, and discoveryClient. Rather than re-initializing them on
// every call, they will be cached and reused.
persistent bool
cfg *rest.Config
restMapper meta.RESTMapper
restMapperMu sync.Mutex
discoveryClient discovery.CachedDiscoveryInterface
discoveryMu sync.Mutex
clientCfg clientcmd.ClientConfig
clientCfgMu sync.Mutex
warningHandler func(string)
}
// setDefaults sets the default values for the MemoryRESTClientGetter.
func (c *MemoryRESTClientGetter) setDefaults() {
if c.namespace == "" {
c.namespace = "default"
}
}
// NewMemoryRESTClientGetter returns a new MemoryRESTClientGetter.
func NewMemoryRESTClientGetter(cfg *rest.Config, opts ...Option) *MemoryRESTClientGetter {
g := &MemoryRESTClientGetter{
cfg: cfg,
}
for _, opts := range opts {
opts(g)
}
g.setDefaults()
return g
}
// NewInClusterMemoryRESTClientGetter returns a new MemoryRESTClientGetter
// that uses the in-cluster REST config. It returns an error if the in-cluster
// REST config cannot be obtained.
func NewInClusterMemoryRESTClientGetter(opts ...Option) (*MemoryRESTClientGetter, error) {
cfg, err := ctrl.GetConfig()
if err != nil {
return nil, fmt.Errorf("failed to get config for in-cluster REST client: %w", err)
}
return NewMemoryRESTClientGetter(cfg, opts...), nil
}
// ToRESTConfig returns the in-memory REST config.
func (c *MemoryRESTClientGetter) ToRESTConfig() (*rest.Config, error) {
if c.cfg == nil {
return nil, fmt.Errorf("MemoryRESTClientGetter has no REST config")
}
return c.cfg, nil
}
// ToDiscoveryClient returns a memory cached discovery client. Calling it
// multiple times will return the same instance.
func (c *MemoryRESTClientGetter) ToDiscoveryClient() (discovery.CachedDiscoveryInterface, error) {
if c.persistent {
return c.toPersistentDiscoveryClient()
}
return c.toDiscoveryClient()
}
func (c *MemoryRESTClientGetter) toPersistentDiscoveryClient() (discovery.CachedDiscoveryInterface, error) {
c.discoveryMu.Lock()
defer c.discoveryMu.Unlock()
if c.discoveryClient == nil {
discoveryClient, err := c.toDiscoveryClient()
if err != nil {
return nil, err
}
c.discoveryClient = discoveryClient
}
return c.discoveryClient, nil
}
func (c *MemoryRESTClientGetter) toDiscoveryClient() (discovery.CachedDiscoveryInterface, error) {
config, err := c.ToRESTConfig()
if err != nil {
return nil, err
}
discoveryClient, err := discovery.NewDiscoveryClientForConfig(config)
if err != nil {
return nil, err
}
return memory.NewMemCacheClient(discoveryClient), nil
}
// ToRESTMapper returns a meta.RESTMapper using the discovery client. Calling
// it multiple times will return the same instance.
func (c *MemoryRESTClientGetter) ToRESTMapper() (meta.RESTMapper, error) {
if c.persistent {
return c.toPersistentRESTMapper()
}
return c.toRESTMapper()
}
func (c *MemoryRESTClientGetter) toPersistentRESTMapper() (meta.RESTMapper, error) {
c.restMapperMu.Lock()
defer c.restMapperMu.Unlock()
if c.restMapper == nil {
restMapper, err := c.toRESTMapper()
if err != nil {
return nil, err
}
c.restMapper = restMapper
}
return c.restMapper, nil
}
func (c *MemoryRESTClientGetter) toRESTMapper() (meta.RESTMapper, error) {
discoveryClient, err := c.ToDiscoveryClient()
if err != nil {
return nil, err
}
mapper := restmapper.NewDeferredDiscoveryRESTMapper(discoveryClient)
return restmapper.NewShortcutExpander(mapper, discoveryClient, c.warningHandler), nil
}
// ToRawKubeConfigLoader returns a clientcmd.ClientConfig using
// clientcmd.DefaultClientConfig. With clientcmd.ClusterDefaults, namespace, and
// impersonate configured as overwrites.
func (c *MemoryRESTClientGetter) ToRawKubeConfigLoader() clientcmd.ClientConfig {
if c.persistent {
return c.toPersistentRawKubeConfigLoader()
}
return c.toRawKubeConfigLoader()
}
func (c *MemoryRESTClientGetter) toPersistentRawKubeConfigLoader() clientcmd.ClientConfig {
c.clientCfgMu.Lock()
defer c.clientCfgMu.Unlock()
if c.clientCfg == nil {
c.clientCfg = c.toRawKubeConfigLoader()
}
return c.clientCfg
}
func (c *MemoryRESTClientGetter) toRawKubeConfigLoader() clientcmd.ClientConfig {
loadingRules := clientcmd.NewDefaultClientConfigLoadingRules()
// use the standard defaults for this client command
// DEPRECATED: remove and replace with something more accurate
loadingRules.DefaultClientConfig = &clientcmd.DefaultClientConfig
overrides := &clientcmd.ConfigOverrides{ClusterDefaults: clientcmd.ClusterDefaults}
overrides.Context.Namespace = c.namespace
overrides.AuthInfo.Impersonate = c.impersonate
return clientcmd.NewNonInteractiveDeferredLoadingClientConfig(loadingRules, overrides)
}