Merge branch '7-add-advanced-matching-options' into 'master'
Resolve "Add advanced matching options to HTTP handler" Closes #7 See merge request inetmock/inetmock!11
This commit is contained in:
commit
e9f79cd59a
86 changed files with 1436 additions and 967 deletions
23
.editorconfig
Normal file
23
.editorconfig
Normal file
|
@ -0,0 +1,23 @@
|
||||||
|
root = true
|
||||||
|
|
||||||
|
[*]
|
||||||
|
charset = utf-8
|
||||||
|
end_of_line = lf
|
||||||
|
indent_size = 4
|
||||||
|
indent_style = space
|
||||||
|
insert_final_newline = false
|
||||||
|
max_line_length = 120
|
||||||
|
tab_width = 4
|
||||||
|
|
||||||
|
[{*.bash, *.sh, *.zsh}]
|
||||||
|
indent_size = 2
|
||||||
|
tab_width = 2
|
||||||
|
|
||||||
|
[{*.go, *.go2}]
|
||||||
|
indent_style = tab
|
||||||
|
|
||||||
|
[{*.har, *.jsb2, *.jsb3, *.json, .babelrc, .eslintrc, .stylelintrc, bowerrc, jest.config}]
|
||||||
|
indent_size = 2
|
||||||
|
|
||||||
|
[{*.yaml, *.yml}]
|
||||||
|
indent_size = 2
|
2
.github/workflows/docker-image.yml
vendored
2
.github/workflows/docker-image.yml
vendored
|
@ -21,7 +21,7 @@ jobs:
|
||||||
run: echo ${{ secrets.GITHUB_TOKEN }} | docker login docker.pkg.github.com -u baez90 --password-stdin
|
run: echo ${{ secrets.GITHUB_TOKEN }} | docker login docker.pkg.github.com -u baez90 --password-stdin
|
||||||
|
|
||||||
- name: Build the Docker image
|
- name: Build the Docker image
|
||||||
run: docker build . --file Dockerfile --tag $IMAGE_NAME
|
run: docker build . --file inetmock.dockerfile --tag $IMAGE_NAME
|
||||||
|
|
||||||
- name: Push image to GitHub packages
|
- name: Push image to GitHub packages
|
||||||
run: |
|
run: |
|
||||||
|
|
9
.github/workflows/go-build.yml
vendored
9
.github/workflows/go-build.yml
vendored
|
@ -9,10 +9,10 @@ jobs:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
|
|
||||||
- name: Set up Go 1.14
|
- name: Set up Go 1.15
|
||||||
uses: actions/setup-go@v1
|
uses: actions/setup-go@v2
|
||||||
with:
|
with:
|
||||||
go-version: 1.14.x
|
go-version: '^1.15'
|
||||||
id: go
|
id: go
|
||||||
|
|
||||||
- name: Install Protoc
|
- name: Install Protoc
|
||||||
|
@ -41,10 +41,9 @@ jobs:
|
||||||
run: make
|
run: make
|
||||||
|
|
||||||
- name: Run GoReleaser
|
- name: Run GoReleaser
|
||||||
uses: goreleaser/goreleaser-action@v1
|
uses: goreleaser/goreleaser-action@v2
|
||||||
with:
|
with:
|
||||||
version: latest
|
version: latest
|
||||||
args: release --rm-dist
|
args: release --rm-dist
|
||||||
key: ${{ secrets.YOUR_PRIVATE_KEY }}
|
|
||||||
env:
|
env:
|
||||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
2
.gitignore
vendored
2
.gitignore
vendored
|
@ -11,6 +11,7 @@
|
||||||
/imctl
|
/imctl
|
||||||
./main
|
./main
|
||||||
**/*.mock.go
|
**/*.mock.go
|
||||||
|
**/*_enum.go
|
||||||
**/*.pb.go
|
**/*.pb.go
|
||||||
|
|
||||||
###############
|
###############
|
||||||
|
@ -21,3 +22,4 @@
|
||||||
.vscode/
|
.vscode/
|
||||||
dist/
|
dist/
|
||||||
out/
|
out/
|
||||||
|
.task/
|
41
.gitlab-ci.yml
Normal file
41
.gitlab-ci.yml
Normal file
|
@ -0,0 +1,41 @@
|
||||||
|
image: registry.gitlab.com/inetmock/ci-image
|
||||||
|
|
||||||
|
stages:
|
||||||
|
- test
|
||||||
|
- build
|
||||||
|
- release
|
||||||
|
|
||||||
|
test:
|
||||||
|
stage: test
|
||||||
|
script:
|
||||||
|
- task cli-cover-report
|
||||||
|
|
||||||
|
lint:
|
||||||
|
stage: test
|
||||||
|
script:
|
||||||
|
- golangci-lint run
|
||||||
|
allow_failure: true
|
||||||
|
|
||||||
|
snapshot-release:
|
||||||
|
stage: build
|
||||||
|
services:
|
||||||
|
- docker:dind
|
||||||
|
before_script:
|
||||||
|
- docker login -u "$CI_REGISTRY_USER" -p "$CI_REGISTRY_PASSWORD" $CI_REGISTRY
|
||||||
|
script:
|
||||||
|
- task snapshot-release
|
||||||
|
except:
|
||||||
|
- tags
|
||||||
|
|
||||||
|
release:
|
||||||
|
stage: release
|
||||||
|
services:
|
||||||
|
- docker:dind
|
||||||
|
only:
|
||||||
|
- tags
|
||||||
|
variables:
|
||||||
|
GITLAB_TOKEN: $CI_JOB_TOKEN
|
||||||
|
GIT_DEPTH: 0
|
||||||
|
script:
|
||||||
|
- docker login -u $CI_REGISTRY_USER -p $CI_REGISTRY_PASSWORD $CI_REGISTRY
|
||||||
|
- goreleaser release --rm-dist
|
136
.golangci.yml
Normal file
136
.golangci.yml
Normal file
|
@ -0,0 +1,136 @@
|
||||||
|
linters-settings:
|
||||||
|
depguard:
|
||||||
|
list-type: blacklist
|
||||||
|
packages:
|
||||||
|
# logging is allowed only by logutils.Log, logrus
|
||||||
|
# is allowed to use only in logutils package
|
||||||
|
- github.com/sirupsen/logrus
|
||||||
|
packages-with-error-message:
|
||||||
|
- github.com/sirupsen/logrus: "logging is allowed only by logutils.Log"
|
||||||
|
dupl:
|
||||||
|
threshold: 100
|
||||||
|
funlen:
|
||||||
|
lines: 100
|
||||||
|
statements: 50
|
||||||
|
gci:
|
||||||
|
local-prefixes: gitlab.com/inetmock/inetmock
|
||||||
|
goconst:
|
||||||
|
min-len: 2
|
||||||
|
min-occurrences: 2
|
||||||
|
gocritic:
|
||||||
|
enabled-tags:
|
||||||
|
- diagnostic
|
||||||
|
- experimental
|
||||||
|
- opinionated
|
||||||
|
- performance
|
||||||
|
- style
|
||||||
|
disabled-checks:
|
||||||
|
- dupImport # https://github.com/go-critic/go-critic/issues/845
|
||||||
|
- ifElseChain
|
||||||
|
- octalLiteral
|
||||||
|
- whyNoLint
|
||||||
|
- wrapperFunc
|
||||||
|
gocyclo:
|
||||||
|
min-complexity: 15
|
||||||
|
goimports:
|
||||||
|
local-prefixes: gitlab.com/inetmock/inetmock
|
||||||
|
golint:
|
||||||
|
min-confidence: 0
|
||||||
|
gomnd:
|
||||||
|
settings:
|
||||||
|
mnd:
|
||||||
|
# don't include the "operation" and "assign"
|
||||||
|
checks: argument,case,condition,return
|
||||||
|
govet:
|
||||||
|
check-shadowing: true
|
||||||
|
lll:
|
||||||
|
line-length: 140
|
||||||
|
maligned:
|
||||||
|
suggest-new: true
|
||||||
|
misspell:
|
||||||
|
locale: US
|
||||||
|
nolintlint:
|
||||||
|
allow-leading-space: true # don't require machine-readable nolint directives (i.e. with no leading space)
|
||||||
|
allow-unused: false # report any unused nolint directives
|
||||||
|
require-explanation: false # don't require an explanation for nolint directives
|
||||||
|
require-specific: false # don't require nolint directives to be specific about which linter is being skipped
|
||||||
|
|
||||||
|
linters:
|
||||||
|
# please, do not use `enable-all`: it's deprecated and will be removed soon.
|
||||||
|
# inverted configuration with `enable-all` and `disable` is not scalable during updates of golangci-lint
|
||||||
|
disable-all: true
|
||||||
|
enable:
|
||||||
|
- bodyclose
|
||||||
|
- deadcode
|
||||||
|
- depguard
|
||||||
|
- dogsled
|
||||||
|
- dupl
|
||||||
|
- errcheck
|
||||||
|
- exhaustive
|
||||||
|
- funlen
|
||||||
|
- gochecknoinits
|
||||||
|
- goconst
|
||||||
|
- gocritic
|
||||||
|
- gocyclo
|
||||||
|
- gofmt
|
||||||
|
- goimports
|
||||||
|
- golint
|
||||||
|
- gomnd
|
||||||
|
- goprintffuncname
|
||||||
|
- gosec
|
||||||
|
- gosimple
|
||||||
|
- govet
|
||||||
|
- ineffassign
|
||||||
|
- interfacer
|
||||||
|
- lll
|
||||||
|
- misspell
|
||||||
|
- nakedret
|
||||||
|
- noctx
|
||||||
|
- nolintlint
|
||||||
|
- rowserrcheck
|
||||||
|
- scopelint
|
||||||
|
- staticcheck
|
||||||
|
- structcheck
|
||||||
|
- stylecheck
|
||||||
|
- typecheck
|
||||||
|
- unconvert
|
||||||
|
- unparam
|
||||||
|
- unused
|
||||||
|
- varcheck
|
||||||
|
- whitespace
|
||||||
|
|
||||||
|
# don't enable:
|
||||||
|
# - asciicheck
|
||||||
|
# - gochecknoglobals
|
||||||
|
# - gocognit
|
||||||
|
# - godot
|
||||||
|
# - godox
|
||||||
|
# - goerr113
|
||||||
|
# - maligned
|
||||||
|
# - nestif
|
||||||
|
# - prealloc
|
||||||
|
# - testpackage
|
||||||
|
# - wsl
|
||||||
|
|
||||||
|
issues:
|
||||||
|
# Excluding configuration per-path, per-linter, per-text and per-source
|
||||||
|
exclude-rules:
|
||||||
|
- path: _test\.go
|
||||||
|
linters:
|
||||||
|
- gomnd
|
||||||
|
|
||||||
|
# https://github.com/go-critic/go-critic/issues/926
|
||||||
|
- linters:
|
||||||
|
- gocritic
|
||||||
|
text: "unnecessaryDefer:"
|
||||||
|
|
||||||
|
run:
|
||||||
|
skip-dirs:
|
||||||
|
- internal/mock
|
||||||
|
|
||||||
|
# golangci.com configuration
|
||||||
|
# https://github.com/golangci/golangci/wiki/Configuration
|
||||||
|
service:
|
||||||
|
golangci-lint-version: 1.23.x # use the fixed version to not introduce new linters unexpectedly
|
||||||
|
prepare:
|
||||||
|
- echo "here I can run custom commands, but no preparation needed for this repo"
|
|
@ -3,7 +3,7 @@
|
||||||
before:
|
before:
|
||||||
hooks:
|
hooks:
|
||||||
# You may remove this if you don't use go modules.
|
# You may remove this if you don't use go modules.
|
||||||
- make generate
|
- task generate
|
||||||
builds:
|
builds:
|
||||||
- id: "inetmock"
|
- id: "inetmock"
|
||||||
binary: inetmock
|
binary: inetmock
|
||||||
|
@ -58,3 +58,27 @@ changelog:
|
||||||
exclude:
|
exclude:
|
||||||
- '^docs:'
|
- '^docs:'
|
||||||
- '^test:'
|
- '^test:'
|
||||||
|
|
||||||
|
release:
|
||||||
|
gitlab:
|
||||||
|
owner: inetmock
|
||||||
|
name: inetmock
|
||||||
|
|
||||||
|
dockers:
|
||||||
|
- binaries:
|
||||||
|
- inetmock
|
||||||
|
- imctl
|
||||||
|
image_templates:
|
||||||
|
- registry.gitlab.com/inetmock/inetmock:latest
|
||||||
|
- registry.gitlab.com/inetmock/inetmock:{{ .Tag }}
|
||||||
|
- registry.gitlab.com/inetmock/inetmock:{{ .Major }}
|
||||||
|
|
||||||
|
dockerfile: build/docker/inetmock.dockerfile
|
||||||
|
build_flag_templates:
|
||||||
|
- "--label=org.opencontainers.image.created={{.Date}}"
|
||||||
|
- "--label=org.opencontainers.image.title={{.ProjectName}}"
|
||||||
|
- "--label=org.opencontainers.image.revision={{.FullCommit}}"
|
||||||
|
- "--label=org.opencontainers.image.version={{.Version}}"
|
||||||
|
extra_files:
|
||||||
|
- config-container.yaml
|
||||||
|
- assets/fakeFiles/
|
||||||
|
|
81
Makefile
81
Makefile
|
@ -1,81 +0,0 @@
|
||||||
VERSION = $(shell git describe --dirty --tags --always)
|
|
||||||
DIR = $(dir $(realpath $(firstword $(MAKEFILE_LIST))))
|
|
||||||
SERVER_BUILD_PATH = github.com/baez90/inetmock/cmd/inetmock
|
|
||||||
CLI_BUILD_PATH = github.com/baez90/inetmock/cmd/imctl
|
|
||||||
PKGS = $(shell go list ./...)
|
|
||||||
TEST_PKGS = $(shell go list ./...)
|
|
||||||
PROTO_FILES = $(shell find $(DIR)api/ -type f -name "*.proto")
|
|
||||||
GOARGS = GOOS=linux GOARCH=amd64
|
|
||||||
GO_BUILD_ARGS = -ldflags='-w -s'
|
|
||||||
GO_CONTAINER_BUILD_ARGS = -ldflags='-w -s' -a -installsuffix cgo
|
|
||||||
GO_DEBUG_BUILD_ARGS = -gcflags "all=-N -l"
|
|
||||||
SERVER_BINARY_NAME = inetmock
|
|
||||||
CLI_BINARY_NAME = imctl
|
|
||||||
DEBUG_PORT = 2345
|
|
||||||
DEBUG_ARGS?= serve --development-logs=true
|
|
||||||
CONTAINER_BUILDER ?= podman
|
|
||||||
DOCKER_IMAGE ?= inetmock
|
|
||||||
|
|
||||||
.PHONY: clean all format deps update-deps compile compile-server compile-cli debug generate protoc snapshot-release test cli-cover-report html-cover-report $(GO_GEN_FILES)
|
|
||||||
all: clean format generate compile test
|
|
||||||
|
|
||||||
clean:
|
|
||||||
@find $(DIR) -type f \( -name "*.out" -or -name "*.so" \) -exec rm -f {} \;
|
|
||||||
@rm -rf $(DIR)*.so
|
|
||||||
@find $(DIR) -type f -name "*.pb.go" -exec rm -f {} \;
|
|
||||||
@find $(DIR) -type f -name "*.mock.go" -exec rm -f {} \;
|
|
||||||
@rm -f $(DIR)$(SERVER_BINARY_NAME) $(DIR)$(CLI_BINARY_NAME) $(DIR)main
|
|
||||||
|
|
||||||
format:
|
|
||||||
@go fmt $(PKGS)
|
|
||||||
|
|
||||||
deps:
|
|
||||||
@go build -v $(SERVER_BUILD_PATH)
|
|
||||||
|
|
||||||
update-deps:
|
|
||||||
@go mod tidy
|
|
||||||
@go get -u $(DIR)/...
|
|
||||||
|
|
||||||
compile-server: deps
|
|
||||||
ifdef DEBUG
|
|
||||||
@echo 'Compiling for debugging...'
|
|
||||||
@$(GOARGS) go build $(GO_DEBUG_BUILD_ARGS) -o $(DIR)$(SERVER_BINARY_NAME) $(SERVER_BUILD_PATH)
|
|
||||||
else ifdef CONTAINER
|
|
||||||
@echo 'Compiling for container usage...'
|
|
||||||
@$(GOARGS) go build $(GO_CONTAINER_BUILD_ARGS) -o $(DIR)$(SERVER_BINARY_NAME) $(SERVER_BUILD_PATH)
|
|
||||||
else
|
|
||||||
@echo 'Compiling for normal Linux env...'
|
|
||||||
@$(GOARGS) go build $(GO_BUILD_ARGS) -o $(DIR)$(SERVER_BINARY_NAME) $(SERVER_BUILD_PATH)
|
|
||||||
endif
|
|
||||||
|
|
||||||
compile-cli: deps
|
|
||||||
@$(GOARGS) go build $(GO_BUILD_ARGS) -o $(CLI_BINARY_NAME) $(CLI_BUILD_PATH)
|
|
||||||
|
|
||||||
compile: compile-server compile-cli
|
|
||||||
|
|
||||||
debug:
|
|
||||||
dlv debug $(SERVER_BUILD_PATH) \
|
|
||||||
--headless \
|
|
||||||
--listen=:2345 \
|
|
||||||
--api-version=2 \
|
|
||||||
-- $(DEBUG_ARGS)
|
|
||||||
|
|
||||||
generate:
|
|
||||||
@go generate ./...
|
|
||||||
@protoc --proto_path $(DIR)api/ --go_out=plugins=grpc:internal/rpc --go_opt=paths=source_relative $(shell find $(DIR)api/ -type f -name "*.proto")
|
|
||||||
|
|
||||||
snapshot-release:
|
|
||||||
@goreleaser release --snapshot --skip-publish --rm-dist
|
|
||||||
|
|
||||||
container:
|
|
||||||
@$(CONTAINER_BUILDER) build -t $(DOCKER_IMAGE):latest -f $(DIR)Dockerfile $(DIR)
|
|
||||||
|
|
||||||
test:
|
|
||||||
@go test -coverprofile=./cov-raw.out -v $(TEST_PKGS)
|
|
||||||
@cat ./cov-raw.out | grep -v "generated" > ./cov.out
|
|
||||||
|
|
||||||
cli-cover-report: test
|
|
||||||
@go tool cover -func=cov.out
|
|
||||||
|
|
||||||
html-cover-report: test
|
|
||||||
@go tool cover -html=cov.out -o .coverage.html
|
|
26
README.md
26
README.md
|
@ -1,7 +1,7 @@
|
||||||
# INetMock
|
# INetMock
|
||||||
|
|
||||||
![Go](https://github.com/baez90/inetmock/workflows/Go/badge.svg)
|
![Go](https://gitlab.com/inetmock/inetmock/workflows/Go/badge.svg)
|
||||||
[![Go Report Card](https://goreportcard.com/badge/github.com/baez90/inetmock)](https://goreportcard.com/report/github.com/baez90/inetmock)
|
[![Go Report Card](https://goreportcard.com/badge/gitlab.com/inetmock/inetmock)](https://goreportcard.com/report/gitlab.com/inetmock/inetmock)
|
||||||
[![Quality Gate Status](https://sonarcloud.io/api/project_badges/measure?project=baez90_inetmock&metric=alert_status)](https://sonarcloud.io/dashboard?id=baez90_inetmock)
|
[![Quality Gate Status](https://sonarcloud.io/api/project_badges/measure?project=baez90_inetmock&metric=alert_status)](https://sonarcloud.io/dashboard?id=baez90_inetmock)
|
||||||
[![Lines of Code](https://sonarcloud.io/api/project_badges/measure?project=baez90_inetmock&metric=ncloc)](https://sonarcloud.io/dashboard?id=baez90_inetmock)
|
[![Lines of Code](https://sonarcloud.io/api/project_badges/measure?project=baez90_inetmock&metric=ncloc)](https://sonarcloud.io/dashboard?id=baez90_inetmock)
|
||||||
[![Maintainability Rating](https://sonarcloud.io/api/project_badges/measure?project=baez90_inetmock&metric=sqale_rating)](https://sonarcloud.io/dashboard?id=baez90_inetmock)
|
[![Maintainability Rating](https://sonarcloud.io/api/project_badges/measure?project=baez90_inetmock&metric=sqale_rating)](https://sonarcloud.io/dashboard?id=baez90_inetmock)
|
||||||
|
@ -12,22 +12,26 @@
|
||||||
INetMock is kind of a fork of [INetSim](https://www.inetsim.org/).
|
INetMock is kind of a fork of [INetSim](https://www.inetsim.org/).
|
||||||
"Kind of" in terms that both applications overlap in their functionality to serve as "fake internet" routers.
|
"Kind of" in terms that both applications overlap in their functionality to serve as "fake internet" routers.
|
||||||
|
|
||||||
INetMock right now does **not** implement so many protocols like INetSim.
|
INetMock right now does **not** implement so many protocols like INetSim. In fact it is only able to respond to HTTP,
|
||||||
In fact it is only able to respond to HTTP, HTTPS, DNS, DNS-over-TLS (DoT) requests and to act as an HTTP proxy.
|
HTTPS, DNS, DNS-over-TLS (DoT) requests and to act as an HTTP proxy. The most notable advantage of INetMOck over INetSim
|
||||||
The most notable advantage of INetMOck over INetSim is that it issues proper TLS certificates on the fly signed by a CA certificate that can be deployed to client systems to achieve "proper" TLS encryption - as long as the client does not use certificate pinning or something similar.
|
is that it issues proper TLS certificates on the fly signed by a CA certificate that can be deployed to client systems
|
||||||
|
to achieve "proper" TLS encryption - as long as the client does not use certificate pinning or something similar.
|
||||||
|
|
||||||
A second advantage is that INetMock is a complete rewrite in Go, based on a plugin system that allows dynamic configuration while it has a way smaller memory footprint and far better startup and shutdown times.
|
A second advantage is that INetMock is a complete rewrite in Go, based on a plugin system that allows dynamic
|
||||||
It also does not enforce `root` privileges as it is also possible to run the application with the required capabilities to open ports e.g. with SystemD (a sample unit file can be found in the `deploy/` directory).
|
configuration while it has a way smaller memory footprint and far better startup and shutdown times. It also does not
|
||||||
|
enforce `root` privileges as it is also possible to run the application with the required capabilities to open ports
|
||||||
|
e.g. with SystemD (a sample unit file can be found in the `deploy/` directory).
|
||||||
|
|
||||||
_This project is still heavy work-in-progress. There may be breaking changes at any time. There's no guarantee for anything except no kittens will be harmed!_
|
_This project is still heavy work-in-progress. There may be breaking changes at any time. There's no guarantee for
|
||||||
|
anything except no kittens will be harmed!_
|
||||||
|
|
||||||
## Docs
|
## Docs
|
||||||
|
|
||||||
Docs are available either in the [`docs/`](./docs/) directory or as rendered markdown book at the [GitHub pages](https://baez90.github.io/inetmock/).
|
Docs are available either in the [`docs/`](./docs/) directory or as rendered markdown book at
|
||||||
|
the [GitHub pages](https://baez90.github.io/inetmock/).
|
||||||
|
|
||||||
## Contribution/feature requests
|
## Contribution/feature requests
|
||||||
|
|
||||||
Please create an issue for any proposal, feature requests, found bug,...
|
Please create an issue for any proposal, feature requests, found bug,... I'm glad for every kind of feedback!
|
||||||
I'm glad for every kind of feedback!
|
|
||||||
|
|
||||||
Right now I've no special workflow for pull requests but I will look into every proposed change.
|
Right now I've no special workflow for pull requests but I will look into every proposed change.
|
98
Taskfile.yml
Normal file
98
Taskfile.yml
Normal file
|
@ -0,0 +1,98 @@
|
||||||
|
version: '3'
|
||||||
|
|
||||||
|
vars:
|
||||||
|
OUT_DIR: ./out
|
||||||
|
INETMOCK_PKG: gitlab.com/inetmock/inetmock/cmd/inetmock
|
||||||
|
IMCTL_PKG: gitlab.com/inetmock/inetmock/cmd/imctl
|
||||||
|
PROTO_FILES:
|
||||||
|
sh: find ./api/ -type f -name "*.proto" -printf "%f "
|
||||||
|
|
||||||
|
env:
|
||||||
|
GOOS: linux
|
||||||
|
GOARCH: amd64
|
||||||
|
CGO_ENABLED: 0
|
||||||
|
|
||||||
|
tasks:
|
||||||
|
clean:
|
||||||
|
cmds:
|
||||||
|
- find . -type f \( -name "*.pb.go" -or -name "*.mock.go" \) -exec rm -f {} \;
|
||||||
|
- rm -rf ./main {{ .OUT_DIR }}
|
||||||
|
|
||||||
|
format:
|
||||||
|
cmds:
|
||||||
|
- go fmt ./...
|
||||||
|
|
||||||
|
protoc:
|
||||||
|
sources:
|
||||||
|
- "**/*.proto"
|
||||||
|
cmds:
|
||||||
|
- protoc --proto_path ./api/ --go_out=./internal/rpc --go_opt=paths=source_relative --go-grpc_out=./internal/rpc --go-grpc_opt=paths=source_relative {{ .PROTO_FILES }}
|
||||||
|
|
||||||
|
go-generate:
|
||||||
|
sources:
|
||||||
|
- "**/*.go"
|
||||||
|
cmds:
|
||||||
|
- go generate -x ./...
|
||||||
|
|
||||||
|
generate:
|
||||||
|
deps:
|
||||||
|
- go-generate
|
||||||
|
- protoc
|
||||||
|
|
||||||
|
test:
|
||||||
|
sources:
|
||||||
|
- "**/*.go"
|
||||||
|
deps:
|
||||||
|
- generate
|
||||||
|
cmds:
|
||||||
|
- mkdir -p {{ .OUT_DIR }}
|
||||||
|
- go test -coverprofile={{ .OUT_DIR }}/cov-raw.out -v ./...
|
||||||
|
- grep -v "generated" {{ .OUT_DIR }}/cov-raw.out > {{ .OUT_DIR }}/cov.out
|
||||||
|
- rm -f {{ .OUT_DIR }}/cov-raw.out
|
||||||
|
|
||||||
|
cli-cover-report:
|
||||||
|
deps:
|
||||||
|
- test
|
||||||
|
cmds:
|
||||||
|
- go tool cover -func={{ .OUT_DIR }}/cov.out
|
||||||
|
|
||||||
|
html-cover-report:
|
||||||
|
deps:
|
||||||
|
- test
|
||||||
|
cmds:
|
||||||
|
- go tool cover -html={{ .OUT_DIR }}/cov.out -o {{ .OUT_DIR }}/coverage.html
|
||||||
|
|
||||||
|
build-inetmock:
|
||||||
|
deps:
|
||||||
|
- test
|
||||||
|
cmds:
|
||||||
|
- mkdir -p {{ .OUT_DIR }}
|
||||||
|
- go build -ldflags='-w -s' -o {{ .OUT_DIR }}/inetmock {{ .INETMOCK_PKG }}
|
||||||
|
|
||||||
|
debug-inetmock:
|
||||||
|
cmds:
|
||||||
|
- dlv --listen=:2345 --headless=true --api-version=2 --accept-multiclient --output {{ .OUT_DIR }}/__debug_bin debug {{ .INETMOCK_PKG }} -- serve
|
||||||
|
|
||||||
|
build-imctl:
|
||||||
|
deps:
|
||||||
|
- test
|
||||||
|
cmds:
|
||||||
|
- mkdir -p {{ .OUT_DIR }}
|
||||||
|
- go build -ldflags='-w -s' -o {{ .OUT_DIR }}/imctl {{ .IMCTL_PKG }}
|
||||||
|
|
||||||
|
build-all:
|
||||||
|
deps:
|
||||||
|
- build-inetmock
|
||||||
|
- build-imctl
|
||||||
|
|
||||||
|
snapshot-release:
|
||||||
|
deps:
|
||||||
|
- test
|
||||||
|
cmds:
|
||||||
|
- goreleaser release --snapshot --skip-publish --rm-dist
|
||||||
|
|
||||||
|
release:
|
||||||
|
deps:
|
||||||
|
- test
|
||||||
|
cmds:
|
||||||
|
- goreleaser release
|
|
@ -1,6 +1,6 @@
|
||||||
syntax = "proto3";
|
syntax = "proto3";
|
||||||
|
|
||||||
option go_package = "github.com/baez90/inetmock/internal/rpc";
|
option go_package = "gitlab.com/inetmock/inetmock/internal/rpc";
|
||||||
option java_multiple_files = true;
|
option java_multiple_files = true;
|
||||||
option java_package = "com.github.baez90.inetmock.rpc";
|
option java_package = "com.github.baez90.inetmock.rpc";
|
||||||
option java_outer_classname = "EndpointsProto";
|
option java_outer_classname = "EndpointsProto";
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
syntax = "proto3";
|
syntax = "proto3";
|
||||||
|
|
||||||
option go_package = "github.com/baez90/inetmock/internal/rpc";
|
option go_package = "gitlab.com/inetmock/inetmock/internal/rpc";
|
||||||
option java_multiple_files = true;
|
option java_multiple_files = true;
|
||||||
option java_package = "com.github.baez90.inetmock.rpc";
|
option java_package = "com.github.baez90.inetmock.rpc";
|
||||||
option java_outer_classname = "HandlersProto";
|
option java_outer_classname = "HandlersProto";
|
||||||
|
@ -8,7 +8,8 @@ option java_outer_classname = "HandlersProto";
|
||||||
package inetmock;
|
package inetmock;
|
||||||
|
|
||||||
service Handlers {
|
service Handlers {
|
||||||
rpc GetHandlers(GetHandlersRequest) returns (GetHandlersResponse) {}
|
rpc GetHandlers (GetHandlersRequest) returns (GetHandlersResponse) {
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
message GetHandlersRequest {
|
message GetHandlersRequest {
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
syntax = "proto3";
|
syntax = "proto3";
|
||||||
|
|
||||||
option go_package = "github.com/baez90/inetmock/internal/rpc";
|
option go_package = "gitlab.com/inetmock/inetmock/internal/rpc";
|
||||||
option java_multiple_files = true;
|
option java_multiple_files = true;
|
||||||
option java_package = "com.github.baez90.inetmock.rpc";
|
option java_package = "com.github.baez90.inetmock.rpc";
|
||||||
option java_outer_classname = "HealthProto";
|
option java_outer_classname = "HealthProto";
|
||||||
|
@ -8,7 +8,8 @@ option java_outer_classname = "HealthProto";
|
||||||
package inetmock;
|
package inetmock;
|
||||||
|
|
||||||
service Health {
|
service Health {
|
||||||
rpc GetHealth(HealthRequest) returns (HealthResponse) {}
|
rpc GetHealth (HealthRequest) returns (HealthResponse) {
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
enum HealthState {
|
enum HealthState {
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
FROM golang:1.15-alpine as build
|
# Runtime layer
|
||||||
|
FROM alpine:3.12
|
||||||
|
|
||||||
# Create appuser and group.
|
# Create appuser and group.
|
||||||
ARG USER=inetmock
|
ARG USER=inetmock
|
||||||
|
@ -6,13 +7,7 @@ ARG GROUP=inetmock
|
||||||
ARG USER_ID=10001
|
ARG USER_ID=10001
|
||||||
ARG GROUP_ID=10001
|
ARG GROUP_ID=10001
|
||||||
|
|
||||||
ENV CGO_ENABLED=0
|
RUN addgroup -S -g "${GROUP_ID}" "${GROUP}" && \
|
||||||
|
|
||||||
# Prepare build stage - can be cached
|
|
||||||
WORKDIR /work
|
|
||||||
RUN apk add -U --no-cache \
|
|
||||||
make protoc gcc musl-dev && \
|
|
||||||
addgroup -S -g "${GROUP_ID}" "${GROUP}" && \
|
|
||||||
adduser \
|
adduser \
|
||||||
--disabled-password \
|
--disabled-password \
|
||||||
--gecos "" \
|
--gecos "" \
|
||||||
|
@ -23,31 +18,8 @@ RUN apk add -U --no-cache \
|
||||||
--uid "${USER_ID}" \
|
--uid "${USER_ID}" \
|
||||||
"${USER}"
|
"${USER}"
|
||||||
|
|
||||||
# Fetch dependencies
|
COPY --chown=$USER:$GROUP inetmock imctl /usr/lib/inetmock/bin/
|
||||||
COPY Makefile go.mod go.sum ./
|
COPY --chown=$USER:$GROUP assets/fakeFiles /var/lib/inetmock/fakeFiles/
|
||||||
RUN go mod download && \
|
|
||||||
go get -u github.com/golang/mock/mockgen@latest && \
|
|
||||||
go get -u github.com/abice/go-enum && \
|
|
||||||
go install github.com/golang/protobuf/protoc-gen-go
|
|
||||||
|
|
||||||
COPY ./ ./
|
|
||||||
|
|
||||||
# Build binaries
|
|
||||||
RUN make CONTAINER=yes
|
|
||||||
|
|
||||||
# Runtime layer
|
|
||||||
|
|
||||||
FROM alpine:3.12
|
|
||||||
|
|
||||||
# Create appuser and group.
|
|
||||||
ARG USER=inetmock
|
|
||||||
ARG GROUP=inetmock
|
|
||||||
ARG USER_ID=10001
|
|
||||||
ARG GROUP_ID=10001
|
|
||||||
|
|
||||||
COPY --from=build /etc/group /etc/passwd /etc/
|
|
||||||
COPY --from=build --chown=$USER:$GROUP /work/inetmock /work/imctl /usr/lib/inetmock/bin/
|
|
||||||
COPY --chown=$USER:$GROUP ./assets/fakeFiles/ /var/lib/inetmock/fakeFiles/
|
|
||||||
COPY config-container.yaml /etc/inetmock/config.yaml
|
COPY config-container.yaml /etc/inetmock/config.yaml
|
||||||
|
|
||||||
RUN mkdir -p /var/run/inetmock /var/lib/inetmock/certs /usr/lib/inetmock && \
|
RUN mkdir -p /var/run/inetmock /var/lib/inetmock/certs /usr/lib/inetmock && \
|
|
@ -1,6 +1,6 @@
|
||||||
package main
|
package main
|
||||||
|
|
||||||
import "github.com/baez90/inetmock/internal/cmd"
|
import "gitlab.com/inetmock/inetmock/internal/cmd"
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
if err := cmd.ExecuteClientCommand(); err != nil {
|
if err := cmd.ExecuteClientCommand(); err != nil {
|
||||||
|
|
|
@ -1,25 +1,24 @@
|
||||||
package main
|
package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"github.com/baez90/inetmock/internal/cmd"
|
"fmt"
|
||||||
"go.uber.org/zap"
|
|
||||||
"os"
|
|
||||||
|
|
||||||
_ "github.com/baez90/inetmock/plugins/dns_mock"
|
"gitlab.com/inetmock/inetmock/internal/cmd"
|
||||||
_ "github.com/baez90/inetmock/plugins/http_mock"
|
_ "gitlab.com/inetmock/inetmock/plugins/dns_mock"
|
||||||
_ "github.com/baez90/inetmock/plugins/http_proxy"
|
_ "gitlab.com/inetmock/inetmock/plugins/http_mock"
|
||||||
_ "github.com/baez90/inetmock/plugins/metrics_exporter"
|
_ "gitlab.com/inetmock/inetmock/plugins/http_proxy"
|
||||||
_ "github.com/baez90/inetmock/plugins/tls_interceptor"
|
_ "gitlab.com/inetmock/inetmock/plugins/metrics_exporter"
|
||||||
|
_ "gitlab.com/inetmock/inetmock/plugins/tls_interceptor"
|
||||||
|
"go.uber.org/zap"
|
||||||
)
|
)
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
logger, _ := zap.NewProduction()
|
logger, _ := zap.NewProduction()
|
||||||
defer logger.Sync()
|
defer func() {
|
||||||
|
if err := logger.Sync(); err != nil {
|
||||||
|
fmt.Printf(err.Error())
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
|
||||||
if err := cmd.ExecuteServerCommand(); err != nil {
|
cmd.ExecuteServerCommand()
|
||||||
logger.Error("Failed to run inetmock",
|
|
||||||
zap.Error(err),
|
|
||||||
)
|
|
||||||
os.Exit(1)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
30
config.yaml
30
config.yaml
|
@ -1,18 +1,44 @@
|
||||||
x-response-rules: &httpResponseRules
|
x-response-rules: &httpResponseRules
|
||||||
rules:
|
rules:
|
||||||
- pattern: ".*\\.(?i)exe"
|
- pattern: ".*\\.(?i)exe"
|
||||||
|
matcher: Path
|
||||||
|
- pattern: "^application/octet-stream$"
|
||||||
|
target: Accept
|
||||||
|
matcher: Header
|
||||||
response: ./assets/fakeFiles/sample.exe
|
response: ./assets/fakeFiles/sample.exe
|
||||||
- pattern: ".*\\.(?i)(jpg|jpeg)"
|
- pattern: "^image/jpeg$"
|
||||||
|
target: Accept
|
||||||
|
matcher: Header
|
||||||
response: ./assets/fakeFiles/default.jpg
|
response: ./assets/fakeFiles/default.jpg
|
||||||
|
- pattern: ".*\\.(?i)(jpg|jpeg)"
|
||||||
|
matcher: Path
|
||||||
|
response: ./assets/fakeFiles/default.jpg
|
||||||
|
- pattern: "^image/png$"
|
||||||
|
target: Accept
|
||||||
|
matcher: Header
|
||||||
|
response: ./assets/fakeFiles/default.png
|
||||||
- pattern: ".*\\.(?i)png"
|
- pattern: ".*\\.(?i)png"
|
||||||
|
matcher: Path
|
||||||
response: ./assets/fakeFiles/default.png
|
response: ./assets/fakeFiles/default.png
|
||||||
- pattern: ".*\\.(?i)gif"
|
- pattern: ".*\\.(?i)gif"
|
||||||
|
matcher: Path
|
||||||
response: ./assets/fakeFiles/default.gif
|
response: ./assets/fakeFiles/default.gif
|
||||||
- pattern: ".*\\.(?i)ico"
|
- pattern: ".*\\.(?i)ico"
|
||||||
|
matcher: Path
|
||||||
response: ./assets/fakeFiles/default.ico
|
response: ./assets/fakeFiles/default.ico
|
||||||
- pattern: ".*\\.(?i)txt"
|
- pattern: "^text/plain$"
|
||||||
|
target: Accept
|
||||||
|
matcher: Header
|
||||||
response: ./assets/fakeFiles/default.txt
|
response: ./assets/fakeFiles/default.txt
|
||||||
|
- pattern: ".*\\.(?i)txt"
|
||||||
|
matcher: Path
|
||||||
|
response: ./assets/fakeFiles/default.txt
|
||||||
|
- pattern: "^text/html$"
|
||||||
|
target: Accept
|
||||||
|
matcher: Header
|
||||||
|
response: ./assets/fakeFiles/default.html
|
||||||
- pattern: ".*"
|
- pattern: ".*"
|
||||||
|
matcher: Path
|
||||||
response: ./assets/fakeFiles/default.html
|
response: ./assets/fakeFiles/default.html
|
||||||
|
|
||||||
api:
|
api:
|
||||||
|
|
|
@ -2,8 +2,8 @@
|
||||||
|
|
||||||
## Plugins & handlers
|
## Plugins & handlers
|
||||||
|
|
||||||
_INetMock_ is based on plugins that ship one or more __protocol handlers__.
|
_INetMock_ is based on plugins that ship one or more __protocol handlers__. Examples for protocol handlers are HTTP or
|
||||||
Examples for protocol handlers are HTTP or DNS but also TLS.
|
DNS but also TLS.
|
||||||
|
|
||||||
The application ships with the following handlers:
|
The application ships with the following handlers:
|
||||||
|
|
||||||
|
@ -11,9 +11,11 @@ The application ships with the following handlers:
|
||||||
* `dns_mock`
|
* `dns_mock`
|
||||||
* `tls_interceptor`
|
* `tls_interceptor`
|
||||||
|
|
||||||
The configuration of an so called endpoint always specifies which handler should be used, which IP address and port it should listen on and some handler specific `options`.
|
The configuration of an so called endpoint always specifies which handler should be used, which IP address and port it
|
||||||
This way the whole system is very flexible and can be configured for various individual scenarios.
|
should listen on and some handler specific `options`. This way the whole system is very flexible and can be configured
|
||||||
|
for various individual scenarios.
|
||||||
|
|
||||||
## Commands
|
## Commands
|
||||||
|
|
||||||
Beside of __protocol handlers__ a plugin can also ship custom commands e.g. the `tls_interceptor` ships a `generate-ca` command to bootstrap a certificate authority key-pair that can be reused for multiple instances.
|
Beside of __protocol handlers__ a plugin can also ship custom commands e.g. the `tls_interceptor` ships a `generate-ca`
|
||||||
|
command to bootstrap a certificate authority key-pair that can be reused for multiple instances.
|
|
@ -3,12 +3,12 @@
|
||||||
## Intro
|
## Intro
|
||||||
|
|
||||||
The `dns_mock` handler expects an array of rules how it should respond to dfferent DNS queries and a fallback strategy.
|
The `dns_mock` handler expects an array of rules how it should respond to dfferent DNS queries and a fallback strategy.
|
||||||
Currently only queries for __A__ records are supported.
|
Currently only queries for __A__ records are supported. The rules are primarily meant to define some exceptions or well
|
||||||
The rules are primarily meant to define some exceptions or well known DNS responses e.g. to return to right Google DNS IP but for everything else it will return dummy IPs.
|
known DNS responses e.g. to return to right Google DNS IP but for everything else it will return dummy IPs.
|
||||||
|
|
||||||
The rules for the `dns_mock` handler are equivalent to the `http_mock` rules.
|
The rules for the `dns_mock` handler are equivalent to the `http_mock` rules. Every rule consists of a `pattern` that
|
||||||
Every rule consists of a `pattern` that specifies a query name e.g. a single host, a wildcard domain, a wildcard top-level domain or even a _"match all"_ rule is possible.
|
specifies a query name e.g. a single host, a wildcard domain, a wildcard top-level domain or even a _"match all"_ rule
|
||||||
These rules are evaluated in the same order they are defined in the `config.yaml`.
|
is possible. These rules are evaluated in the same order they are defined in the `config.yaml`.
|
||||||
|
|
||||||
The fallback strategy is taken into account whenever a query does not match a rule.
|
The fallback strategy is taken into account whenever a query does not match a rule.
|
||||||
|
|
||||||
|
@ -17,18 +17,19 @@ Right now the following fallback strategies are available:
|
||||||
* _random_
|
* _random_
|
||||||
* _incremental_
|
* _incremental_
|
||||||
|
|
||||||
Just like the handler is configured via the `options` object the fallback strategies are configured via an `args` object.
|
Just like the handler is configured via the `options` object the fallback strategies are configured via an `args`
|
||||||
|
object.
|
||||||
|
|
||||||
### _random_ fallback
|
### _random_ fallback
|
||||||
|
|
||||||
The _random_ fallback strategy is the easier one of the both.
|
The _random_ fallback strategy is the easier one of the both. It doesn't take any argument and it just shuffles a random
|
||||||
It doesn't take any argument and it just shuffles a random IP address for every request no matter if it was already asked for this IP or not.
|
IP address for every request no matter if it was already asked for this IP or not.
|
||||||
|
|
||||||
### _incremental_ fallback
|
### _incremental_ fallback
|
||||||
|
|
||||||
The _incremental_ fallback is little bit more intelligent.
|
The _incremental_ fallback is little bit more intelligent. It takes a `startIP` as an argument which defines from which
|
||||||
It takes a `startIP` as an argument which defines from which IP address the strategy starts counting up to respond to DNS queries.
|
IP address the strategy starts counting up to respond to DNS queries. Just like the _incremental_ strategy it is _
|
||||||
Just like the _incremental_ strategy it is _stateless_ and does not store any already given response for later reuse (at least for now).
|
stateless_ and does not store any already given response for later reuse (at least for now).
|
||||||
|
|
||||||
## Configuration
|
## Configuration
|
||||||
|
|
||||||
|
@ -50,8 +51,9 @@ endpoints:
|
||||||
|
|
||||||
### Matching a whole domain
|
### Matching a whole domain
|
||||||
|
|
||||||
While matching a single host is nice2have it's not very helpful in most cases - except for some edge cases where it might be necesary to specifically return a certain IP address.
|
While matching a single host is nice2have it's not very helpful in most cases - except for some edge cases where it
|
||||||
But it's also possible to match a whole domain no matter what subdomain or sub-subdomain or whatever is requested like this:
|
might be necesary to specifically return a certain IP address. But it's also possible to match a whole domain no matter
|
||||||
|
what subdomain or sub-subdomain or whatever is requested like this:
|
||||||
|
|
||||||
```yml
|
```yml
|
||||||
endpoints:
|
endpoints:
|
||||||
|
@ -67,8 +69,8 @@ endpoints:
|
||||||
|
|
||||||
### Matching a whole TLD
|
### Matching a whole TLD
|
||||||
|
|
||||||
In some cases it might also be interesting to distinguish between different requested TLDs.
|
In some cases it might also be interesting to distinguish between different requested TLDs. Therefore it might be
|
||||||
Therefore it might be interesting to define one IP address to resolve to for every TLD that should be distinguishable.
|
interesting to define one IP address to resolve to for every TLD that should be distinguishable.
|
||||||
|
|
||||||
```yml
|
```yml
|
||||||
endpoints:
|
endpoints:
|
||||||
|
@ -84,8 +86,8 @@ endpoints:
|
||||||
|
|
||||||
### Matching any query
|
### Matching any query
|
||||||
|
|
||||||
Last but not least it is obvously also possible to match any query.
|
Last but not least it is obvously also possible to match any query. This is comparable to a _"static"_ fallback strategy
|
||||||
This is comparable to a _"static"_ fallback strategy in cases where different IP addresses are not necessary but the network setup should be as easy as possible.
|
in cases where different IP addresses are not necessary but the network setup should be as easy as possible.
|
||||||
|
|
||||||
```yml
|
```yml
|
||||||
endpoints:
|
endpoints:
|
||||||
|
@ -103,9 +105,9 @@ endpoints:
|
||||||
|
|
||||||
#### _random_
|
#### _random_
|
||||||
|
|
||||||
Like previously mentioned the _random_ strategy is easy as it can be.
|
Like previously mentioned the _random_ strategy is easy as it can be. It just takes a random unsigned integer of 32
|
||||||
It just takes a random unsigned integer of 32 bits, converts it to an IP address and returns this address as response.
|
bits, converts it to an IP address and returns this address as response. Therefore no further configuration is necessary
|
||||||
Therefore no further configuration is necessary for now.
|
for now.
|
||||||
|
|
||||||
```yml
|
```yml
|
||||||
endpoints:
|
endpoints:
|
||||||
|
@ -121,9 +123,9 @@ endpoints:
|
||||||
|
|
||||||
#### _incremental_
|
#### _incremental_
|
||||||
|
|
||||||
Also like previously mentioned the _incremental_ fallback strategy is fairly easy to setup.
|
Also like previously mentioned the _incremental_ fallback strategy is fairly easy to setup. It just takes a `startIP` as
|
||||||
It just takes a `startIP` as argument which is used to count upwards.
|
argument which is used to count upwards. It does __not__ check for an interval or something like this right now so a
|
||||||
It does __not__ check for an interval or something like this right now so a overflow might occur.
|
overflow might occur.
|
||||||
|
|
||||||
```yml
|
```yml
|
||||||
endpoints:
|
endpoints:
|
||||||
|
|
|
@ -2,10 +2,12 @@
|
||||||
|
|
||||||
## Intro
|
## Intro
|
||||||
|
|
||||||
The `http_mock` handler expects an array of rules how it should respond to different request paths.
|
The `http_mock` handler expects an array of rules how it should respond to different request paths. This allows to e.g.
|
||||||
This allows to e.g. return an image if the request path contains something like _"asdf.jpg"_ but with binary if the request path contains something like _"malicous.exe"_.
|
return an image if the request path contains something like _"asdf.jpg"_ but with binary if the request path contains
|
||||||
|
something like _"malicous.exe"_.
|
||||||
|
|
||||||
A _"catch all"_ rule could return in any case an HTML page or if nothing is provided the handler returns an HTTP 404 status code.
|
A _"catch all"_ rule could return in any case an HTML page or if nothing is provided the handler returns an HTTP 404
|
||||||
|
status code.
|
||||||
|
|
||||||
The rules are taken into account in the same order than they are defined in the `config.yaml`.
|
The rules are taken into account in the same order than they are defined in the `config.yaml`.
|
||||||
|
|
||||||
|
@ -33,8 +35,8 @@ endpoints:
|
||||||
|
|
||||||
### Matching a file extensions
|
### Matching a file extensions
|
||||||
|
|
||||||
While matching a static path might be nice as an example it's not very useful.
|
While matching a static path might be nice as an example it's not very useful. Returning a given file for all kinds of
|
||||||
Returning a given file for all kinds of of request paths based on the requested file extension is way more handy:
|
of request paths based on the requested file extension is way more handy:
|
||||||
|
|
||||||
```yml
|
```yml
|
||||||
endpoints:
|
endpoints:
|
||||||
|
@ -62,7 +64,8 @@ endpoints:
|
||||||
response: ./assets/fakeFiles/default.jpg
|
response: ./assets/fakeFiles/default.jpg
|
||||||
```
|
```
|
||||||
|
|
||||||
This way the extension ignores any case and matches both `.jpg` and `.jpeg` (and of course also e.g. `.JpEg` and so on and so forth).
|
This way the extension ignores any case and matches both `.jpg` and `.jpeg` (and of course also e.g. `.JpEg` and so on
|
||||||
|
and so forth).
|
||||||
|
|
||||||
The default `config.yaml` already ships with some basic rules to handle the most common file extensions.
|
The default `config.yaml` already ships with some basic rules to handle the most common file extensions.
|
||||||
|
|
||||||
|
|
|
@ -1,14 +1,15 @@
|
||||||
|
|
||||||
# `config.yaml`
|
# `config.yaml`
|
||||||
|
|
||||||
## Intro
|
## Intro
|
||||||
|
|
||||||
The configuration of _INetMock_ is mostly done in the `config.yaml`.
|
The configuration of _INetMock_ is mostly done in the `config.yaml`. It defines which endpoints should be started with
|
||||||
It defines which endpoints should be started with which handler and a few more things.
|
which handler and a few more things.
|
||||||
|
|
||||||
Every endpoint has a name that is used for logging and as already mentioned consists of listening IP and port, the handler and its options.
|
Every endpoint has a name that is used for logging and as already mentioned consists of listening IP and port, the
|
||||||
|
handler and its options.
|
||||||
|
|
||||||
INetMock comes with _"Batteries included"_ and ships with a basic `config.yaml` that defines a basic set of endpoints for:
|
INetMock comes with _"Batteries included"_ and ships with a basic `config.yaml` that defines a basic set of endpoints
|
||||||
|
for:
|
||||||
|
|
||||||
* HTTP
|
* HTTP
|
||||||
* HTTPS
|
* HTTPS
|
||||||
|
|
8
go.mod
8
go.mod
|
@ -1,11 +1,11 @@
|
||||||
module github.com/baez90/inetmock
|
module gitlab.com/inetmock/inetmock
|
||||||
|
|
||||||
go 1.15
|
go 1.15
|
||||||
|
|
||||||
require (
|
require (
|
||||||
github.com/golang/mock v1.4.4
|
github.com/golang/mock v1.4.4
|
||||||
github.com/golang/protobuf v1.4.2
|
github.com/golang/protobuf v1.4.2
|
||||||
github.com/google/uuid v1.1.1
|
github.com/google/uuid v1.1.2
|
||||||
github.com/miekg/dns v1.1.31
|
github.com/miekg/dns v1.1.31
|
||||||
github.com/olekukonko/tablewriter v0.0.4
|
github.com/olekukonko/tablewriter v0.0.4
|
||||||
github.com/prometheus/client_golang v1.7.1
|
github.com/prometheus/client_golang v1.7.1
|
||||||
|
@ -13,8 +13,8 @@ require (
|
||||||
github.com/spf13/pflag v1.0.5
|
github.com/spf13/pflag v1.0.5
|
||||||
github.com/spf13/viper v1.7.1
|
github.com/spf13/viper v1.7.1
|
||||||
go.uber.org/zap v1.16.0
|
go.uber.org/zap v1.16.0
|
||||||
google.golang.org/grpc v1.29.1
|
google.golang.org/grpc v1.34.0
|
||||||
google.golang.org/protobuf v1.23.0
|
google.golang.org/protobuf v1.25.0
|
||||||
gopkg.in/elazarl/goproxy.v1 v1.0.0-20180725130230-947c36da3153
|
gopkg.in/elazarl/goproxy.v1 v1.0.0-20180725130230-947c36da3153
|
||||||
gopkg.in/yaml.v3 v3.0.0-20200615113413-eeeca48fe776
|
gopkg.in/yaml.v3 v3.0.0-20200615113413-eeeca48fe776
|
||||||
)
|
)
|
||||||
|
|
88
go.sum
88
go.sum
|
@ -37,6 +37,7 @@ github.com/cespare/xxhash/v2 v2.1.1 h1:6MnRN8NT7+YBpUIWxHtefFZOKTAPgGjpQSxqLNn0+
|
||||||
github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
|
github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
|
||||||
github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=
|
github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=
|
||||||
github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc=
|
github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc=
|
||||||
|
github.com/cncf/udpa/go v0.0.0-20200629203442-efcf912fb354/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk=
|
||||||
github.com/coreos/bbolt v1.3.2/go.mod h1:iRUV2dpdMOn7Bo10OQBFzIJO9kkE559Wcmn+qkEiiKk=
|
github.com/coreos/bbolt v1.3.2/go.mod h1:iRUV2dpdMOn7Bo10OQBFzIJO9kkE559Wcmn+qkEiiKk=
|
||||||
github.com/coreos/etcd v3.3.10+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE=
|
github.com/coreos/etcd v3.3.10+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE=
|
||||||
github.com/coreos/etcd v3.3.13+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE=
|
github.com/coreos/etcd v3.3.13+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE=
|
||||||
|
@ -50,19 +51,19 @@ 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/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||||
github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ=
|
github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ=
|
||||||
github.com/dgryski/go-sip13 v0.0.0-20181026042036-e10d5fee7954/go.mod h1:vAd38F8PWV+bWy6jNmig1y/TA+kYO4g3RSRF0IAv0no=
|
github.com/dgryski/go-sip13 v0.0.0-20181026042036-e10d5fee7954/go.mod h1:vAd38F8PWV+bWy6jNmig1y/TA+kYO4g3RSRF0IAv0no=
|
||||||
github.com/elazarl/goproxy v0.0.0-20200809112317-0581fc3aee2d h1:rtM8HsT3NG37YPjz8sYSbUSdElP9lUsQENYzJDZDUBE=
|
github.com/elazarl/goproxy v0.0.0-20201021153353-00ad82a08272 h1:Am81SElhR3XCQBunTisljzNkNese2T1FiV8jP79+dqg=
|
||||||
github.com/elazarl/goproxy v0.0.0-20200809112317-0581fc3aee2d/go.mod h1:Ro8st/ElPeALwNFlcTpWmkr6IoMFfkjXAvTHpevnDsM=
|
github.com/elazarl/goproxy v0.0.0-20201021153353-00ad82a08272/go.mod h1:Ro8st/ElPeALwNFlcTpWmkr6IoMFfkjXAvTHpevnDsM=
|
||||||
github.com/elazarl/goproxy/ext v0.0.0-20190711103511-473e67f1d7d2/go.mod h1:gNh8nYJoAm43RfaxurUnxr+N1PwuFV3ZMl/efxlIlY8=
|
github.com/elazarl/goproxy/ext v0.0.0-20190711103511-473e67f1d7d2/go.mod h1:gNh8nYJoAm43RfaxurUnxr+N1PwuFV3ZMl/efxlIlY8=
|
||||||
github.com/elazarl/goproxy/ext v0.0.0-20200809112317-0581fc3aee2d h1:st1tmvy+4duoRj+RaeeJoECWCWM015fBtf/4aR+hhqk=
|
github.com/elazarl/goproxy/ext v0.0.0-20201021153353-00ad82a08272 h1:xOHQWEGsftkjjFV2KIrC9vOz+iOinvZ7H6EAjSznqUk=
|
||||||
github.com/elazarl/goproxy/ext v0.0.0-20200809112317-0581fc3aee2d/go.mod h1:gNh8nYJoAm43RfaxurUnxr+N1PwuFV3ZMl/efxlIlY8=
|
github.com/elazarl/goproxy/ext v0.0.0-20201021153353-00ad82a08272/go.mod h1:gNh8nYJoAm43RfaxurUnxr+N1PwuFV3ZMl/efxlIlY8=
|
||||||
github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
|
github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
|
||||||
|
github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
|
||||||
github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98=
|
github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98=
|
||||||
|
github.com/envoyproxy/go-control-plane v0.9.7/go.mod h1:cwu0lG7PUMfa9snN8LXBig5ynNVH9qI8YYLbd1fK2po=
|
||||||
github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c=
|
github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c=
|
||||||
github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4=
|
github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4=
|
||||||
github.com/fsnotify/fsnotify v1.4.7 h1:IXs+QLmnXW2CcXuY+8Mzv/fWEsPGWxqefPtCP5CnV9I=
|
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/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
|
||||||
github.com/fsnotify/fsnotify v1.4.9 h1:hsms1Qyu0jgnwNXIxa+/V/PDsU6CfLf6CNO8H7IWoS4=
|
|
||||||
github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ=
|
|
||||||
github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04=
|
github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04=
|
||||||
github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU=
|
github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU=
|
||||||
github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as=
|
github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as=
|
||||||
|
@ -77,8 +78,6 @@ github.com/golang/groupcache v0.0.0-20190129154638-5b532d6fd5ef/go.mod h1:cIg4er
|
||||||
github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
|
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/mock v1.2.0/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
|
||||||
github.com/golang/mock v1.3.1/go.mod h1:sBzyDLLjw3U8JLTeZvSv8jJB+tU5PVekmnlKIyFUx0Y=
|
github.com/golang/mock v1.3.1/go.mod h1:sBzyDLLjw3U8JLTeZvSv8jJB+tU5PVekmnlKIyFUx0Y=
|
||||||
github.com/golang/mock v1.4.3 h1:GV+pQPG/EUUbkh47niozDcADz6go/dUwhVzdUQHIVRw=
|
|
||||||
github.com/golang/mock v1.4.3/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw=
|
|
||||||
github.com/golang/mock v1.4.4 h1:l75CXGRSwbaYNpl/Z2X1XIIAMSCquvXgpVZDhwEIJsc=
|
github.com/golang/mock v1.4.4 h1:l75CXGRSwbaYNpl/Z2X1XIIAMSCquvXgpVZDhwEIJsc=
|
||||||
github.com/golang/mock v1.4.4/go.mod h1:l3mdAwkq5BuhzHwde/uurv3sEJeZMXNpwsxVWU71h+4=
|
github.com/golang/mock v1.4.4/go.mod h1:l3mdAwkq5BuhzHwde/uurv3sEJeZMXNpwsxVWU71h+4=
|
||||||
github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
||||||
|
@ -90,8 +89,11 @@ github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:x
|
||||||
github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs=
|
github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs=
|
||||||
github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w=
|
github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w=
|
||||||
github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0=
|
github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0=
|
||||||
|
github.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QDs8UjoX8=
|
||||||
github.com/golang/protobuf v1.4.2 h1:+Z5KGCizgyZCbGh1KZqA0fcLLkwbsjIzS4aV2v7wJX0=
|
github.com/golang/protobuf v1.4.2 h1:+Z5KGCizgyZCbGh1KZqA0fcLLkwbsjIzS4aV2v7wJX0=
|
||||||
github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI=
|
github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI=
|
||||||
|
github.com/golang/protobuf v1.4.3 h1:JjCZWpVbqXDqFVmTfYWEVTMIYrL/NPdPSCHPJ0T/raM=
|
||||||
|
github.com/golang/protobuf v1.4.3/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI=
|
||||||
github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
|
github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
|
||||||
github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
|
github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
|
||||||
github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M=
|
github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M=
|
||||||
|
@ -99,6 +101,8 @@ github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMyw
|
||||||
github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
|
github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
|
||||||
github.com/google/go-cmp v0.4.0 h1:xsAVV57WRhGj6kEIi8ReJzQlHHqcBYCElAvkovg3B/4=
|
github.com/google/go-cmp v0.4.0 h1:xsAVV57WRhGj6kEIi8ReJzQlHHqcBYCElAvkovg3B/4=
|
||||||
github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||||
|
github.com/google/go-cmp v0.5.0 h1:/QaMHBdZ26BB3SSst0Iwl10Epc+xhTquomWX0oZEB6w=
|
||||||
|
github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||||
github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
|
github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
|
||||||
github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs=
|
github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs=
|
||||||
github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc=
|
github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc=
|
||||||
|
@ -106,6 +110,8 @@ github.com/google/pprof v0.0.0-20190515194954-54271f7e092f/go.mod h1:zfwlbNMJ+OI
|
||||||
github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI=
|
github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI=
|
||||||
github.com/google/uuid v1.1.1 h1:Gkbcsh/GbpXz7lPftLA3P6TYMwjCLYm83jiFQZF/3gY=
|
github.com/google/uuid v1.1.1 h1:Gkbcsh/GbpXz7lPftLA3P6TYMwjCLYm83jiFQZF/3gY=
|
||||||
github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
||||||
|
github.com/google/uuid v1.1.2 h1:EVhdT+1Kseyi1/pUmXKaFxYsDNy9RQYkMWRH68J/W7Y=
|
||||||
|
github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
||||||
github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg=
|
github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg=
|
||||||
github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk=
|
github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk=
|
||||||
github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1 h1:EGx4pi6eqNxGaHF6qqu48+N2wcFQ5qg5FXgOdqsJ5d8=
|
github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1 h1:EGx4pi6eqNxGaHF6qqu48+N2wcFQ5qg5FXgOdqsJ5d8=
|
||||||
|
@ -148,7 +154,6 @@ github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7V
|
||||||
github.com/kisielk/errcheck v1.1.0/go.mod h1:EZBBE59ingxPouuu3KfxchcWSUPOHkagtvWXihfKN4Q=
|
github.com/kisielk/errcheck v1.1.0/go.mod h1:EZBBE59ingxPouuu3KfxchcWSUPOHkagtvWXihfKN4Q=
|
||||||
github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
|
github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
|
||||||
github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
|
github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
|
||||||
github.com/kr/fs v0.1.0/go.mod h1:FFnZGqtBN9Gxj7eW1uZ42v5BccTP0vu6NEaFoC2HwRg=
|
|
||||||
github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc=
|
github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc=
|
||||||
github.com/kr/pretty v0.1.0 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI=
|
github.com/kr/pretty v0.1.0 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI=
|
||||||
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
|
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
|
||||||
|
@ -158,14 +163,10 @@ github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
|
||||||
github.com/magiconair/properties v1.8.0/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ=
|
github.com/magiconair/properties v1.8.0/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ=
|
||||||
github.com/magiconair/properties v1.8.1 h1:ZC2Vc7/ZFkGmsVC9KvOjumD+G5lXy2RtTKyzRKO2BQ4=
|
github.com/magiconair/properties v1.8.1 h1:ZC2Vc7/ZFkGmsVC9KvOjumD+G5lXy2RtTKyzRKO2BQ4=
|
||||||
github.com/magiconair/properties v1.8.1/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ=
|
github.com/magiconair/properties v1.8.1/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ=
|
||||||
github.com/magiconair/properties v1.8.4 h1:8KGKTcQQGm0Kv7vEbKFErAoAOFyyacLStRtQSeYtvkY=
|
|
||||||
github.com/magiconair/properties v1.8.4/go.mod h1:y3VJvCyxH9uVvJTWEGAELF3aiYNyPKd5NZ3oSwXrF60=
|
|
||||||
github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU=
|
github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU=
|
||||||
github.com/mattn/go-isatty v0.0.3/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4=
|
github.com/mattn/go-isatty v0.0.3/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4=
|
||||||
github.com/mattn/go-runewidth v0.0.7 h1:Ei8KR0497xHyKJPAv59M1dkC+rOZCMBJ+t3fZ+twI54=
|
github.com/mattn/go-runewidth v0.0.7 h1:Ei8KR0497xHyKJPAv59M1dkC+rOZCMBJ+t3fZ+twI54=
|
||||||
github.com/mattn/go-runewidth v0.0.7/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m2gUSrubnMI=
|
github.com/mattn/go-runewidth v0.0.7/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m2gUSrubnMI=
|
||||||
github.com/mattn/go-runewidth v0.0.9 h1:Lm995f3rfxdpd6TSmuVCHVb/QhupuXlYr8sCI/QdE+0=
|
|
||||||
github.com/mattn/go-runewidth v0.0.9/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m2gUSrubnMI=
|
|
||||||
github.com/matttproud/golang_protobuf_extensions v1.0.1 h1:4hp9jkHxhMHkqkrB3Ix0jegS5sx/RkqARlsWZ6pIwiU=
|
github.com/matttproud/golang_protobuf_extensions v1.0.1 h1:4hp9jkHxhMHkqkrB3Ix0jegS5sx/RkqARlsWZ6pIwiU=
|
||||||
github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0=
|
github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0=
|
||||||
github.com/miekg/dns v1.0.14 h1:9jZdLNd/P4+SfEJ0TNyxYpsK8N4GtfylBLqtbYN1sbA=
|
github.com/miekg/dns v1.0.14 h1:9jZdLNd/P4+SfEJ0TNyxYpsK8N4GtfylBLqtbYN1sbA=
|
||||||
|
@ -181,8 +182,6 @@ github.com/mitchellh/iochan v1.0.0/go.mod h1:JwYml1nuB7xOzsp52dPpHFffvOCDupsG0Qu
|
||||||
github.com/mitchellh/mapstructure v0.0.0-20160808181253-ca63d7c062ee/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y=
|
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 h1:fmNYVwqnSfB9mZU6OS2O6GsXM+wcskZDuKQzvN1EDeE=
|
||||||
github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y=
|
github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y=
|
||||||
github.com/mitchellh/mapstructure v1.3.3 h1:SzB1nHZ2Xi+17FP0zVQBHIZqvwRN9408fJO8h+eeNA8=
|
|
||||||
github.com/mitchellh/mapstructure v1.3.3/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo=
|
|
||||||
github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
|
github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
|
||||||
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
|
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
|
||||||
github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
|
github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
|
||||||
|
@ -194,12 +193,9 @@ github.com/olekukonko/tablewriter v0.0.4/go.mod h1:zq6QwlOf5SlnkVbMSr5EoBv3636FW
|
||||||
github.com/pascaldekloe/goe v0.0.0-20180627143212-57f6aae5913c/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc=
|
github.com/pascaldekloe/goe v0.0.0-20180627143212-57f6aae5913c/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc=
|
||||||
github.com/pelletier/go-toml v1.2.0 h1:T5zMGML61Wp+FlcbWjRDT7yAxhJNAiPPLOFECq181zc=
|
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 v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic=
|
||||||
github.com/pelletier/go-toml v1.8.1 h1:1Nf83orprkJyknT6h7zbuEGUEjcyVlCxSUGTENmNCRM=
|
|
||||||
github.com/pelletier/go-toml v1.8.1/go.mod h1:T2/BmBdy8dvIRq1a/8aqjN41wvWlN4lrapLU/GW4pbc=
|
|
||||||
github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
||||||
github.com/pkg/errors v0.8.1 h1:iURUrRGxPUNPdy5/HRSm+Yj6okJ6UtLINN0Q9M4+h3I=
|
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/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
||||||
github.com/pkg/sftp v1.10.1/go.mod h1:lYOWFsE0bwd1+KfKJaKeuokY15vzFx25BLbzYYoAxZI=
|
|
||||||
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
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/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.1.1/go.mod h1:em0nMJCgc9GFtwrmVmEMR/ZL6WyhyjMBndrE9hABlRI=
|
||||||
|
@ -245,24 +241,16 @@ github.com/soheilhy/cmux v0.1.4/go.mod h1:IM3LyeVVIOuxMH7sFAkER9+bJ4dT7Ms6E4xg4k
|
||||||
github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA=
|
github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA=
|
||||||
github.com/spf13/afero v1.1.2 h1:m8/z1t7/fwjysjQRYbP0RD+bUIF/8tJwPdEZsI83ACI=
|
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/afero v1.1.2/go.mod h1:j4pytiNVoe2o6bmDsKpLACNPDBIoEAkihy7loJ1B0CQ=
|
||||||
github.com/spf13/afero v1.4.0 h1:jsLTaI1zwYO3vjrzHalkVcIHXTNmdQFepW4OI8H3+x8=
|
|
||||||
github.com/spf13/afero v1.4.0/go.mod h1:Ai8FlHk4v/PARR026UzYexafAt9roJ7LcLMAmO6Z93I=
|
|
||||||
github.com/spf13/cast v1.3.0 h1:oget//CVOEoFewqQxwr0Ej5yjygnqGkvggSE/gB35Q8=
|
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/cast v1.3.0/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE=
|
||||||
github.com/spf13/cast v1.3.1 h1:nFm6S0SMdyzrzcmThSipiEubIDy8WEXKNZ0UOgiRpng=
|
|
||||||
github.com/spf13/cast v1.3.1/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE=
|
|
||||||
github.com/spf13/cobra v1.0.0 h1:6m/oheQuQ13N9ks4hubMG6BnvwOeaJrqSPLahSnczz8=
|
github.com/spf13/cobra v1.0.0 h1:6m/oheQuQ13N9ks4hubMG6BnvwOeaJrqSPLahSnczz8=
|
||||||
github.com/spf13/cobra v1.0.0/go.mod h1:/6GTrnGXV9HjY+aR4k0oJ5tcvakLuG6EuKReYlHNrgE=
|
github.com/spf13/cobra v1.0.0/go.mod h1:/6GTrnGXV9HjY+aR4k0oJ5tcvakLuG6EuKReYlHNrgE=
|
||||||
github.com/spf13/jwalterweatherman v1.0.0 h1:XHEdyB+EcvlqZamSM4ZOMGlc93t6AcsBEu9Gc1vn7yk=
|
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/jwalterweatherman v1.0.0/go.mod h1:cQK4TGJAtQXfYWX+Ddv3mKDzgVb68N+wFjFa4jdeBTo=
|
||||||
github.com/spf13/jwalterweatherman v1.1.0 h1:ue6voC5bR5F8YxI5S67j9i582FU4Qvo2bmqnqMYADFk=
|
|
||||||
github.com/spf13/jwalterweatherman v1.1.0/go.mod h1:aNWZUN0dPAAO/Ljvb5BEdw96iTZ0EXowPYD95IqWIGo=
|
|
||||||
github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4=
|
github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4=
|
||||||
github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA=
|
github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA=
|
||||||
github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
|
github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
|
||||||
github.com/spf13/viper v1.4.0/go.mod h1:PTJ7Z/lr49W6bUbkmS1V3by4uWynFiR9p7+dSq/yZzE=
|
github.com/spf13/viper v1.4.0/go.mod h1:PTJ7Z/lr49W6bUbkmS1V3by4uWynFiR9p7+dSq/yZzE=
|
||||||
github.com/spf13/viper v1.7.0 h1:xVKxvI7ouOI5I+U9s2eeiUfMaWBVoXA3AWskkrqK0VM=
|
|
||||||
github.com/spf13/viper v1.7.0/go.mod h1:8WkrPz2fc9jxqZNCJI/76HCieCp4Q8HaLFoCha5qpdg=
|
|
||||||
github.com/spf13/viper v1.7.1 h1:pM5oEahlgWv/WnHXpgbKz7iLIxRf65tye2Ci+XFK5sk=
|
github.com/spf13/viper v1.7.1 h1:pM5oEahlgWv/WnHXpgbKz7iLIxRf65tye2Ci+XFK5sk=
|
||||||
github.com/spf13/viper v1.7.1/go.mod h1:8WkrPz2fc9jxqZNCJI/76HCieCp4Q8HaLFoCha5qpdg=
|
github.com/spf13/viper v1.7.1/go.mod h1:8WkrPz2fc9jxqZNCJI/76HCieCp4Q8HaLFoCha5qpdg=
|
||||||
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||||
|
@ -271,6 +259,7 @@ github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXf
|
||||||
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
|
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
|
||||||
github.com/stretchr/testify v1.4.0 h1:2E4SXV/wtOkTonXsotYi4li6zVWxYlZuYNCXe9XRJyk=
|
github.com/stretchr/testify v1.4.0 h1:2E4SXV/wtOkTonXsotYi4li6zVWxYlZuYNCXe9XRJyk=
|
||||||
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
|
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
|
||||||
|
github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA=
|
||||||
github.com/subosito/gotenv v1.2.0 h1:Slr1R9HxAlEKefgq5jn9U+DnETlIUa6HfgEzj0g5d7s=
|
github.com/subosito/gotenv v1.2.0 h1:Slr1R9HxAlEKefgq5jn9U+DnETlIUa6HfgEzj0g5d7s=
|
||||||
github.com/subosito/gotenv v1.2.0/go.mod h1:N0PQaV/YGNqwC0u51sEeR/aUtSLEXKX9iv69rRypqCw=
|
github.com/subosito/gotenv v1.2.0/go.mod h1:N0PQaV/YGNqwC0u51sEeR/aUtSLEXKX9iv69rRypqCw=
|
||||||
github.com/tmc/grpc-websocket-proxy v0.0.0-20190109142713-0ad062ec5ee5/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U=
|
github.com/tmc/grpc-websocket-proxy v0.0.0-20190109142713-0ad062ec5ee5/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U=
|
||||||
|
@ -283,18 +272,12 @@ go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8=
|
||||||
go.uber.org/atomic v1.4.0/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE=
|
go.uber.org/atomic v1.4.0/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE=
|
||||||
go.uber.org/atomic v1.6.0 h1:Ezj3JGmsOnG1MoRWQkPBsKLe9DwWD9QeXzTRzzldNVk=
|
go.uber.org/atomic v1.6.0 h1:Ezj3JGmsOnG1MoRWQkPBsKLe9DwWD9QeXzTRzzldNVk=
|
||||||
go.uber.org/atomic v1.6.0/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ=
|
go.uber.org/atomic v1.6.0/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ=
|
||||||
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.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0=
|
go.uber.org/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0=
|
||||||
go.uber.org/multierr v1.5.0 h1:KCa4XfM8CWFCpxXRGok+Q0SS/0XBhMDbHHGABQLvD2A=
|
go.uber.org/multierr v1.5.0 h1:KCa4XfM8CWFCpxXRGok+Q0SS/0XBhMDbHHGABQLvD2A=
|
||||||
go.uber.org/multierr v1.5.0/go.mod h1:FeouvMocqHpRaaGuG9EjoKcStLC43Zu/fmqdUMPcKYU=
|
go.uber.org/multierr v1.5.0/go.mod h1:FeouvMocqHpRaaGuG9EjoKcStLC43Zu/fmqdUMPcKYU=
|
||||||
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/tools v0.0.0-20190618225709-2cfd321de3ee h1:0mgffUl7nfd+FpvXMVz4IDEaUSmT1ysygQC7qYo7sG4=
|
go.uber.org/tools v0.0.0-20190618225709-2cfd321de3ee h1:0mgffUl7nfd+FpvXMVz4IDEaUSmT1ysygQC7qYo7sG4=
|
||||||
go.uber.org/tools v0.0.0-20190618225709-2cfd321de3ee/go.mod h1:vJERXedbb3MVM5f9Ejo0C68/HhF8uaILCdgjnY+goOA=
|
go.uber.org/tools v0.0.0-20190618225709-2cfd321de3ee/go.mod h1:vJERXedbb3MVM5f9Ejo0C68/HhF8uaILCdgjnY+goOA=
|
||||||
go.uber.org/zap v1.10.0/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q=
|
go.uber.org/zap v1.10.0/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q=
|
||||||
go.uber.org/zap v1.15.0 h1:ZZCA22JRF2gQE5FoNmhmrf7jeJJ2uhqDUNRYKm8dvmM=
|
|
||||||
go.uber.org/zap v1.15.0/go.mod h1:Mb2vm2krFEG5DV0W9qcHBYFtp/Wku1cvYaqPsS/WYfc=
|
|
||||||
go.uber.org/zap v1.16.0 h1:uFRZXykJGK9lLY4HtgSw44DnIcAM+kRBP7x5m+NpAOM=
|
go.uber.org/zap v1.16.0 h1:uFRZXykJGK9lLY4HtgSw44DnIcAM+kRBP7x5m+NpAOM=
|
||||||
go.uber.org/zap v1.16.0/go.mod h1:MA8QOfq0BHJwdXa996Y4dYkAqRKB8/1K1QMMZVaNZjQ=
|
go.uber.org/zap v1.16.0/go.mod h1:MA8QOfq0BHJwdXa996Y4dYkAqRKB8/1K1QMMZVaNZjQ=
|
||||||
golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
|
golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
|
||||||
|
@ -303,12 +286,8 @@ golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACk
|
||||||
golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||||
golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5 h1:58fnuSXlxZmFdJyvtTFVmVhcMLU6v5fEb/ok4wyqtNU=
|
golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5 h1:58fnuSXlxZmFdJyvtTFVmVhcMLU6v5fEb/ok4wyqtNU=
|
||||||
golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||||
golang.org/x/crypto v0.0.0-20190820162420-60c769a6c586/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
|
||||||
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550 h1:ObdrDkeb4kJdCP557AjRjq69pTHfNouLtWZG7j9rPN8=
|
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550 h1:ObdrDkeb4kJdCP557AjRjq69pTHfNouLtWZG7j9rPN8=
|
||||||
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
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-20201002094018-c90954cbb977 h1:yH6opeNE+0SY+7pXT4gclZUoKHogXeC2EvOSHGOMGPU=
|
|
||||||
golang.org/x/crypto v0.0.0-20201002094018-c90954cbb977/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
|
||||||
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
|
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
|
||||||
golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
|
golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
|
||||||
golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8=
|
golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8=
|
||||||
|
@ -348,8 +327,8 @@ golang.org/x/net v0.0.0-20190620200207-3b0461eec859 h1:R/3boaszxrf1GEUWTVDzSKVwL
|
||||||
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
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 h1:l5EDrHhldLYb3ZRHDUhXF7Om7MvYXnkV9/iQNo1lX6g=
|
golang.org/x/net v0.0.0-20190923162816-aa69164e4478 h1:l5EDrHhldLYb3ZRHDUhXF7Om7MvYXnkV9/iQNo1lX6g=
|
||||||
golang.org/x/net v0.0.0-20190923162816-aa69164e4478/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-20200930145003-4acb6c075d10 h1:YfxMZzv3PjGonQYNUaeU2+DhAdqOxerQ30JFB6WgAXo=
|
golang.org/x/net v0.0.0-20201224014010-6772e930b67b h1:iFwSg7t5GZmB/Q5TjiEAsdoLDrdJRC1RiF2WhuV29Qw=
|
||||||
golang.org/x/net v0.0.0-20200930145003-4acb6c075d10/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
|
golang.org/x/net v0.0.0-20201224014010-6772e930b67b/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-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
|
||||||
golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
|
golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
|
||||||
golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
|
golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
|
||||||
|
@ -377,20 +356,20 @@ golang.org/x/sys v0.0.0-20190606165138-5da285871e9c/go.mod h1:h1NjWce9XRLGQEsW7w
|
||||||
golang.org/x/sys v0.0.0-20190624142023-c5567b49c5d0 h1:HyfiK1WMnHj5FXFXatD+Qs1A/xC2Run6RzeW1SyHxpc=
|
golang.org/x/sys v0.0.0-20190624142023-c5567b49c5d0 h1:HyfiK1WMnHj5FXFXatD+Qs1A/xC2Run6RzeW1SyHxpc=
|
||||||
golang.org/x/sys v0.0.0-20190624142023-c5567b49c5d0/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20190624142023-c5567b49c5d0/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
golang.org/x/sys v0.0.0-20190924154521-2837fb4f24fe/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20190924154521-2837fb4f24fe/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
golang.org/x/sys v0.0.0-20191005200804-aed5e4c7ecf9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
|
||||||
golang.org/x/sys v0.0.0-20200106162015-b016eb3dc98e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20200106162015-b016eb3dc98e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
|
||||||
golang.org/x/sys v0.0.0-20200615200032-f1bc736245b1 h1:ogLJMz+qpzav7lGMh10LMvAkM/fAoGlaiiHYiFYdm80=
|
golang.org/x/sys v0.0.0-20200615200032-f1bc736245b1 h1:ogLJMz+qpzav7lGMh10LMvAkM/fAoGlaiiHYiFYdm80=
|
||||||
golang.org/x/sys v0.0.0-20200615200032-f1bc736245b1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20200615200032-f1bc736245b1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f h1:+Nyd8tzPX9R7BWHguqsrbFdRx3WQ/1ib8I44HXV5yTA=
|
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20201223074533-0d417f636930 h1:vRgIt+nup/B/BwIS0g2oC0haq0iqbV3ZA+u6+0TlNCo=
|
||||||
golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
golang.org/x/sys v0.0.0-20201223074533-0d417f636930/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
|
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.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||||
golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||||
golang.org/x/text v0.3.2 h1:tW2bmiBqwgJj/UpqtC8EpXEZVYOwU0yG4iWbprSVAcs=
|
golang.org/x/text v0.3.2 h1:tW2bmiBqwgJj/UpqtC8EpXEZVYOwU0yG4iWbprSVAcs=
|
||||||
golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
|
golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
|
||||||
golang.org/x/text v0.3.3 h1:cokOdA+Jmi5PJGXLlLllQSgYigAEfHXJAERHVMaCc2k=
|
|
||||||
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||||
|
golang.org/x/text v0.3.4 h1:0YWbFKbhXG/wIiuHDSKpS0Iy7FSA+u45VtBMfQcFTTc=
|
||||||
|
golang.org/x/text v0.3.4/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||||
golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||||
golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||||
golang.org/x/tools v0.0.0-20180221164845-07fd8470d635/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
golang.org/x/tools v0.0.0-20180221164845-07fd8470d635/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||||
|
@ -414,6 +393,7 @@ golang.org/x/tools v0.0.0-20191029041327-9cc4af7d6b2c/go.mod h1:b+2E5dAYhXwXZwtn
|
||||||
golang.org/x/tools v0.0.0-20191029190741-b9c20aec41a5/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
golang.org/x/tools v0.0.0-20191029190741-b9c20aec41a5/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||||
golang.org/x/tools v0.0.0-20191112195655-aa38f8e97acc h1:NCy3Ohtk6Iny5V/reW2Ktypo4zIpWBdRJ1uFMjBxdg8=
|
golang.org/x/tools v0.0.0-20191112195655-aa38f8e97acc h1:NCy3Ohtk6Iny5V/reW2Ktypo4zIpWBdRJ1uFMjBxdg8=
|
||||||
golang.org/x/tools v0.0.0-20191112195655-aa38f8e97acc/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
golang.org/x/tools v0.0.0-20191112195655-aa38f8e97acc/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||||
|
golang.org/x/tools v0.0.0-20191216052735-49a3e744a425 h1:VvQyQJN0tSuecqgcIxMWnnfG5kSmgy9KZR9sW3W5QeA=
|
||||||
golang.org/x/tools v0.0.0-20191216052735-49a3e744a425/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
|
golang.org/x/tools v0.0.0-20191216052735-49a3e744a425/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
|
||||||
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
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-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||||
|
@ -438,21 +418,35 @@ google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98
|
||||||
google.golang.org/genproto v0.0.0-20190911173649-1774047e7e51/go.mod h1:IbNlFCBrqXvoKpeg0TB2l7cyZUmoaFKYIwrEpbDKLA8=
|
google.golang.org/genproto v0.0.0-20190911173649-1774047e7e51/go.mod h1:IbNlFCBrqXvoKpeg0TB2l7cyZUmoaFKYIwrEpbDKLA8=
|
||||||
google.golang.org/genproto v0.0.0-20191108220845-16a3f7862a1a h1:Ob5/580gVHBJZgXnff1cZDbG+xLtMVE5mDRTe+nIsX4=
|
google.golang.org/genproto v0.0.0-20191108220845-16a3f7862a1a h1:Ob5/580gVHBJZgXnff1cZDbG+xLtMVE5mDRTe+nIsX4=
|
||||||
google.golang.org/genproto v0.0.0-20191108220845-16a3f7862a1a/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=
|
google.golang.org/genproto v0.0.0-20191108220845-16a3f7862a1a/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=
|
||||||
|
google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013 h1:+kGHl1aib/qcwaRi1CbqBZ1rk19r85MNUf8HaBghugY=
|
||||||
|
google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo=
|
||||||
|
google.golang.org/genproto v0.0.0-20201214200347-8c77b98c765d h1:HV9Z9qMhQEsdlvxNFELgQ11RkMzO3CMkjEySjCtuLes=
|
||||||
|
google.golang.org/genproto v0.0.0-20201214200347-8c77b98c765d/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
|
||||||
google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=
|
google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=
|
||||||
google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38=
|
google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38=
|
||||||
google.golang.org/grpc v1.21.0/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM=
|
google.golang.org/grpc v1.21.0/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM=
|
||||||
google.golang.org/grpc v1.21.1/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM=
|
google.golang.org/grpc v1.21.1/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM=
|
||||||
google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg=
|
google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg=
|
||||||
google.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQciAY=
|
google.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQciAY=
|
||||||
|
google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk=
|
||||||
google.golang.org/grpc v1.29.1 h1:EC2SB8S04d2r73uptxphDSUG+kTKVgjRPF+N3xpxRB4=
|
google.golang.org/grpc v1.29.1 h1:EC2SB8S04d2r73uptxphDSUG+kTKVgjRPF+N3xpxRB4=
|
||||||
google.golang.org/grpc v1.29.1/go.mod h1:itym6AZVZYACWQqET3MqgPpjcuV5QH3BxFS3IjizoKk=
|
google.golang.org/grpc v1.29.1/go.mod h1:itym6AZVZYACWQqET3MqgPpjcuV5QH3BxFS3IjizoKk=
|
||||||
|
google.golang.org/grpc v1.34.0 h1:raiipEjMOIC/TO2AvyTxP25XFdLxNIBwzDh3FM3XztI=
|
||||||
|
google.golang.org/grpc v1.34.0/go.mod h1:WotjhfgOW/POjDeRt8vscBtXq+2VjORFy659qA51WJ8=
|
||||||
|
google.golang.org/grpc/cmd/protoc-gen-go-grpc v1.0.1 h1:M8spwkmx0pHrPq+uMdl22w5CvJ/Y+oAJTIs9oGoCpOE=
|
||||||
|
google.golang.org/grpc/cmd/protoc-gen-go-grpc v1.0.1/go.mod h1:6Kw0yEErY5E/yWrBtf03jp27GLLJujG4z/JK95pnjjw=
|
||||||
google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8=
|
google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8=
|
||||||
google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0=
|
google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0=
|
||||||
google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM=
|
google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM=
|
||||||
google.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miEFZTKqfCUM6K7xSMQL9OKL/b6hQv+e19PK+JZNE=
|
google.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miEFZTKqfCUM6K7xSMQL9OKL/b6hQv+e19PK+JZNE=
|
||||||
google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo=
|
google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo=
|
||||||
|
google.golang.org/protobuf v1.22.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
|
||||||
google.golang.org/protobuf v1.23.0 h1:4MY060fB1DLGMB/7MBTLnwQUY6+F09GEiz6SsrNqyzM=
|
google.golang.org/protobuf v1.23.0 h1:4MY060fB1DLGMB/7MBTLnwQUY6+F09GEiz6SsrNqyzM=
|
||||||
google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
|
google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
|
||||||
|
google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
|
||||||
|
google.golang.org/protobuf v1.24.0/go.mod h1:r/3tXBNzIEhYS9I1OUVjXDlt8tc493IdKGjtUeSXeh4=
|
||||||
|
google.golang.org/protobuf v1.25.0 h1:Ejskq+SyPohKW+1uil0JJMtmHCgJPJ/qWTxr8qp+R4c=
|
||||||
|
google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c=
|
||||||
gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw=
|
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 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||||
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 h1:qIbj1fsPNlZgppZ+VLlY7N33q108Sa+fhmuc+sWQYwY=
|
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 h1:qIbj1fsPNlZgppZ+VLlY7N33q108Sa+fhmuc+sWQYwY=
|
||||||
|
@ -464,8 +458,6 @@ gopkg.in/elazarl/goproxy.v1 v1.0.0-20180725130230-947c36da3153/go.mod h1:xzjpkye
|
||||||
gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI=
|
gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI=
|
||||||
gopkg.in/ini.v1 v1.51.0 h1:AQvPpx3LzTDM0AjnIRlVFwFFGC+npRopjZxLJj6gdno=
|
gopkg.in/ini.v1 v1.51.0 h1:AQvPpx3LzTDM0AjnIRlVFwFFGC+npRopjZxLJj6gdno=
|
||||||
gopkg.in/ini.v1 v1.51.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k=
|
gopkg.in/ini.v1 v1.51.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k=
|
||||||
gopkg.in/ini.v1 v1.61.0 h1:LBCdW4FmFYL4s/vDZD1RQYX7oAR6IjujCYgMdbHBR10=
|
|
||||||
gopkg.in/ini.v1 v1.61.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k=
|
|
||||||
gopkg.in/resty.v1 v1.12.0/go.mod h1:mDo4pnntr5jdWRML875a/NmxYqAlA73dVijT2AXvQQo=
|
gopkg.in/resty.v1 v1.12.0/go.mod h1:mDo4pnntr5jdWRML875a/NmxYqAlA73dVijT2AXvQQo=
|
||||||
gopkg.in/yaml.v2 v2.0.0-20170812160011-eb3733d160e7/go.mod h1:JAlM8MvJe8wmxCU4Bli9HhUf9+ttbYbLASfIpnQbh74=
|
gopkg.in/yaml.v2 v2.0.0-20170812160011-eb3733d160e7/go.mod h1:JAlM8MvJe8wmxCU4Bli9HhUf9+ttbYbLASfIpnQbh74=
|
||||||
gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||||
|
@ -474,8 +466,6 @@ gopkg.in/yaml.v2 v2.2.4 h1:/eiJrUcujPVeJ3xlSWaiNi3uSVmDGBK1pDHUHAnao1I=
|
||||||
gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||||
gopkg.in/yaml.v2 v2.2.5 h1:ymVxjfMaHvXD8RqPRmzHHsB3VvucivSkIAvJFDI5O3c=
|
gopkg.in/yaml.v2 v2.2.5 h1:ymVxjfMaHvXD8RqPRmzHHsB3VvucivSkIAvJFDI5O3c=
|
||||||
gopkg.in/yaml.v2 v2.2.5/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
gopkg.in/yaml.v2 v2.2.5/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||||
gopkg.in/yaml.v2 v2.3.0 h1:clyUAQHOM3G0M3f5vQj7LuJrETvjVot3Z5el9nffUtU=
|
|
||||||
gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
|
||||||
gopkg.in/yaml.v3 v3.0.0-20200615113413-eeeca48fe776 h1:tQIYjPdBoyREyB9XMu+nnTclpTYkz2zFM+lzLJFO4gQ=
|
gopkg.in/yaml.v3 v3.0.0-20200615113413-eeeca48fe776 h1:tQIYjPdBoyREyB9XMu+nnTclpTYkz2zFM+lzLJFO4gQ=
|
||||||
gopkg.in/yaml.v3 v3.0.0-20200615113413-eeeca48fe776/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
gopkg.in/yaml.v3 v3.0.0-20200615113413-eeeca48fe776/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||||
honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
||||||
|
@ -485,5 +475,3 @@ honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWh
|
||||||
honnef.co/go/tools v0.0.1-2019.2.3 h1:3JgtbtFHMiCmsznwGVTUWbgGov+pVqnlf1dEJTNAXeM=
|
honnef.co/go/tools v0.0.1-2019.2.3 h1:3JgtbtFHMiCmsznwGVTUWbgGov+pVqnlf1dEJTNAXeM=
|
||||||
honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg=
|
honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg=
|
||||||
rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8=
|
rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8=
|
||||||
rsc.io/quote/v3 v3.1.0/go.mod h1:yEA65RcK8LyAZtP9Kv3t0HmxON59tX3rD+tICJqUlj0=
|
|
||||||
rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA=
|
|
||||||
|
|
167
internal/app/app.go
Normal file
167
internal/app/app.go
Normal file
|
@ -0,0 +1,167 @@
|
||||||
|
//go:generate mockgen -source=$GOFILE -destination=./mock/app.mock.go -package=mock
|
||||||
|
|
||||||
|
package app
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"os"
|
||||||
|
"os/signal"
|
||||||
|
"syscall"
|
||||||
|
|
||||||
|
"github.com/spf13/cobra"
|
||||||
|
"gitlab.com/inetmock/inetmock/internal/endpoints"
|
||||||
|
"gitlab.com/inetmock/inetmock/pkg/api"
|
||||||
|
"gitlab.com/inetmock/inetmock/pkg/cert"
|
||||||
|
"gitlab.com/inetmock/inetmock/pkg/config"
|
||||||
|
"gitlab.com/inetmock/inetmock/pkg/health"
|
||||||
|
"gitlab.com/inetmock/inetmock/pkg/logging"
|
||||||
|
"gitlab.com/inetmock/inetmock/pkg/path"
|
||||||
|
"go.uber.org/zap"
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
configFilePath string
|
||||||
|
logLevel string
|
||||||
|
developmentLogs bool
|
||||||
|
)
|
||||||
|
|
||||||
|
type App interface {
|
||||||
|
api.PluginContext
|
||||||
|
Config() config.Config
|
||||||
|
Checker() health.Checker
|
||||||
|
EndpointManager() endpoints.EndpointManager
|
||||||
|
HandlerRegistry() api.HandlerRegistry
|
||||||
|
Context() context.Context
|
||||||
|
MustRun()
|
||||||
|
Shutdown()
|
||||||
|
WithCommands(cmds ...*cobra.Command) App
|
||||||
|
}
|
||||||
|
|
||||||
|
type app struct {
|
||||||
|
cfg config.Config
|
||||||
|
rootCmd *cobra.Command
|
||||||
|
rootLogger logging.Logger
|
||||||
|
certStore cert.Store
|
||||||
|
checker health.Checker
|
||||||
|
endpointManager endpoints.EndpointManager
|
||||||
|
registry api.HandlerRegistry
|
||||||
|
ctx context.Context
|
||||||
|
cancel context.CancelFunc
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a *app) MustRun() {
|
||||||
|
if err := a.rootCmd.Execute(); err != nil {
|
||||||
|
if a.rootLogger != nil {
|
||||||
|
a.rootLogger.Error(
|
||||||
|
"Failed to run inetmock",
|
||||||
|
zap.Error(err),
|
||||||
|
)
|
||||||
|
} else {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a app) Logger() logging.Logger {
|
||||||
|
return a.rootLogger
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a app) Config() config.Config {
|
||||||
|
return a.cfg
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a app) CertStore() cert.Store {
|
||||||
|
return a.certStore
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a app) Checker() health.Checker {
|
||||||
|
return a.checker
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a app) EndpointManager() endpoints.EndpointManager {
|
||||||
|
return a.endpointManager
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a app) HandlerRegistry() api.HandlerRegistry {
|
||||||
|
return a.registry
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a app) Context() context.Context {
|
||||||
|
return a.ctx
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a app) Shutdown() {
|
||||||
|
a.cancel()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a *app) WithCommands(cmds ...*cobra.Command) App {
|
||||||
|
a.rootCmd.AddCommand(cmds...)
|
||||||
|
return a
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewApp(registrations ...api.Registration) (inetmockApp App, err error) {
|
||||||
|
registry := api.NewHandlerRegistry()
|
||||||
|
|
||||||
|
for _, registration := range registrations {
|
||||||
|
if err = registration(registry); err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ctx, cancel := initAppContext()
|
||||||
|
|
||||||
|
a := &app{
|
||||||
|
rootCmd: &cobra.Command{
|
||||||
|
Short: "INetMock is lightweight internet mock",
|
||||||
|
},
|
||||||
|
checker: health.New(),
|
||||||
|
registry: registry,
|
||||||
|
ctx: ctx,
|
||||||
|
cancel: cancel,
|
||||||
|
}
|
||||||
|
|
||||||
|
a.rootCmd.PersistentFlags().StringVar(&configFilePath, "config", "", "Path to config file that should be used")
|
||||||
|
a.rootCmd.PersistentFlags().StringVar(&logLevel, "log-level", "info", "logging level to use")
|
||||||
|
a.rootCmd.PersistentFlags().BoolVar(&developmentLogs, "development-logs", false, "Enable development mode logs")
|
||||||
|
|
||||||
|
a.rootCmd.PersistentPreRunE = func(cmd *cobra.Command, args []string) (err error) {
|
||||||
|
logging.ConfigureLogging(
|
||||||
|
logging.ParseLevel(logLevel),
|
||||||
|
developmentLogs,
|
||||||
|
map[string]interface{}{
|
||||||
|
"cwd": path.WorkingDirectory(),
|
||||||
|
},
|
||||||
|
)
|
||||||
|
|
||||||
|
if a.rootLogger, err = logging.CreateLogger(); err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
a.cfg = config.CreateConfig(cmd.Flags())
|
||||||
|
|
||||||
|
if err = a.cfg.ReadConfig(configFilePath); err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
a.certStore, err = cert.NewDefaultStore(a.cfg, a.rootLogger)
|
||||||
|
a.endpointManager = endpoints.NewEndpointManager(a.registry, a.Logger().Named("EndpointManager"), a.checker, a)
|
||||||
|
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
return a, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func initAppContext() (context.Context, context.CancelFunc) {
|
||||||
|
ctx, cancel := context.WithCancel(context.Background())
|
||||||
|
|
||||||
|
signals := make(chan os.Signal, 1)
|
||||||
|
signal.Notify(signals, syscall.SIGINT, syscall.SIGTERM, syscall.SIGQUIT)
|
||||||
|
|
||||||
|
go func() {
|
||||||
|
<-signals
|
||||||
|
cancel()
|
||||||
|
}()
|
||||||
|
|
||||||
|
return ctx, cancel
|
||||||
|
}
|
|
@ -3,12 +3,13 @@ package cmd
|
||||||
import (
|
import (
|
||||||
"crypto/tls"
|
"crypto/tls"
|
||||||
"crypto/x509"
|
"crypto/x509"
|
||||||
"github.com/baez90/inetmock/pkg/cert"
|
|
||||||
"github.com/baez90/inetmock/pkg/config"
|
|
||||||
"github.com/baez90/inetmock/pkg/logging"
|
|
||||||
"github.com/spf13/cobra"
|
|
||||||
"go.uber.org/zap"
|
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
"github.com/spf13/cobra"
|
||||||
|
"gitlab.com/inetmock/inetmock/pkg/cert"
|
||||||
|
"gitlab.com/inetmock/inetmock/pkg/config"
|
||||||
|
"gitlab.com/inetmock/inetmock/pkg/logging"
|
||||||
|
"go.uber.org/zap"
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
|
@ -58,6 +59,8 @@ func runGenerateCA(_ *cobra.Command, _ []string) {
|
||||||
var notBefore, notAfter time.Duration
|
var notBefore, notAfter time.Duration
|
||||||
var err error
|
var err error
|
||||||
|
|
||||||
|
logger := server.Logger().Named("generate-ca")
|
||||||
|
|
||||||
if certOutPath, err = getStringFlag(generateCaCmd, generateCACertOutPath, logger); err != nil {
|
if certOutPath, err = getStringFlag(generateCaCmd, generateCACertOutPath, logger); err != nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
@ -71,8 +74,6 @@ func runGenerateCA(_ *cobra.Command, _ []string) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
logger, _ := logging.CreateLogger()
|
|
||||||
|
|
||||||
logger = logger.With(
|
logger = logger.With(
|
||||||
zap.String(generateCACurveName, curveName),
|
zap.String(generateCACurveName, curveName),
|
||||||
zap.String(generateCACertOutPath, certOutPath),
|
zap.String(generateCACertOutPath, certOutPath),
|
||||||
|
|
|
@ -1,8 +1,9 @@
|
||||||
package cmd
|
package cmd
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"github.com/spf13/cobra"
|
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
"github.com/spf13/cobra"
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
|
|
|
@ -3,11 +3,12 @@ package cmd
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"fmt"
|
"fmt"
|
||||||
"github.com/baez90/inetmock/internal/format"
|
|
||||||
"github.com/baez90/inetmock/internal/rpc"
|
|
||||||
"github.com/spf13/cobra"
|
|
||||||
"google.golang.org/grpc"
|
|
||||||
"os"
|
"os"
|
||||||
|
|
||||||
|
"github.com/spf13/cobra"
|
||||||
|
"gitlab.com/inetmock/inetmock/internal/format"
|
||||||
|
"gitlab.com/inetmock/inetmock/internal/rpc"
|
||||||
|
"google.golang.org/grpc"
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
|
|
|
@ -3,11 +3,12 @@ package cmd
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"fmt"
|
"fmt"
|
||||||
"github.com/baez90/inetmock/internal/format"
|
|
||||||
"github.com/baez90/inetmock/internal/rpc"
|
|
||||||
"github.com/spf13/cobra"
|
|
||||||
"google.golang.org/grpc"
|
|
||||||
"os"
|
"os"
|
||||||
|
|
||||||
|
"github.com/spf13/cobra"
|
||||||
|
"gitlab.com/inetmock/inetmock/internal/format"
|
||||||
|
"gitlab.com/inetmock/inetmock/internal/rpc"
|
||||||
|
"google.golang.org/grpc"
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
|
|
|
@ -3,11 +3,12 @@ package cmd
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"fmt"
|
"fmt"
|
||||||
"github.com/baez90/inetmock/internal/format"
|
|
||||||
"github.com/baez90/inetmock/internal/rpc"
|
|
||||||
"github.com/spf13/cobra"
|
|
||||||
"google.golang.org/grpc"
|
|
||||||
"os"
|
"os"
|
||||||
|
|
||||||
|
"github.com/spf13/cobra"
|
||||||
|
"gitlab.com/inetmock/inetmock/internal/format"
|
||||||
|
"gitlab.com/inetmock/inetmock/internal/rpc"
|
||||||
|
"google.golang.org/grpc"
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
|
|
|
@ -1,23 +1,15 @@
|
||||||
package cmd
|
package cmd
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"github.com/baez90/inetmock/internal/endpoints"
|
|
||||||
"github.com/baez90/inetmock/internal/rpc"
|
|
||||||
"github.com/baez90/inetmock/pkg/api"
|
|
||||||
"github.com/baez90/inetmock/pkg/config"
|
|
||||||
"github.com/baez90/inetmock/pkg/health"
|
|
||||||
"github.com/baez90/inetmock/pkg/logging"
|
|
||||||
"github.com/baez90/inetmock/pkg/path"
|
|
||||||
"github.com/spf13/cobra"
|
|
||||||
"go.uber.org/zap"
|
|
||||||
"os"
|
|
||||||
"os/signal"
|
|
||||||
"strings"
|
"strings"
|
||||||
"syscall"
|
|
||||||
|
"github.com/spf13/cobra"
|
||||||
|
"gitlab.com/inetmock/inetmock/internal/rpc"
|
||||||
|
"gitlab.com/inetmock/inetmock/pkg/config"
|
||||||
|
"go.uber.org/zap"
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
endpointManager endpoints.EndpointManager
|
|
||||||
serveCmd = &cobra.Command{
|
serveCmd = &cobra.Command{
|
||||||
Use: "serve",
|
Use: "serve",
|
||||||
Short: "Starts the INetMock server",
|
Short: "Starts the INetMock server",
|
||||||
|
@ -26,51 +18,14 @@ var (
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
func onServerInit() (err error) {
|
|
||||||
logging.ConfigureLogging(
|
|
||||||
logging.ParseLevel(logLevel),
|
|
||||||
developmentLogs,
|
|
||||||
map[string]interface{}{"cwd": path.WorkingDirectory()},
|
|
||||||
)
|
|
||||||
|
|
||||||
logger, _ = logging.CreateLogger()
|
|
||||||
config.CreateConfig(serverCmd.Flags())
|
|
||||||
appConfig := config.Instance()
|
|
||||||
|
|
||||||
if err = appConfig.ReadConfig(configFilePath); err != nil {
|
|
||||||
logger.Error(
|
|
||||||
"failed to read config file",
|
|
||||||
zap.Error(err),
|
|
||||||
)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
if err = api.InitServices(appConfig, logger); err != nil {
|
|
||||||
logger.Error(
|
|
||||||
"failed to initialize app services",
|
|
||||||
zap.Error(err),
|
|
||||||
)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func startINetMock(_ *cobra.Command, _ []string) {
|
func startINetMock(_ *cobra.Command, _ []string) {
|
||||||
if err := onServerInit(); err != nil {
|
rpcAPI := rpc.NewINetMockAPI(server)
|
||||||
panic(err)
|
logger := server.Logger().Named("inetmock").With(zap.String("command", "serve"))
|
||||||
}
|
|
||||||
endpointManager = endpoints.NewEndpointManager(health.CheckerInstance(), logger)
|
|
||||||
cfg := config.Instance()
|
|
||||||
rpcAPI := rpc.NewINetMockAPI(
|
|
||||||
cfg,
|
|
||||||
endpointManager,
|
|
||||||
api.Registry(),
|
|
||||||
)
|
|
||||||
|
|
||||||
for endpointName, endpointHandler := range cfg.EndpointConfigs() {
|
for endpointName, endpointHandler := range server.Config().EndpointConfigs() {
|
||||||
handlerSubConfig := cfg.Viper().Sub(strings.Join([]string{config.EndpointsKey, endpointName, config.OptionsKey}, "."))
|
handlerSubConfig := server.Config().Viper().Sub(strings.Join([]string{config.EndpointsKey, endpointName, config.OptionsKey}, "."))
|
||||||
endpointHandler.Options = handlerSubConfig
|
endpointHandler.Options = handlerSubConfig
|
||||||
if err := endpointManager.CreateEndpoint(endpointName, endpointHandler); err != nil {
|
if err := server.EndpointManager().CreateEndpoint(endpointName, endpointHandler); err != nil {
|
||||||
logger.Warn(
|
logger.Warn(
|
||||||
"error occurred while creating endpoint",
|
"error occurred while creating endpoint",
|
||||||
zap.String("endpointName", endpointName),
|
zap.String("endpointName", endpointName),
|
||||||
|
@ -80,7 +35,7 @@ func startINetMock(_ *cobra.Command, _ []string) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
endpointManager.StartEndpoints()
|
server.EndpointManager().StartEndpoints()
|
||||||
if err := rpcAPI.StartServer(); err != nil {
|
if err := rpcAPI.StartServer(); err != nil {
|
||||||
logger.Error(
|
logger.Error(
|
||||||
"failed to start gRPC API",
|
"failed to start gRPC API",
|
||||||
|
@ -88,17 +43,12 @@ func startINetMock(_ *cobra.Command, _ []string) {
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
signalChannel := make(chan os.Signal, 1)
|
<-server.Context().Done()
|
||||||
signal.Notify(signalChannel, syscall.SIGINT, syscall.SIGTERM, syscall.SIGQUIT)
|
|
||||||
|
|
||||||
// block until canceled
|
|
||||||
s := <-signalChannel
|
|
||||||
|
|
||||||
logger.Info(
|
logger.Info(
|
||||||
"got signal to quit",
|
"App context canceled - shutting down",
|
||||||
zap.String("signal", s.String()),
|
|
||||||
)
|
)
|
||||||
|
|
||||||
rpcAPI.StopServer()
|
rpcAPI.StopServer()
|
||||||
endpointManager.ShutdownEndpoints()
|
server.EndpointManager().ShutdownEndpoints()
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,35 +1,34 @@
|
||||||
package cmd
|
package cmd
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"github.com/baez90/inetmock/pkg/logging"
|
"fmt"
|
||||||
"github.com/spf13/cobra"
|
"os"
|
||||||
|
|
||||||
|
"gitlab.com/inetmock/inetmock/internal/app"
|
||||||
|
"gitlab.com/inetmock/inetmock/plugins/dns_mock"
|
||||||
|
"gitlab.com/inetmock/inetmock/plugins/http_mock"
|
||||||
|
"gitlab.com/inetmock/inetmock/plugins/http_proxy"
|
||||||
|
"gitlab.com/inetmock/inetmock/plugins/metrics_exporter"
|
||||||
|
"gitlab.com/inetmock/inetmock/plugins/tls_interceptor"
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
logger logging.Logger
|
server app.App
|
||||||
serverCmd *cobra.Command
|
|
||||||
|
|
||||||
configFilePath string
|
|
||||||
logLevel string
|
|
||||||
developmentLogs bool
|
|
||||||
)
|
)
|
||||||
|
|
||||||
func init() {
|
func ExecuteServerCommand() {
|
||||||
serverCmd = &cobra.Command{
|
var err error
|
||||||
Use: "",
|
if server, err = app.NewApp(
|
||||||
Short: "INetMock is lightweight internet mock",
|
http_mock.AddHTTPMock,
|
||||||
|
dns_mock.AddDNSMock,
|
||||||
|
tls_interceptor.AddTLSInterceptor,
|
||||||
|
http_proxy.AddHTTPProxy,
|
||||||
|
metrics_exporter.AddMetricsExporter,
|
||||||
|
); err != nil {
|
||||||
|
fmt.Println(err.Error())
|
||||||
|
os.Exit(1)
|
||||||
}
|
}
|
||||||
|
server.
|
||||||
serverCmd.PersistentFlags().StringVar(&configFilePath, "config", "", "Path to config file that should be used")
|
WithCommands(serveCmd, generateCaCmd).
|
||||||
serverCmd.PersistentFlags().StringVar(&logLevel, "log-level", "info", "logging level to use")
|
MustRun()
|
||||||
serverCmd.PersistentFlags().BoolVar(&developmentLogs, "development-logs", false, "Enable development mode logs")
|
|
||||||
|
|
||||||
serverCmd.AddCommand(
|
|
||||||
serveCmd,
|
|
||||||
generateCaCmd,
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
func ExecuteServerCommand() error {
|
|
||||||
return serverCmd.Execute()
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,14 +3,15 @@ package endpoints
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"github.com/baez90/inetmock/pkg/api"
|
|
||||||
"github.com/baez90/inetmock/pkg/config"
|
|
||||||
"github.com/google/uuid"
|
"github.com/google/uuid"
|
||||||
|
"gitlab.com/inetmock/inetmock/pkg/api"
|
||||||
|
"gitlab.com/inetmock/inetmock/pkg/config"
|
||||||
)
|
)
|
||||||
|
|
||||||
type Endpoint interface {
|
type Endpoint interface {
|
||||||
Id() uuid.UUID
|
Id() uuid.UUID
|
||||||
Start() error
|
Start(ctx api.PluginContext) error
|
||||||
Shutdown(ctx context.Context) error
|
Shutdown(ctx context.Context) error
|
||||||
Name() string
|
Name() string
|
||||||
Handler() string
|
Handler() string
|
||||||
|
@ -45,8 +46,8 @@ func (e endpoint) Port() uint16 {
|
||||||
return e.config.Port
|
return e.config.Port
|
||||||
}
|
}
|
||||||
|
|
||||||
func (e *endpoint) Start() (err error) {
|
func (e *endpoint) Start(ctx api.PluginContext) (err error) {
|
||||||
return e.handler.Start(e.config)
|
return e.handler.Start(ctx, e.config)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (e *endpoint) Shutdown(ctx context.Context) (err error) {
|
func (e *endpoint) Shutdown(ctx context.Context) (err error) {
|
||||||
|
|
|
@ -3,14 +3,15 @@ package endpoints
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"fmt"
|
"fmt"
|
||||||
"github.com/baez90/inetmock/pkg/api"
|
|
||||||
"github.com/baez90/inetmock/pkg/config"
|
|
||||||
"github.com/baez90/inetmock/pkg/health"
|
|
||||||
"github.com/baez90/inetmock/pkg/logging"
|
|
||||||
"github.com/google/uuid"
|
|
||||||
"go.uber.org/zap"
|
|
||||||
"sync"
|
"sync"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
"github.com/google/uuid"
|
||||||
|
"gitlab.com/inetmock/inetmock/pkg/api"
|
||||||
|
"gitlab.com/inetmock/inetmock/pkg/config"
|
||||||
|
"gitlab.com/inetmock/inetmock/pkg/health"
|
||||||
|
"gitlab.com/inetmock/inetmock/pkg/logging"
|
||||||
|
"go.uber.org/zap"
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
|
@ -20,25 +21,27 @@ const (
|
||||||
type EndpointManager interface {
|
type EndpointManager interface {
|
||||||
RegisteredEndpoints() []Endpoint
|
RegisteredEndpoints() []Endpoint
|
||||||
StartedEndpoints() []Endpoint
|
StartedEndpoints() []Endpoint
|
||||||
CreateEndpoint(name string, multiHandlerConfig config.MultiHandlerConfig) error
|
CreateEndpoint(name string, multiHandlerConfig config.EndpointConfig) error
|
||||||
StartEndpoints()
|
StartEndpoints()
|
||||||
ShutdownEndpoints()
|
ShutdownEndpoints()
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewEndpointManager(checker health.Checker, logger logging.Logger) EndpointManager {
|
func NewEndpointManager(registry api.HandlerRegistry, logging logging.Logger, checker health.Checker, pluginContext api.PluginContext) EndpointManager {
|
||||||
return &endpointManager{
|
return &endpointManager{
|
||||||
logger: logger,
|
registry: registry,
|
||||||
|
logger: logging,
|
||||||
checker: checker,
|
checker: checker,
|
||||||
registry: api.Registry(),
|
pluginContext: pluginContext,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
type endpointManager struct {
|
type endpointManager struct {
|
||||||
|
registry api.HandlerRegistry
|
||||||
logger logging.Logger
|
logger logging.Logger
|
||||||
checker health.Checker
|
checker health.Checker
|
||||||
|
pluginContext api.PluginContext
|
||||||
registeredEndpoints []Endpoint
|
registeredEndpoints []Endpoint
|
||||||
properlyStartedEndpoints []Endpoint
|
properlyStartedEndpoints []Endpoint
|
||||||
registry api.HandlerRegistry
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (e endpointManager) RegisteredEndpoints() []Endpoint {
|
func (e endpointManager) RegisteredEndpoints() []Endpoint {
|
||||||
|
@ -49,9 +52,9 @@ func (e endpointManager) StartedEndpoints() []Endpoint {
|
||||||
return e.properlyStartedEndpoints
|
return e.properlyStartedEndpoints
|
||||||
}
|
}
|
||||||
|
|
||||||
func (e *endpointManager) CreateEndpoint(name string, multiHandlerConfig config.MultiHandlerConfig) error {
|
func (e *endpointManager) CreateEndpoint(name string, endpointConfig config.EndpointConfig) error {
|
||||||
for _, handlerConfig := range multiHandlerConfig.HandlerConfigs() {
|
for _, handlerConfig := range endpointConfig.HandlerConfigs() {
|
||||||
if handler, ok := e.registry.HandlerForName(multiHandlerConfig.Handler); ok {
|
if handler, ok := e.registry.HandlerForName(endpointConfig.Handler); ok {
|
||||||
e.registeredEndpoints = append(e.registeredEndpoints, &endpoint{
|
e.registeredEndpoints = append(e.registeredEndpoints, &endpoint{
|
||||||
id: uuid.New(),
|
id: uuid.New(),
|
||||||
name: name,
|
name: name,
|
||||||
|
@ -59,7 +62,7 @@ func (e *endpointManager) CreateEndpoint(name string, multiHandlerConfig config.
|
||||||
config: handlerConfig,
|
config: handlerConfig,
|
||||||
})
|
})
|
||||||
} else {
|
} else {
|
||||||
return fmt.Errorf("no matching handler registered for names %s", multiHandlerConfig.Handler)
|
return fmt.Errorf("no matching handler registered for names %s", endpointConfig.Handler)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -73,7 +76,7 @@ func (e *endpointManager) StartEndpoints() {
|
||||||
zap.String("endpoint", endpoint.Name()),
|
zap.String("endpoint", endpoint.Name()),
|
||||||
)
|
)
|
||||||
endpointLogger.Info("Starting endpoint")
|
endpointLogger.Info("Starting endpoint")
|
||||||
if ok := startEndpoint(endpoint, endpointLogger); ok {
|
if ok := startEndpoint(endpoint, e.pluginContext, endpointLogger); ok {
|
||||||
_ = e.checker.RegisterCheck(
|
_ = e.checker.RegisterCheck(
|
||||||
endpointComponentName(endpoint),
|
endpointComponentName(endpoint),
|
||||||
health.StaticResultCheckWithMessage(health.HEALTHY, "Successfully started"),
|
health.StaticResultCheckWithMessage(health.HEALTHY, "Successfully started"),
|
||||||
|
@ -115,7 +118,7 @@ func (e *endpointManager) ShutdownEndpoints() {
|
||||||
waitGroup.Wait()
|
waitGroup.Wait()
|
||||||
}
|
}
|
||||||
|
|
||||||
func startEndpoint(ep Endpoint, logger logging.Logger) (success bool) {
|
func startEndpoint(ep Endpoint, ctx api.PluginContext, logger logging.Logger) (success bool) {
|
||||||
startSuccessful := make(chan bool)
|
startSuccessful := make(chan bool)
|
||||||
|
|
||||||
go func() {
|
go func() {
|
||||||
|
@ -129,7 +132,7 @@ func startEndpoint(ep Endpoint, logger logging.Logger) (success bool) {
|
||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
|
|
||||||
if err := ep.Start(); err != nil {
|
if err := ep.Start(ctx); err != nil {
|
||||||
logger.Error(
|
logger.Error(
|
||||||
"failed to start endpoint",
|
"failed to start endpoint",
|
||||||
zap.Error(err),
|
zap.Error(err),
|
||||||
|
@ -146,6 +149,8 @@ func startEndpoint(ep Endpoint, logger logging.Logger) (success bool) {
|
||||||
success = false
|
success = false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
close(startSuccessful)
|
||||||
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,27 +1,27 @@
|
||||||
package endpoints
|
package endpoints
|
||||||
|
|
||||||
import (
|
import (
|
||||||
api_mock "github.com/baez90/inetmock/internal/mock/api"
|
|
||||||
logging_mock "github.com/baez90/inetmock/internal/mock/logging"
|
|
||||||
plugins_mock "github.com/baez90/inetmock/internal/mock/plugins"
|
|
||||||
"github.com/baez90/inetmock/pkg/api"
|
|
||||||
"github.com/baez90/inetmock/pkg/config"
|
|
||||||
"github.com/baez90/inetmock/pkg/logging"
|
|
||||||
"github.com/golang/mock/gomock"
|
|
||||||
"reflect"
|
"reflect"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
|
"github.com/golang/mock/gomock"
|
||||||
|
api_mock "gitlab.com/inetmock/inetmock/internal/mock/api"
|
||||||
|
logging_mock "gitlab.com/inetmock/inetmock/internal/mock/logging"
|
||||||
|
plugins_mock "gitlab.com/inetmock/inetmock/internal/mock/plugins"
|
||||||
|
"gitlab.com/inetmock/inetmock/pkg/api"
|
||||||
|
"gitlab.com/inetmock/inetmock/pkg/config"
|
||||||
|
"gitlab.com/inetmock/inetmock/pkg/health"
|
||||||
|
"gitlab.com/inetmock/inetmock/pkg/logging"
|
||||||
)
|
)
|
||||||
|
|
||||||
func Test_endpointManager_CreateEndpoint(t *testing.T) {
|
func Test_endpointManager_CreateEndpoint(t *testing.T) {
|
||||||
type fields struct {
|
type fields struct {
|
||||||
logger logging.Logger
|
logger logging.Logger
|
||||||
registeredEndpoints []Endpoint
|
|
||||||
properlyStartedEndpoints []Endpoint
|
|
||||||
registry api.HandlerRegistry
|
registry api.HandlerRegistry
|
||||||
}
|
}
|
||||||
type args struct {
|
type args struct {
|
||||||
name string
|
name string
|
||||||
multiHandlerConfig config.MultiHandlerConfig
|
multiHandlerConfig config.EndpointConfig
|
||||||
}
|
}
|
||||||
tests := []struct {
|
tests := []struct {
|
||||||
name string
|
name string
|
||||||
|
@ -38,8 +38,6 @@ func Test_endpointManager_CreateEndpoint(t *testing.T) {
|
||||||
logger: func() logging.Logger {
|
logger: func() logging.Logger {
|
||||||
return logging_mock.NewMockLogger(gomock.NewController(t))
|
return logging_mock.NewMockLogger(gomock.NewController(t))
|
||||||
}(),
|
}(),
|
||||||
registeredEndpoints: nil,
|
|
||||||
properlyStartedEndpoints: nil,
|
|
||||||
registry: func() api.HandlerRegistry {
|
registry: func() api.HandlerRegistry {
|
||||||
registry := plugins_mock.NewMockHandlerRegistry(gomock.NewController(t))
|
registry := plugins_mock.NewMockHandlerRegistry(gomock.NewController(t))
|
||||||
registry.
|
registry.
|
||||||
|
@ -53,7 +51,7 @@ func Test_endpointManager_CreateEndpoint(t *testing.T) {
|
||||||
},
|
},
|
||||||
args: args{
|
args: args{
|
||||||
name: "sampleEndpoint",
|
name: "sampleEndpoint",
|
||||||
multiHandlerConfig: config.MultiHandlerConfig{
|
multiHandlerConfig: config.EndpointConfig{
|
||||||
Handler: "sampleHandler",
|
Handler: "sampleHandler",
|
||||||
Ports: []uint16{80},
|
Ports: []uint16{80},
|
||||||
ListenAddress: "0.0.0.0",
|
ListenAddress: "0.0.0.0",
|
||||||
|
@ -68,8 +66,6 @@ func Test_endpointManager_CreateEndpoint(t *testing.T) {
|
||||||
logger: func() logging.Logger {
|
logger: func() logging.Logger {
|
||||||
return logging_mock.NewMockLogger(gomock.NewController(t))
|
return logging_mock.NewMockLogger(gomock.NewController(t))
|
||||||
}(),
|
}(),
|
||||||
registeredEndpoints: nil,
|
|
||||||
properlyStartedEndpoints: nil,
|
|
||||||
registry: func() api.HandlerRegistry {
|
registry: func() api.HandlerRegistry {
|
||||||
registry := plugins_mock.NewMockHandlerRegistry(gomock.NewController(t))
|
registry := plugins_mock.NewMockHandlerRegistry(gomock.NewController(t))
|
||||||
registry.
|
registry.
|
||||||
|
@ -83,7 +79,7 @@ func Test_endpointManager_CreateEndpoint(t *testing.T) {
|
||||||
},
|
},
|
||||||
args: args{
|
args: args{
|
||||||
name: "sampleEndpoint",
|
name: "sampleEndpoint",
|
||||||
multiHandlerConfig: config.MultiHandlerConfig{
|
multiHandlerConfig: config.EndpointConfig{
|
||||||
Handler: "sampleHandler",
|
Handler: "sampleHandler",
|
||||||
Ports: []uint16{80},
|
Ports: []uint16{80},
|
||||||
ListenAddress: "0.0.0.0",
|
ListenAddress: "0.0.0.0",
|
||||||
|
@ -93,13 +89,7 @@ func Test_endpointManager_CreateEndpoint(t *testing.T) {
|
||||||
}
|
}
|
||||||
for _, tt := range tests {
|
for _, tt := range tests {
|
||||||
t.Run(tt.name, func(t *testing.T) {
|
t.Run(tt.name, func(t *testing.T) {
|
||||||
e := &endpointManager{
|
e := NewEndpointManager(tt.fields.registry, tt.fields.logger, health.New(), nil)
|
||||||
logger: tt.fields.logger,
|
|
||||||
registeredEndpoints: tt.fields.registeredEndpoints,
|
|
||||||
properlyStartedEndpoints: tt.fields.properlyStartedEndpoints,
|
|
||||||
registry: tt.fields.registry,
|
|
||||||
}
|
|
||||||
|
|
||||||
if err := e.CreateEndpoint(tt.args.name, tt.args.multiHandlerConfig); (err != nil) != tt.wantErr {
|
if err := e.CreateEndpoint(tt.args.name, tt.args.multiHandlerConfig); (err != nil) != tt.wantErr {
|
||||||
t.Errorf("CreateEndpoint() error = %v, wantErr %v", err, tt.wantErr)
|
t.Errorf("CreateEndpoint() error = %v, wantErr %v", err, tt.wantErr)
|
||||||
}
|
}
|
||||||
|
@ -140,7 +130,6 @@ func Test_endpointManager_StartedEndpoints(t *testing.T) {
|
||||||
logger: tt.fields.logger,
|
logger: tt.fields.logger,
|
||||||
registeredEndpoints: tt.fields.registeredEndpoints,
|
registeredEndpoints: tt.fields.registeredEndpoints,
|
||||||
properlyStartedEndpoints: tt.fields.properlyStartedEndpoints,
|
properlyStartedEndpoints: tt.fields.properlyStartedEndpoints,
|
||||||
registry: tt.fields.registry,
|
|
||||||
}
|
}
|
||||||
if got := e.StartedEndpoints(); !reflect.DeepEqual(got, tt.want) {
|
if got := e.StartedEndpoints(); !reflect.DeepEqual(got, tt.want) {
|
||||||
t.Errorf("StartedEndpoints() = %v, want %v", got, tt.want)
|
t.Errorf("StartedEndpoints() = %v, want %v", got, tt.want)
|
||||||
|
|
|
@ -1,184 +0,0 @@
|
||||||
package endpoints
|
|
||||||
|
|
||||||
import (
|
|
||||||
"context"
|
|
||||||
"fmt"
|
|
||||||
apimock "github.com/baez90/inetmock/internal/mock/api"
|
|
||||||
"github.com/baez90/inetmock/pkg/api"
|
|
||||||
"github.com/baez90/inetmock/pkg/config"
|
|
||||||
"github.com/golang/mock/gomock"
|
|
||||||
"reflect"
|
|
||||||
"testing"
|
|
||||||
)
|
|
||||||
|
|
||||||
var (
|
|
||||||
anyContext = context.Background()
|
|
||||||
)
|
|
||||||
|
|
||||||
func Test_endpoint_Name(t *testing.T) {
|
|
||||||
type fields struct {
|
|
||||||
name string
|
|
||||||
handler api.ProtocolHandler
|
|
||||||
config config.HandlerConfig
|
|
||||||
}
|
|
||||||
tests := []struct {
|
|
||||||
name string
|
|
||||||
fields fields
|
|
||||||
want string
|
|
||||||
}{
|
|
||||||
{
|
|
||||||
name: "Empty Name if struct is uninitialized",
|
|
||||||
fields: fields{},
|
|
||||||
want: "",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: "Expected Name if struct is initialized",
|
|
||||||
fields: fields{
|
|
||||||
name: "sampleHandler",
|
|
||||||
},
|
|
||||||
want: "sampleHandler",
|
|
||||||
},
|
|
||||||
}
|
|
||||||
for _, tt := range tests {
|
|
||||||
t.Run(tt.name, func(t *testing.T) {
|
|
||||||
e := endpoint{
|
|
||||||
name: tt.fields.name,
|
|
||||||
handler: tt.fields.handler,
|
|
||||||
config: tt.fields.config,
|
|
||||||
}
|
|
||||||
if got := e.Name(); got != tt.want {
|
|
||||||
t.Errorf("Name() = %v, want %v", got, tt.want)
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func Test_endpoint_Shutdown(t *testing.T) {
|
|
||||||
type fields struct {
|
|
||||||
name string
|
|
||||||
handler api.ProtocolHandler
|
|
||||||
config config.HandlerConfig
|
|
||||||
}
|
|
||||||
tests := []struct {
|
|
||||||
name string
|
|
||||||
fields fields
|
|
||||||
wantErr bool
|
|
||||||
}{
|
|
||||||
{
|
|
||||||
name: "Expect no error if mocked handler does not return one",
|
|
||||||
fields: fields{
|
|
||||||
handler: func() api.ProtocolHandler {
|
|
||||||
handler := apimock.NewMockProtocolHandler(gomock.NewController(t))
|
|
||||||
handler.EXPECT().
|
|
||||||
Shutdown(gomock.Any()).
|
|
||||||
MaxTimes(1).
|
|
||||||
Return(nil)
|
|
||||||
return handler
|
|
||||||
}(),
|
|
||||||
},
|
|
||||||
wantErr: false,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: "Expect error if mocked handler returns one",
|
|
||||||
fields: fields{
|
|
||||||
handler: func() api.ProtocolHandler {
|
|
||||||
handler := apimock.NewMockProtocolHandler(gomock.NewController(t))
|
|
||||||
handler.EXPECT().
|
|
||||||
Shutdown(gomock.AssignableToTypeOf(reflect.TypeOf(context.Background()))).
|
|
||||||
MaxTimes(1).
|
|
||||||
Return(fmt.Errorf(""))
|
|
||||||
return handler
|
|
||||||
}(),
|
|
||||||
},
|
|
||||||
wantErr: true,
|
|
||||||
},
|
|
||||||
}
|
|
||||||
for _, tt := range tests {
|
|
||||||
t.Run(tt.name, func(t *testing.T) {
|
|
||||||
e := &endpoint{
|
|
||||||
name: tt.fields.name,
|
|
||||||
handler: tt.fields.handler,
|
|
||||||
config: tt.fields.config,
|
|
||||||
}
|
|
||||||
if err := e.Shutdown(context.Background()); (err != nil) != tt.wantErr {
|
|
||||||
t.Errorf("Shutdown() error = %v, wantErr %v", err, tt.wantErr)
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func Test_endpoint_Start(t *testing.T) {
|
|
||||||
|
|
||||||
demoHandlerConfig := config.HandlerConfig{
|
|
||||||
HandlerName: "sampleHandler",
|
|
||||||
Port: 80,
|
|
||||||
ListenAddress: "0.0.0.0",
|
|
||||||
}
|
|
||||||
|
|
||||||
type fields struct {
|
|
||||||
name string
|
|
||||||
handler api.ProtocolHandler
|
|
||||||
config config.HandlerConfig
|
|
||||||
}
|
|
||||||
tests := []struct {
|
|
||||||
name string
|
|
||||||
fields fields
|
|
||||||
wantErr bool
|
|
||||||
}{
|
|
||||||
{
|
|
||||||
name: "Expect no error if mocked handler does not return one",
|
|
||||||
fields: fields{
|
|
||||||
handler: func() api.ProtocolHandler {
|
|
||||||
handler := apimock.NewMockProtocolHandler(gomock.NewController(t))
|
|
||||||
handler.EXPECT().
|
|
||||||
Start(gomock.Any()).
|
|
||||||
MaxTimes(1).
|
|
||||||
Return(nil)
|
|
||||||
return handler
|
|
||||||
}(),
|
|
||||||
},
|
|
||||||
wantErr: false,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: "Expect error if mocked handler returns one",
|
|
||||||
fields: fields{
|
|
||||||
handler: func() api.ProtocolHandler {
|
|
||||||
handler := apimock.NewMockProtocolHandler(gomock.NewController(t))
|
|
||||||
handler.EXPECT().
|
|
||||||
Start(gomock.Any()).
|
|
||||||
MaxTimes(1).
|
|
||||||
Return(fmt.Errorf(""))
|
|
||||||
return handler
|
|
||||||
}(),
|
|
||||||
},
|
|
||||||
wantErr: true,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: "Expect config to be passed to Start call",
|
|
||||||
fields: fields{
|
|
||||||
config: demoHandlerConfig,
|
|
||||||
handler: func() api.ProtocolHandler {
|
|
||||||
handler := apimock.NewMockProtocolHandler(gomock.NewController(t))
|
|
||||||
handler.EXPECT().
|
|
||||||
Start(demoHandlerConfig).
|
|
||||||
MaxTimes(1).
|
|
||||||
Return(fmt.Errorf(""))
|
|
||||||
return handler
|
|
||||||
}(),
|
|
||||||
},
|
|
||||||
wantErr: true,
|
|
||||||
},
|
|
||||||
}
|
|
||||||
for _, tt := range tests {
|
|
||||||
t.Run(tt.name, func(t *testing.T) {
|
|
||||||
e := &endpoint{
|
|
||||||
name: tt.fields.name,
|
|
||||||
handler: tt.fields.handler,
|
|
||||||
config: tt.fields.config,
|
|
||||||
}
|
|
||||||
if err := e.Start(); (err != nil) != tt.wantErr {
|
|
||||||
t.Errorf("Start() error = %v, wantErr %v", err, tt.wantErr)
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -2,10 +2,11 @@ package format
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"github.com/olekukonko/tablewriter"
|
|
||||||
"gopkg.in/yaml.v3"
|
|
||||||
"io"
|
"io"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
|
"github.com/olekukonko/tablewriter"
|
||||||
|
"gopkg.in/yaml.v3"
|
||||||
)
|
)
|
||||||
|
|
||||||
type consoleWriterFactory func(io.Writer) ConsoleWriter
|
type consoleWriterFactory func(io.Writer) ConsoleWriter
|
||||||
|
|
|
@ -3,9 +3,10 @@ package format
|
||||||
import (
|
import (
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"github.com/olekukonko/tablewriter"
|
|
||||||
"reflect"
|
"reflect"
|
||||||
"strconv"
|
"strconv"
|
||||||
|
|
||||||
|
"github.com/olekukonko/tablewriter"
|
||||||
)
|
)
|
||||||
|
|
||||||
type tblWriter struct {
|
type tblWriter struct {
|
||||||
|
@ -59,7 +60,7 @@ func (t *tblWriter) Write(in interface{}) (err error) {
|
||||||
t.tableWriter.Render()
|
t.tableWriter.Render()
|
||||||
t.tableWriter.ClearRows()
|
t.tableWriter.ClearRows()
|
||||||
|
|
||||||
return
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
func (t *tblWriter) getData(val reflect.Value, numberOfFields int) (data []string) {
|
func (t *tblWriter) getData(val reflect.Value, numberOfFields int) (data []string) {
|
||||||
|
|
|
@ -2,10 +2,12 @@ package rpc
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"github.com/baez90/inetmock/internal/endpoints"
|
|
||||||
|
"gitlab.com/inetmock/inetmock/internal/endpoints"
|
||||||
)
|
)
|
||||||
|
|
||||||
type endpointsServer struct {
|
type endpointsServer struct {
|
||||||
|
UnimplementedEndpointsServer
|
||||||
endpointsManager endpoints.EndpointManager
|
endpointsManager endpoints.EndpointManager
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,15 +1,14 @@
|
||||||
package rpc
|
package rpc
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"github.com/baez90/inetmock/internal/endpoints"
|
|
||||||
"github.com/baez90/inetmock/pkg/api"
|
|
||||||
"github.com/baez90/inetmock/pkg/config"
|
|
||||||
"github.com/baez90/inetmock/pkg/logging"
|
|
||||||
"go.uber.org/zap"
|
|
||||||
"google.golang.org/grpc"
|
|
||||||
"net"
|
"net"
|
||||||
"net/url"
|
"net/url"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
app2 "gitlab.com/inetmock/inetmock/internal/app"
|
||||||
|
"gitlab.com/inetmock/inetmock/pkg/logging"
|
||||||
|
"go.uber.org/zap"
|
||||||
|
"google.golang.org/grpc"
|
||||||
)
|
)
|
||||||
|
|
||||||
type INetMockAPI interface {
|
type INetMockAPI interface {
|
||||||
|
@ -18,23 +17,20 @@ type INetMockAPI interface {
|
||||||
}
|
}
|
||||||
|
|
||||||
type inetmockAPI struct {
|
type inetmockAPI struct {
|
||||||
|
app app2.App
|
||||||
url *url.URL
|
url *url.URL
|
||||||
server *grpc.Server
|
server *grpc.Server
|
||||||
endpointManager endpoints.EndpointManager
|
|
||||||
registry api.HandlerRegistry
|
|
||||||
logger logging.Logger
|
logger logging.Logger
|
||||||
serverRunning bool
|
serverRunning bool
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewINetMockAPI(
|
func NewINetMockAPI(
|
||||||
config config.Config,
|
app app2.App,
|
||||||
epMgr endpoints.EndpointManager,
|
|
||||||
registry api.HandlerRegistry,
|
|
||||||
) INetMockAPI {
|
) INetMockAPI {
|
||||||
return &inetmockAPI{
|
return &inetmockAPI{
|
||||||
url: config.APIConfig().ListenURL(),
|
app: app,
|
||||||
endpointManager: epMgr,
|
url: app.Config().APIConfig().ListenURL(),
|
||||||
registry: registry,
|
logger: app.Logger().Named("api"),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -46,13 +42,15 @@ func (i *inetmockAPI) StartServer() (err error) {
|
||||||
i.server = grpc.NewServer()
|
i.server = grpc.NewServer()
|
||||||
|
|
||||||
RegisterHandlersServer(i.server, &handlersServer{
|
RegisterHandlersServer(i.server, &handlersServer{
|
||||||
registry: i.registry,
|
registry: i.app.HandlerRegistry(),
|
||||||
})
|
})
|
||||||
RegisterEndpointsServer(i.server, &endpointsServer{
|
RegisterEndpointsServer(i.server, &endpointsServer{
|
||||||
endpointsManager: i.endpointManager,
|
endpointsManager: i.app.EndpointManager(),
|
||||||
})
|
})
|
||||||
|
|
||||||
RegisterHealthServer(i.server, &healthServer{})
|
RegisterHealthServer(i.server, &healthServer{
|
||||||
|
app: i.app,
|
||||||
|
})
|
||||||
|
|
||||||
go i.startServerAsync(lis)
|
go i.startServerAsync(lis)
|
||||||
return
|
return
|
||||||
|
|
|
@ -2,13 +2,18 @@ package rpc
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"github.com/baez90/inetmock/pkg/api"
|
|
||||||
|
"gitlab.com/inetmock/inetmock/pkg/api"
|
||||||
)
|
)
|
||||||
|
|
||||||
type handlersServer struct {
|
type handlersServer struct {
|
||||||
|
UnimplementedHandlersServer
|
||||||
registry api.HandlerRegistry
|
registry api.HandlerRegistry
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (h *handlersServer) mustEmbedUnimplementedHandlersServer() {
|
||||||
|
}
|
||||||
|
|
||||||
func (h *handlersServer) GetHandlers(_ context.Context, _ *GetHandlersRequest) (*GetHandlersResponse, error) {
|
func (h *handlersServer) GetHandlers(_ context.Context, _ *GetHandlersRequest) (*GetHandlersResponse, error) {
|
||||||
return &GetHandlersResponse{
|
return &GetHandlersResponse{
|
||||||
Handlers: h.registry.AvailableHandlers(),
|
Handlers: h.registry.AvailableHandlers(),
|
||||||
|
|
|
@ -2,14 +2,17 @@ package rpc
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"github.com/baez90/inetmock/pkg/health"
|
|
||||||
|
app2 "gitlab.com/inetmock/inetmock/internal/app"
|
||||||
)
|
)
|
||||||
|
|
||||||
type healthServer struct {
|
type healthServer struct {
|
||||||
|
UnimplementedHealthServer
|
||||||
|
app app2.App
|
||||||
}
|
}
|
||||||
|
|
||||||
func (h healthServer) GetHealth(_ context.Context, _ *HealthRequest) (resp *HealthResponse, err error) {
|
func (h healthServer) GetHealth(_ context.Context, _ *HealthRequest) (resp *HealthResponse, err error) {
|
||||||
checker := health.CheckerInstance()
|
checker := h.app.Checker()
|
||||||
result := checker.IsHealthy()
|
result := checker.IsHealthy()
|
||||||
|
|
||||||
resp = &HealthResponse{
|
resp = &HealthResponse{
|
||||||
|
|
|
@ -3,15 +3,18 @@ package api
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"github.com/baez90/inetmock/pkg/config"
|
|
||||||
"go.uber.org/zap"
|
"gitlab.com/inetmock/inetmock/pkg/cert"
|
||||||
|
"gitlab.com/inetmock/inetmock/pkg/config"
|
||||||
|
"gitlab.com/inetmock/inetmock/pkg/logging"
|
||||||
)
|
)
|
||||||
|
|
||||||
type PluginInstanceFactory func() ProtocolHandler
|
type PluginContext interface {
|
||||||
|
Logger() logging.Logger
|
||||||
type LoggingFactory func() (*zap.Logger, error)
|
CertStore() cert.Store
|
||||||
|
}
|
||||||
|
|
||||||
type ProtocolHandler interface {
|
type ProtocolHandler interface {
|
||||||
Start(config config.HandlerConfig) error
|
Start(ctx PluginContext, config config.HandlerConfig) error
|
||||||
Shutdown(ctx context.Context) error
|
Shutdown(ctx context.Context) error
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,12 +8,25 @@ import (
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
registry HandlerRegistry
|
|
||||||
pluginFileNamePattern = regexp.MustCompile(`[\w\-]+\.so$`)
|
pluginFileNamePattern = regexp.MustCompile(`[\w\-]+\.so$`)
|
||||||
)
|
)
|
||||||
|
|
||||||
|
type Registration func(registry HandlerRegistry) error
|
||||||
|
|
||||||
|
type HandlerRegistry interface {
|
||||||
|
RegisterHandler(handlerName string, handlerProvider func() ProtocolHandler)
|
||||||
|
AvailableHandlers() []string
|
||||||
|
HandlerForName(handlerName string) (ProtocolHandler, bool)
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewHandlerRegistry() HandlerRegistry {
|
||||||
|
return &handlerRegistry{
|
||||||
|
handlers: make(map[string]func() ProtocolHandler),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
type handlerRegistry struct {
|
type handlerRegistry struct {
|
||||||
handlers map[string]PluginInstanceFactory
|
handlers map[string]func() ProtocolHandler
|
||||||
}
|
}
|
||||||
|
|
||||||
func (h handlerRegistry) AvailableHandlers() (availableHandlers []string) {
|
func (h handlerRegistry) AvailableHandlers() (availableHandlers []string) {
|
||||||
|
@ -25,33 +38,17 @@ func (h handlerRegistry) AvailableHandlers() (availableHandlers []string) {
|
||||||
|
|
||||||
func (h *handlerRegistry) HandlerForName(handlerName string) (instance ProtocolHandler, ok bool) {
|
func (h *handlerRegistry) HandlerForName(handlerName string) (instance ProtocolHandler, ok bool) {
|
||||||
handlerName = strings.ToLower(handlerName)
|
handlerName = strings.ToLower(handlerName)
|
||||||
var provider PluginInstanceFactory
|
var provider func() ProtocolHandler
|
||||||
if provider, ok = h.handlers[handlerName]; ok {
|
if provider, ok = h.handlers[handlerName]; ok {
|
||||||
instance = provider()
|
instance = provider()
|
||||||
}
|
}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
func (h *handlerRegistry) RegisterHandler(handlerName string, handlerProvider PluginInstanceFactory) {
|
func (h *handlerRegistry) RegisterHandler(handlerName string, handlerProvider func() ProtocolHandler) {
|
||||||
handlerName = strings.ToLower(handlerName)
|
handlerName = strings.ToLower(handlerName)
|
||||||
if _, exists := h.handlers[handlerName]; exists {
|
if _, exists := h.handlers[handlerName]; exists {
|
||||||
panic(fmt.Sprintf("handler with name %s is already registered - there's something strange...in the neighborhood", handlerName))
|
panic(fmt.Sprintf("handler with name %s is already registered - there's something strange...in the neighborhood", handlerName))
|
||||||
}
|
}
|
||||||
h.handlers[handlerName] = handlerProvider
|
h.handlers[handlerName] = handlerProvider
|
||||||
}
|
}
|
||||||
|
|
||||||
func Registry() HandlerRegistry {
|
|
||||||
return registry
|
|
||||||
}
|
|
||||||
|
|
||||||
func init() {
|
|
||||||
registry = &handlerRegistry{
|
|
||||||
handlers: make(map[string]PluginInstanceFactory),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
type HandlerRegistry interface {
|
|
||||||
RegisterHandler(handlerName string, handlerProvider PluginInstanceFactory)
|
|
||||||
AvailableHandlers() []string
|
|
||||||
HandlerForName(handlerName string) (ProtocolHandler, bool)
|
|
||||||
}
|
|
||||||
|
|
|
@ -7,7 +7,7 @@ import (
|
||||||
|
|
||||||
func Test_handlerRegistry_HandlerForName(t *testing.T) {
|
func Test_handlerRegistry_HandlerForName(t *testing.T) {
|
||||||
type fields struct {
|
type fields struct {
|
||||||
handlers map[string]PluginInstanceFactory
|
handlers map[string]func() ProtocolHandler
|
||||||
}
|
}
|
||||||
type args struct {
|
type args struct {
|
||||||
handlerName string
|
handlerName string
|
||||||
|
@ -29,7 +29,7 @@ func Test_handlerRegistry_HandlerForName(t *testing.T) {
|
||||||
{
|
{
|
||||||
name: "Nil instance from pseudo factory",
|
name: "Nil instance from pseudo factory",
|
||||||
fields: fields{
|
fields: fields{
|
||||||
handlers: map[string]PluginInstanceFactory{
|
handlers: map[string]func() ProtocolHandler{
|
||||||
"pseudo": func() ProtocolHandler {
|
"pseudo": func() ProtocolHandler {
|
||||||
return nil
|
return nil
|
||||||
},
|
},
|
||||||
|
|
|
@ -1,41 +0,0 @@
|
||||||
package api
|
|
||||||
|
|
||||||
import (
|
|
||||||
"github.com/baez90/inetmock/pkg/cert"
|
|
||||||
"github.com/baez90/inetmock/pkg/config"
|
|
||||||
"github.com/baez90/inetmock/pkg/logging"
|
|
||||||
)
|
|
||||||
|
|
||||||
var (
|
|
||||||
svcs Services
|
|
||||||
)
|
|
||||||
|
|
||||||
type Services interface {
|
|
||||||
CertStore() cert.Store
|
|
||||||
}
|
|
||||||
|
|
||||||
type services struct {
|
|
||||||
certStore cert.Store
|
|
||||||
}
|
|
||||||
|
|
||||||
func InitServices(
|
|
||||||
config config.Config,
|
|
||||||
logger logging.Logger,
|
|
||||||
) error {
|
|
||||||
certStore, err := cert.NewDefaultStore(config, logger)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
svcs = &services{
|
|
||||||
certStore: certStore,
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func ServicesInstance() Services {
|
|
||||||
return svcs
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *services) CertStore() cert.Store {
|
|
||||||
return s.certStore
|
|
||||||
}
|
|
|
@ -4,14 +4,15 @@ import (
|
||||||
"crypto/tls"
|
"crypto/tls"
|
||||||
"crypto/x509"
|
"crypto/x509"
|
||||||
"fmt"
|
"fmt"
|
||||||
certmock "github.com/baez90/inetmock/internal/mock/cert"
|
|
||||||
"github.com/baez90/inetmock/pkg/config"
|
|
||||||
"github.com/golang/mock/gomock"
|
|
||||||
"os"
|
"os"
|
||||||
"path"
|
"path"
|
||||||
"reflect"
|
"reflect"
|
||||||
"testing"
|
"testing"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
"github.com/golang/mock/gomock"
|
||||||
|
certmock "gitlab.com/inetmock/inetmock/internal/mock/cert"
|
||||||
|
"gitlab.com/inetmock/inetmock/pkg/config"
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
|
|
|
@ -1,8 +1,9 @@
|
||||||
package cert
|
package cert
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"github.com/baez90/inetmock/pkg/defaulting"
|
|
||||||
"reflect"
|
"reflect"
|
||||||
|
|
||||||
|
"gitlab.com/inetmock/inetmock/pkg/defaulting"
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
|
|
|
@ -8,10 +8,11 @@ import (
|
||||||
"crypto/x509"
|
"crypto/x509"
|
||||||
"crypto/x509/pkix"
|
"crypto/x509/pkix"
|
||||||
"encoding/pem"
|
"encoding/pem"
|
||||||
"github.com/baez90/inetmock/pkg/config"
|
|
||||||
"github.com/baez90/inetmock/pkg/defaulting"
|
|
||||||
"math/big"
|
"math/big"
|
||||||
"net"
|
"net"
|
||||||
|
|
||||||
|
"gitlab.com/inetmock/inetmock/pkg/config"
|
||||||
|
"gitlab.com/inetmock/inetmock/pkg/defaulting"
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
|
|
|
@ -1,8 +1,9 @@
|
||||||
package cert
|
package cert
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"github.com/baez90/inetmock/pkg/config"
|
|
||||||
"os"
|
"os"
|
||||||
|
|
||||||
|
"gitlab.com/inetmock/inetmock/pkg/config"
|
||||||
)
|
)
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
|
|
|
@ -1,12 +1,13 @@
|
||||||
package cert
|
package cert
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"github.com/baez90/inetmock/pkg/config"
|
|
||||||
"github.com/spf13/viper"
|
|
||||||
"os"
|
"os"
|
||||||
"strings"
|
"strings"
|
||||||
"testing"
|
"testing"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
"github.com/spf13/viper"
|
||||||
|
"gitlab.com/inetmock/inetmock/pkg/config"
|
||||||
)
|
)
|
||||||
|
|
||||||
func readViper(cfg string) *viper.Viper {
|
func readViper(cfg string) *viper.Viper {
|
||||||
|
|
|
@ -6,9 +6,10 @@ import (
|
||||||
"encoding/pem"
|
"encoding/pem"
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"github.com/baez90/inetmock/pkg/path"
|
|
||||||
"os"
|
"os"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
|
|
||||||
|
"gitlab.com/inetmock/inetmock/pkg/path"
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
|
|
|
@ -6,10 +6,11 @@ import (
|
||||||
"crypto/rand"
|
"crypto/rand"
|
||||||
"crypto/tls"
|
"crypto/tls"
|
||||||
"crypto/x509"
|
"crypto/x509"
|
||||||
"github.com/baez90/inetmock/pkg/config"
|
|
||||||
"github.com/baez90/inetmock/pkg/logging"
|
|
||||||
"go.uber.org/zap"
|
|
||||||
"net"
|
"net"
|
||||||
|
|
||||||
|
"gitlab.com/inetmock/inetmock/pkg/config"
|
||||||
|
"gitlab.com/inetmock/inetmock/pkg/logging"
|
||||||
|
"go.uber.org/zap"
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
|
|
|
@ -1,19 +1,16 @@
|
||||||
package config
|
package config
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"github.com/baez90/inetmock/pkg/logging"
|
"strings"
|
||||||
"github.com/baez90/inetmock/pkg/path"
|
|
||||||
"github.com/spf13/pflag"
|
"github.com/spf13/pflag"
|
||||||
"github.com/spf13/viper"
|
"github.com/spf13/viper"
|
||||||
|
"gitlab.com/inetmock/inetmock/pkg/logging"
|
||||||
|
"gitlab.com/inetmock/inetmock/pkg/path"
|
||||||
"go.uber.org/zap"
|
"go.uber.org/zap"
|
||||||
"strings"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
func CreateConfig(flags *pflag.FlagSet) Config {
|
||||||
appConfig Config
|
|
||||||
)
|
|
||||||
|
|
||||||
func CreateConfig(flags *pflag.FlagSet) {
|
|
||||||
logger, _ := logging.CreateLogger()
|
logger, _ := logging.CreateLogger()
|
||||||
configInstance := &config{
|
configInstance := &config{
|
||||||
logger: logger.Named("Config"),
|
logger: logger.Named("Config"),
|
||||||
|
@ -38,11 +35,7 @@ func CreateConfig(flags *pflag.FlagSet) {
|
||||||
configInstance.cfg.RegisterAlias(k, v)
|
configInstance.cfg.RegisterAlias(k, v)
|
||||||
}
|
}
|
||||||
|
|
||||||
appConfig = configInstance
|
return configInstance
|
||||||
}
|
|
||||||
|
|
||||||
func Instance() Config {
|
|
||||||
return appConfig
|
|
||||||
}
|
}
|
||||||
|
|
||||||
type Config interface {
|
type Config interface {
|
||||||
|
@ -51,14 +44,14 @@ type Config interface {
|
||||||
Viper() *viper.Viper
|
Viper() *viper.Viper
|
||||||
TLSConfig() CertOptions
|
TLSConfig() CertOptions
|
||||||
APIConfig() RPC
|
APIConfig() RPC
|
||||||
EndpointConfigs() map[string]MultiHandlerConfig
|
EndpointConfigs() map[string]EndpointConfig
|
||||||
}
|
}
|
||||||
|
|
||||||
type config struct {
|
type config struct {
|
||||||
cfg *viper.Viper
|
cfg *viper.Viper
|
||||||
logger logging.Logger
|
logger logging.Logger
|
||||||
TLS CertOptions
|
TLS CertOptions
|
||||||
Endpoints map[string]MultiHandlerConfig
|
Endpoints map[string]EndpointConfig
|
||||||
API RPC
|
API RPC
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -76,7 +69,7 @@ func (c *config) ReadConfigString(config, format string) (err error) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *config) EndpointConfigs() map[string]MultiHandlerConfig {
|
func (c *config) EndpointConfigs() map[string]EndpointConfig {
|
||||||
return c.Endpoints
|
return c.Endpoints
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,8 +1,9 @@
|
||||||
package config
|
package config
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"github.com/spf13/pflag"
|
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
|
"github.com/spf13/pflag"
|
||||||
)
|
)
|
||||||
|
|
||||||
func Test_config_ReadConfig(t *testing.T) {
|
func Test_config_ReadConfig(t *testing.T) {
|
||||||
|
@ -53,8 +54,7 @@ endpoints:
|
||||||
}
|
}
|
||||||
for _, tt := range tests {
|
for _, tt := range tests {
|
||||||
t.Run(tt.name, func(t *testing.T) {
|
t.Run(tt.name, func(t *testing.T) {
|
||||||
CreateConfig(tt.args.flags)
|
cfg := CreateConfig(tt.args.flags)
|
||||||
cfg := Instance()
|
|
||||||
if err := cfg.ReadConfigString(tt.args.config, "yaml"); (err != nil) != tt.wantErr {
|
if err := cfg.ReadConfigString(tt.args.config, "yaml"); (err != nil) != tt.wantErr {
|
||||||
t.Errorf("ReadConfig() error = %v, wantErr %v", err, tt.wantErr)
|
t.Errorf("ReadConfig() error = %v, wantErr %v", err, tt.wantErr)
|
||||||
return
|
return
|
||||||
|
|
|
@ -2,6 +2,7 @@ package config
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
|
|
||||||
"github.com/spf13/viper"
|
"github.com/spf13/viper"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
|
@ -1,9 +1,10 @@
|
||||||
package config
|
package config
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"github.com/spf13/viper"
|
|
||||||
"reflect"
|
"reflect"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
|
"github.com/spf13/viper"
|
||||||
)
|
)
|
||||||
|
|
||||||
func Test_handlerConfig_HandlerName(t *testing.T) {
|
func Test_handlerConfig_HandlerName(t *testing.T) {
|
||||||
|
|
|
@ -4,14 +4,14 @@ import (
|
||||||
"github.com/spf13/viper"
|
"github.com/spf13/viper"
|
||||||
)
|
)
|
||||||
|
|
||||||
type MultiHandlerConfig struct {
|
type EndpointConfig struct {
|
||||||
Handler string
|
Handler string
|
||||||
Ports []uint16
|
Ports []uint16
|
||||||
ListenAddress string
|
ListenAddress string
|
||||||
Options *viper.Viper
|
Options *viper.Viper
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m MultiHandlerConfig) HandlerConfigs() []HandlerConfig {
|
func (m EndpointConfig) HandlerConfigs() []HandlerConfig {
|
||||||
configs := make([]HandlerConfig, 0)
|
configs := make([]HandlerConfig, 0)
|
||||||
for _, port := range m.Ports {
|
for _, port := range m.Ports {
|
||||||
configs = append(configs, HandlerConfig{
|
configs = append(configs, HandlerConfig{
|
||||||
|
|
|
@ -27,9 +27,7 @@ func (r *registry) Register(t reflect.Type, defaulter ...Defaulter) {
|
||||||
given = r
|
given = r
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, d := range defaulter {
|
given = append(given, defaulter...)
|
||||||
given = append(given, d)
|
|
||||||
}
|
|
||||||
|
|
||||||
r.defaulters[t] = given
|
r.defaulters[t] = given
|
||||||
}
|
}
|
||||||
|
|
|
@ -29,8 +29,7 @@ func Test_registry_Apply(t *testing.T) {
|
||||||
fields: fields{
|
fields: fields{
|
||||||
defaulters: map[reflect.Type][]Defaulter{
|
defaulters: map[reflect.Type][]Defaulter{
|
||||||
reflect.TypeOf(&sample{}): {func(instance interface{}) {
|
reflect.TypeOf(&sample{}): {func(instance interface{}) {
|
||||||
switch i := instance.(type) {
|
if i, ok := instance.(*sample); ok {
|
||||||
case *sample:
|
|
||||||
i.i = 42
|
i.i = 42
|
||||||
}
|
}
|
||||||
}},
|
}},
|
||||||
|
|
|
@ -26,16 +26,11 @@ type Result struct {
|
||||||
type Check func() CheckResult
|
type Check func() CheckResult
|
||||||
|
|
||||||
var (
|
var (
|
||||||
CheckForComponentAlreadyRegistered = errors.New("a check for the requested component is already registered")
|
ErrCheckForComponentAlreadyRegistered = errors.New("a check for the requested component is already registered")
|
||||||
checkerInstance *checker
|
|
||||||
)
|
)
|
||||||
|
|
||||||
func init() {
|
func New() Checker {
|
||||||
checkerInstance = &checker{
|
return &checker{
|
||||||
componentChecks: map[string]Check{},
|
componentChecks: map[string]Check{},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func CheckerInstance() Checker {
|
|
||||||
return checkerInstance
|
|
||||||
}
|
|
||||||
|
|
|
@ -13,7 +13,7 @@ type Checker interface {
|
||||||
|
|
||||||
func (c *checker) RegisterCheck(component string, check Check) error {
|
func (c *checker) RegisterCheck(component string, check Check) error {
|
||||||
if _, exists := c.componentChecks[component]; exists {
|
if _, exists := c.componentChecks[component]; exists {
|
||||||
return fmt.Errorf("component: %s: %w", component, CheckForComponentAlreadyRegistered)
|
return fmt.Errorf("component: %s: %w", component, ErrCheckForComponentAlreadyRegistered)
|
||||||
}
|
}
|
||||||
|
|
||||||
c.componentChecks[component] = check
|
c.componentChecks[component] = check
|
||||||
|
@ -30,7 +30,7 @@ func (c *checker) IsHealthy() (r Result) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
func max(s1 Status, s2 Status) Status {
|
func max(s1, s2 Status) Status {
|
||||||
var max Status
|
var max Status
|
||||||
if s1 > s2 {
|
if s1 > s2 {
|
||||||
max = s1
|
max = s1
|
||||||
|
|
|
@ -1,9 +1,10 @@
|
||||||
package logging
|
package logging
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"strings"
|
||||||
|
|
||||||
"go.uber.org/zap"
|
"go.uber.org/zap"
|
||||||
"go.uber.org/zap/zapcore"
|
"go.uber.org/zap/zapcore"
|
||||||
"strings"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
|
@ -46,3 +47,11 @@ func CreateLogger() (Logger, error) {
|
||||||
return NewLogger(zapLogger), nil
|
return NewLogger(zapLogger), nil
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func MustCreateLogger() Logger {
|
||||||
|
if logger, err := CreateLogger(); err != nil {
|
||||||
|
panic(err)
|
||||||
|
} else {
|
||||||
|
return logger
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -1,9 +1,10 @@
|
||||||
package logging
|
package logging
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"go.uber.org/zap"
|
|
||||||
"reflect"
|
"reflect"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
|
"go.uber.org/zap"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestParseLevel(t *testing.T) {
|
func TestParseLevel(t *testing.T) {
|
||||||
|
|
|
@ -10,7 +10,6 @@ import (
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestFileExists(t *testing.T) {
|
func TestFileExists(t *testing.T) {
|
||||||
|
|
||||||
tmpFile, err := ioutil.TempFile("", "inetmock")
|
tmpFile, err := ioutil.TempFile("", "inetmock")
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
|
@ -2,11 +2,12 @@ package dns_mock
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"encoding/binary"
|
"encoding/binary"
|
||||||
"github.com/spf13/viper"
|
|
||||||
"math"
|
"math"
|
||||||
"math/rand"
|
"math/rand"
|
||||||
"net"
|
"net"
|
||||||
"unsafe"
|
"unsafe"
|
||||||
|
|
||||||
|
"github.com/spf13/viper"
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
|
|
|
@ -2,9 +2,11 @@ package dns_mock
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"github.com/baez90/inetmock/pkg/config"
|
|
||||||
"github.com/baez90/inetmock/pkg/logging"
|
|
||||||
"github.com/miekg/dns"
|
"github.com/miekg/dns"
|
||||||
|
"gitlab.com/inetmock/inetmock/pkg/api"
|
||||||
|
"gitlab.com/inetmock/inetmock/pkg/config"
|
||||||
|
"gitlab.com/inetmock/inetmock/pkg/logging"
|
||||||
"go.uber.org/zap"
|
"go.uber.org/zap"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -13,7 +15,7 @@ type dnsHandler struct {
|
||||||
dnsServer []*dns.Server
|
dnsServer []*dns.Server
|
||||||
}
|
}
|
||||||
|
|
||||||
func (d *dnsHandler) Start(config config.HandlerConfig) (err error) {
|
func (d *dnsHandler) Start(_ api.PluginContext, config config.HandlerConfig) (err error) {
|
||||||
var options dnsOptions
|
var options dnsOptions
|
||||||
if options, err = loadFromConfig(config.Options); err != nil {
|
if options, err = loadFromConfig(config.Options); err != nil {
|
||||||
return
|
return
|
||||||
|
|
|
@ -1,9 +1,10 @@
|
||||||
package dns_mock
|
package dns_mock
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"github.com/spf13/viper"
|
|
||||||
"net"
|
"net"
|
||||||
"regexp"
|
"regexp"
|
||||||
|
|
||||||
|
"github.com/spf13/viper"
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
|
|
|
@ -1,9 +1,9 @@
|
||||||
package dns_mock
|
package dns_mock
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"github.com/baez90/inetmock/pkg/logging"
|
|
||||||
"github.com/miekg/dns"
|
"github.com/miekg/dns"
|
||||||
"github.com/prometheus/client_golang/prometheus"
|
"github.com/prometheus/client_golang/prometheus"
|
||||||
|
"gitlab.com/inetmock/inetmock/pkg/logging"
|
||||||
"go.uber.org/zap"
|
"go.uber.org/zap"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
|
@ -1,10 +1,10 @@
|
||||||
package dns_mock
|
package dns_mock
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"github.com/baez90/inetmock/pkg/api"
|
|
||||||
"github.com/baez90/inetmock/pkg/logging"
|
|
||||||
"github.com/baez90/inetmock/pkg/metrics"
|
|
||||||
"github.com/prometheus/client_golang/prometheus"
|
"github.com/prometheus/client_golang/prometheus"
|
||||||
|
"gitlab.com/inetmock/inetmock/pkg/api"
|
||||||
|
"gitlab.com/inetmock/inetmock/pkg/logging"
|
||||||
|
"gitlab.com/inetmock/inetmock/pkg/metrics"
|
||||||
"go.uber.org/zap"
|
"go.uber.org/zap"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -19,11 +19,10 @@ var (
|
||||||
requestDurationHistogram *prometheus.HistogramVec
|
requestDurationHistogram *prometheus.HistogramVec
|
||||||
)
|
)
|
||||||
|
|
||||||
func init() {
|
func AddDNSMock(registry api.HandlerRegistry) (err error) {
|
||||||
var err error
|
|
||||||
var logger logging.Logger
|
var logger logging.Logger
|
||||||
if logger, err = logging.CreateLogger(); err != nil {
|
if logger, err = logging.CreateLogger(); err != nil {
|
||||||
panic(err)
|
return
|
||||||
}
|
}
|
||||||
logger = logger.With(
|
logger = logger.With(
|
||||||
zap.String("protocol_handler", name),
|
zap.String("protocol_handler", name),
|
||||||
|
@ -35,7 +34,7 @@ func init() {
|
||||||
"",
|
"",
|
||||||
handlerNameLblName,
|
handlerNameLblName,
|
||||||
); err != nil {
|
); err != nil {
|
||||||
panic(err)
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if unhandledRequestsCounter, err = metrics.Counter(
|
if unhandledRequestsCounter, err = metrics.Counter(
|
||||||
|
@ -44,7 +43,7 @@ func init() {
|
||||||
"",
|
"",
|
||||||
handlerNameLblName,
|
handlerNameLblName,
|
||||||
); err != nil {
|
); err != nil {
|
||||||
panic(err)
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if requestDurationHistogram, err = metrics.Histogram(
|
if requestDurationHistogram, err = metrics.Histogram(
|
||||||
|
@ -54,12 +53,14 @@ func init() {
|
||||||
nil,
|
nil,
|
||||||
handlerNameLblName,
|
handlerNameLblName,
|
||||||
); err != nil {
|
); err != nil {
|
||||||
panic(err)
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
api.Registry().RegisterHandler(name, func() api.ProtocolHandler {
|
registry.RegisterHandler(name, func() api.ProtocolHandler {
|
||||||
return &dnsHandler{
|
return &dnsHandler{
|
||||||
logger: logger,
|
logger: logger,
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
|
return
|
||||||
}
|
}
|
|
@ -4,10 +4,12 @@ import (
|
||||||
"context"
|
"context"
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"github.com/baez90/inetmock/pkg/config"
|
|
||||||
"github.com/baez90/inetmock/pkg/logging"
|
|
||||||
"go.uber.org/zap"
|
|
||||||
"net/http"
|
"net/http"
|
||||||
|
|
||||||
|
"gitlab.com/inetmock/inetmock/pkg/api"
|
||||||
|
"gitlab.com/inetmock/inetmock/pkg/config"
|
||||||
|
"gitlab.com/inetmock/inetmock/pkg/logging"
|
||||||
|
"go.uber.org/zap"
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
|
@ -21,8 +23,16 @@ type httpHandler struct {
|
||||||
server *http.Server
|
server *http.Server
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *httpHandler) Start(config config.HandlerConfig) (err error) {
|
func (p *httpHandler) Start(ctx api.PluginContext, config config.HandlerConfig) (err error) {
|
||||||
options := loadFromConfig(config.Options)
|
p.logger = ctx.Logger().With(
|
||||||
|
zap.String("protocol_handler", name),
|
||||||
|
)
|
||||||
|
|
||||||
|
var options httpOptions
|
||||||
|
if options, err = loadFromConfig(config.Options); err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
p.logger = p.logger.With(
|
p.logger = p.logger.With(
|
||||||
zap.String("handler_name", config.HandlerName),
|
zap.String("handler_name", config.HandlerName),
|
||||||
zap.String("address", config.ListenAddr()),
|
zap.String("address", config.ListenAddr()),
|
||||||
|
|
139
plugins/http_mock/handler_test.go
Normal file
139
plugins/http_mock/handler_test.go
Normal file
|
@ -0,0 +1,139 @@
|
||||||
|
package http_mock_test
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"fmt"
|
||||||
|
"math/rand"
|
||||||
|
"net"
|
||||||
|
"net/http"
|
||||||
|
"strconv"
|
||||||
|
"strings"
|
||||||
|
"testing"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/golang/mock/gomock"
|
||||||
|
"github.com/spf13/viper"
|
||||||
|
api_mock "gitlab.com/inetmock/inetmock/internal/mock/api"
|
||||||
|
"gitlab.com/inetmock/inetmock/pkg/api"
|
||||||
|
"gitlab.com/inetmock/inetmock/pkg/config"
|
||||||
|
"gitlab.com/inetmock/inetmock/pkg/logging"
|
||||||
|
"gitlab.com/inetmock/inetmock/plugins/http_mock"
|
||||||
|
"go.uber.org/zap"
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
testLogger = logging.NewLogger(zap.NewNop())
|
||||||
|
availableExtensions = []string{"gif", "html", "ico", "jpg", "png", "txt"}
|
||||||
|
charSet = "abcdedfghijklmnopqrstABCDEFGHIJKLMNOP"
|
||||||
|
)
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
rand.Seed(time.Now().Unix())
|
||||||
|
}
|
||||||
|
|
||||||
|
func Benchmark_httpHandler(b *testing.B) {
|
||||||
|
ctrl := gomock.NewController(b)
|
||||||
|
defer ctrl.Finish()
|
||||||
|
|
||||||
|
listenPort := randomHighPort()
|
||||||
|
_, handler := setupHandler(b, ctrl, listenPort)
|
||||||
|
|
||||||
|
b.ResetTimer()
|
||||||
|
|
||||||
|
for i := 0; i < b.N; i++ {
|
||||||
|
extension := availableExtensions[rand.Intn(len(availableExtensions))]
|
||||||
|
if resp, err := http.Get(fmt.Sprintf("http://localhost:%d/%s.%s", listenPort, randomString(15), extension)); err != nil {
|
||||||
|
b.Error(err)
|
||||||
|
} else if resp.StatusCode != 200 {
|
||||||
|
b.Error("")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
defer handler.Shutdown(context.Background())
|
||||||
|
}
|
||||||
|
|
||||||
|
func randomString(length int) (result string) {
|
||||||
|
buffer := strings.Builder{}
|
||||||
|
for i := 0; i < length; i++ {
|
||||||
|
buffer.WriteByte(charSet[rand.Intn(len(charSet))])
|
||||||
|
}
|
||||||
|
return buffer.String()
|
||||||
|
}
|
||||||
|
|
||||||
|
func setupHandler(b *testing.B, ctrl *gomock.Controller, listenPort uint16) (api.HandlerRegistry, api.ProtocolHandler) {
|
||||||
|
b.Helper()
|
||||||
|
|
||||||
|
registry := api.NewHandlerRegistry()
|
||||||
|
if err := http_mock.AddHTTPMock(registry); err != nil {
|
||||||
|
b.Errorf("AddHTTPMock() error = %v", err)
|
||||||
|
}
|
||||||
|
handler, ok := registry.HandlerForName("http_mock")
|
||||||
|
if !ok {
|
||||||
|
b.Error("handler not registered")
|
||||||
|
}
|
||||||
|
|
||||||
|
mockApp := api_mock.NewMockPluginContext(ctrl)
|
||||||
|
mockApp.EXPECT().
|
||||||
|
Logger().
|
||||||
|
Return(testLogger)
|
||||||
|
|
||||||
|
v := viper.New()
|
||||||
|
v.Set("rules", []map[string]string{
|
||||||
|
{
|
||||||
|
"pattern": ".*\\.(?i)gif",
|
||||||
|
"response": "./../../assets/fakeFiles/default.gif",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"pattern": ".*\\.(?i)html",
|
||||||
|
"response": "./../../assets/fakeFiles/default.html",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"pattern": ".*\\.(?i)ico",
|
||||||
|
"response": "./../../assets/fakeFiles/default.ico",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"pattern": ".*\\.(?i)jpg",
|
||||||
|
"response": "./../../assets/fakeFiles/default.jpg",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"pattern": ".*\\.(?i)png",
|
||||||
|
"response": "./../../assets/fakeFiles/default.png",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"pattern": ".*\\.(?i)txt",
|
||||||
|
"response": "./../../assets/fakeFiles/default.txt",
|
||||||
|
},
|
||||||
|
})
|
||||||
|
|
||||||
|
handlerConfig := config.HandlerConfig{
|
||||||
|
HandlerName: "http_test",
|
||||||
|
Port: listenPort,
|
||||||
|
ListenAddress: "localhost",
|
||||||
|
Options: v,
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := handler.Start(mockApp, handlerConfig); err != nil {
|
||||||
|
b.Error(err)
|
||||||
|
b.FailNow()
|
||||||
|
}
|
||||||
|
|
||||||
|
return registry, handler
|
||||||
|
}
|
||||||
|
|
||||||
|
func randomHighPort() uint16 {
|
||||||
|
var err error
|
||||||
|
var listener net.Listener
|
||||||
|
defer func() {
|
||||||
|
if listener != nil {
|
||||||
|
_ = listener.Close()
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
|
||||||
|
for {
|
||||||
|
if listener, err = net.Listen("tcp", ":0"); err == nil {
|
||||||
|
parts := strings.Split(listener.Addr().String(), ":")
|
||||||
|
port, _ := strconv.Atoi(parts[len(parts)-1])
|
||||||
|
return uint16(port)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,48 +0,0 @@
|
||||||
package http_mock
|
|
||||||
|
|
||||||
import (
|
|
||||||
"github.com/baez90/inetmock/pkg/api"
|
|
||||||
"github.com/baez90/inetmock/pkg/logging"
|
|
||||||
"github.com/baez90/inetmock/pkg/metrics"
|
|
||||||
"github.com/prometheus/client_golang/prometheus"
|
|
||||||
"go.uber.org/zap"
|
|
||||||
)
|
|
||||||
|
|
||||||
var (
|
|
||||||
totalRequestCounter *prometheus.CounterVec
|
|
||||||
requestDurationHistogram *prometheus.HistogramVec
|
|
||||||
)
|
|
||||||
|
|
||||||
func init() {
|
|
||||||
var err error
|
|
||||||
var logger logging.Logger
|
|
||||||
if logger, err = logging.CreateLogger(); err != nil {
|
|
||||||
panic(err)
|
|
||||||
}
|
|
||||||
logger = logger.With(
|
|
||||||
zap.String("protocol_handler", name),
|
|
||||||
)
|
|
||||||
if totalRequestCounter, err = metrics.Counter(
|
|
||||||
name,
|
|
||||||
"total_requests",
|
|
||||||
"",
|
|
||||||
handlerNameLblName,
|
|
||||||
ruleMatchedLblName,
|
|
||||||
); err != nil {
|
|
||||||
panic(err)
|
|
||||||
}
|
|
||||||
if requestDurationHistogram, err = metrics.Histogram(
|
|
||||||
name,
|
|
||||||
"request_duration",
|
|
||||||
"",
|
|
||||||
nil,
|
|
||||||
handlerNameLblName,
|
|
||||||
); err != nil {
|
|
||||||
panic(err)
|
|
||||||
}
|
|
||||||
api.Registry().RegisterHandler(name, func() api.ProtocolHandler {
|
|
||||||
return &httpHandler{
|
|
||||||
logger: logger,
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
|
@ -1,19 +1,44 @@
|
||||||
|
//go:generate go-enum -f $GOFILE --lower --marshal --names
|
||||||
package http_mock
|
package http_mock
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"github.com/spf13/viper"
|
"net/http"
|
||||||
|
"path/filepath"
|
||||||
"regexp"
|
"regexp"
|
||||||
|
|
||||||
|
"github.com/spf13/viper"
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
var (
|
||||||
rulesConfigKey = "rules"
|
ruleValueSelectors = map[RequestMatchTarget]ruleValueSelector{
|
||||||
patternConfigKey = "pattern"
|
RequestMatchTargetHeader: func(req *http.Request, targetKey string) string {
|
||||||
responseConfigKey = "response"
|
return req.Header.Get(targetKey)
|
||||||
|
},
|
||||||
|
RequestMatchTargetPath: func(req *http.Request, _ string) string {
|
||||||
|
return req.URL.Path
|
||||||
|
},
|
||||||
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
|
/* ENUM(
|
||||||
|
Path,
|
||||||
|
Header
|
||||||
|
)
|
||||||
|
*/
|
||||||
|
type RequestMatchTarget int
|
||||||
|
|
||||||
|
func (x RequestMatchTarget) Matches(req *http.Request, targetKey string, regex *regexp.Regexp) bool {
|
||||||
|
val := ruleValueSelectors[x](req, targetKey)
|
||||||
|
return regex.MatchString(val)
|
||||||
|
}
|
||||||
|
|
||||||
|
type ruleValueSelector func(req *http.Request, targetKey string) string
|
||||||
|
|
||||||
type targetRule struct {
|
type targetRule struct {
|
||||||
pattern *regexp.Regexp
|
pattern *regexp.Regexp
|
||||||
response string
|
response string
|
||||||
|
requestMatchTarget RequestMatchTarget
|
||||||
|
targetKey string
|
||||||
}
|
}
|
||||||
|
|
||||||
func (tr targetRule) Pattern() *regexp.Regexp {
|
func (tr targetRule) Pattern() *regexp.Regexp {
|
||||||
|
@ -28,20 +53,44 @@ type httpOptions struct {
|
||||||
Rules []targetRule
|
Rules []targetRule
|
||||||
}
|
}
|
||||||
|
|
||||||
func loadFromConfig(config *viper.Viper) (options httpOptions) {
|
func loadFromConfig(config *viper.Viper) (options httpOptions, err error) {
|
||||||
anonRules := config.Get(rulesConfigKey).([]interface{})
|
type tmpCfg struct {
|
||||||
|
Pattern string
|
||||||
|
Response string
|
||||||
|
Matcher string
|
||||||
|
Target string
|
||||||
|
}
|
||||||
|
|
||||||
for _, i := range anonRules {
|
tmpRules := struct {
|
||||||
innerData := i.(map[interface{}]interface{})
|
Rules []tmpCfg
|
||||||
|
}{}
|
||||||
|
|
||||||
|
if err = config.Unmarshal(&tmpRules); err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, i := range tmpRules.Rules {
|
||||||
|
var rulePattern *regexp.Regexp
|
||||||
|
var matchTargetValue RequestMatchTarget
|
||||||
|
var absoluteResponsePath string
|
||||||
|
var parseErr error
|
||||||
|
if rulePattern, parseErr = regexp.Compile(i.Pattern); parseErr != nil {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if matchTargetValue, parseErr = ParseRequestMatchTarget(i.Matcher); parseErr != nil {
|
||||||
|
matchTargetValue = RequestMatchTargetPath
|
||||||
|
}
|
||||||
|
|
||||||
|
if absoluteResponsePath, parseErr = filepath.Abs(i.Response); parseErr != nil {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
if rulePattern, err := regexp.Compile(innerData[patternConfigKey].(string)); err == nil {
|
|
||||||
options.Rules = append(options.Rules, targetRule{
|
options.Rules = append(options.Rules, targetRule{
|
||||||
pattern: rulePattern,
|
pattern: rulePattern,
|
||||||
response: innerData[responseConfigKey].(string),
|
response: absoluteResponsePath,
|
||||||
|
requestMatchTarget: matchTargetValue,
|
||||||
|
targetKey: i.Target,
|
||||||
})
|
})
|
||||||
} else {
|
|
||||||
panic(err)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return
|
return
|
||||||
|
|
114
plugins/http_mock/protocol_options_test.go
Normal file
114
plugins/http_mock/protocol_options_test.go
Normal file
|
@ -0,0 +1,114 @@
|
||||||
|
package http_mock
|
||||||
|
|
||||||
|
import (
|
||||||
|
"path/filepath"
|
||||||
|
"reflect"
|
||||||
|
"regexp"
|
||||||
|
"strings"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/spf13/viper"
|
||||||
|
)
|
||||||
|
|
||||||
|
func Test_loadFromConfig(t *testing.T) {
|
||||||
|
type args struct {
|
||||||
|
config string
|
||||||
|
}
|
||||||
|
tests := []struct {
|
||||||
|
name string
|
||||||
|
args args
|
||||||
|
wantOptions httpOptions
|
||||||
|
wantErr bool
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
name: "Parse default config",
|
||||||
|
args: args{
|
||||||
|
config: `
|
||||||
|
rules:
|
||||||
|
- pattern: ".*\\.(?i)exe"
|
||||||
|
response: ./assets/fakeFiles/sample.exe
|
||||||
|
`,
|
||||||
|
},
|
||||||
|
wantOptions: httpOptions{
|
||||||
|
Rules: []targetRule{
|
||||||
|
{
|
||||||
|
pattern: regexp.MustCompile(".*\\.(?i)exe"),
|
||||||
|
response: func() string {
|
||||||
|
p, _ := filepath.Abs("./assets/fakeFiles/sample.exe")
|
||||||
|
return p
|
||||||
|
}(),
|
||||||
|
requestMatchTarget: RequestMatchTargetPath,
|
||||||
|
targetKey: "",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
wantErr: false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Parse config with path matcher",
|
||||||
|
args: args{
|
||||||
|
config: `
|
||||||
|
rules:
|
||||||
|
- pattern: ".*\\.(?i)exe"
|
||||||
|
matcher: Path
|
||||||
|
response: ./assets/fakeFiles/sample.exe
|
||||||
|
`,
|
||||||
|
},
|
||||||
|
wantOptions: httpOptions{
|
||||||
|
Rules: []targetRule{
|
||||||
|
{
|
||||||
|
pattern: regexp.MustCompile(".*\\.(?i)exe"),
|
||||||
|
response: func() string {
|
||||||
|
p, _ := filepath.Abs("./assets/fakeFiles/sample.exe")
|
||||||
|
return p
|
||||||
|
}(),
|
||||||
|
requestMatchTarget: RequestMatchTargetPath,
|
||||||
|
targetKey: "",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
wantErr: false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Parse config with header matcher",
|
||||||
|
args: args{
|
||||||
|
config: `
|
||||||
|
rules:
|
||||||
|
- pattern: "^application/octet-stream$"
|
||||||
|
target: Content-Type
|
||||||
|
matcher: Header
|
||||||
|
response: ./assets/fakeFiles/sample.exe
|
||||||
|
`,
|
||||||
|
},
|
||||||
|
wantOptions: httpOptions{
|
||||||
|
Rules: []targetRule{
|
||||||
|
{
|
||||||
|
pattern: regexp.MustCompile("^application/octet-stream$"),
|
||||||
|
response: func() string {
|
||||||
|
p, _ := filepath.Abs("./assets/fakeFiles/sample.exe")
|
||||||
|
return p
|
||||||
|
}(),
|
||||||
|
requestMatchTarget: RequestMatchTargetHeader,
|
||||||
|
targetKey: "Content-Type",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
wantErr: false,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
for _, tt := range tests {
|
||||||
|
t.Run(tt.name, func(t *testing.T) {
|
||||||
|
v := viper.New()
|
||||||
|
v.SetConfigType("yaml")
|
||||||
|
_ = v.ReadConfig(strings.NewReader(tt.args.config))
|
||||||
|
gotOptions, err := loadFromConfig(v)
|
||||||
|
if (err != nil) != tt.wantErr {
|
||||||
|
t.Errorf("loadFromConfig() error = %v, wantErr %v", err, tt.wantErr)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if !reflect.DeepEqual(gotOptions, tt.wantOptions) {
|
||||||
|
t.Errorf("loadFromConfig() gotOptions = %v, want %v", gotOptions, tt.wantOptions)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
|
@ -2,16 +2,16 @@ package http_mock
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
"github.com/baez90/inetmock/pkg/logging"
|
|
||||||
"github.com/prometheus/client_golang/prometheus"
|
|
||||||
"go.uber.org/zap"
|
|
||||||
"net/http"
|
"net/http"
|
||||||
"regexp"
|
|
||||||
"strconv"
|
"strconv"
|
||||||
|
|
||||||
|
"github.com/prometheus/client_golang/prometheus"
|
||||||
|
"gitlab.com/inetmock/inetmock/pkg/logging"
|
||||||
|
"go.uber.org/zap"
|
||||||
)
|
)
|
||||||
|
|
||||||
type route struct {
|
type route struct {
|
||||||
pattern *regexp.Regexp
|
rule targetRule
|
||||||
handler http.Handler
|
handler http.Handler
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -21,22 +21,23 @@ type RegexpHandler struct {
|
||||||
routes []*route
|
routes []*route
|
||||||
}
|
}
|
||||||
|
|
||||||
func (h *RegexpHandler) Handler(pattern *regexp.Regexp, handler http.Handler) {
|
func (h *RegexpHandler) Handler(rule targetRule, handler http.Handler) {
|
||||||
h.routes = append(h.routes, &route{pattern, handler})
|
h.routes = append(h.routes, &route{rule, handler})
|
||||||
}
|
}
|
||||||
|
|
||||||
func (h *RegexpHandler) HandleFunc(pattern *regexp.Regexp, handler func(http.ResponseWriter, *http.Request)) {
|
func (h *RegexpHandler) HandleFunc(rule targetRule, handler func(http.ResponseWriter, *http.Request)) {
|
||||||
h.routes = append(h.routes, &route{pattern, http.HandlerFunc(handler)})
|
h.routes = append(h.routes, &route{rule, http.HandlerFunc(handler)})
|
||||||
}
|
}
|
||||||
|
|
||||||
func (h *RegexpHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
|
func (h *RegexpHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
|
||||||
timer := prometheus.NewTimer(requestDurationHistogram.WithLabelValues(h.handlerName))
|
timer := prometheus.NewTimer(requestDurationHistogram.WithLabelValues(h.handlerName))
|
||||||
defer timer.ObserveDuration()
|
defer timer.ObserveDuration()
|
||||||
|
|
||||||
for _, route := range h.routes {
|
for idx := range h.routes {
|
||||||
if route.pattern.MatchString(r.URL.Path) {
|
rule := h.routes[idx].rule
|
||||||
|
if h.routes[idx].rule.requestMatchTarget.Matches(r, rule.targetKey, rule.pattern) {
|
||||||
totalRequestCounter.WithLabelValues(h.handlerName, strconv.FormatBool(true)).Inc()
|
totalRequestCounter.WithLabelValues(h.handlerName, strconv.FormatBool(true)).Inc()
|
||||||
route.handler.ServeHTTP(w, r)
|
h.routes[idx].handler.ServeHTTP(w, r)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -52,7 +53,7 @@ func (h *RegexpHandler) setupRoute(rule targetRule) {
|
||||||
zap.String("response", rule.Response()),
|
zap.String("response", rule.Response()),
|
||||||
)
|
)
|
||||||
|
|
||||||
h.Handler(rule.Pattern(), createHandlerForTarget(h.logger, rule.response))
|
h.Handler(rule, createHandlerForTarget(h.logger, rule.response))
|
||||||
}
|
}
|
||||||
|
|
||||||
func createHandlerForTarget(logger logging.Logger, targetPath string) http.Handler {
|
func createHandlerForTarget(logger logging.Logger, targetPath string) http.Handler {
|
||||||
|
|
44
plugins/http_mock/register.go
Normal file
44
plugins/http_mock/register.go
Normal file
|
@ -0,0 +1,44 @@
|
||||||
|
package http_mock
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/prometheus/client_golang/prometheus"
|
||||||
|
"gitlab.com/inetmock/inetmock/pkg/api"
|
||||||
|
"gitlab.com/inetmock/inetmock/pkg/metrics"
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
totalRequestCounter *prometheus.CounterVec
|
||||||
|
requestDurationHistogram *prometheus.HistogramVec
|
||||||
|
)
|
||||||
|
|
||||||
|
func AddHTTPMock(registry api.HandlerRegistry) (err error) {
|
||||||
|
if totalRequestCounter == nil {
|
||||||
|
if totalRequestCounter, err = metrics.Counter(
|
||||||
|
name,
|
||||||
|
"total_requests",
|
||||||
|
"",
|
||||||
|
handlerNameLblName,
|
||||||
|
ruleMatchedLblName,
|
||||||
|
); err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if requestDurationHistogram == nil {
|
||||||
|
if requestDurationHistogram, err = metrics.Histogram(
|
||||||
|
name,
|
||||||
|
"request_duration",
|
||||||
|
"",
|
||||||
|
nil,
|
||||||
|
handlerNameLblName,
|
||||||
|
); err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
registry.RegisterHandler(name, func() api.ProtocolHandler {
|
||||||
|
return &httpHandler{}
|
||||||
|
})
|
||||||
|
|
||||||
|
return
|
||||||
|
}
|
|
@ -4,12 +4,13 @@ import (
|
||||||
"context"
|
"context"
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"github.com/baez90/inetmock/pkg/api"
|
"net/http"
|
||||||
"github.com/baez90/inetmock/pkg/config"
|
|
||||||
"github.com/baez90/inetmock/pkg/logging"
|
"gitlab.com/inetmock/inetmock/pkg/api"
|
||||||
|
"gitlab.com/inetmock/inetmock/pkg/config"
|
||||||
|
"gitlab.com/inetmock/inetmock/pkg/logging"
|
||||||
"go.uber.org/zap"
|
"go.uber.org/zap"
|
||||||
"gopkg.in/elazarl/goproxy.v1"
|
"gopkg.in/elazarl/goproxy.v1"
|
||||||
"net/http"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
|
@ -22,28 +23,28 @@ type httpProxy struct {
|
||||||
server *http.Server
|
server *http.Server
|
||||||
}
|
}
|
||||||
|
|
||||||
func (h *httpProxy) Start(config config.HandlerConfig) (err error) {
|
func (h *httpProxy) Start(ctx api.PluginContext, cfg config.HandlerConfig) (err error) {
|
||||||
var opts httpProxyOptions
|
var opts httpProxyOptions
|
||||||
if err = config.Options.Unmarshal(&opts); err != nil {
|
if err = cfg.Options.Unmarshal(&opts); err != nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
listenAddr := config.ListenAddr()
|
listenAddr := cfg.ListenAddr()
|
||||||
h.server = &http.Server{Addr: listenAddr, Handler: h.proxy}
|
h.server = &http.Server{Addr: listenAddr, Handler: h.proxy}
|
||||||
h.logger = h.logger.With(
|
h.logger = h.logger.With(
|
||||||
zap.String("handler_name", config.HandlerName),
|
zap.String("handler_name", cfg.HandlerName),
|
||||||
zap.String("address", listenAddr),
|
zap.String("address", listenAddr),
|
||||||
)
|
)
|
||||||
|
|
||||||
tlsConfig := api.ServicesInstance().CertStore().TLSConfig()
|
tlsConfig := ctx.CertStore().TLSConfig()
|
||||||
|
|
||||||
proxyHandler := &proxyHttpHandler{
|
proxyHandler := &proxyHttpHandler{
|
||||||
handlerName: config.HandlerName,
|
handlerName: cfg.HandlerName,
|
||||||
options: opts,
|
options: opts,
|
||||||
logger: h.logger,
|
logger: h.logger,
|
||||||
}
|
}
|
||||||
|
|
||||||
proxyHttpsHandler := &proxyHttpsHandler{
|
proxyHttpsHandler := &proxyHttpsHandler{
|
||||||
handlerName: config.HandlerName,
|
handlerName: cfg.HandlerName,
|
||||||
tlsConfig: tlsConfig,
|
tlsConfig: tlsConfig,
|
||||||
logger: h.logger,
|
logger: h.logger,
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,12 +3,13 @@ package http_proxy
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"crypto/tls"
|
"crypto/tls"
|
||||||
"github.com/baez90/inetmock/pkg/logging"
|
|
||||||
"github.com/prometheus/client_golang/prometheus"
|
|
||||||
"go.uber.org/zap"
|
|
||||||
"gopkg.in/elazarl/goproxy.v1"
|
|
||||||
"net/http"
|
"net/http"
|
||||||
"net/url"
|
"net/url"
|
||||||
|
|
||||||
|
"github.com/prometheus/client_golang/prometheus"
|
||||||
|
"gitlab.com/inetmock/inetmock/pkg/logging"
|
||||||
|
"go.uber.org/zap"
|
||||||
|
"gopkg.in/elazarl/goproxy.v1"
|
||||||
)
|
)
|
||||||
|
|
||||||
type proxyHttpHandler struct {
|
type proxyHttpHandler struct {
|
||||||
|
|
|
@ -1,10 +1,10 @@
|
||||||
package http_proxy
|
package http_proxy
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"github.com/baez90/inetmock/pkg/api"
|
|
||||||
"github.com/baez90/inetmock/pkg/logging"
|
|
||||||
"github.com/baez90/inetmock/pkg/metrics"
|
|
||||||
"github.com/prometheus/client_golang/prometheus"
|
"github.com/prometheus/client_golang/prometheus"
|
||||||
|
"gitlab.com/inetmock/inetmock/pkg/api"
|
||||||
|
"gitlab.com/inetmock/inetmock/pkg/logging"
|
||||||
|
"gitlab.com/inetmock/inetmock/pkg/metrics"
|
||||||
"go.uber.org/zap"
|
"go.uber.org/zap"
|
||||||
"gopkg.in/elazarl/goproxy.v1"
|
"gopkg.in/elazarl/goproxy.v1"
|
||||||
)
|
)
|
||||||
|
@ -16,32 +16,33 @@ var (
|
||||||
requestDurationHistogram *prometheus.HistogramVec
|
requestDurationHistogram *prometheus.HistogramVec
|
||||||
)
|
)
|
||||||
|
|
||||||
func init() {
|
func AddHTTPProxy(registry api.HandlerRegistry) (err error) {
|
||||||
var err error
|
|
||||||
var logger logging.Logger
|
var logger logging.Logger
|
||||||
if logger, err = logging.CreateLogger(); err != nil {
|
if logger, err = logging.CreateLogger(); err != nil {
|
||||||
panic(err)
|
return
|
||||||
}
|
}
|
||||||
logger = logger.With(
|
logger = logger.With(
|
||||||
zap.String("protocol_handler", name),
|
zap.String("protocol_handler", name),
|
||||||
)
|
)
|
||||||
|
|
||||||
if totalRequestCounter, err = metrics.Counter(name, "total_requests", "", handlerNameLblName); err != nil {
|
if totalRequestCounter, err = metrics.Counter(name, "total_requests", "", handlerNameLblName); err != nil {
|
||||||
panic(err)
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if requestDurationHistogram, err = metrics.Histogram(name, "request_duration", "", nil, handlerNameLblName); err != nil {
|
if requestDurationHistogram, err = metrics.Histogram(name, "request_duration", "", nil, handlerNameLblName); err != nil {
|
||||||
panic(err)
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if totalHttpsRequestCounter, err = metrics.Counter(name, "total_https_requests", "", handlerNameLblName); err != nil {
|
if totalHttpsRequestCounter, err = metrics.Counter(name, "total_https_requests", "", handlerNameLblName); err != nil {
|
||||||
panic(err)
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
api.Registry().RegisterHandler(name, func() api.ProtocolHandler {
|
registry.RegisterHandler(name, func() api.ProtocolHandler {
|
||||||
return &httpProxy{
|
return &httpProxy{
|
||||||
logger: logger,
|
logger: logger,
|
||||||
proxy: goproxy.NewProxyHttpServer(),
|
proxy: goproxy.NewProxyHttpServer(),
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
|
return
|
||||||
}
|
}
|
|
@ -3,11 +3,13 @@ package metrics_exporter
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"errors"
|
"errors"
|
||||||
"github.com/baez90/inetmock/pkg/config"
|
|
||||||
"github.com/baez90/inetmock/pkg/logging"
|
|
||||||
"github.com/prometheus/client_golang/prometheus/promhttp"
|
|
||||||
"go.uber.org/zap"
|
|
||||||
"net/http"
|
"net/http"
|
||||||
|
|
||||||
|
"github.com/prometheus/client_golang/prometheus/promhttp"
|
||||||
|
"gitlab.com/inetmock/inetmock/pkg/api"
|
||||||
|
"gitlab.com/inetmock/inetmock/pkg/config"
|
||||||
|
"gitlab.com/inetmock/inetmock/pkg/logging"
|
||||||
|
"go.uber.org/zap"
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
|
@ -19,7 +21,7 @@ type metricsExporter struct {
|
||||||
server *http.Server
|
server *http.Server
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m *metricsExporter) Start(config config.HandlerConfig) (err error) {
|
func (m *metricsExporter) Start(_ api.PluginContext, config config.HandlerConfig) (err error) {
|
||||||
exporterOptions := metricsExporterOptions{}
|
exporterOptions := metricsExporterOptions{}
|
||||||
if err = config.Options.Unmarshal(&exporterOptions); err != nil {
|
if err = config.Options.Unmarshal(&exporterOptions); err != nil {
|
||||||
return
|
return
|
||||||
|
|
|
@ -1,20 +0,0 @@
|
||||||
package metrics_exporter
|
|
||||||
|
|
||||||
import (
|
|
||||||
"github.com/baez90/inetmock/pkg/api"
|
|
||||||
"github.com/baez90/inetmock/pkg/logging"
|
|
||||||
"go.uber.org/zap"
|
|
||||||
)
|
|
||||||
|
|
||||||
func init() {
|
|
||||||
logger, _ := logging.CreateLogger()
|
|
||||||
logger = logger.With(
|
|
||||||
zap.String("protocol_handler", name),
|
|
||||||
)
|
|
||||||
|
|
||||||
api.Registry().RegisterHandler(name, func() api.ProtocolHandler {
|
|
||||||
return &metricsExporter{
|
|
||||||
logger: logger,
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
24
plugins/metrics_exporter/register.go
Normal file
24
plugins/metrics_exporter/register.go
Normal file
|
@ -0,0 +1,24 @@
|
||||||
|
package metrics_exporter
|
||||||
|
|
||||||
|
import (
|
||||||
|
"gitlab.com/inetmock/inetmock/pkg/api"
|
||||||
|
"gitlab.com/inetmock/inetmock/pkg/logging"
|
||||||
|
"go.uber.org/zap"
|
||||||
|
)
|
||||||
|
|
||||||
|
func AddMetricsExporter(registry api.HandlerRegistry) (err error) {
|
||||||
|
var logger logging.Logger
|
||||||
|
if logger, err = logging.CreateLogger(); err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
logger = logger.With(
|
||||||
|
zap.String("protocol_handler", name),
|
||||||
|
)
|
||||||
|
|
||||||
|
registry.RegisterHandler(name, func() api.ProtocolHandler {
|
||||||
|
return &metricsExporter{
|
||||||
|
logger: logger,
|
||||||
|
}
|
||||||
|
})
|
||||||
|
return
|
||||||
|
}
|
|
@ -4,15 +4,15 @@ import (
|
||||||
"context"
|
"context"
|
||||||
"crypto/tls"
|
"crypto/tls"
|
||||||
"fmt"
|
"fmt"
|
||||||
"github.com/baez90/inetmock/pkg/api"
|
|
||||||
"github.com/baez90/inetmock/pkg/cert"
|
|
||||||
"github.com/baez90/inetmock/pkg/config"
|
|
||||||
"github.com/baez90/inetmock/pkg/logging"
|
|
||||||
"github.com/google/uuid"
|
|
||||||
"github.com/prometheus/client_golang/prometheus"
|
|
||||||
"go.uber.org/zap"
|
|
||||||
"net"
|
"net"
|
||||||
"sync"
|
"sync"
|
||||||
|
|
||||||
|
"github.com/google/uuid"
|
||||||
|
"github.com/prometheus/client_golang/prometheus"
|
||||||
|
"gitlab.com/inetmock/inetmock/pkg/api"
|
||||||
|
"gitlab.com/inetmock/inetmock/pkg/config"
|
||||||
|
"gitlab.com/inetmock/inetmock/pkg/logging"
|
||||||
|
"go.uber.org/zap"
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
|
@ -24,16 +24,16 @@ type tlsInterceptor struct {
|
||||||
options tlsOptions
|
options tlsOptions
|
||||||
logger logging.Logger
|
logger logging.Logger
|
||||||
listener net.Listener
|
listener net.Listener
|
||||||
certStore cert.Store
|
|
||||||
shutdownRequested bool
|
shutdownRequested bool
|
||||||
currentConnectionsCount *sync.WaitGroup
|
currentConnectionsCount *sync.WaitGroup
|
||||||
currentConnections map[uuid.UUID]*proxyConn
|
currentConnections map[uuid.UUID]*proxyConn
|
||||||
connectionsMutex *sync.Mutex
|
connectionsMutex *sync.Mutex
|
||||||
}
|
}
|
||||||
|
|
||||||
func (t *tlsInterceptor) Start(config config.HandlerConfig) (err error) {
|
func (t *tlsInterceptor) Start(ctx api.PluginContext, config config.HandlerConfig) (err error) {
|
||||||
t.name = config.HandlerName
|
t.name = config.HandlerName
|
||||||
if err = config.Options.Unmarshal(&config.Options); err != nil {
|
|
||||||
|
if err = config.Options.Unmarshal(&t.options); err != nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -43,7 +43,7 @@ func (t *tlsInterceptor) Start(config config.HandlerConfig) (err error) {
|
||||||
zap.String("Target", t.options.Target.address()),
|
zap.String("Target", t.options.Target.address()),
|
||||||
)
|
)
|
||||||
|
|
||||||
if t.listener, err = tls.Listen("tcp", config.ListenAddr(), api.ServicesInstance().CertStore().TLSConfig()); err != nil {
|
if t.listener, err = tls.Listen("tcp", config.ListenAddr(), ctx.CertStore().TLSConfig()); err != nil {
|
||||||
t.logger.Fatal(
|
t.logger.Fatal(
|
||||||
"failed to create tls listener",
|
"failed to create tls listener",
|
||||||
zap.Error(err),
|
zap.Error(err),
|
||||||
|
|
|
@ -21,10 +21,10 @@ func chanFromConn(conn net.Conn) chan []byte {
|
||||||
for {
|
for {
|
||||||
n, err := conn.Read(b)
|
n, err := conn.Read(b)
|
||||||
if n > 0 {
|
if n > 0 {
|
||||||
res := make([]byte, n)
|
res := bufferPool.Get().([]byte)
|
||||||
// Copy the buffer so it doesn't get changed while read by the recipient.
|
// Copy the buffer so it doesn't get changed while read by the recipient.
|
||||||
copy(res, b[:n])
|
copy(res, b[:n])
|
||||||
c <- res
|
c <- res[:n]
|
||||||
}
|
}
|
||||||
if err != nil {
|
if err != nil {
|
||||||
c <- nil
|
c <- nil
|
||||||
|
|
|
@ -1,13 +1,14 @@
|
||||||
package tls_interceptor
|
package tls_interceptor
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"github.com/baez90/inetmock/pkg/api"
|
"sync"
|
||||||
"github.com/baez90/inetmock/pkg/logging"
|
|
||||||
"github.com/baez90/inetmock/pkg/metrics"
|
|
||||||
"github.com/google/uuid"
|
"github.com/google/uuid"
|
||||||
"github.com/prometheus/client_golang/prometheus"
|
"github.com/prometheus/client_golang/prometheus"
|
||||||
|
"gitlab.com/inetmock/inetmock/pkg/api"
|
||||||
|
"gitlab.com/inetmock/inetmock/pkg/logging"
|
||||||
|
"gitlab.com/inetmock/inetmock/pkg/metrics"
|
||||||
"go.uber.org/zap"
|
"go.uber.org/zap"
|
||||||
"sync"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
|
@ -17,8 +18,7 @@ var (
|
||||||
requestDurationHistogram *prometheus.HistogramVec
|
requestDurationHistogram *prometheus.HistogramVec
|
||||||
)
|
)
|
||||||
|
|
||||||
func init() {
|
func AddTLSInterceptor(registry api.HandlerRegistry) (err error) {
|
||||||
var err error
|
|
||||||
var logger logging.Logger
|
var logger logging.Logger
|
||||||
if logger, err = logging.CreateLogger(); err != nil {
|
if logger, err = logging.CreateLogger(); err != nil {
|
||||||
panic(err)
|
panic(err)
|
||||||
|
@ -28,16 +28,16 @@ func init() {
|
||||||
)
|
)
|
||||||
|
|
||||||
if handledRequestCounter, err = metrics.Counter(name, "handled_requests", "", labelNames...); err != nil {
|
if handledRequestCounter, err = metrics.Counter(name, "handled_requests", "", labelNames...); err != nil {
|
||||||
panic(err)
|
return
|
||||||
}
|
}
|
||||||
if openConnectionsGauge, err = metrics.Gauge(name, "open_connections", "", labelNames...); err != nil {
|
if openConnectionsGauge, err = metrics.Gauge(name, "open_connections", "", labelNames...); err != nil {
|
||||||
panic(err)
|
return
|
||||||
}
|
}
|
||||||
if requestDurationHistogram, err = metrics.Histogram(name, "request_duration", "", nil, labelNames...); err != nil {
|
if requestDurationHistogram, err = metrics.Histogram(name, "request_duration", "", nil, labelNames...); err != nil {
|
||||||
panic(err)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
api.Registry().RegisterHandler(name, func() api.ProtocolHandler {
|
registry.RegisterHandler(name, func() api.ProtocolHandler {
|
||||||
return &tlsInterceptor{
|
return &tlsInterceptor{
|
||||||
logger: logger,
|
logger: logger,
|
||||||
currentConnectionsCount: &sync.WaitGroup{},
|
currentConnectionsCount: &sync.WaitGroup{},
|
||||||
|
@ -45,4 +45,5 @@ func init() {
|
||||||
connectionsMutex: &sync.Mutex{},
|
connectionsMutex: &sync.Mutex{},
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
return
|
||||||
}
|
}
|
Loading…
Reference in a new issue