init
This commit is contained in:
5
.gitignore
vendored
Normal file
5
.gitignore
vendored
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
MamContract
|
||||||
|
vendor/
|
||||||
|
.idea/
|
||||||
|
|
||||||
|
*.iml
|
||||||
86
Makefile
Normal file
86
Makefile
Normal file
@@ -0,0 +1,86 @@
|
|||||||
|
# Set an output prefix, which is the local directory if not specified
|
||||||
|
PREFIX?=$(shell pwd)
|
||||||
|
.DEFAULT_GOAL := build
|
||||||
|
|
||||||
|
DOCKER_IMAGE_NAME := MamContract
|
||||||
|
# Setup name variables for the package/tool
|
||||||
|
NAME := MamContract
|
||||||
|
BIN_NAME := MamContract
|
||||||
|
PKG := github.com/kratisto/mam-contract
|
||||||
|
|
||||||
|
# GO env vars
|
||||||
|
ifeq ($(GOPATH),)
|
||||||
|
GOPATH:=~/go
|
||||||
|
endif
|
||||||
|
GO=$(firstword $(subst :, ,$(GOPATH)))
|
||||||
|
|
||||||
|
.PHONY: ensure-vendor
|
||||||
|
ensure-vendor: ## Get all vendor dependencies
|
||||||
|
@echo "+ $@"
|
||||||
|
dep ensure
|
||||||
|
|
||||||
|
.PHONY: update-vendor
|
||||||
|
update-vendor: ## Get all vendor dependencies
|
||||||
|
@echo "+ $@"
|
||||||
|
dep ensure -update
|
||||||
|
|
||||||
|
.PHONY: clean
|
||||||
|
clean: local-clean ## Clean your generated files
|
||||||
|
@echo "+ $@"
|
||||||
|
docker image rm workScheduler:snapshot || true
|
||||||
|
|
||||||
|
.PHONY: local-build
|
||||||
|
local-build: local-clean local-format ## Build locally the binary
|
||||||
|
@echo "+ $@"
|
||||||
|
go build -o $(GO)/bin/$(BIN_NAME) .
|
||||||
|
|
||||||
|
.PHONY: local-clean
|
||||||
|
local-clean: ## Cleanup locally any build binaries or packages
|
||||||
|
@echo "+ $@"
|
||||||
|
@$(RM) $(BIN_NAME)
|
||||||
|
|
||||||
|
.PHONY: local-format
|
||||||
|
local-format: ## format locally all files
|
||||||
|
@echo "+ $@"
|
||||||
|
gofmt -s -l -w .
|
||||||
|
|
||||||
|
.PHONY: build
|
||||||
|
build: sources-image ## Build the docker image with application binary
|
||||||
|
@echo "+ $@"
|
||||||
|
docker build --no-cache \
|
||||||
|
-f containers/Dockerfile \
|
||||||
|
--build-arg SOURCES_IMAGE=workScheduler-sources:snapshot \
|
||||||
|
-t workScheduler:snapshot .
|
||||||
|
|
||||||
|
GIT_CREDENTIALS?=$(shell cat ~/.git-credentials 2> /dev/null)
|
||||||
|
.PHONY: sources-image
|
||||||
|
sources-image: ## Generate a Docker image with only the sources
|
||||||
|
@echo "+ $@"
|
||||||
|
docker build -t workScheduler-sources:snapshot -f containers/Dockerfile.sources .
|
||||||
|
|
||||||
|
|
||||||
|
.PHONY: local-run-dependencies
|
||||||
|
local-run-dependencies: ## Run the dependencies of the server (launch the containers/docker-compose.local.yml)
|
||||||
|
@echo "+ $@"
|
||||||
|
@docker-compose -p $(DOCKER_IMAGE_NAME)-uuid -f containers/docker-compose.local.yml down || true;
|
||||||
|
@docker-compose -p $(DOCKER_IMAGE_NAME)-uuid -f containers/docker-compose.local.yml pull;
|
||||||
|
@docker-compose -p $(DOCKER_IMAGE_NAME)-uuid -f containers/docker-compose.local.yml up -d --build
|
||||||
|
|
||||||
|
.PHONY: local-run-golang
|
||||||
|
local-run-golang: ## Build the server and run it
|
||||||
|
@echo "+ $@"
|
||||||
|
BUILD_GOLANG_CMD=local-build \
|
||||||
|
LAUNCH_GOLANG_CMD="$(GO)/bin/$(BIN_NAME)" \
|
||||||
|
$(MAKE) local-launch-golang
|
||||||
|
|
||||||
|
.PHONY: local-launch-golang
|
||||||
|
local-launch-golang: ## Build the server and run it
|
||||||
|
@echo "+ $@"
|
||||||
|
PID=`ps -ax | egrep "\b$(BIN_NAME)"| cut -d " " -f 1`; \
|
||||||
|
kill $$PID || true
|
||||||
|
$(MAKE) $(BUILD_GOLANG_CMD)
|
||||||
|
DB_PORT=`docker-compose -p $(DOCKER_IMAGE_NAME)-uuid -f containers/docker-compose.local.yml port database 5432 | cut -f2 -d':'`; \
|
||||||
|
$(LAUNCH_GOLANG_CMD) serve --loglevel debug --logformat text --postgreshost localhost:$$DB_PORT
|
||||||
|
|
||||||
|
.PHONY: local-run
|
||||||
|
local-run: local-run-dependencies local-run-golang ## Run the server with its dependencies
|
||||||
118
cmd/root.go
Normal file
118
cmd/root.go
Normal file
@@ -0,0 +1,118 @@
|
|||||||
|
package cmd
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"github.com/kratisto/mam-contract/configuration"
|
||||||
|
"github.com/mitchellh/go-homedir"
|
||||||
|
"github.com/spf13/cobra"
|
||||||
|
"github.com/spf13/viper"
|
||||||
|
"os"
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
// Log
|
||||||
|
parameterLogLevel = "loglevel"
|
||||||
|
parameterLogFormat = "logformat"
|
||||||
|
|
||||||
|
defaultLogLevel = "debug"
|
||||||
|
defaultLogFormat = "text"
|
||||||
|
|
||||||
|
// Mock
|
||||||
|
parameterMock = "mock"
|
||||||
|
|
||||||
|
defaultMock = false
|
||||||
|
|
||||||
|
// Router
|
||||||
|
parameterPort = "port"
|
||||||
|
defaultPort = 8080
|
||||||
|
|
||||||
|
// DATABASE
|
||||||
|
parameterPostgresDBName = "postgresdbname"
|
||||||
|
defaultPostgresDBName = "postgres"
|
||||||
|
parameterPostgresDBSchema = "postgresdbschema"
|
||||||
|
defaultPostgresDBSchema = "workScheduler"
|
||||||
|
parameterPostgresHost = "postgreshost"
|
||||||
|
defaultPostgresHost = "database"
|
||||||
|
parameterPostgresUser = "postgresuser"
|
||||||
|
defaultPostgresUser = "postgres"
|
||||||
|
parameterPostgresPwd = "postgrespwd"
|
||||||
|
defaultPostgresPwd = "password"
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
config = &configuration.Config{}
|
||||||
|
|
||||||
|
cfgFile string
|
||||||
|
// GITHASH : Stores the git revision to be displayed
|
||||||
|
GITHASH string
|
||||||
|
// VERSION : Stores the binary version to be displayed
|
||||||
|
VERSION string
|
||||||
|
|
||||||
|
// rootCmd represents the base command when called without any subcommands
|
||||||
|
rootCmd = &cobra.Command{
|
||||||
|
Use: "workScheduler",
|
||||||
|
Short: "workScheduler",
|
||||||
|
Version: fmt.Sprintf("%s (%s)", VERSION, GITHASH),
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
// Execute adds all child commands to the root command and sets flags appropriately.
|
||||||
|
// This is called by main.main(). It only needs to happen once to the rootCmd.
|
||||||
|
func Execute() {
|
||||||
|
if err := rootCmd.Execute(); err != nil {
|
||||||
|
fmt.Println(err)
|
||||||
|
os.Exit(1)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
rootCmd.AddCommand(serveCmd)
|
||||||
|
|
||||||
|
// Here you will define your flags and configuration settings.
|
||||||
|
// Cobra supports persistent flags, which, if defined here,
|
||||||
|
// will be global for your application.
|
||||||
|
rootCmd.PersistentFlags().StringVar(&cfgFile, "config", "", "config file (default is $HOME/.workScheduler.yaml)")
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
// initConfig reads in config file and ENV variables if set.
|
||||||
|
func initConfig() {
|
||||||
|
if cfgFile != "" {
|
||||||
|
// Use config file from the flag.
|
||||||
|
viper.SetConfigFile(cfgFile)
|
||||||
|
} else {
|
||||||
|
// Find home directory.
|
||||||
|
home, err := homedir.Dir()
|
||||||
|
if err != nil {
|
||||||
|
fmt.Println(err)
|
||||||
|
os.Exit(1)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Search config in home directory with name ".workScheduler" (without extension).
|
||||||
|
viper.AddConfigPath(home)
|
||||||
|
viper.SetConfigName(".workScheduler")
|
||||||
|
}
|
||||||
|
|
||||||
|
viper.AutomaticEnv() // read in environment variables that match
|
||||||
|
|
||||||
|
// If a config file is found, read it in.
|
||||||
|
if err := viper.ReadInConfig(); err == nil {
|
||||||
|
fmt.Println("Using config file:", viper.ConfigFileUsed())
|
||||||
|
}
|
||||||
|
|
||||||
|
config.Mock = viper.GetBool(parameterMock)
|
||||||
|
|
||||||
|
config.Port = viper.GetInt(parameterPort)
|
||||||
|
|
||||||
|
config.LogLevel = viper.GetString(parameterLogLevel)
|
||||||
|
config.LogFormat = viper.GetString(parameterLogFormat)
|
||||||
|
|
||||||
|
config.PostgresDBName = viper.GetString(parameterPostgresDBName)
|
||||||
|
config.PostgresDBSchema = viper.GetString(parameterPostgresDBSchema)
|
||||||
|
config.PostgresHost = viper.GetString(parameterPostgresHost)
|
||||||
|
config.PostgresUser = viper.GetString(parameterPostgresUser)
|
||||||
|
config.PostgresPwd = viper.GetString(parameterPostgresPwd)
|
||||||
|
|
||||||
|
config.Version = VERSION
|
||||||
|
|
||||||
|
}
|
||||||
56
cmd/serve.go
Normal file
56
cmd/serve.go
Normal file
@@ -0,0 +1,56 @@
|
|||||||
|
package cmd
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/kratisto/mam-contract/internal/ginserver"
|
||||||
|
"github.com/kratisto/mam-contract/internal/health"
|
||||||
|
"github.com/kratisto/mam-contract/internal/utils"
|
||||||
|
"github.com/sirupsen/logrus"
|
||||||
|
"github.com/spf13/cobra"
|
||||||
|
"github.com/spf13/viper"
|
||||||
|
)
|
||||||
|
|
||||||
|
// serveCmd represents the serve command
|
||||||
|
var serveCmd = &cobra.Command{
|
||||||
|
Use: "serve",
|
||||||
|
Short: "Serve endpoints",
|
||||||
|
PreRun: initServeBindingsFlags,
|
||||||
|
Run: func(cmd *cobra.Command, args []string) {
|
||||||
|
initConfig()
|
||||||
|
utils.InitLogger(config.LogLevel, config.LogFormat)
|
||||||
|
logrus.
|
||||||
|
WithField(parameterLogLevel, config.LogLevel).
|
||||||
|
WithField(parameterLogFormat, config.LogFormat).
|
||||||
|
WithField(parameterPort, config.Port).
|
||||||
|
WithField(parameterPostgresHost, config.PostgresHost).
|
||||||
|
Warn("Configuration")
|
||||||
|
injector := &utils.Injector{}
|
||||||
|
ginserver.Setup(injector, config)
|
||||||
|
health.Setup(injector)
|
||||||
|
ginserver.Start(injector)
|
||||||
|
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
serveCmd.Flags().String(parameterLogLevel, defaultLogLevel, "Use this flag to set the logging level")
|
||||||
|
serveCmd.Flags().String(parameterLogFormat, defaultLogFormat, "Use this flag to set the logging format")
|
||||||
|
serveCmd.Flags().Bool(parameterMock, defaultMock, "Use this flag to mock external services")
|
||||||
|
serveCmd.Flags().Int(parameterPort, defaultPort, "Use this flag to set the listening port of the api")
|
||||||
|
serveCmd.Flags().String(parameterPostgresDBName, defaultPostgresDBName, "Use this flag to set database name")
|
||||||
|
serveCmd.Flags().String(parameterPostgresDBSchema, defaultPostgresDBSchema, "Use this flag to set database schema name")
|
||||||
|
serveCmd.Flags().String(parameterPostgresHost, defaultPostgresHost, "Use this flag to set database host")
|
||||||
|
serveCmd.Flags().String(parameterPostgresUser, defaultPostgresUser, "Use this flag to set database user name")
|
||||||
|
serveCmd.Flags().String(parameterPostgresPwd, defaultPostgresPwd, "Use this flag to set database user password")
|
||||||
|
}
|
||||||
|
|
||||||
|
func initServeBindingsFlags(cmd *cobra.Command, args []string) {
|
||||||
|
viper.BindPFlag(parameterLogLevel, cmd.Flags().Lookup(parameterLogLevel))
|
||||||
|
viper.BindPFlag(parameterLogFormat, cmd.Flags().Lookup(parameterLogFormat))
|
||||||
|
viper.BindPFlag(parameterMock, cmd.Flags().Lookup(parameterMock))
|
||||||
|
viper.BindPFlag(parameterPort, cmd.Flags().Lookup(parameterPort))
|
||||||
|
viper.BindPFlag(parameterPostgresDBName, cmd.Flags().Lookup(parameterPostgresDBName))
|
||||||
|
viper.BindPFlag(parameterPostgresDBSchema, cmd.Flags().Lookup(parameterPostgresDBSchema))
|
||||||
|
viper.BindPFlag(parameterPostgresHost, cmd.Flags().Lookup(parameterPostgresHost))
|
||||||
|
viper.BindPFlag(parameterPostgresUser, cmd.Flags().Lookup(parameterPostgresUser))
|
||||||
|
viper.BindPFlag(parameterPostgresPwd, cmd.Flags().Lookup(parameterPostgresPwd))
|
||||||
|
}
|
||||||
19
configuration/config.go
Normal file
19
configuration/config.go
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
package configuration
|
||||||
|
|
||||||
|
// Config holds all the configuration of the application
|
||||||
|
type Config struct {
|
||||||
|
Mock bool
|
||||||
|
|
||||||
|
Port int
|
||||||
|
|
||||||
|
LogLevel string
|
||||||
|
LogFormat string
|
||||||
|
|
||||||
|
PostgresDBName string
|
||||||
|
PostgresDBSchema string
|
||||||
|
PostgresHost string
|
||||||
|
PostgresUser string
|
||||||
|
PostgresPwd string
|
||||||
|
|
||||||
|
Version string
|
||||||
|
}
|
||||||
17
containers/Dockerfile
Normal file
17
containers/Dockerfile
Normal file
@@ -0,0 +1,17 @@
|
|||||||
|
# build stage
|
||||||
|
ARG SOURCES_IMAGE
|
||||||
|
FROM $SOURCES_IMAGE as builder
|
||||||
|
|
||||||
|
RUN make local-build
|
||||||
|
|
||||||
|
# final stage
|
||||||
|
FROM alpine:3.7
|
||||||
|
RUN apk --no-cache add ca-certificates
|
||||||
|
|
||||||
|
|
||||||
|
WORKDIR /app
|
||||||
|
COPY --from=builder /go/bin/MamContract .
|
||||||
|
EXPOSE 8080
|
||||||
|
|
||||||
|
ENTRYPOINT ["/app/MamContract"]
|
||||||
|
CMD ["serve", "--logformat", "json", "--loglevel", "debug"]
|
||||||
17
containers/Dockerfile.sources
Normal file
17
containers/Dockerfile.sources
Normal file
@@ -0,0 +1,17 @@
|
|||||||
|
FROM golang:1.11.2-alpine3.8
|
||||||
|
|
||||||
|
# Remove the cache to avoid warning message during `apk info`
|
||||||
|
RUN rm -rf /var/cache/apk/* && \
|
||||||
|
rm -rf /tmp/*
|
||||||
|
RUN apk update
|
||||||
|
|
||||||
|
# GO and PATH env variables already set in golang image
|
||||||
|
# to reduce download time
|
||||||
|
RUN apk --no-cache add -U make git musl-dev gcc
|
||||||
|
|
||||||
|
RUN wget https://raw.githubusercontent.com/golang/dep/master/install.sh && sh install.sh
|
||||||
|
|
||||||
|
WORKDIR $GOPATH/src/github.com/kratisto/MamContract
|
||||||
|
ADD . .
|
||||||
|
|
||||||
|
RUN make ensure-vendor
|
||||||
37
containers/docker-compose.local.yml
Normal file
37
containers/docker-compose.local.yml
Normal file
@@ -0,0 +1,37 @@
|
|||||||
|
version: "2.1"
|
||||||
|
|
||||||
|
services:
|
||||||
|
database:
|
||||||
|
image: postgres:10-alpine
|
||||||
|
ports:
|
||||||
|
- "5432"
|
||||||
|
environment:
|
||||||
|
- POSTGRES_PASSWORD=password
|
||||||
|
healthcheck:
|
||||||
|
test: ["CMD-SHELL", "psql -U postgres -c 'SELECT 1;'"]
|
||||||
|
interval: 10s
|
||||||
|
timeout: 30s
|
||||||
|
retries: 3
|
||||||
|
|
||||||
|
liquibase:
|
||||||
|
image: kilna/liquibase-mysql
|
||||||
|
depends_on:
|
||||||
|
database:
|
||||||
|
condition: service_healthy
|
||||||
|
links:
|
||||||
|
- database
|
||||||
|
environment:
|
||||||
|
- LIQUIBASE_DATABASE=workScheduler
|
||||||
|
- LIQUIBASE_HOST=database
|
||||||
|
- LIQUIBASE_USERNAME=postgres
|
||||||
|
- LIQUIBASE_PASSWORD=password
|
||||||
|
- LIQUIBASE_CHANGELOG=/changelogs/changelog-master.xml
|
||||||
|
- LIQUIBASE_CLASSPATH=/changelogs/postgresql-42.2.5.jar
|
||||||
|
- LIQUIBASE_DRIVER=org.postgresql.Driver
|
||||||
|
- LIQUIBASE_URL=jdbc:postgresql://database:5432/workScheduler
|
||||||
|
volumes:
|
||||||
|
- $PWD/liquibase/changelogs/:/workspace
|
||||||
|
command:
|
||||||
|
- liquibase
|
||||||
|
- --defaultsFile=/workspace/liquibase.properties
|
||||||
|
- update
|
||||||
47
dao/postgres.go
Normal file
47
dao/postgres.go
Normal file
@@ -0,0 +1,47 @@
|
|||||||
|
package dao
|
||||||
|
|
||||||
|
import (
|
||||||
|
"database/sql"
|
||||||
|
"fmt"
|
||||||
|
"github.com/kratisto/mam-contract/configuration"
|
||||||
|
|
||||||
|
_ "github.com/lib/pq" // Required to use the driver with database/sql
|
||||||
|
)
|
||||||
|
|
||||||
|
// Database is the interface for DB access
|
||||||
|
type Database interface {
|
||||||
|
Ping() error
|
||||||
|
}
|
||||||
|
|
||||||
|
// DatabasePostgreSQL is the implementation of the Database interface for PostgreSQL
|
||||||
|
type DatabasePostgreSQL struct {
|
||||||
|
session *sql.DB
|
||||||
|
schema string
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewDatabasePostgreSQL returns an instance of the database
|
||||||
|
func NewDatabasePostgreSQL(config *configuration.Config) Database {
|
||||||
|
var (
|
||||||
|
dbSession *sql.DB
|
||||||
|
err error
|
||||||
|
)
|
||||||
|
|
||||||
|
connectionURI := fmt.Sprintf("postgresql://%s:%s@%s/%s?sslmode=disable", config.PostgresUser, config.PostgresPwd, config.PostgresHost, config.PostgresDBName)
|
||||||
|
dbSession, err = sql.Open("postgres", connectionURI)
|
||||||
|
if err != nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
err = dbSession.Ping()
|
||||||
|
if err != nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
return &DatabasePostgreSQL{session: dbSession, schema: config.PostgresDBSchema}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Ping doesn't use db.Ping because it doesn't Ping after the first time
|
||||||
|
// https://stackoverflow.com/a/41619206/3853913
|
||||||
|
func (db *DatabasePostgreSQL) Ping() error {
|
||||||
|
_, err := db.session.Query("SELECT WHERE 1=0")
|
||||||
|
return err
|
||||||
|
}
|
||||||
58
go.mod
Normal file
58
go.mod
Normal file
@@ -0,0 +1,58 @@
|
|||||||
|
module github.com/kratisto/mam-contract
|
||||||
|
|
||||||
|
go 1.21
|
||||||
|
|
||||||
|
require (
|
||||||
|
github.com/gin-contrib/cors v1.4.0
|
||||||
|
github.com/gin-gonic/gin v1.8.1
|
||||||
|
github.com/lib/pq v1.0.0
|
||||||
|
github.com/mitchellh/go-homedir v1.1.0
|
||||||
|
github.com/sirupsen/logrus v1.2.0
|
||||||
|
github.com/spf13/cobra v0.0.3
|
||||||
|
github.com/spf13/viper v1.3.2
|
||||||
|
google.golang.org/api v0.3.0
|
||||||
|
gopkg.in/go-playground/validator.v9 v9.31.0
|
||||||
|
)
|
||||||
|
|
||||||
|
require (
|
||||||
|
cloud.google.com/go v0.34.0 // indirect
|
||||||
|
github.com/fsnotify/fsnotify v1.4.7 // indirect
|
||||||
|
github.com/gin-contrib/sse v0.1.0 // indirect
|
||||||
|
github.com/go-playground/locales v0.14.0 // indirect
|
||||||
|
github.com/go-playground/universal-translator v0.18.0 // indirect
|
||||||
|
github.com/go-playground/validator/v10 v10.10.0 // indirect
|
||||||
|
github.com/goccy/go-json v0.9.7 // indirect
|
||||||
|
github.com/golang/protobuf v1.5.0 // indirect
|
||||||
|
github.com/hashicorp/golang-lru v0.5.0 // indirect
|
||||||
|
github.com/hashicorp/hcl v1.0.0 // indirect
|
||||||
|
github.com/inconshreveable/mousetrap v1.1.0 // indirect
|
||||||
|
github.com/json-iterator/go v1.1.12 // indirect
|
||||||
|
github.com/konsorten/go-windows-terminal-sequences v1.0.1 // indirect
|
||||||
|
github.com/kr/pretty v0.3.1 // indirect
|
||||||
|
github.com/leodido/go-urn v1.2.1 // indirect
|
||||||
|
github.com/magiconair/properties v1.8.0 // indirect
|
||||||
|
github.com/mattn/go-isatty v0.0.14 // indirect
|
||||||
|
github.com/mitchellh/mapstructure v1.1.2 // indirect
|
||||||
|
github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421 // indirect
|
||||||
|
github.com/modern-go/reflect2 v1.0.2 // indirect
|
||||||
|
github.com/pelletier/go-toml v1.2.0 // indirect
|
||||||
|
github.com/pelletier/go-toml/v2 v2.0.1 // indirect
|
||||||
|
github.com/spf13/afero v1.1.2 // indirect
|
||||||
|
github.com/spf13/cast v1.3.0 // indirect
|
||||||
|
github.com/spf13/jwalterweatherman v1.0.0 // indirect
|
||||||
|
github.com/spf13/pflag v1.0.3 // indirect
|
||||||
|
github.com/ugorji/go/codec v1.2.7 // indirect
|
||||||
|
go.opencensus.io v0.19.2 // indirect
|
||||||
|
golang.org/x/crypto v0.0.0-20210711020723-a769d52b0f97 // indirect
|
||||||
|
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110 // indirect
|
||||||
|
golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421 // indirect
|
||||||
|
golang.org/x/sys v0.0.0-20210806184541-e5e7981a1069 // indirect
|
||||||
|
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1 // indirect
|
||||||
|
golang.org/x/text v0.3.6 // indirect
|
||||||
|
google.golang.org/appengine v1.4.0 // indirect
|
||||||
|
google.golang.org/genproto v0.0.0-20190307195333-5fe7a883aa19 // indirect
|
||||||
|
google.golang.org/grpc v1.19.0 // indirect
|
||||||
|
google.golang.org/protobuf v1.28.0 // indirect
|
||||||
|
gopkg.in/go-playground/assert.v1 v1.2.1 // indirect
|
||||||
|
gopkg.in/yaml.v2 v2.4.0 // indirect
|
||||||
|
)
|
||||||
262
go.sum
Normal file
262
go.sum
Normal file
@@ -0,0 +1,262 @@
|
|||||||
|
cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
|
||||||
|
cloud.google.com/go v0.34.0 h1:eOI3/cP2VTU6uZLDYAoic+eyzzB9YyGmJ7eIjl8rOPg=
|
||||||
|
cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
|
||||||
|
git.apache.org/thrift.git v0.12.0/go.mod h1:fPE2ZNJGynbRyZ4dJvy6G277gSllfV2HJqblrnkyeyg=
|
||||||
|
github.com/BurntSushi/toml v0.3.1 h1:WXkYYl6Yr3qBf1K79EBnL4mak0OimBfB0XUf9Vl28OQ=
|
||||||
|
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
|
||||||
|
github.com/Shopify/sarama v1.19.0/go.mod h1:FVkBWblsNy7DGZRfXLU0O9RCGt5g3g3yEuWXgklEdEo=
|
||||||
|
github.com/Shopify/toxiproxy v2.1.4+incompatible/go.mod h1:OXgGpZ6Cli1/URJOF1DMxUHB2q5Ap20/P/eIdh4G0pI=
|
||||||
|
github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc=
|
||||||
|
github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0=
|
||||||
|
github.com/apache/thrift v0.12.0/go.mod h1:cp2SuWMxlEZw2r+iP2GNCdIi4C1qmUzdZFSVb+bacwQ=
|
||||||
|
github.com/armon/consul-api v0.0.0-20180202201655-eb2c6b5be1b6/go.mod h1:grANhF5doyWs3UAsr3K4I6qtAmlQcZDesFNEHPZAzj8=
|
||||||
|
github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q=
|
||||||
|
github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=
|
||||||
|
github.com/coreos/etcd v3.3.10+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE=
|
||||||
|
github.com/coreos/go-etcd v2.0.0+incompatible/go.mod h1:Jez6KQU2B/sWsbdaef3ED8NzMklzPG4d5KIOhIy30Tk=
|
||||||
|
github.com/coreos/go-semver v0.2.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk=
|
||||||
|
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/eapache/go-resiliency v1.1.0/go.mod h1:kFI+JgMyC7bLPUVY133qvEBtVayf5mFgVsvEsIPBvNs=
|
||||||
|
github.com/eapache/go-xerial-snappy v0.0.0-20180814174437-776d5712da21/go.mod h1:+020luEh2TKB4/GOp8oxxtq0Daoen/Cii55CzbTV6DU=
|
||||||
|
github.com/eapache/queue v1.1.0/go.mod h1:6eCeP0CKFpHLu8blIFXhExK/dRa7WDZfr6jVFPTqq+I=
|
||||||
|
github.com/fsnotify/fsnotify v1.4.7 h1:IXs+QLmnXW2CcXuY+8Mzv/fWEsPGWxqefPtCP5CnV9I=
|
||||||
|
github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
|
||||||
|
github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04=
|
||||||
|
github.com/gin-contrib/cors v1.4.0 h1:oJ6gwtUl3lqV0WEIwM/LxPF1QZ5qe2lGWdY2+bz7y0g=
|
||||||
|
github.com/gin-contrib/cors v1.4.0/go.mod h1:bs9pNM0x/UsmHPBWT2xZz9ROh8xYjYkiURUfmBoMlcs=
|
||||||
|
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.8.1 h1:4+fr/el88TOO3ewCmQr8cx/CtZ/umlIRIs5M4NTNjf8=
|
||||||
|
github.com/gin-gonic/gin v1.8.1/go.mod h1:ji8BvRH1azfM+SYow9zQ6SZMvR8qOMZHmsCuWR9tTTk=
|
||||||
|
github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as=
|
||||||
|
github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE=
|
||||||
|
github.com/go-playground/assert/v2 v2.0.1 h1:MsBgLAaY856+nPRTKrp3/OZK38U/wa0CcBYNjji3q3A=
|
||||||
|
github.com/go-playground/assert/v2 v2.0.1/go.mod h1:VDjEfimB/XKnb+ZQfWdccd7VUvScMdVu0Titje2rxJ4=
|
||||||
|
github.com/go-playground/locales v0.14.0 h1:u50s323jtVGugKlcYeyzC0etD1HifMjqmJqb8WugfUU=
|
||||||
|
github.com/go-playground/locales v0.14.0/go.mod h1:sawfccIbzZTqEDETgFXqTho0QybSa7l++s0DH+LDiLs=
|
||||||
|
github.com/go-playground/universal-translator v0.18.0 h1:82dyy6p4OuJq4/CByFNOn/jYrnRPArHwAcmLoJZxyho=
|
||||||
|
github.com/go-playground/universal-translator v0.18.0/go.mod h1:UvRDBj+xPUEGrFYl+lu/H90nyDXpg0fqeB/AQUGNTVA=
|
||||||
|
github.com/go-playground/validator/v10 v10.10.0 h1:I7mrTYv78z8k8VXa/qJlOlEXn/nBh+BF8dHX5nt/dr0=
|
||||||
|
github.com/go-playground/validator/v10 v10.10.0/go.mod h1:74x4gJWsvQexRdW8Pn3dXSGrTK4nAUsbPlLADvpJkos=
|
||||||
|
github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY=
|
||||||
|
github.com/goccy/go-json v0.9.7 h1:IcB+Aqpx/iMHu5Yooh7jEzJk1JZ7Pjtmys2ukPr7EeM=
|
||||||
|
github.com/goccy/go-json v0.9.7/go.mod h1:6MelG93GURQebXPDq3khkgXZkazVtN9CRI+MGFi0w8I=
|
||||||
|
github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ=
|
||||||
|
github.com/gogo/protobuf v1.2.0/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ=
|
||||||
|
github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b h1:VKtxabqXZkF25pY9ekfRL6a582T4P37/31XEstQ5p58=
|
||||||
|
github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q=
|
||||||
|
github.com/golang/lint v0.0.0-20180702182130-06c8688daad7/go.mod h1:tluoj9z5200jBnyusfRPU2LqT6J+DAorxEvtC7LHB+E=
|
||||||
|
github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
|
||||||
|
github.com/golang/mock v1.2.0/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
|
||||||
|
github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
||||||
|
github.com/golang/protobuf v1.5.0 h1:LUVKkCeviFUMKqHa4tXIIij/lbhnMbP7Fn5wKdKkRh4=
|
||||||
|
github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk=
|
||||||
|
github.com/golang/snappy v0.0.0-20180518054509-2e65f85255db/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
|
||||||
|
github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M=
|
||||||
|
github.com/google/go-cmp v0.5.5 h1:Khx7svrCpmxxtHBq5j2mp/xVjsi8hQMfNLvJFAlrGgU=
|
||||||
|
github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||||
|
github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
|
||||||
|
github.com/gorilla/context v1.1.1/go.mod h1:kBGZzfjB9CEq2AlWe17Uuf7NDRt0dE0s8S51q0aT7Yg=
|
||||||
|
github.com/gorilla/mux v1.6.2/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2zaAs=
|
||||||
|
github.com/grpc-ecosystem/grpc-gateway v1.6.2/go.mod h1:RSKVYQBd5MCa4OVpNdGskqpgL2+G+NZTnrVHpWWfpdw=
|
||||||
|
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/hcl v1.0.0 h1:0Anlzjpi4vEasTeNFn2mLJgTSwt0+6sfsiTG8qcWGx4=
|
||||||
|
github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ=
|
||||||
|
github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU=
|
||||||
|
github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8=
|
||||||
|
github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw=
|
||||||
|
github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM=
|
||||||
|
github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo=
|
||||||
|
github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w=
|
||||||
|
github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
|
||||||
|
github.com/konsorten/go-windows-terminal-sequences v1.0.1 h1:mweAR1A6xJ3oS2pRaGiHgQ4OO8tzTaLawm8vnODuwDk=
|
||||||
|
github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
|
||||||
|
github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc=
|
||||||
|
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
|
||||||
|
github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI=
|
||||||
|
github.com/kr/pretty v0.3.0/go.mod h1:640gp4NfQd8pI5XOwp5fnNeVWj67G7CFk/SaSQn7NBk=
|
||||||
|
github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE=
|
||||||
|
github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk=
|
||||||
|
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/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
|
||||||
|
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
|
||||||
|
github.com/leodido/go-urn v1.2.1 h1:BqpAaACuzVSgi/VLzGZIobT2z4v53pjosyNd9Yv6n/w=
|
||||||
|
github.com/leodido/go-urn v1.2.1/go.mod h1:zt4jvISO2HfUBqxjfIshjdMTYS56ZS/qv49ictyFfxY=
|
||||||
|
github.com/lib/pq v1.0.0 h1:X5PMW56eZitiTeO7tKzZxFCSpbFZJtkMMooicw2us9A=
|
||||||
|
github.com/lib/pq v1.0.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo=
|
||||||
|
github.com/magiconair/properties v1.8.0 h1:LLgXmsheXeRoUOBOjtwPQCWIYqM/LU1ayDtDePerRcY=
|
||||||
|
github.com/magiconair/properties v1.8.0/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ=
|
||||||
|
github.com/mattn/go-isatty v0.0.14 h1:yVuAays6BHfxijgZPzw+3Zlu5yQgKGP2/hcQbHb7S9Y=
|
||||||
|
github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94=
|
||||||
|
github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0=
|
||||||
|
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/mapstructure v1.1.2 h1:fmNYVwqnSfB9mZU6OS2O6GsXM+wcskZDuKQzvN1EDeE=
|
||||||
|
github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y=
|
||||||
|
github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421 h1:ZqeYNhU3OHLH3mGKHDcjJRFFRrJa6eAM5H+CtDdOsPc=
|
||||||
|
github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
|
||||||
|
github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9Gz0M=
|
||||||
|
github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk=
|
||||||
|
github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U=
|
||||||
|
github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
|
||||||
|
github.com/onsi/ginkgo v1.7.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
|
||||||
|
github.com/onsi/gomega v1.4.3/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY=
|
||||||
|
github.com/openzipkin/zipkin-go v0.1.3/go.mod h1:NtoC/o8u3JlF1lSlyPNswIbeQH9bJTmOf0Erfk+hxe8=
|
||||||
|
github.com/openzipkin/zipkin-go v0.1.6/go.mod h1:QgAqvLzwWbR/WpD4A3cGpPtJrZXNIiJc5AZX7/PBEpw=
|
||||||
|
github.com/pelletier/go-toml v1.2.0 h1:T5zMGML61Wp+FlcbWjRDT7yAxhJNAiPPLOFECq181zc=
|
||||||
|
github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic=
|
||||||
|
github.com/pelletier/go-toml/v2 v2.0.1 h1:8e3L2cCQzLFi2CR4g7vGFuFxX7Jl1kKX8gW+iV0GUKU=
|
||||||
|
github.com/pelletier/go-toml/v2 v2.0.1/go.mod h1:r9LEWfGN8R5k0VXJ+0BkIe7MYkRdwZOjgMj2KwnJFUo=
|
||||||
|
github.com/pierrec/lz4 v2.0.5+incompatible/go.mod h1:pdkljMzZIN41W+lC3N2tnIh5sFi+IEE17M5jbnwPHcY=
|
||||||
|
github.com/pkg/diff v0.0.0-20210226163009-20ebb0f2a09e/go.mod h1:pJLUxLENpZxwdsKMEsNbx1VGcRFpLqf3715MtcvvzbA=
|
||||||
|
github.com/pkg/errors v0.8.0/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/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw=
|
||||||
|
github.com/prometheus/client_golang v0.9.3-0.20190127221311-3c4408c8b829/go.mod h1:p2iRAGwDERtqlqzRXnrOVns+ignqQo//hLXqYxZYVNs=
|
||||||
|
github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo=
|
||||||
|
github.com/prometheus/client_model v0.0.0-20190115171406-56726106282f/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo=
|
||||||
|
github.com/prometheus/common v0.2.0/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4=
|
||||||
|
github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk=
|
||||||
|
github.com/prometheus/procfs v0.0.0-20190117184657-bf6a532e95b1/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk=
|
||||||
|
github.com/rcrowley/go-metrics v0.0.0-20181016184325-3113b8401b8a/go.mod h1:bCqnVzQkZxMG4s8nGwiZ5l3QUCyqpo9Y+/ZMZ9VjZe4=
|
||||||
|
github.com/rogpeppe/go-internal v1.6.1/go.mod h1:xXDCJY+GAPziupqXw64V24skbSoqbTEfhy4qGm1nDQc=
|
||||||
|
github.com/rogpeppe/go-internal v1.8.0/go.mod h1:WmiCO8CzOY8rg0OYDC4/i/2WRWAB6poM+XZ2dLUbcbE=
|
||||||
|
github.com/rogpeppe/go-internal v1.9.0 h1:73kH8U+JUqXU8lRuOHeVHaa/SZPifC7BkcraZVejAe8=
|
||||||
|
github.com/rogpeppe/go-internal v1.9.0/go.mod h1:WtVeX8xhTBvf0smdhujwtBcq4Qrzq/fJaraNFVN+nFs=
|
||||||
|
github.com/sirupsen/logrus v1.2.0 h1:juTguoYk5qI21pwyTXY3B3Y5cOTH3ZUyZCg1v/mihuo=
|
||||||
|
github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo=
|
||||||
|
github.com/spf13/afero v1.1.2 h1:m8/z1t7/fwjysjQRYbP0RD+bUIF/8tJwPdEZsI83ACI=
|
||||||
|
github.com/spf13/afero v1.1.2/go.mod h1:j4pytiNVoe2o6bmDsKpLACNPDBIoEAkihy7loJ1B0CQ=
|
||||||
|
github.com/spf13/cast v1.3.0 h1:oget//CVOEoFewqQxwr0Ej5yjygnqGkvggSE/gB35Q8=
|
||||||
|
github.com/spf13/cast v1.3.0/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE=
|
||||||
|
github.com/spf13/cobra v0.0.3 h1:ZlrZ4XsMRm04Fr5pSFxBgfND2EBVa1nLpiy1stUsX/8=
|
||||||
|
github.com/spf13/cobra v0.0.3/go.mod h1:1l0Ry5zgKvJasoi3XT1TypsSe7PqH0Sj9dhYf7v3XqQ=
|
||||||
|
github.com/spf13/jwalterweatherman v1.0.0 h1:XHEdyB+EcvlqZamSM4ZOMGlc93t6AcsBEu9Gc1vn7yk=
|
||||||
|
github.com/spf13/jwalterweatherman v1.0.0/go.mod h1:cQK4TGJAtQXfYWX+Ddv3mKDzgVb68N+wFjFa4jdeBTo=
|
||||||
|
github.com/spf13/pflag v1.0.3 h1:zPAT6CGy6wXeQ7NtTnaTerfKOsV6V6F8agHXFiazDkg=
|
||||||
|
github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4=
|
||||||
|
github.com/spf13/viper v1.3.2 h1:VUFqw5KcqRf7i70GOzW7N+Q7+gxVBkSSqiXB12+JQ4M=
|
||||||
|
github.com/spf13/viper v1.3.2/go.mod h1:ZiWeW+zYFKm7srdB9IoDzzZXaJaI5eL9QjNiN/DMA2s=
|
||||||
|
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||||
|
github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||||
|
github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
|
||||||
|
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
|
||||||
|
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
|
||||||
|
github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||||
|
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 h1:pSgiaMZlXftHpm5L7V1+rVB+AZJydKsMxsQBIJw4PKk=
|
||||||
|
github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
|
||||||
|
github.com/ugorji/go v1.2.7/go.mod h1:nF9osbDWLy6bDVv/Rtoh6QgnvNDpmCalQV5urGCCS6M=
|
||||||
|
github.com/ugorji/go/codec v0.0.0-20181204163529-d75b2dcb6bc8/go.mod h1:VFNgLljTbGfSG7qAOspJ7OScBnGdDN/yBr0sguwnwf0=
|
||||||
|
github.com/ugorji/go/codec v1.2.7 h1:YPXUKf7fYbp/y8xloBqZOw2qaVggbfwMlI8WM3wZUJ0=
|
||||||
|
github.com/ugorji/go/codec v1.2.7/go.mod h1:WGN1fab3R1fzQlVQTkfxVtIBhWDRqOviHU95kRgeqEY=
|
||||||
|
github.com/xordataexchange/crypt v0.0.3-0.20170626215501-b2862e3d0a77/go.mod h1:aYKd//L2LvnjZzWKhF00oedf4jCCReLcmhLdhm1A27Q=
|
||||||
|
go.opencensus.io v0.19.1/go.mod h1:gug0GbSHa8Pafr0d2urOSgoXHZ6x/RUlaiT0d9pqb4A=
|
||||||
|
go.opencensus.io v0.19.2 h1:ZZpq6xI6kv/LuE/5s5UQvBU5vMjvRnPb8PvJrIntAnc=
|
||||||
|
go.opencensus.io v0.19.2/go.mod h1:NO/8qkisMZLZ1FCsKNqtJPwc8/TaclWyY0B6wcYNg9M=
|
||||||
|
golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
|
||||||
|
golang.org/x/crypto v0.0.0-20181203042331-505ab145d0a9/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
|
||||||
|
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
||||||
|
golang.org/x/crypto v0.0.0-20210711020723-a769d52b0f97 h1:/UOmuWzQfxxo9UtlXMwuQU8CMgg1eZXqTRwkSQJWKOI=
|
||||||
|
golang.org/x/crypto v0.0.0-20210711020723-a769d52b0f97/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
|
||||||
|
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
|
||||||
|
golang.org/x/lint v0.0.0-20180702182130-06c8688daad7/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
|
||||||
|
golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
|
||||||
|
golang.org/x/lint v0.0.0-20181217174547-8f45f776aaf1/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
|
||||||
|
golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU=
|
||||||
|
golang.org/x/lint v0.0.0-20190301231843-5614ed5bae6f/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
|
||||||
|
golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||||
|
golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||||
|
golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||||
|
golang.org/x/net v0.0.0-20181106065722-10aee1819953/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||||
|
golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||||
|
golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||||
|
golang.org/x/net v0.0.0-20190125091013-d26f9f9a57f3/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||||
|
golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||||
|
golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||||
|
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110 h1:qWPm9rbaAMKs8Bq/9LRpbMqxWRVUAQwMI9fVrssnTfw=
|
||||||
|
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
|
||||||
|
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
|
||||||
|
golang.org/x/oauth2 v0.0.0-20181203162652-d668ce993890/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
|
||||||
|
golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421 h1:Wo7BWFiOk0QRFMLYMqJGFMd9CgUAcGx7V+qEg/h5IBI=
|
||||||
|
golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
|
||||||
|
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||||
|
golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||||
|
golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||||
|
golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||||
|
golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||||
|
golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||||
|
golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||||
|
golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||||
|
golang.org/x/sys v0.0.0-20181122145206-62eef0e2fa9b/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||||
|
golang.org/x/sys v0.0.0-20181205085412-a5c9d58dba9a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||||
|
golang.org/x/sys v0.0.0-20181218192612-074acd46bca6/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||||
|
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||||
|
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/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-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
|
golang.org/x/sys v0.0.0-20210806184541-e5e7981a1069 h1:siQdpVirKtzPhKl3lZWozZraCFObP8S1v6PRp0bLrtU=
|
||||||
|
golang.org/x/sys v0.0.0-20210806184541-e5e7981a1069/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
|
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1 h1:v+OssWQX+hTHEmOBgwxdZxK4zHq3yOs8F9J7mk0PY8E=
|
||||||
|
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.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||||
|
golang.org/x/text v0.3.6 h1:aRYxNxv6iGQlyVaZmk6ZgYEDa+Jg18DxebPSrd6bg1M=
|
||||||
|
golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||||
|
golang.org/x/tools v0.0.0-20180828015842-6cd1fcedba52/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||||
|
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||||
|
golang.org/x/tools v0.0.0-20181219222714-6e267b5cc78e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||||
|
golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||||
|
golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY=
|
||||||
|
golang.org/x/tools v0.0.0-20190312170243-e65039ee4138/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
|
||||||
|
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543 h1:E7g+9GITq07hpfrRu66IVDexMakfv52eLZ2CXBWiKr4=
|
||||||
|
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||||
|
google.golang.org/api v0.0.0-20181220000619-583d854617af/go.mod h1:4mhQ8q/RsB7i+udVvVy5NUi08OU8ZlA0gRVgrF7VFY0=
|
||||||
|
google.golang.org/api v0.2.0/go.mod h1:IfRCZScioGtypHNTlz3gFk67J8uePVW7uDTBzXuIkhU=
|
||||||
|
google.golang.org/api v0.3.0 h1:UIJY20OEo3+tK5MBlcdx37kmdH6EnRjGkW78mc6+EeA=
|
||||||
|
google.golang.org/api v0.3.0/go.mod h1:IuvZyQh8jgscv8qWfQ4ABd8m7hEudgBFM/EdhA3BnXw=
|
||||||
|
google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM=
|
||||||
|
google.golang.org/appengine v1.3.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
|
||||||
|
google.golang.org/appengine v1.4.0 h1:/wp5JvzpHIxhs/dumFmF7BXTf3Z+dd4uXta4kVyO508=
|
||||||
|
google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
|
||||||
|
google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc=
|
||||||
|
google.golang.org/genproto v0.0.0-20181219182458-5a97ab628bfb/go.mod h1:7Ep/1NZk928CDR8SjdVbjWNpdIf6nzjE3BTgJDr2Atg=
|
||||||
|
google.golang.org/genproto v0.0.0-20190307195333-5fe7a883aa19 h1:Lj2SnHtxkRGJDqnGaSjo+CCdIieEnwVazbOXILwQemk=
|
||||||
|
google.golang.org/genproto v0.0.0-20190307195333-5fe7a883aa19/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
|
||||||
|
google.golang.org/grpc v1.16.0/go.mod h1:0JHn/cJsOMiMfNA9+DeHDlAU7KAAB5GDlYFpa9MZMio=
|
||||||
|
google.golang.org/grpc v1.17.0/go.mod h1:6QZJwpn2B+Zp71q/5VxRsJ6NXXVCE5NRUHRo+f3cWCs=
|
||||||
|
google.golang.org/grpc v1.19.0 h1:cfg4PD8YEdSFnm7qLV4++93WcmhH2nIUhMjhdCvl3j8=
|
||||||
|
google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=
|
||||||
|
google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw=
|
||||||
|
google.golang.org/protobuf v1.28.0 h1:w43yiav+6bVFTBQFZX0r7ipe9JQ1QsbMgHwbBziscLw=
|
||||||
|
google.golang.org/protobuf v1.28.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I=
|
||||||
|
gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw=
|
||||||
|
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||||
|
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||||
|
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
|
||||||
|
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q=
|
||||||
|
gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI=
|
||||||
|
gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys=
|
||||||
|
gopkg.in/go-playground/assert.v1 v1.2.1 h1:xoYuJVE7KT85PYWrN730RguIQO0ePzVRfFMXadIrXTM=
|
||||||
|
gopkg.in/go-playground/assert.v1 v1.2.1/go.mod h1:9RXL0bg/zibRAgZUYszZSwO/z8Y/a8bDuhia5mkpMnE=
|
||||||
|
gopkg.in/go-playground/validator.v9 v9.31.0 h1:bmXmP2RSNtFES+bn4uYuHT7iJFJv7Vj+an+ZQdDaD1M=
|
||||||
|
gopkg.in/go-playground/validator.v9 v9.31.0/go.mod h1:+c9/zcJMFNgbLvly1L1V+PpxWdVbfP1avr/N00E2vyQ=
|
||||||
|
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw=
|
||||||
|
gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||||
|
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||||
|
gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY=
|
||||||
|
gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ=
|
||||||
|
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=
|
||||||
|
honnef.co/go/tools v0.0.0-20180728063816-88497007e858/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
||||||
|
honnef.co/go/tools v0.0.0-20180920025451-e3ad64cb4ed3/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
||||||
|
honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
||||||
71
internal/ginserver/logger.go
Executable file
71
internal/ginserver/logger.go
Executable file
@@ -0,0 +1,71 @@
|
|||||||
|
package ginserver
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/kratisto/mam-contract/internal/utils"
|
||||||
|
"math/rand"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/gin-gonic/gin"
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
letterBytes = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"
|
||||||
|
letterIdxBits = 6 // 6 bits to represent a letter index
|
||||||
|
letterIdxMask = 1<<letterIdxBits - 1 // All 1-bits, as many as letterIdxBits
|
||||||
|
letterIdxMax = 63 / letterIdxBits // # of letter indices fitting in 63 bits
|
||||||
|
)
|
||||||
|
|
||||||
|
var src = rand.NewSource(time.Now().UnixNano())
|
||||||
|
|
||||||
|
func randStringBytesMaskImprSrc(n int) string {
|
||||||
|
b := make([]byte, n)
|
||||||
|
// A src.Int63() generates 63 random bits, enough for letterIdxMax characters!
|
||||||
|
for i, cache, remain := n-1, src.Int63(), letterIdxMax; i >= 0; {
|
||||||
|
if remain == 0 {
|
||||||
|
cache, remain = src.Int63(), letterIdxMax
|
||||||
|
}
|
||||||
|
if idx := int(cache & letterIdxMask); idx < len(letterBytes) {
|
||||||
|
b[i] = letterBytes[idx]
|
||||||
|
i--
|
||||||
|
}
|
||||||
|
cache >>= letterIdxBits
|
||||||
|
remain--
|
||||||
|
}
|
||||||
|
|
||||||
|
return string(b)
|
||||||
|
}
|
||||||
|
|
||||||
|
func GetLoggerMiddleware() gin.HandlerFunc {
|
||||||
|
return func(c *gin.Context) {
|
||||||
|
correlationID := c.Request.Header.Get(utils.HeaderNameCorrelationID)
|
||||||
|
if correlationID == "" {
|
||||||
|
correlationID = randStringBytesMaskImprSrc(30)
|
||||||
|
c.Writer.Header().Set(utils.HeaderNameCorrelationID, correlationID)
|
||||||
|
}
|
||||||
|
|
||||||
|
logger := utils.GetLogger()
|
||||||
|
logEntry := logger.WithField(utils.HeaderNameCorrelationID, correlationID)
|
||||||
|
|
||||||
|
c.Set(utils.ContextKeyLogger, logEntry)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func GetHTTPLoggerMiddleware() gin.HandlerFunc {
|
||||||
|
return func(c *gin.Context) {
|
||||||
|
start := time.Now()
|
||||||
|
|
||||||
|
utils.GetLoggerFromCtx(c).
|
||||||
|
WithField("method", c.Request.Method).
|
||||||
|
WithField("url", c.Request.RequestURI).
|
||||||
|
WithField("from", c.ClientIP()).
|
||||||
|
Info("start handling HTTP request")
|
||||||
|
|
||||||
|
c.Next()
|
||||||
|
d := time.Since(start)
|
||||||
|
|
||||||
|
utils.GetLoggerFromCtx(c).
|
||||||
|
WithField("status", c.Writer.Status()).
|
||||||
|
WithField("duration", d.String()).
|
||||||
|
Info("end handling HTTP request")
|
||||||
|
}
|
||||||
|
}
|
||||||
40
internal/ginserver/oauth_token.go
Normal file
40
internal/ginserver/oauth_token.go
Normal file
@@ -0,0 +1,40 @@
|
|||||||
|
package ginserver
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"github.com/kratisto/mam-contract/internal/storage/model"
|
||||||
|
"github.com/kratisto/mam-contract/internal/utils"
|
||||||
|
"net/http"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"github.com/gin-gonic/gin"
|
||||||
|
"google.golang.org/api/oauth2/v1"
|
||||||
|
)
|
||||||
|
|
||||||
|
func ValidateOAuthToken(c *gin.Context) {
|
||||||
|
authorizationHeader := c.GetHeader("Authorization")
|
||||||
|
authorizationHeaderSplitted := strings.Split(authorizationHeader, " ")
|
||||||
|
if len(authorizationHeaderSplitted) != 2 {
|
||||||
|
utils.JSONError(c.Writer, model.ErrBadRequestFormat)
|
||||||
|
c.Abort()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
oauth2Service, err := oauth2.New(&http.Client{})
|
||||||
|
if oauth2Service == nil {
|
||||||
|
fmt.Println(err)
|
||||||
|
utils.JSONError(c.Writer, model.ErrInternalServer)
|
||||||
|
c.Abort()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
tokenInfoCall := oauth2Service.Tokeninfo()
|
||||||
|
tokenInfoCall.IdToken(authorizationHeaderSplitted[1])
|
||||||
|
token, err := tokenInfoCall.Do()
|
||||||
|
if err != nil {
|
||||||
|
utils.GetLogger().WithError(err).Error(err)
|
||||||
|
utils.JSONError(c.Writer, model.ErrBadRequestFormat)
|
||||||
|
c.Abort()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
c.Set("googleUserId", token.UserId)
|
||||||
|
}
|
||||||
45
internal/ginserver/setup.go
Normal file
45
internal/ginserver/setup.go
Normal file
@@ -0,0 +1,45 @@
|
|||||||
|
package ginserver
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/gin-contrib/cors"
|
||||||
|
"github.com/gin-gonic/gin"
|
||||||
|
"github.com/kratisto/mam-contract/configuration"
|
||||||
|
"github.com/kratisto/mam-contract/internal/utils"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
routerInjectorKey = "ROUTER"
|
||||||
|
|
||||||
|
SecuredRouterInjectorKey = "SECURED_ROUTER"
|
||||||
|
UnsecuredRouterInjectorKey = "UNSECURED_ROUTER"
|
||||||
|
)
|
||||||
|
|
||||||
|
func Setup(injector *utils.Injector, config *configuration.Config) {
|
||||||
|
|
||||||
|
gin.SetMode(gin.ReleaseMode)
|
||||||
|
|
||||||
|
router := gin.New()
|
||||||
|
router.HandleMethodNotAllowed = true
|
||||||
|
|
||||||
|
router.Use(cors.New(cors.Config{
|
||||||
|
AllowOrigins: []string{"http://localhost:8080/", "http://localhost:8080", "http://localhost:19006"},
|
||||||
|
AllowMethods: []string{"*"},
|
||||||
|
AllowHeaders: []string{"*"},
|
||||||
|
ExposeHeaders: []string{"*"},
|
||||||
|
AllowCredentials: true,
|
||||||
|
MaxAge: 12 * time.Hour,
|
||||||
|
}))
|
||||||
|
router.Use(gin.Recovery())
|
||||||
|
router.Use(GetLoggerMiddleware())
|
||||||
|
router.Use(GetHTTPLoggerMiddleware())
|
||||||
|
public := router.Group("/")
|
||||||
|
injector.Set(UnsecuredRouterInjectorKey, public)
|
||||||
|
|
||||||
|
securedUserRoute := public.Group("/users")
|
||||||
|
securedUserRoute.Use(ValidateOAuthToken)
|
||||||
|
|
||||||
|
injector.Set(SecuredRouterInjectorKey, securedUserRoute)
|
||||||
|
injector.Set(routerInjectorKey, router)
|
||||||
|
|
||||||
|
}
|
||||||
38
internal/ginserver/start.go
Normal file
38
internal/ginserver/start.go
Normal file
@@ -0,0 +1,38 @@
|
|||||||
|
package ginserver
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/gin-gonic/gin"
|
||||||
|
"github.com/kratisto/mam-contract/internal/utils"
|
||||||
|
"log"
|
||||||
|
"net/http"
|
||||||
|
"os"
|
||||||
|
"os/signal"
|
||||||
|
"syscall"
|
||||||
|
)
|
||||||
|
|
||||||
|
func Start(injector *utils.Injector) {
|
||||||
|
router := utils.Get[*gin.Engine](injector, routerInjectorKey)
|
||||||
|
|
||||||
|
srv := &http.Server{
|
||||||
|
Addr: ":8080",
|
||||||
|
Handler: router,
|
||||||
|
}
|
||||||
|
|
||||||
|
go func() {
|
||||||
|
// service connections
|
||||||
|
if err := srv.ListenAndServe(); err != nil && err != http.ErrServerClosed {
|
||||||
|
log.Fatalf("listen: %s\n", err)
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
|
||||||
|
// Wait for interrupt signal to gracefully shutdown the server with
|
||||||
|
// a timeout of 5 seconds.
|
||||||
|
quit := make(chan os.Signal)
|
||||||
|
// kill (no param) default send syscanll.SIGTERM
|
||||||
|
// kill -2 is syscall.SIGINT
|
||||||
|
// kill -9 is syscall. SIGKILL but can"t be catch, so don't need add it
|
||||||
|
signal.Notify(quit, syscall.SIGINT, syscall.SIGTERM)
|
||||||
|
<-quit
|
||||||
|
log.Println("Shutdown Server ...")
|
||||||
|
|
||||||
|
}
|
||||||
27
internal/health/handler.go
Normal file
27
internal/health/handler.go
Normal file
@@ -0,0 +1,27 @@
|
|||||||
|
package health
|
||||||
|
|
||||||
|
import (
|
||||||
|
"net/http"
|
||||||
|
|
||||||
|
"github.com/gin-gonic/gin"
|
||||||
|
)
|
||||||
|
|
||||||
|
// @openapi:path
|
||||||
|
// /_health:
|
||||||
|
//
|
||||||
|
// get:
|
||||||
|
// tags:
|
||||||
|
// - "Monitoring"
|
||||||
|
// summary: Health check
|
||||||
|
// description: Health check
|
||||||
|
// responses:
|
||||||
|
// 200:
|
||||||
|
// description: "Health response"
|
||||||
|
// content:
|
||||||
|
// application/json:
|
||||||
|
// schema:
|
||||||
|
// $ref: "#/components/schemas/Health"
|
||||||
|
func GetHealth(c *gin.Context) {
|
||||||
|
health := &Health{Alive: true}
|
||||||
|
c.JSON(http.StatusOK, health)
|
||||||
|
}
|
||||||
8
internal/health/model.go
Normal file
8
internal/health/model.go
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
package health
|
||||||
|
|
||||||
|
// Health struct
|
||||||
|
// @openapi:schema
|
||||||
|
type Health struct {
|
||||||
|
Alive bool `json:"alive"`
|
||||||
|
Version string `json:"version"`
|
||||||
|
}
|
||||||
15
internal/health/setup.go
Normal file
15
internal/health/setup.go
Normal file
@@ -0,0 +1,15 @@
|
|||||||
|
package health
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/gin-gonic/gin"
|
||||||
|
"github.com/kratisto/mam-contract/internal/ginserver"
|
||||||
|
"github.com/kratisto/mam-contract/internal/utils"
|
||||||
|
"net/http"
|
||||||
|
)
|
||||||
|
|
||||||
|
func Setup(injector *utils.Injector) {
|
||||||
|
publicRoute := utils.Get[*gin.RouterGroup](injector, ginserver.UnsecuredRouterInjectorKey)
|
||||||
|
//TODO add secure auth
|
||||||
|
publicRoute.Handle(http.MethodGet, "/health", GetHealth)
|
||||||
|
|
||||||
|
}
|
||||||
32
internal/storage/dao/database_error.go
Executable file
32
internal/storage/dao/database_error.go
Executable file
@@ -0,0 +1,32 @@
|
|||||||
|
package dao
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
)
|
||||||
|
|
||||||
|
type Type int
|
||||||
|
|
||||||
|
const (
|
||||||
|
ErrTypeNotFound Type = iota
|
||||||
|
ErrTypeDuplicate
|
||||||
|
ErrTypeForeignKeyViolation
|
||||||
|
)
|
||||||
|
|
||||||
|
type Error struct {
|
||||||
|
Cause error
|
||||||
|
Type Type
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewDAOError(t Type, cause error) error {
|
||||||
|
return &Error{
|
||||||
|
Type: t,
|
||||||
|
Cause: cause,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e *Error) Error() string {
|
||||||
|
if e.Cause != nil {
|
||||||
|
return fmt.Sprintf("Type %d: %s", e.Type, e.Cause.Error())
|
||||||
|
}
|
||||||
|
return fmt.Sprintf("Type %d: no cause given", e.Type)
|
||||||
|
}
|
||||||
43
internal/storage/dao/postgresql/database_postgresql.go
Executable file
43
internal/storage/dao/postgresql/database_postgresql.go
Executable file
@@ -0,0 +1,43 @@
|
|||||||
|
package postgresql
|
||||||
|
|
||||||
|
import (
|
||||||
|
"database/sql"
|
||||||
|
"fmt"
|
||||||
|
"github.com/kratisto/mam-contract/internal/storage/dao"
|
||||||
|
"github.com/kratisto/mam-contract/internal/utils"
|
||||||
|
|
||||||
|
"github.com/lib/pq"
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
pgCodeUniqueViolation = "23505"
|
||||||
|
pgCodeForeingKeyViolation = "23503"
|
||||||
|
)
|
||||||
|
|
||||||
|
func HandlePgError(e *pq.Error) error {
|
||||||
|
if e.Code == pgCodeUniqueViolation {
|
||||||
|
return dao.NewDAOError(dao.ErrTypeDuplicate, e)
|
||||||
|
}
|
||||||
|
|
||||||
|
if e.Code == pgCodeForeingKeyViolation {
|
||||||
|
return dao.NewDAOError(dao.ErrTypeForeignKeyViolation, e)
|
||||||
|
}
|
||||||
|
return e
|
||||||
|
}
|
||||||
|
|
||||||
|
type DatabasePostgreSQL struct {
|
||||||
|
Session *sql.DB
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewDatabasePostgreSQL(connectionURI string) *DatabasePostgreSQL {
|
||||||
|
db, err := sql.Open("postgres", connectionURI)
|
||||||
|
if err != nil {
|
||||||
|
utils.GetLogger().WithError(err).Fatal("Unable to get a connection to the postgres db")
|
||||||
|
}
|
||||||
|
err = db.Ping()
|
||||||
|
if err != nil {
|
||||||
|
fmt.Println(err)
|
||||||
|
utils.GetLogger().WithError(err).Fatal("Unable to ping the postgres db")
|
||||||
|
}
|
||||||
|
return &DatabasePostgreSQL{Session: db}
|
||||||
|
}
|
||||||
13
internal/storage/dao/postgresql/setup.go
Normal file
13
internal/storage/dao/postgresql/setup.go
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
package postgresql
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/kratisto/mam-contract/internal/utils"
|
||||||
|
)
|
||||||
|
|
||||||
|
var DatabaseKey = "POSTGRES"
|
||||||
|
|
||||||
|
func Setup(injector *utils.Injector, connectionUri string) {
|
||||||
|
database := NewDatabasePostgreSQL(connectionUri)
|
||||||
|
|
||||||
|
injector.Set(DatabaseKey, database)
|
||||||
|
}
|
||||||
68
internal/storage/model/error.go
Normal file
68
internal/storage/model/error.go
Normal file
@@ -0,0 +1,68 @@
|
|||||||
|
package model
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"net/http"
|
||||||
|
|
||||||
|
"github.com/lib/pq"
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
// 400
|
||||||
|
ErrBadRequestFormat = APIError{
|
||||||
|
Type: "bad_format",
|
||||||
|
HTTPCode: http.StatusBadRequest,
|
||||||
|
Description: "unable to read request body, please check that the json is valid",
|
||||||
|
}
|
||||||
|
ErrDataValidation = APIError{
|
||||||
|
Type: "data_validation",
|
||||||
|
HTTPCode: http.StatusBadRequest,
|
||||||
|
Description: "the data are not valid",
|
||||||
|
}
|
||||||
|
|
||||||
|
// 404
|
||||||
|
ErrNotFound = APIError{
|
||||||
|
Type: "not_found",
|
||||||
|
HTTPCode: http.StatusNotFound,
|
||||||
|
}
|
||||||
|
|
||||||
|
// 40x
|
||||||
|
ErrAlreadyExists = APIError{
|
||||||
|
Type: "already_exists",
|
||||||
|
HTTPCode: http.StatusConflict,
|
||||||
|
}
|
||||||
|
|
||||||
|
// 50x
|
||||||
|
ErrInternalServer = APIError{
|
||||||
|
Type: "internal_server_error",
|
||||||
|
HTTPCode: http.StatusInternalServerError,
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
type APIError struct {
|
||||||
|
HTTPCode int `json:"-"`
|
||||||
|
Type string `json:"error"`
|
||||||
|
Description string `json:"error_description"`
|
||||||
|
Details []FieldError `json:"error_details,omitempty"`
|
||||||
|
Headers map[string][]string `json:"-"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type FieldError struct {
|
||||||
|
Field string `json:"field"`
|
||||||
|
Constraint string `json:"constraint"`
|
||||||
|
Description string `json:"description"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e *APIError) Error() string {
|
||||||
|
return fmt.Sprintf("error : %d, %s, %s, %v", e.HTTPCode, e.Type, e.Description, e.Details)
|
||||||
|
}
|
||||||
|
|
||||||
|
func FromPostgresError(err *pq.Error) *APIError {
|
||||||
|
return &APIError{
|
||||||
|
HTTPCode: 0,
|
||||||
|
Type: "",
|
||||||
|
Description: "",
|
||||||
|
Details: nil,
|
||||||
|
Headers: nil,
|
||||||
|
}
|
||||||
|
}
|
||||||
44
internal/storage/validators/error.go
Executable file
44
internal/storage/validators/error.go
Executable file
@@ -0,0 +1,44 @@
|
|||||||
|
package validators
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"github.com/kratisto/mam-contract/internal/storage/model"
|
||||||
|
"github.com/kratisto/mam-contract/internal/utils"
|
||||||
|
"regexp"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"gopkg.in/go-playground/validator.v9"
|
||||||
|
)
|
||||||
|
|
||||||
|
var regexpValidatorNamespacePrefix = regexp.MustCompile(`^\w+\.`)
|
||||||
|
|
||||||
|
func NewDataValidationAPIError(err error) model.APIError {
|
||||||
|
apiErr := model.ErrDataValidation
|
||||||
|
if err != nil {
|
||||||
|
if _, ok := err.(*validator.InvalidValidationError); ok {
|
||||||
|
utils.GetLogger().WithError(err).WithField("templateAPIErr", apiErr).Error("InvalidValidationError")
|
||||||
|
} else {
|
||||||
|
for _, e := range err.(validator.ValidationErrors) {
|
||||||
|
reason := e.Tag()
|
||||||
|
if _, ok := CustomValidators[e.Tag()]; ok {
|
||||||
|
reason = truncatingSprintf(CustomValidators[e.Tag()].Message, e.Param())
|
||||||
|
}
|
||||||
|
|
||||||
|
namespaceWithoutStructName := regexpValidatorNamespacePrefix.ReplaceAllString(e.Namespace(), "")
|
||||||
|
fe := model.FieldError{
|
||||||
|
Field: namespaceWithoutStructName,
|
||||||
|
Constraint: e.Tag(),
|
||||||
|
Description: reason,
|
||||||
|
}
|
||||||
|
apiErr.Details = append(apiErr.Details, fe)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return apiErr
|
||||||
|
}
|
||||||
|
|
||||||
|
// truncatingSprintf is used as fmt.Sprintf but allow to truncate the additional parameters given when there is more parameters than %v in str
|
||||||
|
func truncatingSprintf(str string, args ...interface{}) string {
|
||||||
|
n := strings.Count(str, "%v")
|
||||||
|
return fmt.Sprintf(str, args[:n]...)
|
||||||
|
}
|
||||||
34
internal/storage/validators/validators.go
Executable file
34
internal/storage/validators/validators.go
Executable file
@@ -0,0 +1,34 @@
|
|||||||
|
package validators
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"gopkg.in/go-playground/validator.v9"
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
CustomValidators = map[string]customValidator{
|
||||||
|
"enum": {
|
||||||
|
Message: "This field should be in: %v",
|
||||||
|
Validator: validateEnum,
|
||||||
|
},
|
||||||
|
"required": {
|
||||||
|
Message: "This field is required and cannot be empty",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
type customValidator struct {
|
||||||
|
Message string
|
||||||
|
Validator validator.FuncCtx
|
||||||
|
}
|
||||||
|
|
||||||
|
func validateEnum(ctx context.Context, fl validator.FieldLevel) bool {
|
||||||
|
for _, v := range strings.Split(fl.Param(), " ") {
|
||||||
|
if v == fl.Field().String() {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
8
internal/utils/headers.go
Executable file
8
internal/utils/headers.go
Executable file
@@ -0,0 +1,8 @@
|
|||||||
|
package utils
|
||||||
|
|
||||||
|
const (
|
||||||
|
HeaderNameContentType = "content-type"
|
||||||
|
HeaderNameCorrelationID = "correlationID"
|
||||||
|
|
||||||
|
HeaderValueApplicationJSONUTF8 = "application/json; charset=UTF-8"
|
||||||
|
)
|
||||||
29
internal/utils/injector.go
Normal file
29
internal/utils/injector.go
Normal file
@@ -0,0 +1,29 @@
|
|||||||
|
package utils
|
||||||
|
|
||||||
|
import "fmt"
|
||||||
|
|
||||||
|
type Injector struct {
|
||||||
|
content map[string]any
|
||||||
|
}
|
||||||
|
|
||||||
|
func (i *Injector) Get(key string) any {
|
||||||
|
val, ok := i.content[key]
|
||||||
|
if !ok {
|
||||||
|
panic(fmt.Sprintf("Can't get key %s from injector", key))
|
||||||
|
}
|
||||||
|
return val
|
||||||
|
}
|
||||||
|
func Get[T any](i *Injector, key string) T {
|
||||||
|
return i.Get(key).(T)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (i *Injector) Set(key string, content any) {
|
||||||
|
if i.content == nil {
|
||||||
|
i.content = map[string]any{}
|
||||||
|
}
|
||||||
|
_, ok := i.content[key]
|
||||||
|
if ok {
|
||||||
|
panic(fmt.Sprintf("Key %s already have content", key))
|
||||||
|
}
|
||||||
|
i.content[key] = content
|
||||||
|
}
|
||||||
74
internal/utils/logger.go
Executable file
74
internal/utils/logger.go
Executable file
@@ -0,0 +1,74 @@
|
|||||||
|
package utils
|
||||||
|
|
||||||
|
import (
|
||||||
|
"io"
|
||||||
|
"os"
|
||||||
|
|
||||||
|
"github.com/gin-gonic/gin"
|
||||||
|
"github.com/sirupsen/logrus"
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
LogFormatText = "text"
|
||||||
|
LogFormatJSON = "json"
|
||||||
|
|
||||||
|
ContextKeyLogger = "logger"
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
logLevel = logrus.DebugLevel
|
||||||
|
logFormat logrus.Formatter = &logrus.TextFormatter{}
|
||||||
|
logOut io.Writer
|
||||||
|
)
|
||||||
|
|
||||||
|
func InitLogger(ll, lf string) {
|
||||||
|
logLevel = parseLogrusLevel(ll)
|
||||||
|
logrus.SetLevel(logLevel)
|
||||||
|
|
||||||
|
logFormat = parseLogrusFormat(lf)
|
||||||
|
logrus.SetFormatter(logFormat)
|
||||||
|
|
||||||
|
logOut = os.Stdout
|
||||||
|
logrus.SetOutput(logOut)
|
||||||
|
}
|
||||||
|
|
||||||
|
func GetLoggerFromCtx(c *gin.Context) *logrus.Entry {
|
||||||
|
if logger, ok := c.Get(ContextKeyLogger); ok {
|
||||||
|
logEntry, assertionOk := logger.(*logrus.Entry)
|
||||||
|
if assertionOk {
|
||||||
|
return logEntry
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return logrus.NewEntry(GetLogger())
|
||||||
|
}
|
||||||
|
|
||||||
|
func GetLogger() *logrus.Logger {
|
||||||
|
logger := logrus.New()
|
||||||
|
logger.Formatter = logFormat
|
||||||
|
logger.Level = logLevel
|
||||||
|
logger.Out = logOut
|
||||||
|
return logger
|
||||||
|
}
|
||||||
|
|
||||||
|
func parseLogrusLevel(logLevelStr string) logrus.Level {
|
||||||
|
logLevel, err := logrus.ParseLevel(logLevelStr)
|
||||||
|
if err != nil {
|
||||||
|
logrus.WithError(err).Errorf("error while parsing log level. %v is set as default.", logLevel)
|
||||||
|
logLevel = logrus.DebugLevel
|
||||||
|
}
|
||||||
|
return logLevel
|
||||||
|
}
|
||||||
|
|
||||||
|
func parseLogrusFormat(logFormatStr string) logrus.Formatter {
|
||||||
|
var formatter logrus.Formatter
|
||||||
|
switch logFormatStr {
|
||||||
|
case LogFormatText:
|
||||||
|
formatter = &logrus.TextFormatter{ForceColors: true, FullTimestamp: true}
|
||||||
|
case LogFormatJSON:
|
||||||
|
formatter = &logrus.JSONFormatter{}
|
||||||
|
default:
|
||||||
|
logrus.Errorf("error while parsing log format. %v is set as default.", formatter)
|
||||||
|
formatter = &logrus.TextFormatter{ForceColors: true, FullTimestamp: true}
|
||||||
|
}
|
||||||
|
return formatter
|
||||||
|
}
|
||||||
45
internal/utils/randomizer/rand.go
Normal file
45
internal/utils/randomizer/rand.go
Normal file
@@ -0,0 +1,45 @@
|
|||||||
|
package randomizer
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"math/rand"
|
||||||
|
)
|
||||||
|
|
||||||
|
type Random interface {
|
||||||
|
Int() int
|
||||||
|
}
|
||||||
|
|
||||||
|
func init() {}
|
||||||
|
|
||||||
|
type rndGenerator func(n int) int
|
||||||
|
|
||||||
|
type Randomizer struct {
|
||||||
|
fn rndGenerator
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewRandomizer(fn rndGenerator) *Randomizer {
|
||||||
|
return &Randomizer{fn: fn}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *Randomizer) Int(n int) int {
|
||||||
|
return r.fn(n)
|
||||||
|
}
|
||||||
|
|
||||||
|
func Rand(rand int) int {
|
||||||
|
return randGen(rand)
|
||||||
|
}
|
||||||
|
func realRand(n int) int { return int(rand.Intn(n)) }
|
||||||
|
func fakeRand(n int) func(numb int) int {
|
||||||
|
return func(numb int) int {
|
||||||
|
if n >= numb {
|
||||||
|
panic(fmt.Sprintf("%d Should not be superior of %d", n, numb))
|
||||||
|
}
|
||||||
|
return n
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var randGen = NewRandomizer(realRand).Int
|
||||||
|
|
||||||
|
func FakeRandomizer(n int) {
|
||||||
|
randGen = NewRandomizer(fakeRand(n)).Int
|
||||||
|
}
|
||||||
31
internal/utils/responses.go
Executable file
31
internal/utils/responses.go
Executable file
@@ -0,0 +1,31 @@
|
|||||||
|
package utils
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
"github.com/kratisto/mam-contract/internal/storage/model"
|
||||||
|
"net/http"
|
||||||
|
)
|
||||||
|
|
||||||
|
func JSON(w http.ResponseWriter, status int, data interface{}) {
|
||||||
|
w.Header().Set(HeaderNameContentType, HeaderValueApplicationJSONUTF8)
|
||||||
|
w.WriteHeader(status)
|
||||||
|
if data != nil {
|
||||||
|
json.NewEncoder(w).Encode(data)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func JSONError(w http.ResponseWriter, e model.APIError) {
|
||||||
|
if e.Headers != nil {
|
||||||
|
for k, headers := range e.Headers {
|
||||||
|
for _, headerValue := range headers {
|
||||||
|
w.Header().Add(k, headerValue)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
JSON(w, e.HTTPCode, e)
|
||||||
|
}
|
||||||
|
|
||||||
|
func JSONErrorWithMessage(w http.ResponseWriter, e model.APIError, message string) {
|
||||||
|
e.Description = message
|
||||||
|
JSONError(w, e)
|
||||||
|
}
|
||||||
12
internal/utils/validator/setup.go
Normal file
12
internal/utils/validator/setup.go
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
package validator
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/kratisto/mam-contract/internal/utils"
|
||||||
|
)
|
||||||
|
|
||||||
|
const ValidatorInjectorKey = "VALIDATOR"
|
||||||
|
|
||||||
|
func Setup(injector *utils.Injector) {
|
||||||
|
|
||||||
|
injector.Set(ValidatorInjectorKey, newValidator())
|
||||||
|
}
|
||||||
28
internal/utils/validator/validator.go
Normal file
28
internal/utils/validator/validator.go
Normal file
@@ -0,0 +1,28 @@
|
|||||||
|
package validator
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/kratisto/mam-contract/internal/storage/validators"
|
||||||
|
"gopkg.in/go-playground/validator.v9"
|
||||||
|
"reflect"
|
||||||
|
"strings"
|
||||||
|
)
|
||||||
|
|
||||||
|
func newValidator() *validator.Validate {
|
||||||
|
va := validator.New()
|
||||||
|
|
||||||
|
va.RegisterTagNameFunc(func(fld reflect.StructField) string {
|
||||||
|
name := strings.SplitN(fld.Tag.Get("json"), ",", 2)
|
||||||
|
if len(name) < 1 {
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
return name[0]
|
||||||
|
})
|
||||||
|
|
||||||
|
for k, v := range validators.CustomValidators {
|
||||||
|
if v.Validator != nil {
|
||||||
|
va.RegisterValidationCtx(k, v.Validator)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return va
|
||||||
|
}
|
||||||
12
liquibase/changelogs/changelog-master.xml
Normal file
12
liquibase/changelogs/changelog-master.xml
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
|
||||||
|
<databaseChangeLog xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||||
|
xmlns="http://www.liquibase.org/xml/ns/dbchangelog"
|
||||||
|
xsi:schemaLocation="http://www.liquibase.org/xml/ns/dbchangelog http://www.liquibase.org/xml/ns/dbchangelog/dbchangelog-3.5.xsd">
|
||||||
|
|
||||||
|
<!-- Define default schema name used by changesets-->
|
||||||
|
<property name="schemaName" value="mam-contract"/>
|
||||||
|
|
||||||
|
<include file="prepare-database.sql" relativeToChangelogFile="true"/>
|
||||||
|
<include file="changesets/create-user-table.xml" relativeToChangelogFile="true"/>
|
||||||
|
</databaseChangeLog>
|
||||||
20
liquibase/changelogs/changesets/create-user-table.xml
Normal file
20
liquibase/changelogs/changesets/create-user-table.xml
Normal file
@@ -0,0 +1,20 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
|
||||||
|
<databaseChangeLog xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||||
|
xmlns="http://www.liquibase.org/xml/ns/dbchangelog"
|
||||||
|
xsi:schemaLocation="http://www.liquibase.org/xml/ns/dbchangelog http://www.liquibase.org/xml/ns/dbchangelog/dbchangelog-3.5.xsd"
|
||||||
|
logicalFilePath="/project/changesets/init-tables.xml">
|
||||||
|
<changeSet id="create-user-table" author="kratisto">
|
||||||
|
<createTable tableName="user" schemaName="${schemaName}">
|
||||||
|
<column name="id" type="uuid" defaultValueComputed="gen_random_uuid()">
|
||||||
|
<constraints primaryKey="true" nullable="false"/>
|
||||||
|
</column>
|
||||||
|
<column name="email" type="varchar(255)">
|
||||||
|
<constraints unique="true"/>
|
||||||
|
</column>
|
||||||
|
<column name="google_user_id" type="varchar(255)">
|
||||||
|
<constraints unique="true"/>
|
||||||
|
</column>
|
||||||
|
</createTable>
|
||||||
|
</changeSet>
|
||||||
|
</databaseChangeLog>
|
||||||
7
liquibase/changelogs/liquibase.properties
Normal file
7
liquibase/changelogs/liquibase.properties
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
classpath: /workspace/postgresql-42.2.5.jar
|
||||||
|
driver: org.postgresql.Driver
|
||||||
|
url: jdbc:postgresql://database:5432/postgres
|
||||||
|
username: postgres
|
||||||
|
password: password
|
||||||
|
changeLogFile: changelog-master.xml
|
||||||
|
logLevel: info
|
||||||
2
liquibase/changelogs/prepare-database.sql
Executable file
2
liquibase/changelogs/prepare-database.sql
Executable file
@@ -0,0 +1,2 @@
|
|||||||
|
CREATE SCHEMA IF NOT EXISTS workScheduler;
|
||||||
|
CREATE EXTENSION IF NOT EXISTS pgcrypto;
|
||||||
Reference in New Issue
Block a user