diff --git a/Dockerfile b/Dockerfile index 6e2951e..26056f1 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,38 +1,15 @@ -# Start from the latest golang base image -FROM golang:latest as builder - -# Add Maintainer Info -LABEL maintainer="Borisav Zivanovic " - -# Set the Current Working Directory inside the container +FROM golang:alpine as build_container WORKDIR /app - -# Copy go mod and sum files -COPY go.mod go.sum ./ - - -# Download all dependencies. Dependencies will be cached if the go.mod and go.sum files are not changed +COPY ./go.mod ./go.sum ./ RUN go mod download +COPY ./ . +RUN CGO_ENABLED=0 GOOS=linux go build -a -installsuffix cgo -o configServer . -# Copy everything from the current directory to the Working Directory inside the container -COPY . . - -# Build the Go app -RUN CGO_ENABLED=0 GOOS=linux go build -a -installsuffix cgo -o main . - - - -######## Start a new stage from scratch ####### -FROM alpine:latest - -RUN apk --no-cache add ca-certificates +FROM alpine WORKDIR /root/ +COPY --from=build_container /app/configServer . -EXPOSE 8000 - -# Copy the Pre-built binary file from the previous stage -COPY --from=builder /app/main . +EXPOSE 8080 -# Command to run the executable -CMD ["./main"] \ No newline at end of file +ENTRYPOINT ["./configServer"] \ No newline at end of file diff --git a/go.mod b/go.mod index 11456b5..32724c8 100644 --- a/go.mod +++ b/go.mod @@ -1,21 +1,57 @@ -module github.com/c12s/kuiper +module kuiper go 1.18 require ( - github.com/armon/go-metrics v0.0.0-20180917152333-f0300d1749da // indirect - github.com/fatih/color v1.9.0 // indirect - github.com/google/uuid v1.3.0 // indirect - github.com/hashicorp/consul/api v1.13.0 // indirect - github.com/hashicorp/go-cleanhttp v0.5.1 // indirect - github.com/hashicorp/go-hclog v0.12.0 // indirect - github.com/hashicorp/go-immutable-radix v1.0.0 // indirect - github.com/hashicorp/go-rootcerts v1.0.2 // indirect - github.com/hashicorp/golang-lru v0.5.0 // indirect - github.com/hashicorp/serf v0.9.6 // indirect - github.com/mattn/go-colorable v0.1.6 // indirect - github.com/mattn/go-isatty v0.0.12 // indirect - github.com/mitchellh/go-homedir v1.1.0 // indirect - github.com/mitchellh/mapstructure v1.1.2 // indirect - golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44 // indirect + github.com/gin-gonic/gin v1.9.0 + github.com/google/uuid v1.3.0 + github.com/nats-io/nats.go v1.24.0 + go.etcd.io/etcd/client/v3 v3.5.7 + go.opentelemetry.io/contrib/instrumentation/github.com/gin-gonic/gin/otelgin v0.40.0 + go.opentelemetry.io/otel v1.14.0 + go.opentelemetry.io/otel/exporters/jaeger v1.14.0 + go.opentelemetry.io/otel/sdk v1.14.0 + go.opentelemetry.io/otel/trace v1.14.0 +) + +require ( + github.com/bytedance/sonic v1.8.5 // indirect + github.com/chenzhuoyu/base64x v0.0.0-20221115062448-fe3a3abad311 // indirect + github.com/coreos/go-semver v0.3.0 // indirect + github.com/coreos/go-systemd/v22 v22.3.2 // indirect + github.com/gin-contrib/sse v0.1.0 // indirect + github.com/go-logr/logr v1.2.3 // indirect + github.com/go-logr/stdr v1.2.2 // 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.11.2 // indirect + github.com/goccy/go-json v0.10.1 // indirect + github.com/gogo/protobuf v1.3.2 // indirect + github.com/golang/protobuf v1.5.2 // indirect + github.com/json-iterator/go v1.1.12 // indirect + github.com/klauspost/cpuid/v2 v2.2.4 // indirect + github.com/leodido/go-urn v1.2.2 // indirect + github.com/mattn/go-isatty v0.0.17 // indirect + github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect + github.com/modern-go/reflect2 v1.0.2 // indirect + github.com/nats-io/nats-server/v2 v2.9.15 // indirect + github.com/nats-io/nkeys v0.3.0 // indirect + github.com/nats-io/nuid v1.0.1 // indirect + github.com/pelletier/go-toml/v2 v2.0.7 // indirect + github.com/twitchyliquid64/golang-asm v0.15.1 // indirect + github.com/ugorji/go/codec v1.2.11 // indirect + go.etcd.io/etcd/api/v3 v3.5.7 // indirect + go.etcd.io/etcd/client/pkg/v3 v3.5.7 // indirect + go.uber.org/atomic v1.7.0 // indirect + go.uber.org/multierr v1.6.0 // indirect + go.uber.org/zap v1.17.0 // indirect + golang.org/x/arch v0.3.0 // indirect + golang.org/x/crypto v0.7.0 // indirect + golang.org/x/net v0.8.0 // indirect + golang.org/x/sys v0.6.0 // indirect + golang.org/x/text v0.8.0 // indirect + google.golang.org/genproto v0.0.0-20230110181048-76db0878b65f // indirect + google.golang.org/grpc v1.53.0 // indirect + google.golang.org/protobuf v1.30.0 // indirect + gopkg.in/yaml.v3 v3.0.1 // indirect ) diff --git a/go.sum b/go.sum index 20d0f3c..6e7556e 100644 --- a/go.sum +++ b/go.sum @@ -1,109 +1,179 @@ -github.com/armon/circbuf v0.0.0-20150827004946-bbbad097214e/go.mod h1:3U/XgcO3hCbHZ8TKRvWD2dDTCfh9M9ya+I9JpbB7O8o= -github.com/armon/go-metrics v0.0.0-20180917152333-f0300d1749da h1:8GUt8eRujhVEGZFFEjBj46YV4rDjvGrNxb0KMWYkL2I= -github.com/armon/go-metrics v0.0.0-20180917152333-f0300d1749da/go.mod h1:Q73ZrmVTwzkszR9V5SSuryQ31EELlFMUz1kKyl939pY= -github.com/armon/go-radix v0.0.0-20180808171621-7fddfc383310/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8= -github.com/armon/go-radix v1.0.0/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8= -github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs= +github.com/bytedance/sonic v1.5.0/go.mod h1:ED5hyg4y6t3/9Ku1R6dU/4KyJ48DZ4jPhfY1O2AihPM= +github.com/bytedance/sonic v1.8.5 h1:kjX0/vo5acEQ/sinD/18SkA/lDDUk23F0RcaHvI7omc= +github.com/bytedance/sonic v1.8.5/go.mod h1:i736AoUSYt75HyZLoJW9ERYxcy6eaN6h4BZXU064P/U= +github.com/chenzhuoyu/base64x v0.0.0-20211019084208-fb5309c8db06/go.mod h1:DH46F32mSOjUmXrMHnKwZdA8wcEefY7UVqBKYGjpdQY= +github.com/chenzhuoyu/base64x v0.0.0-20221115062448-fe3a3abad311 h1:qSGYFH7+jGhDF8vLC+iwCD4WpbV1EBDSzWkJODFLams= +github.com/chenzhuoyu/base64x v0.0.0-20221115062448-fe3a3abad311/go.mod h1:b583jCggY9gE99b6G5LEC39OIiVsWj+R97kbl5odCEk= +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/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/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4= -github.com/fatih/color v1.9.0 h1:8xPHl4/q1VyqGIPif1F+1V3Y3lSmrq01EabUW3CoW5s= -github.com/fatih/color v1.9.0/go.mod h1:eQcE1qtQxscV5RaZvpXrrb8Drkc3/DdQ+uUYCNjL+zU= -github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= -github.com/google/go-cmp v0.5.7/go.mod h1:n+brtR0CgQNWTVd5ZUFpTBC8YFBDLK/h/bpaJ8/DtOE= +github.com/gin-contrib/sse v0.1.0 h1:Y/yl/+YNO8GZSjAhjMsSuLt29uWRFHdHYUb5lYOV9qE= +github.com/gin-contrib/sse v0.1.0/go.mod h1:RHrZQHXnP2xjPF+u1gW/2HnVO7nvIa9PG3Gm+fLHvGI= +github.com/gin-gonic/gin v1.9.0 h1:OjyFBKICoexlu99ctXNR2gg+c5pKrKMuyjgARg9qeY8= +github.com/gin-gonic/gin v1.9.0/go.mod h1:W1Me9+hsUSyj3CePGrd1/QrKJMSJ1Tu/0hFEH89961k= +github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= +github.com/go-logr/logr v1.2.3 h1:2DntVwHkVopvECVRSlL5PSo9eG+cAkDCuckLubN+rq0= +github.com/go-logr/logr v1.2.3/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= +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-playground/assert/v2 v2.2.0 h1:JvknZsQTYeFEAhQwI4qEt9cyV5ONwRHC+lYKSsYSR8s= +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= +github.com/go-playground/universal-translator v0.18.1/go.mod h1:xekY+UJKNuX9WP91TpwSH2VMlDf28Uj24BCp08ZFTUY= +github.com/go-playground/validator/v10 v10.11.2 h1:q3SHpufmypg+erIExEKUmsgmhDTyhcJ38oeKGACXohU= +github.com/go-playground/validator/v10 v10.11.2/go.mod h1:NieE624vt4SCTJtD87arVLvdmjPAeV8BQlHtMnw9D7s= +github.com/goccy/go-json v0.10.1 h1:lEs5Ob+oOG/Ze199njvzHbhn6p9T+h64F5hRj69iTTo= +github.com/goccy/go-json v0.10.1/go.mod h1:6MelG93GURQebXPDq3khkgXZkazVtN9CRI+MGFi0w8I= +github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA= +github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q= +github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q= +github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= +github.com/golang/protobuf v1.5.2 h1:ROPKBNFfQgOUMifHyP+KYbvpjbdoFNs+aK7DXlji0Tw= +github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= +github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38= +github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= github.com/google/uuid v1.3.0 h1:t6JiXgmwXMjEs8VusXIJk2BXHsn+wx8BZdTaoZ5fu7I= github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= -github.com/hashicorp/consul/api v1.13.0 h1:2hnLQ0GjQvw7f3O61jMO8gbasZviZTrt9R8WzgiirHc= -github.com/hashicorp/consul/api v1.13.0/go.mod h1:ZlVrynguJKcYr54zGaDbaL3fOvKC9m72FhPvA8T35KQ= -github.com/hashicorp/consul/sdk v0.8.0/go.mod h1:GBvyrGALthsZObzUGsfgHZQDXjg4lOjagTIwIR1vPms= -github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= -github.com/hashicorp/go-cleanhttp v0.5.1 h1:dH3aiDG9Jvb5r5+bYHsikaOUIpcM0xvgMXVoDkXMzJM= -github.com/hashicorp/go-cleanhttp v0.5.1/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80= -github.com/hashicorp/go-hclog v0.12.0 h1:d4QkX8FRTYaKaCZBoXYY8zJX2BXjWxurN/GA2tkrmZM= -github.com/hashicorp/go-hclog v0.12.0/go.mod h1:whpDNt7SSdeAju8AWKIWsul05p54N/39EeqMAyrmvFQ= -github.com/hashicorp/go-immutable-radix v1.0.0 h1:AKDB1HM5PWEA7i4nhcpwOrO2byshxBjXVn/J/3+z5/0= -github.com/hashicorp/go-immutable-radix v1.0.0/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60= -github.com/hashicorp/go-msgpack v0.5.3/go.mod h1:ahLV/dePpqEmjfWmKiqvPkv/twdG7iPBM1vqhUKIvfM= -github.com/hashicorp/go-multierror v1.0.0/go.mod h1:dHtQlpGsu+cZNNAkkCN/P3hoUDHhCYQXV3UM06sGGrk= -github.com/hashicorp/go-multierror v1.1.0/go.mod h1:spPvp8C1qA32ftKqdAHm4hHTbPw+vmowP0z+KUhOZdA= -github.com/hashicorp/go-rootcerts v1.0.2 h1:jzhAVGtqPKbwpyCPELlgNWhE1znq+qwJtW5Oi2viEzc= -github.com/hashicorp/go-rootcerts v1.0.2/go.mod h1:pqUvnprVnM5bf7AOirdbb01K4ccR319Vf4pU3K5EGc8= -github.com/hashicorp/go-sockaddr v1.0.0/go.mod h1:7Xibr9yA9JjQq1JpNB2Vw7kxv8xerXegt+ozgdvDeDU= -github.com/hashicorp/go-syslog v1.0.0/go.mod h1:qPfqrKkXGihmCqbJM2mZgkZGvKG1dFdvsLplgctolz4= -github.com/hashicorp/go-uuid v1.0.0/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= -github.com/hashicorp/go-uuid v1.0.1/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= -github.com/hashicorp/golang-lru v0.5.0 h1:CL2msUPvZTLb5O648aiLNJw3hnBxN2+1Jq8rCOH9wdo= -github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= -github.com/hashicorp/logutils v1.0.0/go.mod h1:QIAnNjmIWmVIIkWDTG1z5v++HQmx9WQRO+LraFDTW64= -github.com/hashicorp/mdns v1.0.4/go.mod h1:mtBihi+LeNXGtG8L9dX59gAEa12BDtBQSp4v/YAJqrc= -github.com/hashicorp/memberlist v0.3.0/go.mod h1:MS2lj3INKhZjWNqd3N0m3J+Jxf3DAOnAH9VT3Sh9MUE= -github.com/hashicorp/serf v0.9.6 h1:uuEX1kLR6aoda1TBttmJQKDLZE1Ob7KN0NPdE7EtCDc= -github.com/hashicorp/serf v0.9.6/go.mod h1:TXZNMjZQijwlDvp+r0b63xZ45H7JmCmgg4gpTwn9UV4= -github.com/kr/pretty v0.2.0/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= -github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= -github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= -github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU= -github.com/mattn/go-colorable v0.1.4/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE= -github.com/mattn/go-colorable v0.1.6 h1:6Su7aK7lXmJ/U79bYtBjLNaha4Fs1Rg9plHpcH+vvnE= -github.com/mattn/go-colorable v0.1.6/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc= -github.com/mattn/go-isatty v0.0.3/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4= -github.com/mattn/go-isatty v0.0.8/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s= -github.com/mattn/go-isatty v0.0.10/go.mod h1:qgIWMr58cqv1PHHyhnkY9lrL7etaEgOFcMEpPG5Rm84= -github.com/mattn/go-isatty v0.0.11/go.mod h1:PhnuNfih5lzO57/f3n+odYbM4JtupLOxQOAqxQCu2WE= -github.com/mattn/go-isatty v0.0.12 h1:wuysRhFDzyxgEmMf5xjvJ2M9dZoWAXNNr5LSBS7uHXY= -github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU= -github.com/miekg/dns v1.1.26/go.mod h1:bPDLeHnStXmXAq1m/Ch/hvfNHr14JKNPMBo3VZKjuso= -github.com/miekg/dns v1.1.41/go.mod h1:p6aan82bvRIyn+zDIv9xYNUpwa73JcSh9BKwknJysuI= -github.com/mitchellh/cli v1.1.0/go.mod h1:xcISNoH86gajksDmfB23e/pu+B+GeFRMYmoHXxx3xhI= -github.com/mitchellh/go-homedir v1.1.0 h1:lukF9ziXFxDFPkA1vsr5zpc1XuPDn/wFntq5mG+4E0Y= -github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0= -github.com/mitchellh/go-testing-interface v1.0.0/go.mod h1:kRemZodwjscx+RGhAo8eIhFbs2+BFgRtFPeD/KE+zxI= -github.com/mitchellh/mapstructure v0.0.0-20160808181253-ca63d7c062ee/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= -github.com/mitchellh/mapstructure v1.1.2 h1:fmNYVwqnSfB9mZU6OS2O6GsXM+wcskZDuKQzvN1EDeE= -github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= -github.com/pascaldekloe/goe v0.0.0-20180627143212-57f6aae5913c/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc= +github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM= +github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo= +github.com/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/cpuid/v2 v2.0.9/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg= +github.com/klauspost/cpuid/v2 v2.2.4 h1:acbojRNwl3o09bUq+yDCtZFc1aiwaAAxtcn8YkZXnvk= +github.com/klauspost/cpuid/v2 v2.2.4/go.mod h1:RVVoqg1df56z8g3pUjL/3lE5UfnlrJX8tyFgg4nqhuY= +github.com/kr/pretty v0.3.0 h1:WgNl7dwNpEZ6jJ9k1snq4pZsg7DOEN8hP9Xw0Tsjwk0= +github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= +github.com/leodido/go-urn v1.2.2 h1:7z68G0FCGvDk646jz1AelTYNYWrTNm0bEcFAo147wt4= +github.com/leodido/go-urn v1.2.2/go.mod h1:kUaIbLZWttglzwNuG0pgsh5vuV6u2YcGBYz1hIPjtOQ= +github.com/mattn/go-isatty v0.0.17 h1:BTarxUcIeDqL27Mc+vyvdWYSL28zpIhv3RoTdsLMPng= +github.com/mattn/go-isatty v0.0.17/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= +github.com/minio/highwayhash v1.0.2 h1:Aak5U0nElisjDCfPSG79Tgzkn2gl66NxOMspRrKnA/g= +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/nats-io/jwt/v2 v2.3.0 h1:z2mA1a7tIf5ShggOFlR1oBPgd6hGqcDYsISxZByUzdI= +github.com/nats-io/nats-server/v2 v2.9.15 h1:MuwEJheIwpvFgqvbs20W8Ish2azcygjf4Z0liVu2I4c= +github.com/nats-io/nats-server/v2 v2.9.15/go.mod h1:QlCTy115fqpx4KSOPFIxSV7DdI6OxtZsGOL1JLdeRlE= +github.com/nats-io/nats.go v1.24.0 h1:CRiD8L5GOQu/DcfkmgBcTTIQORMwizF+rPk6T0RaHVQ= +github.com/nats-io/nats.go v1.24.0/go.mod h1:dVQF+BK3SzUZpwyzHedXsvH3EO38aVKuOPkkHlv5hXA= +github.com/nats-io/nkeys v0.3.0 h1:cgM5tL53EvYRU+2YLXIK0G2mJtK12Ft9oeooSZMA2G8= +github.com/nats-io/nkeys v0.3.0/go.mod h1:gvUNGjVcM2IPr5rCsRsC6Wb3Hr2CQAm08dsxtV6A5y4= +github.com/nats-io/nuid v1.0.1 h1:5iA8DT8V7q8WK2EScv2padNa/rTESc1KdnPw4TC2paw= +github.com/nats-io/nuid v1.0.1/go.mod h1:19wcPz3Ph3q0Jbyiqsd0kePYG7A95tJPxeL+1OSON2c= +github.com/pelletier/go-toml/v2 v2.0.7 h1:muncTPStnKRos5dpVKULv2FVd4bMOhNePj9CjgDb8Us= +github.com/pelletier/go-toml/v2 v2.0.7/go.mod h1:eumQOmlWiOPt5WriQQqoM5y18pDHwha2N+QD+EUNTek= +github.com/pkg/errors v0.8.1 h1:iURUrRGxPUNPdy5/HRSm+Yj6okJ6UtLINN0Q9M4+h3I= github.com/pkg/errors v0.8.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/posener/complete v1.1.1/go.mod h1:em0nMJCgc9GFtwrmVmEMR/ZL6WyhyjMBndrE9hABlRI= -github.com/posener/complete v1.2.3/go.mod h1:WZIdtGGp+qx0sLrYKtIRAruyNpv6hFCicSgv7Sy7s/s= -github.com/ryanuber/columnize v0.0.0-20160712163229-9b3edd62028f/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts= -github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529/go.mod h1:DxrIzT+xaE7yg65j358z/aeFdxmN0P9QXhEzd20vsDc= +github.com/rogpeppe/go-internal v1.8.0 h1:FCbCCtXNOY3UtUuHUYaghJg4y7Fd14rXifAYUAtL9R8= +github.com/rwtodd/Go.Sed v0.0.0-20210816025313-55464686f9ef/go.mod h1:8AEUvGVi2uQ5b24BIhcr0GCcpd/RNAFWaN2CJFrWIIQ= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= -github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= -github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= +github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= +github.com/stretchr/objx v0.5.0 h1:1zr/of2m5FGMsad5YfcqgdqdWrIhu+EBEJRhR1U7z/c= +github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo= +github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= +github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= +github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= +github.com/stretchr/testify v1.8.2 h1:+h33VjcLVPDHtOdpUCuF+7gSuG3yGIftsP1YvFihtJ8= +github.com/stretchr/testify v1.8.2/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= +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.11 h1:BMaWp1Bb6fHwEtbplGBGJ498wD+LKlNSl25MjdZY4dU= +github.com/ugorji/go/codec v1.2.11/go.mod h1:UNopzCgEMSXjBc6AOMqYvWC1ktqTAfzJZUZgYf6w6lg= +github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= +github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= +go.etcd.io/etcd/api/v3 v3.5.7 h1:sbcmosSVesNrWOJ58ZQFitHMdncusIifYcrBfwrlJSY= +go.etcd.io/etcd/api/v3 v3.5.7/go.mod h1:9qew1gCdDDLu+VwmeG+iFpL+QlpHTo7iubavdVDgCAA= +go.etcd.io/etcd/client/pkg/v3 v3.5.7 h1:y3kf5Gbp4e4q7egZdn5T7W9TSHUvkClN6u+Rq9mEOmg= +go.etcd.io/etcd/client/pkg/v3 v3.5.7/go.mod h1:o0Abi1MK86iad3YrWhgUsbGx1pmTS+hrORWc2CamuhY= +go.etcd.io/etcd/client/v3 v3.5.7 h1:u/OhpiuCgYY8awOHlhIhmGIGpxfBU/GZBUP3m/3/Iz4= +go.etcd.io/etcd/client/v3 v3.5.7/go.mod h1:sOWmj9DZUMyAngS7QQwCyAXXAL6WhgTOPLNS/NabQgw= +go.opentelemetry.io/contrib/instrumentation/github.com/gin-gonic/gin/otelgin v0.40.0 h1:E4MMXDxufRnIHXhoTNOlNsdkWpC5HdLhfj84WNRKPkc= +go.opentelemetry.io/contrib/instrumentation/github.com/gin-gonic/gin/otelgin v0.40.0/go.mod h1:A8+gHkpqTfMKxdKWq1pp360nAs096K26CH5Sm2YHDdA= +go.opentelemetry.io/contrib/propagators/b3 v1.15.0 h1:bMaonPyFcAvZ4EVzkUNkfnUHP5Zi63CIDlA3dRsEg8Q= +go.opentelemetry.io/otel v1.14.0 h1:/79Huy8wbf5DnIPhemGB+zEPVwnN6fuQybr/SRXa6hM= +go.opentelemetry.io/otel v1.14.0/go.mod h1:o4buv+dJzx8rohcUeRmWUZhqupFvzWis188WlggnNeU= +go.opentelemetry.io/otel/exporters/jaeger v1.14.0 h1:CjbUNd4iN2hHmWekmOqZ+zSCU+dzZppG8XsV+A3oc8Q= +go.opentelemetry.io/otel/exporters/jaeger v1.14.0/go.mod h1:4Ay9kk5vELRrbg5z4cpP9EtmQRFap2Wb0woPG4lujZA= +go.opentelemetry.io/otel/sdk v1.14.0 h1:PDCppFRDq8A1jL9v6KMI6dYesaq+DFcDZvjsoGvxGzY= +go.opentelemetry.io/otel/sdk v1.14.0/go.mod h1:bwIC5TjrNG6QDCHNWvW4HLHtUQ4I+VQDsnjhvyZCALM= +go.opentelemetry.io/otel/trace v1.14.0 h1:wp2Mmvj41tDsyAJXiWDWpfNsOiIyd38fy85pyKcFq/M= +go.opentelemetry.io/otel/trace v1.14.0/go.mod h1:8avnQLK+CG77yNLUae4ea2JDQ6iT+gozhnZjy/rw9G8= +go.uber.org/atomic v1.7.0 h1:ADUqmZGgLDDfbSL9ZmPxKTybcoEYHgpYfELNoN+7hsw= +go.uber.org/atomic v1.7.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc= +go.uber.org/multierr v1.6.0 h1:y6IPFStTAIT5Ytl7/XYmHvzXQ7S3g/IeZW9hyZ5thw4= +go.uber.org/multierr v1.6.0/go.mod h1:cdWPpRnG4AhwMwsgIHip0KRBQjJy5kYEpYjJxpXp9iU= +go.uber.org/zap v1.17.0 h1:MTjgFu6ZLKvY6Pvaqk97GlxNBuMpV4Hy/3P6tRGlI2U= +go.uber.org/zap v1.17.0/go.mod h1:MXVU+bhUf/A7Xi2HNOnopQOrmycQ5Ih87HtOu4q5SSo= +golang.org/x/arch v0.0.0-20210923205945-b76863e36670/go.mod h1:5om86z9Hs0C8fWVUuoMHwpExlXzs5Tkyp9hOrfG7pp8= +golang.org/x/arch v0.3.0 h1:02VY4/ZcO/gBOH6PUaoiptASxtXU10jazRCP865E97k= +golang.org/x/arch v0.3.0/go.mod h1:5om86z9Hs0C8fWVUuoMHwpExlXzs5Tkyp9hOrfG7pp8= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= -golang.org/x/crypto v0.0.0-20190923035154-9ee001bba392/go.mod h1:/lpIB1dKB+9EgE3H3cr1v9wB50oz8l4C4h62xy7jSTY= +golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= +golang.org/x/crypto v0.0.0-20210314154223-e6e6c4f2bb5b/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4= +golang.org/x/crypto v0.7.0 h1:AvwMYaRytfdeVt3u6mLaxYtErKYjxA2OXjJ1HHq6t3A= +golang.org/x/crypto v0.7.0/go.mod h1:pYwdfH91IfpZVANVyUOhSIPZaFoJGxTFbZhFTx+dXZU= +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/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-20190923162816-aa69164e4478/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= -golang.org/x/net v0.0.0-20210410081132-afb366fc7cd1/go.mod h1:9tjilg8BloeKEkVJvy7fQ90B1CfIiPueXVOjqfkSzI8= +golang.org/x/net v0.8.0 h1:Zrh2ngAOFYneWTAIAPethzeaQLuHwhuBkuV6ZiRnUaQ= +golang.org/x/net v0.8.0/go.mod h1:QVkue5JL9kW//ek3r6jTKnTFis1tRmNAW2P1shuFdJc= golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20190922100055-0a153f010e69/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190924154521-2837fb4f24fe/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20191008105621-543471e840be/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200124204421-9fbb57f87de9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190412213103-97732733099d/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-20210303074136-134d130e1a04/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44 h1:Bli41pIlzTzf3KEY06n+xnzK/BESIg2ze4Pgfh/aI8c= -golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20220704084225-05e143d24a9e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.6.0 h1:MVltZSvRTcU2ljQOhs94SXPftV6DCNnZViHeQps87pQ= +golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= -golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= -golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +golang.org/x/text v0.8.0 h1:57P1ETyNKtuIjB4SRd15iJxuhj8Gc416Y78H3qgMh68= +golang.org/x/text v0.8.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= +golang.org/x/time v0.3.0 h1:rg5rLMjNzMS1RkNLzCG38eapWhnYLFYXDXj2gOlr8j4= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= -golang.org/x/tools v0.0.0-20190907020128-2ca718005c18/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= +golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= 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= +golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +google.golang.org/genproto v0.0.0-20230110181048-76db0878b65f h1:BWUVssLB0HVOSY78gIdvk1dTVYtT1y8SBWtPYuTJ/6w= +google.golang.org/genproto v0.0.0-20230110181048-76db0878b65f/go.mod h1:RGgjbofJ8xD9Sq1VVhDM1Vok1vRONV+rg+CjzG4SZKM= +google.golang.org/grpc v1.53.0 h1:LAv2ds7cmFV/XTS3XG1NneeENYrXGmorPxsBbptIjNc= +google.golang.org/grpc v1.53.0/go.mod h1:OnIrk0ipVdj4N5d9IUoFUx72/VlD7+jUsHwZgwSMQpw= +google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= +google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= +google.golang.org/protobuf v1.30.0 h1:kPPoIgf3TsEvrm0PFe15JQ+570QVxYzEvvHqChK+cng= +google.golang.org/protobuf v1.30.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= -gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= -gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY= +gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= +gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +rsc.io/pdf v0.1.1/go.mod h1:n8OzWcQ6Sp37PL01nO98y4iUCRdTGarVfzxY20ICaU4= \ No newline at end of file diff --git a/main.go b/main.go index ac72ece..523276b 100644 --- a/main.go +++ b/main.go @@ -1,42 +1,98 @@ package main import ( - "github.com/c12s/kuiper/model" - "github.com/c12s/kuiper/repository/consul" - "github.com/c12s/kuiper/service" + "context" + "kuiper/server" + "kuiper/service" + "kuiper/store" + "kuiper/util" + "log" + "net/http" + "os" + "os/signal" + "syscall" + "time" + + "github.com/gin-gonic/gin" + clientv3 "go.etcd.io/etcd/client/v3" + "go.opentelemetry.io/contrib/instrumentation/github.com/gin-gonic/gin/otelgin" + "go.opentelemetry.io/otel" + "go.opentelemetry.io/otel/propagation" ) +const kuiperName = "kuiper" + func main() { - configRepo, err := consul.New() + logger := log.Default() + config, err := server.NewConfig() + if err != nil { + logger.Fatalf("Error: %s", err.Error()) + } + + ctx := context.Background() + //init exporter + exporter, err := util.NewJaegerExporter(config.JaegerAddress) + if err != nil { + logger.Fatalf(err.Error()) + } + //init traceprovider + tp := util.NewTraceProvider(exporter) + defer func() { _ = tp.Shutdown(ctx) }() + otel.SetTracerProvider(tp) + tracer := tp.Tracer(kuiperName) + otel.SetTextMapPropagator(propagation.TraceContext{}) + + router := gin.New() + router.Use(gin.Recovery()) + router.Use(otelgin.Middleware(kuiperName)) + cli, err := clientv3.New(clientv3.Config{ + Endpoints: []string{config.EtcdAddress}, + DialTimeout: 10 * time.Second, + }) if err != nil { - panic(err) + logger.Fatalf(err.Error()) } - configService := service.New(configRepo) - - group := model.Group{ - Configs: []model.Config{ - model.Config{ - Key: "mysql.user", - Value: "asdf", - Labels: []model.Label{}, - }, - model.Config{ - Key: "mysql.pass", - Value: "123", - Labels: []model.Label{}, - }, - }, + natsCon, err := util.Conn(config.NatsAddress) + if err != nil { + logger.Fatalf(err.Error()) } - resp, _ := configService.CreateNewGroup(group) + cfgStore := store.NewConfigStore(*cli, *logger, tracer) + cfgService := service.NewConfigService(cfgStore, *logger, tracer) + handler := server.NewConfigHandler(tracer, *logger, cfgService, *natsCon) + + router.POST("/api/config", handler.SaveConfig) + router.GET("/api/config/:id/:ver", handler.GetConfig) + router.GET("/api/config/:id", handler.GetConfigsByService) + router.POST("/api/config/:id/", handler.CreateNewVersion) + router.DELETE("/api/config/:id/:ver", handler.DeleteConfig) + router.DELETE("/api/config/:id", handler.DeleteConfigsWithPrefix) + + // start server + srv := &http.Server{Addr: "0.0.0.0:8080", Handler: router} + go func() { + log.Println("server starting") + if err := srv.ListenAndServe(); err != nil { + if err != http.ErrServerClosed { + log.Fatal(err) + } + } + }() + + quit := make(chan os.Signal) + signal.Notify(quit, syscall.SIGINT, syscall.SIGTERM) + <-quit - println(resp.Id, resp.Version) + log.Println("service shutting down ...") - stored, _ := configService.GetGroupConfigs(resp.Id, resp.Version, []model.Label{}) + // gracefully stop server + ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second) + defer cancel() - for k, v := range stored { - println(k, v) + if err := srv.Shutdown(ctx); err != nil { + log.Fatal(err) } -} + log.Println("server stopped") +} \ No newline at end of file diff --git a/model/config.go b/model/config.go new file mode 100644 index 0000000..620dafa --- /dev/null +++ b/model/config.go @@ -0,0 +1,9 @@ +package model + +type Entries = map[string]string + +type Config struct { + Service string `json:"service"` + Version string `json:"version"` + Entries Entries `json:"entries"` +} diff --git a/server/config.go b/server/config.go new file mode 100644 index 0000000..8dad5fd --- /dev/null +++ b/server/config.go @@ -0,0 +1,35 @@ +package server + +import ( + "errors" + "os" +) + +type Config struct { + JaegerAddress string + EtcdAddress string + NatsAddress string +} + +const ( + jaegerAddressEnv = "JAEGER_ADDRESS" + etcdAddressEnv = "ETCD_ADDRESS" + natsAddressEnv = "NATS_ADDRESS" +) + +func NewConfig() (Config, error) { + jagAddr, found := os.LookupEnv(jaegerAddressEnv) + if !found { + return Config{}, errors.New(jaegerAddressEnv + " environment variable not set") + } + etcdAddr, found := os.LookupEnv(etcdAddressEnv) + if !found { + return Config{}, errors.New(etcdAddressEnv + " environment variable not set") + } + natsAddr, found := os.LookupEnv(natsAddressEnv) + if !found { + return Config{}, errors.New(natsAddressEnv + " environment variable not set") + } + + return Config{JaegerAddress: jagAddr, EtcdAddress: etcdAddr, NatsAddress: natsAddr}, nil +} diff --git a/server/handlers.go b/server/handlers.go new file mode 100644 index 0000000..ab5fbcc --- /dev/null +++ b/server/handlers.go @@ -0,0 +1,190 @@ +package server + +import ( + "encoding/json" + "errors" + "fmt" + "kuiper/service" + "kuiper/store" + "mime" + "net/http" + + "github.com/gin-gonic/gin" +) + +func (ch configHandler) SaveConfig(c *gin.Context) { + ctx, span := ch.tracer.Start(c.Request.Context(), "configServer.CreateConfig") + defer span.End() + + contentType := c.Request.Header.Get("Content-Type") + // idemKey := c.Request.Header.Get("x-idempotency-key") + + mediatype, _, err := mime.ParseMediaType(contentType) + if err != nil { + span.RecordError(err) + http.Error(c.Writer, err.Error(), http.StatusBadRequest) + return + } + + if mediatype != "application/json" { + err := errors.New("Expect application/json Content-Type") + span.RecordError(err) + http.Error(c.Writer, err.Error(), http.StatusUnsupportedMediaType) + c.JSON(http.StatusUnsupportedMediaType, gin.H{"error": "Only application/json is accepted"}) + return + } + + newCfg, err := decodeConfigBody(c.Request.Body) + if err != nil || newCfg.Entries == nil { + span.RecordError(err) + c.JSON(http.StatusInternalServerError, gin.H{"error": "Invalid JSON"}) + return + } + + cid, err := ch.configService.CreateConfig(ctx, newCfg) + if err == service.NoVersionError { + c.JSON(http.StatusBadRequest, gin.H{"error": "No version supplied"}) + return + } else if err == store.KeyAlreadyExistsError { + c.JSON(http.StatusConflict, gin.H{"error": "Version already exists for the service"}) + return + } else if err == service.NoServiceNameError { + c.JSON(http.StatusBadRequest, gin.H{"error": "No service name supplied"}) + return + } else if err != nil { + c.JSON(http.StatusInternalServerError, gin.H{"error": "Error when saving config"}) + return + } + + cfgJson, _ := json.Marshal(newCfg.Entries) + ch.nats.Publish(natsKey(newCfg.Service), cfgJson) + c.JSON(http.StatusOK, gin.H{"id": cid}) +} + +func (ch configHandler) GetConfig(c *gin.Context) { + ctx, span := ch.tracer.Start(c.Request.Context(), "configServer.GetConfig") + defer span.End() + + id := c.Param("id") + ver := c.Param("ver") + + cfg, err := ch.configService.GetConfig(ctx, id, ver) + if err != nil { + c.JSON(http.StatusNotFound, gin.H{"error": "No value under key"}) + return + } + + c.JSON(http.StatusOK, cfg) +} + +func (ch configHandler) GetConfigsByService(c *gin.Context) { + ctx, span := ch.tracer.Start(c.Request.Context(), "configServer.GetConfigsByService") + defer span.End() + + id := c.Param("id") + if c.Query("latest") == "true" { + cfg, err := ch.configService.GetLatestConfigByService(ctx, id) + if err != nil { + c.JSON(http.StatusNotFound, gin.H{"error": "No value under key"}) + return + } + c.JSON(http.StatusOK, cfg) + return + } + cfgs, err := ch.configService.GetConfigsByService(ctx, id) + if err != nil { + c.JSON(http.StatusNotFound, gin.H{"error": "No value under key"}) + return + } + c.JSON(http.StatusOK, cfgs) + +} + +func (ch configHandler) CreateNewVersion(c *gin.Context) { + ctx, span := ch.tracer.Start(c.Request.Context(), "configServer.CreateNewVersion") + defer span.End() + + id := c.Param("id") + + contentType := c.Request.Header.Get("Content-Type") + // idemKey := c.Request.Header.Get("x-idempotency-key") + + mediatype, _, err := mime.ParseMediaType(contentType) + if err != nil { + span.RecordError(err) + http.Error(c.Writer, err.Error(), http.StatusBadRequest) + return + } + + if mediatype != "application/json" { + err := errors.New("Expect application/json Content-Type") + span.RecordError(err) + http.Error(c.Writer, err.Error(), http.StatusUnsupportedMediaType) + c.JSON(http.StatusUnsupportedMediaType, gin.H{"error": "Only application/json is accepted"}) + return + } + + rt, err := decodeConfigBody(c.Request.Body) + if err != nil || rt.Entries == nil { + span.RecordError(err) + c.JSON(http.StatusInternalServerError, gin.H{"error": "Invalid JSON"}) + return + } + + err = ch.configService.CreateNewVersion(ctx, rt, id) + switch err { + case service.NoVersionError: + c.JSON(http.StatusBadRequest, gin.H{"error": "No version supplied"}) + return + case store.KeyAlreadyExistsError: + c.JSON(http.StatusConflict, gin.H{"error": "Version already exists"}) + return + case store.ErrorNotFound: + c.JSON(http.StatusNotFound, gin.H{"error": "Configuration with given ID doesn't exist"}) + return + } + if err != nil { + c.JSON(http.StatusInternalServerError, gin.H{"error": "Invalid JSON"}) + return + } + + c.JSON(http.StatusCreated, gin.H{"id": id}) + return +} + +func (ch configHandler) DeleteConfig(c *gin.Context) { + ctx, span := ch.tracer.Start(c.Request.Context(), "configServer.DeleteConfig") + defer span.End() + + id := c.Param("id") + ver := c.Param("ver") + + cfg, err := ch.configService.DeleteConfig(ctx, id, ver) + if err == store.ErrorNotFound { + c.JSON(http.StatusNotFound, gin.H{"error": "Configuration with the given ID and version doesn't exist"}) + return + } else if err != nil { + c.JSON(http.StatusInternalServerError, gin.H{"error": "Failure when connecting to database"}) + } + + c.JSON(http.StatusOK, cfg) +} + +func (ch configHandler) DeleteConfigsWithPrefix(c *gin.Context) { + ctx, span := ch.tracer.Start(c.Request.Context(), "configServer.DeleteConfigsWithPrefix") + defer span.End() + + id := c.Param("id") + + cfg, err := ch.configService.DeleteConfigsWithPrefix(ctx, id) + if err == store.ErrorNotFound { + errorMsg := fmt.Sprintf("No configurations found for %s", id) + c.JSON(http.StatusNotFound, gin.H{"error": errorMsg}) + return + } else if err != nil { + c.JSON(http.StatusInternalServerError, gin.H{"error": "Failure when connecting to database"}) + return + } + + c.JSON(http.StatusOK, cfg) +} diff --git a/server/helper.go b/server/helper.go new file mode 100644 index 0000000..1b618b9 --- /dev/null +++ b/server/helper.go @@ -0,0 +1,18 @@ +package server + +import ( + "encoding/json" + "io" + "kuiper/model" +) + +func decodeConfigBody(r io.Reader) (model.Config, error) { + dec := json.NewDecoder(r) + dec.DisallowUnknownFields() + + var config *model.Config + if err := dec.Decode(&config); err != nil { + return model.Config{}, err + } + return *config, nil +} diff --git a/server/server.go b/server/server.go new file mode 100644 index 0000000..d991928 --- /dev/null +++ b/server/server.go @@ -0,0 +1,30 @@ +package server + +import ( + "kuiper/service" + "log" + + "github.com/gin-gonic/gin" + "github.com/nats-io/nats.go" + "go.opentelemetry.io/otel/trace" +) + +type ConfigHandler interface { + SaveConfig(c *gin.Context) + GetConfig(c *gin.Context) + DeleteConfig(c *gin.Context) + CreateNewVersion(c *gin.Context) + DeleteConfigsWithPrefix(c *gin.Context) + GetConfigsByService(c *gin.Context) +} + +type configHandler struct { + tracer trace.Tracer + logger log.Logger + configService service.ConfigService + nats nats.Conn +} + +func NewConfigHandler(tracer trace.Tracer, logger log.Logger, configService service.ConfigService, conn nats.Conn) configHandler { + return configHandler{tracer: tracer, logger: logger, configService: configService, nats: conn} +} diff --git a/service/configService.go b/service/configService.go new file mode 100644 index 0000000..7eb1050 --- /dev/null +++ b/service/configService.go @@ -0,0 +1,108 @@ +package service + +import ( + "context" + "errors" + "kuiper/model" + "kuiper/store" + "log" + + "go.opentelemetry.io/otel/trace" +) + +var NoVersionError = errors.New("Must supply version name when creating a new config") +var NoServiceNameError = errors.New("Must supply service name when creating a new config") +var DbError = errors.New("Error happened while connecting to database") + +type ConfigService interface { + //Checks if cfg is a valid config and tries to persist it. + CreateConfig(ctx context.Context, cfg model.Config) (string, error) + //Finds a config by id and version + GetConfig(ctx context.Context, id, ver string) (model.Entries, error) + //Creates a new version of already existing config + CreateNewVersion(ctx context.Context, cfg model.Config, id string) error + //Deletes config by id and version, returns error when config wasn't foun + DeleteConfig(ctx context.Context, id, ver string) (cfg model.Entries, err error) + //Deletes all configs with the given ID + DeleteConfigsWithPrefix(ctx context.Context, id string) (deleted map[string]model.Entries, err error) + //Gets the latest config of a service + GetLatestConfigByService(ctx context.Context, id string) (map[string]model.Entries, error) + //Gets all of the service's configs + GetConfigsByService(ctx context.Context, id string) (map[string]model.Entries, error) +} + +func NewConfigService(cs store.ConfigStore, logger log.Logger, trace trace.Tracer) ConfigService { + return configService{store: cs, logger: logger, trace: trace} +} + +type configService struct { + store store.ConfigStore + logger log.Logger + trace trace.Tracer +} + +func (cs configService) CreateConfig(ctx context.Context, cfg model.Config) (string, error) { + nCtx, span := cs.trace.Start(ctx, "configService.CreateConfig") + defer span.End() + + if len(cfg.Version) == 0 { + span.RecordError(NoVersionError) + return "", NoVersionError + } + if len(cfg.Service) == 0 { + span.RecordError(NoServiceNameError) + return "", NoServiceNameError + } + + return cs.store.SaveConfig(nCtx, cfg) +} + +func (cs configService) GetConfig(ctx context.Context, id, ver string) (model.Entries, error) { + nCtx, span := cs.trace.Start(ctx, "configService.GetConfig") + defer span.End() + return cs.store.GetConfig(nCtx, id, ver) +} + +var IdNotProvidedError = errors.New("Id not provided") + +func (cs configService) GetConfigsByService(ctx context.Context, id string) (map[string]model.Entries, error) { + nCtx, span := cs.trace.Start(ctx, "configService.GetConfigsByService") + defer span.End() + if id == "" { + return make(map[string]model.Entries), IdNotProvidedError + } + return cs.store.GetConfigsByService(nCtx, id) +} + +func (cs configService) GetLatestConfigByService(ctx context.Context, id string) (map[string]model.Entries, error) { + nCtx, span := cs.trace.Start(ctx, "configService.GetConfigsByService") + defer span.End() + if id == "" { + return make(map[string]model.Entries), IdNotProvidedError + } + return cs.store.GetLatestConfigByService(nCtx, id) +} + +func (cs configService) CreateNewVersion(ctx context.Context, cfg model.Config, id string) error { + nCtx, span := cs.trace.Start(ctx, "configService.CreateNewVersion") + defer span.End() + + if len(cfg.Version) == 0 { + span.RecordError(NoVersionError) + return NoVersionError + } + + return cs.store.SaveVersion(nCtx, cfg, id) +} + +func (cs configService) DeleteConfig(ctx context.Context, id, ver string) (cfg model.Entries, err error) { + nCtx, span := cs.trace.Start(ctx, "configService.DeleteConfig") + defer span.End() + return cs.store.DeleteConfig(nCtx, id, ver) +} + +func (cs configService) DeleteConfigsWithPrefix(ctx context.Context, id string) (deleted map[string]model.Entries, err error) { + nCtx, span := cs.trace.Start(ctx, "configService.DeleteConfig") + defer span.End() + return cs.store.DeleteConfigsWithPrefix(nCtx, id) +} diff --git a/store/configStore.go b/store/configStore.go new file mode 100644 index 0000000..8f234e6 --- /dev/null +++ b/store/configStore.go @@ -0,0 +1,264 @@ +package store + +import ( + "context" + "encoding/json" + "errors" + "kuiper/model" + "log" + "time" + + "go.etcd.io/etcd/api/v3/mvccpb" + clientv3 "go.etcd.io/etcd/client/v3" + "go.opentelemetry.io/otel/trace" +) + +var ErrorNotFound = errors.New("Config not found") +var KeyAlreadyExistsError = errors.New("Version already exists for the given ID") + +// ConfigStore is used for persistance of configurations. +// Configs are uniquely identified by ID and version. Each ID can have multiple versions. +type ConfigStore interface { + //SaveConfig() persists a config and returns it's ID as string. + SaveConfig(ctx context.Context, cfg model.Config) (string, error) + //GetConfig() finds a config by it's ID and version. + GetConfig(ctx context.Context, id, ver string) (map[string]string, error) + //Creates a new version for an already existing id + SaveVersion(ctx context.Context, cfg model.Config, id string) error + //Deletes a config and returns the config that was deleted + DeleteConfig(ctx context.Context, id, ver string) (map[string]string, error) + //Deletes all the configs with the given ID and returns them + DeleteConfigsWithPrefix(ctx context.Context, id string) (map[string]model.Entries, error) + //Gets all of the service's configs + GetConfigsByService(ctx context.Context, id string) (map[string]model.Entries, error) + //Gets only the latest config of a service + GetLatestConfigByService(ctx context.Context, id string) (map[string]model.Entries, error) +} + +func NewConfigStore(cli clientv3.Client, logger log.Logger, trace trace.Tracer) ConfigStore { + return configStoreEtcd{cli: cli, logger: logger, trace: trace} +} + +type configStoreEtcd struct { + logger log.Logger + cli clientv3.Client + trace trace.Tracer +} + +func (cStore configStoreEtcd) SaveConfig(ctx context.Context, cfg model.Config) (string, error) { + _, span := cStore.trace.Start(ctx, "configStoreEtcd.CreateConfig") + defer span.End() + + var id string + id = cfg.Service + + key := makeKey(id, cfg.Version) + + jsonB, err := json.Marshal(cfg.Entries) + if err != nil { + span.RecordError(err) + return "", err + } + + kvCtx, cancel := context.WithTimeout(ctx, time.Second*10) + op := clientv3.OpPut(key, string(jsonB)) + res, err := cStore.cli.Txn(kvCtx).If(clientv3.Compare(clientv3.Version(key), "=", 0)).Then(op).Commit() + cancel() + if err != nil { + span.RecordError(err) + return "", err + } + if !res.Succeeded { + err = KeyAlreadyExistsError + span.RecordError(KeyAlreadyExistsError) + return "", err + } + + return id, nil +} + +func (cStore configStoreEtcd) GetConfig(ctx context.Context, id, ver string) (map[string]string, error) { + _, span := cStore.trace.Start(ctx, "configStoreEtcd.GetConfig") + defer span.End() + + entries := make(map[string]string) + + kvCtx, cancel := context.WithTimeout(ctx, time.Second*10) + res, err := cStore.cli.KV.Get(kvCtx, makeKey(id, ver)) + cancel() + if err != nil { + span.RecordError(err) + return entries, err + } + + kvs := res.Kvs + if len(kvs) > 0 { + kv := kvs[0] + data := kv.Value + err = json.Unmarshal(data, &entries) + if err != nil { + span.RecordError(err) + return entries, err + } + return entries, nil + } + + return entries, ErrorNotFound +} + +func (cStore configStoreEtcd) GetConfigsByService(ctx context.Context, id string) (map[string]model.Entries, error) { + ctx, span := cStore.trace.Start(ctx, "configStoreEtcd.GetConfigsByService") + defer span.End() + + cfgs := make(map[string]model.Entries) + + kvCtx, cancel := context.WithTimeout(ctx, time.Second*10) + res, err := cStore.cli.KV.Get(kvCtx, makeIdPrefix(id), clientv3.WithPrefix()) + cancel() + if err != nil { + span.RecordError(err) + return cfgs, err + } + + return cStore.decodeConfigsFromKvs(res.Kvs, ctx) +} + +func (cStore configStoreEtcd) GetLatestConfigByService(ctx context.Context, id string) (map[string]model.Entries, error) { + ctx, span := cStore.trace.Start(ctx, "configStoreEtcd.GetLatestConfigByService") + defer span.End() + + cfgs := make(map[string]model.Entries) + + kvCtx, cancel := context.WithTimeout(ctx, time.Second*10) + opts := clientv3.WithLastRev() + opts = append(opts, clientv3.WithPrefix()) + res, err := cStore.cli.KV.Get(kvCtx, makeIdPrefix(id), opts...) + cancel() + if err != nil { + span.RecordError(err) + return cfgs, err + } + + return cStore.decodeConfigsFromKvs(res.Kvs, ctx) +} + +func (cStore configStoreEtcd) decodeConfigsFromKvs(kvs []*mvccpb.KeyValue, ctx context.Context) (map[string]model.Entries, error) { + ctx, span := cStore.trace.Start(ctx, "configStoreEtcd.decodeConfigsFromKvs") + defer span.End() + + cfgs := make(map[string]model.Entries) + for _, kv := range kvs { + cfg := make(map[string]string) + data := kv.Value + err := json.Unmarshal(data, &cfg) + if err != nil { + span.RecordError(err) + return cfgs, err + } + + ver := getVersionFromKey(string(kv.Key)) + cfgs[string(ver)] = cfg + } + return cfgs, nil +} + +func (cStore configStoreEtcd) getPrefixCount(ctx context.Context, id string) (int64, error) { + _, span := cStore.trace.Start(ctx, "configStoreEtcd.getPrefixCount") + defer span.End() + + kvCtx, cancel := context.WithTimeout(ctx, time.Second*10) + key := makeIdPrefix(id) + res, err := cStore.cli.Get(kvCtx, key, clientv3.WithPrefix(), clientv3.WithCountOnly()) + cancel() + if err != nil { + return 0, err + } + return res.Count, nil +} + +func (cStore configStoreEtcd) SaveVersion(ctx context.Context, cfg model.Config, id string) error { + ctx, span := cStore.trace.Start(ctx, "configStoreEtcd.SaveVersion") + defer span.End() + + key := makeKey(id, cfg.Version) + + jsonB, err := json.Marshal(cfg.Entries) + if err != nil { + span.RecordError(err) + return err + } + + c, err := cStore.getPrefixCount(ctx, id) + if err != nil { + return err + } + if c == 0 { + return ErrorNotFound + } + + kvCtx, cancel := context.WithTimeout(ctx, time.Second*10) + op := clientv3.OpPut(key, string(jsonB)) + res, err := cStore.cli.Txn(kvCtx).If(clientv3.Compare(clientv3.Version(key), "=", 0)).Then(op).Commit() + cancel() + if err != nil { + span.RecordError(err) + return err + } + + if !res.Succeeded { + return KeyAlreadyExistsError + } + + return nil +} + +func (cStore configStoreEtcd) DeleteConfig(ctx context.Context, id, ver string) (map[string]string, error) { + _, span := cStore.trace.Start(ctx, "configStoreEtcd.DeleteConfig") + defer span.End() + + entries := make(map[string]string) + key := makeKey(id, ver) + + kvCtx, cancel := context.WithTimeout(ctx, time.Second*10) + res, err := cStore.cli.KV.Delete(kvCtx, key, clientv3.WithPrevKV()) + cancel() + if err != nil { + span.RecordError(err) + return entries, err + } + + kvs := res.PrevKvs + if res.Deleted > 0 { + kv := kvs[0] + data := kv.Value + err = json.Unmarshal(data, &entries) + if err != nil { + span.RecordError(err) + return entries, err + } + return entries, nil + } + + return entries, ErrorNotFound +} + +func (cStore configStoreEtcd) DeleteConfigsWithPrefix(ctx context.Context, id string) (map[string]model.Entries, error) { + ctx, span := cStore.trace.Start(ctx, "configStoreEtcd.DeleteConfigWithPrefix") + defer span.End() + + cfgs := make(map[string]map[string]string) + key := makeIdPrefix(id) + + kvCtx, cancel := context.WithTimeout(ctx, time.Second*10) + res, err := cStore.cli.KV.Delete(kvCtx, key, clientv3.WithPrevKV(), clientv3.WithPrefix()) + cancel() + if err != nil { + span.RecordError(err) + return cfgs, err + } + if res.Deleted == 0 { + return cfgs, ErrorNotFound + } + + return cStore.decodeConfigsFromKvs(res.PrevKvs, ctx) +} diff --git a/store/keyUtils.go b/store/keyUtils.go new file mode 100644 index 0000000..e2e02ee --- /dev/null +++ b/store/keyUtils.go @@ -0,0 +1,20 @@ +package store + +import ( + "fmt" + "strings" +) + +func makeKey(id, ver string) string { + key := fmt.Sprintf("config/%s/%s/", id, ver) + return key +} +func makeIdPrefix(id string) string { + key := fmt.Sprintf("config/%s/", id) + return key +} + +func getVersionFromKey(key string) string { + split := strings.Split(string(key), "/") + return split[len(split)-2] +} diff --git a/util/nats.go b/util/nats.go new file mode 100644 index 0000000..4b25365 --- /dev/null +++ b/util/nats.go @@ -0,0 +1,7 @@ +package util + +import "github.com/nats-io/nats.go" + +func Conn(natsAddr string) (*nats.Conn, error) { + return nats.Connect(natsAddr) +} diff --git a/util/tracing.go b/util/tracing.go new file mode 100644 index 0000000..e1fe9d6 --- /dev/null +++ b/util/tracing.go @@ -0,0 +1,37 @@ +package util + +import ( + "go.opentelemetry.io/otel/exporters/jaeger" + "go.opentelemetry.io/otel/sdk/resource" + sdktrace "go.opentelemetry.io/otel/sdk/trace" + semconv "go.opentelemetry.io/otel/semconv/v1.17.0" +) + +func NewTraceProvider(exp sdktrace.SpanExporter) *sdktrace.TracerProvider { + r, err := resource.Merge( + resource.Default(), + resource.NewWithAttributes( + semconv.SchemaURL, + semconv.ServiceNameKey.String("kuiper"), + ), + ) + + if err != nil { + panic(err.Error()) + } + + return sdktrace.NewTracerProvider( + sdktrace.WithBatcher(exp), + sdktrace.WithResource(r), + ) +} + +func NewJaegerExporter(address string) (*jaeger.Exporter, error) { + exp, err := jaeger.New( + jaeger.WithCollectorEndpoint( + jaeger.WithEndpoint(address))) + if err != nil { + return nil, err + } + return exp, nil +}