Add advanced matching options to HTTP handler

- move to Gitlab
- make code better testable
- create app abstraction for server
- cleanup
This commit is contained in:
Peter 2020-12-26 13:11:49 +00:00
parent 57a7e10e74
commit 49e58ac2e4
86 changed files with 1436 additions and 967 deletions

23
.editorconfig Normal file
View 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

View file

@ -21,7 +21,7 @@ jobs:
run: echo ${{ secrets.GITHUB_TOKEN }} | docker login docker.pkg.github.com -u baez90 --password-stdin
- 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
run: |

View file

@ -1,6 +1,6 @@
name: Go
on: [push, pull_request]
on: [ push, pull_request ]
jobs:
@ -9,42 +9,41 @@ jobs:
runs-on: ubuntu-latest
steps:
- name: Set up Go 1.14
uses: actions/setup-go@v1
with:
go-version: 1.14.x
id: go
- name: Set up Go 1.15
uses: actions/setup-go@v2
with:
go-version: '^1.15'
id: go
- name: Install Protoc
uses: arduino/setup-protoc@master
with:
version: '3.x'
- name: Install Protoc
uses: arduino/setup-protoc@master
with:
version: '3.x'
- name: Check out code into the Go module directory
uses: actions/checkout@v2
with:
lfs: true
- name: Check out code into the Go module directory
uses: actions/checkout@v2
with:
lfs: true
- name: Install mockgen
run: go get -u github.com/golang/mock/mockgen@latest
- name: Install mockgen
run: go get -u github.com/golang/mock/mockgen@latest
- name: Install go-enuum
run: go get -u github.com/abice/go-enum
- name: Install go-enuum
run: go get -u github.com/abice/go-enum
- name: Install protoc-gen-go
run: go install github.com/golang/protobuf/protoc-gen-go
- name: Unshallow
run: git fetch --prune --unshallow
- name: Install protoc-gen-go
run: go install github.com/golang/protobuf/protoc-gen-go
- name: Build & test
run: make
- name: Unshallow
run: git fetch --prune --unshallow
- name: Run GoReleaser
uses: goreleaser/goreleaser-action@v1
with:
version: latest
args: release --rm-dist
key: ${{ secrets.YOUR_PRIVATE_KEY }}
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
- name: Build & test
run: make
- name: Run GoReleaser
uses: goreleaser/goreleaser-action@v2
with:
version: latest
args: release --rm-dist
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}

4
.gitignore vendored
View file

