diff --git a/pkg/cri/config/config.go b/pkg/cri/config/config.go index 038ad19f5..26cecdd01 100644 --- a/pkg/cri/config/config.go +++ b/pkg/cri/config/config.go @@ -24,6 +24,8 @@ import ( "time" "github.com/containerd/log" + + "github.com/containerd/containerd/v2/pkg/deprecation" ) type SandboxControllerMode string @@ -365,22 +367,23 @@ const ( ) // ValidatePluginConfig validates the given plugin configuration. -func ValidatePluginConfig(ctx context.Context, c *PluginConfig) error { +func ValidatePluginConfig(ctx context.Context, c *PluginConfig) ([]deprecation.Warning, error) { + var warnings []deprecation.Warning if c.ContainerdConfig.Runtimes == nil { c.ContainerdConfig.Runtimes = make(map[string]Runtime) } // Validation for default_runtime_name if c.ContainerdConfig.DefaultRuntimeName == "" { - return errors.New("`default_runtime_name` is empty") + return warnings, errors.New("`default_runtime_name` is empty") } if _, ok := c.ContainerdConfig.Runtimes[c.ContainerdConfig.DefaultRuntimeName]; !ok { - return fmt.Errorf("no corresponding runtime configured in `containerd.runtimes` for `containerd` `default_runtime_name = \"%s\"", c.ContainerdConfig.DefaultRuntimeName) + return warnings, fmt.Errorf("no corresponding runtime configured in `containerd.runtimes` for `containerd` `default_runtime_name = \"%s\"", c.ContainerdConfig.DefaultRuntimeName) } for k, r := range c.ContainerdConfig.Runtimes { if !r.PrivilegedWithoutHostDevices && r.PrivilegedWithoutHostDevicesAllDevicesAllowed { - return errors.New("`privileged_without_host_devices_all_devices_allowed` requires `privileged_without_host_devices` to be enabled") + return warnings, errors.New("`privileged_without_host_devices_all_devices_allowed` requires `privileged_without_host_devices` to be enabled") } // If empty, use default podSandbox mode if len(r.Sandboxer) == 0 { @@ -392,7 +395,7 @@ func ValidatePluginConfig(ctx context.Context, c *PluginConfig) error { useConfigPath := c.Registry.ConfigPath != "" if len(c.Registry.Mirrors) > 0 { if useConfigPath { - return errors.New("`mirrors` cannot be set when `config_path` is provided") + return warnings, errors.New("`mirrors` cannot be set when `config_path` is provided") } log.G(ctx).Warning("`mirrors` is deprecated, please use `config_path` instead") } @@ -406,7 +409,7 @@ func ValidatePluginConfig(ctx context.Context, c *PluginConfig) error { auth := auth u, err := url.Parse(endpoint) if err != nil { - return fmt.Errorf("failed to parse registry url %q from `registry.auths`: %w", endpoint, err) + return warnings, fmt.Errorf("failed to parse registry url %q from `registry.auths`: %w", endpoint, err) } if u.Scheme != "" { // Do not include the scheme in the new registry config. @@ -422,22 +425,22 @@ func ValidatePluginConfig(ctx context.Context, c *PluginConfig) error { // Validation for stream_idle_timeout if c.StreamIdleTimeout != "" { if _, err := time.ParseDuration(c.StreamIdleTimeout); err != nil { - return fmt.Errorf("invalid stream idle timeout: %w", err) + return warnings, fmt.Errorf("invalid stream idle timeout: %w", err) } } // Validation for image_pull_progress_timeout if c.ImagePullProgressTimeout != "" { if _, err := time.ParseDuration(c.ImagePullProgressTimeout); err != nil { - return fmt.Errorf("invalid image pull progress timeout: %w", err) + return warnings, fmt.Errorf("invalid image pull progress timeout: %w", err) } } // Validation for drain_exec_sync_io_timeout if c.DrainExecSyncIOTimeout != "" { if _, err := time.ParseDuration(c.DrainExecSyncIOTimeout); err != nil { - return fmt.Errorf("invalid `drain_exec_sync_io_timeout`: %w", err) + return warnings, fmt.Errorf("invalid `drain_exec_sync_io_timeout`: %w", err) } } - return nil + return warnings, nil } diff --git a/pkg/cri/config/config_test.go b/pkg/cri/config/config_test.go index 5c021857e..c7086bcf6 100644 --- a/pkg/cri/config/config_test.go +++ b/pkg/cri/config/config_test.go @@ -21,6 +21,8 @@ import ( "testing" "github.com/stretchr/testify/assert" + + "github.com/containerd/containerd/v2/pkg/deprecation" ) func TestValidateConfig(t *testing.T) { @@ -28,6 +30,7 @@ func TestValidateConfig(t *testing.T) { config *PluginConfig expectedErr string expected *PluginConfig + warnings []deprecation.Warning }{ "no default_runtime_name": { config: &PluginConfig{}, @@ -143,13 +146,18 @@ func TestValidateConfig(t *testing.T) { }, } { t.Run(desc, func(t *testing.T) { - err := ValidatePluginConfig(context.Background(), test.config) + w, err := ValidatePluginConfig(context.Background(), test.config) if test.expectedErr != "" { assert.Contains(t, err.Error(), test.expectedErr) } else { assert.NoError(t, err) assert.Equal(t, test.expected, test.config) } + if len(test.warnings) > 0 { + assert.ElementsMatch(t, test.warnings, w) + } else { + assert.Len(t, w, 0) + } }) } } diff --git a/pkg/cri/cri.go b/pkg/cri/cri.go index c64d7b8dc..e85547e68 100644 --- a/pkg/cri/cri.go +++ b/pkg/cri/cri.go @@ -21,20 +21,21 @@ import ( "fmt" "path/filepath" - containerd "github.com/containerd/containerd/v2/client" - "github.com/containerd/containerd/v2/pkg/cri/nri" - "github.com/containerd/containerd/v2/pkg/cri/server" - nriservice "github.com/containerd/containerd/v2/pkg/nri" - "github.com/containerd/containerd/v2/platforms" - "github.com/containerd/containerd/v2/plugins" "github.com/containerd/log" "github.com/containerd/plugin" "github.com/containerd/plugin/registry" imagespec "github.com/opencontainers/image-spec/specs-go/v1" "k8s.io/klog/v2" + containerd "github.com/containerd/containerd/v2/client" criconfig "github.com/containerd/containerd/v2/pkg/cri/config" "github.com/containerd/containerd/v2/pkg/cri/constants" + "github.com/containerd/containerd/v2/pkg/cri/nri" + "github.com/containerd/containerd/v2/pkg/cri/server" + nriservice "github.com/containerd/containerd/v2/pkg/nri" + "github.com/containerd/containerd/v2/platforms" + "github.com/containerd/containerd/v2/plugins" + "github.com/containerd/containerd/v2/services/warning" ) // Register CRI service plugin @@ -48,6 +49,7 @@ func init() { plugins.EventPlugin, plugins.ServicePlugin, plugins.NRIApiPlugin, + plugins.WarningPlugin, }, InitFn: initCRIService, }) @@ -58,8 +60,17 @@ func initCRIService(ic *plugin.InitContext) (interface{}, error) { ic.Meta.Exports = map[string]string{"CRIVersion": constants.CRIVersion} ctx := ic.Context pluginConfig := ic.Config.(*criconfig.PluginConfig) - if err := criconfig.ValidatePluginConfig(ctx, pluginConfig); err != nil { + if warnings, err := criconfig.ValidatePluginConfig(ctx, pluginConfig); err != nil { return nil, fmt.Errorf("invalid plugin config: %w", err) + } else if len(warnings) > 0 { + ws, err := ic.GetSingle(plugins.WarningPlugin) + if err != nil { + return nil, err + } + warn := ws.(warning.Service) + for _, w := range warnings { + warn.Emit(ctx, w) + } } c := criconfig.Config{