mirror of
https://github.com/k8snetworkplumbingwg/multus-cni.git
synced 2025-08-19 00:33:27 +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/types"
|
||||
v1 "k8s.io/api/core/v1"
|
||||
)
|
||||
|
||||
const (
|
||||
@ -45,22 +46,18 @@ type Data struct {
|
||||
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 {
|
||||
fileName string
|
||||
podEntires []PodDevicesEntry
|
||||
}
|
||||
|
||||
// GetCheckpoint returns an instance of Checkpoint
|
||||
func GetCheckpoint() (Checkpoint, error) {
|
||||
func GetCheckpoint() (types.ResourceClient, error) {
|
||||
logging.Debugf("GetCheckpoint(): invoked")
|
||||
return getCheckpoint(checkPointfile)
|
||||
}
|
||||
|
||||
func getCheckpoint(filePath string) (Checkpoint, error) {
|
||||
func getCheckpoint(filePath string) (types.ResourceClient, error) {
|
||||
cp := &checkpoint{fileName: filePath}
|
||||
err := cp.getPodEntries()
|
||||
if err != nil {
|
||||
@ -89,12 +86,12 @@ func (cp *checkpoint) getPodEntries() error {
|
||||
}
|
||||
|
||||
// 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)
|
||||
|
||||
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 {
|
||||
|
@ -10,6 +10,9 @@ import (
|
||||
"testing"
|
||||
|
||||
"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 (
|
||||
@ -74,7 +77,7 @@ var _ = BeforeSuite(func() {
|
||||
var _ = Describe("Kubelet checkpoint data read operations", func() {
|
||||
Context("Using /tmp/kubelet_internal_checkpoint file", func() {
|
||||
var (
|
||||
cp Checkpoint
|
||||
cp types.ResourceClient
|
||||
err error
|
||||
resourceMap map[string]*types.ResourceInfo
|
||||
resourceInfo *types.ResourceInfo
|
||||
@ -87,7 +90,15 @@ var _ = Describe("Kubelet checkpoint data read operations", 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(rmap).NotTo(BeEmpty())
|
||||
resourceMap = rmap
|
||||
|
64
glide.lock
generated
64
glide.lock
generated
@ -1,13 +1,11 @@
|
||||
hash: 0c4ea2a342364d2ff3b43242730cb3b1db3b7e8456f6cf43da3c51dbb67e18da
|
||||
updated: 2018-07-27T03:29:02.093332104+01:00
|
||||
hash: 4288149814e91e63396f7874b87151aca74047110f0d1f43027b60dd6014988f
|
||||
updated: 2019-01-09T10:19:29.688011713Z
|
||||
imports:
|
||||
- name: github.com/containernetworking/cni
|
||||
version: 07c1a6da47b7fbf8b357f4949ecce2113e598491
|
||||
subpackages:
|
||||
- libcni
|
||||
- pkg/invoke
|
||||
- pkg/ip
|
||||
- pkg/ipam
|
||||
- pkg/skel
|
||||
- pkg/types
|
||||
- pkg/types/020
|
||||
@ -16,6 +14,8 @@ imports:
|
||||
- name: github.com/containernetworking/plugins
|
||||
version: 2b8b1ac0af4568e928d96ccc5f47b075416eeabd
|
||||
subpackages:
|
||||
- pkg/ip
|
||||
- pkg/ipam
|
||||
- pkg/ns
|
||||
- pkg/testutils
|
||||
- name: github.com/ghodss/yaml
|
||||
@ -23,7 +23,9 @@ imports:
|
||||
- name: github.com/gogo/protobuf
|
||||
version: c0656edd0d9eab7c66d1eb0c568f9039345796f7
|
||||
subpackages:
|
||||
- gogoproto
|
||||
- proto
|
||||
- protoc-gen-gogo/descriptor
|
||||
- sortkeys
|
||||
- name: github.com/golang/glog
|
||||
version: 44145f04b68cf362d9c4df2182967c2275eaefed
|
||||
@ -53,6 +55,8 @@ imports:
|
||||
version: 6633656539c1639d9d78127b7d47c622b5d7b6dc
|
||||
- name: github.com/json-iterator/go
|
||||
version: f2b4162afba35581b6d4a50d3b8f34e33c144682
|
||||
- name: github.com/Microsoft/go-winio
|
||||
version: 78439966b38d69bf38227fbf57ac8a6fee70f69a
|
||||
- name: github.com/modern-go/concurrent
|
||||
version: bacd9c7ef1dd9b15be4a9909b8ac7a4e313eec94
|
||||
- name: github.com/modern-go/reflect2
|
||||
@ -61,6 +65,7 @@ imports:
|
||||
version: 7f8ab55aaf3b86885aa55b762e803744d1674700
|
||||
subpackages:
|
||||
- config
|
||||
- extensions/table
|
||||
- internal/codelocation
|
||||
- internal/containernode
|
||||
- internal/failer
|
||||
@ -91,15 +96,15 @@ imports:
|
||||
- name: github.com/peterbourgon/diskv
|
||||
version: 5f041e8faa004a95c88a202771f4cc3e991971e6
|
||||
- name: github.com/pkg/errors
|
||||
version: 816c9085562cd7ee03e7f8188a1cfd942858cded
|
||||
version: ffb6e22f01932bf7ac35e0bad9be11f01d1c8685
|
||||
- name: github.com/spf13/pflag
|
||||
version: 583c0c0531f06d5278b7d917446061adc344b5cd
|
||||
- name: github.com/vishvananda/netlink
|
||||
version: 6e453822d85ef5721799774b654d4d02fed62afb
|
||||
version: b2de5d10e38ecce8607e6b438b6d174f389a004e
|
||||
subpackages:
|
||||
- nl
|
||||
- name: github.com/vishvananda/netns
|
||||
version: 54f0e4339ce73702a0607f49922aaa1e749b418d
|
||||
version: be1fbeda19366dea804f00efff2dd73a1642fdcc
|
||||
- name: golang.org/x/crypto
|
||||
version: 49796115aa4b964c318aad4f3084fdb41e9aa067
|
||||
subpackages:
|
||||
@ -111,7 +116,9 @@ imports:
|
||||
- http2
|
||||
- http2/hpack
|
||||
- idna
|
||||
- internal/timeseries
|
||||
- lex/httplex
|
||||
- trace
|
||||
- name: golang.org/x/sys
|
||||
version: 95c6576299259db960f6c5b9b69ea52422860fce
|
||||
subpackages:
|
||||
@ -128,6 +135,40 @@ imports:
|
||||
version: f51c12702a4d776e4c1fa9b0fabab841babae631
|
||||
subpackages:
|
||||
- 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
|
||||
version: 3887ee99ecf07df5b447e9b00d9c0b2adaa9f3e4
|
||||
- name: gopkg.in/yaml.v2
|
||||
@ -135,6 +176,7 @@ imports:
|
||||
- name: k8s.io/api
|
||||
version: 2d6f90ab1293a1fb871cf149423ebb72aa7423aa
|
||||
subpackages:
|
||||
- admission/v1beta1
|
||||
- admissionregistration/v1alpha1
|
||||
- admissionregistration/v1beta1
|
||||
- apps/v1
|
||||
@ -258,4 +300,12 @@ imports:
|
||||
- util/homedir
|
||||
- util/integer
|
||||
- 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: []
|
||||
|
@ -32,5 +32,11 @@ import:
|
||||
- kubernetes
|
||||
- tools/clientcmd
|
||||
- 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/pkg/errors
|
||||
|
@ -31,7 +31,7 @@ import (
|
||||
"github.com/containernetworking/cni/libcni"
|
||||
"github.com/containernetworking/cni/pkg/skel"
|
||||
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/types"
|
||||
)
|
||||
@ -336,7 +336,7 @@ func cniConfigFromNetworkResource(customResource *types.NetworkAttachmentDefinit
|
||||
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)
|
||||
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
|
||||
deviceID := ""
|
||||
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
|
||||
logging.Debugf("getKubernetesDelegate: found resourceName annotation : %s", resourceName)
|
||||
|
||||
if resourceMap == nil {
|
||||
checkpoint, err := checkpoint.GetCheckpoint()
|
||||
ck, err := kubeletclient.GetResourceClient()
|
||||
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 {
|
||||
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)
|
||||
}
|
||||
@ -373,7 +373,7 @@ func getKubernetesDelegate(client KubeClient, net *types.NetworkSelectionElement
|
||||
if ok {
|
||||
if idCount := len(entry.DeviceIDs); idCount > 0 && idCount > 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
|
||||
}
|
||||
}
|
||||
@ -536,7 +536,6 @@ func GetNetworkDelegates(k8sclient KubeClient, pod *v1.Pod, networks []*types.Ne
|
||||
var delegates []*types.DelegateNetConf
|
||||
defaultNamespace := pod.ObjectMeta.Namespace
|
||||
|
||||
podID := pod.UID
|
||||
for _, net := range networks {
|
||||
|
||||
// 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 {
|
||||
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)
|
||||
}
|
||||
|
||||
delegate, _, err := getKubernetesDelegate(kubeClient, networks[0], conf.ConfDir, "", nil)
|
||||
delegate, _, err := getKubernetesDelegate(kubeClient, networks[0], conf.ConfDir, pod, nil)
|
||||
if err != nil {
|
||||
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/current"
|
||||
v1 "k8s.io/api/core/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.
|
||||
NamespaceIsolation bool `json:"namespaceIsolation"`
|
||||
// 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)
|
||||
MultusNamespace string `json:"multusNamespace"`
|
||||
MultusNamespace string `json:"multusNamespace"`
|
||||
}
|
||||
|
||||
type RuntimeConfig struct {
|
||||
@ -149,3 +150,9 @@ type ResourceInfo struct {
|
||||
Index int
|
||||
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