Skip to content

Commit

Permalink
Merge pull request #29 from Divi09112/discord
Browse files Browse the repository at this point in the history
Add discord support
  • Loading branch information
imperfect-fourth authored Jul 17, 2020
2 parents 527ad21 + 74a584f commit c6065d8
Show file tree
Hide file tree
Showing 6 changed files with 144 additions and 5 deletions.
3 changes: 3 additions & 0 deletions src/controllers/deploy.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import (
"github.com/devclub-iitd/DeployBot/src/helper"
"github.com/devclub-iitd/DeployBot/src/history"
"github.com/devclub-iitd/DeployBot/src/slack"
"github.com/devclub-iitd/DeployBot/src/discord"
log "github.com/sirupsen/logrus"
)

Expand All @@ -20,6 +21,7 @@ func deploy(callbackID string, data map[string]interface{}) {
log.Errorf("cannot post begin deployment chat message - %v", err)
return
}
go discord.PostActionMessage(callbackID, actionLog.EmbedFields())
log.Infof("beginning %s with callback_id as %s", actionLog, callbackID)

logPath := fmt.Sprintf("deploy/%s.txt", callbackID)
Expand All @@ -38,6 +40,7 @@ func deploy(callbackID string, data map[string]interface{}) {
history.StoreAction(actionLog)
slack.PostChatMessage(channel, fmt.Sprintf("%s\n", actionLog), nil)
}
go discord.PostActionMessage(callbackID, actionLog.EmbedFields())
}

