func TestGuestToolsFailed(t *testing.T) { // Create temporary storage storage, err := runtime.NewTemporaryStorage(os.TempDir()) if err != nil { panic("Failed to create TemporaryStorage") } environment := &runtime.Environment{ TemporaryStorage: storage, } // Setup a new MetaService logTask := bytes.NewBuffer(nil) result := false resolved := false m := sync.Mutex{} s := metaservice.New([]string{"sh", "-c", "echo \"$TEST_TEXT\" && false"}, map[string]string{ "TEST_TEXT": "Hello world", }, logTask, func(r bool) { m.Lock() defer m.Unlock() if resolved { panic("It shouldn't be possible to resolve twice") } resolved = true result = r }, environment) // Create http server for testing ts := httptest.NewServer(s) defer ts.Close() u, err := url.Parse(ts.URL) if err != nil { panic("Expected a url we can parse") } // Create a logger logger, _ := runtime.CreateLogger("info") log := logger.WithField("component", "guest-tools-tests") // Create an run guest-tools g := new(u.Host, log) g.Run() // Check the state if !resolved { t.Error("Expected the metadata to have resolved the task") } if result != false { t.Error("Expected the metadata to get failed result") } if !strings.Contains(logTask.String(), "Hello world") { t.Error("Got unexpected taskLog: '", logTask.String(), "'") } }
// newSandbox will create a new sandbox and start it. func newSandbox( command []string, env map[string]string, proxies map[string]http.Handler, image *image.Instance, network *network.Network, c *runtime.TaskContext, e *engine, ) (*sandbox, error) { log := e.Log.WithField("taskId", c.TaskID).WithField("runId", c.RunID) vm, err := vm.NewVirtualMachine( e.engineConfig.MachineOptions, image, network, e.engineConfig.SocketFolder, "", "", log.WithField("component", "vm"), ) if err != nil { return nil, err } // Create sandbox s := &sandbox{ vm: vm, context: c, engine: e, proxies: proxies, log: log, } // Setup meta-data service s.metaService = metaservice.New(command, env, c.LogDrain(), s.result, e.Environment) // Create session manager s.sessions = newSessionManager(s.metaService, s.vm) // Setup network handler s.vm.SetHTTPHandler(http.HandlerFunc(s.handleRequest)) // Start the VM debug("Starting virtual machine") s.vm.Start() // Resolve when VM is closed go s.waitForCrash() return s, nil }
func TestGuestToolsProcessingActions(t *testing.T) { // Create temporary storage storage, err := runtime.NewTemporaryStorage(os.TempDir()) if err != nil { panic("Failed to create TemporaryStorage") } environment := &runtime.Environment{ TemporaryStorage: storage, } logTask := bytes.NewBuffer(nil) meta := metaservice.New([]string{}, map[string]string{}, logTask, func(r bool) { panic("This test shouldn't get to this point!") }, environment) // Create http server for testing ts := httptest.NewServer(meta) defer ts.Close() defer meta.StopPollers() // Hack to stop pollers, otherwise server will block u, err := url.Parse(ts.URL) if err != nil { panic("Expected a url we can parse") } // Create a logger logger, _ := runtime.CreateLogger("info") log := logger.WithField("component", "guest-tools-tests") // Create an run guest-tools g := new(u.Host, log) // start processing actions go g.ProcessActions() defer g.StopProcessingActions() //////////////////// debug("### Test meta.GetArtifact") f, err := storage.NewFolder() if err != nil { panic("Failed to create temp folder") } defer f.Remove() testFile := filepath.Join(f.Path(), "hello.txt") err = ioutil.WriteFile(testFile, []byte("hello-world"), 0777) nilOrPanic(err, "Failed to create testFile: ", testFile) debug(" - request file: %s", testFile) r, err := meta.GetArtifact(testFile) nilOrPanic(err, "meta.GetArtifact failed, error: ", err) debug(" - reading testFile") data, err := ioutil.ReadAll(r) nilOrPanic(err, "Failed to read testFile") debug(" - read: '%s'", string(data)) assert(string(data) == "hello-world", "Wrong payload: ", string(data)) //////////////////// debug("### Test meta.GetArtifact (missing file)") r, err = meta.GetArtifact(filepath.Join(f.Path(), "missing-file.txt")) assert(r == nil, "Expected error wihtout a reader") assert(err == engines.ErrResourceNotFound, "Expected ErrResourceNotFound") //////////////////// debug("### Test meta.ListFolder") testFolder := filepath.Join(f.Path(), "test-folder") err = os.Mkdir(testFolder, 0777) nilOrPanic(err, "Failed to create test-folder/") testFile2 := filepath.Join(testFolder, "hello2.txt") err = ioutil.WriteFile(testFile2, []byte("hello-world-2"), 0777) nilOrPanic(err, "Failed to create testFile2: ", testFile2) debug(" - meta.ListFolder") files, err := meta.ListFolder(f.Path()) nilOrPanic(err, "ListFolder failed, err: ", err) assert(len(files) == 2, "Expected 2 files") assert(files[0] == testFile || files[1] == testFile, "Expected testFile") assert(files[0] == testFile2 || files[1] == testFile2, "Expected testFile2") //////////////////// debug("### Test meta.ListFolder (missing folder)") files, err = meta.ListFolder(filepath.Join(f.Path(), "no-such-folder")) assert(files == nil, "Expected files == nil, we hopefully have an error") assert(err == engines.ErrResourceNotFound, "Expected ErrResourceNotFound") //////////////////// debug("### Test meta.ListFolder (empty folder)") emptyFolder := filepath.Join(f.Path(), "empty-folder") err = os.Mkdir(emptyFolder, 0777) nilOrPanic(err, "Failed to create empty-folder/") files, err = meta.ListFolder(emptyFolder) assert(len(files) == 0, "Expected zero files") assert(err == nil, "Didn't expect any error") //////////////////// testShellHello(meta) testShellCat(meta) testShellCatStdErr(meta) }
func (cmd) Execute(arguments map[string]interface{}) bool { // Read arguments imageFile := arguments["<image>"].(string) command := arguments["<command>"].([]string) vnc := arguments["--vnc"].(bool) // Create temporary storage and environment storage, err := runtime.NewTemporaryStorage(os.TempDir()) if err != nil { panic("Failed to create TemporaryStorage") } environment := &runtime.Environment{ TemporaryStorage: storage, } // Create a temporary folder tempFolder := filepath.Join("/tmp", slugid.Nice()) if err = os.Mkdir(tempFolder, 0777); err != nil { log.Fatal("Failed to create temporary folder in /tmp, error: ", err) } // Create the necessary runtime setup gc := &gc.GarbageCollector{} logger, _ := runtime.CreateLogger("info") log := logger.WithField("component", "qemu-run") // Create image manager log.Info("Creating image manager") manager, err := image.NewManager(filepath.Join(tempFolder, "/images/"), gc, logger.WithField("component", "image-manager"), nil) if err != nil { log.Fatal("Failed to create image manager", err) } // Get an instance of the image log.Info("Creating instance of image") image, err := manager.Instance("image", func(target string) error { return cp.CopyFile(target, imageFile) }) if err != nil { log.Fatal("Failed to create instance of image, error: ", err) } // Setup a user-space network log.Info("Creating user-space network") net, err := network.NewUserNetwork(tempFolder) if err != nil { log.Fatal("Failed to create user-space network, error: ", err) } // Create virtual machine log.Info("Creating virtual machine") vm, err := vm.NewVirtualMachine( image.Machine().Options(), image, net, tempFolder, "", "", logger.WithField("component", "vm"), ) if err != nil { log.Fatal("Failed to create virtual-machine, error: ", err) } // Create meta-data service log.Info("Creating meta-data service") var shellServer *interactive.ShellServer var displayServer *interactive.DisplayServer ms := metaservice.New(command, make(map[string]string), os.Stdout, func(result bool) { fmt.Println("### Task Completed, result = ", result) shellServer.WaitAndClose() displayServer.Abort() vm.Kill() }, environment) // Setup http handler for network vm.SetHTTPHandler(ms) // Create ShellServer shellServer = interactive.NewShellServer( ms.ExecShell, log.WithField("component", "shell-server"), ) // Create displayServer displayServer = interactive.NewDisplayServer( &socketDisplayProvider{socket: vm.VNCSocket()}, log.WithField("component", "display-server"), ) interactiveHandler := http.NewServeMux() interactiveHandler.Handle("/shell/", shellServer) interactiveHandler.Handle("/display/", displayServer) interactiveServer := graceful.Server{ Timeout: 30 * time.Second, Server: &http.Server{ Addr: "localhost:8080", Handler: interactiveHandler, }, NoSignalHandling: true, } go interactiveServer.ListenAndServe() // Start the virtual machine log.Info("Start the virtual machine") vm.Start() // Start vncviewer done := make(chan struct{}) if vnc { go StartVNCViewer(vm.VNCSocket(), done) } // Wait for SIGINT/SIGKILL or vm.Done c := make(chan os.Signal, 2) signal.Notify(c, os.Interrupt, os.Kill) // This pattern leaks, acceptable here select { case <-c: signal.Stop(c) fmt.Println("### Terminating QEMU") vm.Kill() case <-vm.Done: fmt.Println("### QEMU terminated") } close(done) // Ensure that QEMU has terminated before we continue <-vm.Done interactiveServer.Stop(100 * time.Millisecond) // Clean up anything left in the garbage collector gc.CollectAll() return true }
func TestGuestToolsLiveLog(t *testing.T) { nowReady := sync.WaitGroup{} nowReady.Add(1) ps := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { debug("Waiting for ready-now to be readable in log") nowReady.Wait() debug("replying: request-ok") w.WriteHeader(http.StatusOK) w.Write([]byte("request-ok")) })) // Create temporary storage storage, err := runtime.NewTemporaryStorage(os.TempDir()) if err != nil { panic("Failed to create TemporaryStorage") } environment := &runtime.Environment{ TemporaryStorage: storage, } // Setup a new MetaService reader, writer := io.Pipe() result := false resolved := false m := sync.Mutex{} s := metaservice.New([]string{"sh", "-c", "echo \"$TEST_TEXT\" && curl -s " + ps.URL}, map[string]string{ "TEST_TEXT": "ready-now", }, writer, func(r bool) { m.Lock() defer m.Unlock() if resolved { panic("It shouldn't be possible to resolve twice") } resolved = true result = r }, environment) // Create http server for testing ts := httptest.NewServer(s) defer ts.Close() u, err := url.Parse(ts.URL) if err != nil { panic("Expected a url we can parse") } // Create a logger logger, _ := runtime.CreateLogger("info") log := logger.WithField("component", "guest-tools-tests") // Wait for logTask := bytes.NewBuffer(nil) logDone := sync.WaitGroup{} logDone.Add(1) go func() { b := make([]byte, 1) for !strings.Contains(logTask.String(), "ready-now") { n, err := reader.Read(b) logTask.Write(b[:n]) if err != nil { panic("Unexpected error") } } nowReady.Done() io.Copy(logTask, reader) logDone.Done() }() // Create an run guest-tools g := new(u.Host, log) g.Run() writer.Close() logDone.Wait() // Check the state if !resolved { t.Error("Expected the metadata to have resolved the task") } if result != true { t.Error("Expected the metadata to get successful result") } if !strings.Contains(logTask.String(), "request-ok") { t.Error("Got unexpected taskLog: '", logTask.String(), "'") } }