github.com/schwarzm/garden-linux@v0.0.0-20150507151835-33bca2147c47/integration/runner/runner.go (about)

     1  package runner
     2  
     3  import (
     4  	"fmt"
     5  	"net"
     6  	"os"
     7  	"os/exec"
     8  	"path/filepath"
     9  	"strconv"
    10  	"syscall"
    11  	"time"
    12  
    13  	"github.com/cloudfoundry-incubator/garden/client"
    14  	"github.com/cloudfoundry-incubator/garden/client/connection"
    15  	"github.com/onsi/ginkgo"
    16  	"github.com/pivotal-golang/lager"
    17  	"github.com/pivotal-golang/lager/lagertest"
    18  	"github.com/tedsuo/ifrit"
    19  	"github.com/tedsuo/ifrit/ginkgomon"
    20  )
    21  
    22  type Runner struct {
    23  	Command *exec.Cmd
    24  
    25  	network string
    26  	addr    string
    27  
    28  	bin  string
    29  	argv []string
    30  
    31  	binPath    string
    32  	rootFSPath string
    33  
    34  	tmpdir    string
    35  	graphPath string
    36  }
    37  
    38  func New(network, addr string, bin, binPath, rootFSPath, graphPath string, argv ...string) *Runner {
    39  	tmpDir := filepath.Join(
    40  		os.TempDir(),
    41  		fmt.Sprintf("test-garden-%d", ginkgo.GinkgoParallelNode()),
    42  	)
    43  
    44  	if graphPath == "" {
    45  		graphPath = filepath.Join(tmpDir, "graph")
    46  	}
    47  
    48  	return &Runner{
    49  		network: network,
    50  		addr:    addr,
    51  
    52  		bin:  bin,
    53  		argv: argv,
    54  
    55  		binPath:    binPath,
    56  		rootFSPath: rootFSPath,
    57  		graphPath:  graphPath,
    58  		tmpdir:     tmpDir,
    59  	}
    60  }
    61  
    62  func (r *Runner) Run(signals <-chan os.Signal, ready chan<- struct{}) error {
    63  	logger := lagertest.NewTestLogger("garden-runner")
    64  
    65  	err := os.MkdirAll(r.tmpdir, 0755)
    66  	if err != nil {
    67  		return err
    68  	}
    69  
    70  	depotPath := filepath.Join(r.tmpdir, "containers")
    71  	overlaysPath := filepath.Join(r.tmpdir, "overlays")
    72  	snapshotsPath := filepath.Join(r.tmpdir, "snapshots")
    73  
    74  	if err := os.MkdirAll(depotPath, 0755); err != nil {
    75  		return err
    76  	}
    77  
    78  	if err := os.MkdirAll(snapshotsPath, 0755); err != nil {
    79  		return err
    80  	}
    81  
    82  	MustMountTmpfs(overlaysPath)
    83  	MustMountTmpfs(r.graphPath)
    84  
    85  	var appendDefaultFlag = func(ar []string, key, value string) []string {
    86  		for _, a := range r.argv {
    87  			if a == key {
    88  				return ar
    89  			}
    90  		}
    91  
    92  		if value != "" {
    93  			return append(ar, key, value)
    94  		} else {
    95  			return append(ar, key)
    96  		}
    97  	}
    98  
    99  	gardenArgs := make([]string, len(r.argv))
   100  	copy(gardenArgs, r.argv)
   101  
   102  	gardenArgs = appendDefaultFlag(gardenArgs, "--listenNetwork", r.network)
   103  	gardenArgs = appendDefaultFlag(gardenArgs, "--listenAddr", r.addr)
   104  	gardenArgs = appendDefaultFlag(gardenArgs, "--bin", r.binPath)
   105  	if r.rootFSPath != "" { //rootfs is an optional parameter
   106  		gardenArgs = appendDefaultFlag(gardenArgs, "--rootfs", r.rootFSPath)
   107  	}
   108  	gardenArgs = appendDefaultFlag(gardenArgs, "--depot", depotPath)
   109  	gardenArgs = appendDefaultFlag(gardenArgs, "--overlays", overlaysPath)
   110  	gardenArgs = appendDefaultFlag(gardenArgs, "--snapshots", snapshotsPath)
   111  	gardenArgs = appendDefaultFlag(gardenArgs, "--graph", r.graphPath)
   112  	gardenArgs = appendDefaultFlag(gardenArgs, "--logLevel", "debug")
   113  	gardenArgs = appendDefaultFlag(gardenArgs, "--disableQuotas", "")
   114  	gardenArgs = appendDefaultFlag(gardenArgs, "--networkPool", fmt.Sprintf("10.250.%d.0/24", ginkgo.GinkgoParallelNode()))
   115  	gardenArgs = appendDefaultFlag(gardenArgs, "--portPoolStart", strconv.Itoa(51000+(1000*ginkgo.GinkgoParallelNode())))
   116  	gardenArgs = appendDefaultFlag(gardenArgs, "--portPoolSize", "1000")
   117  	gardenArgs = appendDefaultFlag(gardenArgs, "--tag", strconv.Itoa(ginkgo.GinkgoParallelNode()))
   118  
   119  	var signal os.Signal
   120  
   121  	r.Command = exec.Command(r.bin, gardenArgs...)
   122  
   123  	process := ifrit.Invoke(&ginkgomon.Runner{
   124  		Name:              "garden-linux",
   125  		Command:           r.Command,
   126  		AnsiColorCode:     "31m",
   127  		StartCheck:        "garden-linux.started",
   128  		StartCheckTimeout: 10 * time.Second,
   129  		Cleanup: func() {
   130  			if signal == syscall.SIGQUIT {
   131  				logger.Info("cleanup-tempdirs")
   132  				if err := os.RemoveAll(r.tmpdir); err != nil {
   133  					logger.Error("cleanup-tempdirs-failed", err, lager.Data{"tmpdir": r.tmpdir})
   134  				} else {
   135  					logger.Info("tempdirs-removed")
   136  				}
   137  			}
   138  		},
   139  	})
   140  
   141  	close(ready)
   142  
   143  	for {
   144  		select {
   145  		case signal = <-signals:
   146  			// SIGQUIT means clean up the containers, the garden process (SIGTERM) and the temporary directories
   147  			// SIGKILL, SIGTERM and SIGINT are passed through to the garden process
   148  			if signal == syscall.SIGQUIT {
   149  				logger.Info("received-signal SIGQUIT")
   150  				if err := r.destroyContainers(); err != nil {
   151  					logger.Error("destroy-containers-failed", err)
   152  					return err
   153  				}
   154  				logger.Info("destroyed-containers")
   155  				process.Signal(syscall.SIGTERM)
   156  			} else {
   157  				logger.Info("received-signal", lager.Data{"signal": signal})
   158  				process.Signal(signal)
   159  			}
   160  
   161  		case waitErr := <-process.Wait():
   162  			logger.Info("process-exited")
   163  			return waitErr
   164  		}
   165  	}
   166  }
   167  
   168  func (r *Runner) TryDial() error {
   169  	conn, dialErr := net.DialTimeout(r.network, r.addr, 100*time.Millisecond)
   170  
   171  	if dialErr == nil {
   172  		conn.Close()
   173  		return nil
   174  	}
   175  
   176  	return dialErr
   177  }
   178  
   179  func (r *Runner) NewClient() client.Client {
   180  	return client.New(connection.New(r.network, r.addr))
   181  }
   182  
   183  func (r *Runner) destroyContainers() error {
   184  	client := r.NewClient()
   185  
   186  	containers, err := client.Containers(nil)
   187  	if err != nil {
   188  		return err
   189  	}
   190  
   191  	for _, container := range containers {
   192  		err := client.Destroy(container.Handle())
   193  		if err != nil {
   194  			return err
   195  		}
   196  	}
   197  
   198  	return nil
   199  }