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() }