github.com/yasker/longhorn-engine@v0.0.0-20160621014712-6ed6cfca0729/app/replica.go (about)

     1  package app
     2  
     3  import (
     4  	"errors"
     5  	"net/http"
     6  	"os"
     7  	"os/exec"
     8  	"path/filepath"
     9  	"syscall"
    10  
    11  	"github.com/Sirupsen/logrus"
    12  	"github.com/codegangsta/cli"
    13  	"github.com/docker/go-units"
    14  	"github.com/rancher/longhorn/replica"
    15  	"github.com/rancher/longhorn/replica/rest"
    16  	"github.com/rancher/longhorn/replica/rpc"
    17  	"github.com/rancher/longhorn/util"
    18  )
    19  
    20  func ReplicaCmd() cli.Command {
    21  	return cli.Command{
    22  		Name:      "replica",
    23  		UsageText: "longhorn controller DIRECTORY SIZE",
    24  		Flags: []cli.Flag{
    25  			cli.StringFlag{
    26  				Name:  "listen",
    27  				Value: "localhost:9502",
    28  			},
    29  			cli.StringFlag{
    30  				Name:  "backing-file",
    31  				Usage: "qcow file to use as the base image of this disk",
    32  			},
    33  			cli.BoolTFlag{
    34  				Name: "sync-agent",
    35  			},
    36  			cli.StringFlag{
    37  				Name:  "size",
    38  				Usage: "Volume size in bytes or human readable 42kb, 42mb, 42gb",
    39  			},
    40  		},
    41  		Action: func(c *cli.Context) {
    42  			if err := startReplica(c); err != nil {
    43  				logrus.Fatalf("Error running start replica command: %v", err)
    44  			}
    45  		},
    46  	}
    47  }
    48  
    49  func startReplica(c *cli.Context) error {
    50  	if c.NArg() != 1 {
    51  		return errors.New("directory name is required")
    52  	}
    53  
    54  	dir := c.Args()[0]
    55  	backingFile, err := openBackingFile(c.String("backing-file"))
    56  	if err != nil {
    57  		return err
    58  	}
    59  
    60  	s := replica.NewServer(dir, backingFile, 512)
    61  
    62  	address := c.String("listen")
    63  	size := c.String("size")
    64  	if size != "" {
    65  		size, err := units.RAMInBytes(size)
    66  		if err != nil {
    67  			return err
    68  		}
    69  
    70  		if err := s.Create(size); err != nil {
    71  			return err
    72  		}
    73  	}
    74  
    75  	controlAddress, dataAddress, syncAddress, err := util.ParseAddresses(address)
    76  	if err != nil {
    77  		return err
    78  	}
    79  
    80  	resp := make(chan error)
    81  
    82  	go func() {
    83  		server := rest.NewServer(s)
    84  		router := http.Handler(rest.NewRouter(server))
    85  		router = util.FilteredLoggingHandler(map[string]struct{}{
    86  			"/ping":          struct{}{},
    87  			"/v1/replicas/1": struct{}{},
    88  		}, os.Stdout, router)
    89  		logrus.Infof("Listening on control %s", controlAddress)
    90  		resp <- http.ListenAndServe(controlAddress, router)
    91  	}()
    92  
    93  	go func() {
    94  		rpcServer := rpc.New(dataAddress, s)
    95  		logrus.Infof("Listening on data %s", dataAddress)
    96  		resp <- rpcServer.ListenAndServe()
    97  	}()
    98  
    99  	if c.Bool("sync-agent") {
   100  		exe, err := exec.LookPath(os.Args[0])
   101  		if err != nil {
   102  			return err
   103  		}
   104  
   105  		exe, err = filepath.Abs(exe)
   106  		if err != nil {
   107  			return err
   108  		}
   109  
   110  		go func() {
   111  			cmd := exec.Command(exe, "sync-agent", "--listen", syncAddress)
   112  			cmd.SysProcAttr = &syscall.SysProcAttr{
   113  				Pdeathsig: syscall.SIGKILL,
   114  			}
   115  			cmd.Dir = dir
   116  			cmd.Stdout = os.Stdout
   117  			cmd.Stderr = os.Stderr
   118  			resp <- cmd.Run()
   119  		}()
   120  	}
   121  
   122  	return <-resp
   123  }