kubelet: Move userns manager to its own package

To that end, we need to add one kubelet getter listPodsFromDisk(). Other
than that, it is a pretty trivial move.

Signed-off-by: Rodrigo Campos <rodrigoca@microsoft.com>
This commit is contained in:
Rodrigo Campos 2023-03-07 18:02:38 +01:00 committed by Giuseppe Scrivano
parent 16d76f6813
commit ec0410a266
No known key found for this signature in database
GPG Key ID: 67E38F7A8BA21772
4 changed files with 34 additions and 28 deletions

View File

@ -109,6 +109,7 @@ import (
"k8s.io/kubernetes/pkg/kubelet/sysctl" "k8s.io/kubernetes/pkg/kubelet/sysctl"
"k8s.io/kubernetes/pkg/kubelet/token" "k8s.io/kubernetes/pkg/kubelet/token"
kubetypes "k8s.io/kubernetes/pkg/kubelet/types" kubetypes "k8s.io/kubernetes/pkg/kubelet/types"
"k8s.io/kubernetes/pkg/kubelet/userns"
"k8s.io/kubernetes/pkg/kubelet/util" "k8s.io/kubernetes/pkg/kubelet/util"
"k8s.io/kubernetes/pkg/kubelet/util/manager" "k8s.io/kubernetes/pkg/kubelet/util/manager"
"k8s.io/kubernetes/pkg/kubelet/util/queue" "k8s.io/kubernetes/pkg/kubelet/util/queue"
@ -900,7 +901,7 @@ func NewMainKubelet(kubeCfg *kubeletconfiginternal.KubeletConfiguration,
StateDirectory: rootDirectory, StateDirectory: rootDirectory,
}) })
klet.shutdownManager = shutdownManager klet.shutdownManager = shutdownManager
klet.usernsManager, err = MakeUserNsManager(klet) klet.usernsManager, err = userns.MakeUserNsManager(klet)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -1248,7 +1249,7 @@ type Kubelet struct {
shutdownManager nodeshutdown.Manager shutdownManager nodeshutdown.Manager
// Manage user namespaces // Manage user namespaces
usernsManager *usernsManager usernsManager *userns.UsernsManager
// Mutex to serialize new pod admission and existing pod resizing // Mutex to serialize new pod admission and existing pod resizing
podResizeMutex sync.Mutex podResizeMutex sync.Mutex

View File

@ -104,6 +104,11 @@ func (kl *Kubelet) GetPodDir(podUID types.UID) string {
return kl.getPodDir(podUID) return kl.getPodDir(podUID)
} }
// ListPodsFromDisk gets a list of pods that have data directories.
func (kl *Kubelet) ListPodsFromDisk() ([]types.UID, error) {
return kl.listPodsFromDisk()
}
// getPodDir returns the full path to the per-pod directory for the pod with // getPodDir returns the full path to the per-pod directory for the pod with
// the given UID. // the given UID.
func (kl *Kubelet) getPodDir(podUID types.UID) string { func (kl *Kubelet) getPodDir(podUID types.UID) string {

View File

@ -14,7 +14,7 @@ See the License for the specific language governing permissions and
limitations under the License. limitations under the License.
*/ */
package kubelet package userns
import ( import (
"encoding/json" "encoding/json"
@ -49,11 +49,11 @@ const maxPods = 1024
const mapReInitializeThreshold = 1000 const mapReInitializeThreshold = 1000
type userNsPodsManager interface { type userNsPodsManager interface {
getPodDir(podUID types.UID) string GetPodDir(podUID types.UID) string
listPodsFromDisk() ([]types.UID, error) ListPodsFromDisk() ([]types.UID, error)
} }
type usernsManager struct { type UsernsManager struct {
used *allocator.AllocationBitmap used *allocator.AllocationBitmap
usedBy map[types.UID]uint32 // Map pod.UID to range used usedBy map[types.UID]uint32 // Map pod.UID to range used
removed int removed int
@ -86,8 +86,8 @@ const mappingsFile = "userns"
// writeMappingsToFile writes the specified user namespace configuration to the pod // writeMappingsToFile writes the specified user namespace configuration to the pod
// directory. // directory.
func (m *usernsManager) writeMappingsToFile(pod types.UID, userNs userNamespace) error { func (m *UsernsManager) writeMappingsToFile(pod types.UID, userNs userNamespace) error {
dir := m.kl.getPodDir(pod) dir := m.kl.GetPodDir(pod)
data, err := json.Marshal(userNs) data, err := json.Marshal(userNs)
if err != nil { if err != nil {
@ -119,8 +119,8 @@ func (m *usernsManager) writeMappingsToFile(pod types.UID, userNs userNamespace)
} }
// readMappingsFromFile reads the user namespace configuration from the pod directory. // readMappingsFromFile reads the user namespace configuration from the pod directory.
func (m *usernsManager) readMappingsFromFile(pod types.UID) ([]byte, error) { func (m *UsernsManager) readMappingsFromFile(pod types.UID) ([]byte, error) {
dir := m.kl.getPodDir(pod) dir := m.kl.GetPodDir(pod)
fstore, err := utilstore.NewFileStore(dir, &utilfs.DefaultFs{}) fstore, err := utilstore.NewFileStore(dir, &utilfs.DefaultFs{})
if err != nil { if err != nil {
return nil, err return nil, err
@ -128,8 +128,8 @@ func (m *usernsManager) readMappingsFromFile(pod types.UID) ([]byte, error) {
return fstore.Read(mappingsFile) return fstore.Read(mappingsFile)
} }
func MakeUserNsManager(kl userNsPodsManager) (*usernsManager, error) { func MakeUserNsManager(kl userNsPodsManager) (*UsernsManager, error) {
m := usernsManager{ m := UsernsManager{
// Create a bitArray for all the UID space (2^32). // Create a bitArray for all the UID space (2^32).
// As a by product of that, no index param to bitArray can be out of bounds (index is uint32). // As a by product of that, no index param to bitArray can be out of bounds (index is uint32).
used: allocator.NewAllocationMap((math.MaxUint32+1)/userNsLength, "user namespaces"), used: allocator.NewAllocationMap((math.MaxUint32+1)/userNsLength, "user namespaces"),
@ -146,7 +146,7 @@ func MakeUserNsManager(kl userNsPodsManager) (*usernsManager, error) {
return &m, nil return &m, nil
} }
found, err := kl.listPodsFromDisk() found, err := kl.ListPodsFromDisk()
if err != nil { if err != nil {
if os.IsNotExist(err) { if os.IsNotExist(err) {
return &m, nil return &m, nil
@ -166,7 +166,7 @@ func MakeUserNsManager(kl userNsPodsManager) (*usernsManager, error) {
// recordPodMappings registers the range used for the user namespace if the // recordPodMappings registers the range used for the user namespace if the
// usernsConfFile exists in the pod directory. // usernsConfFile exists in the pod directory.
func (m *usernsManager) recordPodMappings(pod types.UID) error { func (m *UsernsManager) recordPodMappings(pod types.UID) error {
content, err := m.readMappingsFromFile(pod) content, err := m.readMappingsFromFile(pod)
if err != nil && err != utilstore.ErrKeyNotFound { if err != nil && err != utilstore.ErrKeyNotFound {
return err return err
@ -182,7 +182,7 @@ func (m *usernsManager) recordPodMappings(pod types.UID) error {
} }
// isSet checks if the specified index is already set. // isSet checks if the specified index is already set.
func (m *usernsManager) isSet(v uint32) bool { func (m *UsernsManager) isSet(v uint32) bool {
index := int(v / userNsLength) index := int(v / userNsLength)
return m.used.Has(index) return m.used.Has(index)
} }
@ -190,7 +190,7 @@ func (m *usernsManager) isSet(v uint32) bool {
// allocateOne finds a free user namespace and allocate it to the specified pod. // allocateOne finds a free user namespace and allocate it to the specified pod.
// The first return value is the first ID in the user namespace, the second returns // The first return value is the first ID in the user namespace, the second returns
// the length for the user namespace range. // the length for the user namespace range.
func (m *usernsManager) allocateOne(pod types.UID) (firstID uint32, length uint32, err error) { func (m *UsernsManager) allocateOne(pod types.UID) (firstID uint32, length uint32, err error) {
if m.numAllocated >= maxPods { if m.numAllocated >= maxPods {
return 0, 0, fmt.Errorf("limit on count of pods with user namespaces exceeded (limit is %v, current pods with userns: %v)", maxPods, m.numAllocated) return 0, 0, fmt.Errorf("limit on count of pods with user namespaces exceeded (limit is %v, current pods with userns: %v)", maxPods, m.numAllocated)
} }
@ -217,7 +217,7 @@ func (m *usernsManager) allocateOne(pod types.UID) (firstID uint32, length uint3
} }
// record stores the user namespace [from; from+length] to the specified pod. // record stores the user namespace [from; from+length] to the specified pod.
func (m *usernsManager) record(pod types.UID, from, length uint32) (err error) { func (m *UsernsManager) record(pod types.UID, from, length uint32) (err error) {
if length != userNsLength { if length != userNsLength {
return fmt.Errorf("wrong user namespace length %v", length) return fmt.Errorf("wrong user namespace length %v", length)
} }
@ -257,7 +257,7 @@ func (m *usernsManager) record(pod types.UID, from, length uint32) (err error) {
} }
// Release releases the user namespace allocated to the specified pod. // Release releases the user namespace allocated to the specified pod.
func (m *usernsManager) Release(podUID types.UID) { func (m *UsernsManager) Release(podUID types.UID) {
if !utilfeature.DefaultFeatureGate.Enabled(features.UserNamespacesStatelessPodsSupport) { if !utilfeature.DefaultFeatureGate.Enabled(features.UserNamespacesStatelessPodsSupport) {
return return
} }
@ -268,7 +268,7 @@ func (m *usernsManager) Release(podUID types.UID) {
m.releaseWithLock(podUID) m.releaseWithLock(podUID)
} }
func (m *usernsManager) releaseWithLock(pod types.UID) { func (m *UsernsManager) releaseWithLock(pod types.UID) {
v, ok := m.usedBy[pod] v, ok := m.usedBy[pod]
if !ok { if !ok {
klog.V(5).InfoS("pod user namespace allocation not present", "podUID", pod) klog.V(5).InfoS("pod user namespace allocation not present", "podUID", pod)
@ -280,7 +280,7 @@ func (m *usernsManager) releaseWithLock(pod types.UID) {
m.numAllocated-- m.numAllocated--
m.removed++ m.removed++
_ = os.Remove(filepath.Join(m.kl.getPodDir(pod), mappingsFile)) _ = os.Remove(filepath.Join(m.kl.GetPodDir(pod), mappingsFile))
if m.removed%mapReInitializeThreshold == 0 { if m.removed%mapReInitializeThreshold == 0 {
n := make(map[types.UID]uint32) n := make(map[types.UID]uint32)
@ -293,7 +293,7 @@ func (m *usernsManager) releaseWithLock(pod types.UID) {
m.used.Release(int(v / userNsLength)) m.used.Release(int(v / userNsLength))
} }
func (m *usernsManager) parseUserNsFileAndRecord(pod types.UID, content []byte) (userNs userNamespace, err error) { func (m *UsernsManager) parseUserNsFileAndRecord(pod types.UID, content []byte) (userNs userNamespace, err error) {
if err = json.Unmarshal([]byte(content), &userNs); err != nil { if err = json.Unmarshal([]byte(content), &userNs); err != nil {
err = fmt.Errorf("can't parse file: %w", err) err = fmt.Errorf("can't parse file: %w", err)
return return
@ -333,7 +333,7 @@ func (m *usernsManager) parseUserNsFileAndRecord(pod types.UID, content []byte)
return return
} }
func (m *usernsManager) createUserNs(pod *v1.Pod) (userNs userNamespace, err error) { func (m *UsernsManager) createUserNs(pod *v1.Pod) (userNs userNamespace, err error) {
firstID, length, err := m.allocateOne(pod.UID) firstID, length, err := m.allocateOne(pod.UID)
if err != nil { if err != nil {
return return
@ -366,7 +366,7 @@ func (m *usernsManager) createUserNs(pod *v1.Pod) (userNs userNamespace, err err
} }
// GetOrCreateUserNamespaceMappings returns the configuration for the sandbox user namespace // GetOrCreateUserNamespaceMappings returns the configuration for the sandbox user namespace
func (m *usernsManager) GetOrCreateUserNamespaceMappings(pod *v1.Pod) (*runtimeapi.UserNamespace, error) { func (m *UsernsManager) GetOrCreateUserNamespaceMappings(pod *v1.Pod) (*runtimeapi.UserNamespace, error) {
if !utilfeature.DefaultFeatureGate.Enabled(features.UserNamespacesStatelessPodsSupport) { if !utilfeature.DefaultFeatureGate.Enabled(features.UserNamespacesStatelessPodsSupport) {
return nil, nil return nil, nil
} }
@ -426,7 +426,7 @@ func (m *usernsManager) GetOrCreateUserNamespaceMappings(pod *v1.Pod) (*runtimea
// CleanupOrphanedPodUsernsAllocations reconciliates the state of user namespace // CleanupOrphanedPodUsernsAllocations reconciliates the state of user namespace
// allocations with the pods actually running. It frees any user namespace // allocations with the pods actually running. It frees any user namespace
// allocation for orphaned pods. // allocation for orphaned pods.
func (m *usernsManager) CleanupOrphanedPodUsernsAllocations(pods []*v1.Pod, runningPods []*kubecontainer.Pod) error { func (m *UsernsManager) CleanupOrphanedPodUsernsAllocations(pods []*v1.Pod, runningPods []*kubecontainer.Pod) error {
if !utilfeature.DefaultFeatureGate.Enabled(features.UserNamespacesStatelessPodsSupport) { if !utilfeature.DefaultFeatureGate.Enabled(features.UserNamespacesStatelessPodsSupport) {
return nil return nil
} }
@ -443,7 +443,7 @@ func (m *usernsManager) CleanupOrphanedPodUsernsAllocations(pods []*v1.Pod, runn
} }
allFound := sets.NewString() allFound := sets.NewString()
found, err := m.kl.listPodsFromDisk() found, err := m.kl.ListPodsFromDisk()
if err != nil { if err != nil {
return err return err
} }

View File

@ -14,7 +14,7 @@ See the License for the specific language governing permissions and
limitations under the License. limitations under the License.
*/ */
package kubelet package userns
import ( import (
"fmt" "fmt"
@ -31,11 +31,11 @@ import (
type testUserNsPodsManager struct { type testUserNsPodsManager struct {
} }
func (m *testUserNsPodsManager) getPodDir(podUID types.UID) string { func (m *testUserNsPodsManager) GetPodDir(podUID types.UID) string {
return "/tmp/non-existant-dir.This-is-not-used-in-tests" return "/tmp/non-existant-dir.This-is-not-used-in-tests"
} }
func (m *testUserNsPodsManager) listPodsFromDisk() ([]types.UID, error) { func (m *testUserNsPodsManager) ListPodsFromDisk() ([]types.UID, error) {
return nil, nil return nil, nil
} }