diff --git a/.editorconfig b/.editorconfig new file mode 100644 index 0000000..c3daa0a --- /dev/null +++ b/.editorconfig @@ -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 diff --git a/.github/workflows/docker-image.yml b/.github/workflows/docker-image.yml index 57c81da..82cf8db 100644 --- a/.github/workflows/docker-image.yml +++ b/.github/workflows/docker-image.yml @@ -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: | diff --git a/.github/workflows/go-build.yml b/.github/workflows/go-build.yml index 0ba65d0..7a862c4 100644 --- a/.github/workflows/go-build.yml +++ b/.github/workflows/go-build.yml @@ -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 }} \ No newline at end of file + - 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 }} \ No newline at end of file diff --git a/.gitignore b/.gitignore index 4bea1d6..374b413 100644 --- a/.gitignore +++ b/.gitignore @@ -11,6 +11,7 @@ /imctl ./main **/*.mock.go +**/*_enum.go **/*.pb.go ############### @@ -20,4 +21,5 @@ .idea/ .vscode/ dist/ -out/ \ No newline at end of file +out/ +.task/ \ No newline at end of file diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml new file mode 100644 index 0000000..16d474d --- /dev/null +++ b/.gitlab-ci.yml @@ -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 \ No newline at end of file diff --git a/.golangci.yml b/.golangci.yml new file mode 100644 index 0000000..26cb98b --- /dev/null +++ b/.golangci.yml @@ -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" diff --git a/.goreleaser.yml b/.goreleaser.yml index 31c2d6d..e426e71 100644 --- a/.goreleaser.yml +++ b/.goreleaser.yml @@ -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/ diff --git a/Makefile b/Makefile deleted file mode 100644 index 4f4e8a9..0000000 --- a/Makefile +++ /dev/null @@ -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 diff --git a/README.md b/README.md index 8d44f6f..6aba043 100644 --- a/README.md +++ b/README.md @@ -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. \ No newline at end of file diff --git a/Taskfile.yml b/Taskfile.yml new file mode 100644 index 0000000..bada179 --- /dev/null +++ b/Taskfile.yml @@ -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 \ No newline at end of file diff --git a/api/endpoints.proto b/api/endpoints.proto index 2f76706..3981ff5 100644 --- a/api/endpoints.proto +++ b/api/endpoints.proto @@ -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"; diff --git a/api/handlers.proto b/api/handlers.proto index 121a9e4..6440a99 100644 --- a/api/handlers.proto +++ b/api/handlers.proto @@ -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 { diff --git a/api/health.proto b/api/health.proto index 6d7c187..8c9b6b9 100644 --- a/api/health.proto +++ b/api/health.proto @@ -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 { diff --git a/Dockerfile b/build/docker/inetmock.dockerfile similarity index 55% rename from Dockerfile rename to build/docker/inetmock.dockerfile index e56f64a..33a2e3f 100644 --- a/Dockerfile +++ b/build/docker/inetmock.dockerfile @@ -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 && \ diff --git a/cmd/imctl/main.go b/cmd/imctl/main.go index 8db7efb..1771ede 100644 --- a/cmd/imctl/main.go +++ b/cmd/imctl/main.go @@ -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 { diff --git a/cmd/inetmock/main.go b/cmd/inetmock/main.go index 7eaa048..585a1c8 100644 --- a/cmd/inetmock/main.go +++ b/cmd/inetmock/main.go @@ -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() } diff --git a/config-container.yaml b/config-container.yaml index 2a8d882..f449288 100644 --- a/config-container.yaml +++ b/config-container.yaml @@ -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 diff --git a/config.yaml b/config.yaml index 1a3c774..c71558e 100644 --- a/config.yaml +++ b/config.yaml @@ -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 diff --git a/docs/src/config.md b/docs/src/config.md index 4407a19..bd91014 100644 --- a/docs/src/config.md +++ b/docs/src/config.md @@ -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. \ No newline at end of file +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. \ No newline at end of file diff --git a/docs/src/config/dns_mock.md b/docs/src/config/dns_mock.md index 81b3390..7026c3a 100644 --- a/docs/src/config/dns_mock.md +++ b/docs/src/config/dns_mock.md @@ -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: diff --git a/docs/src/config/http_mock.md b/docs/src/config/http_mock.md index 7620085..f70841f 100644 --- a/docs/src/config/http_mock.md +++ b/docs/src/config/http_mock.md @@ -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. diff --git a/docs/src/config/yaml-config.md b/docs/src/config/yaml-config.md index 2b2a4d2..3f0af33 100644 --- a/docs/src/config/yaml-config.md +++ b/docs/src/config/yaml-config.md @@ -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 diff --git a/go.mod b/go.mod index b660b8c..e17d974 100644 --- a/go.mod +++ b/go.mod @@ -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 ) diff --git a/go.sum b/go.sum index 3778b71..fec03c6 100644 --- a/go.sum +++ b/go.sum @@ -37,6 +37,7 @@ github.com/cespare/xxhash/v2 v2.1.1 h1:6MnRN8NT7+YBpUIWxHtefFZOKTAPgGjpQSxqLNn0+ github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= github.com/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= diff --git a/internal/app/app.go b/internal/app/app.go new file mode 100644 index 0000000..ce8d1ff --- /dev/null +++ b/internal/app/app.go @@ -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 +} diff --git a/internal/cmd/ca.go b/internal/cmd/ca.go index 98d208c..c1c3012 100644 --- a/internal/cmd/ca.go +++ b/internal/cmd/ca.go @@ -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), diff --git a/internal/cmd/cli.go b/internal/cmd/cli.go index eb48b01..68f5491 100644 --- a/internal/cmd/cli.go +++ b/internal/cmd/cli.go @@ -1,8 +1,9 @@ package cmd import ( - "github.com/spf13/cobra" "time" + + "github.com/spf13/cobra" ) var ( diff --git a/internal/cmd/endpoints.go b/internal/cmd/endpoints.go index dc3c7f3..3cd2749 100644 --- a/internal/cmd/endpoints.go +++ b/internal/cmd/endpoints.go @@ -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 ( diff --git a/internal/cmd/handlers.go b/internal/cmd/handlers.go index a5b988b..136829c 100644 --- a/internal/cmd/handlers.go +++ b/internal/cmd/handlers.go @@ -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 ( diff --git a/internal/cmd/health.go b/internal/cmd/health.go index e8f979d..2b17d8f 100644 --- a/internal/cmd/health.go +++ b/internal/cmd/health.go @@ -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 ( diff --git a/internal/cmd/serve.go b/internal/cmd/serve.go index 59afb54..97ce54f 100644 --- a/internal/cmd/serve.go +++ b/internal/cmd/serve.go @@ -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() } diff --git a/internal/cmd/server.go b/internal/cmd/server.go index 22e8315..b182b88 100644 --- a/internal/cmd/server.go +++ b/internal/cmd/server.go @@ -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() } diff --git a/internal/endpoints/endpoint.go b/internal/endpoints/endpoint.go index 820c7e3..f27068b 100644 --- a/internal/endpoints/endpoint.go +++ b/internal/endpoints/endpoint.go @@ -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) { diff --git a/internal/endpoints/endpoint_manager.go b/internal/endpoints/endpoint_manager.go index c251259..afc13e2 100644 --- a/internal/endpoints/endpoint_manager.go +++ b/internal/endpoints/endpoint_manager.go @@ -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 } diff --git a/internal/endpoints/endpoint_manager_test.go b/internal/endpoints/endpoint_manager_test.go index ea2272f..0e49092 100644 --- a/internal/endpoints/endpoint_manager_test.go +++ b/internal/endpoints/endpoint_manager_test.go @@ -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) diff --git a/internal/endpoints/endpoint_test.go b/internal/endpoints/endpoint_test.go deleted file mode 100644 index c989bd7..0000000 --- a/internal/endpoints/endpoint_test.go +++ /dev/null @@ -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) - } - }) - } -} diff --git a/internal/format/console_writer.go b/internal/format/console_writer.go index ce123fb..6551534 100644 --- a/internal/format/console_writer.go +++ b/internal/format/console_writer.go @@ -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 diff --git a/internal/format/table_writer.go b/internal/format/table_writer.go index be5dbfd..feb3383 100644 --- a/internal/format/table_writer.go +++ b/internal/format/table_writer.go @@ -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) { diff --git a/internal/rpc/endpoints_server.go b/internal/rpc/endpoints_server.go index a688ab7..7fada0d 100644 --- a/internal/rpc/endpoints_server.go +++ b/internal/rpc/endpoints_server.go @@ -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 } diff --git a/internal/rpc/grpc_api.go b/internal/rpc/grpc_api.go index 2393b66..cbcc87c 100644 --- a/internal/rpc/grpc_api.go +++ b/internal/rpc/grpc_api.go @@ -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 diff --git a/internal/rpc/handlers_server.go b/internal/rpc/handlers_server.go index bb48b92..bd5491e 100644 --- a/internal/rpc/handlers_server.go +++ b/internal/rpc/handlers_server.go @@ -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(), diff --git a/internal/rpc/health_server.go b/internal/rpc/health_server.go index ba090a9..d92f344 100644 --- a/internal/rpc/health_server.go +++ b/internal/rpc/health_server.go @@ -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{ diff --git a/pkg/api/protocol_handler.go b/pkg/api/protocol_handler.go index 6146216..540ae77 100644 --- a/pkg/api/protocol_handler.go +++ b/pkg/api/protocol_handler.go @@ -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 } diff --git a/pkg/api/registration.go b/pkg/api/registration.go index cc05f51..1f8662c 100644 --- a/pkg/api/registration.go +++ b/pkg/api/registration.go @@ -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) -} diff --git a/pkg/api/registration_test.go b/pkg/api/registration_test.go index 366e892..561d12f 100644 --- a/pkg/api/registration_test.go +++ b/pkg/api/registration_test.go @@ -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 }, diff --git a/pkg/api/services.go b/pkg/api/services.go deleted file mode 100644 index 8c831f4..0000000 --- a/pkg/api/services.go +++ /dev/null @@ -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 -} diff --git a/pkg/cert/cache_test.go b/pkg/cert/cache_test.go index 3bc23eb..8d911ba 100644 --- a/pkg/cert/cache_test.go +++ b/pkg/cert/cache_test.go @@ -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 ( diff --git a/pkg/cert/defaults.go b/pkg/cert/defaults.go index 640d470..6ea10be 100644 --- a/pkg/cert/defaults.go +++ b/pkg/cert/defaults.go @@ -1,8 +1,9 @@ package cert import ( - "github.com/baez90/inetmock/pkg/defaulting" "reflect" + + "gitlab.com/inetmock/inetmock/pkg/defaulting" ) var ( diff --git a/pkg/cert/generator.go b/pkg/cert/generator.go index f0da9cc..64110c1 100644 --- a/pkg/cert/generator.go +++ b/pkg/cert/generator.go @@ -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 ( diff --git a/pkg/cert/options.go b/pkg/cert/options.go index bb66d46..65da2f6 100644 --- a/pkg/cert/options.go +++ b/pkg/cert/options.go @@ -1,8 +1,9 @@ package cert import ( - "github.com/baez90/inetmock/pkg/config" "os" + + "gitlab.com/inetmock/inetmock/pkg/config" ) func init() { diff --git a/pkg/cert/options_test.go b/pkg/cert/options_test.go index 78b3efc..9956c6b 100644 --- a/pkg/cert/options_test.go +++ b/pkg/cert/options_test.go @@ -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 { diff --git a/pkg/cert/pem.go b/pkg/cert/pem.go index 5b78d91..a3058fc 100644 --- a/pkg/cert/pem.go +++ b/pkg/cert/pem.go @@ -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 ( diff --git a/pkg/cert/store.go b/pkg/cert/store.go index 25e3373..0dbe78e 100644 --- a/pkg/cert/store.go +++ b/pkg/cert/store.go @@ -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 ( diff --git a/pkg/config/config.go b/pkg/config/config.go index fb64369..705af5d 100644 --- a/pkg/config/config.go +++ b/pkg/config/config.go @@ -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 } diff --git a/pkg/config/config_test.go b/pkg/config/config_test.go index 1fa3bad..daf977b 100644 --- a/pkg/config/config_test.go +++ b/pkg/config/config_test.go @@ -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 diff --git a/pkg/config/handler_config.go b/pkg/config/handler_config.go index 03d28c9..b7fae34 100644 --- a/pkg/config/handler_config.go +++ b/pkg/config/handler_config.go @@ -2,6 +2,7 @@ package config import ( "fmt" + "github.com/spf13/viper" ) diff --git a/pkg/config/handler_config_test.go b/pkg/config/handler_config_test.go index 527136b..be66f85 100644 --- a/pkg/config/handler_config_test.go +++ b/pkg/config/handler_config_test.go @@ -1,9 +1,10 @@ package config import ( - "github.com/spf13/viper" "reflect" "testing" + + "github.com/spf13/viper" ) func Test_handlerConfig_HandlerName(t *testing.T) { diff --git a/pkg/config/multi_handler_config.go b/pkg/config/multi_handler_config.go index 475b19d..6a821ec 100644 --- a/pkg/config/multi_handler_config.go +++ b/pkg/config/multi_handler_config.go @@ -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{ diff --git a/pkg/defaulting/defaulter.go b/pkg/defaulting/defaulter.go index 4944935..10c75d9 100644 --- a/pkg/defaulting/defaulter.go +++ b/pkg/defaulting/defaulter.go @@ -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 } diff --git a/pkg/defaulting/defaulter_test.go b/pkg/defaulting/defaulter_test.go index d9b23c2..73caaba 100644 --- a/pkg/defaulting/defaulter_test.go +++ b/pkg/defaulting/defaulter_test.go @@ -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 } }}, diff --git a/pkg/health/api.go b/pkg/health/api.go index 0e9c2e4..9bf882f 100644 --- a/pkg/health/api.go +++ b/pkg/health/api.go @@ -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 -} diff --git a/pkg/health/checker.go b/pkg/health/checker.go index e8edd94..e72d5b0 100644 --- a/pkg/health/checker.go +++ b/pkg/health/checker.go @@ -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 diff --git a/pkg/logging/factory.go b/pkg/logging/factory.go index 7ba4ea0..727d55b 100644 --- a/pkg/logging/factory.go +++ b/pkg/logging/factory.go @@ -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 + } +} diff --git a/pkg/logging/factory_test.go b/pkg/logging/factory_test.go index 061462d..e5b69a7 100644 --- a/pkg/logging/factory_test.go +++ b/pkg/logging/factory_test.go @@ -1,9 +1,10 @@ package logging import ( - "go.uber.org/zap" "reflect" "testing" + + "go.uber.org/zap" ) func TestParseLevel(t *testing.T) { diff --git a/pkg/path/helpers_test.go b/pkg/path/helpers_test.go index d01fa94..de27487 100644 --- a/pkg/path/helpers_test.go +++ b/pkg/path/helpers_test.go @@ -10,7 +10,6 @@ import ( ) func TestFileExists(t *testing.T) { - tmpFile, err := ioutil.TempFile("", "inetmock") if err != nil { diff --git a/plugins/dns_mock/fallback.go b/plugins/dns_mock/fallback.go index f7fa398..43697b1 100644 --- a/plugins/dns_mock/fallback.go +++ b/plugins/dns_mock/fallback.go @@ -2,11 +2,12 @@ package dns_mock import ( "encoding/binary" - "github.com/spf13/viper" "math" "math/rand" "net" "unsafe" + + "github.com/spf13/viper" ) const ( diff --git a/plugins/dns_mock/handler.go b/plugins/dns_mock/handler.go index 489cb70..d07f7e0 100644 --- a/plugins/dns_mock/handler.go +++ b/plugins/dns_mock/handler.go @@ -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 diff --git a/plugins/dns_mock/protocol_options.go b/plugins/dns_mock/protocol_options.go index 67b6f60..f3aabc6 100644 --- a/plugins/dns_mock/protocol_options.go +++ b/plugins/dns_mock/protocol_options.go @@ -1,9 +1,10 @@ package dns_mock import ( - "github.com/spf13/viper" "net" "regexp" + + "github.com/spf13/viper" ) const ( diff --git a/plugins/dns_mock/regex_handler.go b/plugins/dns_mock/regex_handler.go index 3e72e7b..b6bc4c0 100644 --- a/plugins/dns_mock/regex_handler.go +++ b/plugins/dns_mock/regex_handler.go @@ -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" ) diff --git a/plugins/dns_mock/init.go b/plugins/dns_mock/register.go similarity index 76% rename from plugins/dns_mock/init.go rename to plugins/dns_mock/register.go index 425f083..ed32569 100644 --- a/plugins/dns_mock/init.go +++ b/plugins/dns_mock/register.go @@ -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 } diff --git a/plugins/http_mock/handler.go b/plugins/http_mock/handler.go index 947e7ee..c87bd2a 100644 --- a/plugins/http_mock/handler.go +++ b/plugins/http_mock/handler.go @@ -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()), diff --git a/plugins/http_mock/handler_test.go b/plugins/http_mock/handler_test.go new file mode 100644 index 0000000..f60d031 --- /dev/null +++ b/plugins/http_mock/handler_test.go @@ -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) + } + } +} diff --git a/plugins/http_mock/init.go b/plugins/http_mock/init.go deleted file mode 100644 index 21929f4..0000000 --- a/plugins/http_mock/init.go +++ /dev/null @@ -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, - } - }) -} diff --git a/plugins/http_mock/protocol_options.go b/plugins/http_mock/protocol_options.go index feff86f..600cfb8 100644 --- a/plugins/http_mock/protocol_options.go +++ b/plugins/http_mock/protocol_options.go @@ -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 diff --git a/plugins/http_mock/protocol_options_test.go b/plugins/http_mock/protocol_options_test.go new file mode 100644 index 0000000..e992c2f --- /dev/null +++ b/plugins/http_mock/protocol_options_test.go @@ -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) + } + }) + } +} diff --git a/plugins/http_mock/regex_router.go b/plugins/http_mock/regex_router.go index b1d62fb..3de7ea4 100644 --- a/plugins/http_mock/regex_router.go +++ b/plugins/http_mock/regex_router.go @@ -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 { diff --git a/plugins/http_mock/register.go b/plugins/http_mock/register.go new file mode 100644 index 0000000..d81e055 --- /dev/null +++ b/plugins/http_mock/register.go @@ -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 +} diff --git a/plugins/http_proxy/handler.go b/plugins/http_proxy/handler.go index 9ae1ae7..251a43e 100644 --- a/plugins/http_proxy/handler.go +++ b/plugins/http_proxy/handler.go @@ -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, } diff --git a/plugins/http_proxy/proxy_handler.go b/plugins/http_proxy/proxy_handler.go index 1d10ba5..9bf6ccb 100644 --- a/plugins/http_proxy/proxy_handler.go +++ b/plugins/http_proxy/proxy_handler.go @@ -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 { diff --git a/plugins/http_proxy/init.go b/plugins/http_proxy/register.go similarity index 76% rename from plugins/http_proxy/init.go rename to plugins/http_proxy/register.go index 335a9de..cd743e5 100644 --- a/plugins/http_proxy/init.go +++ b/plugins/http_proxy/register.go @@ -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 } diff --git a/plugins/metrics_exporter/handler.go b/plugins/metrics_exporter/handler.go index 40dcbae..31aaac5 100644 --- a/plugins/metrics_exporter/handler.go +++ b/plugins/metrics_exporter/handler.go @@ -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 diff --git a/plugins/metrics_exporter/init.go b/plugins/metrics_exporter/init.go deleted file mode 100644 index 38b06b7..0000000 --- a/plugins/metrics_exporter/init.go +++ /dev/null @@ -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, - } - }) -} diff --git a/plugins/metrics_exporter/register.go b/plugins/metrics_exporter/register.go new file mode 100644 index 0000000..f21fcf8 --- /dev/null +++ b/plugins/metrics_exporter/register.go @@ -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 +} diff --git a/plugins/tls_interceptor/handler.go b/plugins/tls_interceptor/handler.go index 320a55a..f5107a7 100644 --- a/plugins/tls_interceptor/handler.go +++ b/plugins/tls_interceptor/handler.go @@ -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), diff --git a/plugins/tls_interceptor/proxy.go b/plugins/tls_interceptor/proxy.go index 1b214cc..5017044 100644 --- a/plugins/tls_interceptor/proxy.go +++ b/plugins/tls_interceptor/proxy.go @@ -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 diff --git a/plugins/tls_interceptor/init.go b/plugins/tls_interceptor/register.go similarity index 79% rename from plugins/tls_interceptor/init.go rename to plugins/tls_interceptor/register.go index c063707..d354da5 100644 --- a/plugins/tls_interceptor/init.go +++ b/plugins/tls_interceptor/register.go @@ -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 }