Skip to content

Commit

Permalink
config/types/config: prevent files/links/dirs from conflicting with s…
Browse files Browse the repository at this point in the history
…ystemd units and dropins
  • Loading branch information
marmijo committed Nov 8, 2022
1 parent 8770e14 commit 2f63faa
Show file tree
Hide file tree
Showing 12 changed files with 1,492 additions and 0 deletions.
1 change: 1 addition & 0 deletions config/shared/errors/errors.go
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,7 @@ var (
ErrDuplicateLabels = errors.New("cannot use the same partition label twice")
ErrInvalidProxy = errors.New("proxies must be http(s)")
ErrInsecureProxy = errors.New("insecure plaintext HTTP proxy specified for HTTPS resources")
ErrPathConflictsSystemd = errors.New("path conflicts with systemd unit or dropin")

// Systemd section errors
ErrInvalidSystemdExt = errors.New("invalid systemd unit extension")
Expand Down
38 changes: 38 additions & 0 deletions config/v3_0/types/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,12 @@
package types

import (
"github.com/coreos/ignition/v2/config/shared/errors"
"github.com/coreos/ignition/v2/config/util"

"github.com/coreos/go-semver/semver"
"github.com/coreos/vcontext/path"
"github.com/coreos/vcontext/report"
)

var (
Expand All @@ -24,3 +29,36 @@ var (
Minor: 0,
}
)

func (cfg Config) Validate(c path.ContextPath) (r report.Report) {
systemdPath := "/etc/systemd/system/"
unitPaths := map[string]struct{}{}
for _, unit := range cfg.Systemd.Units {
if !util.NilOrEmpty(unit.Contents) {
pathString := systemdPath + unit.Name
unitPaths[pathString] = struct{}{}
}
for _, dropin := range unit.Dropins {
if !util.NilOrEmpty(dropin.Contents) {
pathString := systemdPath + unit.Name + ".d/" + dropin.Name
unitPaths[pathString] = struct{}{}
}
}
}
for i, f := range cfg.Storage.Files {
if _, exists := unitPaths[f.Path]; exists {
r.AddOnError(c.Append("storage", "files", i, "path"), errors.ErrPathConflictsSystemd)
}
}
for i, d := range cfg.Storage.Directories {
if _, exists := unitPaths[d.Path]; exists {
r.AddOnError(c.Append("storage", "directories", i, "path"), errors.ErrPathConflictsSystemd)
}
}
for i, l := range cfg.Storage.Links {
if _, exists := unitPaths[l.Path]; exists {
r.AddOnError(c.Append("storage", "links", i, "path"), errors.ErrPathConflictsSystemd)
}
}
return
}
260 changes: 260 additions & 0 deletions config/v3_0/types/config_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,260 @@
// Copyright 2020 Red Hat, Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package types

import (
"reflect"
"testing"

"github.com/coreos/ignition/v2/config/shared/errors"
"github.com/coreos/ignition/v2/config/util"

"github.com/coreos/vcontext/path"
"github.com/coreos/vcontext/report"
)

func TestConfigValidation(t *testing.T) {
tests := []struct {
in Config
out error
at path.ContextPath
}{
// test 0: file conflicts with systemd dropin file, error
{
in: Config{
Storage: Storage{
Files: []File{
{
Node: Node{Path: "/etc/systemd/system/foo.service.d/bar.conf"},
},
},
},
Systemd: Systemd{
Units: []Unit{
{
Name: "foo.service",
Dropins: []Dropin{
{
Name: "bar.conf",
Contents: util.StrToPtr("[Foo]\nQux=Bar"),
},
},
},
},
},
},
out: errors.ErrPathConflictsSystemd,
at: path.New("json", "storage", "files", 0, "path"),
},
// test 1: file conflicts with systemd unit, error
{
in: Config{
Storage: Storage{
Files: []File{
{
Node: Node{Path: "/etc/systemd/system/foo.service"},
},
},
},
Systemd: Systemd{
Units: []Unit{
{
Name: "foo.service",
Contents: util.StrToPtr("[Foo]\nQux=Bar"),
Enabled: util.BoolToPtr(true),
},
},
},
},
out: errors.ErrPathConflictsSystemd,
at: path.New("json", "storage", "files", 0, "path"),
},
// test 2: directory conflicts with systemd dropin file, error
{
in: Config{
Storage: Storage{
Directories: []Directory{
{
Node: Node{Path: "/etc/systemd/system/foo.service.d/bar.conf"},
},
},
},
Systemd: Systemd{
[]Unit{
{
Name: "foo.service",
Dropins: []Dropin{
{
Name: "bar.conf",
Contents: util.StrToPtr("[Foo]\nQux=Bar"),
},
},
},
},
},
},
out: errors.ErrPathConflictsSystemd,
at: path.New("json", "storage", "directories", 0, "path"),
},
// test 3: directory conflicts with systemd unit, error
{
in: Config{
Storage: Storage{
Directories: []Directory{
{
Node: Node{Path: "/etc/systemd/system/foo.service"},
},
},
},
Systemd: Systemd{
[]Unit{
{
Name: "foo.service",
Contents: util.StrToPtr("[foo]\nQux=Baz"),
Enabled: util.BoolToPtr(true),
},
},
},
},
out: errors.ErrPathConflictsSystemd,
at: path.New("json", "storage", "directories", 0, "path"),
},
// test 4: link conflicts with systemd dropin file, error
{
in: Config{
Storage: Storage{
Links: []Link{
{
Node: Node{Path: "/etc/systemd/system/foo.service.d/bar.conf"},
LinkEmbedded1: LinkEmbedded1{Target: "/qux.conf"},
},
},
},
Systemd: Systemd{
[]Unit{
{
Name: "foo.service",
Dropins: []Dropin{
{
Name: "bar.conf",
Contents: util.StrToPtr("[Foo]\nQux=Bar"),
},
},
},
},
},
},
out: errors.ErrPathConflictsSystemd,
at: path.New("json", "storage", "links", 0, "path"),
},
// test 5: link conflicts with systemd unit, error
{
in: Config{
Storage: Storage{
Links: []Link{
{
Node: Node{Path: "/etc/systemd/system/foo.service"},
LinkEmbedded1: LinkEmbedded1{Target: "/qux.conf"},
},
},
},
Systemd: Systemd{
[]Unit{
{
Name: "foo.service",
Contents: util.StrToPtr("[foo]\nQux=Baz"),
Enabled: util.BoolToPtr(true),
},
},
},
},
out: errors.ErrPathConflictsSystemd,
at: path.New("json", "storage", "links", 0, "path"),
},
// test 6: non-conflicting scenarios
{
in: Config{
Storage: Storage{
Files: []File{
{
Node: Node{Path: "/etc/systemd/system/bar.service.d/baz.conf"},
},
{
Node: Node{Path: "/etc/systemd/system/bar.service"},
},
{
Node: Node{Path: "/etc/systemd/system/foo.service.d/qux.conf"},
},
},
Links: []Link{
{
Node: Node{Path: "/etc/systemd/system/qux.service"},
LinkEmbedded1: LinkEmbedded1{Target: "/qux.conf"},
},
{
Node: Node{Path: "/etc/systemd/system/quux.service.d/foo.conf"},
LinkEmbedded1: LinkEmbedded1{Target: "/foo.conf"},
},
},
Directories: []Directory{
{
Node: Node{Path: "/etc/systemd/system/quux.service.d"},
},
},
},
Systemd: Systemd{
Units: []Unit{
{
Name: "foo.service",
Contents: util.StrToPtr("[Foo]\nQux=Baz"),
Enabled: util.BoolToPtr(true),
},
{
Name: "bar.service",
Dropins: []Dropin{
{
Name: "baz.conf",
},
},
Enabled: util.BoolToPtr(true),
},
{
Name: "qux.service",
Dropins: []Dropin{
{
Name: "bar.conf",
Contents: util.StrToPtr("[Foo]\nQux=Baz"),
},
},
},
{
Name: "quux.service",
Contents: util.StrToPtr("[Foo]\nQux=Baz"),
Enabled: util.BoolToPtr(true),
},
},
},
},
},
}
for i, test := range tests {
r := test.in.Validate(path.New("json"))
expected := report.Report{}
expected.AddOnError(test.at, test.out)
if !reflect.DeepEqual(expected, r) {
t.Errorf("#%d: bad error: expected : %v, got %v", i, expected, r)
}
}
}
38 changes: 38 additions & 0 deletions config/v3_1/types/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,12 @@
package types

import (
"github.com/coreos/ignition/v2/config/shared/errors"
"github.com/coreos/ignition/v2/config/util"

"github.com/coreos/go-semver/semver"
"github.com/coreos/vcontext/path"
"github.com/coreos/vcontext/report"
)

var (
Expand All @@ -24,3 +29,36 @@ var (
Minor: 1,
}
)

func (cfg Config) Validate(c path.ContextPath) (r report.Report) {
systemdPath := "/etc/systemd/system/"
unitPaths := map[string]struct{}{}
for _, unit := range cfg.Systemd.Units {
if !util.NilOrEmpty(unit.Contents) {
pathString := systemdPath + unit.Name
unitPaths[pathString] = struct{}{}
}
for _, dropin := range unit.Dropins {
if !util.NilOrEmpty(dropin.Contents) {
pathString := systemdPath + unit.Name + ".d/" + dropin.Name
unitPaths[pathString] = struct{}{}
}
}
}
for i, f := range cfg.Storage.Files {
if _, exists := unitPaths[f.Path]; exists {
r.AddOnError(c.Append("storage", "files", i, "path"), errors.ErrPathConflictsSystemd)
}
}
for i, d := range cfg.Storage.Directories {
if _, exists := unitPaths[d.Path]; exists {
r.AddOnError(c.Append("storage", "directories", i, "path"), errors.ErrPathConflictsSystemd)
}
}
for i, l := range cfg.Storage.Links {
if _, exists := unitPaths[l.Path]; exists {
r.AddOnError(c.Append("storage", "links", i, "path"), errors.ErrPathConflictsSystemd)
}
}
return
}
Loading

0 comments on commit 2f63faa

Please sign in to comment.