func parse(filename string) (sshs []SshClient, err error) { var sshcli SshClient content, err := ioutil.ReadFile(filename) if err != nil { return nil, err } sshclients := strings.Split(string(content), "\n") // sshclients := sshclients[:len(sshclients) - 1] for _, v := range sshclients { if len(v) == 0 { continue } sshfields := strings.Fields(v) for i, v := range sshfields { sshfields[i] = strings.TrimSpace(v) } if len(sshfields) == 1 { sshcli.Hostaddr = sshfields[0] sshcli.Username = gUsername sshcli.Password = gPassword sshcli.Cmd = gCommand } else if len(sshfields) == 2 { sshcli.Hostaddr = sshfields[0] sshcli.Username = sshfields[1] sshcli.Password = gPassword sshcli.Cmd = gCommand } else if len(sshfields) == 3 { sshcli.Hostaddr = sshfields[0] sshcli.Username = sshfields[1] sshcli.Password = sshfields[2] sshcli.Cmd = gCommand } else if len(sshfields) >= 4 { sshcli.Hostaddr = sshfields[0] sshcli.Username = sshfields[1] sshcli.Password = sshfields[2] sshcli.Cmd = strings.Join(sshfields[3:], " ") sshcli.Cmd = helper.Abs(sshcli.Cmd) vprintf("%#v\n", sshcli.Cmd) } sshs = append(sshs, sshcli) } return }
func main() { flag.Usage = usage flag.Parse() // SetLog() // defer log4go.Close() args := flag.Args() argnums := flag.NArg() if flag.NArg() < 1 && flag.NFlag() < 1 { usage() } if argnums >= 1 { switch args[0] { case "help": usage() case "version": version() os.Exit(2) case "&", "|", "<", ">": default: if args[argnums-1] == "&" { args = args[:argnums-1] } } } var err error if *infile == "" { fmt.Println("please input your infile which included 'hostaddr username password command' one per line") usage() } else if !com.IsExist(*infile) { fmt.Printf("not found input file: %s\n", *infile) usage() } if *cfg == "" { gCfg = "./mssh.conf" } else { gCfg = *cfg } if !parseconf(gCfg) { fmt.Printf("init conf file %s failed, exit\n", *cfg) os.Exit(2) } if *cmd != "" { if len(args) > 0 { gCommand = fmt.Sprintf("%s %s", *cmd, strings.Join(args, " ")) } else { if *shellmode { curpath, _ := os.Getwd() if !strings.Contains(*cmd, "/") { *cmd = curpath + "/" + *cmd } gCommand = fmt.Sprintf("%s %s", "/bin/bash", *cmd) } else { gCommand = *cmd } } } gCommand = helper.Abs(gCommand) vprintf("gCommnad: %s\n", gCommand) vprintf("gUsername: %s\n", gUsername) vprintf("gPassword: %s\n", gPassword) vprintf("gTimeout: %v\n", gTimeout) sshobjs, err := parse(*infile) if err != nil { log.Fatal(err) } vprintf("%#v\n", sshobjs) if *n < 1 || *n > 10000 { *n = runtime.NumCPU() } cmdout, _, err := com.ExecCmd("logname") vprintf("cmdout: %s", cmdout) if err == nil { cmdout = strings.TrimSpace(cmdout) if len(gMaillist) == 0 { gMaillist = fmt.Sprintf("*****@*****.**", cmdout) } } vprintf("gMaillist: %s\n", gMaillist) // basename := filepath.Base(*cmd) var r = []byte("0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz_") randomfname := string(helper.RandomCreateBytes(32, r...)) + ".sh" vprintf("randomfname: %s\n", randomfname) chFirst := make(chan SshClient, *n) // chSecond := make(chan SshClient, *n) oldtime := time.Now() scpTout := fmt.Sprintf("ConnectTimeout=%d", gTimeout) go func() { defer close(chFirst) for i, _ := range sshobjs { if *israndompwd { sshobjs[i].Cmd = fmt.Sprintf("echo %s | passwd --stdin %s", sshobjs[i].Password, sshobjs[i].Username) vprintf("%#v\n", sshobjs[i]) } else if *shellmode { com.ExecCmd("scp", "-o", scpTout, "-o", "BatchMode=yes", "-r", *cmd, fmt.Sprintf("%s:/tmp/%s", helper.GetHost(sshobjs[i].Hostaddr, ":"), randomfname)) sshobjs[i].Cmd = fmt.Sprintf("/bin/bash /tmp/%s && /bin/rm -f /tmp/%s", randomfname, randomfname) vprintf("%#v\n", sshobjs[i]) } chFirst <- sshobjs[i] } }() wg1 := new(sync.WaitGroup) wg2 := new(sync.WaitGroup) tryslice := make([]SshClient, 0) sem := make(chan struct{}, *n) mux := new(sync.Mutex) for i := 0; i < *n; i++ { wg1.Add(1) go func(ch chan SshClient) { defer wg1.Done() for v := range ch { vprintf("%#v\n", v) func(sshitem SshClient) { err, _, stdout, _ := sshutils.SshExec(sshitem.Hostaddr, sshitem.Username, sshitem.Password, sshitem.Cmd, gTimeout) if err != nil { mux.Lock() tryslice = append(tryslice, sshitem) mux.Unlock() return } mux.Lock() cnt++ fmt.Println(strings.Repeat("*", 40), "[", cnt, "]", strings.Repeat("*", 40)) fmt.Println(fmt.Sprintf("%s:\n%s\n", sshitem.Hostaddr, stdout)) mux.Unlock() }(v) } }(chFirst) } wg1.Wait() //for /usr/bin/ssh execute shell cmds buf.WriteString("\nrunning results(error host lists):\n\n") for _, v := range tryslice { sem <- struct{}{} wg2.Add(1) go func(sshitem SshClient) { defer wg2.Done() err, _, stdout, _ := sshutils.SshCmdExec(sshitem.Hostaddr, sshitem.Username, sshitem.Password, sshitem.Cmd, gTimeout) if err != nil { log.Println("[/usr/bin/ssh]", sshitem.Hostaddr, err) // log4go.Error("[/usr/bin/ssh] %s %v", sshitem.Hostaddr, err) buf.WriteString(sshitem.Hostaddr + "\n") <-sem return } mux.Lock() cnt++ fmt.Println("[", cnt, "]", strings.Repeat("*", 80)) fmt.Println(fmt.Sprintf("%s %s:\n%s\n", "[/usr/bin/ssh]", sshitem.Hostaddr, stdout)) // log4go.Info(fmt.Sprintf("%s %s:\n%s\n", "[/usr/bin/ssh]", sshitem.Hostaddr, stdout)) mux.Unlock() <-sem }(v) } wg2.Wait() //kill ssh process which is timeout vprintf("Kill ssh for timeout\n") kill(sshutils.Cmds) errMsg := buf.String() htmlErrMsg := strings.Replace(errMsg, "\n", "<br>", -1) now := time.Now().String() title := gTitle mode := gMode execTime := time.Since(oldtime) totalTime := execTime.String() var body string if mode == "html" { body = now + "<br>" + gBody + "<br>" + htmlErrMsg + "<br>total time: " + totalTime } else { body = now + "\n" + gBody + "\n" + errMsg + "\ntotal time: " + totalTime } maillist := []string{gMaillist} config := fmt.Sprintf(`{"username":"******","password":"******","host":"%s","port":%d}`, mailUsername, mailPassword, mailHost, mailPort) mail := utils.NewEMail(config) mail.To = maillist mail.From = gFr_addr mail.Subject = title if mode == "html" { mail.HTML = body } else { mail.Text = body } if *ismail { err = mail.Send() if err != nil { log.Println("send mail failed:", err) goto LEAVE } fmt.Println("send mail successful") } LEAVE: newtime := time.Since(oldtime) fmt.Println("run time:", newtime) }