mirror of
https://github.com/k8snetworkplumbingwg/multus-cni.git
synced 2025-08-19 16:51:33 +00:00
add kubelet client for Pod resource info
This change introduces kubelet client to get allocated device information of a Pod from newly added Kubelet grpc service. For more information please see: [kubernetes/kubernetes#70508](https://github.com/kubernetes/kubernetes/pull/70508) Change-Id: I11e58ccdd52662601f445fa24c7d55c225441efc Signed-off-by: Abdul Halim <abdul.halim@intel.com>
This commit is contained in:
parent
8ee7eb335e
commit
d3c92b4aa2
@ -21,6 +21,7 @@ import (
|
|||||||
|
|
||||||
"github.com/intel/multus-cni/logging"
|
"github.com/intel/multus-cni/logging"
|
||||||
"github.com/intel/multus-cni/types"
|
"github.com/intel/multus-cni/types"
|
||||||
|
v1 "k8s.io/api/core/v1"
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
@ -45,22 +46,18 @@ type Data struct {
|
|||||||
Checksum uint64
|
Checksum uint64
|
||||||
}
|
}
|
||||||
|
|
||||||
type Checkpoint interface {
|
|
||||||
// GetComputeDeviceMap returns an instance of a map of ResourceInfo for a PodID
|
|
||||||
GetComputeDeviceMap(string) (map[string]*types.ResourceInfo, error)
|
|
||||||
}
|
|
||||||
type checkpoint struct {
|
type checkpoint struct {
|
||||||
fileName string
|
fileName string
|
||||||
podEntires []PodDevicesEntry
|
podEntires []PodDevicesEntry
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetCheckpoint returns an instance of Checkpoint
|
// GetCheckpoint returns an instance of Checkpoint
|
||||||
func GetCheckpoint() (Checkpoint, error) {
|
func GetCheckpoint() (types.ResourceClient, error) {
|
||||||
logging.Debugf("GetCheckpoint(): invoked")
|
logging.Debugf("GetCheckpoint(): invoked")
|
||||||
return getCheckpoint(checkPointfile)
|
return getCheckpoint(checkPointfile)
|
||||||
}
|
}
|
||||||
|
|
||||||
func getCheckpoint(filePath string) (Checkpoint, error) {
|
func getCheckpoint(filePath string) (types.ResourceClient, error) {
|
||||||
cp := &checkpoint{fileName: filePath}
|
cp := &checkpoint{fileName: filePath}
|
||||||
err := cp.getPodEntries()
|
err := cp.getPodEntries()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -89,12 +86,12 @@ func (cp *checkpoint) getPodEntries() error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// GetComputeDeviceMap returns an instance of a map of ResourceInfo
|
// GetComputeDeviceMap returns an instance of a map of ResourceInfo
|
||||||
func (cp *checkpoint) GetComputeDeviceMap(podID string) (map[string]*types.ResourceInfo, error) {
|
func (cp *checkpoint) GetPodResourceMap(pod *v1.Pod) (map[string]*types.ResourceInfo, error) {
|
||||||
|
podID := string(pod.UID)
|
||||||
resourceMap := make(map[string]*types.ResourceInfo)
|
resourceMap := make(map[string]*types.ResourceInfo)
|
||||||
|
|
||||||
if podID == "" {
|
if podID == "" {
|
||||||
return nil, logging.Errorf("GetComputeDeviceMap(): invalid Pod cannot be empty")
|
return nil, logging.Errorf("GetPodResourceMap(): invalid Pod cannot be empty")
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, pod := range cp.podEntires {
|
for _, pod := range cp.podEntires {
|
||||||
|
@ -10,6 +10,9 @@ import (
|
|||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/intel/multus-cni/types"
|
"github.com/intel/multus-cni/types"
|
||||||
|
v1 "k8s.io/api/core/v1"
|
||||||
|
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||||
|
k8sTypes "k8s.io/apimachinery/pkg/types"
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
@ -74,7 +77,7 @@ var _ = BeforeSuite(func() {
|
|||||||
var _ = Describe("Kubelet checkpoint data read operations", func() {
|
var _ = Describe("Kubelet checkpoint data read operations", func() {
|
||||||
Context("Using /tmp/kubelet_internal_checkpoint file", func() {
|
Context("Using /tmp/kubelet_internal_checkpoint file", func() {
|
||||||
var (
|
var (
|
||||||
cp Checkpoint
|
cp types.ResourceClient
|
||||||
err error
|
err error
|
||||||
resourceMap map[string]*types.ResourceInfo
|
resourceMap map[string]*types.ResourceInfo
|
||||||
resourceInfo *types.ResourceInfo
|
resourceInfo *types.ResourceInfo
|
||||||
@ -87,7 +90,15 @@ var _ = Describe("Kubelet checkpoint data read operations", func() {
|
|||||||
})
|
})
|
||||||
|
|
||||||
It("should return a ResourceMap instance", func() {
|
It("should return a ResourceMap instance", func() {
|
||||||
rmap, err := cp.GetComputeDeviceMap("970a395d-bb3b-11e8-89df-408d5c537d23")
|
podUID := k8sTypes.UID("970a395d-bb3b-11e8-89df-408d5c537d23")
|
||||||
|
fakePod := &v1.Pod{
|
||||||
|
ObjectMeta: metav1.ObjectMeta{
|
||||||
|
Name: "fakePod",
|
||||||
|
Namespace: "podNamespace",
|
||||||
|
UID: podUID,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
rmap, err := cp.GetPodResourceMap(fakePod)
|
||||||
Expect(err).NotTo(HaveOccurred())
|
Expect(err).NotTo(HaveOccurred())
|
||||||
Expect(rmap).NotTo(BeEmpty())
|
Expect(rmap).NotTo(BeEmpty())
|
||||||
resourceMap = rmap
|
resourceMap = rmap
|
||||||
|
64
glide.lock
generated
64
glide.lock
generated
@ -1,13 +1,11 @@
|
|||||||
hash: 0c4ea2a342364d2ff3b43242730cb3b1db3b7e8456f6cf43da3c51dbb67e18da
|
hash: 4288149814e91e63396f7874b87151aca74047110f0d1f43027b60dd6014988f
|
||||||
updated: 2018-07-27T03:29:02.093332104+01:00
|
updated: 2019-01-09T10:19:29.688011713Z
|
||||||
imports:
|
imports:
|
||||||
- name: github.com/containernetworking/cni
|
- name: github.com/containernetworking/cni
|
||||||
version: 07c1a6da47b7fbf8b357f4949ecce2113e598491
|
version: 07c1a6da47b7fbf8b357f4949ecce2113e598491
|
||||||
subpackages:
|
subpackages:
|
||||||
- libcni
|
- libcni
|
||||||
- pkg/invoke
|
- pkg/invoke
|
||||||
- pkg/ip
|
|
||||||
- pkg/ipam
|
|
||||||
- pkg/skel
|
- pkg/skel
|
||||||
- pkg/types
|
- pkg/types
|
||||||
- pkg/types/020
|
- pkg/types/020
|
||||||
@ -16,6 +14,8 @@ imports:
|
|||||||
- name: github.com/containernetworking/plugins
|
- name: github.com/containernetworking/plugins
|
||||||
version: 2b8b1ac0af4568e928d96ccc5f47b075416eeabd
|
version: 2b8b1ac0af4568e928d96ccc5f47b075416eeabd
|
||||||
subpackages:
|
subpackages:
|
||||||
|
- pkg/ip
|
||||||
|
- pkg/ipam
|
||||||
- pkg/ns
|
- pkg/ns
|
||||||
- pkg/testutils
|
- pkg/testutils
|
||||||
- name: github.com/ghodss/yaml
|
- name: github.com/ghodss/yaml
|
||||||
@ -23,7 +23,9 @@ imports:
|
|||||||
- name: github.com/gogo/protobuf
|
- name: github.com/gogo/protobuf
|
||||||
version: c0656edd0d9eab7c66d1eb0c568f9039345796f7
|
version: c0656edd0d9eab7c66d1eb0c568f9039345796f7
|
||||||
subpackages:
|
subpackages:
|
||||||
|
- gogoproto
|
||||||
- proto
|
- proto
|
||||||
|
- protoc-gen-gogo/descriptor
|
||||||
- sortkeys
|
- sortkeys
|
||||||
- name: github.com/golang/glog
|
- name: github.com/golang/glog
|
||||||
version: 44145f04b68cf362d9c4df2182967c2275eaefed
|
version: 44145f04b68cf362d9c4df2182967c2275eaefed
|
||||||
@ -53,6 +55,8 @@ imports:
|
|||||||
version: 6633656539c1639d9d78127b7d47c622b5d7b6dc
|
version: 6633656539c1639d9d78127b7d47c622b5d7b6dc
|
||||||
- name: github.com/json-iterator/go
|
- name: github.com/json-iterator/go
|
||||||
version: f2b4162afba35581b6d4a50d3b8f34e33c144682
|
version: f2b4162afba35581b6d4a50d3b8f34e33c144682
|
||||||
|
- name: github.com/Microsoft/go-winio
|
||||||
|
version: 78439966b38d69bf38227fbf57ac8a6fee70f69a
|
||||||
- name: github.com/modern-go/concurrent
|
- name: github.com/modern-go/concurrent
|
||||||
version: bacd9c7ef1dd9b15be4a9909b8ac7a4e313eec94
|
version: bacd9c7ef1dd9b15be4a9909b8ac7a4e313eec94
|
||||||
- name: github.com/modern-go/reflect2
|
- name: github.com/modern-go/reflect2
|
||||||
@ -61,6 +65,7 @@ imports:
|
|||||||
version: 7f8ab55aaf3b86885aa55b762e803744d1674700
|
version: 7f8ab55aaf3b86885aa55b762e803744d1674700
|
||||||
subpackages:
|
subpackages:
|
||||||
- config
|
- config
|
||||||
|
- extensions/table
|
||||||
- internal/codelocation
|
- internal/codelocation
|
||||||
- internal/containernode
|
- internal/containernode
|
||||||
- internal/failer
|
- internal/failer
|
||||||
@ -91,15 +96,15 @@ imports:
|
|||||||
- name: github.com/peterbourgon/diskv
|
- name: github.com/peterbourgon/diskv
|
||||||
version: 5f041e8faa004a95c88a202771f4cc3e991971e6
|
version: 5f041e8faa004a95c88a202771f4cc3e991971e6
|
||||||
- name: github.com/pkg/errors
|
- name: github.com/pkg/errors
|
||||||
version: 816c9085562cd7ee03e7f8188a1cfd942858cded
|
version: ffb6e22f01932bf7ac35e0bad9be11f01d1c8685
|
||||||
- name: github.com/spf13/pflag
|
- name: github.com/spf13/pflag
|
||||||
version: 583c0c0531f06d5278b7d917446061adc344b5cd
|
version: 583c0c0531f06d5278b7d917446061adc344b5cd
|
||||||
- name: github.com/vishvananda/netlink
|
- name: github.com/vishvananda/netlink
|
||||||
version: 6e453822d85ef5721799774b654d4d02fed62afb
|
version: b2de5d10e38ecce8607e6b438b6d174f389a004e
|
||||||
subpackages:
|
subpackages:
|
||||||
- nl
|
- nl
|
||||||
- name: github.com/vishvananda/netns
|
- name: github.com/vishvananda/netns
|
||||||
version: 54f0e4339ce73702a0607f49922aaa1e749b418d
|
version: be1fbeda19366dea804f00efff2dd73a1642fdcc
|
||||||
- name: golang.org/x/crypto
|
- name: golang.org/x/crypto
|
||||||
version: 49796115aa4b964c318aad4f3084fdb41e9aa067
|
version: 49796115aa4b964c318aad4f3084fdb41e9aa067
|
||||||
subpackages:
|
subpackages:
|
||||||
@ -111,7 +116,9 @@ imports:
|
|||||||
- http2
|
- http2
|
||||||
- http2/hpack
|
- http2/hpack
|
||||||
- idna
|
- idna
|
||||||
|
- internal/timeseries
|
||||||
- lex/httplex
|
- lex/httplex
|
||||||
|
- trace
|
||||||
- name: golang.org/x/sys
|
- name: golang.org/x/sys
|
||||||
version: 95c6576299259db960f6c5b9b69ea52422860fce
|
version: 95c6576299259db960f6c5b9b69ea52422860fce
|
||||||
subpackages:
|
subpackages:
|
||||||
@ -128,6 +135,40 @@ imports:
|
|||||||
version: f51c12702a4d776e4c1fa9b0fabab841babae631
|
version: f51c12702a4d776e4c1fa9b0fabab841babae631
|
||||||
subpackages:
|
subpackages:
|
||||||
- rate
|
- rate
|
||||||
|
- name: google.golang.org/genproto
|
||||||
|
version: 09f6ed296fc66555a25fe4ce95173148778dfa85
|
||||||
|
subpackages:
|
||||||
|
- googleapis/rpc/status
|
||||||
|
- name: google.golang.org/grpc
|
||||||
|
version: 168a6198bcb0ef175f7dacec0b8691fc141dc9b8
|
||||||
|
subpackages:
|
||||||
|
- balancer
|
||||||
|
- balancer/base
|
||||||
|
- balancer/roundrobin
|
||||||
|
- codes
|
||||||
|
- connectivity
|
||||||
|
- credentials
|
||||||
|
- encoding
|
||||||
|
- encoding/proto
|
||||||
|
- grpclb/grpc_lb_v1/messages
|
||||||
|
- grpclog
|
||||||
|
- health
|
||||||
|
- health/grpc_health_v1
|
||||||
|
- internal
|
||||||
|
- internal/backoff
|
||||||
|
- internal/channelz
|
||||||
|
- internal/grpcrand
|
||||||
|
- keepalive
|
||||||
|
- metadata
|
||||||
|
- naming
|
||||||
|
- peer
|
||||||
|
- resolver
|
||||||
|
- resolver/dns
|
||||||
|
- resolver/passthrough
|
||||||
|
- stats
|
||||||
|
- status
|
||||||
|
- tap
|
||||||
|
- transport
|
||||||
- name: gopkg.in/inf.v0
|
- name: gopkg.in/inf.v0
|
||||||
version: 3887ee99ecf07df5b447e9b00d9c0b2adaa9f3e4
|
version: 3887ee99ecf07df5b447e9b00d9c0b2adaa9f3e4
|
||||||
- name: gopkg.in/yaml.v2
|
- name: gopkg.in/yaml.v2
|
||||||
@ -135,6 +176,7 @@ imports:
|
|||||||
- name: k8s.io/api
|
- name: k8s.io/api
|
||||||
version: 2d6f90ab1293a1fb871cf149423ebb72aa7423aa
|
version: 2d6f90ab1293a1fb871cf149423ebb72aa7423aa
|
||||||
subpackages:
|
subpackages:
|
||||||
|
- admission/v1beta1
|
||||||
- admissionregistration/v1alpha1
|
- admissionregistration/v1alpha1
|
||||||
- admissionregistration/v1beta1
|
- admissionregistration/v1beta1
|
||||||
- apps/v1
|
- apps/v1
|
||||||
@ -258,4 +300,12 @@ imports:
|
|||||||
- util/homedir
|
- util/homedir
|
||||||
- util/integer
|
- util/integer
|
||||||
- util/retry
|
- util/retry
|
||||||
|
- name: k8s.io/klog
|
||||||
|
version: 8139d8cb77af419532b33dfa7dd09fbc5f1d344f
|
||||||
|
- name: k8s.io/kubernetes
|
||||||
|
version: ddf47ac13c1a9483ea035a79cd7c10005ff21a6d
|
||||||
|
subpackages:
|
||||||
|
- pkg/kubelet/apis/podresources
|
||||||
|
- pkg/kubelet/apis/podresources/v1alpha1
|
||||||
|
- pkg/kubelet/util
|
||||||
testImports: []
|
testImports: []
|
||||||
|
@ -32,5 +32,11 @@ import:
|
|||||||
- kubernetes
|
- kubernetes
|
||||||
- tools/clientcmd
|
- tools/clientcmd
|
||||||
- util/retry
|
- util/retry
|
||||||
|
- package: k8s.io/kubernetes
|
||||||
|
version: v1.13.0
|
||||||
|
subpackages:
|
||||||
|
- pkg/kubelet/apis/podresources
|
||||||
|
- pkg/kubelet/apis/podresources/v1alpha1
|
||||||
|
- pkg/kubelet/util
|
||||||
- package: github.com/vishvananda/netns
|
- package: github.com/vishvananda/netns
|
||||||
- package: github.com/pkg/errors
|
- package: github.com/pkg/errors
|
||||||
|
@ -31,7 +31,7 @@ import (
|
|||||||
"github.com/containernetworking/cni/libcni"
|
"github.com/containernetworking/cni/libcni"
|
||||||
"github.com/containernetworking/cni/pkg/skel"
|
"github.com/containernetworking/cni/pkg/skel"
|
||||||
cnitypes "github.com/containernetworking/cni/pkg/types"
|
cnitypes "github.com/containernetworking/cni/pkg/types"
|
||||||
"github.com/intel/multus-cni/checkpoint"
|
"github.com/intel/multus-cni/kubeletclient"
|
||||||
"github.com/intel/multus-cni/logging"
|
"github.com/intel/multus-cni/logging"
|
||||||
"github.com/intel/multus-cni/types"
|
"github.com/intel/multus-cni/types"
|
||||||
)
|
)
|
||||||
@ -336,7 +336,7 @@ func cniConfigFromNetworkResource(customResource *types.NetworkAttachmentDefinit
|
|||||||
return config, nil
|
return config, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func getKubernetesDelegate(client KubeClient, net *types.NetworkSelectionElement, confdir string, podID string, resourceMap map[string]*types.ResourceInfo) (*types.DelegateNetConf, map[string]*types.ResourceInfo, error) {
|
func getKubernetesDelegate(client KubeClient, net *types.NetworkSelectionElement, confdir string, pod *v1.Pod, resourceMap map[string]*types.ResourceInfo) (*types.DelegateNetConf, map[string]*types.ResourceInfo, error) {
|
||||||
|
|
||||||
logging.Debugf("getKubernetesDelegate: %v, %v, %s", client, net, confdir)
|
logging.Debugf("getKubernetesDelegate: %v, %v, %s", client, net, confdir)
|
||||||
rawPath := fmt.Sprintf("/apis/k8s.cni.cncf.io/v1/namespaces/%s/network-attachment-definitions/%s", net.Namespace, net.Name)
|
rawPath := fmt.Sprintf("/apis/k8s.cni.cncf.io/v1/namespaces/%s/network-attachment-definitions/%s", net.Namespace, net.Name)
|
||||||
@ -353,18 +353,18 @@ func getKubernetesDelegate(client KubeClient, net *types.NetworkSelectionElement
|
|||||||
// Get resourceName annotation from NetworkAttachmentDefinition
|
// Get resourceName annotation from NetworkAttachmentDefinition
|
||||||
deviceID := ""
|
deviceID := ""
|
||||||
resourceName, ok := customResource.Metadata.Annotations[resourceNameAnnot]
|
resourceName, ok := customResource.Metadata.Annotations[resourceNameAnnot]
|
||||||
if ok && podID != "" {
|
if ok && pod.Name != "" && pod.Namespace != "" {
|
||||||
// ResourceName annotation is found; try to get device info from resourceMap
|
// ResourceName annotation is found; try to get device info from resourceMap
|
||||||
logging.Debugf("getKubernetesDelegate: found resourceName annotation : %s", resourceName)
|
logging.Debugf("getKubernetesDelegate: found resourceName annotation : %s", resourceName)
|
||||||
|
|
||||||
if resourceMap == nil {
|
if resourceMap == nil {
|
||||||
checkpoint, err := checkpoint.GetCheckpoint()
|
ck, err := kubeletclient.GetResourceClient()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, resourceMap, logging.Errorf("getKubernetesDelegate: failed to get a checkpoint instance: %v", err)
|
return nil, resourceMap, logging.Errorf("getKubernetesDelegate: failed to get a ResourceClient instance: %v", err)
|
||||||
}
|
}
|
||||||
resourceMap, err = checkpoint.GetComputeDeviceMap(podID)
|
resourceMap, err = ck.GetPodResourceMap(pod)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, resourceMap, logging.Errorf("getKubernetesDelegate: failed to get resourceMap from kubelet checkpoint file: %v", err)
|
return nil, resourceMap, logging.Errorf("getKubernetesDelegate: failed to get resourceMap from ResourceClient: %v", err)
|
||||||
}
|
}
|
||||||
logging.Debugf("getKubernetesDelegate(): resourceMap instance: %+v", resourceMap)
|
logging.Debugf("getKubernetesDelegate(): resourceMap instance: %+v", resourceMap)
|
||||||
}
|
}
|
||||||
@ -373,7 +373,7 @@ func getKubernetesDelegate(client KubeClient, net *types.NetworkSelectionElement
|
|||||||
if ok {
|
if ok {
|
||||||
if idCount := len(entry.DeviceIDs); idCount > 0 && idCount > entry.Index {
|
if idCount := len(entry.DeviceIDs); idCount > 0 && idCount > entry.Index {
|
||||||
deviceID = entry.DeviceIDs[entry.Index]
|
deviceID = entry.DeviceIDs[entry.Index]
|
||||||
logging.Debugf("getKubernetesDelegate: podID: %s deviceID: %s", podID, deviceID)
|
logging.Debugf("getKubernetesDelegate: podName: %s deviceID: %s", pod.Name, deviceID)
|
||||||
entry.Index++ // increment Index for next delegate
|
entry.Index++ // increment Index for next delegate
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -536,7 +536,6 @@ func GetNetworkDelegates(k8sclient KubeClient, pod *v1.Pod, networks []*types.Ne
|
|||||||
var delegates []*types.DelegateNetConf
|
var delegates []*types.DelegateNetConf
|
||||||
defaultNamespace := pod.ObjectMeta.Namespace
|
defaultNamespace := pod.ObjectMeta.Namespace
|
||||||
|
|
||||||
podID := pod.UID
|
|
||||||
for _, net := range networks {
|
for _, net := range networks {
|
||||||
|
|
||||||
// The pods namespace (stored as defaultNamespace, does not equal the annotation's target namespace in net.Namespace)
|
// The pods namespace (stored as defaultNamespace, does not equal the annotation's target namespace in net.Namespace)
|
||||||
@ -547,7 +546,7 @@ func GetNetworkDelegates(k8sclient KubeClient, pod *v1.Pod, networks []*types.Ne
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
delegate, updatedResourceMap, err := getKubernetesDelegate(k8sclient, net, confdir, string(podID), resourceMap)
|
delegate, updatedResourceMap, err := getKubernetesDelegate(k8sclient, net, confdir, pod, resourceMap)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, logging.Errorf("GetPodNetwork: failed getting the delegate: %v", err)
|
return nil, logging.Errorf("GetPodNetwork: failed getting the delegate: %v", err)
|
||||||
}
|
}
|
||||||
@ -690,7 +689,7 @@ func tryLoadK8sPodDefaultNetwork(kubeClient KubeClient, pod *v1.Pod, conf *types
|
|||||||
return nil, logging.Errorf("tryLoadK8sPodDefaultNetwork: more than one default network is specified: %s", netAnnot)
|
return nil, logging.Errorf("tryLoadK8sPodDefaultNetwork: more than one default network is specified: %s", netAnnot)
|
||||||
}
|
}
|
||||||
|
|
||||||
delegate, _, err := getKubernetesDelegate(kubeClient, networks[0], conf.ConfDir, "", nil)
|
delegate, _, err := getKubernetesDelegate(kubeClient, networks[0], conf.ConfDir, pod, nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, logging.Errorf("tryLoadK8sPodDefaultNetwork: failed getting the delegate: %v", err)
|
return nil, logging.Errorf("tryLoadK8sPodDefaultNetwork: failed getting the delegate: %v", err)
|
||||||
}
|
}
|
||||||
|
113
kubeletclient/kubeletclient.go
Normal file
113
kubeletclient/kubeletclient.go
Normal file
@ -0,0 +1,113 @@
|
|||||||
|
package kubeletclient
|
||||||
|
|
||||||
|
import (
|
||||||
|
"os"
|
||||||
|
"path/filepath"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/intel/multus-cni/checkpoint"
|
||||||
|
"github.com/intel/multus-cni/logging"
|
||||||
|
"github.com/intel/multus-cni/types"
|
||||||
|
"golang.org/x/net/context"
|
||||||
|
v1 "k8s.io/api/core/v1"
|
||||||
|
"k8s.io/kubernetes/pkg/kubelet/apis/podresources"
|
||||||
|
podresourcesapi "k8s.io/kubernetes/pkg/kubelet/apis/podresources/v1alpha1"
|
||||||
|
"k8s.io/kubernetes/pkg/kubelet/util"
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
defaultKubeletSocketFile = "kubelet.sock"
|
||||||
|
defaultPodResourcesMaxSize = 1024 * 1024 * 16 // 16 Mb
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
kubeletSocket string
|
||||||
|
defaultPodResourcesPath = "/var/lib/kubelet/pod-resources"
|
||||||
|
)
|
||||||
|
|
||||||
|
// GetResourceClient returns an instance of ResourceClient interface initialized with Pod resource information
|
||||||
|
func GetResourceClient() (types.ResourceClient, error) {
|
||||||
|
// If Kubelet resource API endpoint exist use that by default
|
||||||
|
// Or else fallback with checkpoint file
|
||||||
|
if hasKubeletAPIEndpoint() {
|
||||||
|
logging.Printf(logging.VerboseLevel, "GetResourceClient(): using Kubelet resource API endpoint")
|
||||||
|
return getKubeletClient()
|
||||||
|
} else {
|
||||||
|
logging.Printf(logging.VerboseLevel, "GetResourceClient(): using Kubelet device plugin checkpoint")
|
||||||
|
return checkpoint.GetCheckpoint()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func getKubeletClient() (types.ResourceClient, error) {
|
||||||
|
newClient := &kubeletClient{}
|
||||||
|
if kubeletSocket == "" {
|
||||||
|
kubeletSocket = util.LocalEndpoint(defaultPodResourcesPath, podresources.Socket)
|
||||||
|
}
|
||||||
|
|
||||||
|
client, conn, err := podresources.GetClient(kubeletSocket, 10*time.Second, defaultPodResourcesMaxSize)
|
||||||
|
if err != nil {
|
||||||
|
return nil, logging.Errorf("GetResourceClient(): error getting grpc client: %v\n", err)
|
||||||
|
}
|
||||||
|
defer conn.Close()
|
||||||
|
|
||||||
|
if err := newClient.getPodResources(client); err != nil {
|
||||||
|
return nil, logging.Errorf("GetResourceClient(): error getting resource client: %v\n", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return newClient, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
type kubeletClient struct {
|
||||||
|
resources []*podresourcesapi.PodResources
|
||||||
|
}
|
||||||
|
|
||||||
|
func (rc *kubeletClient) getPodResources(client podresourcesapi.PodResourcesListerClient) error {
|
||||||
|
|
||||||
|
ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
|
||||||
|
defer cancel()
|
||||||
|
|
||||||
|
resp, err := client.List(ctx, &podresourcesapi.ListPodResourcesRequest{})
|
||||||
|
if err != nil {
|
||||||
|
return logging.Errorf("getPodResources(): %v.Get(_) = _, %v", client, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
rc.resources = resp.PodResources
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetPodResourceMap returns an instance of a map of Pod ResourceInfo given a (Pod name, namespace) tuple
|
||||||
|
func (rc *kubeletClient) GetPodResourceMap(pod *v1.Pod) (map[string]*types.ResourceInfo, error) {
|
||||||
|
resourceMap := make(map[string]*types.ResourceInfo)
|
||||||
|
|
||||||
|
name := pod.Name
|
||||||
|
ns := pod.Namespace
|
||||||
|
|
||||||
|
if name == "" || ns == "" {
|
||||||
|
return nil, logging.Errorf("GetPodResourcesMap(): Pod name or namespace cannot be empty")
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, pr := range rc.resources {
|
||||||
|
if pr.Name == name && pr.Namespace == ns {
|
||||||
|
for _, cnt := range pr.Containers {
|
||||||
|
for _, dev := range cnt.Devices {
|
||||||
|
if rInfo, ok := resourceMap[dev.ResourceName]; ok {
|
||||||
|
rInfo.DeviceIDs = append(rInfo.DeviceIDs, dev.DeviceIds...)
|
||||||
|
} else {
|
||||||
|
resourceMap[dev.ResourceName] = &types.ResourceInfo{DeviceIDs: dev.DeviceIds}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return resourceMap, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func hasKubeletAPIEndpoint() bool {
|
||||||
|
// Check for kubelet resource API socket file
|
||||||
|
kubeletAPISocket := filepath.Join(defaultPodResourcesPath, defaultKubeletSocketFile)
|
||||||
|
if _, err := os.Stat(kubeletAPISocket); err != nil {
|
||||||
|
logging.Verbosef("hasKubeletAPIEndpoint(): error looking up kubelet resource api socket file: %q", err)
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
}
|
209
kubeletclient/kubeletclient_test.go
Normal file
209
kubeletclient/kubeletclient_test.go
Normal file
@ -0,0 +1,209 @@
|
|||||||
|
package kubeletclient
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"io/ioutil"
|
||||||
|
"os"
|
||||||
|
"path/filepath"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
. "github.com/onsi/ginkgo"
|
||||||
|
. "github.com/onsi/gomega"
|
||||||
|
"google.golang.org/grpc"
|
||||||
|
v1 "k8s.io/api/core/v1"
|
||||||
|
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||||
|
k8sTypes "k8s.io/apimachinery/pkg/types"
|
||||||
|
"k8s.io/kubernetes/pkg/kubelet/util"
|
||||||
|
|
||||||
|
mtypes "github.com/intel/multus-cni/types"
|
||||||
|
podresourcesapi "k8s.io/kubernetes/pkg/kubelet/apis/podresources/v1alpha1"
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
socketDir string
|
||||||
|
socketName string
|
||||||
|
fakeServer *fakeResourceServer
|
||||||
|
)
|
||||||
|
|
||||||
|
type fakeResourceServer struct {
|
||||||
|
server *grpc.Server
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *fakeResourceServer) List(ctx context.Context, req *podresourcesapi.ListPodResourcesRequest) (*podresourcesapi.ListPodResourcesResponse, error) {
|
||||||
|
podName := "pod-name"
|
||||||
|
podNamespace := "pod-namespace"
|
||||||
|
containerName := "container-name"
|
||||||
|
|
||||||
|
devs := []*podresourcesapi.ContainerDevices{
|
||||||
|
{
|
||||||
|
ResourceName: "resource",
|
||||||
|
DeviceIds: []string{"dev0", "dev1"},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
resp := &podresourcesapi.ListPodResourcesResponse{
|
||||||
|
PodResources: []*podresourcesapi.PodResources{
|
||||||
|
{
|
||||||
|
Name: podName,
|
||||||
|
Namespace: podNamespace,
|
||||||
|
Containers: []*podresourcesapi.ContainerResources{
|
||||||
|
{
|
||||||
|
Name: containerName,
|
||||||
|
Devices: devs,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
return resp, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestKubeletclient(t *testing.T) {
|
||||||
|
RegisterFailHandler(Fail)
|
||||||
|
RunSpecs(t, "Kubeletclient Suite")
|
||||||
|
}
|
||||||
|
|
||||||
|
func setUp() error {
|
||||||
|
tempSocketDir, err := ioutil.TempDir("", "kubelet-resource-client")
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
defaultPodResourcesPath = filepath.Join(tempSocketDir, defaultPodResourcesPath)
|
||||||
|
|
||||||
|
if err := os.MkdirAll(defaultPodResourcesPath, os.ModeDir); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
socketDir = defaultPodResourcesPath
|
||||||
|
socketName = filepath.Join(socketDir, "kubelet.sock")
|
||||||
|
|
||||||
|
fakeServer = &fakeResourceServer{server: grpc.NewServer()}
|
||||||
|
podresourcesapi.RegisterPodResourcesListerServer(fakeServer.server, fakeServer)
|
||||||
|
lis, err := util.CreateListener(socketName)
|
||||||
|
if err != nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
go fakeServer.server.Serve(lis)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func tearDown(path string) error {
|
||||||
|
if fakeServer != nil {
|
||||||
|
fakeServer.server.Stop()
|
||||||
|
}
|
||||||
|
if err := os.RemoveAll(path); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
var _ = BeforeSuite(func() {
|
||||||
|
err := setUp()
|
||||||
|
Expect(err).NotTo(HaveOccurred())
|
||||||
|
})
|
||||||
|
|
||||||
|
var _ = AfterSuite(func() {
|
||||||
|
err := tearDown(socketDir)
|
||||||
|
Expect(err).NotTo(HaveOccurred())
|
||||||
|
})
|
||||||
|
|
||||||
|
var _ = Describe("Kubelet resource endpoint data read operations", func() {
|
||||||
|
|
||||||
|
Context("GetResourceClient()", func() {
|
||||||
|
It("should return no error", func() {
|
||||||
|
kubeletSocket = socketName
|
||||||
|
_, err := GetResourceClient()
|
||||||
|
Expect(err).NotTo(HaveOccurred())
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
Context("GetPodResourceMap() with valid pod name and namespace", func() {
|
||||||
|
It("should return no error", func() {
|
||||||
|
podUID := k8sTypes.UID("970a395d-bb3b-11e8-89df-408d5c537d23")
|
||||||
|
fakePod := &v1.Pod{
|
||||||
|
ObjectMeta: metav1.ObjectMeta{
|
||||||
|
Name: "pod-name",
|
||||||
|
Namespace: "pod-namespace",
|
||||||
|
UID: podUID,
|
||||||
|
},
|
||||||
|
Spec: v1.PodSpec{
|
||||||
|
Containers: []v1.Container{
|
||||||
|
{
|
||||||
|
Name: "container-name",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
kubeletSocket = socketName
|
||||||
|
client, err := getKubeletClient()
|
||||||
|
Expect(err).NotTo(HaveOccurred())
|
||||||
|
|
||||||
|
outputRMap := map[string]*mtypes.ResourceInfo{
|
||||||
|
"resource": &mtypes.ResourceInfo{DeviceIDs: []string{"dev0", "dev1"}},
|
||||||
|
}
|
||||||
|
resourceMap, err := client.GetPodResourceMap(fakePod)
|
||||||
|
Expect(err).NotTo(HaveOccurred())
|
||||||
|
Expect(resourceMap).ShouldNot(BeNil())
|
||||||
|
Expect(resourceMap).To(Equal(outputRMap))
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
Context("GetPodResourceMap() with empty podname", func() {
|
||||||
|
It("should return error", func() {
|
||||||
|
podUID := k8sTypes.UID("970a395d-bb3b-11e8-89df-408d5c537d23")
|
||||||
|
fakePod := &v1.Pod{
|
||||||
|
ObjectMeta: metav1.ObjectMeta{
|
||||||
|
Name: "",
|
||||||
|
Namespace: "pod-namespace",
|
||||||
|
UID: podUID,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
kubeletSocket = socketName
|
||||||
|
client, err := getKubeletClient()
|
||||||
|
Expect(err).NotTo(HaveOccurred())
|
||||||
|
_, err = client.GetPodResourceMap(fakePod)
|
||||||
|
Expect(err).To(HaveOccurred())
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
Context("GetPodResourceMap() with empty namespace", func() {
|
||||||
|
It("should return error", func() {
|
||||||
|
podUID := k8sTypes.UID("970a395d-bb3b-11e8-89df-408d5c537d23")
|
||||||
|
fakePod := &v1.Pod{
|
||||||
|
ObjectMeta: metav1.ObjectMeta{
|
||||||
|
Name: "pod-name",
|
||||||
|
Namespace: "",
|
||||||
|
UID: podUID,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
kubeletSocket = socketName
|
||||||
|
client, err := getKubeletClient()
|
||||||
|
Expect(err).NotTo(HaveOccurred())
|
||||||
|
_, err = client.GetPodResourceMap(fakePod)
|
||||||
|
Expect(err).To(HaveOccurred())
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
Context("GetPodResourceMap() with non-existent podname and namespace", func() {
|
||||||
|
It("should return no error", func() {
|
||||||
|
podUID := k8sTypes.UID("970a395d-bb3b-11e8-89df-408d5c537d23")
|
||||||
|
fakePod := &v1.Pod{
|
||||||
|
ObjectMeta: metav1.ObjectMeta{
|
||||||
|
Name: "whateverpod",
|
||||||
|
Namespace: "whatevernamespace",
|
||||||
|
UID: podUID,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
kubeletSocket = socketName
|
||||||
|
client, err := getKubeletClient()
|
||||||
|
Expect(err).NotTo(HaveOccurred())
|
||||||
|
|
||||||
|
emptyRMap := map[string]*mtypes.ResourceInfo{}
|
||||||
|
resourceMap, err := client.GetPodResourceMap(fakePod)
|
||||||
|
Expect(err).NotTo(HaveOccurred())
|
||||||
|
Expect(resourceMap).ShouldNot(BeNil())
|
||||||
|
Expect(resourceMap).To(Equal(emptyRMap))
|
||||||
|
})
|
||||||
|
})
|
||||||
|
})
|
@ -20,6 +20,7 @@ import (
|
|||||||
|
|
||||||
"github.com/containernetworking/cni/pkg/types"
|
"github.com/containernetworking/cni/pkg/types"
|
||||||
"github.com/containernetworking/cni/pkg/types/current"
|
"github.com/containernetworking/cni/pkg/types/current"
|
||||||
|
v1 "k8s.io/api/core/v1"
|
||||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -50,9 +51,9 @@ type NetConf struct {
|
|||||||
// Option to isolate the usage of CR's to the namespace in which a pod resides.
|
// Option to isolate the usage of CR's to the namespace in which a pod resides.
|
||||||
NamespaceIsolation bool `json:"namespaceIsolation"`
|
NamespaceIsolation bool `json:"namespaceIsolation"`
|
||||||
// Option to set system namespaces (to avoid to add defaultNetworks)
|
// Option to set system namespaces (to avoid to add defaultNetworks)
|
||||||
SystemNamespaces []string `json:"systemNamespaces"`
|
SystemNamespaces []string `json:"systemNamespaces"`
|
||||||
// Option to set the namespace that multus-cni uses (clusterNetwork/defaultNetworks)
|
// Option to set the namespace that multus-cni uses (clusterNetwork/defaultNetworks)
|
||||||
MultusNamespace string `json:"multusNamespace"`
|
MultusNamespace string `json:"multusNamespace"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type RuntimeConfig struct {
|
type RuntimeConfig struct {
|
||||||
@ -149,3 +150,9 @@ type ResourceInfo struct {
|
|||||||
Index int
|
Index int
|
||||||
DeviceIDs []string
|
DeviceIDs []string
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ResourceClient provides a kubelet Pod resource handle
|
||||||
|
type ResourceClient interface {
|
||||||
|
// GetPodResourceMap returns an instance of a map of Pod ResourceInfo given a (Pod name, namespace) tuple
|
||||||
|
GetPodResourceMap(*v1.Pod) (map[string]*ResourceInfo, error)
|
||||||
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user