Skip to content

Commit 186eb64

Browse files
samuelkarpthaJeztah
authored andcommitted
cri: write generated CNI config atomically on Unix
The 10-containerd-net.conflist file generated from the conf_template should be written atomically so that partial writes are not visible to CNI plugins. Use the new consistentfile package to ensure this on Unix-like platforms such as Linux, FreeBSD, and Darwin. Fixes #8607 Signed-off-by: Samuel Karp <[email protected]> (cherry picked from commit 3c4a1ab) Signed-off-by: Sebastiaan van Stijn <[email protected]>
1 parent 64c3dcd commit 186eb64

File tree

2 files changed

+60
-44
lines changed

2 files changed

+60
-44
lines changed

pkg/cri/sbserver/update_runtime_config.go

Lines changed: 30 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -26,8 +26,10 @@ import (
2626
"text/template"
2727
"time"
2828

29-
"github.com/containerd/containerd/log"
3029
runtime "k8s.io/cri-api/pkg/apis/runtime/v1"
30+
31+
"github.com/containerd/containerd/log"
32+
"github.com/containerd/containerd/pkg/atomicfile"
3133
)
3234

3335
// cniConfigTemplate contains the values containerd will overwrite
@@ -88,27 +90,8 @@ func (c *criService) UpdateRuntimeConfig(ctx context.Context, r *runtime.UpdateR
8890
log.G(ctx).Infof("CNI config is successfully loaded, skip generating cni config from template %q", confTemplate)
8991
return &runtime.UpdateRuntimeConfigResponse{}, nil
9092
}
91-
log.G(ctx).Infof("Generating cni config from template %q", confTemplate)
92-
// generate cni config file from the template with updated pod cidr.
93-
t, err := template.ParseFiles(confTemplate)
94-
if err != nil {
95-
return nil, fmt.Errorf("failed to parse cni config template %q: %w", confTemplate, err)
96-
}
97-
if err := os.MkdirAll(c.config.NetworkPluginConfDir, 0755); err != nil {
98-
return nil, fmt.Errorf("failed to create cni config directory: %q: %w", c.config.NetworkPluginConfDir, err)
99-
}
100-
confFile := filepath.Join(c.config.NetworkPluginConfDir, cniConfigFileName)
101-
f, err := os.OpenFile(confFile, os.O_WRONLY|os.O_CREATE, 0644)
102-
if err != nil {
103-
return nil, fmt.Errorf("failed to open cni config file %q: %w", confFile, err)
104-
}
105-
defer f.Close()
106-
if err := t.Execute(f, cniConfigTemplate{
107-
PodCIDR: cidrs[0],
108-
PodCIDRRanges: cidrs,
109-
Routes: routes,
110-
}); err != nil {
111-
return nil, fmt.Errorf("failed to generate cni config file %q: %w", confFile, err)
93+
if err := writeCNIConfigFile(ctx, c.config.NetworkPluginConfDir, confTemplate, cidrs[0], cidrs, routes); err != nil {
94+
return nil, err
11295
}
11396
return &runtime.UpdateRuntimeConfigResponse{}, nil
11497
}
@@ -138,3 +121,28 @@ func getRoutes(cidrs []string) ([]string, error) {
138121
}
139122
return routes, nil
140123
}
124+
125+
func writeCNIConfigFile(ctx context.Context, confDir string, confTemplate string, podCIDR string, podCIDRRanges []string, routes []string) error {
126+
log.G(ctx).Infof("Generating cni config from template %q", confTemplate)
127+
// generate cni config file from the template with updated pod cidr.
128+
t, err := template.ParseFiles(confTemplate)
129+
if err != nil {
130+
return fmt.Errorf("failed to parse cni config template %q: %w", confTemplate, err)
131+
}
132+
if err := os.MkdirAll(confDir, 0755); err != nil {
133+
return fmt.Errorf("failed to create cni config directory: %q: %w", confDir, err)
134+
}
135+
confFile := filepath.Join(confDir, cniConfigFileName)
136+
f, err := atomicfile.New(confFile, 0o644)
137+
defer func() {
138+
err = f.Close()
139+
}()
140+
if err := t.Execute(f, cniConfigTemplate{
141+
PodCIDR: podCIDR,
142+
PodCIDRRanges: podCIDRRanges,
143+
Routes: routes,
144+
}); err != nil {
145+
return fmt.Errorf("failed to generate cni config file %q: %w", confFile, err)
146+
}
147+
return err
148+
}

