// request wraps HTTP requests to the postmaster server. It is used internally // by other functions to make various API requests. It uses a request object and // a pointer to an empty repsonse object from the api package. func (client *Client) request(endpoint string, req interface{}, res interface{}) error { hClient, err := client.getHttpClient() if err != nil { return err } http.DefaultClient.Timeout = 0 requestBytes, err := json.Marshal(req) url := fmt.Sprintf("http://%s/%s", client.Host, endpoint) reader := bytes.NewReader(requestBytes) resp, err := hClient.Post(url, "application/json", reader) if err != nil { return err } responseData, _ := ioutil.ReadAll(resp.Body) if client.ShowRequests == true { fmt.Printf("URL: %s\nRequest: %s\nResponse: %s\n", url, string(requestBytes), string(responseData)) } if resp.StatusCode == 404 { return errors.New("API endpoint not found") } if resp.StatusCode == 426 { log.Warn("Server version does not match") } if resp.StatusCode != 200 { var errorResponse api.ApiError json.Unmarshal(responseData, &errorResponse) return errors.New(errorResponse.Error) } return json.Unmarshal(responseData, &res) }
// Start loads the web server and begins listening. func Start(addr string) error { if serverRunning == true { return nil } if mailbox.DB == nil { mailbox.OpenDB() if _, err := os.Stat("mailboxes.db"); os.IsNotExist(err) { err := mailbox.CreateDB() if err != nil { panic(err) } } } cleanupTicker := time.Tick(1 * time.Hour) go func() { for { select { case <-cleanupTicker: err := cleanupFiles() if err != nil { log.Warn(err.Error()) } } } }() endpoints := EndPointHandler{} svr := &http.Server{ Addr: addr, ReadTimeout: 12 * time.Minute, WriteTimeout: 12 * time.Minute, } endpoints.Add("GET", `/upgrade`, sendConduitBinary) endpoints.Add("POST", `/get`, getMessage) endpoints.Add("POST", "/put", putMessage) endpoints.Add("POST", "/stats/clients", clientStats) endpoints.Add("POST", "/stats", systemStats) endpoints.Add("POST", "/delete", deleteMessage) endpoints.Add("POST", "/deploy/list", deployInfo) endpoints.Add("POST", "/deploy/respond", deployRespond) endpoints.Add("POST", "/register", register) endpoints.Add("POST", "/deregister", deregister) endpoints.Add("POST", "/upload", acceptFile) endpoints.Add("POST", "/checkfile", checkfile) endpoints.Add("POST", "/asset", getAsset) http.Handle("/", &endpoints) serverRunning = true err := svr.ListenAndServe() return err }
func cleanupFiles() error { files, _ := ioutil.ReadDir(filesPath()) for _, f := range files { pending, err := mailbox.AssetPending(f.Name()) if err == nil && !pending { log.Infof("Cleaning up file %s", f.Name()) err := os.Remove(filepath.Join(filesPath(), f.Name())) if err != nil { log.Warn("File clenaup " + err.Error()) } } else if err != nil { return err } else { if time.Since(f.ModTime()) > 720*time.Hour { err := os.Remove(filepath.Join(filesPath(), f.Name())) if err != nil { log.Warn("File clenaup " + err.Error()) } } } } return nil }
func runClient(noLoop bool) { viper.SetDefault("script_timeout", 300) log.LogFile = true if viper.GetBool("master.enabled") { log.Info("Launching master server") go runProxy() } log.Info("Waiting for messages...") client, _ := ClientFromConfig() if viper.IsSet("master.host") { client.UseProxy = true client.ProxyAddress = "http://" + viper.GetString("master.host") } var persistantScripts = []*engine.ScriptEngine{} if viper.IsSet("agents") { engine.Agents = viper.GetStringMapString("agents") engine.AgentAccessKey = viper.GetString("access_key") } // Begin polling cycle for { time.Sleep(time.Duration(rand.Intn(1000)+2000) * time.Millisecond) resp, err := client.Get() // If an error is returned by the client we will begin an exponential back // off in retrying. The backoff caps out at 15 retries. if err != nil { log.Error("Error getting messages: " + err.Error()) if errorCount < 15 { errorCount++ } expBackoff := int(math.Pow(float64(errorCount), 2)) displacement := rand.Intn(errorCount + 1) sleepTime := expBackoff + displacement time.Sleep(time.Duration(sleepTime) * time.Second) continue } // A response was received but it might be an empty response from the // server timing out the long poll. errorCount = 0 if resp.Body != "" { log.Infof("Script receieved (%s)", resp.Message) eng := engine.New() eng.Constant("DEPLOYMENT_ID", resp.Deployment) eng.Constant("SCRIPT_ID", resp.Message) persistant, _ := eng.GetVar("$persistant", resp.Body) if p, ok := persistant.(bool); ok { if p { persistantScripts = append(persistantScripts, eng) } } if resp.Asset != "" { assetPath, err := client.DownloadAsset(resp.Asset) if err != nil { client.Respond(resp.Message, "Could not download asset", true) log.Error("Could not download asset") _, err = client.Delete(resp.Message) continue } else { log.Infof("Downloaded asset to %s", assetPath) } eng.SetAsset(assetPath) } executionStartTime := time.Now() errChan := make(chan string, 1) timeoutSeconds := viper.GetInt("script_timeout") go func() { err = eng.Execute(resp.Body) if err != nil { errChan <- err.Error() } else { errChan <- "" } }() select { case e := <-errChan: if e != "" { err = errors.New(e) } case <-time.After(time.Second * time.Duration(timeoutSeconds)): log.Warn("Timing out script") err = errors.New("Scirpt timeed out") } executionTime := time.Since(executionStartTime) log.Infof("Script executed in %s", executionTime) if err != nil { log.Error("Error executing script " + resp.Message) log.Debug(err.Error()) client.Respond(resp.Message, err.Error(), true) } _, err = client.Delete(resp.Message) if err != nil { log.Debug(err.Error()) log.Error("Could not confirm script.") } else { log.Debug("Script confirmed: " + resp.Message) } } if noLoop == true { break } } }
client, err := ClientFromConfig() if err != nil { log.Debug(err.Error()) log.Fatal("Could not configure client") } limitToken := (cmd.Flag("all").Value.String() == "false") count, _ := strconv.ParseInt(cmd.Flag("count").Value.String(), 10, 64) resp, err := client.ListDeploys(cmd.Flag("name").Value.String(), limitToken, int(count)) if err != nil { log.Debug(err.Error()) log.Error("Could not list deploys") return } if len(resp.Deployments) == 0 { log.Warn("There are no open deployments") } for _, dep := range resp.Deployments { log.Alertf("%s:", dep.Name) log.Infof(" Deployed at: %s", dep.CreatedAt.Format("01/02 03:04 PM")) log.Infof(" Deployed by: %s", dep.DeployedBy) log.Infof(" Executions: %d/%d", dep.MessageCount-dep.PendingCount, dep.MessageCount) log.Infof(" Repsonses: %d/%d", dep.ResponseCount, dep.MessageCount) } }, } func init() { deployCmd.AddCommand(listCmd)