@ -11,6 +11,7 @@
/imctl
./main
**/*.mock.go
**/*_enum.go
**/*.pb.go
###############
@ -20,4 +21,5 @@
.idea/
.vscode/
dist/
out/
out/
.task/

41
.gitlab-ci.yml Normal file
View 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
View 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"

View file

@ -3,7 +3,7 @@
before:
hooks:
# You may remove this if you don't use go modules.
- make generate
- task generate
builds:
- id: "inetmock"
binary: inetmock
@ -11,12 +11,12 @@ builds:
ldflags:
- -w -s
env:
- CGO_ENABLED=0
- CGO_ENABLED=0
goos:
- linux
- darwin
- linux
- darwin
goarch:
- amd64
- amd64
- id: "imctl"
binary: imctl
main: ./cmd/imctl/main.go
@ -32,7 +32,7 @@ builds:
archives:
- id: inetmock
builds:
- inetmock
- inetmock
name_template: "{{ .ProjectName }}_server_{{ .Version }}_{{ .Os }}_{{ .Arch }}"
replacements:
amd64: x86_64
@ -47,7 +47,7 @@ archives:
replacements:
amd64: x86_64
wrap_in_directory: true
files: []
files: [ ]
checksum:
name_template: 'checksums.txt'
snapshot:
@ -56,5 +56,29 @@ changelog:
sort: asc
filters:
exclude:
- '^docs:'
- '^test:'
- '^docs:'
- '^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/

View file

@ -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

View file

@ -1,7 +1,7 @@
# INetMock
![Go](https://github.com/baez90/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](https://gitlab.com/inetmock/inetmock/workflows/Go/badge.svg)
[![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)
[![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)
@ -12,22 +12,26 @@
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.
INetMock right now does **not** implement so many protocols like INetSim.
In fact it is only able to respond to HTTP, HTTPS, DNS, DNS-over-TLS (DoT) requests and to act as an HTTP proxy.
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.
INetMock right now does **not** implement so many protocols like INetSim. In fact it is only able to respond to HTTP,
HTTPS, DNS, DNS-over-TLS (DoT) requests and to act as an HTTP proxy. 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.
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.
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).
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. 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 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
Please create an issue for any proposal, feature requests, found bug,...
I'm glad for every kind of feedback!
Please create an issue for any proposal, feature requests, found bug,... 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.

98
Taskfile.yml Normal file
View 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

View file

@ -1,6 +1,6 @@
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_package = "com.github.baez90.inetmock.rpc";
option java_outer_classname = "EndpointsProto";

View file

@ -1,6 +1,6 @@
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_package = "com.github.baez90.inetmock.rpc";
option java_outer_classname = "HandlersProto";
@ -8,7 +8,8 @@ option java_outer_classname = "HandlersProto";
package inetmock;
service Handlers {
rpc GetHandlers(GetHandlersRequest) returns (GetHandlersResponse) {}
rpc GetHandlers (GetHandlersRequest) returns (GetHandlersResponse) {
}
}
message GetHandlersRequest {

View file

@ -1,6 +1,6 @@
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_package = "com.github.baez90.inetmock.rpc";
option java_outer_classname = "HealthProto";
@ -8,7 +8,8 @@ option java_outer_classname = "HealthProto";
package inetmock;
service Health {
rpc GetHealth(HealthRequest) returns (HealthResponse) {}
rpc GetHealth (HealthRequest) returns (HealthResponse) {
}
}
enum HealthState {

View file

@ -1,4 +1,5 @@
FROM golang:1.15-alpine as build
# Runtime layer
FROM alpine:3.12
# Create appuser and group.
ARG USER=inetmock
@ -6,13 +7,7 @@ ARG GROUP=inetmock
ARG USER_ID=10001
ARG GROUP_ID=10001
ENV CGO_ENABLED=0
# 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}" && \
RUN addgroup -S -g "${GROUP_ID}" "${GROUP}" && \
adduser \
--disabled-password \
--gecos "" \
@ -23,31 +18,8 @@ RUN apk add -U --no-cache \
--uid "${USER_ID}" \
"${USER}"
# Fetch dependencies
COPY Makefile go.mod go.sum ./
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 --chown=$USER:$GROUP inetmock imctl /usr/lib/inetmock/bin/
COPY --chown=$USER:$GROUP assets/fakeFiles /var/lib/inetmock/fakeFiles/
COPY config-container.yaml /etc/inetmock/config.yaml
RUN mkdir -p /var/run/inetmock /var/lib/inetmock/certs /usr/lib/inetmock && \

View file

@ -1,6 +1,6 @@
package main
import "github.com/baez90/inetmock/internal/cmd"
import "gitlab.com/inetmock/inetmock/internal/cmd"
func main() {
if err := cmd.ExecuteClientCommand(); err != nil {

View file

@ -1,25 +1,24 @@
package main
import (
"github.com/baez90/inetmock/internal/cmd"
"go.uber.org/zap"
"os"
"fmt"
_ "github.com/baez90/inetmock/plugins/dns_mock"
_ "github.com/baez90/inetmock/plugins/http_mock"
_ "github.com/baez90/inetmock/plugins/http_proxy"
_ "github.com/baez90/inetmock/plugins/metrics_exporter"
_ "github.com/baez90/inetmock/plugins/tls_interceptor"
"gitlab.com/inetmock/inetmock/internal/cmd"
_ "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"
"go.uber.org/zap"
)
func main() {
logger, _ := zap.NewProduction()
defer logger.Sync()
defer func() {
if err := logger.Sync(); err != nil {
fmt.Printf(err.Error())
}
}()
if err := cmd.ExecuteServerCommand(); err != nil {
logger.Error("Failed to run inetmock",
zap.Error(err),
)
os.Exit(1)
}
cmd.ExecuteServerCommand()
}

View file

@ -39,15 +39,15 @@ endpoints:
handler: http_mock
listenAddress: 0.0.0.0
ports:
- 80
- 8080
- 80
- 8080
options:
<<: *httpResponseRules
proxy:
handler: http_proxy
listenAddress: 0.0.0.0
ports:
- 3128
- 3128
options:
target:
ipAddress: 127.0.0.1
@ -56,8 +56,8 @@ endpoints:
handler: tls_interceptor
listenAddress: 0.0.0.0
ports:
- 443
- 8443
- 443
- 8443
options:
target:
ipAddress: 127.0.0.1
@ -66,7 +66,7 @@ endpoints:
handler: dns_mock
listenAddress: 0.0.0.0
ports:
- 53
- 53
options:
rules:
- pattern: ".*\\.google\\.com"
@ -81,7 +81,7 @@ endpoints:
handler: tls_interceptor
listenAddress: 0.0.0.0
ports:
- 853
- 853
options:
target:
ipAddress: 127.0.0.1

View file

@ -1,18 +1,44 @@
x-response-rules: &httpResponseRules
rules:
- pattern: ".*\\.(?i)exe"
matcher: Path
- pattern: "^application/octet-stream$"
target: Accept
matcher: Header
response: ./assets/fakeFiles/sample.exe
- pattern: ".*\\.(?i)(jpg|jpeg)"
- pattern: "^image/jpeg$"
target: Accept
matcher: Header
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"
matcher: Path
response: ./assets/fakeFiles/default.png
- pattern: ".*\\.(?i)gif"
matcher: Path
response: ./assets/fakeFiles/default.gif
- pattern: ".*\\.(?i)ico"
matcher: Path
response: ./assets/fakeFiles/default.ico
- pattern: ".*\\.(?i)txt"
- pattern: "^text/plain$"
target: Accept
matcher: Header
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: ".*"
matcher: Path
response: ./assets/fakeFiles/default.html
api:
@ -39,15 +65,15 @@ endpoints:
handler: http_mock
listenAddress: 0.0.0.0
ports:
- 80
- 8080
- 80
- 8080
options:
<<: *httpResponseRules
proxy:
handler: http_proxy
listenAddress: 0.0.0.0
ports:
- 3128
- 3128
options:
target:
ipAddress: 127.0.0.1
@ -56,8 +82,8 @@ endpoints:
handler: tls_interceptor
listenAddress: 0.0.0.0
ports:
- 443
- 8443
- 443
- 8443
options:
target:
ipAddress: 127.0.0.1
@ -66,7 +92,7 @@ endpoints:
handler: dns_mock
listenAddress: 0.0.0.0
ports:
- 53
- 53
options:
rules:
- pattern: ".*\\.google\\.com"
@ -81,7 +107,7 @@ endpoints:
handler: tls_interceptor
listenAddress: 0.0.0.0
ports:
- 853
- 853
options:
target:
ipAddress: 127.0.0.1

View file

@ -2,8 +2,8 @@
## Plugins & handlers
_INetMock_ is based on plugins that ship one or more __protocol handlers__.
Examples for protocol handlers are HTTP or DNS but also TLS.
_INetMock_ is based on plugins that ship one or more __protocol handlers__. Examples for protocol handlers are HTTP or
DNS but also TLS.
The application ships with the following handlers:
@ -11,9 +11,11 @@ The application ships with the following handlers:
* `dns_mock`
* `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`.
This way the whole system is very flexible and can be configured for various individual scenarios.
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`. This way the whole system is very flexible and can be configured
for various individual scenarios.
## 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.

View file

@ -3,12 +3,12 @@
## Intro
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.
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.
Currently only queries for __A__ records are supported. 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.
The rules for the `dns_mock` handler are equivalent to the `http_mock` rules.
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.
These rules are evaluated in the same order they are defined in the `config.yaml`.
The rules for the `dns_mock` handler are equivalent to the `http_mock` rules. 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. 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.
@ -17,18 +17,19 @@ Right now the following fallback strategies are available:
* _random_
* _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
The _random_ fallback strategy is the easier one of the both.
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.
The _random_ fallback strategy is the easier one of the both. 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.
### _incremental_ fallback
The _incremental_ fallback is little bit more intelligent.
It takes a `startIP` as an argument which defines from which IP address the strategy starts counting up to respond to DNS queries.
Just like the _incremental_ strategy it is _stateless_ and does not store any already given response for later reuse (at least for now).
The _incremental_ fallback is little bit more intelligent. It takes a `startIP` as an argument which defines from which
IP address the strategy starts counting up to respond to DNS queries. Just like the _incremental_ strategy it is _
stateless_ and does not store any already given response for later reuse (at least for now).
## Configuration
@ -50,8 +51,9 @@ endpoints:
### 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.
But it's also possible to match a whole domain no matter what subdomain or sub-subdomain or whatever is requested like this:
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. But it's also possible to match a whole domain no matter
what subdomain or sub-subdomain or whatever is requested like this:
```yml
endpoints:
@ -67,8 +69,8 @@ endpoints:
### Matching a whole TLD
In some cases it might also be interesting to distinguish between different requested TLDs.
Therefore it might be interesting to define one IP address to resolve to for every TLD that should be distinguishable.
In some cases it might also be interesting to distinguish between different requested TLDs. Therefore it might be
interesting to define one IP address to resolve to for every TLD that should be distinguishable.
```yml
endpoints:
@ -84,8 +86,8 @@ endpoints:
### Matching any query
Last but not least it is obvously also possible to match any query.
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.
Last but not least it is obvously also possible to match any query. 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.
```yml
endpoints:
@ -103,9 +105,9 @@ endpoints:
#### _random_
Like previously mentioned the _random_ strategy is easy as it can be.
It just takes a random unsigned integer of 32 bits, converts it to an IP address and returns this address as response.
Therefore no further configuration is necessary for now.
Like previously mentioned the _random_ strategy is easy as it can be. It just takes a random unsigned integer of 32
bits, converts it to an IP address and returns this address as response. Therefore no further configuration is necessary
for now.
```yml
endpoints:
@ -121,9 +123,9 @@ endpoints:
#### _incremental_
Also like previously mentioned the _incremental_ fallback strategy is fairly easy to setup.
It just takes a `startIP` as argument which is used to count upwards.
It does __not__ check for an interval or something like this right now so a overflow might occur.
Also like previously mentioned the _incremental_ fallback strategy is fairly easy to setup. It just takes a `startIP` as
argument which is used to count upwards. It does __not__ check for an interval or something like this right now so a
overflow might occur.
```yml
endpoints:

View file

@ -2,10 +2,12 @@
## Intro
The `http_mock` handler expects an array of rules how it should respond to different request paths.
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"_.
The `http_mock` handler expects an array of rules how it should respond to different request paths. 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"_.
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`.
@ -33,8 +35,8 @@ endpoints:
### Matching a file extensions
While matching a static path might be nice as an example it's not very useful.
Returning a given file for all kinds of of request paths based on the requested file extension is way more handy:
While matching a static path might be nice as an example it's not very useful. Returning a given file for all kinds of
of request paths based on the requested file extension is way more handy:
```yml
endpoints:
@ -62,7 +64,8 @@ endpoints:
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.

View file

@ -1,14 +1,15 @@
# `config.yaml`
## Intro
The configuration of _INetMock_ is mostly done in the `config.yaml`.
It defines which endpoints should be started with which handler and a few more things.
The configuration of _INetMock_ is mostly done in the `config.yaml`. It defines which endpoints should be started with
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
* HTTPS

8
go.mod
View file

@ -1,11 +1,11 @@
module github.com/baez90/inetmock
module gitlab.com/inetmock/inetmock
go 1.15
require (
github.com/golang/mock v1.4.4
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/olekukonko/tablewriter v0.0.4
github.com/prometheus/client_golang v1.7.1
@ -13,8 +13,8 @@ require (
github.com/spf13/pflag v1.0.5
github.com/spf13/viper v1.7.1
go.uber.org/zap v1.16.0
google.golang.org/grpc v1.29.1
google.golang.org/protobuf v1.23.0
google.golang.org/grpc v1.34.0
google.golang.org/protobuf v1.25.0
gopkg.in/elazarl/goproxy.v1 v1.0.0-20180725130230-947c36da3153
gopkg.in/yaml.v3 v3.0.0-20200615113413-eeeca48fe776
)

88
go.sum
View file

@ -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/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-20200629203442-efcf912fb354/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk=
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.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/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/elazarl/goproxy v0.0.0-20200809112317-0581fc3aee2d h1:rtM8HsT3NG37YPjz8sYSbUSdElP9lUsQENYzJDZDUBE=
github.com/elazarl/goproxy v0.0.0-20200809112317-0581fc3aee2d/go.mod h1:Ro8st/ElPeALwNFlcTpWmkr6IoMFfkjXAvTHpevnDsM=
github.com/elazarl/goproxy v0.0.0-20201021153353-00ad82a08272 h1:Am81SElhR3XCQBunTisljzNkNese2T1FiV8jP79+dqg=
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-20200809112317-0581fc3aee2d h1:st1tmvy+4duoRj+RaeeJoECWCWM015fBtf/4aR+hhqk=
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 h1:xOHQWEGsftkjjFV2KIrC9vOz+iOinvZ7H6EAjSznqUk=
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.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.7/go.mod h1:cwu0lG7PUMfa9snN8LXBig5ynNVH9qI8YYLbd1fK2po=
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/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.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/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=
@ -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.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.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/go.mod h1:l3mdAwkq5BuhzHwde/uurv3sEJeZMXNpwsxVWU71h+4=
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.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.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QDs8UjoX8=
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.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 v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
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.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.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/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs=
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/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.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.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk=
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/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/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/pretty v0.1.0 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI=
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.1 h1:ZC2Vc7/ZFkGmsVC9KvOjumD+G5lXy2RtTKyzRKO2BQ4=
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-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/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/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0=
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 v1.1.2 h1:fmNYVwqnSfB9mZU6OS2O6GsXM+wcskZDuKQzvN1EDeE=
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-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
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/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.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.1 h1:iURUrRGxPUNPdy5/HRSm+Yj6okJ6UtLINN0Q9M4+h3I=
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/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
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/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.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/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/go.mod h1:/6GTrnGXV9HjY+aR4k0oJ5tcvakLuG6EuKReYlHNrgE=
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.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.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA=
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.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/go.mod h1:8WkrPz2fc9jxqZNCJI/76HCieCp4Q8HaLFoCha5qpdg=
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.4.0 h1:2E4SXV/wtOkTonXsotYi4li6zVWxYlZuYNCXe9XRJyk=
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/go.mod h1:N0PQaV/YGNqwC0u51sEeR/aUtSLEXKX9iv69rRypqCw=
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.6.0 h1:Ezj3JGmsOnG1MoRWQkPBsKLe9DwWD9QeXzTRzzldNVk=
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.5.0 h1:KCa4XfM8CWFCpxXRGok+Q0SS/0XBhMDbHHGABQLvD2A=
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/go.mod h1:vJERXedbb3MVM5f9Ejo0C68/HhF8uaILCdgjnY+goOA=
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/go.mod h1:MA8QOfq0BHJwdXa996Y4dYkAqRKB8/1K1QMMZVaNZjQ=
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-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-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/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-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
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-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-20200930145003-4acb6c075d10 h1:YfxMZzv3PjGonQYNUaeU2+DhAdqOxerQ30JFB6WgAXo=
golang.org/x/net v0.0.0-20200930145003-4acb6c075d10/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
golang.org/x/net v0.0.0-20201224014010-6772e930b67b h1:iFwSg7t5GZmB/Q5TjiEAsdoLDrdJRC1RiF2WhuV29Qw=
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-20190226205417-e64efc72b421/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/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-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/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f h1:+Nyd8tzPX9R7BWHguqsrbFdRx3WQ/1ib8I44HXV5yTA=
golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20201223074533-0d417f636930 h1:vRgIt+nup/B/BwIS0g2oC0haq0iqbV3ZA+u6+0TlNCo=
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.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/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.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-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
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-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-20191216052735-49a3e744a425 h1:VvQyQJN0tSuecqgcIxMWnnfG5kSmgy9KZR9sW3W5QeA=
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-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-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-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.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.1/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM=
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.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/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-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 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.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/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/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=
@ -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/ini.v1 v1.51.0 h1:AQvPpx3LzTDM0AjnIRlVFwFFGC+npRopjZxLJj6gdno=
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/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=
@ -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.5 h1:ymVxjfMaHvXD8RqPRmzHHsB3VvucivSkIAvJFDI5O3c=
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/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
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/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg=
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
View 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
}

View file

@ -3,12 +3,13 @@ package cmd
import (
"crypto/tls"
"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"
"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 (
@ -58,6 +59,8 @@ func runGenerateCA(_ *cobra.Command, _ []string) {
var notBefore, notAfter time.Duration
var err error
logger := server.Logger().Named("generate-ca")
if certOutPath, err = getStringFlag(generateCaCmd, generateCACertOutPath, logger); err != nil {
return
}
@ -71,8 +74,6 @@ func runGenerateCA(_ *cobra.Command, _ []string) {
return
}
logger, _ := logging.CreateLogger()
logger = logger.With(
zap.String(generateCACurveName, curveName),
zap.String(generateCACertOutPath, certOutPath),

View file

@ -1,8 +1,9 @@
package cmd
import (
"github.com/spf13/cobra"
"time"
"github.com/spf13/cobra"
)
var (

View file

@ -3,11 +3,12 @@ package cmd
import (
"context"
"fmt"
"github.com/baez90/inetmock/internal/format"
"github.com/baez90/inetmock/internal/rpc"
"github.com/spf13/cobra"
"google.golang.org/grpc"
"os"
"github.com/spf13/cobra"
"gitlab.com/inetmock/inetmock/internal/format"
"gitlab.com/inetmock/inetmock/internal/rpc"
"google.golang.org/grpc"
)
var (

View file

@ -3,11 +3,12 @@ package cmd
import (
"context"
"fmt"
"github.com/baez90/inetmock/internal/format"
"github.com/baez90/inetmock/internal/rpc"
"github.com/spf13/cobra"
"google.golang.org/grpc"
"os"
"github.com/spf13/cobra"
"gitlab.com/inetmock/inetmock/internal/format"
"gitlab.com/inetmock/inetmock/internal/rpc"
"google.golang.org/grpc"
)
var (

View file

@ -3,11 +3,12 @@ package cmd
import (
"context"
"fmt"
"github.com/baez90/inetmock/internal/format"
"github.com/baez90/inetmock/internal/rpc"
"github.com/spf13/cobra"
"google.golang.org/grpc"
"os"
"github.com/spf13/cobra"
"gitlab.com/inetmock/inetmock/internal/format"
"gitlab.com/inetmock/inetmock/internal/rpc"
"google.golang.org/grpc"
)
var (

View file

@ -1,24 +1,16 @@
package cmd
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"
"syscall"
"github.com/spf13/cobra"
"gitlab.com/inetmock/inetmock/internal/rpc"
"gitlab.com/inetmock/inetmock/pkg/config"
"go.uber.org/zap"
)
var (
endpointManager endpoints.EndpointManager
serveCmd = &cobra.Command{
serveCmd = &cobra.Command{
Use: "serve",
Short: "Starts the INetMock server",
Long: ``,
@ -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) {
if err := onServerInit(); err != nil {
panic(err)
}
endpointManager = endpoints.NewEndpointManager(health.CheckerInstance(), logger)
cfg := config.Instance()
rpcAPI := rpc.NewINetMockAPI(
cfg,
endpointManager,
api.Registry(),
)
rpcAPI := rpc.NewINetMockAPI(server)
logger := server.Logger().Named("inetmock").With(zap.String("command", "serve"))
for endpointName, endpointHandler := range cfg.EndpointConfigs() {
handlerSubConfig := cfg.Viper().Sub(strings.Join([]string{config.EndpointsKey, endpointName, config.OptionsKey}, "."))
for endpointName, endpointHandler := range server.Config().EndpointConfigs() {
handlerSubConfig := server.Config().Viper().Sub(strings.Join([]string{config.EndpointsKey, endpointName, config.OptionsKey}, "."))
endpointHandler.Options = handlerSubConfig
if err := endpointManager.CreateEndpoint(endpointName, endpointHandler); err != nil {
if err := server.EndpointManager().CreateEndpoint(endpointName, endpointHandler); err != nil {
logger.Warn(
"error occurred while creating endpoint",
zap.String("endpointName", endpointName),
@ -80,7 +35,7 @@ func startINetMock(_ *cobra.Command, _ []string) {
}
}
endpointManager.StartEndpoints()
server.EndpointManager().StartEndpoints()
if err := rpcAPI.StartServer(); err != nil {
logger.Error(
"failed to start gRPC API",
@ -88,17 +43,12 @@ func startINetMock(_ *cobra.Command, _ []string) {
)
}
signalChannel := make(chan os.Signal, 1)
signal.Notify(signalChannel, syscall.SIGINT, syscall.SIGTERM, syscall.SIGQUIT)
// block until canceled
s := <-signalChannel
<-server.Context().Done()
logger.Info(
"got signal to quit",
zap.String("signal", s.String()),
"App context canceled - shutting down",
)
rpcAPI.StopServer()
endpointManager.ShutdownEndpoints()
server.EndpointManager().ShutdownEndpoints()
}

View file

@ -1,35 +1,34 @@
package cmd
import (
"github.com/baez90/inetmock/pkg/logging"
"github.com/spf13/cobra"
"fmt"
"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 (
logger logging.Logger
serverCmd *cobra.Command
configFilePath string
logLevel string
developmentLogs bool
server app.App
)
func init() {
serverCmd = &cobra.Command{
Use: "",
Short: "INetMock is lightweight internet mock",
func ExecuteServerCommand() {
var err error
if server, err = app.NewApp(
http_mock.AddHTTPMock,
dns_mock.AddDNSMock,
tls_interceptor.AddTLSInterceptor,
http_proxy.AddHTTPProxy,
metrics_exporter.AddMetricsExporter,
); err != nil {
fmt.Println(err.Error())
os.Exit(1)
}
serverCmd.PersistentFlags().StringVar(&configFilePath, "config", "", "Path to config file that should be used")
serverCmd.PersistentFlags().StringVar(&logLevel, "log-level", "info", "logging level to use")
serverCmd.PersistentFlags().BoolVar(&developmentLogs, "development-logs", false, "Enable development mode logs")
serverCmd.AddCommand(
serveCmd,
generateCaCmd,
)
}
func ExecuteServerCommand() error {
return serverCmd.Execute()
server.
WithCommands(serveCmd, generateCaCmd).
MustRun()
}

View file

@ -3,14 +3,15 @@ package endpoints
import (
"context"
"github.com/baez90/inetmock/pkg/api"
"github.com/baez90/inetmock/pkg/config"
"github.com/google/uuid"
"gitlab.com/inetmock/inetmock/pkg/api"
"gitlab.com/inetmock/inetmock/pkg/config"
)
type Endpoint interface {
Id() uuid.UUID
Start() error
Start(ctx api.PluginContext) error
Shutdown(ctx context.Context) error
Name() string
Handler() string
@ -45,8 +46,8 @@ func (e endpoint) Port() uint16 {
return e.config.Port
}
func (e *endpoint) Start() (err error) {
return e.handler.Start(e.config)
func (e *endpoint) Start(ctx api.PluginContext) (err error) {
return e.handler.Start(ctx, e.config)
}
func (e *endpoint) Shutdown(ctx context.Context) (err error) {

View file

@ -3,14 +3,15 @@ package endpoints
import (
"context"
"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"
"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 (
@ -20,25 +21,27 @@ const (
type EndpointManager interface {
RegisteredEndpoints() []Endpoint
StartedEndpoints() []Endpoint
CreateEndpoint(name string, multiHandlerConfig config.MultiHandlerConfig) error
CreateEndpoint(name string, multiHandlerConfig config.EndpointConfig) error
StartEndpoints()
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{
logger: logger,
checker: checker,
registry: api.Registry(),
registry: registry,
logger: logging,
checker: checker,
pluginContext: pluginContext,
}
}
type endpointManager struct {
registry api.HandlerRegistry
logger logging.Logger
checker health.Checker
pluginContext api.PluginContext
registeredEndpoints []Endpoint
properlyStartedEndpoints []Endpoint
registry api.HandlerRegistry
}
func (e endpointManager) RegisteredEndpoints() []Endpoint {
@ -49,9 +52,9 @@ func (e endpointManager) StartedEndpoints() []Endpoint {
return e.properlyStartedEndpoints
}
func (e *endpointManager) CreateEndpoint(name string, multiHandlerConfig config.MultiHandlerConfig) error {
for _, handlerConfig := range multiHandlerConfig.HandlerConfigs() {
if handler, ok := e.registry.HandlerForName(multiHandlerConfig.Handler); ok {
func (e *endpointManager) CreateEndpoint(name string, endpointConfig config.EndpointConfig) error {
for _, handlerConfig := range endpointConfig.HandlerConfigs() {
if handler, ok := e.registry.HandlerForName(endpointConfig.Handler); ok {
e.registeredEndpoints = append(e.registeredEndpoints, &endpoint{
id: uuid.New(),
name: name,
@ -59,7 +62,7 @@ func (e *endpointManager) CreateEndpoint(name string, multiHandlerConfig config.
config: handlerConfig,
})
} 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()),
)
endpointLogger.Info("Starting endpoint")
if ok := startEndpoint(endpoint, endpointLogger); ok {
if ok := startEndpoint(endpoint, e.pluginContext, endpointLogger); ok {
_ = e.checker.RegisterCheck(
endpointComponentName(endpoint),
health.StaticResultCheckWithMessage(health.HEALTHY, "Successfully started"),
@ -115,7 +118,7 @@ func (e *endpointManager) ShutdownEndpoints() {
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)
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(
"failed to start endpoint",
zap.Error(err),
@ -146,6 +149,8 @@ func startEndpoint(ep Endpoint, logger logging.Logger) (success bool) {
success = false
}
close(startSuccessful)
return
}

View file

@ -1,27 +1,27 @@
package endpoints
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"
"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) {
type fields struct {
logger logging.Logger
registeredEndpoints []Endpoint
properlyStartedEndpoints []Endpoint
registry api.HandlerRegistry
logger logging.Logger
registry api.HandlerRegistry
}
type args struct {
name string
multiHandlerConfig config.MultiHandlerConfig
multiHandlerConfig config.EndpointConfig
}
tests := []struct {
name string
@ -38,8 +38,6 @@ func Test_endpointManager_CreateEndpoint(t *testing.T) {
logger: func() logging.Logger {
return logging_mock.NewMockLogger(gomock.NewController(t))
}(),
registeredEndpoints: nil,
properlyStartedEndpoints: nil,
registry: func() api.HandlerRegistry {
registry := plugins_mock.NewMockHandlerRegistry(gomock.NewController(t))
registry.
@ -53,7 +51,7 @@ func Test_endpointManager_CreateEndpoint(t *testing.T) {
},
args: args{
name: "sampleEndpoint",
multiHandlerConfig: config.MultiHandlerConfig{
multiHandlerConfig: config.EndpointConfig{
Handler: "sampleHandler",
Ports: []uint16{80},
ListenAddress: "0.0.0.0",
@ -68,8 +66,6 @@ func Test_endpointManager_CreateEndpoint(t *testing.T) {
logger: func() logging.Logger {
return logging_mock.NewMockLogger(gomock.NewController(t))
}(),
registeredEndpoints: nil,
properlyStartedEndpoints: nil,
registry: func() api.HandlerRegistry {
registry := plugins_mock.NewMockHandlerRegistry(gomock.NewController(t))
registry.
@ -83,7 +79,7 @@ func Test_endpointManager_CreateEndpoint(t *testing.T) {
},
args: args{
name: "sampleEndpoint",
multiHandlerConfig: config.MultiHandlerConfig{
multiHandlerConfig: config.EndpointConfig{
Handler: "sampleHandler",
Ports: []uint16{80},
ListenAddress: "0.0.0.0",
@ -93,13 +89,7 @@ func Test_endpointManager_CreateEndpoint(t *testing.T) {
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
e := &endpointManager{
logger: tt.fields.logger,
registeredEndpoints: tt.fields.registeredEndpoints,
properlyStartedEndpoints: tt.fields.properlyStartedEndpoints,
registry: tt.fields.registry,
}
e := NewEndpointManager(tt.fields.registry, tt.fields.logger, health.New(), nil)
if err := e.CreateEndpoint(tt.args.name, tt.args.multiHandlerConfig); (err != nil) != 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,
registeredEndpoints: tt.fields.registeredEndpoints,
properlyStartedEndpoints: tt.fields.properlyStartedEndpoints,
registry: tt.fields.registry,
}
if got := e.StartedEndpoints(); !reflect.DeepEqual(got, tt.want) {
t.Errorf("StartedEndpoints() = %v, want %v", got, tt.want)

View file

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

View file

@ -2,10 +2,11 @@ package format
import (
"encoding/json"
"github.com/olekukonko/tablewriter"
"gopkg.in/yaml.v3"
"io"
"strings"
"github.com/olekukonko/tablewriter"
"gopkg.in/yaml.v3"
)
type consoleWriterFactory func(io.Writer) ConsoleWriter

View file

@ -3,9 +3,10 @@ package format
import (
"errors"
"fmt"
"github.com/olekukonko/tablewriter"
"reflect"
"strconv"
"github.com/olekukonko/tablewriter"
)
type tblWriter struct {
@ -59,7 +60,7 @@ func (t *tblWriter) Write(in interface{}) (err error) {
t.tableWriter.Render()
t.tableWriter.ClearRows()
return
return err
}
func (t *tblWriter) getData(val reflect.Value, numberOfFields int) (data []string) {

View file

@ -2,10 +2,12 @@ package rpc
import (
"context"
"github.com/baez90/inetmock/internal/endpoints"
"gitlab.com/inetmock/inetmock/internal/endpoints"
)
type endpointsServer struct {
UnimplementedEndpointsServer
endpointsManager endpoints.EndpointManager
}

View file

@ -1,15 +1,14 @@
package rpc
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/url"
"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 {
@ -18,23 +17,20 @@ type INetMockAPI interface {
}
type inetmockAPI struct {
url *url.URL
server *grpc.Server
endpointManager endpoints.EndpointManager
registry api.HandlerRegistry
logger logging.Logger
serverRunning bool
app app2.App
url *url.URL
server *grpc.Server
logger logging.Logger
serverRunning bool
}
func NewINetMockAPI(
config config.Config,
epMgr endpoints.EndpointManager,
registry api.HandlerRegistry,
app app2.App,
) INetMockAPI {
return &inetmockAPI{
url: config.APIConfig().ListenURL(),
endpointManager: epMgr,
registry: registry,
app: app,
url: app.Config().APIConfig().ListenURL(),
logger: app.Logger().Named("api"),
}
}
@ -46,13 +42,15 @@ func (i *inetmockAPI) StartServer() (err error) {
i.server = grpc.NewServer()
RegisterHandlersServer(i.server, &handlersServer{
registry: i.registry,
registry: i.app.HandlerRegistry(),
})
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)
return

View file

@ -2,13 +2,18 @@ package rpc
import (
"context"
"github.com/baez90/inetmock/pkg/api"
"gitlab.com/inetmock/inetmock/pkg/api"
)
type handlersServer struct {
UnimplementedHandlersServer
registry api.HandlerRegistry
}
func (h *handlersServer) mustEmbedUnimplementedHandlersServer() {
}
func (h *handlersServer) GetHandlers(_ context.Context, _ *GetHandlersRequest) (*GetHandlersResponse, error) {
return &GetHandlersResponse{
Handlers: h.registry.AvailableHandlers(),

View file

@ -2,14 +2,17 @@ package rpc
import (
"context"
"github.com/baez90/inetmock/pkg/health"
app2 "gitlab.com/inetmock/inetmock/internal/app"
)
type healthServer struct {
UnimplementedHealthServer
app app2.App
}
func (h healthServer) GetHealth(_ context.Context, _ *HealthRequest) (resp *HealthResponse, err error) {
checker := health.CheckerInstance()
checker := h.app.Checker()
result := checker.IsHealthy()
resp = &HealthResponse{

View file

@ -3,15 +3,18 @@ package api
import (
"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 LoggingFactory func() (*zap.Logger, error)
type PluginContext interface {
Logger() logging.Logger
CertStore() cert.Store
}
type ProtocolHandler interface {
Start(config config.HandlerConfig) error
Start(ctx PluginContext, config config.HandlerConfig) error
Shutdown(ctx context.Context) error
}

View file

@ -8,12 +8,25 @@ import (
)
var (
registry HandlerRegistry
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 {
handlers map[string]PluginInstanceFactory
handlers map[string]func() ProtocolHandler
}
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) {
handlerName = strings.ToLower(handlerName)
var provider PluginInstanceFactory
var provider func() ProtocolHandler
if provider, ok = h.handlers[handlerName]; ok {
instance = provider()
}
return
}
func (h *handlerRegistry) RegisterHandler(handlerName string, handlerProvider PluginInstanceFactory) {
func (h *handlerRegistry) RegisterHandler(handlerName string, handlerProvider func() ProtocolHandler) {
handlerName = strings.ToLower(handlerName)
if _, exists := h.handlers[handlerName]; exists {
panic(fmt.Sprintf("handler with name %s is already registered - there's something strange...in the neighborhood", handlerName))
}
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)
}

View file

@ -7,7 +7,7 @@ import (
func Test_handlerRegistry_HandlerForName(t *testing.T) {
type fields struct {
handlers map[string]PluginInstanceFactory
handlers map[string]func() ProtocolHandler
}
type args struct {
handlerName string
@ -29,7 +29,7 @@ func Test_handlerRegistry_HandlerForName(t *testing.T) {
{
name: "Nil instance from pseudo factory",
fields: fields{
handlers: map[string]PluginInstanceFactory{
handlers: map[string]func() ProtocolHandler{
"pseudo": func() ProtocolHandler {
return nil
},

View file

@ -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
}

View file

@ -4,14 +4,15 @@ import (
"crypto/tls"
"crypto/x509"
"fmt"
certmock "github.com/baez90/inetmock/internal/mock/cert"
"github.com/baez90/inetmock/pkg/config"
"github.com/golang/mock/gomock"
"os"
"path"
"reflect"
"testing"
"time"
"github.com/golang/mock/gomock"
certmock "gitlab.com/inetmock/inetmock/internal/mock/cert"
"gitlab.com/inetmock/inetmock/pkg/config"
)
const (

View file

@ -1,8 +1,9 @@
package cert
import (
"github.com/baez90/inetmock/pkg/defaulting"
"reflect"
"gitlab.com/inetmock/inetmock/pkg/defaulting"
)
var (

View file

@ -8,10 +8,11 @@ import (
"crypto/x509"
"crypto/x509/pkix"
"encoding/pem"
"github.com/baez90/inetmock/pkg/config"
"github.com/baez90/inetmock/pkg/defaulting"
"math/big"
"net"
"gitlab.com/inetmock/inetmock/pkg/config"
"gitlab.com/inetmock/inetmock/pkg/defaulting"
)
var (

View file

@ -1,8 +1,9 @@
package cert
import (
"github.com/baez90/inetmock/pkg/config"
"os"
"gitlab.com/inetmock/inetmock/pkg/config"
)
func init() {

View file

@ -1,12 +1,13 @@
package cert
import (
"github.com/baez90/inetmock/pkg/config"
"github.com/spf13/viper"
"os"
"strings"
"testing"
"time"
"github.com/spf13/viper"
"gitlab.com/inetmock/inetmock/pkg/config"
)
func readViper(cfg string) *viper.Viper {

View file

@ -6,9 +6,10 @@ import (
"encoding/pem"
"errors"
"fmt"
"github.com/baez90/inetmock/pkg/path"
"os"
"path/filepath"
"gitlab.com/inetmock/inetmock/pkg/path"
)
const (

View file

@ -6,10 +6,11 @@ import (
"crypto/rand"
"crypto/tls"
"crypto/x509"
"github.com/baez90/inetmock/pkg/config"
"github.com/baez90/inetmock/pkg/logging"
"go.uber.org/zap"
"net"
"gitlab.com/inetmock/inetmock/pkg/config"
"gitlab.com/inetmock/inetmock/pkg/logging"
"go.uber.org/zap"
)
const (

View file

@ -1,19 +1,16 @@
package config
import (
"github.com/baez90/inetmock/pkg/logging"
"github.com/baez90/inetmock/pkg/path"
"strings"
"github.com/spf13/pflag"
"github.com/spf13/viper"
"gitlab.com/inetmock/inetmock/pkg/logging"
"gitlab.com/inetmock/inetmock/pkg/path"
"go.uber.org/zap"
"strings"
)
var (
appConfig Config
)
func CreateConfig(flags *pflag.FlagSet) {
func CreateConfig(flags *pflag.FlagSet) Config {
logger, _ := logging.CreateLogger()
configInstance := &config{
logger: logger.Named("Config"),
@ -38,11 +35,7 @@ func CreateConfig(flags *pflag.FlagSet) {
configInstance.cfg.RegisterAlias(k, v)
}
appConfig = configInstance
}
func Instance() Config {
return appConfig
return configInstance
}
type Config interface {
@ -51,14 +44,14 @@ type Config interface {
Viper() *viper.Viper
TLSConfig() CertOptions
APIConfig() RPC
EndpointConfigs() map[string]MultiHandlerConfig
EndpointConfigs() map[string]EndpointConfig
}
type config struct {
cfg *viper.Viper
logger logging.Logger
TLS CertOptions
Endpoints map[string]MultiHandlerConfig
Endpoints map[string]EndpointConfig
API RPC
}
@ -76,7 +69,7 @@ func (c *config) ReadConfigString(config, format string) (err error) {
return
}
func (c *config) EndpointConfigs() map[string]MultiHandlerConfig {
func (c *config) EndpointConfigs() map[string]EndpointConfig {
return c.Endpoints
}

View file

@ -1,8 +1,9 @@
package config
import (
"github.com/spf13/pflag"
"testing"
"github.com/spf13/pflag"
)
func Test_config_ReadConfig(t *testing.T) {
@ -53,8 +54,7 @@ endpoints:
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
CreateConfig(tt.args.flags)
cfg := Instance()
cfg := CreateConfig(tt.args.flags)
if err := cfg.ReadConfigString(tt.args.config, "yaml"); (err != nil) != tt.wantErr {
t.Errorf("ReadConfig() error = %v, wantErr %v", err, tt.wantErr)
return

View file

@ -2,6 +2,7 @@ package config
import (
"fmt"
"github.com/spf13/viper"
)

View file

@ -1,9 +1,10 @@
package config
import (
"github.com/spf13/viper"
"reflect"
"testing"
"github.com/spf13/viper"
)
func Test_handlerConfig_HandlerName(t *testing.T) {

View file

@ -4,14 +4,14 @@ import (
"github.com/spf13/viper"
)
type MultiHandlerConfig struct {
type EndpointConfig struct {
Handler string
Ports []uint16
ListenAddress string
Options *viper.Viper
}
func (m MultiHandlerConfig) HandlerConfigs() []HandlerConfig {
func (m EndpointConfig) HandlerConfigs() []HandlerConfig {
configs := make([]HandlerConfig, 0)
for _, port := range m.Ports {
configs = append(configs, HandlerConfig{

View file

@ -27,9 +27,7 @@ func (r *registry) Register(t reflect.Type, defaulter ...Defaulter) {
given = r
}
for _, d := range defaulter {
given = append(given, d)
}
given = append(given, defaulter...)
r.defaulters[t] = given
}

View file

@ -29,8 +29,7 @@ func Test_registry_Apply(t *testing.T) {
fields: fields{
defaulters: map[reflect.Type][]Defaulter{
reflect.TypeOf(&sample{}): {func(instance interface{}) {
switch i := instance.(type) {
case *sample:
if i, ok := instance.(*sample); ok {
i.i = 42
}
}},

View file

@ -26,16 +26,11 @@ type Result struct {
type Check func() CheckResult
var (
CheckForComponentAlreadyRegistered = errors.New("a check for the requested component is already registered")
checkerInstance *checker
ErrCheckForComponentAlreadyRegistered = errors.New("a check for the requested component is already registered")
)
func init() {
checkerInstance = &checker{
func New() Checker {
return &checker{
componentChecks: map[string]Check{},
}
}
func CheckerInstance() Checker {
return checkerInstance
}

View file

@ -13,7 +13,7 @@ type Checker interface {
func (c *checker) RegisterCheck(component string, check Check) error {
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
@ -30,7 +30,7 @@ func (c *checker) IsHealthy() (r Result) {
return
}
func max(s1 Status, s2 Status) Status {
func max(s1, s2 Status) Status {
var max Status
if s1 > s2 {
max = s1

View file

@ -1,9 +1,10 @@
package logging
import (
"strings"
"go.uber.org/zap"
"go.uber.org/zap/zapcore"
"strings"
)
var (
@ -46,3 +47,11 @@ func CreateLogger() (Logger, error) {
return NewLogger(zapLogger), nil
}
}
func MustCreateLogger() Logger {
if logger, err := CreateLogger(); err != nil {
panic(err)
} else {
return logger
}
}

View file

@ -1,9 +1,10 @@
package logging
import (
"go.uber.org/zap"
"reflect"
"testing"
"go.uber.org/zap"
)
func TestParseLevel(t *testing.T) {

View file

@ -10,7 +10,6 @@ import (
)
func TestFileExists(t *testing.T) {
tmpFile, err := ioutil.TempFile("", "inetmock")
if err != nil {

View file

@ -2,11 +2,12 @@ package dns_mock
import (
"encoding/binary"
"github.com/spf13/viper"
"math"
"math/rand"
"net"
"unsafe"
"github.com/spf13/viper"
)
const (

View file

@ -2,9 +2,11 @@ package dns_mock
import (
"context"
"github.com/baez90/inetmock/pkg/config"
"github.com/baez90/inetmock/pkg/logging"
"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"
)
@ -13,7 +15,7 @@ type dnsHandler struct {
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
if options, err = loadFromConfig(config.Options); err != nil {
return

View file

@ -1,9 +1,10 @@
package dns_mock
import (
"github.com/spf13/viper"
"net"
"regexp"
"github.com/spf13/viper"
)
const (

View file

@ -1,9 +1,9 @@
package dns_mock
import (
"github.com/baez90/inetmock/pkg/logging"
"github.com/miekg/dns"
"github.com/prometheus/client_golang/prometheus"
"gitlab.com/inetmock/inetmock/pkg/logging"
"go.uber.org/zap"
)

View file

@ -1,10 +1,10 @@
package dns_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"
"gitlab.com/inetmock/inetmock/pkg/api"
"gitlab.com/inetmock/inetmock/pkg/logging"
"gitlab.com/inetmock/inetmock/pkg/metrics"
"go.uber.org/zap"
)
@ -19,11 +19,10 @@ var (
requestDurationHistogram *prometheus.HistogramVec
)
func init() {
var err error
func AddDNSMock(registry api.HandlerRegistry) (err error) {
var logger logging.Logger
if logger, err = logging.CreateLogger(); err != nil {
panic(err)
return
}
logger = logger.With(
zap.String("protocol_handler", name),
@ -35,7 +34,7 @@ func init() {
"",
handlerNameLblName,
); err != nil {
panic(err)
return
}
if unhandledRequestsCounter, err = metrics.Counter(
@ -44,7 +43,7 @@ func init() {
"",
handlerNameLblName,
); err != nil {
panic(err)
return
}
if requestDurationHistogram, err = metrics.Histogram(
@ -54,12 +53,14 @@ func init() {
nil,
handlerNameLblName,
); err != nil {
panic(err)
return
}
api.Registry().RegisterHandler(name, func() api.ProtocolHandler {
registry.RegisterHandler(name, func() api.ProtocolHandler {
return &dnsHandler{
logger: logger,
}
})
return
}

View file

@ -4,10 +4,12 @@ import (
"context"
"errors"
"fmt"
"github.com/baez90/inetmock/pkg/config"
"github.com/baez90/inetmock/pkg/logging"
"go.uber.org/zap"
"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 (
@ -21,8 +23,16 @@ type httpHandler struct {
server *http.Server
}
func (p *httpHandler) Start(config config.HandlerConfig) (err error) {
options := loadFromConfig(config.Options)
func (p *httpHandler) Start(ctx api.PluginContext, config config.HandlerConfig) (err error) {
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(
zap.String("handler_name", config.HandlerName),
zap.String("address", config.ListenAddr()),

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

View file

@ -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,
}
})
}

View file

@ -1,19 +1,44 @@
//go:generate go-enum -f $GOFILE --lower --marshal --names
package http_mock
import (
"github.com/spf13/viper"
"net/http"
"path/filepath"
"regexp"
"github.com/spf13/viper"
)
const (
rulesConfigKey = "rules"
patternConfigKey = "pattern"
responseConfigKey = "response"
var (
ruleValueSelectors = map[RequestMatchTarget]ruleValueSelector{
RequestMatchTargetHeader: func(req *http.Request, targetKey string) string {
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 {
pattern *regexp.Regexp
response string
pattern *regexp.Regexp
response string
requestMatchTarget RequestMatchTarget
targetKey string
}
func (tr targetRule) Pattern() *regexp.Regexp {
@ -28,20 +53,44 @@ type httpOptions struct {
Rules []targetRule
}
func loadFromConfig(config *viper.Viper) (options httpOptions) {
anonRules := config.Get(rulesConfigKey).([]interface{})
func loadFromConfig(config *viper.Viper) (options httpOptions, err error) {
type tmpCfg struct {
Pattern string
Response string
Matcher string
Target string
}
for _, i := range anonRules {
innerData := i.(map[interface{}]interface{})
tmpRules := struct {
Rules []tmpCfg
}{}
if rulePattern, err := regexp.Compile(innerData[patternConfigKey].(string)); err == nil {
options.Rules = append(options.Rules, targetRule{
pattern: rulePattern,
response: innerData[responseConfigKey].(string),
})
} else {
panic(err)
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 {
}
options.Rules = append(options.Rules, targetRule{
pattern: rulePattern,
response: absoluteResponsePath,
requestMatchTarget: matchTargetValue,
targetKey: i.Target,
})
}
return

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

View file

@ -2,16 +2,16 @@ package http_mock
import (
"bytes"
"github.com/baez90/inetmock/pkg/logging"
"github.com/prometheus/client_golang/prometheus"
"go.uber.org/zap"
"net/http"
"regexp"
"strconv"
"github.com/prometheus/client_golang/prometheus"
"gitlab.com/inetmock/inetmock/pkg/logging"
"go.uber.org/zap"
)
type route struct {
pattern *regexp.Regexp
rule targetRule
handler http.Handler
}
@ -21,22 +21,23 @@ type RegexpHandler struct {
routes []*route
}
func (h *RegexpHandler) Handler(pattern *regexp.Regexp, handler http.Handler) {
h.routes = append(h.routes, &route{pattern, handler})
func (h *RegexpHandler) Handler(rule targetRule, handler http.Handler) {
h.routes = append(h.routes, &route{rule, handler})
}
func (h *RegexpHandler) HandleFunc(pattern *regexp.Regexp, handler func(http.ResponseWriter, *http.Request)) {
h.routes = append(h.routes, &route{pattern, http.HandlerFunc(handler)})
func (h *RegexpHandler) HandleFunc(rule targetRule, handler func(http.ResponseWriter, *http.Request)) {
h.routes = append(h.routes, &route{rule, http.HandlerFunc(handler)})
}
func (h *RegexpHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
timer := prometheus.NewTimer(requestDurationHistogram.WithLabelValues(h.handlerName))
defer timer.ObserveDuration()
for _, route := range h.routes {
if route.pattern.MatchString(r.URL.Path) {
for idx := range h.routes {
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()
route.handler.ServeHTTP(w, r)
h.routes[idx].handler.ServeHTTP(w, r)
return
}
}
@ -52,7 +53,7 @@ func (h *RegexpHandler) setupRoute(rule targetRule) {
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 {

View 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
}

View file

@ -4,12 +4,13 @@ import (
"context"
"errors"
"fmt"
"github.com/baez90/inetmock/pkg/api"
"github.com/baez90/inetmock/pkg/config"
"github.com/baez90/inetmock/pkg/logging"
"net/http"
"gitlab.com/inetmock/inetmock/pkg/api"
"gitlab.com/inetmock/inetmock/pkg/config"
"gitlab.com/inetmock/inetmock/pkg/logging"
"go.uber.org/zap"
"gopkg.in/elazarl/goproxy.v1"
"net/http"
)
const (
@ -22,28 +23,28 @@ type httpProxy struct {
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
if err = config.Options.Unmarshal(&opts); err != nil {
if err = cfg.Options.Unmarshal(&opts); err != nil {
return
}
listenAddr := config.ListenAddr()
listenAddr := cfg.ListenAddr()
h.server = &http.Server{Addr: listenAddr, Handler: h.proxy}
h.logger = h.logger.With(
zap.String("handler_name", config.HandlerName),
zap.String("handler_name", cfg.HandlerName),
zap.String("address", listenAddr),
)
tlsConfig := api.ServicesInstance().CertStore().TLSConfig()
tlsConfig := ctx.CertStore().TLSConfig()
proxyHandler := &proxyHttpHandler{
handlerName: config.HandlerName,
handlerName: cfg.HandlerName,
options: opts,
logger: h.logger,
}
proxyHttpsHandler := &proxyHttpsHandler{
handlerName: config.HandlerName,
handlerName: cfg.HandlerName,
tlsConfig: tlsConfig,
logger: h.logger,
}

View file

@ -3,12 +3,13 @@ package http_proxy
import (
"context"
"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/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 {

View file

@ -1,10 +1,10 @@
package http_proxy
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"
"gitlab.com/inetmock/inetmock/pkg/api"
"gitlab.com/inetmock/inetmock/pkg/logging"
"gitlab.com/inetmock/inetmock/pkg/metrics"
"go.uber.org/zap"
"gopkg.in/elazarl/goproxy.v1"
)
@ -16,32 +16,33 @@ var (
requestDurationHistogram *prometheus.HistogramVec
)
func init() {
var err error
func AddHTTPProxy(registry api.HandlerRegistry) (err error) {
var logger logging.Logger
if logger, err = logging.CreateLogger(); err != nil {
panic(err)
return
}
logger = logger.With(
zap.String("protocol_handler", name),
)
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 {
panic(err)
return
}
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{
logger: logger,
proxy: goproxy.NewProxyHttpServer(),
}
})
return
}

View file

@ -3,11 +3,13 @@ package metrics_exporter
import (
"context"
"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"
"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 (
@ -19,7 +21,7 @@ type metricsExporter struct {
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{}
if err = config.Options.Unmarshal(&exporterOptions); err != nil {
return

View file

@ -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,
}
})
}

View 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
}

View file

@ -4,15 +4,15 @@ import (
"context"
"crypto/tls"
"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"
"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 (
@ -24,16 +24,16 @@ type tlsInterceptor struct {
options tlsOptions
logger logging.Logger
listener net.Listener
certStore cert.Store
shutdownRequested bool
currentConnectionsCount *sync.WaitGroup
currentConnections map[uuid.UUID]*proxyConn
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
if err = config.Options.Unmarshal(&config.Options); err != nil {
if err = config.Options.Unmarshal(&t.options); err != nil {
return
}
@ -43,7 +43,7 @@ func (t *tlsInterceptor) Start(config config.HandlerConfig) (err error) {
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(
"failed to create tls listener",
zap.Error(err),

View file

@ -21,10 +21,10 @@ func chanFromConn(conn net.Conn) chan []byte {
for {
n, err := conn.Read(b)
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(res, b[:n])
c <- res
c <- res[:n]
}
if err != nil {
c <- nil

View file

@ -1,13 +1,14 @@
package tls_interceptor
import (
"github.com/baez90/inetmock/pkg/api"
"github.com/baez90/inetmock/pkg/logging"
"github.com/baez90/inetmock/pkg/metrics"
"sync"
"github.com/google/uuid"
"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"
"sync"
)
var (
@ -17,8 +18,7 @@ var (
requestDurationHistogram *prometheus.HistogramVec
)
func init() {
var err error
func AddTLSInterceptor(registry api.HandlerRegistry) (err error) {
var logger logging.Logger
if logger, err = logging.CreateLogger(); err != nil {
panic(err)
@ -28,16 +28,16 @@ func init() {
)
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 {
panic(err)
return
}
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{
logger: logger,
currentConnectionsCount: &sync.WaitGroup{},
@ -45,4 +45,5 @@ func init() {
connectionsMutex: &sync.Mutex{},
}
})
return
}