mirror of
https://github.com/k8snetworkplumbingwg/multus-cni.git
synced 2025-08-11 21:14:34 +00:00
add support for Dynamic Resource Allocation
Signed-off-by: Moshe Levi <moshele@nvidia.com>
This commit is contained in:
parent
b6206a0dbf
commit
40378cabd3
@ -21,6 +21,7 @@ import (
|
|||||||
"net/url"
|
"net/url"
|
||||||
"os"
|
"os"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"golang.org/x/net/context"
|
"golang.org/x/net/context"
|
||||||
@ -137,19 +138,45 @@ func (rc *kubeletClient) GetPodResourceMap(pod *v1.Pod) (map[string]*types.Resou
|
|||||||
for _, pr := range rc.resources {
|
for _, pr := range rc.resources {
|
||||||
if pr.Name == name && pr.Namespace == ns {
|
if pr.Name == name && pr.Namespace == ns {
|
||||||
for _, cnt := range pr.Containers {
|
for _, cnt := range pr.Containers {
|
||||||
for _, dev := range cnt.Devices {
|
rc.getDevicePluginResources(cnt.Devices, resourceMap)
|
||||||
if rInfo, ok := resourceMap[dev.ResourceName]; ok {
|
rc.getDRAResources(cnt.DynamicResources, resourceMap)
|
||||||
rInfo.DeviceIDs = append(rInfo.DeviceIDs, dev.DeviceIds...)
|
|
||||||
} else {
|
|
||||||
resourceMap[dev.ResourceName] = &types.ResourceInfo{DeviceIDs: dev.DeviceIds}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return resourceMap, nil
|
return resourceMap, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (rc *kubeletClient) getDevicePluginResources(devices []*podresourcesapi.ContainerDevices, resourceMap map[string]*types.ResourceInfo) {
|
||||||
|
for _, dev := range devices {
|
||||||
|
if rInfo, ok := resourceMap[dev.ResourceName]; ok {
|
||||||
|
rInfo.DeviceIDs = append(rInfo.DeviceIDs, dev.DeviceIds...)
|
||||||
|
} else {
|
||||||
|
resourceMap[dev.ResourceName] = &types.ResourceInfo{DeviceIDs: dev.DeviceIds}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (rc *kubeletClient) getDRAResources(dynamicResources []*podresourcesapi.DynamicResource, resourceMap map[string]*types.ResourceInfo) {
|
||||||
|
for _, dynamicResource := range dynamicResources {
|
||||||
|
var deviceIDs []string
|
||||||
|
for _, claimResource := range dynamicResource.ClaimResources {
|
||||||
|
for _, cdiDevice := range claimResource.CDIDevices {
|
||||||
|
res := strings.Split(cdiDevice.Name, "=")
|
||||||
|
if len(res) == 2 {
|
||||||
|
deviceIDs = append(deviceIDs, res[1])
|
||||||
|
} else {
|
||||||
|
logging.Errorf("GetPodResourceMap: Invalid CDI format")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if rInfo, ok := resourceMap[dynamicResource.ClassName]; ok {
|
||||||
|
rInfo.DeviceIDs = append(rInfo.DeviceIDs, deviceIDs...)
|
||||||
|
} else {
|
||||||
|
resourceMap[dynamicResource.ClassName] = &types.ResourceInfo{DeviceIDs: deviceIDs}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func hasKubeletAPIEndpoint(url *url.URL) bool {
|
func hasKubeletAPIEndpoint(url *url.URL) bool {
|
||||||
// Check for kubelet resource API socket file
|
// Check for kubelet resource API socket file
|
||||||
if _, err := os.Stat(url.Path); err != nil {
|
if _, err := os.Stat(url.Path); err != nil {
|
||||||
|
@ -60,10 +60,6 @@ func (m *fakeResourceServer) Get(_ context.Context, _ *podresourcesapi.GetPodRes
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (m *fakeResourceServer) List(_ context.Context, _ *podresourcesapi.ListPodResourcesRequest) (*podresourcesapi.ListPodResourcesResponse, error) {
|
func (m *fakeResourceServer) List(_ context.Context, _ *podresourcesapi.ListPodResourcesRequest) (*podresourcesapi.ListPodResourcesResponse, error) {
|
||||||
podName := "pod-name"
|
|
||||||
podNamespace := "pod-namespace"
|
|
||||||
containerName := "container-name"
|
|
||||||
|
|
||||||
devs := []*podresourcesapi.ContainerDevices{
|
devs := []*podresourcesapi.ContainerDevices{
|
||||||
{
|
{
|
||||||
ResourceName: "resource",
|
ResourceName: "resource",
|
||||||
@ -71,18 +67,49 @@ func (m *fakeResourceServer) List(_ context.Context, _ *podresourcesapi.ListPodR
|
|||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
cdiDevices := []*podresourcesapi.CDIDevice{
|
||||||
|
{
|
||||||
|
Name: "cdi-kind=cdi-resource",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
claimsResource := []*podresourcesapi.ClaimResource{
|
||||||
|
{
|
||||||
|
CDIDevices: cdiDevices,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
dynamicResources := []*podresourcesapi.DynamicResource{
|
||||||
|
{
|
||||||
|
ClassName: "resource-class",
|
||||||
|
ClaimName: "resource-claim",
|
||||||
|
ClaimNamespace: "dynamic-resource-pod-namespace",
|
||||||
|
ClaimResources: claimsResource,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
resp := &podresourcesapi.ListPodResourcesResponse{
|
resp := &podresourcesapi.ListPodResourcesResponse{
|
||||||
PodResources: []*podresourcesapi.PodResources{
|
PodResources: []*podresourcesapi.PodResources{
|
||||||
{
|
{
|
||||||
Name: podName,
|
Name: "pod-name",
|
||||||
Namespace: podNamespace,
|
Namespace: "pod-namespace",
|
||||||
Containers: []*podresourcesapi.ContainerResources{
|
Containers: []*podresourcesapi.ContainerResources{
|
||||||
{
|
{
|
||||||
Name: containerName,
|
Name: "container-name",
|
||||||
Devices: devs,
|
Devices: devs,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
Name: "dynamic-resource-pod-name",
|
||||||
|
Namespace: "dynamic-resource-pod-namespace",
|
||||||
|
Containers: []*podresourcesapi.ContainerResources{
|
||||||
|
{
|
||||||
|
Name: "dynamic-resource-container-name",
|
||||||
|
DynamicResources: dynamicResources,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
return resp, nil
|
return resp, nil
|
||||||
@ -188,7 +215,7 @@ var _ = Describe("Kubelet resource endpoint data read operations", func() {
|
|||||||
})
|
})
|
||||||
})
|
})
|
||||||
Context("GetPodResourceMap() with valid pod name and namespace", func() {
|
Context("GetPodResourceMap() with valid pod name and namespace", func() {
|
||||||
It("should return no error", func() {
|
It("should return no error with device plugin resource", func() {
|
||||||
podUID := k8sTypes.UID("970a395d-bb3b-11e8-89df-408d5c537d23")
|
podUID := k8sTypes.UID("970a395d-bb3b-11e8-89df-408d5c537d23")
|
||||||
fakePod := &v1.Pod{
|
fakePod := &v1.Pod{
|
||||||
ObjectMeta: metav1.ObjectMeta{
|
ObjectMeta: metav1.ObjectMeta{
|
||||||
@ -216,6 +243,34 @@ var _ = Describe("Kubelet resource endpoint data read operations", func() {
|
|||||||
Expect(resourceMap).To(Equal(outputRMap))
|
Expect(resourceMap).To(Equal(outputRMap))
|
||||||
})
|
})
|
||||||
|
|
||||||
|
It("should return no error with dynamic resource", func() {
|
||||||
|
podUID := k8sTypes.UID("9f94e27b-4233-43d6-bd10-f73b4de6f456")
|
||||||
|
fakePod := &v1.Pod{
|
||||||
|
ObjectMeta: metav1.ObjectMeta{
|
||||||
|
Name: "dynamic-resource-pod-name",
|
||||||
|
Namespace: "dynamic-resource-pod-namespace",
|
||||||
|
UID: podUID,
|
||||||
|
},
|
||||||
|
Spec: v1.PodSpec{
|
||||||
|
Containers: []v1.Container{
|
||||||
|
{
|
||||||
|
Name: "dynamic-resource-container-name",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
client, err := getKubeletClient(testKubeletSocket)
|
||||||
|
Expect(err).NotTo(HaveOccurred())
|
||||||
|
|
||||||
|
outputRMap := map[string]*mtypes.ResourceInfo{
|
||||||
|
"resource-class": {DeviceIDs: []string{"cdi-resource"}},
|
||||||
|
}
|
||||||
|
resourceMap, err := client.GetPodResourceMap(fakePod)
|
||||||
|
Expect(err).NotTo(HaveOccurred())
|
||||||
|
Expect(resourceMap).ShouldNot(BeNil())
|
||||||
|
Expect(resourceMap).To(Equal(outputRMap))
|
||||||
|
})
|
||||||
|
|
||||||
It("should return an error with garbage socket value", func() {
|
It("should return an error with garbage socket value", func() {
|
||||||
u, err := url.Parse("/badfilepath!?//")
|
u, err := url.Parse("/badfilepath!?//")
|
||||||
Expect(err).NotTo(HaveOccurred())
|
Expect(err).NotTo(HaveOccurred())
|
||||||
|
Loading…
Reference in New Issue
Block a user