diff --git a/tools/packaging/kata-deploy/binary/src/config.rs b/tools/packaging/kata-deploy/binary/src/config.rs index 2b17bc3e2e..37e1028a70 100644 --- a/tools/packaging/kata-deploy/binary/src/config.rs +++ b/tools/packaging/kata-deploy/binary/src/config.rs @@ -243,7 +243,21 @@ impl Config { }; let crio_drop_in_conf_file_debug = format!("{crio_drop_in_conf_dir}/100-debug"); - let containerd_conf_file = "/etc/containerd/config.toml".to_string(); + let containerd_config_file_name = env::var("CONTAINERD_CONFIG_FILE_NAME") + .ok() + .map(|s| s.trim().to_string()) + .filter(|s| !s.is_empty()) + .unwrap_or_else(|| "config.toml".to_string()); + let containerd_conf_path = Path::new("/etc/containerd").join(&containerd_config_file_name); + if containerd_conf_path.parent() != Some(Path::new("/etc/containerd")) + || containerd_conf_path.file_name() != Some(containerd_config_file_name.as_ref()) + { + return Err(anyhow::anyhow!( + "CONTAINERD_CONFIG_FILE_NAME must be a simple file name without path separators, \ + got: '{containerd_config_file_name}'" + )); + } + let containerd_conf_file = containerd_conf_path.to_string_lossy().to_string(); let containerd_conf_file_backup = format!("{containerd_conf_file}.bak"); let containerd_drop_in_conf_file = format!("{dest_dir}/containerd/config.d/kata-deploy.toml"); @@ -503,6 +517,7 @@ impl Config { "* EXPERIMENTAL_FORCE_GUEST_PULL: {}", self.experimental_force_guest_pull_for_arch.join(",") ); + info!("* CONTAINERD_CONF_FILE: {}", self.containerd_conf_file); info!( "* CUSTOM_RUNTIMES_ENABLED: {}", self.custom_runtimes_enabled @@ -558,7 +573,7 @@ impl Config { .await .ok(); let use_v3 = k3s_rke2_resolve_use_v3( - &self.containerd_conf_file, + k3s_rke2_rendered_config_path(), container_runtime_version.as_deref(), )?; let config_file = k3s_rke2_containerd_template_path(use_v3).to_string(); @@ -801,6 +816,7 @@ mod tests { "EXPERIMENTAL_FORCE_GUEST_PULL_AARCH64", "EXPERIMENTAL_FORCE_GUEST_PULL_S390X", "EXPERIMENTAL_FORCE_GUEST_PULL_PPC64LE", + "CONTAINERD_CONFIG_FILE_NAME", ]; for var in &vars { std::env::remove_var(var); @@ -1196,6 +1212,134 @@ mod tests { cleanup_env_vars(); } + #[serial] + #[test] + fn test_containerd_config_file_name_default() { + setup_minimal_env(); + + let config = Config::from_env().unwrap(); + assert_eq!(config.containerd_conf_file, "/etc/containerd/config.toml"); + assert_eq!( + config.containerd_conf_file_backup, + "/etc/containerd/config.toml.bak" + ); + + cleanup_env_vars(); + } + + #[serial] + #[test] + fn test_containerd_config_file_name_custom() { + setup_minimal_env(); + std::env::set_var("CONTAINERD_CONFIG_FILE_NAME", "my-config.toml"); + + let config = Config::from_env().unwrap(); + assert_eq!( + config.containerd_conf_file, + "/etc/containerd/my-config.toml" + ); + assert_eq!( + config.containerd_conf_file_backup, + "/etc/containerd/my-config.toml.bak" + ); + + cleanup_env_vars(); + } + + #[serial] + #[test] + fn test_containerd_config_file_name_empty_uses_default() { + setup_minimal_env(); + std::env::set_var("CONTAINERD_CONFIG_FILE_NAME", ""); + + let config = Config::from_env().unwrap(); + assert_eq!(config.containerd_conf_file, "/etc/containerd/config.toml"); + + cleanup_env_vars(); + } + + #[serial] + #[test] + fn test_containerd_config_file_name_whitespace_only_uses_default() { + setup_minimal_env(); + std::env::set_var("CONTAINERD_CONFIG_FILE_NAME", " "); + + let config = Config::from_env().unwrap(); + assert_eq!(config.containerd_conf_file, "/etc/containerd/config.toml"); + + cleanup_env_vars(); + } + + #[serial] + #[test] + fn test_containerd_config_file_name_trimmed() { + setup_minimal_env(); + std::env::set_var("CONTAINERD_CONFIG_FILE_NAME", " my-config.toml "); + + let config = Config::from_env().unwrap(); + assert_eq!( + config.containerd_conf_file, + "/etc/containerd/my-config.toml" + ); + + cleanup_env_vars(); + } + + #[serial] + #[test] + fn test_containerd_config_file_name_rejects_path_separator() { + setup_minimal_env(); + std::env::set_var("CONTAINERD_CONFIG_FILE_NAME", "../etc/shadow"); + + assert_config_error_contains("simple file name"); + cleanup_env_vars(); + } + + #[serial] + #[test] + fn test_containerd_config_file_name_rejects_slash() { + setup_minimal_env(); + std::env::set_var("CONTAINERD_CONFIG_FILE_NAME", "subdir/config.toml"); + + assert_config_error_contains("simple file name"); + cleanup_env_vars(); + } + + #[serial] + #[test] + fn test_containerd_config_file_name_rejects_dotdot() { + setup_minimal_env(); + std::env::set_var("CONTAINERD_CONFIG_FILE_NAME", ".."); + + assert_config_error_contains("simple file name"); + cleanup_env_vars(); + } + + #[serial] + #[test] + fn test_containerd_config_file_name_rejects_dot() { + setup_minimal_env(); + std::env::set_var("CONTAINERD_CONFIG_FILE_NAME", "."); + + assert_config_error_contains("simple file name"); + cleanup_env_vars(); + } + + #[serial] + #[test] + fn test_containerd_config_file_name_allows_dots_in_name() { + setup_minimal_env(); + std::env::set_var("CONTAINERD_CONFIG_FILE_NAME", "config.v2.toml"); + + let config = Config::from_env().unwrap(); + assert_eq!( + config.containerd_conf_file, + "/etc/containerd/config.v2.toml" + ); + + cleanup_env_vars(); + } + #[serial] #[test] fn test_arch_specific_all_variables() { diff --git a/tools/packaging/kata-deploy/helm-chart/kata-deploy/templates/_helpers.tpl b/tools/packaging/kata-deploy/helm-chart/kata-deploy/templates/_helpers.tpl index 1735602d70..514017c612 100644 --- a/tools/packaging/kata-deploy/helm-chart/kata-deploy/templates/_helpers.tpl +++ b/tools/packaging/kata-deploy/helm-chart/kata-deploy/templates/_helpers.tpl @@ -44,13 +44,16 @@ app.kubernetes.io/instance: {{ .Release.Name }} {{- end }} {{/* -Set the correct containerd conf path depending on the k8s distribution +Set the correct containerd conf path depending on the k8s distribution. +If containerd.configDir is set explicitly, use that instead. */}} {{- define "containerdConfPath" -}} -{{- if eq .k8sDistribution "rke2" -}} +{{- if and .containerd .containerd.configDir -}} +{{- .containerd.configDir -}} +{{- else if eq .k8sDistribution "rke2" -}} /var/lib/rancher/rke2/agent/etc/containerd/ {{- else if eq .k8sDistribution "k3s" -}} - /var/lib/rancher/k3s/agent/etc/containerd/ +/var/lib/rancher/k3s/agent/etc/containerd/ {{- else if eq .k8sDistribution "k0s" -}} /etc/k0s/ {{- else if eq .k8sDistribution "microk8s" -}} diff --git a/tools/packaging/kata-deploy/helm-chart/kata-deploy/templates/kata-deploy.yaml b/tools/packaging/kata-deploy/helm-chart/kata-deploy/templates/kata-deploy.yaml index 21d2622f47..b0aaa19643 100644 --- a/tools/packaging/kata-deploy/helm-chart/kata-deploy/templates/kata-deploy.yaml +++ b/tools/packaging/kata-deploy/helm-chart/kata-deploy/templates/kata-deploy.yaml @@ -291,6 +291,10 @@ spec: - name: EXPERIMENTAL_FORCE_GUEST_PULL_PPC64LE value: {{ $forceGuestPullPpc64le | quote }} {{- end }} +{{- if .Values.containerd.configFileName | trim }} + - name: CONTAINERD_CONFIG_FILE_NAME + value: {{ .Values.containerd.configFileName | trim | quote }} +{{- end }} {{- with .Values.env.hostOS }} - name: HOST_OS value: {{ . | quote }} diff --git a/tools/packaging/kata-deploy/helm-chart/kata-deploy/values.yaml b/tools/packaging/kata-deploy/helm-chart/kata-deploy/values.yaml index 20474ba66c..660822c729 100644 --- a/tools/packaging/kata-deploy/helm-chart/kata-deploy/values.yaml +++ b/tools/packaging/kata-deploy/helm-chart/kata-deploy/values.yaml @@ -12,6 +12,20 @@ kubectlImage: k8sDistribution: "k8s" # k8s, k3s, rke2, k0s, microk8s +# Containerd configuration overrides +# These override the auto-detected paths based on k8sDistribution. +# Use these when your containerd setup doesn't match any built-in distribution preset. +containerd: + # Override the host directory where containerd config lives. + # When empty, derived automatically from k8sDistribution. + # Example: "/etc/my-containerd/" + configDir: "" + # Override the containerd config file name. + # When empty, the kata-deploy binary uses its built-in default ("config.toml") + # or auto-detects based on the runtime (k0s, microk8s, k3s/rke2). + # Example: "my-config.toml" + configFileName: "" + # Node selector and tolerations to control which nodes the kata-deploy daemonset runs on # Examples: # nodeSelector: