diff --git a/.circleci/config.yml b/.circleci/config.yml index 588bde6..b25d998 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -2,7 +2,7 @@ version: 2.1 orbs: release: sharptools/release@0.0.3 - go: sharptools/go@0.0.5 + go: sharptools/go@0.0.7 workflows: diff --git a/.gitignore b/.gitignore index e7ed7ca..c59f5aa 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,4 @@ .env .vscode -__debug_bin \ No newline at end of file +__debug_bin +docker \ No newline at end of file diff --git a/.version b/.version index b6df663..63700cc 100644 --- a/.version +++ b/.version @@ -1 +1 @@ -VERSION=0.1.10 \ No newline at end of file +VERSION=0.2.0 \ No newline at end of file diff --git a/README.md b/README.md index f4e2a68..939f89e 100644 --- a/README.md +++ b/README.md @@ -1,16 +1,79 @@ [![CircleCI](https://circleci.com/gh/Sharpz7/sharpcd.svg?style=svg)](https://circleci.com/gh/Sharpz7/sharpcd) -SharpCD || Continuous Development for your server -=========== +# SharpCD || Continuous Development for your server + +![](https://files.mcaq.me/zbnf.png) + +# Example Config +```yml +version: 1 + +trak: + local: https://localhost:5666 + remote: https://mcaq.me:5666 + +tasks: + basic_task: + name: Basic + type: docker + sharpurl: https://localhost:5666 + giturl: https://raw.githubusercontent.com/Sharpz7/ + compose: /sharpcd/dev/testing/basic.yml + + registry_task: + name: Registry + type: docker + registry: docker.mcaq.me + envfile: .env + sharpurl: https://localhost:5666 + giturl: https://raw.githubusercontent.com/Sharpz7/ + compose: /sharpcd/dev/testing/registry.yml + + env_task: + name: Enviroment Test Fail + type: docker + envfile: .env + sharpurl: https://localhost:5666 + giturl: https://raw.githubusercontent.com/Sharpz7/ + compose: /sharpcd/dev/testing/env.yml +``` + +# Installation +On linux, just run: +```console +╭─adam@box ~/ +╰─➤ sudo curl -s -L https://github.com/Sharpz7/sharpcd/releases/download/0.2.0/install.sh | sudo bash +``` + +## Command Options -Installation -=========== On linux, just run: ```console -adam@console~$ sudo curl -s -L https://github.com/Sharpz7/sharpcd/releases/download/0.1.10/install.sh | sudo bash +╭─adam@box ~/ +╰─➤ sharpcd help + +Args of SharpCD: + + - server: Run the sharpcd server + - setsecret: Set the secret for API and Task Calls + - addfilter: Add a url for a compose file + - changetoken: Add a token for private github repos + - removefilter: Remove a url for a compose file + - version: Returns the Current Version + - trak: Run the Trak program + +Sub Command Trak: + + - alljobs {type}: Get info on all jobs + - job {type} {id}: Get info on job with logging + - list {type}: Get all jobs running on sharpcd server + +Flags: + + -secret string + Put secret as a arg for automation tasks ``` -Maintainers and Developers -========== +## Maintainers -- Sharp / [@Sharpz7](https://github.com/Sharpz7) \ No newline at end of file +- [Adam McArthur](https://adam.mcaq.me) \ No newline at end of file diff --git a/gopack.yml b/gopack.yml index 77330c3..7218107 100644 --- a/gopack.yml +++ b/gopack.yml @@ -5,5 +5,10 @@ packages: - github.com/joho/godotenv - golang.org/x/term - github.com/hashicorp/go-version +- github.com/gosuri/uilive +- github.com/gizak/termui +- github.com/common-nighthawk/go-figure +- github.com/gorilla/websocket + devpackages: - golang.org/x/sys/unix diff --git a/internal/sharpcd-data/logs/.gitignore b/internal/sharpcd-data/logs/.gitignore deleted file mode 100644 index c96a04f..0000000 --- a/internal/sharpcd-data/logs/.gitignore +++ /dev/null @@ -1,2 +0,0 @@ -* -!.gitignore \ No newline at end of file diff --git a/sharpcd.yml b/sharpcd.yml index 984220a..9abc79d 100644 --- a/sharpcd.yml +++ b/sharpcd.yml @@ -1,5 +1,9 @@ version: 1 +trak: + local: https://localhost:5666 + remote: https://mcaq.me:5666 + tasks: basic_task: name: Basic @@ -47,16 +51,16 @@ tasks: giturl: https://raw.githubusercontent.com/Sharpz7/ compose: /sharpcd/dev/testing/basic - Delayed_task: - name: Delayed stop + restart_task: + name: Test Log exit type: docker sharpurl: https://localhost:5666 giturl: https://raw.githubusercontent.com/Sharpz7/ - compose: /sharpcd/dev/testing/delayed.yml + compose: /sharpcd/dev/testing/restart.yml - Restart_task: - name: Test Log exit + trak_task: + name: Trak Log Test type: docker sharpurl: https://localhost:5666 giturl: https://raw.githubusercontent.com/Sharpz7/ - compose: /sharpcd/dev/testing/restart.yml \ No newline at end of file + compose: /sharpcd/dev/testing/trak.yml \ No newline at end of file diff --git a/sharpdev.yml b/sharpdev.yml index 0780839..02f2e6b 100644 --- a/sharpdev.yml +++ b/sharpdev.yml @@ -9,17 +9,19 @@ scripts: build: | go build -o ./internal/sharpcd ./src - revert: git revert $_ARG1..HEAD - list: git branch - archive: | - git tag archive/$_ARG1 $_ARG1 - git branch -d $_ARG1 + sharpcd1: | + sharpdev build + ./internal/sharpcd $_ARG1 server: | sudo apt-get install -y lsof sudo kill $(sudo lsof -t -i:5666) > /dev/null 2>&1 || true sharpdev build - sudo ./internal/sharpcd server + $(sudo ./internal/sharpcd server &) & + + kill: | + sudo apt-get install -y lsof + sudo kill $(sudo lsof -t -i:5666) > /dev/null 2>&1 || true client: | sudo docker-compose -f "./internal/sharpcd-data/docker/external_task/docker-compose.yml" down @@ -28,23 +30,37 @@ scripts: sharpdev build ./internal/sharpcd --secret $PASSD - job: curl -k -X POST -d SECRETD https://localhost:5666/api/job/$_ARG1 - logs: curl -k -X POST -d SECRETD https://localhost:5666/api/logs/$_ARG1 + trak: | + sharpdev build + ./internal/sharpcd --secret $PASSD trak $_ARG1 $_ARG2 $_ARG3 + + trakone: | + sharpdev trak job local $_ARG1 + + trakall: | + sharpdev trak alljobs local + + traklist: | + sharpdev trak list local + + filter: ./internal/sharpcd addfilter https://raw.githubusercontent.com/Sharpz7/ remove: ./internal/sharpcd removefilter https://raw.githubusercontent.com/Sharpz7/ token: ./internal/sharpcd changetoken $_ARG1 - alljobsd: curl -k -X POST -d SECRETD https://localhost:5666/api/jobs - alljobs: curl -k -X POST -d SECRET https://173.212.252.82:5666/api/jobs - - file: | - curl -H 'Authorization: token $_ARG1' \ - -H 'Accept: application/vnd.github.v3.raw' \ - -O \ - -L https://raw.githubusercontent.com/Sharpz7/stuandbob/main/docker-compose.yml test: | git checkout dev git push origin dev sharpdev client + alljobsd: curl -k -X POST -d SECRETD https://localhost:5666/api/jobs + alljobs: curl -k -X POST -d SECRET https://173.212.252.82:5666/api/jobs + logsfeed: curl -k -X POST -d SECRETD https://localhost:5666/api/logsfeed/$_ARG1 + job: curl -k -X POST -d SECRETD https://localhost:5666/api/job/$_ARG1 + logs: curl -k -X POST -d SECRETD https://localhost:5666/api/logs/$_ARG1 + logsremote: curl -k -X POST -d SECRET https://mcaq.me:5666/api/logs/$_ARG1 + + keygen: | + sudo openssl req -x509 -nodes -days 730 -newkey rsa:2048 -keyout /home/coder/code-server/go/src/sharpCD/internal/sharpcd-data/private/server.key -out /home/coder/code-server/go/src/sharpCD/internal/sharpcd-data/private/server.crt -config /home/coder/code-server/go/src/sharpCD/testing/openssl.conf -extensions 'v3_req' + diff --git a/src/api.go b/src/api.go index 1452a40..823ff32 100644 --- a/src/api.go +++ b/src/api.go @@ -5,6 +5,7 @@ import ( "io/ioutil" "net/http" "os" + "os/exec" "strings" ) @@ -24,6 +25,9 @@ func getAPIData(r *http.Request, resp *response) error { case "logs": resp.Message, err = getLogs(path[1]) return err + case "logsfeed": + resp.Message, err = getLogsFeed(path[1]) + return err } return nil @@ -31,7 +35,7 @@ func getAPIData(r *http.Request, resp *response) error { // Gets the logs from the task ID's file func getLogs(path string) (string, error) { - logs := folder.Logs + path + "/info.log" + logs := folder.Docker + path + "/info.log" file, err := os.Open(logs) if err != nil { return "", err @@ -45,6 +49,19 @@ func getLogs(path string) (string, error) { return string(bytes), nil } +func getLogsFeed(path string) (string, error) { + logs := folder.Docker + path + "/info.log" + + cmd := exec.Command("tail", "-11", logs) + out, err := cmd.CombinedOutput() + msg := string(out) + if err != nil { + return msg, errors.New("Failed to run Docker Compose") + } + + return msg, nil +} + func getJobs(path string) (*taskJob, error) { var emptyJob *taskJob @@ -62,7 +79,7 @@ func checkJobStatus(job *taskJob) error { logs, err := getLogs(job.ID) if strings.Contains(logs, "exited with code") { job.Status = jobStatus.Stopped - job.ErrMsg = "A Container exited unexpectedly" + job.ErrMsg = "A Container has maybe exited unexpectedly" } return err diff --git a/src/client.go b/src/client.go index d36bb95..379e685 100644 --- a/src/client.go +++ b/src/client.go @@ -131,6 +131,8 @@ func postCommChecks(t task, id string) error { counter := 0 fmt.Println("Waiting on server response...") + + // Ensure task hasn't stopped unexpectantly early for { resp, code := post(payload, jobURL) if code != statCode.Accepted { @@ -148,6 +150,7 @@ func postCommChecks(t task, id string) error { building := job.Status == jobStatus.Building && !buildingTriggered running := job.Status == jobStatus.Running && !runningTriggered + // Marks that a new build has started if building { buildingTriggered = true fmt.Println("The Task is now building a job") @@ -159,6 +162,7 @@ func postCommChecks(t task, id string) error { fmt.Println("Making sure it does not stop unexpectedly...") } + // Marks some sort of error if errored || stopped { fmt.Println("Task stopped running!") fmt.Println("Error Message: " + job.ErrMsg) @@ -183,6 +187,7 @@ func postCommChecks(t task, id string) error { lastIssue = job.Issue } + // If 7 seconds has elapsed, comsider it started properly if counter > 7 { fmt.Println("Task has started Properly!") return nil diff --git a/src/handlers.go b/src/handlers.go index b745ff4..74c6c65 100644 --- a/src/handlers.go +++ b/src/handlers.go @@ -30,8 +30,7 @@ func httpHandleAPI(w http.ResponseWriter, r *http.Request) { if status == statCode.Accepted { } else { - resp = response{} - resp.Message = getFailMessage(status) + resp.Message = getFailMessage(status) + " Message: " + resp.Message } json.NewEncoder(w).Encode(resp) @@ -138,15 +137,21 @@ func checkMethod(method string) error { return nil } +// Check that client versions match func checkVersion(clientVersion string) error { - v1, err := version.NewVersion(clientVersion) - v2, err := version.NewVersion(sharpCDVersion) + if clientVersion != "" { + v1, err := version.NewVersion(clientVersion) + v2, err := version.NewVersion(sharpCDVersion) + + if v1.LessThan(v2) { + err = errors.New("Wrong Client Version") + } - if v1.LessThan(v2) { - err = errors.New("Wrong Client Version") + return err } - return err + // Means its a non-sharpcd task + return nil } // Checks if URLs are okay diff --git a/src/jobs.go b/src/jobs.go index 8a4f01e..47eefbe 100644 --- a/src/jobs.go +++ b/src/jobs.go @@ -8,6 +8,8 @@ import ( "os/exec" "regexp" "strings" + + "github.com/joho/godotenv" ) // Pointer to variable storing all jobs @@ -92,9 +94,11 @@ func (job *taskJob) DockerCmd() *exec.Cmd { // All Location Data id := job.ID url := job.URL - logsLoc := folder.Logs + id + logsLoc := folder.Docker + id composeLoc := folder.Docker + id + "/docker-compose.yml" + var err error + if job.Reconnect != true { // Get github token f, err := readFilter() @@ -139,6 +143,7 @@ func (job *taskJob) DockerCmd() *exec.Cmd { _, err = os.Stat(composeLoc) if err == nil { err = os.Remove(composeLoc) + if err != nil { handleAPI(err, job, "Failed to Remove") } @@ -160,7 +165,8 @@ func (job *taskJob) DockerCmd() *exec.Cmd { err = job.buildCommand("-f", composeLoc, "up", "--no-start") if err == nil { // Remove any previous containers - job.buildCommand("-f", composeLoc, "down") + // Deals with any network active endpoints + job.buildCommand("-f", composeLoc, "down", "--remove-orphans") // Run Code job.buildCommand("-f", composeLoc, "up", "-d") @@ -185,14 +191,39 @@ func (job *taskJob) DockerCmd() *exec.Cmd { } func (job *taskJob) insertEnviroment() []string { + + var err error + envfile := folder.Docker + job.ID + "/.env" var environ []string - for key, val := range job.Enviroment { - str := key + "=" + val - environ = append(environ, str) + // If there is enviroment vars to use + if len(job.Enviroment) != 0 { + + // Apply them + _, err = os.Create(envfile) + err = godotenv.Write(job.Enviroment, envfile) + + handleAPI(err, job, "Failed to write to Envfile") + } else { + // Check if file exists for .env vars + + _, err = os.Stat(envfile) + if err == nil { + job.Issue = "EnvFile exists but no Job Env Vars was given" + } } - return append(os.Environ(), environ...) + fileEnviroment, err := godotenv.Read(envfile) + if err == nil { + for key, val := range fileEnviroment { + str := key + "=" + val + environ = append(environ, str) + } + + return append(os.Environ(), environ...) + } + + return nil } func (job *taskJob) dockerLogin() { diff --git a/src/main.go b/src/main.go index 91ee97f..e8ce3f1 100644 --- a/src/main.go +++ b/src/main.go @@ -9,7 +9,6 @@ import ( ) var secretFlag string -var tokenFlag string // Create Flags needed func init() { @@ -26,11 +25,19 @@ Args of SharpCD: - changetoken: Add a token for private github repos - removefilter: Remove a url for a compose file - version: Returns the Current Version + - trak: Run the Trak program -This will read the sharpdev.yml file +Sub Command Trak: + + - alljobs {type}: Get info on all jobs + - job {type} {id}: Get info on job with logging + - list {type}: Get all jobs running on sharpcd server + +Flags: `) flag.PrintDefaults() + fmt.Println() } } @@ -47,6 +54,8 @@ func main() { switch arg1 { case "server": server() + case "trak": + trak() case "help": flag.Usage() case "setsecret": @@ -67,6 +76,8 @@ func main() { return } +// Get the local directory +// Method changes depending on enviroment func getDir() string { var exPath string var err error diff --git a/src/structs.go b/src/structs.go index 3c183e2..bd23d99 100644 --- a/src/structs.go +++ b/src/structs.go @@ -1,5 +1,11 @@ package main +import ( + "github.com/gorilla/websocket" +) + +var sharpCDVersion = "0.2.0" + type statusCodes struct { NotPostMethod int Accepted int @@ -23,7 +29,12 @@ var statCode = statusCodes{ CommDoesNotExist: 617, WrongVersion: 618} -var sharpCDVersion = "0.1.10" +var ( + upgrader = websocket.Upgrader{ + ReadBufferSize: 1024, + WriteBufferSize: 1024, + } +) type jobStats struct { Running string @@ -70,6 +81,11 @@ type postData struct { Version string `json:"version"` } +type trakPostData struct { + Secret string `json:"secret"` + Version string `json:"version"` +} + type task struct { ID string Name string @@ -85,6 +101,7 @@ type task struct { type config struct { Version float32 Tasks map[string]task + Trak map[string]string } type filter struct { @@ -108,5 +125,4 @@ type allDirs struct { var folder = allDirs{ Root: getDir() + "/sharpcd-data/", Private: getDir() + "/sharpcd-data/private/", - Logs: getDir() + "/sharpcd-data/logs/", Docker: getDir() + "/sharpcd-data/docker/"} diff --git a/src/trak.go b/src/trak.go new file mode 100644 index 0000000..08c08ba --- /dev/null +++ b/src/trak.go @@ -0,0 +1,358 @@ +package main + +import ( + "bytes" + "crypto/tls" + "encoding/json" + "errors" + "flag" + "fmt" + "io/ioutil" + "log" + "net/http" + "strconv" + "strings" + "time" + + "github.com/common-nighthawk/go-figure" + ui "github.com/gizak/termui" + "github.com/gizak/termui/widgets" + "gopkg.in/yaml.v2" +) + +var tablePadding int = 2 + +func trak() { + + var trakArg = flag.Args()[1] + + switch trakArg { + case "alljobs": + liveFeed() + case "job": + liveFeed() + case "list": + listJobs() + default: + handle(errors.New(""), "No valid trak arg was given") + flag.Usage() + } + +} + +// Lists all jobs running on server +func listJobs() { + var location = flag.Args()[2] + + var jobIDs []string + + // Get sharpcd file + f, err := ioutil.ReadFile("./sharpcd.yml") + var con config + err = yaml.Unmarshal(f, &con) + handle(err, "Failed to read and extract sharpcd.yml") + + urlJobs := con.Trak[location] + "/api/jobs/" + + jobs := getAPIOutput(urlJobs).Jobs + + for _, job := range jobs { + jobIDs = append(jobIDs, " - "+job.ID) + } + + fmt.Println("\nList of SharpCD Jobs running on " + con.Trak[location] + ":\n") + fmt.Println(strings.Join(jobIDs, "\n") + "\n") +} + +// Creates Interface +func liveFeed() { + + var urlJob string + var urlJobs string + var urlLog string + var oldWidth = 0 + + var trakAll string = "alljobs" + var trakOne string = "job" + + var trakArg = flag.Args()[1] + var location = flag.Args()[2] + + // Get sharpcd file + f, err := ioutil.ReadFile("./sharpcd.yml") + var con config + err = yaml.Unmarshal(f, &con) + handle(err, "Failed to read and extract sharpcd.yml") + + urlJobs = con.Trak[location] + "/api/jobs/" + + // Only needed for single job requests + if trakArg == trakOne { + var jobID = flag.Args()[3] + + urlJob = con.Trak[location] + "/api/job/" + jobID + urlLog = con.Trak[location] + "/api/logsfeed/" + jobID + } + + // Tests to ensure you can actually reach the server + getAPIOutput(urlJobs) + + // Load UI + if err := ui.Init(); err != nil { + log.Fatalf("failed to initialize termui: %v", err) + } + defer ui.Close() + + // Function for rendering UI + draw := func() { + table := tableMain() + + var jobs []*taskJob + + // Gets all rows if there is one job + if trakArg == trakOne { + job := getAPIOutput(urlJob).Job + + jobs = append(jobs, job) + } + + // Gets all rows if there is there are multiple jobs + if trakArg == trakAll { + jobs = getAPIOutput(urlJobs).Jobs + } + + // Adds in a row for each job + for _, job := range jobs { + jobStr := []string{ + job.ID, job.Name, job.Type, job.Status, job.ErrMsg, strconv.FormatBool(job.Reconnect), + } + table.Rows = append(table.Rows, jobStr) + } + + // Makes sure all widths are correct + table.ColumnWidths = generateColumnWidths(table.Rows, table.Rows[0]) + width := sum(table.ColumnWidths) + len(table.Rows[0]) + 1 + + // Deals with bug that if width space shrinks it doesn't render correctly + if oldWidth > width { + width = oldWidth + } else { + oldWidth = width + } + + title, heightTitle := createTitle(width) + ui.Render(title) + + // Creates Table + deltaYTable := heightTitle + heightTable := deltaYTable + len(table.Rows)*2 + 1 + table.SetRect(0, deltaYTable, width, heightTable) + ui.Render(table) + + // Creates Logs if needed + var heightLogs int + var trakLogs *widgets.Paragraph + + if trakArg == trakOne { + trakLogs, heightLogs = logging(width, heightTable, urlLog) + ui.Render(trakLogs) + } else { + heightLogs = heightTable + } + + close := closing(width, tablePadding, heightLogs) + ui.Render(close) + + } + + // Runs Interface + uiEvents := ui.PollEvents() + ticker := time.NewTicker(time.Second).C + draw() + + for { + select { + case e := <-uiEvents: + switch e.ID { + case "q", "": + return + } + case <-ticker: + draw() + } + } + +} + +// Creates Table with styling +func tableMain() *widgets.Table { + + headers := []string{"ID", "Name", "Type", "Status", "Error Message", "Reconnected"} + + table1 := widgets.NewTable() + + table1.TextStyle = ui.NewStyle(ui.ColorWhite) + table1.TextAlignment = ui.AlignCenter + table1.FillRow = true + + table1.Rows = [][]string{headers} + table1.BorderStyle.Fg = ui.ColorCyan + table1.RowStyles[0] = ui.NewStyle(ui.ColorGreen, ui.ColorClear, ui.ModifierBold) + + return table1 +} + +// Creates the fancy title font +func createTitle(width int) (*widgets.Paragraph, int) { + title := widgets.NewParagraph() + myFigure := figure.NewFigure("SharpCD Trak", "", true) + figureRows := myFigure.Slicify() + title.Text = "" + titleSpace := 0 + + // Centers the Figure + if width < len(figureRows[0]) { + width = len(figureRows[0]) + 4 + titleSpace = 0 + } else { + titleSpace = (width-len(figureRows[0]))/2 - 2*tablePadding - 1 + } + + // Check to make sure there is room + if titleSpace < 1 { + titleSpace = 0 + } + + // Draw the Figure into a string + for _, row := range figureRows { + title.Text += (strings.Repeat(" ", titleSpace) + row + "\n") + } + + heightTitle := len(figureRows) + tablePadding + title.SetRect(0, 0, width, heightTitle) + title.BorderStyle.Fg = ui.ColorCyan + title.TextStyle = ui.NewStyle(ui.ColorGreen, ui.ColorClear, ui.ModifierBold) + + return title, heightTitle +} + +// Creates closing screen +func closing(width int, tablePadding int, heightLogs int) *widgets.Paragraph { + + deltaYClose := heightLogs + heightClose := deltaYClose + 3 + + close := widgets.NewParagraph() + + dt := time.Now() + + text1 := " Press Ctrl+C to Exit" + text2 := dt.Format("01-02-2006 15:04:05") + " " + space := width - len(text1) - len(text2) - tablePadding + + // Ensure the text is aligned and padded + close.Text = text1 + strings.Repeat(" ", space) + text2 + close.SetRect(0, deltaYClose, width, heightClose) + close.BorderStyle.Fg = ui.ColorCyan + + close.TextStyle = ui.NewStyle(ui.ColorGreen, ui.ColorClear, ui.ModifierBold) + + return close +} + +// Creates the logging page +func logging(width int, heightTable int, urlLog string) (*widgets.Paragraph, int) { + logs := getAPIOutput(urlLog).Message + + deltaYLogs := heightTable + heightLogs := deltaYLogs + 22 + + trakLogs := widgets.NewParagraph() + trakLogs.Text = "\n" + logs + trakLogs.SetRect(0, deltaYLogs, width, heightLogs) + + trakLogs.BorderStyle.Fg = ui.ColorCyan + trakLogs.Title = "Live Output" + + trakLogs.TitleStyle = ui.NewStyle(ui.ColorGreen, ui.ColorClear, ui.ModifierBold) + + return trakLogs, heightLogs +} + +// Finds the sum of ints +func sum(array []int) int { + result := 0 + for _, v := range array { + result += v + } + return result +} + +// Finds the longest string in column (index) +func longest(array [][]string, index int) int { + longestString := 0 + + for _, row := range array { + if new := len(row[index]); new > longestString { + longestString = new + } + } + + if longestString > 40 { + longestString = 40 + } + + return longestString + 4 +} + +func generateColumnWidths(rows [][]string, columns []string) []int { + + columnWidths := []int{} + + for index := range columns { + columnWidths = append(columnWidths, longest(rows, index)) + } + + return columnWidths +} + +func getAPIOutput(url string) response { + + // Insert needed data + secret := getSec() + trakPayload := trakPostData{ + Secret: secret, + Version: sharpCDVersion, + } + + // Create request + jsonStr, err := json.Marshal(trakPayload) + req, err := http.NewRequest("POST", url, bytes.NewBuffer(jsonStr)) + handle(err, "Failed to create request for"+url) + + // Create client + // Allow self-signed certs + req.Header.Set("Content-Type", "application/json") + client := &http.Client{ + Transport: &http.Transport{ + TLSClientConfig: &tls.Config{ + InsecureSkipVerify: true, + }, + }, + } + + // Do Request + resp, err := client.Do(req) + handle(err, "Failed to do POST request"+url) + defer resp.Body.Close() + + // Read Body and Status + body, err := ioutil.ReadAll(resp.Body) + handle(err, "Failed to read body of response"+url) + + var apiOutput response + err = json.Unmarshal(body, &apiOutput) + handle(err, "Failed to unmarshal body"+url) + + return apiOutput +} diff --git a/testing/.gitignore b/testing/.gitignore new file mode 100644 index 0000000..4ced156 --- /dev/null +++ b/testing/.gitignore @@ -0,0 +1 @@ +openssl.conf \ No newline at end of file diff --git a/testing/delayed.yml b/testing/delayed.yml deleted file mode 100644 index c77e4b0..0000000 --- a/testing/delayed.yml +++ /dev/null @@ -1,5 +0,0 @@ -version: '3' -services: - hello_world: - image: ubuntu - command: ["/bin/sh", "-c", "echo Hello && sleep 1"] \ No newline at end of file diff --git a/testing/restart.yml b/testing/restart.yml index b7b5fea..e4cb5f6 100644 --- a/testing/restart.yml +++ b/testing/restart.yml @@ -6,5 +6,5 @@ services: hello_world2: image: ubuntu - command: ["/bin/sh", "-c", "echo Hello && sleep 2 && exit 2"] + command: ["/bin/sh", "-c", "echo Hello && sleep 3 && exit 2"] restart: always \ No newline at end of file diff --git a/testing/trak.yml b/testing/trak.yml new file mode 100644 index 0000000..e79860f --- /dev/null +++ b/testing/trak.yml @@ -0,0 +1,16 @@ +version: "3" + +services: + db: + image: mysql:5.7 + volumes: + - db_data:/var/lib/mysql + restart: always + environment: + MYSQL_ROOT_PASSWORD: somewordpress + MYSQL_DATABASE: wordpress + MYSQL_USER: wordpress + MYSQL_PASSWORD: wordpress + +volumes: + db_data: {} \ No newline at end of file