mirror of
https://github.com/k8snetworkplumbingwg/multus-cni.git
synced 2025-08-11 13:03:59 +00:00
k8sclient: use InClusterConfig() for kubeclient when run as daemonset
When multus is run inside a container, eg as a daemonset, we can use InClusterConfig() to automatically get the service account token, the CA certificate, and the apiserver address, all without a kubeconfig file.
This commit is contained in:
parent
926910af08
commit
42e6894962
@ -17,12 +17,14 @@ package k8sclient
|
|||||||
import (
|
import (
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"os"
|
||||||
"regexp"
|
"regexp"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||||
"k8s.io/client-go/kubernetes"
|
"k8s.io/client-go/kubernetes"
|
||||||
v1 "k8s.io/client-go/pkg/api/v1"
|
v1 "k8s.io/client-go/pkg/api/v1"
|
||||||
|
"k8s.io/client-go/rest"
|
||||||
"k8s.io/client-go/tools/clientcmd"
|
"k8s.io/client-go/tools/clientcmd"
|
||||||
|
|
||||||
"github.com/containernetworking/cni/libcni"
|
"github.com/containernetworking/cni/libcni"
|
||||||
@ -53,22 +55,6 @@ func (d *defaultKubeClient) GetPod(namespace, name string) (*v1.Pod, error) {
|
|||||||
return d.client.Core().Pods(namespace).Get(name, metav1.GetOptions{})
|
return d.client.Core().Pods(namespace).Get(name, metav1.GetOptions{})
|
||||||
}
|
}
|
||||||
|
|
||||||
func createK8sClient(kubeconfig string) (KubeClient, error) {
|
|
||||||
// uses the current context in kubeconfig
|
|
||||||
config, err := clientcmd.BuildConfigFromFlags("", kubeconfig)
|
|
||||||
if err != nil {
|
|
||||||
return nil, fmt.Errorf("createK8sClient: failed to get context for the kubeconfig %v, refer Multus README.md for the usage guide: %v", kubeconfig, err)
|
|
||||||
}
|
|
||||||
|
|
||||||
// creates the clientset
|
|
||||||
client, err := kubernetes.NewForConfig(config)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
return &defaultKubeClient{client: client}, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func getPodNetworkAnnotation(client KubeClient, k8sArgs types.K8sArgs) (string, string, error) {
|
func getPodNetworkAnnotation(client KubeClient, k8sArgs types.K8sArgs) (string, string, error) {
|
||||||
var err error
|
var err error
|
||||||
|
|
||||||
@ -276,7 +262,44 @@ type KubeClient interface {
|
|||||||
GetPod(namespace, name string) (*v1.Pod, error)
|
GetPod(namespace, name string) (*v1.Pod, error)
|
||||||
}
|
}
|
||||||
|
|
||||||
func GetK8sNetwork(args *skel.CmdArgs, kubeconfig string, k8sclient KubeClient, confdir string) ([]*types.DelegateNetConf, error) {
|
func GetK8sClient(kubeconfig string, kubeClient KubeClient) (KubeClient, error) {
|
||||||
|
// If we get a valid kubeClient (eg from testcases) just return that
|
||||||
|
// one.
|
||||||
|
if kubeClient != nil {
|
||||||
|
return kubeClient, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
var err error
|
||||||
|
var config *rest.Config
|
||||||
|
|
||||||
|
// Otherwise try to create a kubeClient from a given kubeConfig
|
||||||
|
if kubeconfig != "" {
|
||||||
|
// uses the current context in kubeconfig
|
||||||
|
config, err = clientcmd.BuildConfigFromFlags("", kubeconfig)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("GetK8sClient: failed to get context for the kubeconfig %v, refer Multus README.md for the usage guide: %v", kubeconfig, err)
|
||||||
|
}
|
||||||
|
} else if os.Getenv("KUBERNETES_SERVICE_HOST") != "" && os.Getenv("KUBERNETES_SERVICE_PORT") != "" {
|
||||||
|
// Try in-cluster config where multus might be running in a kubernetes pod
|
||||||
|
config, err = rest.InClusterConfig()
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("createK8sClient: failed to get context for in-cluster kube config, refer Multus README.md for the usage guide: %v", err)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// No kubernetes config; assume we shouldn't talk to Kube at all
|
||||||
|
return nil, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// creates the clientset
|
||||||
|
client, err := kubernetes.NewForConfig(config)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return &defaultKubeClient{client: client}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func GetK8sNetwork(k8sclient KubeClient, args *skel.CmdArgs, confdir string) ([]*types.DelegateNetConf, error) {
|
||||||
k8sArgs := types.K8sArgs{}
|
k8sArgs := types.K8sArgs{}
|
||||||
|
|
||||||
err := cnitypes.LoadArgs(args.Args, &k8sArgs)
|
err := cnitypes.LoadArgs(args.Args, &k8sArgs)
|
||||||
@ -284,13 +307,6 @@ func GetK8sNetwork(args *skel.CmdArgs, kubeconfig string, k8sclient KubeClient,
|
|||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
if k8sclient == nil {
|
|
||||||
k8sclient, err = createK8sClient(kubeconfig)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
netAnnot, defaultNamespace, err := getPodNetworkAnnotation(k8sclient, k8sArgs)
|
netAnnot, defaultNamespace, err := getPodNetworkAnnotation(k8sclient, k8sArgs)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
|
@ -77,7 +77,9 @@ var _ = Describe("k8sclient operations", func() {
|
|||||||
// net3 is not used; make sure it's not accessed
|
// net3 is not used; make sure it's not accessed
|
||||||
fKubeClient.AddNetConfig(fakePod.ObjectMeta.Namespace, "net3", net3)
|
fKubeClient.AddNetConfig(fakePod.ObjectMeta.Namespace, "net3", net3)
|
||||||
|
|
||||||
delegates, err := GetK8sNetwork(args, "", fKubeClient, tmpDir)
|
kubeClient, err := GetK8sClient("", fKubeClient)
|
||||||
|
Expect(err).NotTo(HaveOccurred())
|
||||||
|
delegates, err := GetK8sNetwork(kubeClient, args, tmpDir)
|
||||||
Expect(err).NotTo(HaveOccurred())
|
Expect(err).NotTo(HaveOccurred())
|
||||||
Expect(fKubeClient.PodCount).To(Equal(1))
|
Expect(fKubeClient.PodCount).To(Equal(1))
|
||||||
Expect(fKubeClient.NetCount).To(Equal(2))
|
Expect(fKubeClient.NetCount).To(Equal(2))
|
||||||
@ -106,7 +108,9 @@ var _ = Describe("k8sclient operations", func() {
|
|||||||
fKubeClient.AddPod(fakePod)
|
fKubeClient.AddPod(fakePod)
|
||||||
fKubeClient.AddNetConfig(fakePod.ObjectMeta.Namespace, "net3", net3)
|
fKubeClient.AddNetConfig(fakePod.ObjectMeta.Namespace, "net3", net3)
|
||||||
|
|
||||||
delegates, err := GetK8sNetwork(args, "", fKubeClient, tmpDir)
|
kubeClient, err := GetK8sClient("", fKubeClient)
|
||||||
|
Expect(err).NotTo(HaveOccurred())
|
||||||
|
delegates, err := GetK8sNetwork(kubeClient, args, tmpDir)
|
||||||
Expect(len(delegates)).To(Equal(0))
|
Expect(len(delegates)).To(Equal(0))
|
||||||
Expect(err).To(MatchError("GetK8sNetwork: failed getting the delegate: getKubernetesDelegate: failed to get network resource, refer Multus README.md for the usage guide: resource not found"))
|
Expect(err).To(MatchError("GetK8sNetwork: failed getting the delegate: getKubernetesDelegate: failed to get network resource, refer Multus README.md for the usage guide: resource not found"))
|
||||||
})
|
})
|
||||||
@ -146,7 +150,9 @@ var _ = Describe("k8sclient operations", func() {
|
|||||||
"cniVersion": "0.2.0"
|
"cniVersion": "0.2.0"
|
||||||
}`)
|
}`)
|
||||||
|
|
||||||
delegates, err := GetK8sNetwork(args, "", fKubeClient, tmpDir)
|
kubeClient, err := GetK8sClient("", fKubeClient)
|
||||||
|
Expect(err).NotTo(HaveOccurred())
|
||||||
|
delegates, err := GetK8sNetwork(kubeClient, args, tmpDir)
|
||||||
Expect(err).NotTo(HaveOccurred())
|
Expect(err).NotTo(HaveOccurred())
|
||||||
Expect(fKubeClient.PodCount).To(Equal(1))
|
Expect(fKubeClient.PodCount).To(Equal(1))
|
||||||
Expect(fKubeClient.NetCount).To(Equal(3))
|
Expect(fKubeClient.NetCount).To(Equal(3))
|
||||||
@ -169,7 +175,9 @@ var _ = Describe("k8sclient operations", func() {
|
|||||||
fKubeClient := testutils.NewFakeKubeClient()
|
fKubeClient := testutils.NewFakeKubeClient()
|
||||||
fKubeClient.AddPod(fakePod)
|
fKubeClient.AddPod(fakePod)
|
||||||
|
|
||||||
delegates, err := GetK8sNetwork(args, "", fKubeClient, tmpDir)
|
kubeClient, err := GetK8sClient("", fKubeClient)
|
||||||
|
Expect(err).NotTo(HaveOccurred())
|
||||||
|
delegates, err := GetK8sNetwork(kubeClient, args, tmpDir)
|
||||||
Expect(len(delegates)).To(Equal(0))
|
Expect(len(delegates)).To(Equal(0))
|
||||||
Expect(err).To(MatchError("parsePodNetworkAnnotation: failed to parse pod Network Attachment Selection Annotation JSON format: invalid character 'a' looking for beginning of value"))
|
Expect(err).To(MatchError("parsePodNetworkAnnotation: failed to parse pod Network Attachment Selection Annotation JSON format: invalid character 'a' looking for beginning of value"))
|
||||||
})
|
})
|
||||||
@ -195,7 +203,9 @@ var _ = Describe("k8sclient operations", func() {
|
|||||||
"cniVersion": "0.2.0"
|
"cniVersion": "0.2.0"
|
||||||
}`)
|
}`)
|
||||||
|
|
||||||
delegates, err := GetK8sNetwork(args, "", fKubeClient, tmpDir)
|
kubeClient, err := GetK8sClient("", fKubeClient)
|
||||||
|
Expect(err).NotTo(HaveOccurred())
|
||||||
|
delegates, err := GetK8sNetwork(kubeClient, args, tmpDir)
|
||||||
Expect(err).NotTo(HaveOccurred())
|
Expect(err).NotTo(HaveOccurred())
|
||||||
Expect(fKubeClient.PodCount).To(Equal(1))
|
Expect(fKubeClient.PodCount).To(Equal(1))
|
||||||
Expect(fKubeClient.NetCount).To(Equal(2))
|
Expect(fKubeClient.NetCount).To(Equal(2))
|
||||||
@ -244,7 +254,9 @@ var _ = Describe("k8sclient operations", func() {
|
|||||||
net2Name := filepath.Join(tmpDir, "20-net2.conf")
|
net2Name := filepath.Join(tmpDir, "20-net2.conf")
|
||||||
fKubeClient.AddNetFile(fakePod.ObjectMeta.Namespace, "net2", net2Name, "asdfasdfasfdasfd")
|
fKubeClient.AddNetFile(fakePod.ObjectMeta.Namespace, "net2", net2Name, "asdfasdfasfdasfd")
|
||||||
|
|
||||||
delegates, err := GetK8sNetwork(args, "", fKubeClient, tmpDir)
|
kubeClient, err := GetK8sClient("", fKubeClient)
|
||||||
|
Expect(err).NotTo(HaveOccurred())
|
||||||
|
delegates, err := GetK8sNetwork(kubeClient, args, tmpDir)
|
||||||
Expect(len(delegates)).To(Equal(0))
|
Expect(len(delegates)).To(Equal(0))
|
||||||
Expect(err).To(MatchError(fmt.Sprintf("GetK8sNetwork: failed getting the delegate: cniConfigFromNetworkResource: err in getCNIConfigFromFile: Error loading CNI config file %s: error parsing configuration: invalid character 'a' looking for beginning of value", net2Name)))
|
Expect(err).To(MatchError(fmt.Sprintf("GetK8sNetwork: failed getting the delegate: cniConfigFromNetworkResource: err in getCNIConfigFromFile: Error loading CNI config file %s: error parsing configuration: invalid character 'a' looking for beginning of value", net2Name)))
|
||||||
})
|
})
|
||||||
|
@ -148,29 +148,52 @@ func delPlugins(exec invoke.Exec, argIfname string, delegates []*types.DelegateN
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Attempts to load Kubernetes-defined delegates and add them to the Multus config.
|
||||||
|
// Returns the number of Kubernetes-defined delegates added or an error.
|
||||||
|
func tryLoadK8sDelegates(args *skel.CmdArgs, conf *types.NetConf, kubeClient k8s.KubeClient) (int, error) {
|
||||||
|
var err error
|
||||||
|
|
||||||
|
kubeClient, err = k8s.GetK8sClient(conf.Kubeconfig, kubeClient)
|
||||||
|
if err != nil {
|
||||||
|
return 0, err
|
||||||
|
}
|
||||||
|
|
||||||
|
if kubeClient == nil {
|
||||||
|
if len(conf.Delegates) == 0 {
|
||||||
|
// No available kube client and no delegates, we can't do anything
|
||||||
|
return 0, fmt.Errorf("must have either Kubernetes config or delegates, refer Multus README.md for the usage guide")
|
||||||
|
}
|
||||||
|
return 0, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
delegates, err := k8s.GetK8sNetwork(kubeClient, args, conf.ConfDir)
|
||||||
|
if err != nil {
|
||||||
|
if _, ok := err.(*k8s.NoK8sNetworkError); ok {
|
||||||
|
return 0, nil
|
||||||
|
}
|
||||||
|
return 0, fmt.Errorf("Multus: Err in getting k8s network from pod: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if err = conf.AddDelegates(delegates); err != nil {
|
||||||
|
return 0, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return len(delegates), nil
|
||||||
|
}
|
||||||
|
|
||||||
func cmdAdd(args *skel.CmdArgs, exec invoke.Exec, kubeClient k8s.KubeClient) (cnitypes.Result, error) {
|
func cmdAdd(args *skel.CmdArgs, exec invoke.Exec, kubeClient k8s.KubeClient) (cnitypes.Result, error) {
|
||||||
var nopodnet bool
|
|
||||||
n, err := types.LoadNetConf(args.StdinData)
|
n, err := types.LoadNetConf(args.StdinData)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("err in loading netconf: %v", err)
|
return nil, fmt.Errorf("err in loading netconf: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
if n.Kubeconfig != "" {
|
numK8sDelegates, err := tryLoadK8sDelegates(args, n, kubeClient)
|
||||||
delegates, err := k8s.GetK8sNetwork(args, n.Kubeconfig, kubeClient, n.ConfDir)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if _, ok := err.(*k8s.NoK8sNetworkError); ok {
|
|
||||||
nopodnet = true
|
|
||||||
} else {
|
|
||||||
return nil, fmt.Errorf("Multus: Err in getting k8s network from pod: %v", err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if err = n.AddDelegates(delegates); err != nil {
|
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
if n.Kubeconfig == "" || nopodnet {
|
if numK8sDelegates == 0 {
|
||||||
|
// cache the multus config if we have only Multus delegates
|
||||||
if err := saveDelegates(args.ContainerID, n.CNIDir, n.Delegates); err != nil {
|
if err := saveDelegates(args.ContainerID, n.CNIDir, n.Delegates); err != nil {
|
||||||
return nil, fmt.Errorf("Multus: Err in saving the delegates: %v", err)
|
return nil, fmt.Errorf("Multus: Err in saving the delegates: %v", err)
|
||||||
}
|
}
|
||||||
@ -213,29 +236,18 @@ func cmdGet(args *skel.CmdArgs, exec invoke.Exec, kubeClient k8s.KubeClient) (cn
|
|||||||
}
|
}
|
||||||
|
|
||||||
func cmdDel(args *skel.CmdArgs, exec invoke.Exec, kubeClient k8s.KubeClient) error {
|
func cmdDel(args *skel.CmdArgs, exec invoke.Exec, kubeClient k8s.KubeClient) error {
|
||||||
var nopodnet bool
|
|
||||||
|
|
||||||
in, err := types.LoadNetConf(args.StdinData)
|
in, err := types.LoadNetConf(args.StdinData)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
if in.Kubeconfig != "" {
|
numK8sDelegates, err := tryLoadK8sDelegates(args, in, kubeClient)
|
||||||
delegates, err := k8s.GetK8sNetwork(args, in.Kubeconfig, kubeClient, in.ConfDir)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if _, ok := err.(*k8s.NoK8sNetworkError); ok {
|
|
||||||
nopodnet = true
|
|
||||||
} else {
|
|
||||||
return fmt.Errorf("Multus: Err in getting k8s network from pod: %v", err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if err = in.AddDelegates(delegates); err != nil {
|
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
if in.Kubeconfig == "" || nopodnet {
|
if numK8sDelegates == 0 {
|
||||||
|
// re-read the scratch multus config if we have only Multus delegates
|
||||||
netconfBytes, err := consumeScratchNetConf(args.ContainerID, in.CNIDir)
|
netconfBytes, err := consumeScratchNetConf(args.ContainerID, in.CNIDir)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if os.IsNotExist(err) {
|
if os.IsNotExist(err) {
|
||||||
|
Loading…
Reference in New Issue
Block a user