pagerduty-cachet

git clone git://archive.git.mtrnord.blog/MTRNord/pagerduty-cachet.git
Log | Files | Refs | README

commit 6343ddfa9536d85b40c6a353b6230a4853319625
parent d3ba1ddf513c536b964938a86d016c7fb28235c9
Author: MTRNord <mtrnord1@gmail.com>
Date:   Mon,  7 Oct 2024 01:15:37 +0200

Cleanup and ci

Diffstat:
A.dockerignore | 2++
A.github/workflows/docker.yml | 54++++++++++++++++++++++++++++++++++++++++++++++++++++++
Mserver.go | 207++++++++++++++++++++++++++++++++++++++++---------------------------------------
3 files changed, 162 insertions(+), 101 deletions(-)

diff --git a/.dockerignore b/.dockerignore @@ -0,0 +1 @@ +pagerduty_cachet +\ No newline at end of file diff --git a/.github/workflows/docker.yml b/.github/workflows/docker.yml @@ -0,0 +1,53 @@ +name: docker + +on: + push: + branches: + - main + +env: + REGISTRY: ghcr.io + IMAGE_NAME: ${{ github.repository }} + +jobs: + docker: + runs-on: ubuntu-latest + permissions: + contents: read + packages: write + id-token: write + attestations: write + steps: + - name: Checkout code + uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4 + + - name: Set up QEMU + uses: docker/setup-qemu-action@49b3bc8e6bdd4a60e6116a5414239cba5943d3cf # v3 + + - name: Set up Docker Buildx + uses: docker/setup-buildx-action@988b5a0280414f521da01fcc63a27aeeb4b104db # v3 + + - name: Docker meta + id: meta + uses: docker/metadata-action@8e5442c4ef9f78752691e2d8f8d19755c6f78e81 # v5 + with: + images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }} + + - name: Log in to the Container registry + uses: docker/login-action@9780b0c442fbb1117ed29e0efdff1e18412f7567 # v3 + with: + registry: ${{ env.REGISTRY }} + username: ${{ github.actor }} + password: ${{ secrets.GITHUB_TOKEN }} + + - name: Build and push + uses: docker/build-push-action@5cd11c3a4ced054e52742c5fd54dca954e0edd85 # v6 + id: push + with: + platforms: linux/amd64,linux/arm64 + context: . + push: ${{ github.event_name != 'pull_request' }} + tags: ${{ steps.meta.outputs.tags }} + labels: ${{ steps.meta.outputs.labels }} + env: + SOURCE_DATE_EPOCH: 0 +\ No newline at end of file diff --git a/server.go b/server.go @@ -25,137 +25,142 @@ var ( secret = os.Getenv("WEBHOOK_SECRET") ) -func main() { - router := mux.NewRouter() +func syncMaintenanceWindows() { + client := pagerduty.NewClient(pagerdutyKey) - router.HandleFunc("/webhook", handler).Methods("POST") - router.Use(mux.CORSMethodMiddleware(router)) - http.Handle("/", router) + cachetClient, _ := cachet_go.NewClient(cachetURL, nil) + cachetClient.Authentication.SetTokenAuth(cachetKey) + _, status, err := cachetClient.General.Ping() + if err != nil || status.StatusCode != 200 { + log.Println(err) + return + } - go func() { - client := pagerduty.NewClient(pagerdutyKey) + // Fethc maintenance windows every 30 minutes + for { + maintenanceWindows, err := fetchMaintenanceWindows(client) + if err != nil { + log.Println(err) + continue + } + log.Printf("Fetched %d maintenance windows\n", len(maintenanceWindows)) - cachetClient, _ := cachet_go.NewClient(cachetURL, nil) - cachetClient.Authentication.SetTokenAuth(cachetKey) - _, status, err := cachetClient.General.Ping() - if err != nil || status.StatusCode != 200 { + // Set them in cachet as schedules if they don't exist + + // Get all schedules + schedules, _, err := cachetClient.Schedules.GetAll(&cachet_go.SchedulesQueryParams{ + QueryOptions: cachet_go.QueryOptions{ + PerPage: 100, + }, + }) + if err != nil { log.Println(err) - return + continue } - // Fethc maintenance windows every 30 minutes - for { - maintenanceWindows, err := fetchMaintenanceWindows(client) - if err != nil { - log.Println(err) - continue - } - log.Printf("Fetched %d maintenance windows\n", len(maintenanceWindows)) + // Create a map of schedules by start and end time + schedulesMap := map[string]*cachet_go.Schedule{} + for _, s := range schedules.Schedules { + schedulesMap[s.ScheduledAt+"_"+s.CompletedAt] = &s + } + + // Load Europe/Berlin timezone + loc, err := time.LoadLocation("Europe/Berlin") + if err != nil { + log.Println(err) + continue + } - // Set them in cachet as schedules if they don't exist + // Create a map of maintenance windows by start and end time if they don't exist + for _, mw := range maintenanceWindows { + // Convert the pagerduty time in the format "2015-11-09T20:00:00-05:00" to "Y-m-d H:i:sO". + // Keep in mind that cachet is in Europe/Berlin timezone + // Keep in mind that pagerduty is giving us a string - // Get all schedules - schedules, _, err := cachetClient.Schedules.GetAll(&cachet_go.SchedulesQueryParams{ - QueryOptions: cachet_go.QueryOptions{ - PerPage: 100, - }, - }) + // Parse the start and end time + startTime, err := time.Parse(time.RFC3339, mw.StartTime) if err != nil { log.Println(err) continue } - - // Create a map of schedules by start and end time - schedulesMap := map[string]*cachet_go.Schedule{} - for _, s := range schedules.Schedules { - schedulesMap[s.ScheduledAt+"_"+s.CompletedAt] = &s - } - - // Load Europe/Berlin timezone - loc, err := time.LoadLocation("Europe/Berlin") + endTime, err := time.Parse(time.RFC3339, mw.EndTime) if err != nil { log.Println(err) continue } - // Create a map of maintenance windows by start and end time if they don't exist - for _, mw := range maintenanceWindows { - // Convert the pagerduty time in the format "2015-11-09T20:00:00-05:00" to "Y-m-d H:i:sO". - // Keep in mind that cachet is in Europe/Berlin timezone - // Keep in mind that pagerduty is giving us a string - - // Parse the start and end time - startTime, err := time.Parse(time.RFC3339, mw.StartTime) - if err != nil { - log.Println(err) - continue - } - endTime, err := time.Parse(time.RFC3339, mw.EndTime) - if err != nil { - log.Println(err) - continue - } - - // If the endTime is before now, skip - if endTime.Before(time.Now()) { - continue - } - - // Convert the start and end time to Europe/Berlin timezone - startTime = startTime.In(loc) - endTime = endTime.In(loc) + // If the endTime is before now, skip + if endTime.Before(time.Now()) { + continue + } - // Convert the start and end time to the format "Y-m-d H:i:sO" - mw.StartTime = gotime.Format(startTime, "yyyy-mm-dd hhh:ii") - mw.EndTime = gotime.Format(endTime, "yyyy-mm-dd hhh:ii") - // Also convert it with space instead of + for the lookup table - mwStart := gotime.Format(startTime, "yyyy-mm-dd hhh:ii:ss") - mwEnd := gotime.Format(endTime, "yyyy-mm-dd hhh:ii:ss") + // Convert the start and end time to Europe/Berlin timezone + startTime = startTime.In(loc) + endTime = endTime.In(loc) - // If there is no summary then we want to set it to "Maintenance" - if mw.Description == "" { - mw.Description = "Maintenance" - } + // Convert the start and end time to the format "Y-m-d H:i:sO" + mw.StartTime = gotime.Format(startTime, "yyyy-mm-dd hhh:ii") + mw.EndTime = gotime.Format(endTime, "yyyy-mm-dd hhh:ii") + // Also convert it with space instead of + for the lookup table + mwStart := gotime.Format(startTime, "yyyy-mm-dd hhh:ii:ss") + mwEnd := gotime.Format(endTime, "yyyy-mm-dd hhh:ii:ss") - log.Printf("Maintenance window (%s): %s - %s\n", mw.Summary, mw.StartTime, mw.EndTime) - - var components []cachet_go.Component - if mw.Services != nil { - for _, s := range mw.Services { - component, err := findComponentByName(cachetClient, s.Summary) - if err != nil { - log.Println(err) - continue - } - if component != nil { - components = append(components, *component) - } - } - } + // If there is no summary then we want to set it to "Maintenance" + if mw.Description == "" { + mw.Description = "Maintenance" + } - if _, ok := schedulesMap[mwStart+"_"+mwEnd]; !ok { - newSchedule := &cachet_go.Schedule{ - Name: mw.Description, - Message: mw.Description, - Status: "0", - ScheduledAt: mw.StartTime, - CompletedAt: mw.EndTime, - Components: components, - } - // Print the schedule to the console - log.Printf("%+v\n", newSchedule) + log.Printf("Maintenance window (%s): %s - %s\n", mw.Summary, mw.StartTime, mw.EndTime) - _, _, err := cachetClient.Schedules.Create(newSchedule) + var components []cachet_go.Component + if mw.Services != nil { + for _, s := range mw.Services { + component, err := findComponentByName(cachetClient, s.Summary) if err != nil { log.Println(err) continue } + if component != nil { + components = append(components, *component) + } } } - time.Sleep(30 * time.Minute) + if _, ok := schedulesMap[mwStart+"_"+mwEnd]; !ok { + newSchedule := &cachet_go.Schedule{ + Name: mw.Description, + Message: mw.Description, + Status: "0", + ScheduledAt: mw.StartTime, + CompletedAt: mw.EndTime, + Components: components, + } + // Print the schedule to the console + log.Printf("%+v\n", newSchedule) + + _, _, err := cachetClient.Schedules.Create(newSchedule) + if err != nil { + log.Println(err) + continue + } + } } - }() + + time.Sleep(30 * time.Minute) + } +} + +func main() { + router := mux.NewRouter() + + router.HandleFunc("/webhook", handler).Methods("POST") + router.HandleFunc("/healthz", func(w http.ResponseWriter, r *http.Request) { + w.WriteHeader(http.StatusOK) + }).Methods("GET") + router.Use(mux.CORSMethodMiddleware(router)) + http.Handle("/", router) + + go syncMaintenanceWindows() log.Println("Listening on 0.0.0.0:8080") log.Fatal(http.ListenAndServe("0.0.0.0:8080", router))