Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

*: add kernel argument support #1178

Merged
merged 6 commits into from
Apr 29, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
250 changes: 158 additions & 92 deletions config/merge/merge_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,8 @@ import (
"testing"

"github.com/coreos/ignition/v2/config/util"
"github.com/coreos/ignition/v2/config/v3_2/types"
v3_2 "github.com/coreos/ignition/v2/config/v3_2/types"
"github.com/coreos/ignition/v2/config/v3_3_experimental/types"

"github.com/coreos/vcontext/path"
"github.com/stretchr/testify/assert"
Expand Down Expand Up @@ -319,97 +320,6 @@ func TestMerge(t *testing.T) {
}},
},

// struct pointers
// we're not supposed to have any, but some ended up in the
// Clevis and Luks structs in spec 3.2.0
// https://github.com/coreos/ignition/issues/1132
{
in1: types.Config{
Storage: types.Storage{
Luks: []types.Luks{
// nested struct pointers, one override
{
Clevis: &types.Clevis{
arithx marked this conversation as resolved.
Show resolved Hide resolved
Custom: &types.Custom{
Config: "cfg",
Pin: "pin",
},
Threshold: util.IntToPtr(1),
},
Device: util.StrToPtr("/dev/foo"),
Name: "bar",
},
},
},
},
in2: types.Config{
Storage: types.Storage{
Luks: []types.Luks{
// nested struct pointers
{
Clevis: &types.Clevis{
Threshold: util.IntToPtr(2),
},
Name: "bar",
},
// struct pointer containing nil struct pointer
{
Clevis: &types.Clevis{
Tpm2: util.BoolToPtr(true),
},
Device: util.StrToPtr("/dev/baz"),
Name: "bleh",
},
},
},
},
out: types.Config{
Storage: types.Storage{
Luks: []types.Luks{
{
Clevis: &types.Clevis{
Custom: &types.Custom{
Config: "cfg",
Pin: "pin",
},
Threshold: util.IntToPtr(2),
},
Device: util.StrToPtr("/dev/foo"),
Name: "bar",
},
{
Clevis: &types.Clevis{
Tpm2: util.BoolToPtr(true),
},
Device: util.StrToPtr("/dev/baz"),
Name: "bleh",
},
},
},
},
transcript: Transcript{[]Mapping{
{path.New(TAG_PARENT, "storage", "luks", 0, "clevis", "custom", "config"), path.New(TAG_RESULT, "storage", "luks", 0, "clevis", "custom", "config")},
{path.New(TAG_PARENT, "storage", "luks", 0, "clevis", "custom", "pin"), path.New(TAG_RESULT, "storage", "luks", 0, "clevis", "custom", "pin")},
{path.New(TAG_PARENT, "storage", "luks", 0, "clevis", "custom"), path.New(TAG_RESULT, "storage", "luks", 0, "clevis", "custom")},
{path.New(TAG_CHILD, "storage", "luks", 0, "clevis", "threshold"), path.New(TAG_RESULT, "storage", "luks", 0, "clevis", "threshold")},
{path.New(TAG_PARENT, "storage", "luks", 0, "clevis"), path.New(TAG_RESULT, "storage", "luks", 0, "clevis")},
{path.New(TAG_CHILD, "storage", "luks", 0, "clevis"), path.New(TAG_RESULT, "storage", "luks", 0, "clevis")},
{path.New(TAG_PARENT, "storage", "luks", 0, "device"), path.New(TAG_RESULT, "storage", "luks", 0, "device")},
{path.New(TAG_CHILD, "storage", "luks", 0, "name"), path.New(TAG_RESULT, "storage", "luks", 0, "name")},
{path.New(TAG_PARENT, "storage", "luks", 0), path.New(TAG_RESULT, "storage", "luks", 0)},
{path.New(TAG_CHILD, "storage", "luks", 0), path.New(TAG_RESULT, "storage", "luks", 0)},
{path.New(TAG_CHILD, "storage", "luks", 1, "clevis", "tpm2"), path.New(TAG_RESULT, "storage", "luks", 1, "clevis", "tpm2")},
{path.New(TAG_CHILD, "storage", "luks", 1, "clevis"), path.New(TAG_RESULT, "storage", "luks", 1, "clevis")},
{path.New(TAG_CHILD, "storage", "luks", 1, "device"), path.New(TAG_RESULT, "storage", "luks", 1, "device")},
{path.New(TAG_CHILD, "storage", "luks", 1, "name"), path.New(TAG_RESULT, "storage", "luks", 1, "name")},
{path.New(TAG_CHILD, "storage", "luks", 1), path.New(TAG_RESULT, "storage", "luks", 1)},
{path.New(TAG_PARENT, "storage", "luks"), path.New(TAG_RESULT, "storage", "luks")},
{path.New(TAG_CHILD, "storage", "luks"), path.New(TAG_RESULT, "storage", "luks")},
{path.New(TAG_PARENT, "storage"), path.New(TAG_RESULT, "storage")},
{path.New(TAG_CHILD, "storage"), path.New(TAG_RESULT, "storage")},
}},
},

