mirror of
https://github.com/portainer/portainer.git
synced 2026-06-23 04:40:13 +00:00
feat(kubernetes): Gateway api client included in kubeclient [C9S-244] (#2884)
This commit is contained in:
@@ -18,7 +18,7 @@ import (
|
||||
func (service *service) upgradeKubernetes(environment *portainer.Endpoint, licenseKey, version string) error {
|
||||
ctx := context.TODO()
|
||||
|
||||
kubeCLI, err := service.kubernetesClientFactory.CreateClient(environment)
|
||||
kubeCLI, _, err := service.kubernetesClientFactory.CreateClient(environment)
|
||||
if err != nil {
|
||||
return errors.WithMessage(err, "failed to get kubernetes client")
|
||||
}
|
||||
|
||||
@@ -20,6 +20,7 @@ import (
|
||||
"k8s.io/client-go/rest"
|
||||
"k8s.io/client-go/tools/clientcmd"
|
||||
metricsv "k8s.io/metrics/pkg/client/clientset/versioned"
|
||||
gatewaycliv1 "sigs.k8s.io/gateway-api/pkg/client/clientset/versioned/typed/apis/v1"
|
||||
)
|
||||
|
||||
const (
|
||||
@@ -42,6 +43,7 @@ type (
|
||||
// KubeClient represent a service used to execute Kubernetes operations
|
||||
KubeClient struct {
|
||||
cli kubernetes.Interface
|
||||
gatewayCLI gatewaycliv1.GatewayV1Interface
|
||||
instanceID string
|
||||
mu sync.Mutex
|
||||
isKubeAdmin bool
|
||||
@@ -105,8 +107,10 @@ func (factory *ClientFactory) GetAddrHTTPS() string {
|
||||
return factory.AddrHTTPS
|
||||
}
|
||||
|
||||
// GetPrivilegedKubeClient checks if an existing client is already registered for the environment(endpoint) and returns it if one is found.
|
||||
// If no client is registered, it will create a new client, register it, and returns it.
|
||||
// GetPrivilegedKubeClient checks if an existing client is already registered
|
||||
// for the environment(endpoint) and returns it if one is found.
|
||||
//
|
||||
// If no client is registered, it will create a new client, register it, and return it.
|
||||
func (factory *ClientFactory) GetPrivilegedKubeClient(endpoint *portainer.Endpoint) (*KubeClient, error) {
|
||||
key := strconv.Itoa(int(endpoint.ID))
|
||||
pcl, ok := factory.endpointProxyClients.Get(key)
|
||||
@@ -123,8 +127,11 @@ func (factory *ClientFactory) GetPrivilegedKubeClient(endpoint *portainer.Endpoi
|
||||
return kcl, nil
|
||||
}
|
||||
|
||||
// GetPrivilegedUserKubeClient checks if an existing admin client is already registered for the environment(endpoint) and user and returns it if one is found.
|
||||
// If no client is registered, it will create a new client, register it, and returns it.
|
||||
// GetPrivilegedUserKubeClient checks if an existing admin client is already
|
||||
// registered for the environment(endpoint) and user and returns it if one is
|
||||
// found.
|
||||
//
|
||||
// If no client is registered, it will create a new client, register it, and return it.
|
||||
func (factory *ClientFactory) GetPrivilegedUserKubeClient(endpoint *portainer.Endpoint, userID portainer.UserID) (*KubeClient, error) {
|
||||
key := strconv.Itoa(int(endpoint.ID)) + ".admin." + strconv.Itoa(int(userID))
|
||||
pcl, ok := factory.endpointProxyClients.Get(key)
|
||||
@@ -174,13 +181,24 @@ func (factory *ClientFactory) CreateKubeClientFromKubeConfig(clusterID string, k
|
||||
clientConfig.QPS = defaultKubeClientQPS
|
||||
clientConfig.Burst = defaultKubeClientBurst
|
||||
|
||||
cli, err := kubernetes.NewForConfig(clientConfig)
|
||||
httpClient, err := rest.HTTPClientFor(clientConfig)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to create a new clientset for the given config: %w", err)
|
||||
return nil, fmt.Errorf("failed to create http client for the given config: %w", err)
|
||||
}
|
||||
|
||||
cli, err := kubernetes.NewForConfigAndClient(clientConfig, httpClient)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to create clientset for the given config: %w", err)
|
||||
}
|
||||
|
||||
gatewayCLI, err := gatewaycliv1.NewForConfigAndClient(clientConfig, httpClient)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to create gateway clientset for the given config: %w", err)
|
||||
}
|
||||
|
||||
return &KubeClient{
|
||||
cli: cli,
|
||||
gatewayCLI: gatewayCLI,
|
||||
instanceID: factory.instanceID,
|
||||
isKubeAdmin: IsKubeAdmin,
|
||||
nonAdminNamespaces: NonAdminNamespaces,
|
||||
@@ -188,29 +206,45 @@ func (factory *ClientFactory) CreateKubeClientFromKubeConfig(clusterID string, k
|
||||
}
|
||||
|
||||
func (factory *ClientFactory) createCachedPrivilegedKubeClient(endpoint *portainer.Endpoint) (*KubeClient, error) {
|
||||
cli, err := factory.CreateClient(endpoint)
|
||||
cli, gatewayCLI, err := factory.CreateClient(endpoint)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &KubeClient{
|
||||
cli: cli,
|
||||
gatewayCLI: gatewayCLI,
|
||||
instanceID: factory.instanceID,
|
||||
isKubeAdmin: true,
|
||||
}, nil
|
||||
}
|
||||
|
||||
// CreateClient returns a pointer to a new Clientset instance.
|
||||
func (factory *ClientFactory) CreateClient(endpoint *portainer.Endpoint) (*kubernetes.Clientset, error) {
|
||||
// CreateClient returns a pointer to a new Kubernetes Core Clientset instance.
|
||||
func (factory *ClientFactory) CreateClient(endpoint *portainer.Endpoint) (*kubernetes.Clientset, *gatewaycliv1.GatewayV1Client, error) {
|
||||
switch endpoint.Type {
|
||||
case portainer.KubernetesLocalEnvironment, portainer.AgentOnKubernetesEnvironment, portainer.EdgeAgentOnKubernetesEnvironment:
|
||||
c, err := factory.CreateConfig(endpoint)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
return nil, nil, err
|
||||
}
|
||||
return kubernetes.NewForConfig(c)
|
||||
|
||||
httpClient, err := rest.HTTPClientFor(c)
|
||||
if err != nil {
|
||||
return nil, nil, fmt.Errorf("failed to create http client for the given config: %w", err)
|
||||
}
|
||||
|
||||
cli, err := kubernetes.NewForConfigAndClient(c, httpClient)
|
||||
if err != nil {
|
||||
return nil, nil, fmt.Errorf("failed to create clientset for the given config: %w", err)
|
||||
}
|
||||
|
||||
gatewayCLI, err := gatewaycliv1.NewForConfigAndClient(c, httpClient)
|
||||
if err != nil {
|
||||
return nil, nil, fmt.Errorf("failed to create gateway clientset for the given config: %w", err)
|
||||
}
|
||||
return cli, gatewayCLI, nil
|
||||
}
|
||||
return nil, errors.New("unsupported environment type")
|
||||
return nil, nil, errors.New("unsupported environment type")
|
||||
}
|
||||
|
||||
// CreateConfig returns a pointer to a new kubeconfig ready to create a client.
|
||||
|
||||
@@ -19,7 +19,7 @@ func NewSnapshotter(clientFactory *cli.ClientFactory) *Snapshotter {
|
||||
|
||||
// CreateSnapshot creates a snapshot of a specific Kubernetes environment(endpoint)
|
||||
func (snapshotter *Snapshotter) CreateSnapshot(endpoint *portainer.Endpoint) (*portainer.KubernetesSnapshot, error) {
|
||||
client, err := snapshotter.clientFactory.CreateClient(endpoint)
|
||||
client, _, err := snapshotter.clientFactory.CreateClient(endpoint)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
@@ -72,6 +72,7 @@ require (
|
||||
k8s.io/kubectl v0.35.1
|
||||
k8s.io/metrics v0.35.1
|
||||
oras.land/oras-go/v2 v2.6.0
|
||||
sigs.k8s.io/gateway-api v1.5.1
|
||||
)
|
||||
|
||||
require (
|
||||
@@ -364,13 +365,13 @@ require (
|
||||
k8s.io/component-helpers v0.35.1 // indirect
|
||||
k8s.io/klog/v2 v2.140.0 // indirect
|
||||
k8s.io/kube-openapi v0.0.0-20250910181357-589584f1c912 // indirect
|
||||
k8s.io/utils v0.0.0-20251002143259-bc988d571ff4 // indirect
|
||||
k8s.io/utils v0.0.0-20260108192941-914a6e750570 // indirect
|
||||
sigs.k8s.io/controller-runtime v0.23.1 // indirect
|
||||
sigs.k8s.io/json v0.0.0-20250730193827-2d320260d730 // indirect
|
||||
sigs.k8s.io/kustomize/api v0.21.1 // indirect
|
||||
sigs.k8s.io/kustomize/kyaml v0.21.1 // indirect
|
||||
sigs.k8s.io/randfill v1.0.0 // indirect
|
||||
sigs.k8s.io/structured-merge-diff/v6 v6.3.2-0.20260122202528-d9cc6641c482 // indirect
|
||||
sigs.k8s.io/structured-merge-diff/v6 v6.3.2 // indirect
|
||||
sigs.k8s.io/yaml v1.6.0 // indirect
|
||||
tags.cncf.io/container-device-interface v1.1.0 // indirect
|
||||
)
|
||||
|
||||
@@ -757,8 +757,8 @@ github.com/onsi/ginkgo/v2 v2.28.1 h1:S4hj+HbZp40fNKuLUQOYLDgZLwNUVn19N3Atb98NCyI
|
||||
github.com/onsi/ginkgo/v2 v2.28.1/go.mod h1:CLtbVInNckU3/+gC8LzkGUb9oF+e8W8TdUsxPwvdOgE=
|
||||
github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7JYyY=
|
||||
github.com/onsi/gomega v1.9.0/go.mod h1:Ho0h+IUsWyvy1OpqCwxlQ/21gkhVunqlU8fDGcoTdcA=
|
||||
github.com/onsi/gomega v1.39.0 h1:y2ROC3hKFmQZJNFeGAMeHZKkjBL65mIZcvrLQBF9k6Q=
|
||||
github.com/onsi/gomega v1.39.0/go.mod h1:ZCU1pkQcXDO5Sl9/VVEGlDyp+zm0m1cmeG5TOzLgdh4=
|
||||
github.com/onsi/gomega v1.39.1 h1:1IJLAad4zjPn2PsnhH70V4DKRFlrCzGBNrNaru+Vf28=
|
||||
github.com/onsi/gomega v1.39.1/go.mod h1:hL6yVALoTOxeWudERyfppUcZXjMwIMLnuSfruD2lcfg=
|
||||
github.com/open-telemetry/opentelemetry-collector-contrib/internal/exp/metrics v0.148.0 h1:CiTjQE/Hh5xK2t56ogrDK4nl0+tJPNmASCs4zEYZ/xU=
|
||||
github.com/open-telemetry/opentelemetry-collector-contrib/internal/exp/metrics v0.148.0/go.mod h1:WUFkzTiOpt7EYyL67gv1GOf3RD8qKWGtin3lY9LYzW4=
|
||||
github.com/open-telemetry/opentelemetry-collector-contrib/pkg/pdatautil v0.148.0 h1:1TLg6YrS3Au6F7xw3ws2Njbwj13IMqPplvGFi+18fWs=
|
||||
@@ -1268,12 +1268,14 @@ k8s.io/kubectl v0.35.1 h1:zP3Er8C5i1dcAFUMh9Eva0kVvZHptXIn/+8NtRWMxwg=
|
||||
k8s.io/kubectl v0.35.1/go.mod h1:cQ2uAPs5IO/kx8R5s5J3Ihv3VCYwrx0obCXum0CvnXo=
|
||||
k8s.io/metrics v0.35.1 h1:MUcrUcWlq81XiripkydzCGsY9zQawDXfP9IICNNcVVw=
|
||||
k8s.io/metrics v0.35.1/go.mod h1:9x7xWOAOiWzHA0vaqLgSE4PXF3vyT5ts5XIbx8OSjiI=
|
||||
k8s.io/utils v0.0.0-20251002143259-bc988d571ff4 h1:SjGebBtkBqHFOli+05xYbK8YF1Dzkbzn+gDM4X9T4Ck=
|
||||
k8s.io/utils v0.0.0-20251002143259-bc988d571ff4/go.mod h1:OLgZIPagt7ERELqWJFomSt595RzquPNLL48iOWgYOg0=
|
||||
k8s.io/utils v0.0.0-20260108192941-914a6e750570 h1:JT4W8lsdrGENg9W+YwwdLJxklIuKWdRm+BC+xt33FOY=
|
||||
k8s.io/utils v0.0.0-20260108192941-914a6e750570/go.mod h1:xDxuJ0whA3d0I4mf/C4ppKHxXynQ+fxnkmQH0vTHnuk=
|
||||
oras.land/oras-go/v2 v2.6.0 h1:X4ELRsiGkrbeox69+9tzTu492FMUu7zJQW6eJU+I2oc=
|
||||
oras.land/oras-go/v2 v2.6.0/go.mod h1:magiQDfG6H1O9APp+rOsvCPcW1GD2MM7vgnKY0Y+u1o=
|
||||
sigs.k8s.io/controller-runtime v0.23.1 h1:TjJSM80Nf43Mg21+RCy3J70aj/W6KyvDtOlpKf+PupE=
|
||||
sigs.k8s.io/controller-runtime v0.23.1/go.mod h1:B6COOxKptp+YaUT5q4l6LqUJTRpizbgf9KSRNdQGns0=
|
||||
sigs.k8s.io/gateway-api v1.5.1 h1:RqVRIlkhLhUO8wOHKTLnTJA6o/1un4po4/6M1nRzdd0=
|
||||
sigs.k8s.io/gateway-api v1.5.1/go.mod h1:GvCETiaMAlLym5CovLxGjS0NysqFk3+Yuq3/rh6QL2o=
|
||||
sigs.k8s.io/json v0.0.0-20250730193827-2d320260d730 h1:IpInykpT6ceI+QxKBbEflcR5EXP7sU1kvOlxwZh5txg=
|
||||
sigs.k8s.io/json v0.0.0-20250730193827-2d320260d730/go.mod h1:mdzfpAEoE6DHQEN0uh9ZbOCuHbLK5wOm7dK4ctXE9Tg=
|
||||
sigs.k8s.io/kustomize/api v0.21.1 h1:lzqbzvz2CSvsjIUZUBNFKtIMsEw7hVLJp0JeSIVmuJs=
|
||||
@@ -1282,8 +1284,8 @@ sigs.k8s.io/kustomize/kyaml v0.21.1 h1:IVlbmhC076nf6foyL6Taw4BkrLuEsXUXNpsE+ScX7
|
||||
sigs.k8s.io/kustomize/kyaml v0.21.1/go.mod h1:hmxADesM3yUN2vbA5z1/YTBnzLJ1dajdqpQonwBL1FQ=
|
||||
sigs.k8s.io/randfill v1.0.0 h1:JfjMILfT8A6RbawdsK2JXGBR5AQVfd+9TbzrlneTyrU=
|
||||
sigs.k8s.io/randfill v1.0.0/go.mod h1:XeLlZ/jmk4i1HRopwe7/aU3H5n1zNUcX6TM94b3QxOY=
|
||||
sigs.k8s.io/structured-merge-diff/v6 v6.3.2-0.20260122202528-d9cc6641c482 h1:2WOzJpHUBVrrkDjU4KBT8n5LDcj824eX0I5UKcgeRUs=
|
||||
sigs.k8s.io/structured-merge-diff/v6 v6.3.2-0.20260122202528-d9cc6641c482/go.mod h1:M3W8sfWvn2HhQDIbGWj3S099YozAsymCo/wrT5ohRUE=
|
||||
sigs.k8s.io/structured-merge-diff/v6 v6.3.2 h1:kwVWMx5yS1CrnFWA/2QHyRVJ8jM6dBA80uLmm0wJkk8=
|
||||
sigs.k8s.io/structured-merge-diff/v6 v6.3.2/go.mod h1:M3W8sfWvn2HhQDIbGWj3S099YozAsymCo/wrT5ohRUE=
|
||||
sigs.k8s.io/yaml v1.6.0 h1:G8fkbMSAFqgEFgh4b1wmtzDnioxFCUgTZhlbj5P9QYs=
|
||||
sigs.k8s.io/yaml v1.6.0/go.mod h1:796bPqUfzR/0jLAl6XjHl3Ck7MiyVv8dbTdyT3/pMf4=
|
||||
tags.cncf.io/container-device-interface v1.1.0 h1:RnxNhxF1JOu6CJUVpetTYvrXHdxw9j9jFYgZpI+anSY=
|
||||
|
||||
Reference in New Issue
Block a user