mirror of
https://github.com/k3s-io/kubernetes.git
synced 2025-07-28 14:07:14 +00:00
kubelet: add GetHostIDsForPod()
In future commits we will need this to set the user/group of supported volumes of KEP 127 - Phase 1. Signed-off-by: Rodrigo Campos <rodrigoca@microsoft.com>
This commit is contained in:
parent
9b2fc639a0
commit
d07c2688fe
@ -819,6 +819,10 @@ func (adc *attachDetachController) GetPodVolumeDir(podUID types.UID, pluginName,
|
|||||||
return ""
|
return ""
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (adc *attachDetachController) GetHostIDsForPod(pod *v1.Pod, containerUID, containerGID *int64) (hostUID, hostGID *int64, err error) {
|
||||||
|
return nil, nil, nil
|
||||||
|
}
|
||||||
|
|
||||||
func (adc *attachDetachController) GetPodPluginDir(podUID types.UID, pluginName string) string {
|
func (adc *attachDetachController) GetPodPluginDir(podUID types.UID, pluginName string) string {
|
||||||
return ""
|
return ""
|
||||||
}
|
}
|
||||||
|
@ -394,6 +394,10 @@ func (expc *expandController) GetPodsDir() string {
|
|||||||
return ""
|
return ""
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (expc *expandController) GetHostIDsForPod(pod *v1.Pod, containerUID, containerGID *int64) (hostUID, hostGID *int64, err error) {
|
||||||
|
return nil, nil, nil
|
||||||
|
}
|
||||||
|
|
||||||
func (expc *expandController) GetPodVolumeDir(podUID types.UID, pluginName string, volumeName string) string {
|
func (expc *expandController) GetPodVolumeDir(podUID types.UID, pluginName string, volumeName string) string {
|
||||||
return ""
|
return ""
|
||||||
}
|
}
|
||||||
|
@ -55,6 +55,10 @@ func (ctrl *PersistentVolumeController) GetPodVolumeDir(podUID types.UID, plugin
|
|||||||
return ""
|
return ""
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (ctrl *PersistentVolumeController) GetHostIDsForPod(pod *v1.Pod, containerUID, containerGID *int64) (hostUID, hostGID *int64, err error) {
|
||||||
|
return nil, nil, nil
|
||||||
|
}
|
||||||
|
|
||||||
func (ctrl *PersistentVolumeController) GetPodPluginDir(podUID types.UID, pluginName string) string {
|
func (ctrl *PersistentVolumeController) GetPodPluginDir(podUID types.UID, pluginName string) string {
|
||||||
return ""
|
return ""
|
||||||
}
|
}
|
||||||
|
@ -425,6 +425,10 @@ func (kl *Kubelet) GetOrCreateUserNamespaceMappings(pod *v1.Pod) (*runtimeapi.Us
|
|||||||
return kl.usernsManager.GetOrCreateUserNamespaceMappings(pod)
|
return kl.usernsManager.GetOrCreateUserNamespaceMappings(pod)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (kl *Kubelet) getHostIDsForPod(pod *v1.Pod, containerUID, containerGID *int64) (hostUID, hostGID *int64, err error) {
|
||||||
|
return kl.usernsManager.getHostIDsForPod(pod, containerUID, containerGID)
|
||||||
|
}
|
||||||
|
|
||||||
// GeneratePodHostNameAndDomain creates a hostname and domain name for a pod,
|
// GeneratePodHostNameAndDomain creates a hostname and domain name for a pod,
|
||||||
// given that pod's spec and annotations or returns an error.
|
// given that pod's spec and annotations or returns an error.
|
||||||
func (kl *Kubelet) GeneratePodHostNameAndDomain(pod *v1.Pod) (string, string, error) {
|
func (kl *Kubelet) GeneratePodHostNameAndDomain(pod *v1.Pod) (string, string, error) {
|
||||||
|
@ -528,3 +528,68 @@ func (m *usernsManager) CleanupOrphanedPodUsernsAllocations(pods []*v1.Pod, runn
|
|||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// getHostIDsForPod if the pod uses user namespaces, takes the uid and gid
|
||||||
|
// inside the container and returns the host UID and GID those are mapped to on
|
||||||
|
// the host. If containerUID/containerGID is nil, then it returns the host
|
||||||
|
// UID/GID for ID 0 inside the container.
|
||||||
|
// If the pod is not using user namespaces, as there is no mapping needed, the
|
||||||
|
// same containerUID and containerGID params are returned.
|
||||||
|
func (m *usernsManager) getHostIDsForPod(pod *v1.Pod, containerUID, containerGID *int64) (hostUID, hostGID *int64, err error) {
|
||||||
|
if !utilfeature.DefaultFeatureGate.Enabled(features.UserNamespacesStatelessPodsSupport) {
|
||||||
|
return containerUID, containerGID, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
if pod == nil || pod.Spec.HostUsers == nil || *pod.Spec.HostUsers == true {
|
||||||
|
return containerUID, containerGID, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
mapping, err := m.GetOrCreateUserNamespaceMappings(pod)
|
||||||
|
if err != nil {
|
||||||
|
err = fmt.Errorf("Error getting pod user namespace mapping: %w", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
uid, err := hostIDFromMapping(mapping.Uids, containerUID)
|
||||||
|
if err != nil {
|
||||||
|
err = fmt.Errorf("Error getting host UID: %w", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
gid, err := hostIDFromMapping(mapping.Gids, containerGID)
|
||||||
|
if err != nil {
|
||||||
|
err = fmt.Errorf("Error getting host GID: %w", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
return &uid, &gid, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func hostIDFromMapping(mapping []*runtimeapi.IDMapping, containerId *int64) (int64, error) {
|
||||||
|
if len(mapping) == 0 {
|
||||||
|
return 0, fmt.Errorf("can't use empty user namespace mapping")
|
||||||
|
}
|
||||||
|
|
||||||
|
// If none is requested, root inside the container is used
|
||||||
|
id := int64(0)
|
||||||
|
if containerId != nil {
|
||||||
|
id = *containerId
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, m := range mapping {
|
||||||
|
if m == nil {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
firstId := int64(m.ContainerId)
|
||||||
|
lastId := firstId + int64(m.Length) - 1
|
||||||
|
|
||||||
|
// The id we are looking for is in the range
|
||||||
|
if id >= firstId && id <= lastId {
|
||||||
|
// Return the host id for this container id
|
||||||
|
return int64(m.HostId) + id - firstId, nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0, fmt.Errorf("ID: %v not present in pod user namespace", id)
|
||||||
|
}
|
||||||
|
@ -25,6 +25,7 @@ import (
|
|||||||
"k8s.io/apimachinery/pkg/types"
|
"k8s.io/apimachinery/pkg/types"
|
||||||
utilfeature "k8s.io/apiserver/pkg/util/feature"
|
utilfeature "k8s.io/apiserver/pkg/util/feature"
|
||||||
featuregatetesting "k8s.io/component-base/featuregate/testing"
|
featuregatetesting "k8s.io/component-base/featuregate/testing"
|
||||||
|
runtimeapi "k8s.io/cri-api/pkg/apis/runtime/v1"
|
||||||
pkgfeatures "k8s.io/kubernetes/pkg/features"
|
pkgfeatures "k8s.io/kubernetes/pkg/features"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -176,6 +177,136 @@ func TestUserNsManagerParseUserNsFile(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestUserNsManagerHostIDFromMapping(t *testing.T) {
|
||||||
|
// mapping []*runtimeapi.IDMapping, containerId *int64
|
||||||
|
|
||||||
|
cases := []struct {
|
||||||
|
name string
|
||||||
|
success bool
|
||||||
|
containerId int64 // -1 means a nil ptr will be used.
|
||||||
|
expHostId int64
|
||||||
|
m []*runtimeapi.IDMapping
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
name: "one basic mapping",
|
||||||
|
success: true,
|
||||||
|
containerId: -1,
|
||||||
|
expHostId: 0,
|
||||||
|
m: []*runtimeapi.IDMapping{
|
||||||
|
{
|
||||||
|
HostId: 0,
|
||||||
|
ContainerId: 0,
|
||||||
|
Length: userNsLength,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "one unprivileged mapping",
|
||||||
|
success: true,
|
||||||
|
containerId: -1,
|
||||||
|
expHostId: userNsLength * 2,
|
||||||
|
m: []*runtimeapi.IDMapping{
|
||||||
|
{
|
||||||
|
HostId: userNsLength * 2,
|
||||||
|
ContainerId: 0,
|
||||||
|
Length: userNsLength,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "one unprivileged mapping random id",
|
||||||
|
success: true,
|
||||||
|
containerId: 3,
|
||||||
|
expHostId: userNsLength*2 + 3,
|
||||||
|
m: []*runtimeapi.IDMapping{
|
||||||
|
{
|
||||||
|
HostId: userNsLength * 2,
|
||||||
|
ContainerId: 0,
|
||||||
|
Length: userNsLength,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "two unprivileged mapping",
|
||||||
|
success: true,
|
||||||
|
containerId: 0,
|
||||||
|
expHostId: userNsLength*2 + 0,
|
||||||
|
m: []*runtimeapi.IDMapping{
|
||||||
|
{
|
||||||
|
HostId: userNsLength * 2,
|
||||||
|
ContainerId: 0,
|
||||||
|
Length: 1,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
HostId: userNsLength*2 + 10,
|
||||||
|
ContainerId: 1,
|
||||||
|
Length: 1,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "two unprivileged mapping - random id",
|
||||||
|
success: true,
|
||||||
|
containerId: 1,
|
||||||
|
expHostId: userNsLength*2 + 10,
|
||||||
|
m: []*runtimeapi.IDMapping{
|
||||||
|
{
|
||||||
|
HostId: userNsLength * 2,
|
||||||
|
ContainerId: 0,
|
||||||
|
Length: 1,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
HostId: userNsLength*2 + 10,
|
||||||
|
ContainerId: 1,
|
||||||
|
Length: 1,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "two unprivileged mapping - not mapped user",
|
||||||
|
success: false,
|
||||||
|
containerId: 3,
|
||||||
|
m: []*runtimeapi.IDMapping{
|
||||||
|
{
|
||||||
|
HostId: userNsLength * 2,
|
||||||
|
ContainerId: 0,
|
||||||
|
Length: 1,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
HostId: userNsLength*2 + 1,
|
||||||
|
ContainerId: 1,
|
||||||
|
Length: 1,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "no mappings",
|
||||||
|
success: false,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, tc := range cases {
|
||||||
|
t.Run(tc.name, func(t *testing.T) {
|
||||||
|
var containerId *int64
|
||||||
|
if tc.containerId != -1 {
|
||||||
|
containerId = &tc.containerId
|
||||||
|
}
|
||||||
|
|
||||||
|
id, err := hostIDFromMapping(tc.m, containerId)
|
||||||
|
if (tc.success && err != nil) || (!tc.success && err == nil) {
|
||||||
|
t.Fatalf("%v: expected success: %v - got error: %v", tc.name, tc.success, err)
|
||||||
|
}
|
||||||
|
if !tc.success && err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if id != tc.expHostId {
|
||||||
|
t.Errorf("expected: %v - got: %v", tc.expHostId, id)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func BenchmarkBitmaskFindAndSetFirstZero(t *testing.B) {
|
func BenchmarkBitmaskFindAndSetFirstZero(t *testing.B) {
|
||||||
b := makeBitArray(userNsLength)
|
b := makeBitArray(userNsLength)
|
||||||
for i := 0; i < userNsLength; i++ {
|
for i := 0; i < userNsLength; i++ {
|
||||||
|
@ -128,6 +128,16 @@ func (kvh *kubeletVolumeHost) GetPodsDir() string {
|
|||||||
return kvh.kubelet.getPodsDir()
|
return kvh.kubelet.getPodsDir()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// GetHostIDsForPod if the pod uses user namespaces, takes the uid and gid
|
||||||
|
// inside the container and returns the host UID and GID those are mapped to on
|
||||||
|
// the host. If containerUID/containerGID is nil, then it returns the host
|
||||||
|
// UID/GID for ID 0 inside the container.
|
||||||
|
// If the pod is not using user namespaces, as there is no mapping needed, the
|
||||||
|
// same containerUID and containerGID params are returned.
|
||||||
|
func (kvh *kubeletVolumeHost) GetHostIDsForPod(pod *v1.Pod, containerUID, containerGID *int64) (hostUID, hostGID *int64, err error) {
|
||||||
|
return kvh.kubelet.getHostIDsForPod(pod, containerUID, containerGID)
|
||||||
|
}
|
||||||
|
|
||||||
func (kvh *kubeletVolumeHost) GetPodVolumeDir(podUID types.UID, pluginName string, volumeName string) string {
|
func (kvh *kubeletVolumeHost) GetPodVolumeDir(podUID types.UID, pluginName string, volumeName string) string {
|
||||||
dir := kvh.kubelet.getPodVolumeDir(podUID, pluginName, volumeName)
|
dir := kvh.kubelet.getPodVolumeDir(podUID, pluginName, volumeName)
|
||||||
if runtime.GOOS == "windows" {
|
if runtime.GOOS == "windows" {
|
||||||
|
@ -340,6 +340,13 @@ type KubeletVolumeHost interface {
|
|||||||
WaitForCacheSync() error
|
WaitForCacheSync() error
|
||||||
// Returns hostutil.HostUtils
|
// Returns hostutil.HostUtils
|
||||||
GetHostUtil() hostutil.HostUtils
|
GetHostUtil() hostutil.HostUtils
|
||||||
|
// GetHostIDsForPod if the pod uses user namespaces, takes the uid and
|
||||||
|
// gid inside the container and returns the host UID and GID those are
|
||||||
|
// mapped to on the host. If containerUID/containerGID is nil, then it
|
||||||
|
// returns the host UID/GID for ID 0 inside the container.
|
||||||
|
// If the pod is not using user namespaces, as there is no mapping needed, the
|
||||||
|
// same containerUID and containerGID params are returned.
|
||||||
|
GetHostIDsForPod(pod *v1.Pod, containerUID, containerGID *int64) (hostUID, hostGID *int64, err error)
|
||||||
}
|
}
|
||||||
|
|
||||||
// AttachDetachVolumeHost is a AttachDetach Controller specific interface that plugins can use
|
// AttachDetachVolumeHost is a AttachDetach Controller specific interface that plugins can use
|
||||||
|
@ -118,6 +118,10 @@ func (f *fakeVolumeHost) GetPodsDir() string {
|
|||||||
return filepath.Join(f.rootDir, "pods")
|
return filepath.Join(f.rootDir, "pods")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (f *fakeVolumeHost) GetHostIDsForPod(pod *v1.Pod, containerUID, containerGID *int64) (hostUID, hostGID *int64, err error) {
|
||||||
|
return containerUID, containerGID, nil
|
||||||
|
}
|
||||||
|
|
||||||
func (f *fakeVolumeHost) GetPodVolumeDir(podUID types.UID, pluginName, volumeName string) string {
|
func (f *fakeVolumeHost) GetPodVolumeDir(podUID types.UID, pluginName, volumeName string) string {
|
||||||
return filepath.Join(f.rootDir, "pods", string(podUID), "volumes", pluginName, volumeName)
|
return filepath.Join(f.rootDir, "pods", string(podUID), "volumes", pluginName, volumeName)
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user