Keep host order as defined in TOML file

Signed-off-by: Maksym Pavlenko <pavlenko.maksym@gmail.com>
This commit is contained in:
Maksym Pavlenko 2021-04-01 09:29:16 -07:00
parent 6866b36ab6
commit 5ada2f74a7
3 changed files with 48 additions and 15 deletions

View File

@ -48,7 +48,7 @@ type Runtime struct {
// This only works for runtime type "io.containerd.runtime.v1.linux".
Root string `toml:"runtime_root" json:"runtimeRoot"`
// Options are config options for the runtime. If options is loaded
// from toml config, it will be toml.Primitive.
// from toml config, it will be toml.Tree.
Options *toml.Tree `toml:"options" json:"options"`
// PrivilegedWithoutHostDevices overloads the default behaviour for adding host devices to the
// runtime spec when the container is privileged. Defaults to false.

View File

@ -27,15 +27,15 @@ import (
"os"
"path"
"path/filepath"
"sort"
"strings"
"time"
"github.com/pelletier/go-toml"
"github.com/pkg/errors"
"github.com/containerd/containerd/errdefs"
"github.com/containerd/containerd/log"
"github.com/containerd/containerd/remotes/docker"
"github.com/pelletier/go-toml"
"github.com/pkg/errors"
)
// UpdateClientFunc is a function that lets you to amend http Client behavior used by registry clients.
@ -317,6 +317,11 @@ func parseHostsFile(baseDir string, b []byte) ([]hostConfig, error) {
HostConfigs map[string]hostFileConfig `toml:"host"`
}{}
orderedHosts, err := getSortedHosts(tree)
if err != nil {
return nil, err
}
var (
hosts []hostConfig
)
@ -325,15 +330,10 @@ func parseHostsFile(baseDir string, b []byte) ([]hostConfig, error) {
return nil, err
}
// Parse root host config
parsed, err := parseHostConfig(c.Server, baseDir, c.HostFileConfig)
if err != nil {
return nil, err
}
hosts = append(hosts, parsed)
// Parse hosts array
for host, config := range c.HostConfigs {
for _, host := range orderedHosts {
config := c.HostConfigs[host]
parsed, err := parseHostConfig(host, baseDir, config)
if err != nil {
return nil, err
@ -341,6 +341,13 @@ func parseHostsFile(baseDir string, b []byte) ([]hostConfig, error) {
hosts = append(hosts, parsed)
}
// Parse root host config and append it as the last element
parsed, err := parseHostConfig(c.Server, baseDir, c.HostFileConfig)
if err != nil {
return nil, err
}
hosts = append(hosts, parsed)
return hosts, nil
}
@ -464,6 +471,26 @@ func parseHostConfig(server string, baseDir string, config hostFileConfig) (host
return result, nil
}
// getSortedHosts returns the list of hosts as they defined in the file.
func getSortedHosts(root *toml.Tree) ([]string, error) {
iter, ok := root.Get("host").(*toml.Tree)
if !ok {
return nil, errors.Errorf("invalid `host` tree")
}
list := append([]string{}, iter.Keys()...)
// go-toml stores TOML sections in the map object, so no order guaranteed.
// We retrieve line number for each key and sort the keys by position.
sort.Slice(list, func(i, j int) bool {
h1 := iter.GetPath([]string{list[i]}).(*toml.Tree)
h2 := iter.GetPath([]string{list[j]}).(*toml.Tree)
return h1.Position().Line < h2.Position().Line
})
return list, nil
}
// makeStringSlice is a helper func to convert from []interface{} to []string.
// Additionally an optional cb func may be passed to perform string mapping.
func makeStringSlice(slice []interface{}, cb func(string) string) ([]string, error) {

View File

@ -26,8 +26,6 @@ import (
"path/filepath"
"testing"
"github.com/stretchr/testify/assert"
"github.com/containerd/containerd/log/logtest"
"github.com/containerd/containerd/remotes/docker"
)
@ -181,7 +179,15 @@ ca = "/etc/path/default"
}
}()
assert.ElementsMatch(t, expected, hosts)
if len(hosts) != len(expected) {
t.Fatalf("Unexpected number of hosts %d, expected %d", len(hosts), len(expected))
}
for i := range hosts {
if !compareHostConfig(hosts[i], expected[i]) {
t.Fatalf("Mismatch at host %d", i)
}
}
}
func TestLoadCertFiles(t *testing.T) {