// merge config reference that contains HTTP headers
{
in1: types.Config{
Expand Down Expand Up @@ -1382,6 +1292,52 @@ func TestMerge(t *testing.T) {
{path.New(TAG_CHILD, "storage"), path.New(TAG_RESULT, "storage")},
}},
},

// kernel arguments MergedKeys test where child ShouldNotExist overrides parent ShouldExist
{
arithx marked this conversation as resolved.
Show resolved Hide resolved
in1: types.Config{
KernelArguments: types.KernelArguments{
ShouldExist: []types.KernelArgument{
"foo",
"bar baz",
"test",
},
ShouldNotExist: []types.KernelArgument{
"brown fox",
},
},
},
in2: types.Config{
KernelArguments: types.KernelArguments{
ShouldNotExist: []types.KernelArgument{
"test",
},
},
},
out: types.Config{
KernelArguments: types.KernelArguments{
ShouldExist: []types.KernelArgument{
"foo",
"bar baz",
},
ShouldNotExist: []types.KernelArgument{
"brown fox",
"test",
},
},
},
transcript: Transcript{[]Mapping{
{path.New(TAG_PARENT, "kernelArguments", "shouldExist", 0), path.New(TAG_RESULT, "kernelArguments", "shouldExist", 0)},
{path.New(TAG_PARENT, "kernelArguments", "shouldExist", 1), path.New(TAG_RESULT, "kernelArguments", "shouldExist", 1)},
{path.New(TAG_PARENT, "kernelArguments", "shouldExist"), path.New(TAG_RESULT, "kernelArguments", "shouldExist")},
{path.New(TAG_PARENT, "kernelArguments", "shouldNotExist", 0), path.New(TAG_RESULT, "kernelArguments", "shouldNotExist", 0)},
{path.New(TAG_CHILD, "kernelArguments", "shouldNotExist", 0), path.New(TAG_RESULT, "kernelArguments", "shouldNotExist", 1)},
{path.New(TAG_PARENT, "kernelArguments", "shouldNotExist"), path.New(TAG_RESULT, "kernelArguments", "shouldNotExist")},
{path.New(TAG_CHILD, "kernelArguments", "shouldNotExist"), path.New(TAG_RESULT, "kernelArguments", "shouldNotExist")},
{path.New(TAG_PARENT, "kernelArguments"), path.New(TAG_RESULT, "kernelArguments")},
{path.New(TAG_CHILD, "kernelArguments"), path.New(TAG_RESULT, "kernelArguments")},
}},
},
}

for i, test := range tests {
Expand All @@ -1392,3 +1348,113 @@ func TestMerge(t *testing.T) {
assert.Equal(t, test.transcript, transcript, "#%d bad transcript", i)
}
}