// internaldeploy deploys the given app on the server specified.
Expand Down
17 changes: 12 additions & 5 deletions src/controllers/logs.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import (
"path"
"time"

"github.com/devclub-iitd/DeployBot/src/discord"
"github.com/devclub-iitd/DeployBot/src/helper"
"github.com/devclub-iitd/DeployBot/src/history"
"github.com/devclub-iitd/DeployBot/src/slack"
Expand All @@ -17,27 +18,33 @@ import (
func logs(callbackID string, data map[string]interface{}) {
repoURL := data["git_repo"].(string)
channelID := data["channel"].(string)
actionLog := history.NewAction("logs", data)
if err := slack.PostChatMessage(channelID, fmt.Sprintf("Fetching logs for %s ...", repoURL), nil); err != nil {
log.Warnf("error occured in posting message - %v", err)
return
}
go discord.PostActionMessage(callbackID, actionLog.EmbedFields())
log.Infof("Fetching logs for service %s with callback_id as %s", repoURL, callbackID)

output, err := internalLogs(data)
if err != nil {
_ = slack.PostChatMessage(channelID, fmt.Sprintf("Logs for service %s could not be fetched.\nERROR: %s", repoURL, err.Error()), nil)
actionLog.Result = "failed"
} else {
filePath := path.Join(logDir, "service", fmt.Sprintf("%s.txt", callbackID))
helper.WriteToFile(filePath, string(output))
log.Info("starting timer for " + filePath)
actionLog.Result = "success"
filePath := path.Join("service", fmt.Sprintf("%s.txt", callbackID))
helper.WriteToFile(path.Join(logDir, filePath), string(output))
actionLog.LogPath = filePath
log.Info("starting timer for log file: %s", filePath)
go time.AfterFunc(time.Minute*logsExpiryMins, func() {
os.Remove(filePath)
log.Infof("Deleted " + filePath)
log.Infof("Deleted log file: %s", filePath)
})
_ = slack.PostChatMessage(channelID,
fmt.Sprintf("Requested logs for service %s would be available at %s/logs/service/%s.txt for %d minutes.", repoURL, serverURL, callbackID, logsExpiryMins),
fmt.Sprintf("Requested logs for service %s would be available at %s/logs/%s for %d minutes.", repoURL, serverURL, filePath, logsExpiryMins),
nil)
}
go discord.PostActionMessage(callbackID, actionLog.EmbedFields())
}

func internalLogs(data map[string]interface{}) ([]byte, error) {
Expand Down
3 changes: 3 additions & 0 deletions src/controllers/stop.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import (
"github.com/devclub-iitd/DeployBot/src/helper"
"github.com/devclub-iitd/DeployBot/src/history"
"github.com/devclub-iitd/DeployBot/src/slack"
"github.com/devclub-iitd/DeployBot/src/discord"
log "github.com/sirupsen/logrus"
)

Expand All @@ -20,6 +21,7 @@ func stop(callbackID string, data map[string]interface{}) {
log.Warnf("error occured in posting chat message - %v", err)
return
}
go discord.PostActionMessage(callbackID, actionLog.EmbedFields())
log.Infof("beginning %s with callback_id as %s", actionLog, callbackID)

logPath := fmt.Sprintf("stop/%s.txt", callbackID)
Expand All @@ -36,6 +38,7 @@ func stop(callbackID string, data map[string]interface{}) {
history.StoreAction(actionLog)
slack.PostChatMessage(channel, actionLog.String(), nil)
}
go discord.PostActionMessage(callbackID, actionLog.EmbedFields())
}

// internalStop actually runs the script to stop the given app.
Expand Down
59 changes: 59 additions & 0 deletions src/discord/config.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
package discord

import (
"fmt"

"github.com/devclub-iitd/DeployBot/src/helper"
log "github.com/sirupsen/logrus"
)

var (
// postMessageHookURL is the webhook url for posting messages on discord
postMessageHookURL string
serverURL string
)

func init() {
postMessageHookURL = helper.Env("DISCORD_MESSAGE_WEBHOOK", "None")
if postMessageHookURL == "None" {
log.Fatal("DISCORD_MESSAGE_WEBHOOK not present in environment, Exiting")
}
serverURL = helper.Env("SERVER_URL", "https://listen.devclub.iitd.ac.in")
}

type Embed struct {
Title string `json:"title"`
Color int `json:"color"`
Fields []interface{} `json:"fields"`
}

type Message struct {
Content string `json:"content"`
Embeds []*Embed `json:"embeds"`
}

func newMessage(callbackID, action, result string, fields []interface{}) Message {
var callbackField interface{}
callbackField = map[string]interface{}{
"name": "Action ID",
"value": callbackID,
"inline": true,
}
fields = append([]interface{}{callbackField}, fields...)
embed := &Embed{Fields: fields}
switch result {
case "success":
embed.Title = fmt.Sprintf("%s action completed", action)
embed.Color = 6749952
case "failed":
embed.Title = fmt.Sprintf("%s action failed", action)
embed.Color = 16724736
default:
embed.Title = fmt.Sprintf("%s action in progress", action)
embed.Color = 3381759
}

return Message{
Embeds: []*Embed{embed},
}
}
28 changes: 28 additions & 0 deletions src/discord/discord.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
package discord

import (
"net/http"
"encoding/json"
"fmt"
"bytes"

log "github.com/sirupsen/logrus"
)

func PostActionMessage(callbackID string, data map[string]interface{}) error {
msg := newMessage(callbackID, data["action"].(string), data["result"].(string), data["fields"].([]interface{}))
payload, err := json.Marshal(msg)
if err != nil {
log.Errorf("cannot marshal discord message - %v", err)
return err
}
log.Infof("Posting chat message to discord: %+v", msg)
resp, err := http.Post(postMessageHookURL, "application/json", bytes.NewBuffer(payload))
resp.Body.Close()
if err != nil {
return fmt.Errorf("discord POST request failed - %v", err)
}
log.Infof("Message posted to discord")
return nil
}

39 changes: 39 additions & 0 deletions src/history/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ var (
stateFile string
// serverURL is the URL of the server
serverURL string
domain string

statusTemplate *template.Template

Expand Down Expand Up @@ -116,6 +117,43 @@ func (a *ActionInstance) Fields() []interface{} {
return fields
}

type EmbedField struct {
Name string `json:"name"`
Value string `json:"value"`
Inline bool `json:"inline"`
}

func (a *ActionInstance) EmbedFields() map[string]interface{} {
m := map[string]interface{}{"action": a.Action, "result": a.Result}
if a.Result != "" {
fields := []interface{}{
EmbedField{"Result", a.Result, true},
EmbedField{"Repo", a.RepoURL, false},
EmbedField{"Logs", fmt.Sprintf("%s/logs/%s", serverURL, a.LogPath), false},
}
if a.Action == "deploy" && a.Result == "success" {
fields = append(fields,
EmbedField{"URL", fmt.Sprintf("https://%s.%s", a.Subdomain, domain), false},
)
}
m["fields"] = fields
return m
}
fields := []interface{}{
EmbedField{"User", a.User, true},
EmbedField{"Repo", a.RepoURL, false},
}
if a.Action == "deploy" {
fields = append(fields,
EmbedField{"Subdomain", a.Subdomain, true},
EmbedField{"Server", a.Server, true},
EmbedField{"Access", a.Access, true},
)
}
m["fields"] = fields
return m
}

// HealthCheck type stores the result of a healthcheck
type HealthCheck struct {
Timestamp time.Time `json:"timestamp"`
Expand Down Expand Up @@ -194,6 +232,7 @@ func newZapLogger(outfile string) (*zap.SugaredLogger, error) {

func init() {
serverURL = helper.Env("SERVER_URL", "https://listen.devclub.iitd.ac.in")
domain = helper.Env("DOMAIN", "devclub.iitd.ac.in")
historyFile = helper.Env("HISTORY_FILE", "/etc/nginx/logs/history.json")
healthCheckFile = helper.Env("HEALTH_CHECK_FILE", "/etc/nginx/logs/health.json")
stateFile = helper.Env("STATE_FILE", "/etc/nginx/logs/state.json")
Expand Down

0 comments on commit c6065d8

Please sign in to comment.