github.com/Equinix-Metal/virtlet@v1.5.2-0.20210807010419-342346535dc5/tests/integration/manager.go (about)

     1  /*
     2  Copyright 2017 Mirantis
     3  
     4  Licensed under the Apache License, Version 2.0 (the "License");
     5  you may not use this file except in compliance with the License.
     6  You may obtain a copy of the License at
     7  
     8      http://www.apache.org/licenses/LICENSE-2.0
     9  
    10  Unless required by applicable law or agreed to in writing, software
    11  distributed under the License is distributed on an "AS IS" BASIS,
    12  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    13  See the License for the specific language governing permissions and
    14  limitations under the License.
    15  */
    16  
    17  package integration
    18  
    19  import (
    20  	"fmt"
    21  	"io/ioutil"
    22  	"net"
    23  	"net/http"
    24  	"net/http/httptest"
    25  	"os"
    26  	"path/filepath"
    27  	"testing"
    28  	"time"
    29  
    30  	"google.golang.org/grpc"
    31  
    32  	"github.com/Equinix-Metal/virtlet/pkg/api/virtlet.k8s/v1"
    33  	"github.com/Equinix-Metal/virtlet/pkg/config"
    34  	"github.com/Equinix-Metal/virtlet/pkg/diag"
    35  	"github.com/Equinix-Metal/virtlet/pkg/manager"
    36  	"github.com/Equinix-Metal/virtlet/pkg/tapmanager"
    37  )
    38  
    39  const (
    40  	virtletSocket    = "/tmp/virtlet.sock"
    41  	disableKvmEnvVar = "VIRTLET_DISABLE_KVM"
    42  )
    43  
    44  type fakeFDManager struct{}
    45  
    46  var fdManager tapmanager.FDManager
    47  
    48  func (m *fakeFDManager) AddFDs(key string, data interface{}) ([]byte, error) {
    49  	return nil, nil
    50  }
    51  
    52  func (m *fakeFDManager) ReleaseFDs(key string) error {
    53  	return nil
    54  }
    55  
    56  func (m *fakeFDManager) Recover(key string, data interface{}) error {
    57  	return nil
    58  }
    59  
    60  type fakeImageFileSystem struct {
    61  	t     *testing.T
    62  	inner http.FileSystem
    63  }
    64  
    65  func newFakeImageFileSystem(t *testing.T) http.FileSystem {
    66  	return &fakeImageFileSystem{t: t, inner: http.Dir("/images")}
    67  }
    68  
    69  func (fs *fakeImageFileSystem) Open(name string) (http.File, error) {
    70  	if name != "/cirros.img" && name != "/copy/cirros.img" {
    71  		fs.t.Errorf("bad file name %q", name)
    72  		return nil, fmt.Errorf("bad file name %q", name)
    73  	}
    74  	return fs.inner.Open("/cirros.img")
    75  }
    76  
    77  type VirtletManager struct {
    78  	t       *testing.T
    79  	ts      *httptest.Server
    80  	tempDir string
    81  	manager *manager.VirtletManager
    82  	conn    *grpc.ClientConn
    83  	doneCh  chan struct{}
    84  }
    85  
    86  func NewVirtletManager(t *testing.T) *VirtletManager {
    87  	return &VirtletManager{t: t}
    88  }
    89  
    90  func (v *VirtletManager) startImageServer() {
    91  	l, err := net.Listen("tcp", "127.0.0.1:80")
    92  	if err != nil {
    93  		v.t.Fatalf("can't listen on port 80: %v", err)
    94  	}
    95  	v.ts = httptest.NewUnstartedServer(http.FileServer(newFakeImageFileSystem(v.t)))
    96  	v.ts.Listener = l
    97  	v.ts.Start()
    98  }
    99  
   100  func (v *VirtletManager) Run() {
   101  	if v.manager != nil {
   102  		v.t.Fatalf("virtlet manager already started")
   103  	}
   104  
   105  	v.startImageServer()
   106  
   107  	var err error
   108  	v.tempDir, err = ioutil.TempDir("", "virtlet-manager")
   109  	if err != nil {
   110  		v.t.Fatalf("Can't create temp directory: %v", err)
   111  	}
   112  
   113  	os.Setenv("KUBERNETES_CLUSTER_URL", "")
   114  	pstr := func(s string) *string { return &s }
   115  	pbool := func(b bool) *bool { return &b }
   116  	cfg := config.GetDefaultConfig()
   117  	config.Override(cfg, &v1.VirtletConfig{
   118  		DatabasePath:         pstr(filepath.Join(v.tempDir, "virtlet.db")),
   119  		DownloadProtocol:     pstr("http"),
   120  		ImageDir:             pstr(filepath.Join(v.tempDir, "images")),
   121  		SkipImageTranslation: pbool(true),
   122  		LibvirtURI:           pstr(libvirtURI),
   123  		RawDevices:           pstr("loop*"),
   124  		CRISocketPath:        pstr(virtletSocket),
   125  		DisableLogging:       pbool(true),
   126  		DisableKVM:           pbool(os.Getenv(disableKvmEnvVar) != ""),
   127  	})
   128  	v.manager = manager.NewVirtletManager(cfg, &fakeFDManager{}, nil, diag.NewDiagSet())
   129  	v.doneCh = make(chan struct{})
   130  	go func() {
   131  		if err := v.manager.Run(); err != nil {
   132  			v.t.Logf("VirtletManager result (expect closed network connection error): %v", err)
   133  		}
   134  		v.manager = nil
   135  		close(v.doneCh)
   136  	}()
   137  
   138  	if err := waitForSocket(virtletSocket); err != nil {
   139  		v.t.Fatalf("Couldn't connect to virtlet socket: %v", err)
   140  	}
   141  
   142  	v.conn, err = grpc.Dial(virtletSocket, grpc.WithInsecure(), grpc.WithDialer(Dial))
   143  	if err != nil {
   144  		v.t.Fatalf("Couldn't connect to virtlet socket: %v", err)
   145  	}
   146  }
   147  
   148  func (v *VirtletManager) Close() {
   149  	if v.manager == nil {
   150  		v.t.Fatalf("virtlet manager not started")
   151  	}
   152  	v.manager.Stop()
   153  	os.RemoveAll(v.tempDir)
   154  	v.ts.Close()
   155  	<-v.doneCh
   156  }
   157  
   158  func Dial(socket string, timeout time.Duration) (net.Conn, error) {
   159  	return net.DialTimeout("unix", socket, timeout)
   160  }