Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 16 additions & 0 deletions go.mod
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
module paas

go 1.24.1

Check warning on line 3 in go.mod

View check run for this annotation

Codacy Production / Codacy Static Code Analysis

go.mod#L3

Insecure dependency golang/stdlib@v1.24.1 (CVE-2025-0913: Inconsistent handling of O_CREATE|O_EXCL on Unix and Windows in os in syscall) (update to 1.24.4)

Check warning on line 3 in go.mod

View check run for this annotation

Codacy Production / Codacy Static Code Analysis

go.mod#L3

Insecure dependency golang/stdlib@v1.24.1 (CVE-2025-22871: net/http: Request smuggling due to acceptance of invalid chunked data in net/http) (update to 1.24.2)

Check warning on line 3 in go.mod

View check run for this annotation

Codacy Production / Codacy Static Code Analysis

go.mod#L3

Insecure dependency golang/stdlib@v1.24.1 (CVE-2025-22874: crypto/x509: Usage of ExtKeyUsageAny disables policy validation in crypto/x509) (update to 1.24.4)

Check warning on line 3 in go.mod

View check run for this annotation

Codacy Production / Codacy Static Code Analysis

go.mod#L3

Insecure dependency golang/stdlib@v1.24.1 (CVE-2025-4673: net/http: Sensitive headers not cleared on cross-origin redirect in net/http) (update to 1.24.4)

Check warning on line 3 in go.mod

View check run for this annotation

Codacy Production / Codacy Static Code Analysis

go.mod#L3

Insecure dependency golang/stdlib@v1.24.1 (CVE-2025-47906: os/exec: Unexpected paths returned from LookPath in os/exec) (update to 1.24.6)

Check warning on line 3 in go.mod

View check run for this annotation

Codacy Production / Codacy Static Code Analysis

go.mod#L3

Insecure dependency golang/stdlib@v1.24.1 (CVE-2025-47907: database/sql: Postgres Scan Race Condition) (update to 1.24.6)

require github.com/spf13/cobra v1.9.1

require (
github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421 // indirect
github.com/modern-go/reflect2 v1.0.2 // indirect
)

require (
github.com/inconshreveable/mousetrap v1.1.0 // indirect
github.com/json-iterator/go v1.1.12
github.com/spf13/pflag v1.0.6 // indirect
)
22 changes: 22 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
github.com/cpuguy83/go-md2man/v2 v2.0.6/go.mod h1:oOW0eioCTA6cOiMLiUPZOpcVxMig6NIQQ7OS05n1F4g=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8=
github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw=
github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM=
github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo=
github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421 h1:ZqeYNhU3OHLH3mGKHDcjJRFFRrJa6eAM5H+CtDdOsPc=
github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9Gz0M=
github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
github.com/spf13/cobra v1.9.1 h1:CXSaggrXdbHK9CF+8ywj8Amf7PBRmPCOJugH954Nnlo=
github.com/spf13/cobra v1.9.1/go.mod h1:nDyEzZ8ogv936Cinf6g1RU9MRY64Ir93oCnqb9wxYW0=
github.com/spf13/pflag v1.0.6 h1:jFzHGLGAlb3ruxLB8MhbI6A8+AQX/2eW4qeyNZXNp2o=
github.com/spf13/pflag v1.0.6/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
59 changes: 59 additions & 0 deletions main.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
package main

import (
"fmt"
"os"
"paas/pkg/argocd"
"paas/pkg/datadog"
"time"

"github.com/spf13/cobra"
)

const (
downtimeDuration = 5 * time.Minute
)

var (
appName string

syncCommand = &cobra.Command{
Use: "sync",
Short: "sync an application with argocd",
RunE: func(cmd *cobra.Command, args []string) error {
app := datadog.NewDatadogApp(datadog.WithName(appName), datadog.WithStartDate(time.Now()), datadog.WithEndDate(time.Now().Add(downtimeDuration)))

if err := app.ActivateDowntime(); err != nil {
return err
}

argoApp := argocd.NewArgocdAppHandler()

if err := argoApp.Sync(&argocd.ArgocdAppReq{Name: appName}); err != nil {
return fmt.Errorf("error while syncing argocd %s app, %w", appName, err)
}

if err := app.RemoveDownTime(); err != nil {
return err
}

return nil
},
}
)

func initSyncCommand() *cobra.Command {
syncCommand.Flags().StringVarP(&appName, "app", "a", "", "name of the application to sync")
syncCommand.MarkFlagRequired("app")

return syncCommand
}

func main() {
cmd := initSyncCommand()

if err := cmd.Execute(); err != nil {
fmt.Println(err.Error())
os.Exit(1)
}
}
29 changes: 29 additions & 0 deletions pkg/argocd/application.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
package argocd

import "fmt"

type (
ArgocdApp interface {
Sync(req *ArgocdAppReq) error
}

ArgocdAppReq struct {
Name string
}

argocdAppHandler struct{}
)

func NewArgocdAppHandler() ArgocdApp {
return &argocdAppHandler{}
}

func (a *argocdAppHandler) Sync(req *ArgocdAppReq) error {
if req.Name == "" {
return fmt.Errorf("no application name specified")
}

// Call argocd...

return nil
}
103 changes: 103 additions & 0 deletions pkg/datadog/application.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,103 @@
package datadog

import (
"encoding/json"
"fmt"
"time"
)

type (
DatadogApp interface {
Get() *DatadogAppBody
ActivateDowntime() error
RemoveDownTime() error
}

DatadogAppBody struct {
Name string
Downtime time.Time
}

datadogAppHandler struct {
Name string
StartDate time.Time
EndDate time.Time
}

Option func(*datadogAppHandler)
)

func NewDatadogApp(opts ...Option) DatadogApp {
app := &datadogAppHandler{}
for _, opt := range opts {
opt(app)
}

return app
}

func WithName(name string) Option {
return func(d *datadogAppHandler) {
d.Name = name
}
}

func WithStartDate(start time.Time) Option {
return func(d *datadogAppHandler) {
d.StartDate = start
}
}

func WithEndDate(end time.Time) Option {
return func(d *datadogAppHandler) {
d.EndDate = end
}
}

func (d *datadogAppHandler) Get() *DatadogAppBody {
return &DatadogAppBody{Name: d.Name, Downtime: d.StartDate}
}

func (d *datadogAppHandler) ActivateDowntime() error {
remoteApp := d.Get()
if remoteApp.Downtime.Unix() != 0 {
fmt.Printf("%s app already got a downtime", d.Name)
return nil
}

if d.Name == "" {
return fmt.Errorf("no app name specified")
}

if d.EndDate.Before(d.StartDate) {
return fmt.Errorf("end date is before start date")
}

_, err := d.Marshal()
if err != nil {
return err
}

// Do datadog call

return nil
}

func (d *datadogAppHandler) RemoveDownTime() error {
remoteApp := d.Get()
if remoteApp.Downtime.Unix() == 0 {
fmt.Printf("no downtime specified for %s, skipping", d.Name)
return nil
}

return nil
}

func (d *datadogAppHandler) Marshal() ([]byte, error) {
content, err := json.Marshal(d)
if err != nil {
return nil, fmt.Errorf("unable to parse datadog downtime request, %w", err)
}

return content, nil
}