vendor files

This commit is contained in:
Serguei Bezverkhi
2018-01-09 13:57:14 -05:00
parent 558bc6c02a
commit 7b24313bd6
16547 changed files with 4527373 additions and 0 deletions

68
vendor/k8s.io/kubernetes/test/e2e_node/system/BUILD generated vendored Normal file
View File

@ -0,0 +1,68 @@
package(default_visibility = ["//visibility:public"])
load(
"@io_bazel_rules_go//go:def.bzl",
"go_library",
"go_test",
)
go_library(
name = "go_default_library",
srcs = [
"cgroup_validator.go",
"docker_validator.go",
"kernel_validator.go",
"kernel_validator_helper.go",
"os_validator.go",
"package_validator.go",
"report.go",
"types.go",
"types_unix.go",
"validators.go",
] + select({
"@io_bazel_rules_go//go/platform:windows_amd64": [
"types_windows.go",
],
"//conditions:default": [],
}),
importpath = "k8s.io/kubernetes/test/e2e_node/system",
deps = [
"//vendor/github.com/blang/semver:go_default_library",
"//vendor/github.com/docker/docker/api/types:go_default_library",
"//vendor/github.com/docker/docker/client:go_default_library",
"//vendor/github.com/golang/glog:go_default_library",
"//vendor/golang.org/x/net/context:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/util/errors:go_default_library",
],
)
go_test(
name = "go_default_test",
srcs = [
"cgroup_validator_test.go",
"docker_validator_test.go",
"kernel_validator_test.go",
"os_validator_test.go",
"package_validator_test.go",
],
importpath = "k8s.io/kubernetes/test/e2e_node/system",
library = ":go_default_library",
tags = ["e2e"],
deps = [
"//vendor/github.com/docker/docker/api/types:go_default_library",
"//vendor/github.com/stretchr/testify/assert:go_default_library",
],
)
filegroup(
name = "package-srcs",
srcs = glob(["**"]),
tags = ["automanaged"],
visibility = ["//visibility:private"],
)
filegroup(
name = "all-srcs",
srcs = [":package-srcs"],
tags = ["automanaged"],
)

View File

