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 }