Files
kata-containers/virtcontainers/kata_agent_test.go
Sebastien Boeuf 8152e15a61 virtcontainers: kata_agent: Factorize appending devices
This commit factorizes the code appending devices to the device list
provided to the Kata agent, in order to reduce the complexity of the
function createContainer().

Fixes #56

Signed-off-by: Sebastien Boeuf <sebastien.boeuf@intel.com>
2018-03-15 12:20:32 -07:00

382 lines
9.6 KiB
Go

//
// 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 virtcontainers
import (
"fmt"
"io/ioutil"
"net"
"os"
"reflect"
"testing"
"github.com/kata-containers/runtime/virtcontainers/pkg/mock"
gpb "github.com/gogo/protobuf/types"
pb "github.com/kata-containers/agent/protocols/grpc"
"github.com/stretchr/testify/assert"
"github.com/vishvananda/netlink"
"golang.org/x/net/context"
"google.golang.org/grpc"
)
var (
testKataProxyURLTempl = "unix://%s/kata-proxy-test.sock"
testBlockDeviceVirtPath = "testBlockDeviceVirtPath"
testBlockDeviceCtrPath = "testBlockDeviceCtrPath"
)
func proxyHandlerDiscard(c net.Conn) {
buf := make([]byte, 1024)
c.Read(buf)
}
func testGenerateKataProxySockDir() (string, error) {
dir, err := ioutil.TempDir("", "kata-proxy-test")
if err != nil {
return "", err
}
return dir, nil
}
func TestKataAgentConnect(t *testing.T) {
proxy := mock.ProxyUnixMock{
ClientHandler: proxyHandlerDiscard,
}
sockDir, err := testGenerateKataProxySockDir()
if err != nil {
t.Fatal(err)
}
defer os.RemoveAll(sockDir)
testKataProxyURL := fmt.Sprintf(testKataProxyURLTempl, sockDir)
if err := proxy.Start(testKataProxyURL); err != nil {
t.Fatal(err)
}
defer proxy.Stop()
k := &kataAgent{
state: KataAgentState{
URL: testKataProxyURL,
},
}
if err := k.connect(); err != nil {
t.Fatal(err)
}
if k.client == nil {
t.Fatal("Kata agent client is not properly initialized")
}
}
func TestKataAgentDisconnect(t *testing.T) {
proxy := mock.ProxyUnixMock{
ClientHandler: proxyHandlerDiscard,
}
sockDir, err := testGenerateKataProxySockDir()
if err != nil {
t.Fatal(err)
}
defer os.RemoveAll(sockDir)
testKataProxyURL := fmt.Sprintf(testKataProxyURLTempl, sockDir)
if err := proxy.Start(testKataProxyURL); err != nil {
t.Fatal(err)
}
defer proxy.Stop()
k := &kataAgent{
state: KataAgentState{
URL: testKataProxyURL,
},
}
if err := k.connect(); err != nil {
t.Fatal(err)
}
if err := k.disconnect(); err != nil {
t.Fatal(err)
}
if k.client != nil {
t.Fatal("Kata agent client pointer should be nil")
}
}
type gRPCProxy struct{}
var emptyResp = &gpb.Empty{}
func (p *gRPCProxy) CreateContainer(ctx context.Context, req *pb.CreateContainerRequest) (*gpb.Empty, error) {
return emptyResp, nil
}
func (p *gRPCProxy) StartContainer(ctx context.Context, req *pb.StartContainerRequest) (*gpb.Empty, error) {
return emptyResp, nil
}
func (p *gRPCProxy) ExecProcess(ctx context.Context, req *pb.ExecProcessRequest) (*gpb.Empty, error) {
return emptyResp, nil
}
func (p *gRPCProxy) SignalProcess(ctx context.Context, req *pb.SignalProcessRequest) (*gpb.Empty, error) {
return emptyResp, nil
}
func (p *gRPCProxy) WaitProcess(ctx context.Context, req *pb.WaitProcessRequest) (*pb.WaitProcessResponse, error) {
return &pb.WaitProcessResponse{}, nil
}
func (p *gRPCProxy) RemoveContainer(ctx context.Context, req *pb.RemoveContainerRequest) (*gpb.Empty, error) {
return emptyResp, nil
}
func (p *gRPCProxy) WriteStdin(ctx context.Context, req *pb.WriteStreamRequest) (*pb.WriteStreamResponse, error) {
return &pb.WriteStreamResponse{}, nil
}
func (p *gRPCProxy) ReadStdout(ctx context.Context, req *pb.ReadStreamRequest) (*pb.ReadStreamResponse, error) {
return &pb.ReadStreamResponse{}, nil
}
func (p *gRPCProxy) ReadStderr(ctx context.Context, req *pb.ReadStreamRequest) (*pb.ReadStreamResponse, error) {
return &pb.ReadStreamResponse{}, nil
}
func (p *gRPCProxy) CloseStdin(ctx context.Context, req *pb.CloseStdinRequest) (*gpb.Empty, error) {
return emptyResp, nil
}
func (p *gRPCProxy) TtyWinResize(ctx context.Context, req *pb.TtyWinResizeRequest) (*gpb.Empty, error) {
return emptyResp, nil
}
func (p *gRPCProxy) CreateSandbox(ctx context.Context, req *pb.CreateSandboxRequest) (*gpb.Empty, error) {
return emptyResp, nil
}
func (p *gRPCProxy) DestroySandbox(ctx context.Context, req *pb.DestroySandboxRequest) (*gpb.Empty, error) {
return emptyResp, nil
}
func (p *gRPCProxy) AddInterface(ctx context.Context, req *pb.AddInterfaceRequest) (*pb.Interface, error) {
return nil, nil
}
func (p *gRPCProxy) RemoveInterface(ctx context.Context, req *pb.RemoveInterfaceRequest) (*pb.Interface, error) {
return nil, nil
}
func (p *gRPCProxy) UpdateInterface(ctx context.Context, req *pb.UpdateInterfaceRequest) (*pb.Interface, error) {
return nil, nil
}
func (p *gRPCProxy) UpdateRoutes(ctx context.Context, req *pb.UpdateRoutesRequest) (*pb.Routes, error) {
return nil, nil
}
func (p *gRPCProxy) OnlineCPUMem(ctx context.Context, req *pb.OnlineCPUMemRequest) (*gpb.Empty, error) {
return emptyResp, nil
}
func gRPCRegister(s *grpc.Server, srv interface{}) {
switch g := srv.(type) {
case *gRPCProxy:
pb.RegisterAgentServiceServer(s, g)
}
}
var reqList = []interface{}{
&pb.CreateSandboxRequest{},
&pb.DestroySandboxRequest{},
&pb.ExecProcessRequest{},
&pb.CreateContainerRequest{},
&pb.StartContainerRequest{},
&pb.RemoveContainerRequest{},
&pb.SignalProcessRequest{},
}
func TestKataAgentSendReq(t *testing.T) {
impl := &gRPCProxy{}
proxy := mock.ProxyGRPCMock{
GRPCImplementer: impl,
GRPCRegister: gRPCRegister,
}
sockDir, err := testGenerateKataProxySockDir()
if err != nil {
t.Fatal(err)
}
defer os.RemoveAll(sockDir)
testKataProxyURL := fmt.Sprintf(testKataProxyURLTempl, sockDir)
if err := proxy.Start(testKataProxyURL); err != nil {
t.Fatal(err)
}
defer proxy.Stop()
k := &kataAgent{
state: KataAgentState{
URL: testKataProxyURL,
},
}
for _, req := range reqList {
if _, err := k.sendReq(req); err != nil {
t.Fatal(err)
}
}
}
func TestGenerateInterfacesAndRoutes(t *testing.T) {
impl := &gRPCProxy{}
proxy := mock.ProxyGRPCMock{
GRPCImplementer: impl,
GRPCRegister: gRPCRegister,
}
sockDir, err := testGenerateKataProxySockDir()
if err != nil {
t.Fatal(err)
}
defer os.RemoveAll(sockDir)
testKataProxyURL := fmt.Sprintf(testKataProxyURLTempl, sockDir)
if err := proxy.Start(testKataProxyURL); err != nil {
t.Fatal(err)
}
defer proxy.Stop()
k := &kataAgent{
state: KataAgentState{
URL: testKataProxyURL,
},
}
//
//Create a couple of addresses
//
address1 := &net.IPNet{IP: net.IPv4(172, 17, 0, 2), Mask: net.CIDRMask(16, 32)}
address2 := &net.IPNet{IP: net.IPv4(182, 17, 0, 2), Mask: net.CIDRMask(16, 32)}
addrs := []netlink.Addr{
{IPNet: address1, Label: "phyaddr1"},
{IPNet: address2, Label: "phyaddr2"},
}
// Create a couple of routes:
dst2 := &net.IPNet{IP: net.IPv4(172, 17, 0, 0), Mask: net.CIDRMask(16, 32)}
src2 := net.IPv4(172, 17, 0, 2)
gw2 := net.IPv4(172, 17, 0, 1)
routes := []netlink.Route{
{LinkIndex: 329, Dst: nil, Src: nil, Gw: net.IPv4(172, 17, 0, 1), Scope: netlink.Scope(254)},
{LinkIndex: 329, Dst: dst2, Src: src2, Gw: gw2},
}
networkInfo := NetworkInfo{
Iface: NetlinkIface{
LinkAttrs: netlink.LinkAttrs{MTU: 1500},
Type: "",
},
Addrs: addrs,
Routes: routes,
}
ep0 := &PhysicalEndpoint{
IfaceName: "eth0",
HardAddr: net.HardwareAddr{0x02, 0x00, 0xca, 0xfe, 0x00, 0x04}.String(),
EndpointProperties: networkInfo,
}
endpoints := []Endpoint{ep0}
nns := NetworkNamespace{NetNsPath: "foobar", NetNsCreated: true, Endpoints: endpoints}
resInterfaces, resRoutes, err := k.generateInterfacesAndRoutes(nns)
//
// Build expected results:
//
expectedAddresses := []*pb.IPAddress{
{Family: 0, Address: "172.17.0.2", Mask: "16"},
{Family: 0, Address: "182.17.0.2", Mask: "16"},
}
expectedInterfaces := []*pb.Interface{
{Device: "eth0", Name: "eth0", IPAddresses: expectedAddresses, Mtu: 1500, HwAddr: "02:00:ca:fe:00:04"},
}
expectedRoutes := []*pb.Route{
{Dest: "", Gateway: "172.17.0.1", Device: "eth0", Source: "", Scope: uint32(254)},
{Dest: "172.17.0.0/16", Gateway: "172.17.0.1", Device: "eth0", Source: "172.17.0.2"},
}
assert.Nil(t, err, "unexpected failure when calling generateKataInterfacesAndRoutes")
assert.True(t, reflect.DeepEqual(resInterfaces, expectedInterfaces),
"Interfaces returned didn't match: got %+v, expecting %+v", resInterfaces, expectedInterfaces)
assert.True(t, reflect.DeepEqual(resRoutes, expectedRoutes),
"Routes returned didn't match: got %+v, expecting %+v", resRoutes, expectedRoutes)
}
func TestAppendDevicesEmptyContainerDeviceList(t *testing.T) {
k := kataAgent{}
devList := []*pb.Device{}
expected := []*pb.Device{}
ctrDevices := []Device{}
updatedDevList := k.appendDevices(devList, ctrDevices)
assert.True(t, reflect.DeepEqual(updatedDevList, expected),
"Device lists didn't match: got %+v, expecting %+v",
updatedDevList, expected)
}
func TestAppendDevices(t *testing.T) {
k := kataAgent{}
devList := []*pb.Device{}
expected := []*pb.Device{
{
Type: kataBlkDevType,
VmPath: testBlockDeviceVirtPath,
ContainerPath: testBlockDeviceCtrPath,
},
}
ctrDevices := []Device{
&BlockDevice{
VirtPath: testBlockDeviceVirtPath,
DeviceInfo: DeviceInfo{
ContainerPath: testBlockDeviceCtrPath,
},
},
}
updatedDevList := k.appendDevices(devList, ctrDevices)
assert.True(t, reflect.DeepEqual(updatedDevList, expected),
"Device lists didn't match: got %+v, expecting %+v",
updatedDevList, expected)
}