diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000..27c8e18 --- /dev/null +++ b/Dockerfile @@ -0,0 +1,18 @@ +# ---- Build container +FROM golang:alpine AS builder +WORKDIR /synology-notifications +COPY . . +RUN apk add --no-cache git +RUN go build -v ./... + +# ---- App container +FROM alpine:latest as synology-notifications +EXPOSE 8080 +ENV API_KEY= +ENV SLACK_WEBHOOK= +ENV SLACK_ATTACHMENT_COLOR= +ENV LISTEN_PORT=8080 +RUN apk --no-cache add ca-certificates +COPY --from=builder synology-notifications/synology-notifications / +ENTRYPOINT ./synology-notifications +LABEL Name=synology-notifications Version=0.0.1 diff --git a/Jenkinsfile b/Jenkinsfile new file mode 100644 index 0000000..2011d57 --- /dev/null +++ b/Jenkinsfile @@ -0,0 +1,39 @@ +podTemplate(yaml: """ +kind: Pod +spec: + containers: + - name: kaniko + image: gcr.io/kaniko-project/executor:debug-539ddefcae3fd6b411a95982a830d987f4214251 + imagePullPolicy: Always + command: + - /busybox/cat + tty: true + volumeMounts: + - name: jenkins-docker-cfg + mountPath: /kaniko/.docker + volumes: + - name: jenkins-docker-cfg + projected: + sources: + - secret: + name: regcred + items: + - key: .dockerconfigjson + path: config.json +""" + ) { + + node(POD_LABEL) { + stage('Build with Kaniko') { + git url: 'ssh://git@git.ervine.org/jonny/x86_64-alpine-dsm2slack.git', credentialsId: 'jenkins-to-git' + container('kaniko') { + sh '/kaniko/executor -f `pwd`/Dockerfile -c `pwd` --cache=true --destination=harbor.ervine.dev/public/x86_64/alpine/dsm2slack:v1' + } + } + } +} + +stage('Notify gchat') { + hangoutsNotify message: "Synology DSM to Slack notifier on Alpine has built",token: "A2ET831pVslqXTqAx6ycu573r",threadByJob: false +} + diff --git a/assets/Step_1.png b/assets/Step_1.png new file mode 100644 index 0000000..4e6e5ee Binary files /dev/null and b/assets/Step_1.png differ diff --git a/assets/Step_2.png b/assets/Step_2.png new file mode 100644 index 0000000..cd844ac Binary files /dev/null and b/assets/Step_2.png differ diff --git a/assets/Step_3.png b/assets/Step_3.png new file mode 100644 index 0000000..f184dee Binary files /dev/null and b/assets/Step_3.png differ diff --git a/assets/Step_4.png b/assets/Step_4.png new file mode 100644 index 0000000..ef7dd67 Binary files /dev/null and b/assets/Step_4.png differ diff --git a/assets/Step_5.png b/assets/Step_5.png new file mode 100644 index 0000000..96fa5af Binary files /dev/null and b/assets/Step_5.png differ diff --git a/go.mod b/go.mod new file mode 100644 index 0000000..17d4c1c --- /dev/null +++ b/go.mod @@ -0,0 +1,10 @@ +module github.com/ryancurrah/synology-notifications + +go 1.12 + +require ( + github.com/caarlos0/env v3.5.0+incompatible + github.com/gorilla/websocket v1.4.0 // indirect + github.com/nlopes/slack v0.5.0 + github.com/pkg/errors v0.8.1 // indirect +) diff --git a/go.sum b/go.sum new file mode 100644 index 0000000..7c1f424 --- /dev/null +++ b/go.sum @@ -0,0 +1,8 @@ +github.com/caarlos0/env v3.5.0+incompatible h1:Yy0UN8o9Wtr/jGHZDpCBLpNrzcFLLM2yixi/rBrKyJs= +github.com/caarlos0/env v3.5.0+incompatible/go.mod h1:tdCsowwCzMLdkqRYDlHpZCp2UooDD3MspDBjZ2AD02Y= +github.com/gorilla/websocket v1.4.0 h1:WDFjx/TMzVgy9VdMMQi2K2Emtwi2QcUQsztZ/zLaH/Q= +github.com/gorilla/websocket v1.4.0/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ= +github.com/nlopes/slack v0.5.0 h1:NbIae8Kd0NpqaEI3iUrsuS0KbcEDhzhc939jLW5fNm0= +github.com/nlopes/slack v0.5.0/go.mod h1:jVI4BBK3lSktibKahxBF74txcK2vyvkza1z/+rRnVAM= +github.com/pkg/errors v0.8.1 h1:iURUrRGxPUNPdy5/HRSm+Yj6okJ6UtLINN0Q9M4+h3I= +github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= diff --git a/main.go b/main.go new file mode 100644 index 0000000..d8e09e3 --- /dev/null +++ b/main.go @@ -0,0 +1,89 @@ +package main + +import ( + "encoding/json" + "fmt" + "io/ioutil" + "log" + "net/http" + + "github.com/caarlos0/env" + "github.com/nlopes/slack" +) + +var appConfig = AppConfig{} +var slackConfig = SlackConfig{} + +type SynologyMessage struct { + Message string `json:"message"` +} + +type AppConfig struct { + ListenPort string `env:"LISTEN_PORT" envDefault:"8080"` + APIKey string `env:"API_KEY,required"` +} + +type SlackConfig struct { + Webhook string `env:"SLACK_WEBHOOK,required"` + Color string `env:"SLACK_ATTACHMENT_COLOR" envDefault:"warning"` +} + +// PostHandler send notifications from synology to slack +func PostHandler(w http.ResponseWriter, r *http.Request) { + if r.Header.Get("api_key") != appConfig.APIKey { + http.Error(w, "invalid api key", http.StatusUnauthorized) + log.Printf("invalid api key") + return + } + + if r.Method == "POST" { + body, err := ioutil.ReadAll(r.Body) + if err != nil { + http.Error(w, "error reading request body", http.StatusInternalServerError) + log.Printf("error reading request body: %s", err) + return + } + + synologyMessage := SynologyMessage{} + err = json.Unmarshal(body, &synologyMessage) + if err != nil { + http.Error(w, "error reading request body", http.StatusInternalServerError) + log.Printf("error reading request body: %s", err) + return + } + + msg := slack.WebhookMessage{Attachments: []slack.Attachment{{Color: slackConfig.Color, Text: fmt.Sprintf("%s", synologyMessage.Message)}}} + + err = slack.PostWebhook(slackConfig.Webhook, &msg) + if err != nil { + http.Error(w, "error sendming slack message", http.StatusInternalServerError) + log.Printf("error sendming slack message: %s", err) + return + } + } else { + http.Error(w, "invalid request method", http.StatusMethodNotAllowed) + return + } +} + +func main() { + err := env.Parse(&appConfig) + if err != nil { + panic(err) + } + + err = env.Parse(&slackConfig) + if err != nil { + panic(err) + } + + if len(appConfig.APIKey) < 32 { + panic(fmt.Errorf("api key not long enough it should be 32 characters long not %d", len(appConfig.APIKey))) + } + + mux := http.NewServeMux() + mux.HandleFunc("/", PostHandler) + + log.Printf("listening on port %s", appConfig.ListenPort) + log.Fatal(http.ListenAndServe(fmt.Sprintf(":%s", appConfig.ListenPort), mux)) +}