//doSend is an internal function that accepts a url and a logbuffer object that //contains LogEntry objects to be Marshalled to JSON then sent via HTTP POST //to the specified url. It returns an error if the http reqeust fails. func doSend(url string, buffer logbuffer) error { data, err := json.Marshal(buffer) if err != nil { return fmt.Errorf("HTTP Backend: unable to Marshal JSON from logbuffer struct: %s", err) } b := bytes.NewBuffer(data) err = http.Post(url, b) if err != nil { return fmt.Errorf("HTTP Backend: unable to POST to specified URL, library returned error: %s", err) } return nil }
func PostString(url string, data string) { if err := http.Post(url, strings.NewReader(data)); err != nil { log.Fatal("could not post") } }
// Main function to get build and run test. func main() { // Build with git version and build time. Print them when it starts. fmt.Println("Git version: " + GitVersion) fmt.Println("Build time: " + BuildTime) fmt.Println("Start ArchCI simple worker") dbutil.InitializeModels() log.Info("Start simple-worker") workerConfig := ParseWorkerYaml("worker.yml") // Record the worker in database. ip, _ := iputil.GetLocalIp() dbutil.AddWorker(rand.Int63(), ip, time.Now(), models.WORKER_STATUS_BUSY) // Exit if it doesn't meet the requirement. if CheckRequirement() == false { // TODO: Add more info to install requirement fmt.Println("Need some requirements, exit now") return } // Loop to pull task and run test. for { fmt.Println("Start while loop") build, err := dbutil.GetOneNotStartBuild() if err != nil { fmt.Println("No build to run test") fmt.Println("Sleep for next task") time.Sleep(time.Duration(workerConfig.Interval) * time.Second) continue } //build = models.Build{Id:1234, ProjectName: "test-project", RepoUrl: "https://github.com/tobegit3hub/test-project", Branch: "master"} fmt.Println("Build the project " + build.ProjectName) dbutil.UpdateBuildStatus(build.Id, models.BUILD_STATUS_BUILDING) // 1. Clone the code in specified directory // TODO: support user defined directory, avoid the name conflict // TODO: Support other command than "git clone" cloneCmd := exec.Command("git", "clone", build.RepoUrl) w := bytes.NewBuffer(nil) cloneCmd.Stderr = w _, err = cloneCmd.Output() if err != nil { // TODO: Don't be so easy to exit log.Warn("Error to run clone command" + err.Error()) log.Warn(string(w.Bytes())) return } fmt.Println("Success to clone the code") // 2. Parse archci.yaml file for base image and test scripts archciConfig := ParseArchciYaml(build.ProjectName + "/.archci.yml") dockerImage := archciConfig.Image // 3. Generate archci.sh to "cd", combine user scipts and redirect STDOUT to file, this file should put into user's root directory // TODO: Make sure that the archci.sh is not conflict or just rm the user's one archciShellContent := GenerateArchciShellContent(archciConfig) archciShellFile, err2 := os.OpenFile(build.ProjectName+"/archci.sh", os.O_RDWR|os.O_CREATE|os.O_EXCL, 0755) // TODO: Make it a constant if err2 != nil { panic(err2) } defer archciShellFile.Close() _, err2 = archciShellFile.WriteString(archciShellContent) if err2 != nil { panic(err2) } archciShellFile.Sync() archciShellFile.Close() fmt.Println("Success to create archci.sh") // 4. Docker run the base image and put the code into container to test // docker run --rm -v $PWD:/project golan:1.4 /project/archci.sh > docker.log 2>&1 ; echo $? > exit_code.log cpuLimit := "" // " -c 2 " memoryLimit := "" // " -m 100m " dockerCommand := "docker run --rm " + cpuLimit + memoryLimit + "-v $PWD/" + build.ProjectName + ":/project " + dockerImage + " /project/archci.sh > docker.log 2>&1 ; echo $? > exit_code.log" // TODO(tobe): Get stderr if it fails dockerCmd := exec.Command("sh", "-c", dockerCommand) dockerOut, err := dockerCmd.Output() if err != nil { fmt.Println(string(dockerOut)) os.Exit(1) } fmt.Println("Success to run " + dockerCommand) // 5. Delete the code // TODO: make it a function to call rmCmd := exec.Command("rm", "-rf", build.ProjectName) rmOut, err := rmCmd.Output() if err != nil { // TODO: Don't be so easy to exit fmt.Println(string(rmOut)) os.Exit(1) } fmt.Println("Success to delete the code") // 6. Non-block read the log and exit_code file and put them into redis fileutil.WriteFileToRedis(build.Id, "docker.log") // 7. Read exit code file and update build status exitCodeFileContent, err9 := fileutil.ReadFile("exit_code.log") if err9 != nil { fmt.Println(err9) panic(err9) } exitCode, _ := strconv.Atoi(strings.TrimSpace(exitCodeFileContent)) if exitCode == 0 { fmt.Println("Exit code is 0") dbutil.UpdateBuildStatus(build.Id, models.BUILD_STATUS_SUCCESS) } else { fmt.Println("Exit code is not 0") dbutil.UpdateBuildStatus(build.Id, models.BUILD_STATUS_FAIL) } // 9. Send POST to webhook if exitCode == 0 { for _, url := range archciConfig.Webhook.Success { log.Debug("Trigger webhook to send POST to " + url) err = http.Post(url, strings.NewReader("{build: success}")) if err != nil { log.Fatal("Could not send post request") fmt.Println(err) } } } else { for _, url := range archciConfig.Webhook.Failure { log.Debug("Trigger webhook to send POST to " + url) err = http.Post(url, strings.NewReader("{build: failure}")) if err != nil { log.Fatal("Could not send post request") fmt.Println(err) } } } // Sleep for next task fmt.Println("Sleep for next task") time.Sleep(time.Duration(workerConfig.Interval) * time.Second) } fmt.Println("Simple worker exists") }