Skip to content

Commit 194cee9

Browse files
committed
v3_5_experimental: add validation, unit tests and error
1 parent dfcba34 commit 194cee9

File tree

4 files changed

+45
-43
lines changed

4 files changed

+45
-43
lines changed

config/shared/errors/errors.go

+2-1
Original file line numberDiff line numberDiff line change
@@ -85,7 +85,8 @@ var (
8585
ErrInvalidProxy = errors.New("proxies must be http(s)")
8686
ErrInsecureProxy = errors.New("insecure plaintext HTTP proxy specified for HTTPS resources")
8787
ErrPathConflictsSystemd = errors.New("path conflicts with systemd unit or dropin")
88-
ErrPathConflictsParentDir = errors.New("path conflicts with parent directory of another file, link, or directory")
88+
ErrPathAlreadyExists = errors.New("path already exists")
89+
ErrMissLabeledDir = errors.New("parent directory path matches configured file, check path, and ensure parent directory is configured")
8990

9091
// Systemd section errors
9192
ErrInvalidSystemdExt = errors.New("invalid systemd unit extension")

config/v3_5_experimental/types/config.go

+36-33
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
package types
1616

1717
import (
18+
"fmt"
1819
"path/filepath"
1920
"sort"
2021
"strings"
@@ -35,6 +36,8 @@ var (
3536
}
3637
)
3738

39+
var paths = map[string]struct{}{}
40+
3841
func (cfg Config) Validate(c path.ContextPath) (r report.Report) {
3942
systemdPath := "/etc/systemd/system/"
4043
unitPaths := map[string]struct{}{}
@@ -76,43 +79,21 @@ func (cfg Config) validateParents(c path.ContextPath) report.Report {
7679
Path string
7780
Field string
7881
}
79-
paths := map[string]struct{}{}
8082
r := report.Report{}
8183

8284
for i, f := range cfg.Storage.Files {
83-
if _, exists := paths[f.Path]; exists {
84-
r.AddOnError(c.Append("storage", "files", i, "path"), errors.ErrPathConflictsParentDir) //TODO: should add different error?
85-
return r
86-
}
87-
paths[f.Path] = struct{}{}
88-
entries = append(entries, struct {
89-
Path string
90-
Field string
91-
}{Path: f.Path, Field: "files"})
85+
r = handlePathConflict(f.Path, "files", i, c, r, errors.ErrPathAlreadyExists)
86+
addPathAndEntry(f.Path, "files", &entries)
9287
}
9388

9489
for i, d := range cfg.Storage.Directories {
95-
if _, exists := paths[d.Path]; exists {
96-
r.AddOnError(c.Append("storage", "directories", i, "path"), errors.ErrPathConflictsParentDir) //TODO: should add different error?
97-
return r
98-
}
99-
paths[d.Path] = struct{}{}
100-
entries = append(entries, struct {
101-
Path string
102-
Field string
103-
}{Path: d.Path, Field: "directories"})
90+
r = handlePathConflict(d.Path, "directories", i, c, r, errors.ErrPathAlreadyExists)
91+
addPathAndEntry(d.Path, "directories", &entries)
10492
}
10593

10694
for i, l := range cfg.Storage.Links {
107-
if _, exists := paths[l.Path]; exists {
108-
r.AddOnError(c.Append("storage", "links", i, "path"), errors.ErrPathConflictsParentDir) //TODO: error to already exist path
109-
return r
110-
}
111-
paths[l.Path] = struct{}{}
112-
entries = append(entries, struct {
113-
Path string
114-
Field string
115-
}{Path: l.Path, Field: "links"})
95+
r = handlePathConflict(l.Path, "links", i, c, r, errors.ErrPathAlreadyExists)
96+
addPathAndEntry(l.Path, "links", &entries)
11697
}
11798

11899
sort.Slice(entries, func(i, j int) bool {
@@ -122,7 +103,8 @@ func (cfg Config) validateParents(c path.ContextPath) report.Report {
122103
for i, entry := range entries {
123104
if i > 0 && isWithin(entry.Path, entries[i-1].Path) {
124105
if entries[i-1].Field != "directories" {
125-
r.AddOnError(c.Append("storage", entry.Field, i, "path"), errors.ErrPathConflictsParentDir) //TODO: conflict parent directories error
106+
errorMsg := fmt.Errorf("invalid entry at path %s: %v", entry.Path, errors.ErrMissLabeledDir)
107+
r.AddOnError(c.Append("storage", entry.Field, i, "path"), errorMsg)
126108
return r
127109
}
128110
}
@@ -131,16 +113,37 @@ func (cfg Config) validateParents(c path.ContextPath) report.Report {
131113
return r
132114
}
133115

134-
// check the depth
116+
func handlePathConflict(path, fieldName string, index int, c path.ContextPath, r report.Report, err error) report.Report {
117+
if _, exists := paths[path]; exists {
118+
r.AddOnError(c.Append("storage", fieldName, index, "path"), err)
119+
}
120+
return r
121+
}
122+
123+
func addPathAndEntry(path, fieldName string, entries *[]struct{ Path, Field string }) {
124+
*entries = append(*entries, struct {
125+
Path string
126+
Field string
127+
}{Path: path, Field: fieldName})
128+
}
129+
135130
func depth(path string) uint {
136131
var count uint
137-
for p := filepath.Clean(path); p != "/" && p != "."; count++ {
138-
p = filepath.Dir(p)
132+
cleanedPath := filepath.FromSlash(filepath.Clean(path))
133+
sep := string(filepath.Separator)
134+
135+
volume := filepath.VolumeName(cleanedPath)
136+
if volume != "" {
137+
cleanedPath = cleanedPath[len(volume):]
138+
}
139+
140+
for cleanedPath != sep && cleanedPath != "." {
141+
cleanedPath = filepath.Dir(cleanedPath)
142+
count++
139143
}
140144
return count
141145
}
142146

143-
// isWithin checks if newPath is within prevPath.
144147
func isWithin(newPath, prevPath string) bool {
145148
return strings.HasPrefix(newPath, prevPath) && newPath != prevPath
146149
}

config/v3_5_experimental/types/config_test.go

+6-9
Original file line numberDiff line numberDiff line change
@@ -15,12 +15,12 @@
1515
package types
1616

1717
import (
18+
"fmt"
1819
"reflect"
1920
"testing"
2021

2122
"github.com/coreos/ignition/v2/config/shared/errors"
2223
"github.com/coreos/ignition/v2/config/util"
23-
2424
"github.com/coreos/vcontext/path"
2525
"github.com/coreos/vcontext/report"
2626
)
@@ -194,10 +194,9 @@ func TestConfigValidation(t *testing.T) {
194194
},
195195
},
196196
},
197-
out: errors.ErrPathConflictsParentDir,
197+
out: fmt.Errorf("invalid entry at path /foo/bar/baz: %w", errors.ErrMissLabeledDir),
198198
at: path.New("json", "storage", "files", 1, "path"),
199199
},
200-
201200
// test 7: file path conflicts with link path, should error
202201
{
203202
in: Config{
@@ -210,8 +209,8 @@ func TestConfigValidation(t *testing.T) {
210209
},
211210
},
212211
},
213-
out: errors.ErrPathConflictsParentDir,
214-
at: path.New("json", "storage", "links", 0, "path"),
212+
out: fmt.Errorf("invalid entry at path /foo/bar/baz: %w", errors.ErrMissLabeledDir),
213+
at: path.New("json", "storage", "links", 1, "path"),
215214
},
216215

217216
// test 8: file path conflicts with directory path, should error
@@ -220,15 +219,14 @@ func TestConfigValidation(t *testing.T) {
220219
Storage: Storage{
221220
Files: []File{
222221
{Node: Node{Path: "/foo/bar"}},
223-
{Node: Node{Path: "/foo/bar"}},
224222
},
225223
Directories: []Directory{
226224
{Node: Node{Path: "/foo/bar/baz"}},
227225
},
228226
},
229227
},
230-
out: errors.ErrPathConflictsParentDir,
231-
at: path.New("json", "storage", "directories", 0, "path"),
228+
out: fmt.Errorf("invalid entry at path /foo/bar/baz: %w", errors.ErrMissLabeledDir),
229+
at: path.New("json", "storage", "directories", 1, "path"),
232230
},
233231

234232
// test 9: non-conflicting scenarios with systemd unit and systemd dropin file, should not error
@@ -302,7 +300,6 @@ func TestConfigValidation(t *testing.T) {
302300
in: Config{
303301
Storage: Storage{
304302
Files: []File{
305-
{Node: Node{Path: "/foo/bar"}},
306303
{Node: Node{Path: "/foo/bar/baz"}},
307304
},
308305
Directories: []Directory{

docs/release-notes.md

+1
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ nav_order: 9
2424

2525
- Fix failure when config only disables units already disabled
2626
- Retry HTTP requests on Azure on status codes 404, 410, and 429
27+
- Fix validation to catch conflicts with the parent directory of another file, link or directories
2728

2829

2930
## Ignition 2.17.0 (2023-11-20)

0 commit comments

Comments
 (0)