mirror of
https://github.com/k3s-io/kubernetes.git
synced 2026-07-17 11:28:58 +00:00
Add test and doc for processing all the sub-directories in drop-in folder
This commit is contained in:
@@ -89,6 +89,7 @@ type KubeletFlags struct {
|
||||
// KubeletDropinConfigDirectory is the path to a directory containing drop-in configuration files that override settings from defaults and the --config file.
|
||||
// The path may be absolute or relative; relative paths are under the Kubelet's current working directory.
|
||||
// Drop-in files must have a '.conf' suffix and are processed in lexical order. Only '.conf' files are loaded; all other files are ignored.
|
||||
// All .conf files in the directory and its subdirectories are processed in lexical order.
|
||||
KubeletDropinConfigDirectory string
|
||||
|
||||
// WindowsService should be set to true if kubelet is running as a service on Windows.
|
||||
@@ -278,7 +279,7 @@ func (f *KubeletFlags) AddFlags(mainfs *pflag.FlagSet) {
|
||||
f.addOSFlags(fs)
|
||||
|
||||
fs.StringVar(&f.KubeletConfigFile, "config", f.KubeletConfigFile, "The Kubelet will load its initial configuration from this file. The path may be absolute or relative; relative paths start at the Kubelet's current working directory. Omit this flag to use the built-in default configuration values. Command-line flags override configuration from this file.")
|
||||
fs.StringVar(&f.KubeletDropinConfigDirectory, "config-dir", "", "Path to a directory containing drop-in configuration files that override settings from defaults and the --config file. The path may be absolute or relative; relative paths start at the Kubelet's current working directory. Drop-in files must have a '.conf' suffix (e.g., '99-kubelet-address.conf') and are processed in lexical order. Only '.conf' files are loaded; all other files are ignored. [default='']")
|
||||
fs.StringVar(&f.KubeletDropinConfigDirectory, "config-dir", "", "Path to a directory containing drop-in configuration files that override settings from defaults and the --config file. The path may be absolute or relative; relative paths start at the Kubelet's current working directory. Drop-in files must have a '.conf' suffix (e.g., '99-kubelet-address.conf') and are processed in lexical order. Only '.conf' files are loaded; all other files are ignored. All .conf files in the directory and its subdirectories are processed in lexical order. [default='']")
|
||||
fs.StringVar(&f.KubeConfig, "kubeconfig", f.KubeConfig, "Path to a kubeconfig file, specifying how to connect to the API server. Providing --kubeconfig enables API server mode, omitting --kubeconfig enables standalone mode.")
|
||||
|
||||
fs.StringVar(&f.BootstrapKubeconfig, "bootstrap-kubeconfig", f.BootstrapKubeconfig, "Path to a kubeconfig file that will be used to get client certificate for kubelet. "+
|
||||
|
||||
@@ -330,7 +330,7 @@ is checked every 20 seconds (also configurable with a flag).`,
|
||||
// configurations in files with lower numeric prefixes are applied first, followed by higher numeric prefixes.
|
||||
// For example, if the drop-in directory contains files named "10-config.conf" and "20-config.conf",
|
||||
// the configurations in "10-config.conf" will be applied first, and then the configurations in "20-config.conf" will be applied,
|
||||
// potentially overriding the previous values.
|
||||
// potentially overriding the previous values. Files in subdirectories are also processed in lexical order.
|
||||
// Returns a list of skipped files and an error.
|
||||
func mergeKubeletConfigurations(kubeletConfig *kubeletconfiginternal.KubeletConfiguration, kubeletDropInConfigDir string) ([]string, error) {
|
||||
const dropinFileExtension = ".conf"
|
||||
|
||||
@@ -416,3 +416,108 @@ port: [this is not valid
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestMergeKubeletConfigsWithSubdirs(t *testing.T) {
|
||||
testCases := []struct {
|
||||
name string
|
||||
kubeletConfig *kubeletconfiginternal.KubeletConfiguration
|
||||
dropins map[string]string // map[relativePath]content
|
||||
overwrittenConfigFields map[string]interface{}
|
||||
}{
|
||||
{
|
||||
name: "subdirectories are processed in lexical order",
|
||||
kubeletConfig: &kubeletconfiginternal.KubeletConfiguration{
|
||||
TypeMeta: metav1.TypeMeta{
|
||||
Kind: "KubeletConfiguration",
|
||||
APIVersion: "kubelet.config.k8s.io/v1beta1",
|
||||
},
|
||||
Port: int32(9090),
|
||||
ReadOnlyPort: int32(10257),
|
||||
},
|
||||
dropins: map[string]string{
|
||||
"10-kubelet.conf": `
|
||||
apiVersion: kubelet.config.k8s.io/v1beta1
|
||||
kind: KubeletConfiguration
|
||||
port: 8080
|
||||
`,
|
||||
"subdir/20-kubelet.conf": `
|
||||
apiVersion: kubelet.config.k8s.io/v1beta1
|
||||
kind: KubeletConfiguration
|
||||
port: 7777
|
||||
readOnlyPort: 9999
|
||||
`,
|
||||
},
|
||||
overwrittenConfigFields: map[string]interface{}{
|
||||
"Port": int32(7777),
|
||||
"ReadOnlyPort": int32(9999),
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "same filename in multiple directories - lexical order applies",
|
||||
kubeletConfig: &kubeletconfiginternal.KubeletConfiguration{
|
||||
TypeMeta: metav1.TypeMeta{
|
||||
Kind: "KubeletConfiguration",
|
||||
APIVersion: "kubelet.config.k8s.io/v1beta1",
|
||||
},
|
||||
Port: int32(9090),
|
||||
ReadOnlyPort: int32(10255),
|
||||
},
|
||||
dropins: map[string]string{
|
||||
"10-kubelet.conf": `
|
||||
apiVersion: kubelet.config.k8s.io/v1beta1
|
||||
kind: KubeletConfiguration
|
||||
port: 8080
|
||||
`,
|
||||
"sub-dir1/10-kubelet.conf": `
|
||||
apiVersion: kubelet.config.k8s.io/v1beta1
|
||||
kind: KubeletConfiguration
|
||||
port: 7070
|
||||
readOnlyPort: 8888
|
||||
`,
|
||||
"sub-dir2/10-kubelet.conf": `
|
||||
apiVersion: kubelet.config.k8s.io/v1beta1
|
||||
kind: KubeletConfiguration
|
||||
port: 6060
|
||||
readOnlyPort: 9999
|
||||
`,
|
||||
},
|
||||
overwrittenConfigFields: map[string]interface{}{
|
||||
"Port": int32(6060),
|
||||
"ReadOnlyPort": int32(9999),
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
for _, test := range testCases {
|
||||
t.Run(test.name, func(t *testing.T) {
|
||||
tempDir := t.TempDir()
|
||||
kubeletConfDir := filepath.Join(tempDir, "kubelet.conf.d")
|
||||
err := os.Mkdir(kubeletConfDir, 0755)
|
||||
require.NoError(t, err, "Failed to create kubelet.conf.d directory")
|
||||
|
||||
// Create drop-in files including those in subdirectories
|
||||
for relPath, content := range test.dropins {
|
||||
fullPath := filepath.Join(kubeletConfDir, relPath)
|
||||
// Create subdirectory if needed
|
||||
dir := filepath.Dir(fullPath)
|
||||
if dir != kubeletConfDir {
|
||||
err = os.MkdirAll(dir, 0755)
|
||||
require.NoError(t, err, "Failed to create subdirectory: "+dir)
|
||||
}
|
||||
err = os.WriteFile(fullPath, []byte(content), 0644)
|
||||
require.NoError(t, err, "Failed to create drop-in file: "+relPath)
|
||||
}
|
||||
|
||||
// Merge the kubelet configurations
|
||||
_, err = mergeKubeletConfigurations(test.kubeletConfig, kubeletConfDir)
|
||||
require.NoError(t, err, "failed to merge kubelet drop-in configs")
|
||||
|
||||
// Verify the merged configuration fields
|
||||
for fieldName, expectedValue := range test.overwrittenConfigFields {
|
||||
value := reflect.ValueOf(test.kubeletConfig).Elem()
|
||||
field := value.FieldByName(fieldName)
|
||||
require.Equal(t, expectedValue, field.Interface(), "Field mismatch: "+fieldName)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user