pkg/cri/server/update_runtime_config.go

Lines changed: 30 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -26,8 +26,10 @@ import (
2626
"text/template"
2727
"time"
2828

29-
"github.com/containerd/containerd/log"
3029
runtime "k8s.io/cri-api/pkg/apis/runtime/v1"
30+
31+
"github.com/containerd/containerd/log"
32+
"github.com/containerd/containerd/pkg/atomicfile"
3133
)
3234

3335
// cniConfigTemplate contains the values containerd will overwrite
@@ -89,27 +91,8 @@ func (c *criService) UpdateRuntimeConfig(ctx context.Context, r *runtime.UpdateR
8991
log.G(ctx).Infof("CNI config is successfully loaded, skip generating cni config from template %q", confTemplate)
9092
return &runtime.UpdateRuntimeConfigResponse{}, nil
9193
}
92-
log.G(ctx).Infof("Generating cni config from template %q", confTemplate)
93-
// generate cni config file from the template with updated pod cidr.
94-
t, err := template.ParseFiles(confTemplate)
95-
if err != nil {
96-
return nil, fmt.Errorf("failed to parse cni config template %q: %w", confTemplate, err)
97-
}
98-
if err := os.MkdirAll(c.config.NetworkPluginConfDir, 0755); err != nil {
99-
return nil, fmt.Errorf("failed to create cni config directory: %q: %w", c.config.NetworkPluginConfDir, err)
100-
}
101-
confFile := filepath.Join(c.config.NetworkPluginConfDir, cniConfigFileName)
102-
f, err := os.OpenFile(confFile, os.O_WRONLY|os.O_CREATE, 0644)
103-
if err != nil {
104-
return nil, fmt.Errorf("failed to open cni config file %q: %w", confFile, err)
105-
}
106-
defer f.Close()
107-
if err := t.Execute(f, cniConfigTemplate{
108-
PodCIDR: cidrs[0],
109-
PodCIDRRanges: cidrs,
110-
Routes: routes,
111-
}); err != nil {
112-
return nil, fmt.Errorf("failed to generate cni config file %q: %w", confFile, err)
94+
if err := writeCNIConfigFile(ctx, c.config.NetworkPluginConfDir, confTemplate, cidrs[0], cidrs, routes); err != nil {
95+
return nil, err
11396
}
11497
return &runtime.UpdateRuntimeConfigResponse{}, nil
11598
}
@@ -139,3 +122,28 @@ func getRoutes(cidrs []string) ([]string, error) {
139122
}
140123
return routes, nil
141124
}
125+
126+
func writeCNIConfigFile(ctx context.Context, confDir string, confTemplate string, podCIDR string, podCIDRRanges []string, routes []string) error {
127+
log.G(ctx).Infof("Generating cni config from template %q", confTemplate)
128+
// generate cni config file from the template with updated pod cidr.
129+
t, err := template.ParseFiles(confTemplate)
130+
if err != nil {
131+
return fmt.Errorf("failed to parse cni config template %q: %w", confTemplate, err)
132+
}
133+
if err := os.MkdirAll(confDir, 0755); err != nil {
134+
return fmt.Errorf("failed to create cni config directory: %q: %w", confDir, err)
135+
}
136+
confFile := filepath.Join(confDir, cniConfigFileName)
137+
f, err := atomicfile.New(confFile, 0o644)
138+
defer func() {
139+
err = f.Close()
140+
}()
141+
if err := t.Execute(f, cniConfigTemplate{
142+
PodCIDR: podCIDR,
143+
PodCIDRRanges: podCIDRRanges,
144+
Routes: routes,
145+
}); err != nil {
146+
return fmt.Errorf("failed to generate cni config file %q: %w", confFile, err)
147+
}
148+
return err
149+
}

0 commit comments

Comments
 (0)