// We are explicitly testing 3.2.0 because it mistakenly has struct
// pointers. These should not exist but ended up in the Clevis & Luks
// structs in spec 3.2.0.
// https://github.com/coreos/ignition/issues/1132
func TestMergeStructPointers(t *testing.T) {
type test struct {
in1 v3_2.Config
in2 v3_2.Config
out v3_2.Config
transcript Transcript
}

tests := []test{
{
in1: v3_2.Config{
Storage: v3_2.Storage{
Luks: []v3_2.Luks{
// nested struct pointers, one override
{
Clevis: &v3_2.Clevis{
Custom: &v3_2.Custom{
Config: "cfg",
Pin: "pin",
},
Threshold: util.IntToPtr(1),
},
Device: util.StrToPtr("/dev/foo"),
Name: "bar",
},
},
},
},
in2: v3_2.Config{
Storage: v3_2.Storage{
Luks: []v3_2.Luks{
// nested struct pointers
{
Clevis: &v3_2.Clevis{
Threshold: util.IntToPtr(2),
},
Name: "bar",
},
// struct pointer containing nil struct pointer
{
Clevis: &v3_2.Clevis{
Tpm2: util.BoolToPtr(true),
},
Device: util.StrToPtr("/dev/baz"),
Name: "bleh",
},
},
},
},
out: v3_2.Config{
Storage: v3_2.Storage{
Luks: []v3_2.Luks{
{
Clevis: &v3_2.Clevis{
Custom: &v3_2.Custom{
Config: "cfg",
Pin: "pin",
},
Threshold: util.IntToPtr(2),
},
Device: util.StrToPtr("/dev/foo"),
Name: "bar",
},
{
Clevis: &v3_2.Clevis{
Tpm2: util.BoolToPtr(true),
},
Device: util.StrToPtr("/dev/baz"),
Name: "bleh",
},
},
},
},
transcript: Transcript{[]Mapping{
{path.New(TAG_PARENT, "storage", "luks", 0, "clevis", "custom", "config"), path.New(TAG_RESULT, "storage", "luks", 0, "clevis", "custom", "config")},
{path.New(TAG_PARENT, "storage", "luks", 0, "clevis", "custom", "pin"), path.New(TAG_RESULT, "storage", "luks", 0, "clevis", "custom", "pin")},
{path.New(TAG_PARENT, "storage", "luks", 0, "clevis", "custom"), path.New(TAG_RESULT, "storage", "luks", 0, "clevis", "custom")},
{path.New(TAG_CHILD, "storage", "luks", 0, "clevis", "threshold"), path.New(TAG_RESULT, "storage", "luks", 0, "clevis", "threshold")},
{path.New(TAG_PARENT, "storage", "luks", 0, "clevis"), path.New(TAG_RESULT, "storage", "luks", 0, "clevis")},
{path.New(TAG_CHILD, "storage", "luks", 0, "clevis"), path.New(TAG_RESULT, "storage", "luks", 0, "clevis")},
{path.New(TAG_PARENT, "storage", "luks", 0, "device"), path.New(TAG_RESULT, "storage", "luks", 0, "device")},
{path.New(TAG_CHILD, "storage", "luks", 0, "name"), path.New(TAG_RESULT, "storage", "luks", 0, "name")},
{path.New(TAG_PARENT, "storage", "luks", 0), path.New(TAG_RESULT, "storage", "luks", 0)},
{path.New(TAG_CHILD, "storage", "luks", 0), path.New(TAG_RESULT, "storage", "luks", 0)},
{path.New(TAG_CHILD, "storage", "luks", 1, "clevis", "tpm2"), path.New(TAG_RESULT, "storage", "luks", 1, "clevis", "tpm2")},
{path.New(TAG_CHILD, "storage", "luks", 1, "clevis"), path.New(TAG_RESULT, "storage", "luks", 1, "clevis")},
{path.New(TAG_CHILD, "storage", "luks", 1, "device"), path.New(TAG_RESULT, "storage", "luks", 1, "device")},
{path.New(TAG_CHILD, "storage", "luks", 1, "name"), path.New(TAG_RESULT, "storage", "luks", 1, "name")},
{path.New(TAG_CHILD, "storage", "luks", 1), path.New(TAG_RESULT, "storage", "luks", 1)},
{path.New(TAG_PARENT, "storage", "luks"), path.New(TAG_RESULT, "storage", "luks")},
{path.New(TAG_CHILD, "storage", "luks"), path.New(TAG_RESULT, "storage", "luks")},
{path.New(TAG_PARENT, "storage"), path.New(TAG_RESULT, "storage")},
{path.New(TAG_CHILD, "storage"), path.New(TAG_RESULT, "storage")},
}},
},
}

for i, test := range tests {
outi, transcript := MergeStructTranscribe(test.in1, test.in2)
out := outi.(v3_2.Config)

assert.Equal(t, test.out, out, "#%d bad merge", i)
assert.Equal(t, test.transcript, transcript, "#%d bad transcript", i)
}
}
23 changes: 23 additions & 0 deletions config/v3_3_experimental/schema/ignition.json
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,9 @@
},
"passwd": {
"$ref": "#/definitions/passwd"
},
"kernelArguments": {
"$ref": "#/definitions/kernelArguments"
}
},
"required": [
Expand Down Expand Up @@ -543,6 +546,26 @@
}
}
},
"kernelArguments": {
"type": "object",
"properties": {
"shouldExist": {
"type": "array",
"items": {
"$ref": "#/definitions/kernelArgument"
}
},
"shouldNotExist": {
"type": "array",
"items": {
"$ref": "#/definitions/kernelArgument"
}
}
}
},
"kernelArgument": {
arithx marked this conversation as resolved.
Show resolved Hide resolved
"type": "string"
},
"passwd": {
"type": "object",
"properties": {
Expand Down
5 changes: 4 additions & 1 deletion config/v3_3_experimental/translate/translate.go
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,9 @@ func Translate(old old_types.Config) (ret types.Config) {
tr := translate.NewTranslator()
tr.AddCustomTranslator(translateIgnition)
tr.AddCustomTranslator(translateLuks)
tr.Translate(&old, &ret)
tr.Translate(&old.Ignition, &ret.Ignition)
tr.Translate(&old.Passwd, &ret.Passwd)
arithx marked this conversation as resolved.
Show resolved Hide resolved
tr.Translate(&old.Storage, &ret.Storage)
tr.Translate(&old.Systemd, &ret.Systemd)
return
}
22 changes: 22 additions & 0 deletions config/v3_3_experimental/types/kargs.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
// Copyright 2021 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

func (k KernelArguments) MergedKeys() map[string]string {
return map[string]string{
"ShouldExist": "KernelArgument",
"ShouldNotExist": "KernelArgument",
}
}
51 changes: 51 additions & 0 deletions config/v3_3_experimental/types/kargs_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
// Copyright 2021 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 (
"testing"

"github.com/coreos/ignition/v2/config/validate"
)

func TestKernelArgumentsValidate(t *testing.T) {
tests := []struct {
in KernelArguments
out string
}{
// Ensure that ValidateWithContext prevents duplicate entries
// in ShouldExist & ShouldNotExist
{
KernelArguments{
ShouldExist: []KernelArgument{
"foo",
"bar",
},
ShouldNotExist: []KernelArgument{
"baz",
"foo",
},
},
"error at $.shouldNotExist.1: duplicate entry defined\n",
},
}

for i, test := range tests {
r := validate.ValidateWithContext(test.in, nil)
if test.out != r.String() {
t.Errorf("#%d: bad error: want %q, got %q", i, test.out, r.String())
}
}
}