mirror of
https://github.com/kata-containers/kata-containers.git
synced 2025-10-22 04:18:53 +00:00
cli: Add initial cli implementation.
- Add kata-runtime - Add unit test - Add Makefile to build cli Fixes: #33 Signed-off-by: Julio Montes <julio.montes@intel.com> Signed-off-by: James O. D. Hunt <james.o.hunt@intel.com> Signed-off-by: Jose Carlos Venegas Munoz <jose.carlos.venegas.munoz@intel.com>
This commit is contained in:
committed by
Jose Carlos Venegas Munoz
parent
65b9936798
commit
e84a9a70b0
466
cli/kata-check_amd64_test.go
Normal file
466
cli/kata-check_amd64_test.go
Normal file
@@ -0,0 +1,466 @@
|
||||
// Copyright (c) 2018 Intel Corporation
|
||||
//
|
||||
// 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 main
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"path"
|
||||
"path/filepath"
|
||||
"regexp"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"github.com/sirupsen/logrus"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/urfave/cli"
|
||||
)
|
||||
|
||||
func setupCheckHostIsVMContainerCapable(assert *assert.Assertions, cpuInfoFile string, cpuData []testCPUData, moduleData []testModuleData) {
|
||||
createModules(assert, cpuInfoFile, moduleData)
|
||||
|
||||
// all the modules files have now been created, so deal with the
|
||||
// cpuinfo data.
|
||||
for _, d := range cpuData {
|
||||
err := makeCPUInfoFile(cpuInfoFile, d.vendorID, d.flags)
|
||||
assert.NoError(err)
|
||||
|
||||
details := vmContainerCapableDetails{
|
||||
cpuInfoFile: cpuInfoFile,
|
||||
requiredCPUFlags: archRequiredCPUFlags,
|
||||
requiredCPUAttribs: archRequiredCPUAttribs,
|
||||
requiredKernelModules: archRequiredKernelModules,
|
||||
}
|
||||
|
||||
err = hostIsVMContainerCapable(details)
|
||||
if d.expectError {
|
||||
assert.Error(err)
|
||||
} else {
|
||||
assert.NoError(err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestCCCheckCLIFunction(t *testing.T) {
|
||||
assert := assert.New(t)
|
||||
|
||||
dir, err := ioutil.TempDir("", "")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
defer os.RemoveAll(dir)
|
||||
|
||||
savedSysModuleDir := sysModuleDir
|
||||
savedProcCPUInfo := procCPUInfo
|
||||
|
||||
cpuInfoFile := filepath.Join(dir, "cpuinfo")
|
||||
|
||||
// XXX: override
|
||||
sysModuleDir = filepath.Join(dir, "sys/module")
|
||||
procCPUInfo = cpuInfoFile
|
||||
|
||||
defer func() {
|
||||
sysModuleDir = savedSysModuleDir
|
||||
procCPUInfo = savedProcCPUInfo
|
||||
}()
|
||||
|
||||
err = os.MkdirAll(sysModuleDir, testDirMode)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
cpuData := []testCPUData{
|
||||
{"GenuineIntel", "lm vmx sse4_1", false},
|
||||
}
|
||||
|
||||
moduleData := []testModuleData{
|
||||
{filepath.Join(sysModuleDir, "kvm_intel/parameters/unrestricted_guest"), false, "Y"},
|
||||
{filepath.Join(sysModuleDir, "kvm_intel/parameters/nested"), false, "Y"},
|
||||
}
|
||||
|
||||
devNull, err := os.OpenFile(os.DevNull, os.O_WRONLY, 0666)
|
||||
assert.NoError(err)
|
||||
defer devNull.Close()
|
||||
|
||||
savedLogOutput := kataLog.Logger.Out
|
||||
|
||||
// discard normal output
|
||||
kataLog.Logger.Out = devNull
|
||||
|
||||
defer func() {
|
||||
kataLog.Logger.Out = savedLogOutput
|
||||
}()
|
||||
|
||||
setupCheckHostIsVMContainerCapable(assert, cpuInfoFile, cpuData, moduleData)
|
||||
|
||||
app := cli.NewApp()
|
||||
ctx := cli.NewContext(app, nil, nil)
|
||||
app.Name = "foo"
|
||||
|
||||
// create buffer to save logger output
|
||||
buf := &bytes.Buffer{}
|
||||
|
||||
// capture output this time
|
||||
kataLog.Logger.Out = buf
|
||||
|
||||
fn, ok := kataCheckCLICommand.Action.(func(context *cli.Context) error)
|
||||
assert.True(ok)
|
||||
|
||||
err = fn(ctx)
|
||||
assert.NoError(err)
|
||||
|
||||
output := buf.String()
|
||||
|
||||
for _, c := range cpuData {
|
||||
assert.True(findAnchoredString(output, c.vendorID))
|
||||
for _, flag := range strings.Fields(c.flags) {
|
||||
assert.True(findAnchoredString(output, flag))
|
||||
}
|
||||
}
|
||||
|
||||
for _, m := range moduleData {
|
||||
name := path.Base(m.path)
|
||||
assert.True(findAnchoredString(output, name))
|
||||
}
|
||||
}
|
||||
|
||||
func TestCheckCheckKernelModulesNoNesting(t *testing.T) {
|
||||
assert := assert.New(t)
|
||||
|
||||
dir, err := ioutil.TempDir("", "")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
defer os.RemoveAll(dir)
|
||||
|
||||
savedSysModuleDir := sysModuleDir
|
||||
savedProcCPUInfo := procCPUInfo
|
||||
|
||||
cpuInfoFile := filepath.Join(dir, "cpuinfo")
|
||||
|
||||
// XXX: override
|
||||
sysModuleDir = filepath.Join(dir, "sys/module")
|
||||
procCPUInfo = cpuInfoFile
|
||||
|
||||
defer func() {
|
||||
sysModuleDir = savedSysModuleDir
|
||||
procCPUInfo = savedProcCPUInfo
|
||||
}()
|
||||
|
||||
err = os.MkdirAll(sysModuleDir, testDirMode)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
requiredModules := map[string]kernelModule{
|
||||
"kvm_intel": {
|
||||
desc: "Intel KVM",
|
||||
parameters: map[string]string{
|
||||
"nested": "Y",
|
||||
"unrestricted_guest": "Y",
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
actualModuleData := []testModuleData{
|
||||
{filepath.Join(sysModuleDir, "kvm"), true, ""},
|
||||
{filepath.Join(sysModuleDir, "kvm_intel"), true, ""},
|
||||
{filepath.Join(sysModuleDir, "kvm_intel/parameters/unrestricted_guest"), false, "Y"},
|
||||
|
||||
// XXX: force a warning
|
||||
{filepath.Join(sysModuleDir, "kvm_intel/parameters/nested"), false, "N"},
|
||||
}
|
||||
|
||||
vendor := "GenuineIntel"
|
||||
flags := "vmx lm sse4_1 hypervisor"
|
||||
|
||||
_, err = checkKernelModules(requiredModules, archKernelParamHandler)
|
||||
// no cpuInfoFile yet
|
||||
assert.Error(err)
|
||||
|
||||
createModules(assert, cpuInfoFile, actualModuleData)
|
||||
|
||||
err = makeCPUInfoFile(cpuInfoFile, vendor, flags)
|
||||
assert.NoError(err)
|
||||
|
||||
count, err := checkKernelModules(requiredModules, archKernelParamHandler)
|
||||
assert.NoError(err)
|
||||
assert.Equal(count, uint32(0))
|
||||
|
||||
// create buffer to save logger output
|
||||
buf := &bytes.Buffer{}
|
||||
|
||||
savedLogOutput := kataLog.Logger.Out
|
||||
|
||||
defer func() {
|
||||
kataLog.Logger.Out = savedLogOutput
|
||||
}()
|
||||
|
||||
kataLog.Logger.Out = buf
|
||||
|
||||
count, err = checkKernelModules(requiredModules, archKernelParamHandler)
|
||||
|
||||
assert.NoError(err)
|
||||
assert.Equal(count, uint32(0))
|
||||
|
||||
re := regexp.MustCompile(`\bwarning\b.*\bnested\b`)
|
||||
matches := re.FindAllStringSubmatch(buf.String(), -1)
|
||||
assert.NotEmpty(matches)
|
||||
}
|
||||
|
||||
func TestCheckCheckKernelModulesNoUnrestrictedGuest(t *testing.T) {
|
||||
assert := assert.New(t)
|
||||
|
||||
dir, err := ioutil.TempDir("", "")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
defer os.RemoveAll(dir)
|
||||
|
||||
savedSysModuleDir := sysModuleDir
|
||||
savedProcCPUInfo := procCPUInfo
|
||||
|
||||
cpuInfoFile := filepath.Join(dir, "cpuinfo")
|
||||
|
||||
// XXX: override
|
||||
sysModuleDir = filepath.Join(dir, "sys/module")
|
||||
procCPUInfo = cpuInfoFile
|
||||
|
||||
defer func() {
|
||||
sysModuleDir = savedSysModuleDir
|
||||
procCPUInfo = savedProcCPUInfo
|
||||
}()
|
||||
|
||||
err = os.MkdirAll(sysModuleDir, testDirMode)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
requiredModules := map[string]kernelModule{
|
||||
"kvm_intel": {
|
||||
desc: "Intel KVM",
|
||||
parameters: map[string]string{
|
||||
"nested": "Y",
|
||||
"unrestricted_guest": "Y",
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
actualModuleData := []testModuleData{
|
||||
{filepath.Join(sysModuleDir, "kvm"), true, ""},
|
||||
{filepath.Join(sysModuleDir, "kvm_intel"), true, ""},
|
||||
{filepath.Join(sysModuleDir, "kvm_intel/parameters/nested"), false, "Y"},
|
||||
|
||||
// XXX: force a failure on non-VMM systems
|
||||
{filepath.Join(sysModuleDir, "kvm_intel/parameters/unrestricted_guest"), false, "N"},
|
||||
}
|
||||
|
||||
vendor := "GenuineIntel"
|
||||
flags := "vmx lm sse4_1"
|
||||
|
||||
_, err = checkKernelModules(requiredModules, archKernelParamHandler)
|
||||
// no cpuInfoFile yet
|
||||
assert.Error(err)
|
||||
|
||||
err = makeCPUInfoFile(cpuInfoFile, vendor, flags)
|
||||
assert.NoError(err)
|
||||
|
||||
createModules(assert, cpuInfoFile, actualModuleData)
|
||||
|
||||
count, err := checkKernelModules(requiredModules, archKernelParamHandler)
|
||||
|
||||
assert.NoError(err)
|
||||
// fails due to unrestricted_guest not being available
|
||||
assert.Equal(count, uint32(1))
|
||||
|
||||
// pretend test is running under a hypervisor
|
||||
flags += " hypervisor"
|
||||
|
||||
// recreate
|
||||
err = makeCPUInfoFile(cpuInfoFile, vendor, flags)
|
||||
assert.NoError(err)
|
||||
|
||||
// create buffer to save logger output
|
||||
buf := &bytes.Buffer{}
|
||||
|
||||
savedLogOutput := kataLog.Logger.Out
|
||||
|
||||
defer func() {
|
||||
kataLog.Logger.Out = savedLogOutput
|
||||
}()
|
||||
|
||||
kataLog.Logger.Out = buf
|
||||
|
||||
count, err = checkKernelModules(requiredModules, archKernelParamHandler)
|
||||
|
||||
// no error now because running under a hypervisor
|
||||
assert.NoError(err)
|
||||
assert.Equal(count, uint32(0))
|
||||
|
||||
re := regexp.MustCompile(`\bwarning\b.*\bunrestricted_guest\b`)
|
||||
matches := re.FindAllStringSubmatch(buf.String(), -1)
|
||||
assert.NotEmpty(matches)
|
||||
}
|
||||
|
||||
func TestCheckHostIsVMContainerCapable(t *testing.T) {
|
||||
assert := assert.New(t)
|
||||
|
||||
dir, err := ioutil.TempDir("", "")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
defer os.RemoveAll(dir)
|
||||
|
||||
savedSysModuleDir := sysModuleDir
|
||||
savedProcCPUInfo := procCPUInfo
|
||||
|
||||
cpuInfoFile := filepath.Join(dir, "cpuinfo")
|
||||
|
||||
// XXX: override
|
||||
sysModuleDir = filepath.Join(dir, "sys/module")
|
||||
procCPUInfo = cpuInfoFile
|
||||
|
||||
defer func() {
|
||||
sysModuleDir = savedSysModuleDir
|
||||
procCPUInfo = savedProcCPUInfo
|
||||
}()
|
||||
|
||||
err = os.MkdirAll(sysModuleDir, testDirMode)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
cpuData := []testCPUData{
|
||||
{"", "", true},
|
||||
{"Intel", "", true},
|
||||
{"GenuineIntel", "", true},
|
||||
{"GenuineIntel", "lm", true},
|
||||
{"GenuineIntel", "lm vmx", true},
|
||||
{"GenuineIntel", "lm vmx sse4_1", false},
|
||||
}
|
||||
|
||||
moduleData := []testModuleData{
|
||||
{filepath.Join(sysModuleDir, "kvm"), true, ""},
|
||||
{filepath.Join(sysModuleDir, "kvm_intel"), true, ""},
|
||||
{filepath.Join(sysModuleDir, "kvm_intel/parameters/nested"), false, "Y"},
|
||||
{filepath.Join(sysModuleDir, "kvm_intel/parameters/unrestricted_guest"), false, "Y"},
|
||||
}
|
||||
|
||||
setupCheckHostIsVMContainerCapable(assert, cpuInfoFile, cpuData, moduleData)
|
||||
|
||||
// remove the modules to force a failure
|
||||
err = os.RemoveAll(sysModuleDir)
|
||||
assert.NoError(err)
|
||||
|
||||
details := vmContainerCapableDetails{
|
||||
cpuInfoFile: cpuInfoFile,
|
||||
requiredCPUFlags: archRequiredCPUFlags,
|
||||
requiredCPUAttribs: archRequiredCPUAttribs,
|
||||
requiredKernelModules: archRequiredKernelModules,
|
||||
}
|
||||
|
||||
err = hostIsVMContainerCapable(details)
|
||||
assert.Error(err)
|
||||
}
|
||||
|
||||
func TestArchKernelParamHandler(t *testing.T) {
|
||||
assert := assert.New(t)
|
||||
|
||||
type testData struct {
|
||||
onVMM bool
|
||||
fields logrus.Fields
|
||||
msg string
|
||||
expectIgnore bool
|
||||
}
|
||||
|
||||
data := []testData{
|
||||
{true, logrus.Fields{}, "", false},
|
||||
{false, logrus.Fields{}, "", false},
|
||||
|
||||
{
|
||||
false,
|
||||
logrus.Fields{
|
||||
// wrong type
|
||||
"parameter": 123,
|
||||
},
|
||||
"foo",
|
||||
false,
|
||||
},
|
||||
|
||||
{
|
||||
false,
|
||||
logrus.Fields{
|
||||
"parameter": "unrestricted_guest",
|
||||
},
|
||||
"",
|
||||
false,
|
||||
},
|
||||
|
||||
{
|
||||
true,
|
||||
logrus.Fields{
|
||||
"parameter": "unrestricted_guest",
|
||||
},
|
||||
"",
|
||||
true,
|
||||
},
|
||||
|
||||
{
|
||||
false,
|
||||
logrus.Fields{
|
||||
"parameter": "nested",
|
||||
},
|
||||
"",
|
||||
true,
|
||||
},
|
||||
}
|
||||
|
||||
for i, d := range data {
|
||||
result := archKernelParamHandler(d.onVMM, d.fields, d.msg)
|
||||
if d.expectIgnore {
|
||||
assert.True(result, "test %d (%+v)", i, d)
|
||||
} else {
|
||||
assert.False(result, "test %d (%+v)", i, d)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestKvmIsUsable(t *testing.T) {
|
||||
assert := assert.New(t)
|
||||
|
||||
dir, err := ioutil.TempDir("", "")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
defer os.RemoveAll(dir)
|
||||
|
||||
savedKvmDevice := kvmDevice
|
||||
fakeKVMDevice := filepath.Join(dir, "kvm")
|
||||
kvmDevice = fakeKVMDevice
|
||||
|
||||
defer func() {
|
||||
kvmDevice = savedKvmDevice
|
||||
}()
|
||||
|
||||
err = kvmIsUsable()
|
||||
assert.Error(err)
|
||||
|
||||
err = createEmptyFile(fakeKVMDevice)
|
||||
assert.NoError(err)
|
||||
|
||||
err = kvmIsUsable()
|
||||
assert.Error(err)
|
||||
}
|
||||
Reference in New Issue
Block a user