diff --git a/.gitignore b/.gitignore
index ec4ade1..9b90426 100644
--- a/.gitignore
+++ b/.gitignore
@@ -42,11 +42,7 @@ go.work
# Reference: https://intellij-support.jetbrains.com/hc/en-us/articles/206544839
# User-specific stuff
-.idea/**/workspace.xml
-.idea/**/tasks.xml
-.idea/**/usage.statistics.xml
-.idea/**/dictionaries
-.idea/**/shelf
+.idea/
# AWS User-specific
.idea/**/aws.xml
diff --git a/.idea/.gitignore b/.idea/.gitignore
deleted file mode 100644
index 13566b8..0000000
--- a/.idea/.gitignore
+++ /dev/null
@@ -1,8 +0,0 @@
-# Default ignored files
-/shelf/
-/workspace.xml
-# Editor-based HTTP Client requests
-/httpRequests/
-# Datasource local storage ignored files
-/dataSources/
-/dataSources.local.xml
diff --git a/.idea/discord.xml b/.idea/discord.xml
deleted file mode 100644
index d8e9561..0000000
--- a/.idea/discord.xml
+++ /dev/null
@@ -1,7 +0,0 @@
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/.idea/misc.xml b/.idea/misc.xml
deleted file mode 100644
index 639900d..0000000
--- a/.idea/misc.xml
+++ /dev/null
@@ -1,6 +0,0 @@
-
-
-
-
-
-
\ No newline at end of file
diff --git a/.idea/modules.xml b/.idea/modules.xml
deleted file mode 100644
index b6d5258..0000000
--- a/.idea/modules.xml
+++ /dev/null
@@ -1,8 +0,0 @@
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/.idea/vcs.xml b/.idea/vcs.xml
deleted file mode 100644
index 94a25f7..0000000
--- a/.idea/vcs.xml
+++ /dev/null
@@ -1,6 +0,0 @@
-
-
-
-
-
-
\ No newline at end of file
diff --git a/Dockerfile b/Dockerfile
index 19f9eb2..83eee55 100644
--- a/Dockerfile
+++ b/Dockerfile
@@ -1,6 +1,4 @@
-FROM golang:1.22-alpine3.19 as builder
-
-ENV GOOS=linux
+FROM --platform=$BUILDPLATFORM golang:1.22-alpine3.19 as builder
RUN apk --no-cache add ca-certificates
RUN apk add --no-cache tzdata
@@ -9,12 +7,12 @@ WORKDIR /app
COPY go.mod ./
COPY go.sum ./
-
RUN go mod download
COPY . ./
-
-RUN go build -o /rincon
+ARG TARGETOS
+ARG TARGETARCH
+RUN GOOS=$TARGETOS GOARCH=$TARGETARCH go build -o /rincon
##
## Deploy
diff --git a/LICENSE b/LICENSE
new file mode 100644
index 0000000..fa8c050
--- /dev/null
+++ b/LICENSE
@@ -0,0 +1,21 @@
+MIT License
+
+Copyright (c) 2024 Bharat Kathi
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
diff --git a/api/main.go b/api/main.go
index 111982f..b4b85f6 100644
--- a/api/main.go
+++ b/api/main.go
@@ -50,7 +50,7 @@ func AuthMiddleware() gin.HandlerFunc {
payload, _ := base64.StdEncoding.DecodeString(auth[1])
pair := strings.SplitN(string(payload), ":", 2)
if len(pair) != 2 || pair[0] != config.AuthUser || pair[1] != config.AuthPassword {
- c.AbortWithStatusJSON(401, gin.H{"message": "Request not authorized"})
+ c.AbortWithStatusJSON(401, gin.H{"message": "Invalid credentials"})
return
}
}
diff --git a/database/db.go b/database/db.go
index c00dbb4..5cd64fd 100644
--- a/database/db.go
+++ b/database/db.go
@@ -22,19 +22,21 @@ func InitializeDB() {
return
}
if err != nil {
- if dbRetries < 10 {
+ if dbRetries < 5 {
dbRetries++
utils.SugarLogger.Errorln("Failed to connect database, retrying in 5s... ")
time.Sleep(time.Second * 5)
InitializeDB()
} else {
- utils.SugarLogger.Fatalln("Failed to connect database after 10 attempts, terminating program...")
+ utils.SugarLogger.Errorln("Failed to connect database after 5 attempts, defaulting to local storage")
+ config.StorageMode = "local"
+ return
}
} else {
utils.SugarLogger.Infoln("Connected to database")
- err := db.AutoMigrate(&model.Service{}, &model.ServiceDependency{}, &model.Route{})
+ err = db.AutoMigrate(&model.Service{}, &model.ServiceDependency{}, &model.Route{})
if err != nil {
- utils.SugarLogger.Fatalln("AutoMigration failed", err)
+ utils.SugarLogger.Errorln("AutoMigration failed", err)
}
utils.SugarLogger.Infoln("AutoMigration complete")
DB = db
diff --git a/docker-compose.yml b/docker-compose.yml
index 956643e..6892de7 100644
--- a/docker-compose.yml
+++ b/docker-compose.yml
@@ -2,7 +2,7 @@ version: "3.9"
services:
postgres:
- image: postgres:14.1-alpine
+ image: postgres:16-alpine
restart: unless-stopped
environment:
POSTGRES_DB: rincon
diff --git a/go.mod b/go.mod
index 85fcc7b..bbd3c64 100644
--- a/go.mod
+++ b/go.mod
@@ -8,13 +8,26 @@ require (
)
require (
+ dario.cat/mergo v1.0.0 // indirect
filippo.io/edwards25519 v1.1.0 // indirect
+ github.com/Azure/go-ansiterm v0.0.0-20210617225240-d185dfc1b5a1 // indirect
+ github.com/Microsoft/go-winio v0.6.1 // indirect
+ github.com/Microsoft/hcsshim v0.11.4 // indirect
github.com/bytedance/sonic v1.11.6 // indirect
github.com/bytedance/sonic/loader v0.1.1 // indirect
+ github.com/cenkalti/backoff/v4 v4.2.1 // indirect
github.com/cloudwego/base64x v0.1.4 // indirect
github.com/cloudwego/iasm v0.2.0 // indirect
+ github.com/containerd/containerd v1.7.15 // indirect
+ github.com/containerd/log v0.1.0 // indirect
github.com/coreos/go-semver v0.3.0 // indirect
- github.com/coreos/go-systemd/v22 v22.3.2 // indirect
+ github.com/coreos/go-systemd/v22 v22.5.0 // indirect
+ github.com/cpuguy83/dockercfg v0.3.1 // indirect
+ github.com/distribution/reference v0.5.0 // indirect
+ github.com/docker/docker v25.0.5+incompatible // indirect
+ github.com/docker/go-connections v0.5.0 // indirect
+ github.com/docker/go-units v0.5.0 // indirect
+ github.com/felixge/httpsnoop v1.0.4 // indirect
github.com/gabriel-vasile/mimetype v1.4.3 // indirect
github.com/gin-contrib/cors v1.7.2 // indirect
github.com/gin-contrib/sse v0.1.0 // indirect
@@ -22,6 +35,9 @@ require (
github.com/go-co-op/gocron v1.37.0 // indirect
github.com/go-co-op/gocron-etcd-elector v0.0.0-20240205030445-720b1270dfa2 // indirect
github.com/go-co-op/gocron/v2 v2.5.0 // indirect
+ github.com/go-logr/logr v1.4.1 // indirect
+ github.com/go-logr/stdr v1.2.2 // indirect
+ github.com/go-ole/go-ole v1.2.6 // indirect
github.com/go-playground/locales v0.14.1 // indirect
github.com/go-playground/universal-translator v0.18.1 // indirect
github.com/go-playground/validator/v10 v10.20.0 // indirect
@@ -29,7 +45,7 @@ require (
github.com/go-sql-driver/mysql v1.8.1 // indirect
github.com/goccy/go-json v0.10.2 // indirect
github.com/gogo/protobuf v1.3.2 // indirect
- github.com/golang/protobuf v1.5.3 // indirect
+ github.com/golang/protobuf v1.5.4 // indirect
github.com/google/uuid v1.6.0 // indirect
github.com/jackc/pgpassfile v1.0.0 // indirect
github.com/jackc/pgservicefile v0.0.0-20231201235250-de7065d80cb9 // indirect
@@ -39,29 +55,55 @@ require (
github.com/jinzhu/now v1.1.5 // indirect
github.com/jonboulle/clockwork v0.4.0 // indirect
github.com/json-iterator/go v1.1.12 // indirect
+ github.com/klauspost/compress v1.16.0 // indirect
github.com/klauspost/cpuid/v2 v2.2.7 // indirect
github.com/leodido/go-urn v1.4.0 // indirect
+ github.com/lufia/plan9stats v0.0.0-20211012122336-39d0f177ccd0 // indirect
+ github.com/magiconair/properties v1.8.7 // indirect
github.com/mattn/go-colorable v0.1.13 // indirect
github.com/mattn/go-isatty v0.0.20 // indirect
+ github.com/moby/patternmatcher v0.6.0 // indirect
+ github.com/moby/sys/sequential v0.5.0 // indirect
+ github.com/moby/sys/user v0.1.0 // indirect
+ github.com/moby/term v0.5.0 // indirect
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
github.com/modern-go/reflect2 v1.0.2 // indirect
+ github.com/morikuni/aec v1.0.0 // indirect
+ github.com/opencontainers/go-digest v1.0.0 // indirect
+ github.com/opencontainers/image-spec v1.1.0 // indirect
github.com/pelletier/go-toml/v2 v2.2.2 // indirect
github.com/pkg/errors v0.9.1 // indirect
+ github.com/power-devops/perfstat v0.0.0-20210106213030-5aafc221ea8c // indirect
github.com/robfig/cron/v3 v3.0.1 // indirect
+ github.com/shirou/gopsutil/v3 v3.23.12 // indirect
+ github.com/shoenig/go-m1cpu v0.1.6 // indirect
+ github.com/sirupsen/logrus v1.9.3 // indirect
+ github.com/testcontainers/testcontainers-go v0.31.0 // indirect
+ github.com/testcontainers/testcontainers-go/modules/mysql v0.31.0 // indirect
+ github.com/testcontainers/testcontainers-go/modules/postgres v0.31.0 // indirect
+ github.com/tklauser/go-sysconf v0.3.12 // indirect
+ github.com/tklauser/numcpus v0.6.1 // indirect
github.com/twitchyliquid64/golang-asm v0.15.1 // indirect
github.com/ugorji/go/codec v1.2.12 // indirect
+ github.com/yusufpapurcu/wmi v1.2.3 // indirect
go.etcd.io/etcd/api/v3 v3.5.12 // indirect
go.etcd.io/etcd/client/pkg/v3 v3.5.12 // indirect
go.etcd.io/etcd/client/v3 v3.5.12 // indirect
+ go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.49.0 // indirect
+ go.opentelemetry.io/otel v1.24.0 // indirect
+ go.opentelemetry.io/otel/metric v1.24.0 // indirect
+ go.opentelemetry.io/otel/trace v1.24.0 // indirect
go.uber.org/atomic v1.9.0 // indirect
go.uber.org/multierr v1.11.0 // indirect
golang.org/x/arch v0.8.0 // indirect
golang.org/x/crypto v0.23.0 // indirect
golang.org/x/exp v0.0.0-20240416160154-fe59bbe5cc7f // indirect
+ golang.org/x/mod v0.17.0 // indirect
golang.org/x/net v0.25.0 // indirect
golang.org/x/sync v0.7.0 // indirect
golang.org/x/sys v0.20.0 // indirect
golang.org/x/text v0.15.0 // indirect
+ golang.org/x/tools v0.20.0 // indirect
google.golang.org/genproto v0.0.0-20230822172742-b8732ec3820d // indirect
google.golang.org/genproto/googleapis/api v0.0.0-20230822172742-b8732ec3820d // indirect
google.golang.org/genproto/googleapis/rpc v0.0.0-20230822172742-b8732ec3820d // indirect
diff --git a/go.sum b/go.sum
index 64d05b6..5f4edff 100644
--- a/go.sum
+++ b/go.sum
@@ -1,23 +1,50 @@
+dario.cat/mergo v1.0.0 h1:AGCNq9Evsj31mOgNPcLyXc+4PNABt905YmuqPYYpBWk=
+dario.cat/mergo v1.0.0/go.mod h1:uNxQE+84aUszobStD9th8a29P2fMDhsBdgRYvZOxGmk=
filippo.io/edwards25519 v1.1.0 h1:FNf4tywRC1HmFuKW5xopWpigGjJKiJSV0Cqo0cJWDaA=
filippo.io/edwards25519 v1.1.0/go.mod h1:BxyFTGdWcka3PhytdK4V28tE5sGfRvvvRV7EaN4VDT4=
+github.com/Azure/go-ansiterm v0.0.0-20210617225240-d185dfc1b5a1 h1:UQHMgLO+TxOElx5B5HZ4hJQsoJ/PvUvKRhJHDQXO8P8=
+github.com/Azure/go-ansiterm v0.0.0-20210617225240-d185dfc1b5a1/go.mod h1:xomTg63KZ2rFqZQzSB4Vz2SUXa1BpHTVz9L5PTmPC4E=
+github.com/Microsoft/go-winio v0.6.1 h1:9/kr64B9VUZrLm5YYwbGtUJnMgqWVOdUAXu6Migciow=
+github.com/Microsoft/go-winio v0.6.1/go.mod h1:LRdKpFKfdobln8UmuiYcKPot9D2v6svN5+sAH+4kjUM=
+github.com/Microsoft/hcsshim v0.11.4 h1:68vKo2VN8DE9AdN4tnkWnmdhqdbpUFM8OF3Airm7fz8=
+github.com/Microsoft/hcsshim v0.11.4/go.mod h1:smjE4dvqPX9Zldna+t5FG3rnoHhaB7QYxPRqGcpAD9w=
github.com/bytedance/sonic v1.11.6 h1:oUp34TzMlL+OY1OUWxHqsdkgC/Zfc85zGqw9siXjrc0=
github.com/bytedance/sonic v1.11.6/go.mod h1:LysEHSvpvDySVdC2f87zGWf6CIKJcAvqab1ZaiQtds4=
github.com/bytedance/sonic/loader v0.1.1 h1:c+e5Pt1k/cy5wMveRDyk2X4B9hF4g7an8N3zCYjJFNM=
github.com/bytedance/sonic/loader v0.1.1/go.mod h1:ncP89zfokxS5LZrJxl5z0UJcsk4M4yY2JpfqGeCtNLU=
+github.com/cenkalti/backoff/v4 v4.2.1 h1:y4OZtCnogmCPw98Zjyt5a6+QwPLGkiQsYW5oUqylYbM=
+github.com/cenkalti/backoff/v4 v4.2.1/go.mod h1:Y3VNntkOUPxTVeUxJ/G5vcM//AlwfmyYozVcomhLiZE=
github.com/cloudwego/base64x v0.1.4 h1:jwCgWpFanWmN8xoIUHa2rtzmkd5J2plF/dnLS6Xd/0Y=
github.com/cloudwego/base64x v0.1.4/go.mod h1:0zlkT4Wn5C6NdauXdJRhSKRlJvmclQ1hhJgA0rcu/8w=
github.com/cloudwego/iasm v0.2.0 h1:1KNIy1I1H9hNNFEEH3DVnI4UujN+1zjpuk6gwHLTssg=
github.com/cloudwego/iasm v0.2.0/go.mod h1:8rXZaNYT2n95jn+zTI1sDr+IgcD2GVs0nlbbQPiEFhY=
+github.com/containerd/containerd v1.7.15 h1:afEHXdil9iAm03BmhjzKyXnnEBtjaLJefdU7DV0IFes=
+github.com/containerd/containerd v1.7.15/go.mod h1:ISzRRTMF8EXNpJlTzyr2XMhN+j9K302C21/+cr3kUnY=
+github.com/containerd/log v0.1.0 h1:TCJt7ioM2cr/tfR8GPbGf9/VRAX8D2B4PjzCpfX540I=
+github.com/containerd/log v0.1.0/go.mod h1:VRRf09a7mHDIRezVKTRCrOq78v577GXq3bSa3EhrzVo=
github.com/coreos/go-semver v0.3.0 h1:wkHLiw0WNATZnSG7epLsujiMCgPAc9xhjJ4tgnAxmfM=
github.com/coreos/go-semver v0.3.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk=
github.com/coreos/go-systemd/v22 v22.3.2 h1:D9/bQk5vlXQFZ6Kwuu6zaiXJ9oTPe68++AzAJc1DzSI=
github.com/coreos/go-systemd/v22 v22.3.2/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc=
+github.com/coreos/go-systemd/v22 v22.5.0/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc=
+github.com/cpuguy83/dockercfg v0.3.1 h1:/FpZ+JaygUR/lZP2NlFI2DVfrOEMAIKP5wWEJdoYe9E=
+github.com/cpuguy83/dockercfg v0.3.1/go.mod h1:sugsbF4//dDlL/i+S+rtpIWp+5h0BHJHfjj5/jFyUJc=
github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
+github.com/distribution/reference v0.5.0 h1:/FUIFXtfc/x2gpa5/VGfiGLuOIdYa1t65IKK2OFGvA0=
+github.com/distribution/reference v0.5.0/go.mod h1:BbU0aIcezP1/5jX/8MP0YiH4SdvB5Y4f/wlDRiLyi3E=
+github.com/docker/docker v25.0.5+incompatible h1:UmQydMduGkrD5nQde1mecF/YnSbTOaPeFIeP5C4W+DE=
+github.com/docker/docker v25.0.5+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk=
+github.com/docker/go-connections v0.5.0 h1:USnMq7hx7gwdVZq1L49hLXaFtUdTADjXGp+uj1Br63c=
+github.com/docker/go-connections v0.5.0/go.mod h1:ov60Kzw0kKElRwhNs9UlUHAE/F9Fe6GLaXnqyDdmEXc=
+github.com/docker/go-units v0.5.0 h1:69rxXcBk27SvSaaxTtLh/8llcHD8vYHT7WSdRZ/jvr4=
+github.com/docker/go-units v0.5.0/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk=
github.com/fatih/color v1.16.0 h1:zmkK9Ngbjj+K0yRhTVONQh1p/HknKYSlNT+vZCzyokM=
github.com/fatih/color v1.16.0/go.mod h1:fL2Sau1YI5c0pdGEVCbKQbLXB6edEj1ZgiY4NijnWvE=
+github.com/felixge/httpsnoop v1.0.4 h1:NFTV2Zj1bL4mc9sqWACXbQFVBBg2W3GPvqp8/ESS2Wg=
+github.com/felixge/httpsnoop v1.0.4/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U=
github.com/gabriel-vasile/mimetype v1.4.3 h1:in2uUcidCuFcDKtdcBxlR0rJ1+fsokWf+uqxgUFjbI0=
github.com/gabriel-vasile/mimetype v1.4.3/go.mod h1:d8uq/6HKRL6CGdk+aubisF/M5GcPfT7nKyLpA0lbSSk=
github.com/gin-contrib/cors v1.7.2 h1:oLDHxdg8W/XDoN/8zamqk/Drgt4oVZDvaV0YmvVICQw=
@@ -32,6 +59,13 @@ github.com/go-co-op/gocron-etcd-elector v0.0.0-20240205030445-720b1270dfa2 h1:EK
github.com/go-co-op/gocron-etcd-elector v0.0.0-20240205030445-720b1270dfa2/go.mod h1:ril0wisd5mNcj8Tc8/jhoo+RWvJXVplCeYatICh2k04=
github.com/go-co-op/gocron/v2 v2.5.0 h1:ff/TJX9GdTJBDL1il9cyd/Sj3WnS+BB7ZzwHKSNL5p8=
github.com/go-co-op/gocron/v2 v2.5.0/go.mod h1:ckPQw96ZuZLRUGu88vVpd9a6d9HakI14KWahFZtGvNw=
+github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A=
+github.com/go-logr/logr v1.4.1 h1:pKouT5E8xu9zeFC39JXRDukb6JFQPXM5p5I91188VAQ=
+github.com/go-logr/logr v1.4.1/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY=
+github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag=
+github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE=
+github.com/go-ole/go-ole v1.2.6 h1:/Fpf6oFPoeFik9ty7siob0G6Ke8QvQEuVcuChpwXzpY=
+github.com/go-ole/go-ole v1.2.6/go.mod h1:pprOEPIfldk/42T2oK7lQ4v4JSDwmV0As9GaiUsvbm0=
github.com/go-playground/locales v0.14.1 h1:EWaQ/wswjilfKLTECiXz7Rh+3BjFhfDFKv/oXslEjJA=
github.com/go-playground/locales v0.14.1/go.mod h1:hxrqLVvrK65+Rwrd5Fc6F2O76J/NuW9t0sjnWqG1slY=
github.com/go-playground/universal-translator v0.18.1 h1:Bcnm0ZwsGyWbCzImXv+pAJnYK9S473LQFuzCbDbfSFY=
@@ -51,7 +85,12 @@ github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69
github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk=
github.com/golang/protobuf v1.5.3 h1:KhyjKVUg7Usr/dYsdSqoFveMYd5ko72D+zANwlG1mmg=
github.com/golang/protobuf v1.5.3/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY=
+github.com/golang/protobuf v1.5.4 h1:i7eJL8qZTpSEXOPTxNKhASYpMn+8e5Q6AdndVa1dWek=
+github.com/golang/protobuf v1.5.4/go.mod h1:lnTiLA8Wa4RWRcIUkrtSVa5nRhsEGBg48fD6rSs7xps=
github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
+github.com/google/go-cmp v0.5.6/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
+github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
+github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
github.com/google/uuid v1.4.0 h1:MtMxsa51/r9yyhkyLsVeVt0B+BGQZzpQiTQ4eHZ8bc4=
github.com/google/uuid v1.4.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
@@ -75,6 +114,8 @@ github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnr
github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo=
github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8=
github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
+github.com/klauspost/compress v1.16.0 h1:iULayQNOReoYUe+1qtKOqw9CwJv3aNQu8ivo7lw1HU4=
+github.com/klauspost/compress v1.16.0/go.mod h1:ntbaceVETuRiXiv4DpjP66DpAtAGkEQskQzEyD//IeE=
github.com/klauspost/cpuid/v2 v2.0.9/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg=
github.com/klauspost/cpuid/v2 v2.2.7 h1:ZWSB3igEs+d0qvnxR/ZBzXVmxkgt8DdzP6m9pfuVLDM=
github.com/klauspost/cpuid/v2 v2.2.7/go.mod h1:Lcz8mBdAVJIBVzewtcLocK12l3Y+JytZYpaMropDUws=
@@ -87,16 +128,34 @@ github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
github.com/leodido/go-urn v1.4.0 h1:WT9HwE9SGECu3lg4d/dIA+jxlljEa1/ffXKmRjqdmIQ=
github.com/leodido/go-urn v1.4.0/go.mod h1:bvxc+MVxLKB4z00jd1z+Dvzr47oO32F/QSNjSBOlFxI=
+github.com/lufia/plan9stats v0.0.0-20211012122336-39d0f177ccd0 h1:6E+4a0GO5zZEnZ81pIr0yLvtUWk2if982qA3F3QD6H4=
+github.com/lufia/plan9stats v0.0.0-20211012122336-39d0f177ccd0/go.mod h1:zJYVVT2jmtg6P3p1VtQj7WsuWi/y4VnjVBn7F8KPB3I=
+github.com/magiconair/properties v1.8.7 h1:IeQXZAiQcpL9mgcAe1Nu6cX9LLw6ExEHKjN0VQdvPDY=
+github.com/magiconair/properties v1.8.7/go.mod h1:Dhd985XPs7jluiymwWYZ0G4Z61jb3vdS329zhj2hYo0=
github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA=
github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg=
github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM=
github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY=
github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
+github.com/moby/patternmatcher v0.6.0 h1:GmP9lR19aU5GqSSFko+5pRqHi+Ohk1O69aFiKkVGiPk=
+github.com/moby/patternmatcher v0.6.0/go.mod h1:hDPoyOpDY7OrrMDLaYoY3hf52gNCR/YOUYxkhApJIxc=
+github.com/moby/sys/sequential v0.5.0 h1:OPvI35Lzn9K04PBbCLW0g4LcFAJgHsvXsRyewg5lXtc=
+github.com/moby/sys/sequential v0.5.0/go.mod h1:tH2cOOs5V9MlPiXcQzRC+eEyab644PWKGRYaaV5ZZlo=
+github.com/moby/sys/user v0.1.0 h1:WmZ93f5Ux6het5iituh9x2zAG7NFY9Aqi49jjE1PaQg=
+github.com/moby/sys/user v0.1.0/go.mod h1:fKJhFOnsCN6xZ5gSfbM6zaHGgDJMrqt9/reuj4T7MmU=
+github.com/moby/term v0.5.0 h1:xt8Q1nalod/v7BqbG21f8mQPqH+xAaC9C3N3wfWbVP0=
+github.com/moby/term v0.5.0/go.mod h1:8FzsFHVUBGZdbDsJw/ot+X+d5HLUbvklYLJ9uGfcI3Y=
github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg=
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/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/morikuni/aec v1.0.0 h1:nP9CBfwrvYnBRgY6qfDQkygYDmYwOilePFkwzv4dU8A=
+github.com/morikuni/aec v1.0.0/go.mod h1:BbKIizmSmc5MMPqRYbxO4ZU0S0+P200+tUnFx7PXmsc=
+github.com/opencontainers/go-digest v1.0.0 h1:apOUWs51W5PlhuyGyz9FCeeBIOUDA/6nW8Oi/yOhh5U=
+github.com/opencontainers/go-digest v1.0.0/go.mod h1:0JzlMkj0TRzQZfJkVvzbP0HBR3IKzErnv2BNG4W4MAM=
+github.com/opencontainers/image-spec v1.1.0 h1:8SG7/vwALn54lVB/0yZ/MMwhFrPYtpEHQb2IpWsCzug=
+github.com/opencontainers/image-spec v1.1.0/go.mod h1:W4s4sFTMaBeK1BQLXbG4AdM2szdn85PY75RI83NrTrM=
github.com/pelletier/go-toml/v2 v2.2.2 h1:aYUidT7k73Pcl9nb2gScu7NSrKCSHIDE89b3+6Wq+LM=
github.com/pelletier/go-toml/v2 v2.2.2/go.mod h1:1t835xjRzz80PqgE6HHgN2JOsmgYu/h4qDAS4n929Rs=
github.com/pkg/diff v0.0.0-20210226163009-20ebb0f2a09e/go.mod h1:pJLUxLENpZxwdsKMEsNbx1VGcRFpLqf3715MtcvvzbA=
@@ -104,10 +163,19 @@ github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
+github.com/power-devops/perfstat v0.0.0-20210106213030-5aafc221ea8c h1:ncq/mPwQF4JjgDlrVEn3C11VoGHZN7m8qihwgMEtzYw=
+github.com/power-devops/perfstat v0.0.0-20210106213030-5aafc221ea8c/go.mod h1:OmDBASR4679mdNQnz2pUhc2G8CO2JrUAVFDRBDP/hJE=
github.com/robfig/cron/v3 v3.0.1 h1:WdRxkvbJztn8LMz/QEvLN5sBU+xKpSqwwUO1Pjr4qDs=
github.com/robfig/cron/v3 v3.0.1/go.mod h1:eQICP3HwyT7UooqI/z+Ov+PtYAWygg1TEWWzGIFLtro=
github.com/rogpeppe/go-internal v1.6.1/go.mod h1:xXDCJY+GAPziupqXw64V24skbSoqbTEfhy4qGm1nDQc=
github.com/rogpeppe/go-internal v1.8.1/go.mod h1:JeRgkft04UBgHMgCIwADu4Pn6Mtm5d4nPKWu0nJ5d+o=
+github.com/shirou/gopsutil/v3 v3.23.12 h1:z90NtUkp3bMtmICZKpC4+WaknU1eXtp5vtbQ11DgpE4=
+github.com/shirou/gopsutil/v3 v3.23.12/go.mod h1:1FrWgea594Jp7qmjHUUPlJDTPgcsb9mGnXDxavtikzM=
+github.com/shoenig/go-m1cpu v0.1.6 h1:nxdKQNcEB6vzgA2E2bvzKIYRuNj7XNJ4S/aRSwKzFtM=
+github.com/shoenig/go-m1cpu v0.1.6/go.mod h1:1JJMcUBvfNwpq05QDQVAnx3gUHr9IYF7GNg9SUEw2VQ=
+github.com/shoenig/test v0.6.4/go.mod h1:byHiCGXqrVaflBLAMq/srcZIHynQPQgeyvkvXnjqq0k=
+github.com/sirupsen/logrus v1.9.3 h1:dueUQJ1C2q9oE3F7wvmSGAaVtTmUizReu6fjN8uqzbQ=
+github.com/sirupsen/logrus v1.9.3/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo=
@@ -121,6 +189,16 @@ github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o
github.com/stretchr/testify v1.8.2/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo=
github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
+github.com/testcontainers/testcontainers-go v0.31.0 h1:W0VwIhcEVhRflwL9as3dhY6jXjVCA27AkmbnZ+UTh3U=
+github.com/testcontainers/testcontainers-go v0.31.0/go.mod h1:D2lAoA0zUFiSY+eAflqK5mcUx/A5hrrORaEQrd0SefI=
+github.com/testcontainers/testcontainers-go/modules/mysql v0.31.0 h1:790+S8ewZYCbG+o8IiFlZ8ZZ33XbNO6zV9qhU6xhlRk=
+github.com/testcontainers/testcontainers-go/modules/mysql v0.31.0/go.mod h1:REFmO+lSG9S6uSBEwIMZCxeI36uhScjTwChYADeO3JA=
+github.com/testcontainers/testcontainers-go/modules/postgres v0.31.0 h1:isAwFS3KNKRbJMbWv+wolWqOFUECmjYZ+sIRZCIBc/E=
+github.com/testcontainers/testcontainers-go/modules/postgres v0.31.0/go.mod h1:ZNYY8vumNCEG9YI59A9d6/YaMY49uwRhmeU563EzFGw=
+github.com/tklauser/go-sysconf v0.3.12 h1:0QaGUFOdQaIVdPgfITYzaTegZvdCjmYO52cSFAEVmqU=
+github.com/tklauser/go-sysconf v0.3.12/go.mod h1:Ho14jnntGE1fpdOqQEEaiKRpvIavV0hSfmBq8nJbHYI=
+github.com/tklauser/numcpus v0.6.1 h1:ng9scYS7az0Bk4OZLvrNXNSAO2Pxr1XXRAPyjhIx+Fk=
+github.com/tklauser/numcpus v0.6.1/go.mod h1:1XfjsgE2zo8GVw7POkMbHENHzVg3GzmoZ9fESEdAacY=
github.com/twitchyliquid64/golang-asm v0.15.1 h1:SU5vSMR7hnwNxj24w34ZyCi/FmDZTkS4MhqMhdFk5YI=
github.com/twitchyliquid64/golang-asm v0.15.1/go.mod h1:a1lVb/DtPvCB8fslRZhAngC2+aY1QWCk3Cedj/Gdt08=
github.com/ugorji/go/codec v1.2.12 h1:9LC83zGrHhuUA9l16C9AHXAqEV/2wBQ4nkvumAE65EE=
@@ -128,12 +206,22 @@ github.com/ugorji/go/codec v1.2.12/go.mod h1:UNopzCgEMSXjBc6AOMqYvWC1ktqTAfzJZUZ
github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY=
+github.com/yusufpapurcu/wmi v1.2.3 h1:E1ctvB7uKFMOJw3fdOW32DwGE9I7t++CRUEMKvFoFiw=
+github.com/yusufpapurcu/wmi v1.2.3/go.mod h1:SBZ9tNy3G9/m5Oi98Zks0QjeHVDvuK0qfxQmPyzfmi0=
go.etcd.io/etcd/api/v3 v3.5.12 h1:W4sw5ZoU2Juc9gBWuLk5U6fHfNVyY1WC5g9uiXZio/c=
go.etcd.io/etcd/api/v3 v3.5.12/go.mod h1:Ot+o0SWSyT6uHhA56al1oCED0JImsRiU9Dc26+C2a+4=
go.etcd.io/etcd/client/pkg/v3 v3.5.12 h1:EYDL6pWwyOsylrQyLp2w+HkQ46ATiOvoEdMarindU2A=
go.etcd.io/etcd/client/pkg/v3 v3.5.12/go.mod h1:seTzl2d9APP8R5Y2hFL3NVlD6qC/dOT+3kvrqPyTas4=
go.etcd.io/etcd/client/v3 v3.5.12 h1:v5lCPXn1pf1Uu3M4laUE2hp/geOTc5uPcYYsNe1lDxg=
go.etcd.io/etcd/client/v3 v3.5.12/go.mod h1:tSbBCakoWmmddL+BKVAJHa9km+O/E+bumDe9mSbPiqw=
+go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.49.0 h1:jq9TW8u3so/bN+JPT166wjOI6/vQPF6Xe7nMNIltagk=
+go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.49.0/go.mod h1:p8pYQP+m5XfbZm9fxtSKAbM6oIllS7s2AfxrChvc7iw=
+go.opentelemetry.io/otel v1.24.0 h1:0LAOdjNmQeSTzGBzduGe/rU4tZhMwL5rWgtp9Ku5Jfo=
+go.opentelemetry.io/otel v1.24.0/go.mod h1:W7b9Ozg4nkF5tWI5zsXkaKKDjdVjpD4oAt9Qi/MArHo=
+go.opentelemetry.io/otel/metric v1.24.0 h1:6EhoGWWK28x1fbpA4tYTOWBkPefTDQnb8WSGXlc88kI=
+go.opentelemetry.io/otel/metric v1.24.0/go.mod h1:VYhLe1rFfxuTXLgj4CBiyz+9WYBA8pNGJgDcSFRKBco=
+go.opentelemetry.io/otel/trace v1.24.0 h1:CsKnnL4dUAr/0llH9FKuc698G04IrpWV0MQA/Y1YELI=
+go.opentelemetry.io/otel/trace v1.24.0/go.mod h1:HPc3Xr/cOApsBI154IU0OI0HJexz+aw5uPdbs3UCjNU=
go.uber.org/atomic v1.9.0 h1:ECmE8Bn/WFTYwEW/bpKD3M8VtR/zQVbavAoalC1PYyE=
go.uber.org/atomic v1.9.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc=
go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto=
@@ -158,6 +246,8 @@ golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4=
golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
+golang.org/x/mod v0.17.0 h1:zY54UmvipHiNd+pm+m0x9KhZ9hl1/7QNMyxXbc6ICqA=
+golang.org/x/mod v0.17.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c=
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
@@ -178,17 +268,23 @@ golang.org/x/sync v0.7.0 h1:YsImfSBoP9QPYL0xyKJPq0gcaJdG3rInoqxTWbfQu9M=
golang.org/x/sync v0.7.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20190916202348-b4ddaad3f8a3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20201204225414-ed752295db88/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/sys v0.0.0-20210616094352-59db8d763f22/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/sys v0.11.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.14.0 h1:Vz7Qs629MkJkGyHxUlRHizWJRG2j8fbQKjELVSNhy7Q=
golang.org/x/sys v0.14.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
+golang.org/x/sys v0.15.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/sys v0.17.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/sys v0.20.0 h1:Od9JTbYCk261bKm4M/mw7AklTlFYIa0bIp9BgSm1S8Y=
golang.org/x/sys v0.20.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
@@ -213,6 +309,8 @@ golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roY
golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc=
golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU=
+golang.org/x/tools v0.20.0 h1:hz/CVckiOxybQvFw6h7b/q80NTr9IUQb4s1IIzW7KNY=
+golang.org/x/tools v0.20.0/go.mod h1:WvitBU7JJf6A4jOdg4S1tviW9bhUxkgeCui/0JHctQg=
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
diff --git a/scripts/deploy.sh b/scripts/deploy.sh
index a219b25..493f1ae 100755
--- a/scripts/deploy.sh
+++ b/scripts/deploy.sh
@@ -15,4 +15,4 @@ fi
echo "Building container for Rincon v$1"
# Build the docker container
-docker build -t bk1031/rincon:"$1" -t bk1031/rincon:latest --platform linux/amd64,linux/arm64 --push --progress=plain .
\ No newline at end of file
+docker build -t bk1031/rincon:"$1" -t bk1031/rincon:latest --platform linux/amd64,linux/arm64,linux/arm/v7,linux/arm/v6 --push --progress=plain .
\ No newline at end of file
diff --git a/service/main_test.go b/service/main_test.go
index dd92561..623d86e 100644
--- a/service/main_test.go
+++ b/service/main_test.go
@@ -1,16 +1,110 @@
package service
import (
+ "context"
+ "github.com/testcontainers/testcontainers-go"
+ "github.com/testcontainers/testcontainers-go/modules/mysql"
+ "github.com/testcontainers/testcontainers-go/modules/postgres"
+ "github.com/testcontainers/testcontainers-go/wait"
+ "log"
"os"
+ "rincon/config"
"rincon/database"
+ "rincon/model"
"rincon/utils"
"testing"
+ "time"
)
func TestMain(m *testing.M) {
utils.InitializeLogger()
utils.VerifyConfig()
database.InitializeLocal()
+
+ // Test SQL connection failure before spinning up testcontainers
+ database.InitializeDB()
+ config.DatabaseDriver = "postgres"
+ database.InitializeDB()
+
+ // testcontainers time
+ ctx := context.Background()
+ ms := InitializeMysql(ctx)
+ pg := InitializePostgres(ctx)
+ defer func() {
+ if err := pg.Terminate(ctx); err != nil {
+ log.Fatalf("failed to terminate container: %s", err)
+ }
+ if err := ms.Terminate(ctx); err != nil {
+ log.Fatalf("failed to terminate container: %s", err)
+ }
+ }()
+
exitVal := m.Run()
os.Exit(exitVal)
}
+
+func InitializePostgres(ctx context.Context) *postgres.PostgresContainer {
+ config.StorageMode = "sql"
+ config.DatabaseDriver = "postgres"
+ config.DatabaseHost = "localhost"
+ config.DatabaseName = "rincon"
+ config.DatabaseUser = "postgres"
+ config.DatabasePassword = "postgres"
+ postgresContainer, err := postgres.RunContainer(ctx,
+ testcontainers.WithImage("docker.io/postgres:16-alpine"),
+ postgres.WithDatabase(config.DatabaseName),
+ postgres.WithUsername(config.DatabaseUser),
+ postgres.WithPassword(config.DatabasePassword),
+ testcontainers.WithWaitStrategy(
+ wait.ForLog("database system is ready to accept connections").
+ WithOccurrence(2).
+ WithStartupTimeout(5*time.Second)),
+ )
+ if err != nil {
+ log.Fatalf("failed to start container: %s", err)
+ }
+ p, err := postgresContainer.MappedPort(ctx, "5432")
+ if err != nil {
+ log.Fatalf("failed to get mapped port: %s", err)
+ }
+ config.DatabasePort = p.Port()
+ database.InitializeDB()
+ return postgresContainer
+}
+
+func InitializeMysql(ctx context.Context) *mysql.MySQLContainer {
+ config.StorageMode = "sql"
+ config.DatabaseDriver = "mysql"
+ config.DatabaseHost = "localhost"
+ config.DatabaseName = "rincon"
+ config.DatabaseUser = "admin"
+ config.DatabasePassword = "admin"
+ mysqlContainer, err := mysql.RunContainer(ctx,
+ testcontainers.WithImage("mysql:8.3"),
+ mysql.WithDatabase(config.DatabaseName),
+ mysql.WithUsername(config.DatabaseUser),
+ mysql.WithPassword(config.DatabasePassword),
+ )
+ if err != nil {
+ utils.SugarLogger.Fatalf("failed to start container: %s", err)
+ }
+ p, err := mysqlContainer.MappedPort(ctx, "3306")
+ if err != nil {
+ utils.SugarLogger.Fatalf("failed to get mapped port: %s", err)
+ }
+ config.DatabasePort = p.Port()
+ database.InitializeDB()
+ return mysqlContainer
+}
+
+func ResetLocalDB() {
+ config.StorageMode = "local"
+ database.Local.Services = make([]model.Service, 0)
+ database.Local.Routes = make([]model.Route, 0)
+}
+
+func ResetSQLDB() {
+ config.StorageMode = "sql"
+ database.DB.Where("1 = 1").Delete(&model.Service{})
+ database.DB.Where("1 = 1").Delete(&model.Route{})
+}
diff --git a/service/route.go b/service/route.go
index 8ae9b01..e59df58 100644
--- a/service/route.go
+++ b/service/route.go
@@ -12,20 +12,35 @@ import (
func GetAllRoutes() []model.Route {
routes := make([]model.Route, 0)
- routes = database.Local.Routes
+ if config.StorageMode == "sql" {
+ database.DB.Find(&routes)
+ } else {
+ routes = database.Local.Routes
+ }
return routes
}
func GetNumRoutes() int {
- return len(database.Local.Routes)
+ if config.StorageMode == "sql" {
+ var count int64
+ database.DB.Model(&model.Route{}).Count(&count)
+ return int(count)
+
+ } else {
+ return len(database.Local.Routes)
+ }
}
func GetRouteByID(id string) model.Route {
var route model.Route
- for _, r := range database.Local.Routes {
- if r.Route == id {
- route = r
- break
+ if config.StorageMode == "sql" {
+ database.DB.Where("route = ?", id).First(&route)
+ } else {
+ for _, r := range database.Local.Routes {
+ if r.Route == id {
+ route = r
+ break
+ }
}
}
return route
@@ -34,9 +49,13 @@ func GetRouteByID(id string) model.Route {
func GetRoutesByServiceName(name string) []model.Route {
name = utils.NormalizeName(name)
routes := make([]model.Route, 0)
- for _, r := range database.Local.Routes {
- if r.ServiceName == name {
- routes = append(routes, r)
+ if config.StorageMode == "sql" {
+ database.DB.Where("service_name = ?", name).Find(&routes)
+ } else {
+ for _, r := range database.Local.Routes {
+ if r.ServiceName == name {
+ routes = append(routes, r)
+ }
}
}
return routes
@@ -66,16 +85,24 @@ func CreateRoute(route model.Route) error {
return nil
}
}
- database.Local.Routes = append(database.Local.Routes, route)
+ if config.StorageMode == "sql" {
+ database.DB.Create(&route)
+ } else {
+ database.Local.Routes = append(database.Local.Routes, route)
+ }
utils.SugarLogger.Infof("route with id %s registered for service %s", route.Route, route.ServiceName)
return nil
}
func DeleteRoute(id string) {
- for i, r := range database.Local.Routes {
- if r.Route == id {
- database.Local.Routes = append(database.Local.Routes[:i], database.Local.Routes[i+1:]...)
- break
+ if config.StorageMode == "sql" {
+ database.DB.Where("route = ?", id).Delete(&model.Route{})
+ } else {
+ for i, r := range database.Local.Routes {
+ if r.Route == id {
+ database.Local.Routes = append(database.Local.Routes[:i], database.Local.Routes[i+1:]...)
+ break
+ }
}
}
utils.SugarLogger.Infof("route with id %s deleted", id)
diff --git a/service/route_test.go b/service/route_test.go
index a7e9276..7de1f8c 100644
--- a/service/route_test.go
+++ b/service/route_test.go
@@ -2,12 +2,12 @@ package service
import (
"rincon/config"
- "rincon/database"
"rincon/model"
"testing"
)
func TestCreateRouteLocal(t *testing.T) {
+ ResetLocalDB()
t.Run("Test No Route", func(t *testing.T) {
route := model.Route{
ServiceName: "Service 1",
@@ -93,8 +93,98 @@ func TestCreateRouteLocal(t *testing.T) {
}
func TestGetRoutesLocal(t *testing.T) {
+ ResetLocalDB()
+ t.Run("Test Get All Routes", func(t *testing.T) {
+ routes := GetAllRoutes()
+ if len(routes) != 0 {
+ t.Errorf("Expected length to be 0")
+ }
+ })
+ t.Run("Test Get Num Routes", func(t *testing.T) {
+ CreateRoute(model.Route{
+ Route: "/test",
+ ServiceName: "Service 1",
+ })
+ num := GetNumRoutes()
+ if num == 0 {
+ t.Errorf("No routes found")
+ }
+ })
+ t.Run("Test Get Route By ID", func(t *testing.T) {
+ route := GetRouteByID("/test")
+ if route.Route != "/test" {
+ t.Errorf("No route found")
+ }
+ })
+ t.Run("Test Get Routes By Service Name", func(t *testing.T) {
+ routes := GetRoutesByServiceName("Service 1")
+ if len(routes) == 0 {
+ t.Errorf("No routes found")
+ }
+ })
+}
+
+func TestCreateRouteSQL(t *testing.T) {
+ ResetSQLDB()
+ t.Run("Test Create Route", func(t *testing.T) {
+ route := model.Route{
+ Route: "/test",
+ ServiceName: "Service 1",
+ }
+ err := CreateRoute(route)
+ if err != nil {
+ t.Errorf("Error when creating route: %v", err)
+ }
+ })
+ t.Run("Test Route Exists 1", func(t *testing.T) {
+ route := model.Route{
+ Route: "/test",
+ ServiceName: "Service 1",
+ }
+ config.OverwriteRoutes = "true"
+ err := CreateRoute(route)
+ if err != nil {
+ t.Errorf("Error when creating route: %v", err)
+ }
+ })
+ t.Run("Test Route Exists 2", func(t *testing.T) {
+ route := model.Route{
+ Route: "/test",
+ ServiceName: "Service 1",
+ }
+ config.OverwriteRoutes = "false"
+ err := CreateRoute(route)
+ if err != nil {
+ t.Errorf("Error when creating route: %v", err)
+ }
+ })
+ t.Run("Test Route Exists 3", func(t *testing.T) {
+ route := model.Route{
+ Route: "/test",
+ ServiceName: "Service 2",
+ }
+ config.OverwriteRoutes = "false"
+ err := CreateRoute(route)
+ if err == nil {
+ t.Errorf("No error when creating route: %v", err)
+ }
+ })
+ t.Run("Test Route Exists 4", func(t *testing.T) {
+ route := model.Route{
+ Route: "/test",
+ ServiceName: "Service 2",
+ }
+ config.OverwriteRoutes = "true"
+ err := CreateRoute(route)
+ if err != nil {
+ t.Errorf("Error when creating route: %v", err)
+ }
+ })
+}
+
+func TestGetRoutesSQL(t *testing.T) {
+ ResetSQLDB()
t.Run("Test Get All Routes", func(t *testing.T) {
- database.Local.Routes = make([]model.Route, 0)
routes := GetAllRoutes()
if len(routes) != 0 {
t.Errorf("Expected length to be 0")
@@ -125,6 +215,7 @@ func TestGetRoutesLocal(t *testing.T) {
}
func TestMatchRoute(t *testing.T) {
+ ResetLocalDB()
CreateService(model.Service{
Name: "Montecito",
Version: "1.4.2",
@@ -186,6 +277,7 @@ func TestMatchRoute(t *testing.T) {
}
func TestPrintRouteGraph(t *testing.T) {
+ ResetLocalDB()
CreateService(model.Service{
Name: "Montecito",
Version: "1.4.2",
diff --git a/service/service.go b/service/service.go
index 9531164..4378a8e 100644
--- a/service/service.go
+++ b/service/service.go
@@ -11,28 +11,48 @@ import (
func GetAllServices() []model.Service {
services := make([]model.Service, 0)
- services = database.Local.Services
+ if config.StorageMode == "sql" {
+ database.DB.Find(&services)
+ } else {
+ services = database.Local.Services
+ }
return services
}
func GetNumServices() int {
- return len(database.Local.Services)
+ if config.StorageMode == "sql" {
+ var count int64
+ database.DB.Model(&model.Service{}).Count(&count)
+ return int(count)
+ } else {
+ return len(database.Local.Services)
+ }
}
func GetNumUniqueServices() int {
- unique := make(map[string]bool)
- for _, s := range database.Local.Services {
- unique[s.Name] = true
+ if config.StorageMode == "sql" {
+ var services []model.Service
+ database.DB.Distinct("name").Find(&services)
+ return len(services)
+ } else {
+ unique := make(map[string]bool)
+ for _, s := range database.Local.Services {
+ unique[s.Name] = true
+ }
+ return len(unique)
}
- return len(unique)
}
func GetServiceByID(id int) model.Service {
var service model.Service
- for _, s := range database.Local.Services {
- if s.ID == id {
- service = s
- break
+ if config.StorageMode == "sql" {
+ database.DB.First(&service, id)
+ } else {
+ for _, s := range database.Local.Services {
+ if s.ID == id {
+ service = s
+ break
+ }
}
}
return service
@@ -40,9 +60,13 @@ func GetServiceByID(id int) model.Service {
func GetServicesByName(name string) []model.Service {
services := make([]model.Service, 0)
- for _, s := range database.Local.Services {
- if s.Name == name {
- services = append(services, s)
+ if config.StorageMode == "sql" {
+ database.DB.Where("name = ?", name).Find(&services)
+ } else {
+ for _, s := range database.Local.Services {
+ if s.Name == name {
+ services = append(services, s)
+ }
}
}
return services
@@ -50,10 +74,14 @@ func GetServicesByName(name string) []model.Service {
func GetServiceByEndpoint(endpoint string) model.Service {
var service model.Service
- for _, s := range database.Local.Services {
- if s.Endpoint == endpoint {
- service = s
- break
+ if config.StorageMode == "sql" {
+ database.DB.Where("endpoint = ?", endpoint).First(&service)
+ } else {
+ for _, s := range database.Local.Services {
+ if s.Endpoint == endpoint {
+ service = s
+ break
+ }
}
}
return service
@@ -70,35 +98,48 @@ func CreateService(service model.Service) (model.Service, error) {
return model.Service{}, fmt.Errorf("service health check cannot be empty")
}
service.Name = utils.NormalizeName(service.Name)
- var newService model.Service
existing := GetServiceByEndpoint(service.Endpoint)
- if existing.Endpoint != "" {
- service.ID = existing.ID
- service.CreatedAt = existing.CreatedAt
- service.UpdatedAt = time.Now()
- for i, s := range database.Local.Services {
- if s.ID == existing.ID {
- database.Local.Services[i] = service
- break
- }
+ if config.StorageMode == "sql" {
+ if existing.Endpoint != "" {
+ service.ID = existing.ID
+ database.DB.Model(&service).Where("endpoint = ?", service.Endpoint).Updates(service)
+ } else {
+ service.ID = utils.GenerateID(0)
+ database.DB.Create(&service)
}
- newService = service
} else {
- service.ID = utils.GenerateID(0)
- service.UpdatedAt = time.Now()
- service.CreatedAt = time.Now()
- database.Local.Services = append(database.Local.Services, service)
- newService = service
+ if existing.Endpoint != "" {
+ service.ID = existing.ID
+ service.CreatedAt = existing.CreatedAt
+ service.UpdatedAt = time.Now()
+ for i, s := range database.Local.Services {
+ if s.ID == existing.ID {
+ database.Local.Services[i] = service
+ break
+ }
+ }
+ } else {
+ service.ID = utils.GenerateID(0)
+ service.UpdatedAt = time.Now()
+ service.CreatedAt = time.Now()
+ database.Local.Services = append(database.Local.Services, service)
+ }
}
+ newService := GetServiceByEndpoint(service.Endpoint)
utils.SugarLogger.Infof("registered service (%d) %s at %s", newService.ID, newService.Name, newService.Endpoint)
return newService, nil
}
func RemoveService(id int) {
- for i, s := range database.Local.Services {
- if s.ID == id {
- database.Local.Services = append(database.Local.Services[:i], database.Local.Services[i+1:]...)
- break
+ if config.StorageMode == "sql" {
+ database.DB.Delete(&model.Service{}, id)
+ return
+ } else {
+ for i, s := range database.Local.Services {
+ if s.ID == id {
+ database.Local.Services = append(database.Local.Services[:i], database.Local.Services[i+1:]...)
+ break
+ }
}
}
}
diff --git a/service/service_test.go b/service/service_test.go
index 18fda9b..690762c 100644
--- a/service/service_test.go
+++ b/service/service_test.go
@@ -8,6 +8,7 @@ import (
)
func TestCreateServiceLocal(t *testing.T) {
+ ResetLocalDB()
t.Run("Test No Name", func(t *testing.T) {
service := model.Service{
Version: "1.0.0",
@@ -100,8 +101,8 @@ func TestCreateServiceLocal(t *testing.T) {
}
func TestGetServicesLocal(t *testing.T) {
+ ResetLocalDB()
t.Run("Test Get All Services 1", func(t *testing.T) {
- database.Local.Services = make([]model.Service, 0)
services := GetAllServices()
if len(services) != 0 {
t.Errorf("Services not empty")
@@ -150,6 +151,113 @@ func TestGetServicesLocal(t *testing.T) {
}
func TestRemoveServiceLocal(t *testing.T) {
+ ResetLocalDB()
+ t.Run("Test Remove Service", func(t *testing.T) {
+ s, _ := CreateService(model.Service{
+ Name: "Service 1",
+ Version: "1.0.0",
+ Endpoint: "http://localhost:8080",
+ HealthCheck: "http://localhost:8080/health",
+ })
+ s, _ = CreateService(s)
+ RemoveService(s.ID)
+ })
+}
+
+func TestCreateServiceSQL(t *testing.T) {
+ ResetSQLDB()
+ t.Run("Test Create Service", func(t *testing.T) {
+ service := model.Service{
+ Name: "Service 1",
+ Version: "1.0.0",
+ Endpoint: "http://localhost:8080",
+ HealthCheck: "http://localhost:8080/health",
+ UpdatedAt: time.Time{},
+ CreatedAt: time.Time{},
+ }
+ s, err := CreateService(service)
+ if err != nil {
+ t.Errorf("Error when creating service: %v", err)
+ }
+ if s.ID == 0 {
+ t.Errorf("Service ID not set")
+ }
+ })
+ t.Run("Test Update Service", func(t *testing.T) {
+ service := model.Service{
+ Name: "Service 1",
+ Version: "1.1.0",
+ Endpoint: "http://localhost:8080",
+ HealthCheck: "http://localhost:8080/health",
+ UpdatedAt: time.Time{},
+ CreatedAt: time.Time{},
+ }
+ s, err := CreateService(service)
+ if err != nil {
+ t.Errorf("Error when creating service: %v", err)
+ }
+ if s.ID == 0 {
+ t.Errorf("Service ID not set")
+ }
+ if s.Version != "1.1.0" {
+ t.Errorf("Service version not updated")
+ }
+ })
+}
+
+func TestGetServicesSQL(t *testing.T) {
+ ResetSQLDB()
+ t.Run("Test Get All Services 1", func(t *testing.T) {
+ database.DB.Where("1 = 1").Delete(&model.Service{})
+ services := GetAllServices()
+ if len(services) != 0 {
+ t.Errorf("Services not empty")
+ }
+ })
+ t.Run("Test Get All Services 2", func(t *testing.T) {
+ _, _ = CreateService(model.Service{
+ Name: "Service 1",
+ Version: "1.0.0",
+ Endpoint: "http://localhost:8080",
+ HealthCheck: "http://localhost:8080/health",
+ })
+ services := GetAllServices()
+ if len(services) == 0 {
+ t.Errorf("Services not 1")
+ }
+ })
+ t.Run("Test Get Service By ID", func(t *testing.T) {
+ s, _ := CreateService(model.Service{
+ Name: "Service 1",
+ Version: "1.0.0",
+ Endpoint: "http://localhost:8081",
+ HealthCheck: "http://localhost:8081/health",
+ })
+ s = GetServiceByID(s.ID)
+ if s.ID == 0 {
+ t.Errorf("Service not found")
+ }
+ })
+ t.Run("Test Get Service By Name", func(t *testing.T) {
+ s := GetServicesByName("service_1")
+ if len(s) != 2 {
+ t.Errorf("Service not found")
+ }
+ })
+ t.Run("Test Get Num Services", func(t *testing.T) {
+ if GetNumServices() != 2 {
+ t.Errorf("Services not found")
+ }
+ })
+ t.Run("Test Get Unique Num Services", func(t *testing.T) {
+ if GetNumUniqueServices() != 1 {
+ t.Errorf("Services not found")
+ }
+ })
+}
+
+func TestRemoveServiceSQL(t *testing.T) {
+ ResetSQLDB()
t.Run("Test Remove Service", func(t *testing.T) {
s, _ := CreateService(model.Service{
Name: "Service 1",
@@ -163,5 +271,6 @@ func TestRemoveServiceLocal(t *testing.T) {
}
func TestRegisterSelf(t *testing.T) {
+ ResetLocalDB()
RegisterSelf()
}