mirror of
https://github.com/k3s-io/kubernetes.git
synced 2025-07-23 03:41:45 +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 ""
|
||||
}
|
||||
|
||||
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 {
|
||||
return ""
|
||||
}
|
||||
|
@ -394,6 +394,10 @@ func (expc *expandController) GetPodsDir() string {
|
||||
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 {
|
||||
return ""
|
||||
}
|
||||
|
@ -55,6 +55,10 @@ func (ctrl *PersistentVolumeController) GetPodVolumeDir(podUID types.UID, plugin
|
||||
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 {
|
||||
return ""
|
||||
}
|
||||
|
@ -425,6 +425,10 @@ func (kl *Kubelet) GetOrCreateUserNamespaceMappings(pod *v1.Pod) (*runtimeapi.Us
|
||||
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,
|
||||
// given that pod's spec and annotations or returns an 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
|
||||
}
|
||||
|
||||
// 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"
|
||||
utilfeature "k8s.io/apiserver/pkg/util/feature"
|
||||
featuregatetesting "k8s.io/component-base/featuregate/testing"
|
||||
runtimeapi "k8s.io/cri-api/pkg/apis/runtime/v1"
|
||||
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) {
|
||||
b := makeBitArray(userNsLength)
|
||||
for i := 0; i < userNsLength; i++ {
|
||||
|
@ -128,6 +128,16 @@ func (kvh *kubeletVolumeHost) GetPodsDir() string {
|
||||
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 {
|
||||
dir := kvh.kubelet.getPodVolumeDir(podUID, pluginName, volumeName)
|
||||
if runtime.GOOS == "windows" {
|
||||
|
@ -340,6 +340,13 @@ type KubeletVolumeHost interface {
|
||||
WaitForCacheSync() error
|
||||
// Returns 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
|
||||
|
@ -118,6 +118,10 @@ func (f *fakeVolumeHost) GetPodsDir() string {
|
||||
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 {
|
||||
return filepath.Join(f.rootDir, "pods", string(podUID), "volumes", pluginName, volumeName)
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user