mirror of
https://github.com/kubernetes/kubernetes.git
synced 2026-02-16 01:08:06 -05:00
179 lines
5.1 KiB
Go
179 lines
5.1 KiB
Go
// Copyright 2014 Google Inc. All Rights Reserved.
|
|
//
|
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
// you may not use this file except in compliance with the License.
|
|
// You may obtain a copy of the License at
|
|
//
|
|
// http://www.apache.org/licenses/LICENSE-2.0
|
|
//
|
|
// Unless required by applicable law or agreed to in writing, software
|
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
// See the License for the specific language governing permissions and
|
|
// limitations under the License.
|
|
|
|
package fs
|
|
|
|
import (
|
|
"errors"
|
|
"fmt"
|
|
"sync"
|
|
|
|
mount "github.com/moby/sys/mountinfo"
|
|
"k8s.io/klog/v2"
|
|
)
|
|
|
|
// FsPlugin provides filesystem-specific statistics collection.
|
|
type FsPlugin interface {
|
|
// Name returns the plugin identifier (e.g., "zfs", "devicemapper", "vfs").
|
|
Name() string
|
|
|
|
// CanHandle returns true if this plugin handles the given filesystem type.
|
|
CanHandle(fsType string) bool
|
|
|
|
// Priority returns the plugin priority (higher = checked first).
|
|
// Allows specific plugins (zfs, btrfs) to override generic (vfs).
|
|
Priority() int
|
|
|
|
// GetStats returns filesystem statistics for a partition.
|
|
GetStats(device string, partition PartitionInfo) (*FsStats, error)
|
|
|
|
// ProcessMount optionally modifies mount info during processing.
|
|
// Returns (shouldInclude bool, modifiedMount *mount.Info, error).
|
|
ProcessMount(mnt *mount.Info) (bool, *mount.Info, error)
|
|
}
|
|
|
|
// FsCachingPlugin is an optional interface for plugins that want to cache
|
|
// stats by a key (e.g., device ID) to avoid redundant stat calls.
|
|
// This is useful for network filesystems like NFS where multiple mounts
|
|
// may point to the same underlying device.
|
|
type FsCachingPlugin interface {
|
|
FsPlugin
|
|
|
|
// CacheKey returns a cache key for the given partition.
|
|
// Stats will be cached by this key and reused for partitions with the same key.
|
|
// Return empty string to disable caching for a specific partition.
|
|
CacheKey(partition PartitionInfo) string
|
|
}
|
|
|
|
// FsWatcherPlugin is an optional interface for plugins that provide
|
|
// background monitoring (e.g., ZFS watcher, ThinPool watcher).
|
|
type FsWatcherPlugin interface {
|
|
FsPlugin
|
|
|
|
// StartWatcher starts background monitoring.
|
|
// Returns a Watcher that can be used to get container-level usage.
|
|
StartWatcher() (FsWatcher, error)
|
|
}
|
|
|
|
// FsWatcher provides container-level filesystem usage from background monitoring.
|
|
type FsWatcher interface {
|
|
// GetUsage returns filesystem usage for a specific container/path.
|
|
GetUsage(containerID string, deviceID string) (uint64, error)
|
|
|
|
// Stop stops the background monitoring.
|
|
Stop()
|
|
}
|
|
|
|
// PartitionInfo contains information needed for stats collection.
|
|
type PartitionInfo struct {
|
|
Mountpoint string
|
|
Major uint
|
|
Minor uint
|
|
FsType string
|
|
BlockSize uint
|
|
}
|
|
|
|
// FsStats contains filesystem statistics returned by plugins.
|
|
type FsStats struct {
|
|
Capacity uint64
|
|
Free uint64
|
|
Available uint64
|
|
Inodes *uint64
|
|
InodesFree *uint64
|
|
Type FsType
|
|
}
|
|
|
|
// ErrFallbackToVFS signals that a specialized plugin cannot handle
|
|
// this filesystem and VFS should be used instead.
|
|
var ErrFallbackToVFS = errors.New("fallback to VFS")
|
|
|
|
// Plugin registry (init-time registration only).
|
|
var (
|
|
pluginsLock sync.RWMutex
|
|
plugins = make(map[string]FsPlugin)
|
|
)
|
|
|
|
// RegisterPlugin registers a filesystem plugin.
|
|
// This should be called from init() functions.
|
|
func RegisterPlugin(name string, plugin FsPlugin) error {
|
|
pluginsLock.Lock()
|
|
defer pluginsLock.Unlock()
|
|
if _, found := plugins[name]; found {
|
|
return fmt.Errorf("FsPlugin %q was registered twice", name)
|
|
}
|
|
klog.V(4).Infof("Registered FsPlugin %q", name)
|
|
plugins[name] = plugin
|
|
return nil
|
|
}
|
|
|
|
// GetPluginForFsType returns the appropriate plugin for the filesystem type.
|
|
// Returns nil if no plugin can handle the filesystem type.
|
|
func GetPluginForFsType(fsType string) FsPlugin {
|
|
pluginsLock.RLock()
|
|
defer pluginsLock.RUnlock()
|
|
|
|
var best FsPlugin
|
|
for _, p := range plugins {
|
|
if p.CanHandle(fsType) {
|
|
if best == nil || p.Priority() > best.Priority() {
|
|
best = p
|
|
}
|
|
}
|
|
}
|
|
return best
|
|
}
|
|
|
|
// GetAllPlugins returns all registered plugins.
|
|
func GetAllPlugins() []FsPlugin {
|
|
pluginsLock.RLock()
|
|
defer pluginsLock.RUnlock()
|
|
|
|
result := make([]FsPlugin, 0, len(plugins))
|
|
for _, p := range plugins {
|
|
result = append(result, p)
|
|
}
|
|
return result
|
|
}
|
|
|
|
// InitializeWatchers starts all plugin watchers and returns them.
|
|
func InitializeWatchers() map[string]FsWatcher {
|
|
pluginsLock.RLock()
|
|
defer pluginsLock.RUnlock()
|
|
|
|
watchers := make(map[string]FsWatcher)
|
|
for name, plugin := range plugins {
|
|
if wp, ok := plugin.(FsWatcherPlugin); ok {
|
|
watcher, err := wp.StartWatcher()
|
|
if err != nil {
|
|
klog.V(4).Infof("Failed to start watcher for plugin %s: %v", name, err)
|
|
continue
|
|
}
|
|
if watcher != nil {
|
|
watchers[name] = watcher
|
|
klog.V(4).Infof("Started watcher for FsPlugin %q", name)
|
|
}
|
|
}
|
|
}
|
|
return watchers
|
|
}
|
|
|
|
// StopWatchers stops all provided watchers.
|
|
func StopWatchers(watchers map[string]FsWatcher) {
|
|
for name, watcher := range watchers {
|
|
if watcher != nil {
|
|
watcher.Stop()
|
|
klog.V(4).Infof("Stopped watcher for FsPlugin %q", name)
|
|
}
|
|
}
|
|
}
|