@ -0,0 +1,95 @@
/*
Copyright 2016 The Kubernetes Authors.
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 system
import (
"bufio"
"fmt"
"os"
"strings"
)
var _ Validator = &CgroupsValidator{}
type CgroupsValidator struct {
Reporter Reporter
}
func (c *CgroupsValidator) Name() string {
return "cgroups"
}
const (
cgroupsConfigPrefix = "CGROUPS_"
)
func (c *CgroupsValidator) Validate(spec SysSpec) (error, error) {
subsystems, err := c.getCgroupSubsystems()
if err != nil {
return nil, fmt.Errorf("failed to get cgroup subsystems: %v", err)
}
return nil, c.validateCgroupSubsystems(spec.Cgroups, subsystems)
}
func (c *CgroupsValidator) validateCgroupSubsystems(cgroupSpec, subsystems []string) error {
missing := []string{}
for _, cgroup := range cgroupSpec {
found := false
for _, subsystem := range subsystems {
if cgroup == subsystem {
found = true
break
}
}
item := cgroupsConfigPrefix + strings.ToUpper(cgroup)
if found {
c.Reporter.Report(item, "enabled", good)
} else {
c.Reporter.Report(item, "missing", bad)
missing = append(missing, cgroup)
}
}
if len(missing) > 0 {
return fmt.Errorf("missing cgroups: %s", strings.Join(missing, " "))
}
return nil
}
func (c *CgroupsValidator) getCgroupSubsystems() ([]string, error) {
f, err := os.Open("/proc/cgroups")
if err != nil {
return nil, err
}
defer f.Close()
subsystems := []string{}
s := bufio.NewScanner(f)
for s.Scan() {
if err := s.Err(); err != nil {
return nil, err
}
text := s.Text()
if text[0] != '#' {
parts := strings.Fields(text)
if len(parts) >= 4 && parts[3] != "0" {
subsystems = append(subsystems, parts[0])
}
}
}
return subsystems, nil
}

View File

@ -0,0 +1,56 @@
/*
Copyright 2016 The Kubernetes Authors.
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 system
import (
"testing"
"github.com/stretchr/testify/assert"
)
func TestValidateCgroupSubsystem(t *testing.T) {
v := &CgroupsValidator{
Reporter: DefaultReporter,
}
cgroupSpec := []string{"system1", "system2"}
for desc, test := range map[string]struct {
cgroupSpec []string
subsystems []string
err bool
}{
"missing cgroup subsystem should report error": {
subsystems: []string{"system1"},
err: true,
},
"extra cgroup subsystems should not report error": {
subsystems: []string{"system1", "system2", "system3"},
err: false,
},
"subsystems the same with spec should not report error": {
subsystems: []string{"system1", "system2"},
err: false,
},
} {
err := v.validateCgroupSubsystems(cgroupSpec, test.subsystems)
if !test.err {
assert.Nil(t, err, "%q: Expect error not to occur with cgroup", desc)
} else {
assert.NotNil(t, err, "%q: Expect error to occur with docker info", desc)
}
}
}

View File

@ -0,0 +1,100 @@
/*
Copyright 2016 The Kubernetes Authors.
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 system
import (
"fmt"
"regexp"
"github.com/docker/docker/api/types"
"github.com/docker/docker/client"
"golang.org/x/net/context"
)
var _ Validator = &DockerValidator{}
// DockerValidator validates docker configuration.
type DockerValidator struct {
Reporter Reporter
}
func (d *DockerValidator) Name() string {
return "docker"
}
const (
dockerConfigPrefix = "DOCKER_"
maxDockerValidatedVersion = "17.03"
)
// TODO(random-liu): Add more validating items.
func (d *DockerValidator) Validate(spec SysSpec) (error, error) {
if spec.RuntimeSpec.DockerSpec == nil {
// If DockerSpec is not specified, assume current runtime is not
// docker, skip the docker configuration validation.
return nil, nil
}
c, err := client.NewClient(dockerEndpoint, "", nil, nil)
if err != nil {
return nil, fmt.Errorf("failed to create docker client: %v", err)
}
info, err := c.Info(context.Background())
if err != nil {
return nil, fmt.Errorf("failed to get docker info: %v", err)
}
return d.validateDockerInfo(spec.RuntimeSpec.DockerSpec, info)
}
func (d *DockerValidator) validateDockerInfo(spec *DockerSpec, info types.Info) (error, error) {
// Validate docker version.
matched := false
for _, v := range spec.Version {
r := regexp.MustCompile(v)
if r.MatchString(info.ServerVersion) {
d.Reporter.Report(dockerConfigPrefix+"VERSION", info.ServerVersion, good)
matched = true
}
}
if !matched {
// If it's of the new Docker version scheme but didn't match above, it
// must be a newer version than the most recently validated one.
ver := `\d{2}\.\d+\.\d+-[a-z]{2}`
r := regexp.MustCompile(ver)
if r.MatchString(info.ServerVersion) {
d.Reporter.Report(dockerConfigPrefix+"VERSION", info.ServerVersion, good)
w := fmt.Errorf(
"docker version is greater than the most recently validated version. Docker version: %s. Max validated version: %s",
info.ServerVersion,
maxDockerValidatedVersion,
)
return w, nil
}
d.Reporter.Report(dockerConfigPrefix+"VERSION", info.ServerVersion, bad)
return nil, fmt.Errorf("unsupported docker version: %s", info.ServerVersion)
}
// Validate graph driver.
item := dockerConfigPrefix + "GRAPH_DRIVER"
for _, gd := range spec.GraphDriver {
if info.Driver == gd {
d.Reporter.Report(item, info.Driver, good)
return nil, nil
}
}
d.Reporter.Report(item, info.Driver, bad)
return nil, fmt.Errorf("unsupported graph driver: %s", info.Driver)
}

View File

@ -0,0 +1,88 @@
/*
Copyright 2016 The Kubernetes Authors.
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 system
import (
"testing"
"github.com/docker/docker/api/types"
"github.com/stretchr/testify/assert"
)
func TestValidateDockerInfo(t *testing.T) {
v := &DockerValidator{
Reporter: DefaultReporter,
}
spec := &DockerSpec{
Version: []string{`1\.1[1-3]\..*`, `17\.03\..*`}, // Requires [1.11, 17.03].
GraphDriver: []string{"driver_1", "driver_2"},
}
for _, test := range []struct {
info types.Info
err bool
warn bool
}{
{
info: types.Info{Driver: "driver_1", ServerVersion: "1.10.1"},
err: true,
warn: false,
},
{
info: types.Info{Driver: "bad_driver", ServerVersion: "1.11.1"},
err: true,
warn: false,
},
{
info: types.Info{Driver: "driver_1", ServerVersion: "1.11.1"},
err: false,
warn: false,
},
{
info: types.Info{Driver: "driver_2", ServerVersion: "1.12.1"},
err: false,
warn: false,
},
{
info: types.Info{Driver: "driver_2", ServerVersion: "1.13.1"},
err: false,
warn: false,
},
{
info: types.Info{Driver: "driver_2", ServerVersion: "17.03.0-ce"},
err: false,
warn: false,
},
{
info: types.Info{Driver: "driver_2", ServerVersion: "17.06.0-ce"},
err: false,
warn: true,
},
} {
warn, err := v.validateDockerInfo(spec, test.info)
if !test.err {
assert.Nil(t, err, "Expect error not to occur with docker info %+v", test.info)
} else {
assert.NotNil(t, err, "Expect error to occur with docker info %+v", test.info)
}
if !test.warn {
assert.Nil(t, warn, "Expect error not to occur with docker info %+v", test.info)
} else {
assert.NotNil(t, warn, "Expect error to occur with docker info %+v", test.info)
}
}
}

View File

@ -0,0 +1,259 @@
/*
Copyright 2016 The Kubernetes Authors.
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 system
import (
"bufio"
"bytes"
"compress/gzip"
"fmt"
"io"
"io/ioutil"
"os"
"os/exec"
"path/filepath"
"regexp"
"strings"
"github.com/golang/glog"
"k8s.io/apimachinery/pkg/util/errors"
)
var _ Validator = &KernelValidator{}
// KernelValidator validates kernel. Currently only validate kernel version
// and kernel configuration.
type KernelValidator struct {
kernelRelease string
Reporter Reporter
}
func (k *KernelValidator) Name() string {
return "kernel"
}
// kConfigOption is the possible kernel config option.
type kConfigOption string
const (
builtIn kConfigOption = "y"
asModule kConfigOption = "m"
leftOut kConfigOption = "n"
// validKConfigRegex is the regex matching kernel configuration line.
validKConfigRegex = "^CONFIG_[A-Z0-9_]+=[myn]"
// kConfigPrefix is the prefix of kernel configuration.
kConfigPrefix = "CONFIG_"
)
func (k *KernelValidator) Validate(spec SysSpec) (error, error) {
helper := KernelValidatorHelperImpl{}
release, err := helper.GetKernelReleaseVersion()
if err != nil {
return nil, fmt.Errorf("failed to get kernel release: %v", err)
}
k.kernelRelease = release
var errs []error
errs = append(errs, k.validateKernelVersion(spec.KernelSpec))
// only validate kernel config when necessary (currently no kernel config for windows)
if len(spec.KernelSpec.Required) > 0 || len(spec.KernelSpec.Forbidden) > 0 || len(spec.KernelSpec.Optional) > 0 {
errs = append(errs, k.validateKernelConfig(spec.KernelSpec))
}
return nil, errors.NewAggregate(errs)
}
// validateKernelVersion validates the kernel version.
func (k *KernelValidator) validateKernelVersion(kSpec KernelSpec) error {
glog.Infof("Validating kernel version")
versionRegexps := kSpec.Versions
for _, versionRegexp := range versionRegexps {
r := regexp.MustCompile(versionRegexp)
if r.MatchString(k.kernelRelease) {
k.Reporter.Report("KERNEL_VERSION", k.kernelRelease, good)
return nil
}
}
k.Reporter.Report("KERNEL_VERSION", k.kernelRelease, bad)
return fmt.Errorf("unsupported kernel release: %s", k.kernelRelease)
}
// validateKernelConfig validates the kernel configurations.
func (k *KernelValidator) validateKernelConfig(kSpec KernelSpec) error {
glog.Infof("Validating kernel config")
allConfig, err := k.getKernelConfig()
if err != nil {
return fmt.Errorf("failed to parse kernel config: %v", err)
}
return k.validateCachedKernelConfig(allConfig, kSpec)
}
// validateCachedKernelConfig validates the kernel confgiurations cached in internal data type.
func (k *KernelValidator) validateCachedKernelConfig(allConfig map[string]kConfigOption, kSpec KernelSpec) error {
badConfigs := []string{}
// reportAndRecord is a helper function to record bad config when
// report.
reportAndRecord := func(name, msg, desc string, result ValidationResultType) {
if result == bad {
badConfigs = append(badConfigs, name)
}
// report description when the config is bad or warn.
if result != good && desc != "" {
msg = msg + " - " + desc
}
k.Reporter.Report(name, msg, result)
}
const (
required = iota
optional
forbidden
)
validateOpt := func(config KernelConfig, expect int) {
var found, missing ValidationResultType
switch expect {
case required:
found, missing = good, bad
case optional:
found, missing = good, warn
case forbidden:
found, missing = bad, good
}
var name string
var opt kConfigOption
var ok bool
for _, name = range append([]string{config.Name}, config.Aliases...) {
name = kConfigPrefix + name
if opt, ok = allConfig[name]; ok {
break
}
}
if !ok {
reportAndRecord(name, "not set", config.Description, missing)
return
}
switch opt {
case builtIn:
reportAndRecord(name, "enabled", config.Description, found)
case asModule:
reportAndRecord(name, "enabled (as module)", config.Description, found)
case leftOut:
reportAndRecord(name, "disabled", config.Description, missing)
default:
reportAndRecord(name, fmt.Sprintf("unknown option: %s", opt), config.Description, missing)
}
}
for _, config := range kSpec.Required {
validateOpt(config, required)
}
for _, config := range kSpec.Optional {
validateOpt(config, optional)
}
for _, config := range kSpec.Forbidden {
validateOpt(config, forbidden)
}
if len(badConfigs) > 0 {
return fmt.Errorf("unexpected kernel config: %s", strings.Join(badConfigs, " "))
}
return nil
}
// getKernelConfigReader search kernel config file in a predefined list. Once the kernel config
// file is found it will read the configurations into a byte buffer and return. If the kernel
// config file is not found, it will try to load kernel config module and retry again.
func (k *KernelValidator) getKernelConfigReader() (io.Reader, error) {
possibePaths := []string{
"/proc/config.gz",
"/boot/config-" + k.kernelRelease,
"/usr/src/linux-" + k.kernelRelease + "/.config",
"/usr/src/linux/.config",
}
configsModule := "configs"
modprobeCmd := "modprobe"
// loadModule indicates whether we've tried to load kernel config module ourselves.
loadModule := false
for {
for _, path := range possibePaths {
_, err := os.Stat(path)
if err != nil {
continue
}
// Buffer the whole file, so that we can close the file and unload
// kernel config module in this function.
b, err := ioutil.ReadFile(path)
if err != nil {
return nil, err
}
var r io.Reader
r = bytes.NewReader(b)
// This is a gzip file (config.gz), unzip it.
if filepath.Ext(path) == ".gz" {
r, err = gzip.NewReader(r)
if err != nil {
return nil, err
}
}
return r, nil
}
// If we've tried to load kernel config module, break and return error.
if loadModule {
break
}
// If the kernel config file is not found, try to load the kernel
// config module and check again.
output, err := exec.Command(modprobeCmd, configsModule).CombinedOutput()
if err != nil {
return nil, fmt.Errorf("unable to load kernel module %q: output - %q, err - %v",
configsModule, output, err)
}
// Unload the kernel config module to make sure the validation have no side effect.
defer exec.Command(modprobeCmd, "-r", configsModule).Run()
loadModule = true
}
return nil, fmt.Errorf("no config path in %v is available", possibePaths)
}
// getKernelConfig gets kernel config from kernel config file and convert kernel config to internal type.
func (k *KernelValidator) getKernelConfig() (map[string]kConfigOption, error) {
r, err := k.getKernelConfigReader()
if err != nil {
return nil, err
}
return k.parseKernelConfig(r)
}
// parseKernelConfig converts kernel config to internal type.
func (k *KernelValidator) parseKernelConfig(r io.Reader) (map[string]kConfigOption, error) {
config := map[string]kConfigOption{}
regex := regexp.MustCompile(validKConfigRegex)
s := bufio.NewScanner(r)
for s.Scan() {
if err := s.Err(); err != nil {
return nil, err
}
line := strings.TrimSpace(s.Text())
if !regex.MatchString(line) {
continue
}
fields := strings.Split(line, "=")
if len(fields) != 2 {
glog.Errorf("Unexpected fields number in config %q", line)
continue
}
config[fields[0]] = kConfigOption(fields[1])
}
return config, nil
}

View File

@ -0,0 +1,23 @@
/*
Copyright 2017 The Kubernetes Authors.
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 system
// KernelValidatorHelper is an interface intended to help with os specific kernel validation
type KernelValidatorHelper interface {
// GetKernelReleaseVersion gets the current kernel release version of the system
GetKernelReleaseVersion() (string, error)
}

View File

@ -0,0 +1,197 @@
/*
Copyright 2016 The Kubernetes Authors.
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 system
import (
"bytes"
"testing"
"github.com/stretchr/testify/assert"
)
func TestValidateKernelVersion(t *testing.T) {
v := &KernelValidator{
Reporter: DefaultReporter,
}
// Currently, testRegex is align with DefaultSysSpec.KernelVersion, but in the future
// they may be different.
// This is fine, because the test mainly tests the kernel version validation logic,
// not the DefaultSysSpec. The DefaultSysSpec should be tested with node e2e.
testRegex := []string{`3\.[1-9][0-9].*`, `4\..*`}
for _, test := range []struct {
version string
err bool
}{
// first version regex matches
{
version: "3.19.9-99-test",
err: false,
},
// one of version regexes matches
{
version: "4.4.14+",
err: false,
},
// no version regex matches
{
version: "2.0.0",
err: true,
},
{
version: "5.0.0",
err: true,
},
{
version: "3.9.0",
err: true,
},
} {
v.kernelRelease = test.version
err := v.validateKernelVersion(KernelSpec{Versions: testRegex})
if !test.err {
assert.Nil(t, err, "Expect error not to occur with kernel version %q", test.version)
} else {
assert.NotNil(t, err, "Expect error to occur with kenrel version %q", test.version)
}
}
}
func TestValidateCachedKernelConfig(t *testing.T) {
v := &KernelValidator{
Reporter: DefaultReporter,
}
testKernelSpec := KernelSpec{
Required: []KernelConfig{{Name: "REQUIRED_1"}, {Name: "REQUIRED_2", Aliases: []string{"ALIASE_REQUIRED_2"}}},
Optional: []KernelConfig{{Name: "OPTIONAL_1"}, {Name: "OPTIONAL_2"}},
Forbidden: []KernelConfig{
{Name: "FORBIDDEN_1", Description: "TEST FORBIDDEN"},
{Name: "FORBIDDEN_2", Aliases: []string{"ALIASE_FORBIDDEN_2"}},
},
}
for c, test := range []struct {
desc string
config map[string]kConfigOption
err bool
}{
{
desc: "meet all required configurations should not report error.",
config: map[string]kConfigOption{
"REQUIRED_1": builtIn,
"REQUIRED_2": asModule,
},
err: false,
},
{
desc: "one required configuration disabled should report error.",
config: map[string]kConfigOption{
"REQUIRED_1": leftOut,
"REQUIRED_2": builtIn,
},
err: true,
},
{
desc: "one required configuration missing should report error.",
config: map[string]kConfigOption{
"REQUIRED_1": builtIn,
},
err: true,
},
{
desc: "alias of required configuration should not report error.",
config: map[string]kConfigOption{
"REQUIRED_1": builtIn,
"ALIASE_REQUIRED_2": asModule,
},
err: false,
},
{
desc: "optional configuration set or not should not report error.",
config: map[string]kConfigOption{
"REQUIRED_1": builtIn,
"REQUIRED_2": asModule,
"OPTIONAL_1": builtIn,
},
err: false,
},
{
desc: "forbidden configuration disabled should not report error.",
config: map[string]kConfigOption{
"REQUIRED_1": builtIn,
"REQUIRED_2": asModule,
"FORBIDDEN_1": leftOut,
},
err: false,
},
{
desc: "forbidden configuration built-in should report error.",
config: map[string]kConfigOption{
"REQUIRED_1": builtIn,
"REQUIRED_2": asModule,
"FORBIDDEN_1": builtIn,
},
err: true,
},
{
desc: "forbidden configuration built as module should report error.",
config: map[string]kConfigOption{
"REQUIRED_1": builtIn,
"REQUIRED_2": asModule,
"FORBIDDEN_1": asModule,
},
err: true,
},
{
desc: "alias of forbidden configuration should report error.",
config: map[string]kConfigOption{
"REQUIRED_1": builtIn,
"REQUIRED_2": asModule,
"ALIASE_FORBIDDEN_2": asModule,
},
err: true,
},
} {
t.Logf("TestCase #%d %s", c, test.desc)
// Add kernel config prefix.
for k, v := range test.config {
delete(test.config, k)
test.config[kConfigPrefix+k] = v
}
err := v.validateCachedKernelConfig(test.config, testKernelSpec)
if !test.err {
assert.Nil(t, err, "Expect error not to occur with kernel config %q", test.config)
} else {
assert.NotNil(t, err, "Expect error to occur with kenrel config %q", test.config)
}
}
}
func TestValidateParseKernelConfig(t *testing.T) {
config := `CONFIG_1=y
CONFIG_2=m
CONFIG_3=n`
expected := map[string]kConfigOption{
"CONFIG_1": builtIn,
"CONFIG_2": asModule,
"CONFIG_3": leftOut,
}
v := &KernelValidator{
Reporter: DefaultReporter,
}
got, err := v.parseKernelConfig(bytes.NewReader([]byte(config)))
assert.Nil(t, err, "Expect error not to occur when parse kernel configuration %q", config)
assert.Equal(t, expected, got)
}

View File

@ -0,0 +1,50 @@
/*
Copyright 2016 The Kubernetes Authors.
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 system
import (
"fmt"
"os/exec"
"strings"
)
var _ Validator = &OSValidator{}
type OSValidator struct {
Reporter Reporter
}
func (o *OSValidator) Name() string {
return "os"
}
func (o *OSValidator) Validate(spec SysSpec) (error, error) {
os, err := exec.Command("uname").CombinedOutput()
if err != nil {
return nil, fmt.Errorf("failed to get os name: %v", err)
}
return nil, o.validateOS(strings.TrimSpace(string(os)), spec.OS)
}
func (o *OSValidator) validateOS(os, specOS string) error {
if os != specOS {
o.Reporter.Report("OS", os, bad)
return fmt.Errorf("unsupported operating system: %s", os)
}
o.Reporter.Report("OS", os, good)
return nil
}

View File

@ -0,0 +1,54 @@
/*
Copyright 2016 The Kubernetes Authors.
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 system
import (
"testing"
"github.com/stretchr/testify/assert"
)
func TestValidateOS(t *testing.T) {
v := &OSValidator{
Reporter: DefaultReporter,
}
specOS := "Linux"
for _, test := range []struct {
os string
err bool
}{
{
os: "Linux",
err: false,
},
{
os: "Windows",
err: true,
},
{
os: "Darwin",
err: true,
},
} {
err := v.validateOS(test.os, specOS)
if !test.err {
assert.Nil(t, err, "Expect error not to occur with os %q", test.os)
} else {
assert.NotNil(t, err, "Expect error to occur with os %q", test.os)
}
}
}

View File

@ -0,0 +1,325 @@
/*
Copyright 2017 The Kubernetes Authors.
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 system
import (
"fmt"
"io/ioutil"
"os/exec"
"strings"
"k8s.io/apimachinery/pkg/util/errors"
"github.com/blang/semver"
"github.com/golang/glog"
)
// semVerDotsCount is the number of dots in a valid semantic version.
const semVerDotsCount int = 2
// packageManager is an interface that abstracts the basic operations of a
// package manager.
type packageManager interface {
// getPackageVersion returns the version of the package given the
// packageName, or an error if no such package exists.
getPackageVersion(packageName string) (string, error)
}
// newPackageManager returns the package manager on the running machine, and an
// error if no package managers is available.
func newPackageManager() (packageManager, error) {
if m, ok := newDPKG(); ok {
return m, nil
}
return nil, fmt.Errorf("failed to find package manager")
}
// dpkg implements packageManager. It uses "dpkg-query" to retrieve package
// information.
type dpkg struct{}
// newDPKG returns a Debian package manager. It returns (nil, false) if no such
// package manager exists on the running machine.
func newDPKG() (packageManager, bool) {
_, err := exec.LookPath("dpkg-query")
if err != nil {
return nil, false
}
return dpkg{}, true
}
// getPackageVersion returns the upstream package version for the package given
// the packageName, and an error if no such package exists.
func (_ dpkg) getPackageVersion(packageName string) (string, error) {
output, err := exec.Command("dpkg-query", "--show", "--showformat='${Version}'", packageName).Output()
if err != nil {
return "", fmt.Errorf("dpkg-query failed: %s", err)
}
version := extractUpstreamVersion(string(output))
if version == "" {
return "", fmt.Errorf("no version information")
}
return version, nil
}
// packageValidator implements the Validator interface. It validates packages
// and their versions.
type packageValidator struct {
reporter Reporter
kernelRelease string
osDistro string
}
// Name returns the name of the package validator.
func (self *packageValidator) Name() string {
return "package"
}
// Validate checks packages and their versions against the spec using the
// package manager on the running machine, and returns an error on any
// package/version mismatch.
func (self *packageValidator) Validate(spec SysSpec) (error, error) {
if len(spec.PackageSpecs) == 0 {
return nil, nil
}
var err error
if self.kernelRelease, err = getKernelRelease(); err != nil {
return nil, err
}
if self.osDistro, err = getOSDistro(); err != nil {
return nil, err
}
manager, err := newPackageManager()
if err != nil {
return nil, err
}
specs := applyPackageSpecOverride(spec.PackageSpecs, spec.PackageSpecOverrides, self.osDistro)
return self.validate(specs, manager)
}
// Validate checks packages and their versions against the packageSpecs using
// the packageManager, and returns an error on any package/version mismatch.
func (self *packageValidator) validate(packageSpecs []PackageSpec, manager packageManager) (error, error) {
var errs []error
for _, spec := range packageSpecs {
// Substitute variables in package name.
packageName := resolvePackageName(spec.Name, self.kernelRelease)
nameWithVerRange := fmt.Sprintf("%s (%s)", packageName, spec.VersionRange)
// Get the version of the package on the running machine.
version, err := manager.getPackageVersion(packageName)
if err != nil {
glog.V(1).Infof("Failed to get the version for the package %q: %s\n", packageName, err)
errs = append(errs, err)
self.reporter.Report(nameWithVerRange, "not installed", bad)
continue
}
// Version requirement will not be enforced if version range is
// not specified in the spec.
if spec.VersionRange == "" {
self.reporter.Report(packageName, version, good)
continue
}
// Convert both the version range in the spec and the version returned
// from package manager to semantic version format, and then check if
// the version is in the range.
sv, err := semver.Make(toSemVer(version))
if err != nil {
glog.Errorf("Failed to convert %q to semantic version: %s\n", version, err)
errs = append(errs, err)
self.reporter.Report(nameWithVerRange, "internal error", bad)
continue
}
versionRange := semver.MustParseRange(toSemVerRange(spec.VersionRange))
if versionRange(sv) {
self.reporter.Report(nameWithVerRange, version, good)
} else {
errs = append(errs, fmt.Errorf("package \"%s %s\" does not meet the spec \"%s (%s)\"", packageName, sv, packageName, spec.VersionRange))
self.reporter.Report(nameWithVerRange, version, bad)
}
}
return nil, errors.NewAggregate(errs)
}
// getKernelRelease returns the kernel release of the local machine.
func getKernelRelease() (string, error) {
output, err := exec.Command("uname", "-r").Output()
if err != nil {
return "", fmt.Errorf("failed to get kernel release: %s", err)
}
return strings.TrimSpace(string(output)), nil
}
// getOSDistro returns the OS distro of the local machine.
func getOSDistro() (string, error) {
f := "/etc/lsb-release"
b, err := ioutil.ReadFile(f)
if err != nil {
return "", fmt.Errorf("failed to read %q: %s", f, err)
}
content := string(b)
switch {
case strings.Contains(content, "Ubuntu"):
return "ubuntu", nil
case strings.Contains(content, "Chrome OS"):
return "cos", nil
case strings.Contains(content, "CoreOS"):
return "coreos", nil
default:
return "", fmt.Errorf("failed to get OS distro: %s", content)
}
}
// resolvePackageName substitutes the variables in the packageName with the
// local information.
// E.g., "linux-headers-${KERNEL_RELEASE}" -> "linux-headers-4.4.0-75-generic".
func resolvePackageName(packageName string, kernelRelease string) string {
packageName = strings.Replace(packageName, "${KERNEL_RELEASE}", kernelRelease, -1)
return packageName
}
// applyPackageSpecOverride applies the package spec overrides for the given
// osDistro to the packageSpecs and returns the applied result.
func applyPackageSpecOverride(packageSpecs []PackageSpec, overrides []PackageSpecOverride, osDistro string) []PackageSpec {
var override *PackageSpecOverride
for _, o := range overrides {
if o.OSDistro == osDistro {
override = &o
break
}
}
if override == nil {
return packageSpecs
}
// Remove packages in the spec that matches the overrides in
// Subtractions.
var out []PackageSpec
subtractions := make(map[string]bool)
for _, spec := range override.Subtractions {
subtractions[spec.Name] = true
}
for _, spec := range packageSpecs {
if _, ok := subtractions[spec.Name]; !ok {
out = append(out, spec)
}
}
// Add packages in the spec that matches the overrides in Additions.
return append(out, override.Additions...)
}
// extractUpstreamVersion returns the upstream version of the given full
// version in dpkg format. E.g., "1:1.0.6-2ubuntu2.1" -> "1.0.6".
func extractUpstreamVersion(version string) string {
// The full version is in the format of
// "[epoch:]upstream_version[-debian_revision]". See
// https://www.debian.org/doc/debian-policy/ch-controlfields.html#s-f-Version.
version = strings.Trim(version, " '")
if i := strings.Index(version, ":"); i != -1 {
version = version[i+1:]
}
if i := strings.Index(version, "-"); i != -1 {
version = version[:i]
}
return version
}
// toSemVerRange converts the input to a semantic version range.
// E.g., ">=1.0" -> ">=1.0.x"
// ">=1" -> ">=1.x"
// ">=1 <=2.3" -> ">=1.x <=2.3.x"
// ">1 || >3.1.0 !4.2" -> ">1.x || >3.1.0 !4.2.x"
func toSemVerRange(input string) string {
var output []string
fields := strings.Fields(input)
for _, f := range fields {
numDots, hasDigits := 0, false
for _, c := range f {
switch {
case c == '.':
numDots++
case c >= '0' && c <= '9':
hasDigits = true
}
}
if hasDigits && numDots < semVerDotsCount {
f = strings.TrimRight(f, " ")
f += ".x"
}
output = append(output, f)
}
return strings.Join(output, " ")
}
// toSemVer converts the input to a semantic version, and an empty string on
// error.
func toSemVer(version string) string {
// Remove the first non-digit and non-dot character as well as the ones
// following it.
// E.g., "1.8.19p1" -> "1.8.19".
if i := strings.IndexFunc(version, func(c rune) bool {
if (c < '0' || c > '9') && c != '.' {
return true
}
return false
}); i != -1 {
version = version[:i]
}
// Remove the trailing dots if there's any, and then returns an empty
// string if nothing left.
version = strings.TrimRight(version, ".")
if version == "" {
return ""
}
numDots := strings.Count(version, ".")
switch {
case numDots < semVerDotsCount:
// Add minor version and patch version.
// E.g. "1.18" -> "1.18.0" and "481" -> "481.0.0".
version += strings.Repeat(".0", semVerDotsCount-numDots)
case numDots > semVerDotsCount:
// Remove anything beyond the patch version
// E.g. "2.0.10.4" -> "2.0.10".
for numDots != semVerDotsCount {
if i := strings.LastIndex(version, "."); i != -1 {
version = version[:i]
numDots--
}
}
}
// Remove leading zeros in major/minor/patch version.
// E.g., "2.02" -> "2.2"
// "8.0.0095" -> "8.0.95"
var subs []string
for _, s := range strings.Split(version, ".") {
s := strings.TrimLeft(s, "0")
if s == "" {
s = "0"
}
subs = append(subs, s)
}
return strings.Join(subs, ".")
}

View File

@ -0,0 +1,266 @@
/*
Copyright 2017 The Kubernetes Authors.
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 system
import (
"errors"
"fmt"
"reflect"
"testing"
)
func TestExtractUpstreamVersion(t *testing.T) {
for _, test := range []struct {
input string
expected string
}{
{
input: "",
expected: "",
},
{
input: "1.0.6",
expected: "1.0.6",
},
{
input: "1:1.0.6",
expected: "1.0.6",
},
{
input: "1.0.6-2ubuntu2.1",
expected: "1.0.6",
},
{
input: "1:1.0.6-2ubuntu2.1",
expected: "1.0.6",
},
} {
got := extractUpstreamVersion(test.input)
if test.expected != got {
t.Errorf("extractUpstreamVersion(%q) = %q, want %q", test.input, got, test.expected)
}
}
}
func TestToSemVer(t *testing.T) {
for _, test := range []struct {
input string
expected string
}{
{
input: "",
expected: "",
},
{
input: "1.2.3",
expected: "1.2.3",
},
{
input: "1.8.19p1",
expected: "1.8.19",
},
{
input: "1.8.19.p1",
expected: "1.8.19",
},
{
input: "p1",
expected: "",
},
{
input: "1.18",
expected: "1.18.0",
},
{
input: "481",
expected: "481.0.0",
},
{
input: "2.0.10.4",
expected: "2.0.10",
},
{
input: "03",
expected: "3.0.0",
},
{
input: "2.02",
expected: "2.2.0",
},
{
input: "8.0.0095",
expected: "8.0.95",
},
} {
got := toSemVer(test.input)
if test.expected != got {
t.Errorf("toSemVer(%q) = %q, want %q", test.input, got, test.expected)
}
}
}
func TestToSemVerRange(t *testing.T) {
for _, test := range []struct {
input string
expected string
}{
{
input: "",
expected: "",
},
{
input: ">=1.0.0",
expected: ">=1.0.0",
},
{
input: ">=1.0",
expected: ">=1.0.x",
},
{
input: ">=1",
expected: ">=1.x",
},
{
input: ">=1 || !2.3",
expected: ">=1.x || !2.3.x",
},
{
input: ">1 || >3.1.0 !4.2",
expected: ">1.x || >3.1.0 !4.2.x",
},
} {
got := toSemVerRange(test.input)
if test.expected != got {
t.Errorf("toSemVerRange(%q) = %q, want %q", test.input, got, test.expected)
}
}
}
// testPackageManager implements the packageManager interface.
type testPackageManager struct {
packageVersions map[string]string
}
func (m testPackageManager) getPackageVersion(packageName string) (string, error) {
if v, ok := m.packageVersions[packageName]; ok {
return v, nil
}
return "", fmt.Errorf("package %q does not exist", packageName)
}
func TestValidatePackageVersion(t *testing.T) {
testKernelRelease := "test-kernel-release"
manager := testPackageManager{
packageVersions: map[string]string{
"foo": "1.0.0",
"bar": "2.1.0",
"bar-" + testKernelRelease: "3.0.0",
},
}
v := &packageValidator{
reporter: DefaultReporter,
kernelRelease: testKernelRelease,
}
for _, test := range []struct {
desc string
specs []PackageSpec
err error
}{
{
desc: "all packages meet the spec",
specs: []PackageSpec{
{Name: "foo", VersionRange: ">=1.0"},
{Name: "bar", VersionRange: ">=2.0 <= 3.0"},
},
},
{
desc: "package version does not meet the spec",
specs: []PackageSpec{
{Name: "foo", VersionRange: ">=1.0"},
{Name: "bar", VersionRange: ">=3.0"},
},
err: errors.New("package \"bar 2.1.0\" does not meet the spec \"bar (>=3.0)\""),
},
{
desc: "package not installed",
specs: []PackageSpec{
{Name: "baz"},
},
err: errors.New("package \"baz\" does not exist"),
},
{
desc: "use variable in package name",
specs: []PackageSpec{
{Name: "bar-${KERNEL_RELEASE}", VersionRange: ">=3.0"},
},
},
} {
_, err := v.validate(test.specs, manager)
if test.err == nil && err != nil {
t.Errorf("%s: v.validate(): err = %s", test.desc, err)
}
if test.err != nil {
if err == nil {
t.Errorf("%s: v.validate() is expected to fail.", test.desc)
} else if test.err.Error() != err.Error() {
t.Errorf("%s: v.validate(): err = %q, want = %q", test.desc, err, test.err)
}
}
}
}
func TestApplyPackageOverride(t *testing.T) {
for _, test := range []struct {
overrides []PackageSpecOverride
osDistro string
specs []PackageSpec
expected []PackageSpec
}{
{
specs: []PackageSpec{{Name: "foo", VersionRange: ">=1.0"}},
expected: []PackageSpec{{Name: "foo", VersionRange: ">=1.0"}},
},
{
osDistro: "ubuntu",
overrides: []PackageSpecOverride{
{
OSDistro: "ubuntu",
Subtractions: []PackageSpec{{Name: "foo"}},
Additions: []PackageSpec{{Name: "bar", VersionRange: ">=2.0"}},
},
},
specs: []PackageSpec{{Name: "foo", VersionRange: ">=1.0"}},
expected: []PackageSpec{{Name: "bar", VersionRange: ">=2.0"}},
},
{
osDistro: "ubuntu",
overrides: []PackageSpecOverride{
{
OSDistro: "debian",
Subtractions: []PackageSpec{{Name: "foo"}},
},
},
specs: []PackageSpec{{Name: "foo", VersionRange: ">=1.0"}},
expected: []PackageSpec{{Name: "foo", VersionRange: ">=1.0"}},
},
} {
got := applyPackageSpecOverride(test.specs, test.overrides, test.osDistro)
if !reflect.DeepEqual(test.expected, got) {
t.Errorf("applyPackageSpecOverride(%+v, %+v, %s) = %+v, want = %+v", test.specs, test.overrides, test.osDistro, got, test.expected)
}
}
}

View File

@ -0,0 +1,78 @@
/*
Copyright 2016 The Kubernetes Authors.
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 system
import (
"fmt"
"io"
"os"
)
// ValidationResultType is type of the validation result. Different validation results
// corresponds to different colors.
type ValidationResultType int32
const (
good ValidationResultType = iota
bad
warn
)
// color is the color of the message.
type color int32
const (
red color = 31
green = 32
yellow = 33
white = 37
)
func colorize(s string, c color) string {
return fmt.Sprintf("\033[0;%dm%s\033[0m", c, s)
}
// The default reporter for the system verification test
type StreamReporter struct {
// The stream that this reporter is writing to
WriteStream io.Writer
}
func (dr *StreamReporter) Report(key, value string, resultType ValidationResultType) error {
var c color
switch resultType {
case good:
c = green
case bad:
c = red
case warn:
c = yellow
default:
c = white
}
if dr.WriteStream == nil {
return fmt.Errorf("WriteStream has to be defined for this reporter")
}
fmt.Fprintf(dr.WriteStream, "%s: %s\n", colorize(key, white), colorize(value, c))
return nil
}
// DefaultReporter is the default Reporter
var DefaultReporter = &StreamReporter{
WriteStream: os.Stdout,
}

View File

@ -0,0 +1,272 @@
# This is the system spec that must be satisfied by the images running on GKE.
os: Linux
kernelSpec:
versions:
# GKE requires kernel version 4.4+.
- '4\.[4-9].*'
- '4\.[1-9][0-9].*'
- '[5-9].*'
# Required kernel configurations -- the configuration must be set to "y" or
# "m".
required:
# The configurations required by virtual machine or cloud provider.
- name: BOOTPARAM_HARDLOCKUP_PANIC
description: 'Enable the kernel to panic on "hard lockups".'
- name: BOOTPARAM_SOFTLOCKUP_PANIC
description: 'Enable the kernel to panic on "soft lockups".'
- name: PANIC_ON_OOPS
description: 'Enable the kernel to panic when it oops.'
- name: PVPANIC
description: 'Enable the VM (guest) to communicate panic events with the
host.'
- name: DMIID
description: 'Make sure /sys/class/dmi is exported - cAdvisor currently
uses this to determine which the cloud provider it is: aws, azure, or
gce, etc'
- name: ACPI_BUTTON
description: 'Enable the software-controlled power management, and required
by reset or stop button of GCE console.'
# The configurations required by network.
- name: INET
description: 'Enable TCP/IP networking.'
- name: VXLAN
description: 'Required by the overlay networking in Kubernetes.'
- name: IP_SET
description: 'Required by Kubernetes network policy.'
- name: IP_SET_HASH_IP
description: 'This introduces hash:ip set type support, which is required
by Kubernetes Calico networking.'
- name: IPVLAN
description: 'Required by IPVLAN feature.'
- name: IPV6
description: 'Required by IPVLAN feature.'
- name: IP6_NF_IPTABLES
description: 'Required by kube-proxy.'
- name: IP_NF_TARGET_REDIRECT
alias:
- NETFILTER_XT_TARGET_REDIRECT
description: 'Enabled REDIRECT: all incoming connections are mapped onto
the incoming interface''s address, causing the packets to come to the
local machine instead of passing through. This is required by
kube-proxy.'
- name: NETFILTER_XT_MATCH_COMMENT
description: 'This option adds a "comment" dummy-match, which allows you to
put comments in your iptables ruleset. Today''s kube-proxy implementation
depends on this feature.'
# This is not critical, but debian-based container-vm kernel module study
# shows that many customers' nodes have loaded those kernel modules. We
# suspect sysdig module depends on these set of kernel modules for
# monitoring.
- name: PACKET_DIAG
description: 'Required by ss (similar to netstat) tools to display Linux
TCP / UDP network and socket information.'
- name: UNIX_DIAG
description: 'Required by ss (similar to netstat) tools to display Linux
TCP / UDP network and socket information.'
- name: INET_DIAG
description: 'Required by ss (similar to netstat) tools to display Linux
TCP / UDP network and socket information.'
- name: INET_TCP_DIAG
description: 'Required by ss (similar to netstat) tools to display Linux
TCP / UDP network and socket information.'
- name: INET_UDP_DIAG
description: 'Required by ss (similar to netstat) tools to display Linux
TCP / UDP network and socket information.'
- name: NETLINK_DIAG
description: 'Required by ss (similar to netstat) tools to display Linux
TCP / UDP network and socket information.'
# The configurations are required by filesystem.
- name: EXT4_FS
- name: DEBUG_FS
- name: PROC_FS
- name: XFS_FS
- name: SCSI_PROC_FS
# Currently Kubelet supports three docker graph drivers: overlay, aufs, and
# devicemapper due to the legacy reason. But for GKE, we plan to only support
# overlayfs.
- name: OVERLAY_FS
description: 'Enable OverlayFS, which will be the only docker graph driver
supported on GKE.'
- name: NFS_FS
description: 'Required by NFS support.'
- name: AUTOFS4_FS
description: 'Required by NFS support.'
- name: NFS_FSCACHE
description: 'Required by NFS support.'
- name: FSCACHE
description: 'Required by NFS support.'
- name: CACHEFILES
description: 'Required by NFS support.'
- name: FUSE_FS
description: 'Required by GlusterFS support.'
- name: BCACHE
# TODO(yguo0905): Add a description for BCACHE.
# The configuration required by the resource isolation, accounting, and
# management.
- name: NAMESPACES
description: 'Required by kubelet and docker. Enabling it allows the
processes within a pod or a container to have their own view of the
system.'
- name: IPC_NS
description: 'Required by kubelet and docker. Enabling it allows the
processes within a pod or a container to have their own view of the
system.'
- name: NET_NS
description: 'Required by kubelet and docker. Enabling it allows the
processes within a pod or a container to have their own view of the
system.'
- name: PID_NS
description: 'Required by kubelet and docker. Enabling it allows the
processes within a pod or a container to have their own view of the
system.'
- name: UTS_NS
description: 'Required by kubelet and docker. Enabling it allows the
processes within a pod or a container to have their own view of the
system.'
- name: CGROUPS
description: 'Required by kubelet and docker. The resource usage of the
processes within a pod or a container can be monitored, accounted, and
controlled.'
- name: CGROUP_CPUACCT
description: 'Required by kubelet and docker. The resource usage of the
processes within a pod or a container can be monitored, accounted, and
controlled.'
- name: CGROUP_DEVICE
description: 'Required by kubelet and docker. The resource usage of the
processes within a pod or a container can be monitored, accounted, and
controlled.'
- name: CGROUP_SCHED
description: 'Required by kubelet and docker. The resource usage of the
processes within a pod or a container can be monitored, accounted, and
controlled.'
- name: CPUSETS
description: 'Required by kubelet and docker. The resource usage of the
processes within a pod or a container can be monitored, accounted, and
controlled.'
- name: MEMCG
description: 'Required by kubelet and docker. The resource usage of the
processes within a pod or a container can be monitored, accounted, and
controlled.'
- name: QUOTA
description: 'Required by kubelet to have an accurate and efficient disk
space and inode accounting, and eventually to limit the usage.'
# The security-related configurations
- name: SECCOMP
description: 'Enabled the SECCOMP application API.'
- name: SECURITY_APPARMOR
description: 'Enable for AppArmor support.'
- name: CC_STACKPROTECTOR_STRONG
alias:
- CONFIG_CC_STACKPROTECTOR_REGULAR
CONFIG_CC_STACKPROTECTOR_ALL
description: 'Add the stack buffer overflow protections.'
- name: STRICT_DEVMEM
description: 'Required for blocking the direct physical memory access.'
- name: IMA
description: 'Required for security-related logging and auditing.'
- name: AUDIT
description: 'Required for security-related logging and auditing.'
- name: AUDITSYSCALL
description: 'Required for security-related logging and auditing.'
# Misc. configurations
- name: MODULES
description: 'Required for loadable module support.'
- name: PRINTK
description: 'Required for kernel logging message.'
- name: MMU
description: 'Required for memory management hardware and mmap() system
call.'
packageSpecs:
- name: apparmor
versionRange: '>=2.10.1'
- name: apparmor-profiles
versionRange: '>=2.10.1'
- name: audit
versionRange: '>=2.5.0'
- name: autofs
versionRange: '>=5.0.7'
- name: bash
versionRange: '>=4.3'
- name: bridge-utils
versionRange: '>=1.5'
- name: cloud-init
versionRange: '>=0.7.6'
- name: coreutils
versionRange: '>=8.24'
- name: dbus
versionRange: '>=1.6.8'
- name: e2fsprogs
versionRange: '>=1.4.3'
- name: ebtables
versionRange: '>=2.0.10'
- name: ethtool
versionRange: '>=3.18'
- name: iproute2
versionRange: '>=4.2.0'
- name: less
versionRange: '>=481'
- name: linux-headers-${KERNEL_RELEASE}
- name: netcat-openbsd
versionRange: '>=1.10'
- name: python
versionRange: '>=2.7.10'
- name: pv
versionRange: '>=1.3.4'
- name: sudo
versionRange: '>=1.8.12'
- name: systemd
versionRange: '>=225'
- name: tar
versionRange: '>=1.28'
- name: util-linux
versionRange: '>=2.27.1'
- name: vim
versionRange: '>=7.4.712'
- name: wget
versionRange: '>=1.18'
- name: gce-compute-image-packages
versionRange: '>=20170227'
# TODO(yguo0905): Figure out whether watchdog is required.
# packageSpecOverrides contains the OS distro specific package requirements.
packageSpecOverrides:
# The following overrides apply to all Ubuntu images.
- osDistro: ubuntu
subtractions:
- name: apparmor-profiles
description: 'On Ubuntu the apparmor profiles are shipped with individual
application package, so the "apparmor-profiles" package is not required.'
- name: audit
description: 'On Ubuntu the equivalent package is called "auditd", so the
"audit" package is not required and "auditd" exists in the additions.'
- name: wget
description: 'The Ubuntu 1604-xenial image includes wget 1.17.1, which does
not satisfy the spec (>=1.18), but meets the functionality requirements.
Therefore, it is removed from the base spec. See wget in the additions.'
additions:
- name: auditd
versionRange: '>=2.4.5'
description: 'auditd 2.4.5 currently satisfies the requirements because the
GKE features that require auditd 2.5 are not yet available.'
- name: grub-common
versionRange: '>=2.2'
description: 'grub is the bootloader on Ubuntu.'
- name: wget
versionRange: '>=1.17.1'
description: 'wget 1.17.1 satisfies the functionality requirements but does
not meet the spec, which is fine'

124
vendor/k8s.io/kubernetes/test/e2e_node/system/types.go generated vendored Normal file
View File

@ -0,0 +1,124 @@
/*
Copyright 2016 The Kubernetes Authors.
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 system
// KernelConfig defines one kernel configration item.
type KernelConfig struct {
// Name is the general name of the kernel configuration. It is used to
// match kernel configuration.
Name string `json:"name,omitempty"`
// TODO(yguo0905): Support the "or" operation, which will be the same
// as the "aliases".
//
// Aliases are aliases of the kernel configuration. Some configuration
// has different names in different kernel version. Names of different
// versions will be treated as aliases.
Aliases []string `json:"aliases,omitempty"`
// Description is the description of the kernel configuration, for example:
// * What is it used for?
// * Why is it needed?
// * Who needs it?
Description string `json:"description,omitempty"`
}
// KernelSpec defines the specification for the kernel. Currently, it contains
// specification for:
// * Kernel Version
// * Kernel Configuration
type KernelSpec struct {
// Versions define supported kernel version. It is a group of regexps.
Versions []string `json:"versions,omitempty"`
// Required contains all kernel configurations required to be enabled
// (built in or as module).
Required []KernelConfig `json:"required,omitempty"`
// Optional contains all kernel configurations are required for optional
// features.
Optional []KernelConfig `json:"optional,omitempty"`
// Forbidden contains all kernel configurations which areforbidden (disabled
// or not set)
Forbidden []KernelConfig `json:"forbidden,omitempty"`
}
// DockerSpec defines the requirement configuration for docker. Currently, it only
// contains spec for graph driver.
type DockerSpec struct {
// Version is a group of regex matching supported docker versions.
Version []string `json:"version,omitempty"`
// GraphDriver is the graph drivers supported by kubelet.
GraphDriver []string `json:"graphDriver,omitempty"`
}
// RuntimeSpec is the abstract layer for different runtimes. Different runtimes
// should put their spec inside the RuntimeSpec.
type RuntimeSpec struct {
*DockerSpec `json:",inline"`
}
// PackageSpec defines the required packages and their versions.
// PackageSpec is only supported on OS distro with Debian package manager.
//
// TODO(yguo0905): Support operator OR of multiple packages for the case where
// either "foo (>=1.0)" or "bar (>=2.0)" is required.
type PackageSpec struct {
// Name is the name of the package to be checked.
Name string `json:"name,omitempty"`
// VersionRange represents a range of versions that the package must
// satisfy. Note that the version requirement will not be enforced if
// the version range is empty. For example,
// - "" would match any versions but the package must be installed.
// - ">=1" would match "1.0.0", "1.0.1", "1.1.0", and "2.0".
// - ">1.0 <2.0" would match between both ranges, so "1.1.1" and "1.8.7"
// but not "1.0.0" or "2.0.0".
// - "<2.0.0 || >=3.0.0" would match "1.0.0" and "3.0.0" but not "2.0.0".
VersionRange string `json:"versionRange,omitempty"`
// Description explains the reason behind this package requirements.
//
// TODO(yguo0905): Print the description where necessary.
Description string `json:"description,omitempty"`
}
// PackageSpecOverride defines the overrides on the PackageSpec for an OS
// distro.
type PackageSpecOverride struct {
// OSDistro identifies to which OS distro this override applies.
// Must be "ubuntu", "cos" or "coreos".
OSDistro string `json:"osDistro,omitempty"`
// Subtractions is a list of package names that are excluded from the
// package spec.
Subtractions []PackageSpec `json:"subtractions,omitempty"`
// Additions is a list of additional package requirements included the
// package spec.
Additions []PackageSpec `json:"additions,omitempty"`
}
// SysSpec defines the requirement of supported system. Currently, it only contains
// spec for OS, Kernel and Cgroups.
type SysSpec struct {
// OS is the operating system of the SysSpec.
OS string `json:"os,omitempty"`
// KernelConfig defines the spec for kernel.
KernelSpec KernelSpec `json:"kernelSpec,omitempty"`
// Cgroups is the required cgroups.
Cgroups []string `json:"cgroups,omitempty"`
// RuntimeSpec defines the spec for runtime.
RuntimeSpec RuntimeSpec `json:"runtimeSpec,omitempty"`
// PackageSpec defines the required packages and their versions.
PackageSpecs []PackageSpec `json:"packageSpecs,omitempty"`
// PackageSpec defines the overrides of the required packages and their
// versions for an OS distro.
PackageSpecOverrides []PackageSpecOverride `json:"packageSpecOverrides,omitempty"`
}

View File

@ -0,0 +1,83 @@
// +build !windows
/*
Copyright 2017 The Kubernetes Authors.
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 system
import (
"os/exec"
"strings"
)
// dockerEndpoint is the os specific endpoint for docker communication
const dockerEndpoint = "unix:///var/run/docker.sock"
// DefaultSysSpec is the default SysSpec for Linux
var DefaultSysSpec = SysSpec{
OS: "Linux",
KernelSpec: KernelSpec{
Versions: []string{`3\.[1-9][0-9].*`, `4\..*`}, // Requires 3.10+ or 4+
// TODO(random-liu): Add more config
// TODO(random-liu): Add description for each kernel configuration:
Required: []KernelConfig{
{Name: "NAMESPACES"},
{Name: "NET_NS"},
{Name: "PID_NS"},
{Name: "IPC_NS"},
{Name: "UTS_NS"},
{Name: "CGROUPS"},
{Name: "CGROUP_CPUACCT"},
{Name: "CGROUP_DEVICE"},
{Name: "CGROUP_FREEZER"},
{Name: "CGROUP_SCHED"},
{Name: "CPUSETS"},
{Name: "MEMCG"},
{Name: "INET"},
{Name: "EXT4_FS"},
{Name: "PROC_FS"},
{Name: "NETFILTER_XT_TARGET_REDIRECT", Aliases: []string{"IP_NF_TARGET_REDIRECT"}},
{Name: "NETFILTER_XT_MATCH_COMMENT"},
},
Optional: []KernelConfig{
{Name: "OVERLAY_FS", Aliases: []string{"OVERLAYFS_FS"}, Description: "Required for overlayfs."},
{Name: "AUFS_FS", Description: "Required for aufs."},
{Name: "BLK_DEV_DM", Description: "Required for devicemapper."},
},
Forbidden: []KernelConfig{},
},
Cgroups: []string{"cpu", "cpuacct", "cpuset", "devices", "freezer", "memory"},
RuntimeSpec: RuntimeSpec{
DockerSpec: &DockerSpec{
Version: []string{`1\.1[1-3]\..*`, `17\.03\..*`}, // Requires [1.11, 17.03]
GraphDriver: []string{"aufs", "overlay", "overlay2", "devicemapper"},
},
},
}
// KernelValidatorHelperImpl is the 'linux' implementation of KernelValidatorHelper
type KernelValidatorHelperImpl struct{}
var _ KernelValidatorHelper = &KernelValidatorHelperImpl{}
// GetKernelReleaseVersion returns the kernel release version (ex. 4.4.0-96-generic) as a string
func (o *KernelValidatorHelperImpl) GetKernelReleaseVersion() (string, error) {
releaseVersion, err := exec.Command("uname", "-r").CombinedOutput()
if err != nil {
return "", err
}
return strings.TrimSpace(string(releaseVersion)), nil
}

View File

@ -0,0 +1,60 @@
// +build windows
/*
Copyright 2017 The Kubernetes Authors.
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 system
import (
"os/exec"
"strings"
)
// dockerEndpoint is the os specific endpoint for docker communication
const dockerEndpoint = "npipe:////./pipe/docker_engine"
// DefaultSysSpec is the default SysSpec for Windows
var DefaultSysSpec = SysSpec{
OS: "Microsoft Windows Server 2016",
KernelSpec: KernelSpec{
Versions: []string{`10\.0\.1439[3-9]`, `10\.0\.14[4-9][0-9]{2}`, `10\.0\.1[5-9][0-9]{3}`, `10\.0\.[2-9][0-9]{4}`, `10\.[1-9]+\.[0-9]+`}, //requires >= '10.0.14393'
Required: []KernelConfig{},
Optional: []KernelConfig{},
Forbidden: []KernelConfig{},
},
Cgroups: []string{},
RuntimeSpec: RuntimeSpec{
DockerSpec: &DockerSpec{
Version: []string{`17\.03\..*`}, //Requires [17.03] or later
GraphDriver: []string{"windowsfilter"},
},
},
}
// KernelValidatorHelperImpl is the 'windows' implementation of KernelValidatorHelper
type KernelValidatorHelperImpl struct{}
var _ KernelValidatorHelper = &KernelValidatorHelperImpl{}
// GetKernelRelease returns the windows release version (ex. 10.0.14393) as a string
func (o *KernelValidatorHelperImpl) GetKernelReleaseVersion() (string, error) {
args := []string{"(Get-CimInstance Win32_OperatingSystem).Version"}
releaseVersion, err := exec.Command("powershell", args...).Output()
if err != nil {
return "", err
}
return strings.TrimSpace(string(releaseVersion)), nil
}

View File

@ -0,0 +1,72 @@
/*
Copyright 2016 The Kubernetes Authors.
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 system
import (
"github.com/golang/glog"
"k8s.io/apimachinery/pkg/util/errors"
)
// Validator is the interface for all validators.
type Validator interface {
// Name is the name of the validator.
Name() string
// Validate is the validate function.
Validate(SysSpec) (error, error)
}
// Reporter is the interface for the reporters for the validators.
type Reporter interface {
// Report reports the results of the system verification
Report(string, string, ValidationResultType) error
}
// Validate uses validators to validate the system and returns a warning or error.
func Validate(spec SysSpec, validators []Validator) (error, error) {
var errs []error
var warns []error
for _, v := range validators {
glog.Infof("Validating %s...", v.Name())
warn, err := v.Validate(spec)
errs = append(errs, err)
warns = append(warns, warn)
}
return errors.NewAggregate(warns), errors.NewAggregate(errs)
}
// ValidateSpec uses all default validators to validate the system and writes to stdout.
func ValidateSpec(spec SysSpec, runtime string) (error, error) {
// OS-level validators.
var osValidators = []Validator{
&OSValidator{Reporter: DefaultReporter},
&KernelValidator{Reporter: DefaultReporter},
&CgroupsValidator{Reporter: DefaultReporter},
&packageValidator{reporter: DefaultReporter},
}
// Docker-specific validators.
var dockerValidators = []Validator{
&DockerValidator{Reporter: DefaultReporter},
}
validators := osValidators
switch runtime {
case "docker":
validators = append(validators, dockerValidators...)
}
return Validate(spec, validators)
}