github.com/kata-containers/runtime@v0.0.0-20210505125100-04f29832a923/virtcontainers/pkg/mock/mock.go (about)

     1  // Copyright (c) 2017 Intel Corporation
     2  //
     3  // SPDX-License-Identifier: Apache-2.0
     4  //
     5  
     6  package mock
     7  
     8  import (
     9  	"flag"
    10  	"fmt"
    11  	"io/ioutil"
    12  	"net"
    13  	"net/url"
    14  	"os"
    15  	"path/filepath"
    16  
    17  	"google.golang.org/grpc"
    18  )
    19  
    20  // DefaultMockKataShimBinPath is populated at link time.
    21  var DefaultMockKataShimBinPath string
    22  
    23  // DefaultMockHookBinPath is populated at link time.
    24  var DefaultMockHookBinPath string
    25  
    26  // ShimStdoutOutput is the expected output sent by the mock shim on stdout.
    27  const ShimStdoutOutput = "Some output on stdout"
    28  
    29  // ShimStderrOutput is the expected output sent by the mock shim on stderr.
    30  const ShimStderrOutput = "Some output on stderr"
    31  
    32  // ShimMockConfig is the configuration structure for all virtcontainers shim mock implementations.
    33  type ShimMockConfig struct {
    34  	Name               string
    35  	URLParamName       string
    36  	ContainerParamName string
    37  	TokenParamName     string
    38  }
    39  
    40  // StartShim is a common routine for starting a shim mock.
    41  func StartShim(config ShimMockConfig) error {
    42  	logDirPath, err := ioutil.TempDir("", config.Name+"-")
    43  	if err != nil {
    44  		return err
    45  	}
    46  
    47  	logFilePath := filepath.Join(logDirPath, "mock_"+config.Name+".log")
    48  
    49  	f, err := os.Create(logFilePath)
    50  	if err != nil {
    51  		return err
    52  	}
    53  	defer f.Close()
    54  
    55  	tokenFlag := flag.String(config.TokenParamName, "", "Container token")
    56  	urlFlag := flag.String(config.URLParamName, "", "Agent URL")
    57  	containerFlag := flag.String(config.ContainerParamName, "", "Container ID")
    58  
    59  	flag.Parse()
    60  
    61  	fmt.Fprintf(f, "INFO: Token = %s\n", *tokenFlag)
    62  	fmt.Fprintf(f, "INFO: URL = %s\n", *urlFlag)
    63  	fmt.Fprintf(f, "INFO: Container = %s\n", *containerFlag)
    64  
    65  	if *tokenFlag == "" {
    66  		err := fmt.Errorf("token should not be empty")
    67  		fmt.Fprintf(f, "%s\n", err)
    68  		return err
    69  	}
    70  
    71  	if *urlFlag == "" {
    72  		err := fmt.Errorf("url should not be empty")
    73  		fmt.Fprintf(f, "%s\n", err)
    74  		return err
    75  	}
    76  
    77  	if _, err := url.Parse(*urlFlag); err != nil {
    78  		err2 := fmt.Errorf("could not parse the URL %q: %s", *urlFlag, err)
    79  		fmt.Fprintf(f, "%s\n", err2)
    80  		return err2
    81  	}
    82  
    83  	if *containerFlag == "" {
    84  		err := fmt.Errorf("container should not be empty")
    85  		fmt.Fprintf(f, "%s\n", err)
    86  		return err
    87  	}
    88  
    89  	// Print some traces to stdout
    90  	fmt.Fprint(os.Stdout, ShimStdoutOutput)
    91  	os.Stdout.Close()
    92  
    93  	// Print some traces to stderr
    94  	fmt.Fprint(os.Stderr, ShimStderrOutput)
    95  	os.Stderr.Close()
    96  
    97  	fmt.Fprint(f, "INFO: Shim exited properly\n")
    98  
    99  	return nil
   100  }
   101  
   102  // ProxyMock is the proxy mock interface.
   103  // It allows for implementing different kind
   104  // of containers proxies front end.
   105  type ProxyMock interface {
   106  	Start(URL string) error
   107  	Stop() error
   108  }
   109  
   110  // ProxyUnixMock is the UNIX proxy mock
   111  type ProxyUnixMock struct {
   112  	ClientHandler func(c net.Conn)
   113  
   114  	listener net.Listener
   115  }
   116  
   117  // ProxyGRPCMock is the gRPC proxy mock
   118  type ProxyGRPCMock struct {
   119  	// GRPCImplementer is the structure implementing
   120  	// the GRPC interface we want the proxy to serve.
   121  	GRPCImplementer interface{}
   122  
   123  	// GRPCRegister is the registration routine for
   124  	// the GRPC service.
   125  	GRPCRegister func(s *grpc.Server, srv interface{})
   126  
   127  	listener net.Listener
   128  }
   129  
   130  // Start starts the UNIX proxy mock
   131  func (p *ProxyUnixMock) Start(URL string) error {
   132  	if p.ClientHandler == nil {
   133  		return fmt.Errorf("Missing client handler")
   134  	}
   135  
   136  	url, err := url.Parse(URL)
   137  	if err != nil {
   138  		return err
   139  	}
   140  
   141  	l, err := net.Listen(url.Scheme, url.Path)
   142  	if err != nil {
   143  		return err
   144  	}
   145  
   146  	p.listener = l
   147  
   148  	go func() {
   149  		defer func() {
   150  			l.Close()
   151  		}()
   152  
   153  		for {
   154  			conn, err := l.Accept()
   155  			if err != nil {
   156  				return
   157  			}
   158  
   159  			go p.ClientHandler(conn)
   160  		}
   161  	}()
   162  
   163  	return nil
   164  }
   165  
   166  // Stop stops the UNIX proxy mock
   167  func (p *ProxyUnixMock) Stop() error {
   168  	if p.listener == nil {
   169  		return fmt.Errorf("Missing proxy listener")
   170  	}
   171  
   172  	return p.listener.Close()
   173  }
   174  
   175  // Start starts the gRPC proxy mock
   176  func (p *ProxyGRPCMock) Start(URL string) error {
   177  	if p.GRPCImplementer == nil {
   178  		return fmt.Errorf("Missing gRPC handler")
   179  	}
   180  
   181  	if p.GRPCRegister == nil {
   182  		return fmt.Errorf("Missing gRPC registration routine")
   183  	}
   184  
   185  	url, err := url.Parse(URL)
   186  	if err != nil {
   187  		return err
   188  	}
   189  
   190  	l, err := net.Listen(url.Scheme, url.Path)
   191  	if err != nil {
   192  		return err
   193  	}
   194  
   195  	p.listener = l
   196  
   197  	grpcServer := grpc.NewServer()
   198  	p.GRPCRegister(grpcServer, p.GRPCImplementer)
   199  
   200  	go func() {
   201  		grpcServer.Serve(l)
   202  	}()
   203  
   204  	return nil
   205  }
   206  
   207  // Stop stops the gRPC proxy mock
   208  func (p *ProxyGRPCMock) Stop() error {
   209  	if p.listener == nil {
   210  		return fmt.Errorf("Missing proxy listener")
   211  	}
   212  
   213  	return p.listener.Close()
   214  }