github.com/yasker/longhorn-engine@v0.0.0-20160621014712-6ed6cfca0729/sync/agent/process.go (about) 1 package agent 2 3 import ( 4 "bytes" 5 "errors" 6 "fmt" 7 "net/http" 8 "os" 9 "os/exec" 10 "strconv" 11 "sync" 12 "syscall" 13 14 "github.com/Sirupsen/logrus" 15 "github.com/docker/docker/pkg/reexec" 16 "github.com/gorilla/mux" 17 "github.com/rancher/go-rancher/api" 18 "github.com/rancher/go-rancher/client" 19 ) 20 21 type Server struct { 22 sync.Mutex 23 24 processCounter int 25 currentPort int 26 startPort, endPort int 27 nextProcess int 28 processes map[string]*Process 29 processesByPort map[int]*Process 30 } 31 32 func NewServer(start, end int) *Server { 33 return &Server{ 34 currentPort: start, 35 startPort: start, 36 endPort: end, 37 processes: map[string]*Process{}, 38 processesByPort: map[int]*Process{}, 39 } 40 } 41 42 func (s *Server) ListProcesses(rw http.ResponseWriter, req *http.Request) error { 43 apiContext := api.GetApiContext(req) 44 resp := ProcessCollection{ 45 Collection: client.Collection{ 46 ResourceType: "process", 47 }, 48 } 49 50 s.Lock() 51 for _, p := range s.processes { 52 resp.Data = append(resp.Data, *p) 53 } 54 s.Unlock() 55 56 apiContext.Write(&resp) 57 return nil 58 } 59 60 func (s *Server) GetProcess(rw http.ResponseWriter, req *http.Request) error { 61 apiContext := api.GetApiContext(req) 62 id := mux.Vars(req)["id"] 63 64 s.Lock() 65 p, ok := s.processes[id] 66 s.Unlock() 67 68 if ok { 69 apiContext.Write(&p) 70 } else { 71 rw.WriteHeader(http.StatusNotFound) 72 } 73 74 return nil 75 } 76 77 func (s *Server) CreateProcess(rw http.ResponseWriter, req *http.Request) error { 78 var p Process 79 apiContext := api.GetApiContext(req) 80 if err := apiContext.Read(&p); err != nil { 81 return err 82 } 83 84 s.Lock() 85 86 if p.SrcFile == "" { 87 var err error 88 p.Port, err = s.nextPort() 89 if err != nil { 90 s.Unlock() 91 return err 92 } 93 } 94 95 s.processCounter++ 96 id := strconv.Itoa(s.processCounter) 97 p.Id = id 98 p.Type = "process" 99 s.processes[p.Id] = &p 100 s.processesByPort[p.Port] = &p 101 102 s.Unlock() 103 104 p.ExitCode = -2 105 go func() { 106 if err := s.launch(&p); err != nil { 107 logrus.Errorf("Failed to launch %#v: %v", p, err) 108 } 109 s.Lock() 110 delete(s.processesByPort, p.Port) 111 s.Unlock() 112 }() 113 114 apiContext.Write(&p) 115 return nil 116 } 117 118 func (s *Server) launch(p *Process) error { 119 switch p.ProcessType { 120 case "sync": 121 return s.launchSync(p) 122 case "fold": 123 return s.launchFold(p) 124 case "backup": 125 return s.launchBackup(p) 126 case "rmbackup": 127 return s.launchRmBackup(p) 128 case "restore": 129 return s.launchRestore(p) 130 case "inspectbackup": 131 return s.launchInspectBackup(p) 132 case "hardlink": 133 return s.launchHardLink(p) 134 } 135 return fmt.Errorf("Unknown process type %s", p.ProcessType) 136 } 137 138 func (s *Server) launchFold(p *Process) error { 139 cmd := reexec.Command("sfold", p.SrcFile, p.DestFile) 140 cmd.SysProcAttr = &syscall.SysProcAttr{ 141 Pdeathsig: syscall.SIGKILL, 142 } 143 cmd.Stdout = os.Stdout 144 cmd.Stderr = os.Stderr 145 if err := cmd.Start(); err != nil { 146 return err 147 } 148 149 logrus.Infof("Running %s %v", cmd.Path, cmd.Args) 150 err := cmd.Wait() 151 if err != nil { 152 logrus.Infof("Error running %s %v: %v", "sfold", cmd.Args, err) 153 p.ExitCode = 1 154 if exitError, ok := err.(*exec.ExitError); ok { 155 if waitStatus, ok := exitError.Sys().(syscall.WaitStatus); ok { 156 logrus.Infof("Error running %s %v: %v", "sfold", cmd.Args, waitStatus.ExitStatus()) 157 p.ExitCode = waitStatus.ExitStatus() 158 } 159 } 160 return err 161 } 162 163 p.ExitCode = 0 164 logrus.Infof("Done running %s %v", "sfold", cmd.Args) 165 return nil 166 } 167 168 func binName() (string, error) { 169 if _, err := os.Stat(os.Args[0]); err == nil { 170 return os.Args[0], nil 171 } 172 return exec.LookPath(os.Args[0]) 173 } 174 175 func (s *Server) launchSync(p *Process) error { 176 args := []string{"ssync"} 177 if p.Host != "" { 178 args = append(args, "-host", p.Host) 179 } 180 if p.Port != 0 { 181 args = append(args, "-port", strconv.Itoa(p.Port)) 182 } 183 if p.SrcFile == "" { 184 args = append(args, "-daemon") 185 } else { 186 args = append(args, p.SrcFile) 187 if p.DestFile != "" { 188 args = append(args, p.DestFile) 189 } 190 } 191 192 cmd := reexec.Command(args...) 193 cmd.SysProcAttr = &syscall.SysProcAttr{ 194 Pdeathsig: syscall.SIGKILL, 195 } 196 cmd.Stdout = os.Stdout 197 cmd.Stderr = os.Stderr 198 if err := cmd.Start(); err != nil { 199 return err 200 } 201 202 logrus.Infof("Running %s %v", "ssync", args) 203 err := cmd.Wait() 204 if err != nil { 205 logrus.Infof("Error running %s %v: %v", "ssync", args, err) 206 p.ExitCode = 1 207 if exitError, ok := err.(*exec.ExitError); ok { 208 if waitStatus, ok := exitError.Sys().(syscall.WaitStatus); ok { 209 logrus.Infof("Error running %s %v: %v", "ssync", args, waitStatus.ExitStatus()) 210 p.ExitCode = waitStatus.ExitStatus() 211 } 212 } 213 return err 214 } 215 216 p.ExitCode = 0 217 logrus.Infof("Done running %s %v", "ssync", args) 218 return nil 219 } 220 221 func (s *Server) nextPort() (int, error) { 222 // Must be called with s.Lock() obtained 223 for i := 0; i < (s.endPort - s.startPort + 1); i++ { 224 port := s.currentPort 225 s.currentPort++ 226 if s.currentPort > s.endPort { 227 s.currentPort = s.startPort 228 } 229 230 if _, ok := s.processesByPort[port]; ok { 231 continue 232 } 233 234 return port, nil 235 } 236 237 return 0, errors.New("Out of ports") 238 } 239 240 func (s *Server) launchBackup(p *Process) error { 241 buf := new(bytes.Buffer) 242 243 cmd := reexec.Command("sbackup", "create", p.SrcFile, "--dest", p.DestFile, 244 "--volume", p.Host) 245 cmd.SysProcAttr = &syscall.SysProcAttr{ 246 Pdeathsig: syscall.SIGKILL, 247 } 248 cmd.Stdout = buf 249 cmd.Stderr = os.Stdout 250 if err := cmd.Start(); err != nil { 251 return err 252 } 253 254 logrus.Infof("Running %s %v", cmd.Path, cmd.Args) 255 err := cmd.Wait() 256 257 p.Output = buf.String() 258 fmt.Fprintf(os.Stdout, p.Output) 259 if err != nil { 260 logrus.Infof("Error running %s %v: %v", "sbackup", cmd.Args, err) 261 p.ExitCode = 1 262 if exitError, ok := err.(*exec.ExitError); ok { 263 if waitStatus, ok := exitError.Sys().(syscall.WaitStatus); ok { 264 logrus.Infof("Error running %s %v: %v", "sbackup", cmd.Args, waitStatus.ExitStatus()) 265 p.ExitCode = waitStatus.ExitStatus() 266 } 267 } 268 return err 269 } 270 271 p.ExitCode = 0 272 logrus.Infof("Done running %s %v, returns %v", "sbackup", cmd.Args, p.Output) 273 return nil 274 } 275 276 func (s *Server) launchRmBackup(p *Process) error { 277 buf := new(bytes.Buffer) 278 279 cmd := reexec.Command("sbackup", "delete", p.SrcFile) 280 cmd.SysProcAttr = &syscall.SysProcAttr{ 281 Pdeathsig: syscall.SIGKILL, 282 } 283 cmd.Stdout = buf 284 cmd.Stderr = os.Stdout 285 if err := cmd.Start(); err != nil { 286 return err 287 } 288 289 logrus.Infof("Running %s %v", cmd.Path, cmd.Args) 290 err := cmd.Wait() 291 292 p.Output = buf.String() 293 fmt.Fprintf(os.Stdout, p.Output) 294 if err != nil { 295 logrus.Infof("Error running %s %v: %v", "sbackup", cmd.Args, err) 296 p.ExitCode = 1 297 if exitError, ok := err.(*exec.ExitError); ok { 298 if waitStatus, ok := exitError.Sys().(syscall.WaitStatus); ok { 299 logrus.Infof("Error running %s %v: %v", "sbackup", cmd.Args, waitStatus.ExitStatus()) 300 p.ExitCode = waitStatus.ExitStatus() 301 } 302 } 303 return err 304 } 305 306 p.ExitCode = 0 307 logrus.Infof("Done running %s %v", "sbackup", cmd.Args) 308 return nil 309 } 310 311 func (s *Server) launchRestore(p *Process) error { 312 buf := new(bytes.Buffer) 313 314 cmd := reexec.Command("sbackup", "restore", p.SrcFile, "--to", p.DestFile) 315 cmd.SysProcAttr = &syscall.SysProcAttr{ 316 Pdeathsig: syscall.SIGKILL, 317 } 318 cmd.Stdout = buf 319 cmd.Stderr = os.Stderr 320 if err := cmd.Start(); err != nil { 321 return err 322 } 323 324 logrus.Infof("Running %s %v", cmd.Path, cmd.Args) 325 err := cmd.Wait() 326 327 p.Output = buf.String() 328 fmt.Fprintf(os.Stdout, p.Output) 329 if err != nil { 330 logrus.Infof("Error running %s %v: %v", "sbackup", cmd.Args, err) 331 p.ExitCode = 1 332 if exitError, ok := err.(*exec.ExitError); ok { 333 if waitStatus, ok := exitError.Sys().(syscall.WaitStatus); ok { 334 logrus.Infof("Error running %s %v: %v", "sbackup", cmd.Args, waitStatus.ExitStatus()) 335 p.ExitCode = waitStatus.ExitStatus() 336 } 337 } 338 return err 339 } 340 341 p.ExitCode = 0 342 logrus.Infof("Done running %s %v", "sbackup", cmd.Args) 343 return nil 344 } 345 346 func (s *Server) launchHardLink(p *Process) error { 347 oldName := p.SrcFile 348 newName := p.DestFile 349 350 if oldName == "" { 351 p.ExitCode = 0 352 return nil 353 } 354 355 if _, err := os.Stat(newName); err == nil { 356 logrus.Infof("Old file %s exists, deleting", newName) 357 if err := os.Remove(newName); err != nil { 358 p.ExitCode = 1 359 return err 360 } 361 } 362 363 if err := os.Link(oldName, newName); err != nil { 364 p.ExitCode = 1 365 return err 366 } 367 368 p.ExitCode = 0 369 logrus.Infof("Done running %s %v %v", "hardlink", oldName, newName) 370 return nil 371 } 372 373 func (s *Server) launchInspectBackup(p *Process) error { 374 buf := new(bytes.Buffer) 375 376 cmd := reexec.Command("sbackup", "inspect", p.SrcFile) 377 cmd.SysProcAttr = &syscall.SysProcAttr{ 378 Pdeathsig: syscall.SIGKILL, 379 } 380 cmd.Stdout = buf 381 cmd.Stderr = os.Stderr 382 if err := cmd.Start(); err != nil { 383 return err 384 } 385 386 logrus.Infof("Running %s %v", cmd.Path, cmd.Args) 387 err := cmd.Wait() 388 389 p.Output = buf.String() 390 fmt.Fprintf(os.Stdout, p.Output) 391 if err != nil { 392 logrus.Infof("Error running %s %v: %v", "sbackup", cmd.Args, err) 393 p.ExitCode = 1 394 if exitError, ok := err.(*exec.ExitError); ok { 395 if waitStatus, ok := exitError.Sys().(syscall.WaitStatus); ok { 396 logrus.Infof("Error running %s %v: %v", "sbackup", cmd.Args, waitStatus.ExitStatus()) 397 p.ExitCode = waitStatus.ExitStatus() 398 } 399 } 400 return err 401 } 402 403 p.ExitCode = 0 404 logrus.Infof("Done running %s %v", "sbackup", cmd.Args) 405 return nil 406 }