├── .bingo ├── .gitignore ├── README.md ├── Variables.mk ├── copyright.mod ├── copyright.sum ├── embedmd.mod ├── embedmd.sum ├── faillint.mod ├── faillint.sum ├── go.mod ├── goimports.mod ├── goimports.sum ├── golangci-lint.mod ├── golangci-lint.sum ├── mdox.mod ├── mdox.sum ├── misspell.mod ├── misspell.sum ├── proxy.mod ├── proxy.sum └── variables.env ├── .errcheck_excludes.txt ├── .github ├── ISSUE_TEMPLATE │ ├── bug-report.md │ └── feature-request.md └── workflows │ └── go.yaml ├── .gitignore ├── .golangci.yml ├── COPYRIGHT ├── LICENSE ├── Makefile ├── README.md ├── doc.go ├── docs └── best_practice.md ├── encoding ├── doc.go ├── encoder.go ├── encoding_test.go ├── errreader.go ├── hcl.go ├── json.go └── yaml.go ├── examples ├── kubernetes-statefulset │ ├── example.go │ ├── go.mod │ └── go.sum ├── prometheus-rem-read-benchmark │ ├── README.md │ ├── abstr │ │ ├── doc.go │ │ └── kubernetes │ │ │ └── volumes │ │ │ └── volumes.go │ ├── go.mod │ ├── go.sum │ ├── main.go │ ├── rpc.proto │ ├── schemas │ │ ├── doc.go │ │ └── prometheus │ │ │ ├── discovery │ │ │ ├── azure │ │ │ │ └── azure.go │ │ │ ├── config │ │ │ │ └── config.go │ │ │ ├── consul │ │ │ │ └── consul.go │ │ │ ├── dns │ │ │ │ └── dns.go │ │ │ ├── ec2 │ │ │ │ └── ec2.go │ │ │ ├── file │ │ │ │ └── file.go │ │ │ ├── gce │ │ │ │ └── gce.go │ │ │ ├── kubernetes │ │ │ │ └── kubernetes.go │ │ │ ├── marathon │ │ │ │ └── marathon.go │ │ │ ├── openstack │ │ │ │ └── openstack.go │ │ │ ├── targetgroup │ │ │ │ └── targetgroup.go │ │ │ ├── triton │ │ │ │ └── triton.go │ │ │ └── zookeeper │ │ │ │ └── zookeeper.go │ │ │ └── prometheus.go │ ├── test.sh │ └── types.proto └── terraform │ ├── go.mod │ ├── go.sum │ └── main.go ├── files.go ├── gen.go ├── go.mod ├── go.sum └── panic.go /.bingo/.gitignore: -------------------------------------------------------------------------------- 1 | 2 | # Ignore everything 3 | * 4 | 5 | # But not these files: 6 | !.gitignore 7 | !*.mod 8 | !*.sum 9 | !README.md 10 | !Variables.mk 11 | !variables.env 12 | 13 | *tmp.mod 14 | -------------------------------------------------------------------------------- /.bingo/README.md: -------------------------------------------------------------------------------- 1 | # Project Development Dependencies. 2 | 3 | This is directory which stores Go modules with pinned buildable package that is used within this repository, managed by https://github.com/bwplotka/bingo. 4 | 5 | * Run `bingo get` to install all tools having each own module file in this directory. 6 | * Run `bingo get ` to install that have own module file in this directory. 7 | * For Makefile: Make sure to put `include .bingo/Variables.mk` in your Makefile, then use $() variable where is the .bingo/.mod. 8 | * For shell: Run `source .bingo/variables.env` to source all environment variable for each tool. 9 | * For go: Import `.bingo/variables.go` to for variable names. 10 | * See https://github.com/bwplotka/bingo or -h on how to add, remove or change binaries dependencies. 11 | 12 | ## Requirements 13 | 14 | * Go 1.14+ 15 | -------------------------------------------------------------------------------- /.bingo/Variables.mk: -------------------------------------------------------------------------------- 1 | # Auto generated binary variables helper managed by https://github.com/bwplotka/bingo v0.7. DO NOT EDIT. 2 | # All tools are designed to be build inside $GOBIN. 3 | BINGO_DIR := $(dir $(lastword $(MAKEFILE_LIST))) 4 | GOPATH ?= $(shell go env GOPATH) 5 | GOBIN ?= $(firstword $(subst :, ,${GOPATH}))/bin 6 | GO ?= $(shell which go) 7 | 8 | # Below generated variables ensure that every time a tool under each variable is invoked, the correct version 9 | # will be used; reinstalling only if needed. 10 | # For example for copyright variable: 11 | # 12 | # In your main Makefile (for non array binaries): 13 | # 14 | #include .bingo/Variables.mk # Assuming -dir was set to .bingo . 15 | # 16 | #command: $(COPYRIGHT) 17 | # @echo "Running copyright" 18 | # @$(COPYRIGHT) 19 | # 20 | COPYRIGHT := $(GOBIN)/copyright-v0.0.0-20210112004814-138d5e5695fe 21 | $(COPYRIGHT): $(BINGO_DIR)/copyright.mod 22 | @# Install binary/ries using Go 1.14+ build command. This is using bwplotka/bingo-controlled, separate go module with pinned dependencies. 23 | @echo "(re)installing $(GOBIN)/copyright-v0.0.0-20210112004814-138d5e5695fe" 24 | @cd $(BINGO_DIR) && GOWORK=off $(GO) build -mod=mod -modfile=copyright.mod -o=$(GOBIN)/copyright-v0.0.0-20210112004814-138d5e5695fe "github.com/efficientgo/tools/copyright" 25 | 26 | EMBEDMD := $(GOBIN)/embedmd-v1.0.0 27 | $(EMBEDMD): $(BINGO_DIR)/embedmd.mod 28 | @# Install binary/ries using Go 1.14+ build command. This is using bwplotka/bingo-controlled, separate go module with pinned dependencies. 29 | @echo "(re)installing $(GOBIN)/embedmd-v1.0.0" 30 | @cd $(BINGO_DIR) && GOWORK=off $(GO) build -mod=mod -modfile=embedmd.mod -o=$(GOBIN)/embedmd-v1.0.0 "github.com/campoy/embedmd" 31 | 32 | FAILLINT := $(GOBIN)/faillint-v1.11.0 33 | $(FAILLINT): $(BINGO_DIR)/faillint.mod 34 | @# Install binary/ries using Go 1.14+ build command. This is using bwplotka/bingo-controlled, separate go module with pinned dependencies. 35 | @echo "(re)installing $(GOBIN)/faillint-v1.11.0" 36 | @cd $(BINGO_DIR) && GOWORK=off $(GO) build -mod=mod -modfile=faillint.mod -o=$(GOBIN)/faillint-v1.11.0 "github.com/fatih/faillint" 37 | 38 | GOIMPORTS := $(GOBIN)/goimports-v0.0.0-20210112230658-8b4aab62c064 39 | $(GOIMPORTS): $(BINGO_DIR)/goimports.mod 40 | @# Install binary/ries using Go 1.14+ build command. This is using bwplotka/bingo-controlled, separate go module with pinned dependencies. 41 | @echo "(re)installing $(GOBIN)/goimports-v0.0.0-20210112230658-8b4aab62c064" 42 | @cd $(BINGO_DIR) && GOWORK=off $(GO) build -mod=mod -modfile=goimports.mod -o=$(GOBIN)/goimports-v0.0.0-20210112230658-8b4aab62c064 "golang.org/x/tools/cmd/goimports" 43 | 44 | GOLANGCI_LINT := $(GOBIN)/golangci-lint-v1.51.2 45 | $(GOLANGCI_LINT): $(BINGO_DIR)/golangci-lint.mod 46 | @# Install binary/ries using Go 1.14+ build command. This is using bwplotka/bingo-controlled, separate go module with pinned dependencies. 47 | @echo "(re)installing $(GOBIN)/golangci-lint-v1.51.2" 48 | @cd $(BINGO_DIR) && GOWORK=off $(GO) build -mod=mod -modfile=golangci-lint.mod -o=$(GOBIN)/golangci-lint-v1.51.2 "github.com/golangci/golangci-lint/cmd/golangci-lint" 49 | 50 | MDOX := $(GOBIN)/mdox-v0.2.1 51 | $(MDOX): $(BINGO_DIR)/mdox.mod 52 | @# Install binary/ries using Go 1.14+ build command. This is using bwplotka/bingo-controlled, separate go module with pinned dependencies. 53 | @echo "(re)installing $(GOBIN)/mdox-v0.2.1" 54 | @cd $(BINGO_DIR) && GOWORK=off $(GO) build -mod=mod -modfile=mdox.mod -o=$(GOBIN)/mdox-v0.2.1 "github.com/bwplotka/mdox" 55 | 56 | MISSPELL := $(GOBIN)/misspell-v0.3.4 57 | $(MISSPELL): $(BINGO_DIR)/misspell.mod 58 | @# Install binary/ries using Go 1.14+ build command. This is using bwplotka/bingo-controlled, separate go module with pinned dependencies. 59 | @echo "(re)installing $(GOBIN)/misspell-v0.3.4" 60 | @cd $(BINGO_DIR) && GOWORK=off $(GO) build -mod=mod -modfile=misspell.mod -o=$(GOBIN)/misspell-v0.3.4 "github.com/client9/misspell/cmd/misspell" 61 | 62 | PROXY := $(GOBIN)/proxy-v0.10.0 63 | $(PROXY): $(BINGO_DIR)/proxy.mod 64 | @# Install binary/ries using Go 1.14+ build command. This is using bwplotka/bingo-controlled, separate go module with pinned dependencies. 65 | @echo "(re)installing $(GOBIN)/proxy-v0.10.0" 66 | @cd $(BINGO_DIR) && GOWORK=off $(GO) build -mod=mod -modfile=proxy.mod -o=$(GOBIN)/proxy-v0.10.0 "github.com/gomods/athens/cmd/proxy" 67 | 68 | -------------------------------------------------------------------------------- /.bingo/copyright.mod: -------------------------------------------------------------------------------- 1 | module _ // Auto generated by https://github.com/bwplotka/bingo. DO NOT EDIT 2 | 3 | go 1.15 4 | 5 | require github.com/efficientgo/tools/copyright v0.0.0-20210112004814-138d5e5695fe 6 | -------------------------------------------------------------------------------- /.bingo/copyright.sum: -------------------------------------------------------------------------------- 1 | cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= 2 | github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= 3 | github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751 h1:JYp7IbQjafoB+tBA3gMyHYHrpOtNuDiK/uB5uXxq5wM= 4 | github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= 5 | github.com/alecthomas/units v0.0.0-20201120081800-1786d5ef83d4 h1:EBTWhcAX7rNQ80RLwLCpHZBBrJuzallFHnF+yMXo928= 6 | github.com/alecthomas/units v0.0.0-20201120081800-1786d5ef83d4/go.mod h1:OMCwj8VM1Kc9e19TLln2VL61YJF0x1XFtfdL4JdbSyE= 7 | github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= 8 | github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI= 9 | github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI= 10 | github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU= 11 | github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= 12 | github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= 13 | github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= 14 | github.com/efficientgo/tools v0.0.0-20201228165755-e2b84817bf79 h1:Pi2rMrMQeQ45UAZr8Ple+eSk9WCyglYpkFh0r22E00c= 15 | github.com/efficientgo/tools v0.0.0-20201228165755-e2b84817bf79/go.mod h1:jQUsxCcf91LHRhOnGqrx/yrleJbosynzf29/UlCbzlk= 16 | github.com/efficientgo/tools/copyright v0.0.0-20210112004814-138d5e5695fe h1:UxrVXSiy2FNfp1y+Hli0iooqqls5Yoh11KPrR9GOhg8= 17 | github.com/efficientgo/tools/copyright v0.0.0-20210112004814-138d5e5695fe/go.mod h1:5J0wuuxLMX06WeEgnpf+SvTCptlR9+RHRNO/WEMAwSw= 18 | github.com/efficientgo/tools/core v0.0.0-20210106193344-1108f4e7d16b h1:yi5z8x/FKDHrqtEFiAsxF5b7Sz2+CJrRwBC2kbyhVcA= 19 | github.com/efficientgo/tools/core v0.0.0-20210106193344-1108f4e7d16b/go.mod h1:RJm2+KCRfMUwgEgRte3obd5uLdVY5YbDZjgSMPY0HSA= 20 | github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= 21 | github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= 22 | github.com/felixge/fgprof v0.9.1/go.mod h1:7/HK6JFtFaARhIljgP2IV8rJLIoHDoOYoUphsnGvqxE= 23 | github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= 24 | github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= 25 | github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= 26 | github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= 27 | github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8= 28 | github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA= 29 | github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs= 30 | github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w= 31 | github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0= 32 | github.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QDs8UjoX8= 33 | github.com/golang/protobuf v1.4.3 h1:JjCZWpVbqXDqFVmTfYWEVTMIYrL/NPdPSCHPJ0T/raM= 34 | github.com/golang/protobuf v1.4.3/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= 35 | github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= 36 | github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= 37 | github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= 38 | github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= 39 | github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= 40 | github.com/google/pprof v0.0.0-20200615235658-03e1cf38a040/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= 41 | github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= 42 | github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= 43 | github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= 44 | github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= 45 | github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= 46 | github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= 47 | github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= 48 | github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= 49 | github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= 50 | github.com/protoconfig/protoconfig/go v0.0.0-20210106192113-733758adefac h1:PWrv6uwNBua14NbS74ukVgXgdRDQPx/2B+Rf6KXXoQk= 51 | github.com/protoconfig/protoconfig/go v0.0.0-20210106192113-733758adefac/go.mod h1:ig8lL2CeTS14ijDIIRoi6pTap0BHc0Xrnke+SKmn9QM= 52 | github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= 53 | github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= 54 | github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= 55 | github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= 56 | go.uber.org/goleak v1.1.10/go.mod h1:8a7PlsEVH3e/a/GLqe5IIrQx6GzcnRmZEufDUTk4A7A= 57 | golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= 58 | golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= 59 | golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= 60 | golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= 61 | golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= 62 | golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU= 63 | golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= 64 | golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= 65 | golang.org/x/lint v0.0.0-20200302205851-738671d3881b/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= 66 | golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= 67 | golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= 68 | golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= 69 | golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= 70 | golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= 71 | golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= 72 | golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= 73 | golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= 74 | golang.org/x/net v0.0.0-20200822124328-c89045814202/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= 75 | golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= 76 | golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= 77 | golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= 78 | golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= 79 | golang.org/x/sync v0.0.0-20200625203802-6e8e738ad208/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= 80 | golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= 81 | golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= 82 | golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 83 | golang.org/x/sys v0.0.0-20191204072324-ce4227a45e2e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 84 | golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 85 | golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= 86 | golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= 87 | golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY= 88 | golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= 89 | golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= 90 | golang.org/x/tools v0.0.0-20191108193012-7d206e10da11/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= 91 | golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= 92 | golang.org/x/tools v0.0.0-20200130002326-2f3ba24bd6e7/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= 93 | golang.org/x/tools v0.0.0-20201020161133-226fd2f889ca/go.mod h1:z6u4i615ZeAfBE4XtMziQW1fSVJXACjjbWkB/mvPzlU= 94 | golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= 95 | golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= 96 | golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= 97 | golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= 98 | google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= 99 | google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= 100 | google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= 101 | google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= 102 | google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo= 103 | google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= 104 | google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= 105 | google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= 106 | google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= 107 | google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0= 108 | google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM= 109 | google.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miEFZTKqfCUM6K7xSMQL9OKL/b6hQv+e19PK+JZNE= 110 | google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo= 111 | google.golang.org/protobuf v1.22.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= 112 | google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= 113 | google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= 114 | google.golang.org/protobuf v1.25.0 h1:Ejskq+SyPohKW+1uil0JJMtmHCgJPJ/qWTxr8qp+R4c= 115 | google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c= 116 | gopkg.in/alecthomas/kingpin.v2 v2.2.6 h1:jMFz6MfLP0/4fUyZle81rXUoxOBFi19VUFKVDOQfozc= 117 | gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw= 118 | gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= 119 | gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= 120 | gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= 121 | gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= 122 | gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= 123 | gopkg.in/yaml.v3 v3.0.0-20200615113413-eeeca48fe776/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= 124 | honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= 125 | honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= 126 | -------------------------------------------------------------------------------- /.bingo/embedmd.mod: -------------------------------------------------------------------------------- 1 | module _ // Auto generated by https://github.com/bwplotka/bingo. DO NOT EDIT 2 | 3 | go 1.14 4 | 5 | require github.com/campoy/embedmd v1.0.0 6 | -------------------------------------------------------------------------------- /.bingo/embedmd.sum: -------------------------------------------------------------------------------- 1 | github.com/campoy/embedmd v1.0.0 h1:V4kI2qTJJLf4J29RzI/MAt2c3Bl4dQSYPuflzwFH2hY= 2 | github.com/campoy/embedmd v1.0.0/go.mod h1:oxyr9RCiSXg0M3VJ3ks0UGfp98BpSSGr0kpiX3MzVl8= 3 | github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= 4 | github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= 5 | -------------------------------------------------------------------------------- /.bingo/faillint.mod: -------------------------------------------------------------------------------- 1 | module _ // Auto generated by https://github.com/bwplotka/bingo. DO NOT EDIT 2 | 3 | go 1.17 4 | 5 | require github.com/fatih/faillint v1.11.0 6 | -------------------------------------------------------------------------------- /.bingo/faillint.sum: -------------------------------------------------------------------------------- 1 | dmitri.shuralyov.com/go/generated v0.0.0-20170818220700-b1254a446363 h1:o4lAkfETerCnr1kF9/qwkwjICnU+YLHNDCM8h2xj7as= 2 | dmitri.shuralyov.com/go/generated v0.0.0-20170818220700-b1254a446363/go.mod h1:WG7q7swWsS2f9PYpt5DoEP/EBYWx8We5UoRltn9vJl8= 3 | github.com/fatih/faillint v1.5.0 h1:fUolG+EsD6zdRW4rapzrM0tSf7VdpxWG3GLCPafUOcE= 4 | github.com/fatih/faillint v1.5.0/go.mod h1:e+3n7K3aI9fnZS4aNCggnoB+uBF4hwjqqR7BmA35PCE= 5 | github.com/fatih/faillint v1.10.0 h1:NQ2zhSNuYp0g23/6gyCSi2IfdVIfOk/JkSzpWSDEnYQ= 6 | github.com/fatih/faillint v1.10.0/go.mod h1:upblMxCjN4sL78nBbOHFEH9UGHTSw61M3Kj9BMS0UL0= 7 | github.com/fatih/faillint v1.11.0 h1:EhmAKe8k0Cx2gnf+/JiX/IAeeKjwsQao5dY8oG6cQB4= 8 | github.com/fatih/faillint v1.11.0/go.mod h1:d9kdQwFcr+wD4cLXOdjTw1ENUUvv5+z0ctJ5Wm0dTvA= 9 | github.com/yuin/goldmark v1.4.1/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= 10 | github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY= 11 | golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= 12 | golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= 13 | golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= 14 | golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= 15 | golang.org/x/mod v0.6.0-dev.0.20220106191415-9b9b3d81d5e3 h1:kQgndtyPBW/JIYERgdxfwMYh3AVStj88WQTlNDi2a+o= 16 | golang.org/x/mod v0.6.0-dev.0.20220106191415-9b9b3d81d5e3/go.mod h1:3p9vT2HGsQu2K1YbXdKPJLVgG5VJdoTa1poYQBtP1AY= 17 | golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4 h1:6zppjxzCulZykYSLyVDYbneBfbaBIQPYMevg0bEwv2s= 18 | golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= 19 | golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= 20 | golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= 21 | golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= 22 | golang.org/x/net v0.0.0-20211015210444-4f30a5c0130f/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= 23 | golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= 24 | golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= 25 | golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= 26 | golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= 27 | golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= 28 | golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 29 | golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 30 | golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 31 | golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= 32 | golang.org/x/sys v0.0.0-20211019181941-9d821ace8654 h1:id054HUawV2/6IGm2IV8KZQjqtwAOo2CYlOToYqa0d0= 33 | golang.org/x/sys v0.0.0-20211019181941-9d821ace8654/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= 34 | golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= 35 | golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f h1:v4INt8xihDGvnrfjMDVXGxw9wrfxYyCjk0KbXjhR55s= 36 | golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= 37 | golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= 38 | golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= 39 | golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= 40 | golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= 41 | golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= 42 | golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= 43 | golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= 44 | golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= 45 | golang.org/x/tools v0.0.0-20200207224406-61798d64f025 h1:i84/3szN87uN9jFX/jRqUbszQto2oAsFlqPf6lbR8H4= 46 | golang.org/x/tools v0.0.0-20200207224406-61798d64f025/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= 47 | golang.org/x/tools v0.1.10 h1:QjFRCZxdOhBJ/UNgnBZLbNV13DlbnK0quyivTnXJM20= 48 | golang.org/x/tools v0.1.10/go.mod h1:Uh6Zz+xoGYZom868N8YTex3t7RhtHDBrE8Gzo9bV56E= 49 | golang.org/x/tools v0.1.12 h1:VveCTK38A2rkS8ZqFY25HIDFscX5X9OoEhJd3quQmXU= 50 | golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc= 51 | golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= 52 | golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= 53 | golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 h1:go1bK/D/BFZV2I8cIQd1NKEZ+0owSTG1fDTci4IqFcE= 54 | golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= 55 | -------------------------------------------------------------------------------- /.bingo/go.mod: -------------------------------------------------------------------------------- 1 | module _ // Fake go.mod auto-created by 'bingo' for go -moddir compatibility with non-Go projects. Commit this file, together with other .mod files. -------------------------------------------------------------------------------- /.bingo/goimports.mod: -------------------------------------------------------------------------------- 1 | module _ // Auto generated by https://github.com/bwplotka/bingo. DO NOT EDIT 2 | 3 | go 1.14 4 | 5 | require golang.org/x/tools v0.0.0-20210112230658-8b4aab62c064 // cmd/goimports 6 | -------------------------------------------------------------------------------- /.bingo/goimports.sum: -------------------------------------------------------------------------------- 1 | github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= 2 | golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= 3 | golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= 4 | golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= 5 | golang.org/x/mod v0.3.0 h1:RM4zey1++hCTbCVQfnWeKs9/IEsaBLA8vTkd0WVtmH4= 6 | golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= 7 | golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= 8 | golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= 9 | golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= 10 | golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= 11 | golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= 12 | golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= 13 | golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 14 | golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 15 | golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= 16 | golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= 17 | golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= 18 | golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= 19 | golang.org/x/tools v0.0.0-20210112230658-8b4aab62c064 h1:BmCFkEH4nJrYcAc2L08yX5RhYGD4j58PTMkEUDkpz2I= 20 | golang.org/x/tools v0.0.0-20210112230658-8b4aab62c064/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= 21 | golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= 22 | golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= 23 | golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 h1:go1bK/D/BFZV2I8cIQd1NKEZ+0owSTG1fDTci4IqFcE= 24 | golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= 25 | -------------------------------------------------------------------------------- /.bingo/golangci-lint.mod: -------------------------------------------------------------------------------- 1 | module _ // Auto generated by https://github.com/bwplotka/bingo. DO NOT EDIT 2 | 3 | go 1.14 4 | 5 | require github.com/golangci/golangci-lint v1.51.2 // cmd/golangci-lint 6 | -------------------------------------------------------------------------------- /.bingo/mdox.mod: -------------------------------------------------------------------------------- 1 | module _ // Auto generated by https://github.com/bwplotka/bingo. DO NOT EDIT 2 | 3 | go 1.15 4 | 5 | require github.com/bwplotka/mdox v0.2.1 6 | -------------------------------------------------------------------------------- /.bingo/misspell.mod: -------------------------------------------------------------------------------- 1 | module _ // Auto generated by https://github.com/bwplotka/bingo. DO NOT EDIT 2 | 3 | go 1.14 4 | 5 | require github.com/client9/misspell v0.3.4 // cmd/misspell 6 | -------------------------------------------------------------------------------- /.bingo/misspell.sum: -------------------------------------------------------------------------------- 1 | github.com/client9/misspell v0.3.4 h1:ta993UF76GwbvJcIo3Y68y/M3WxlpEHPWIGDkJYwzJI= 2 | github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= 3 | -------------------------------------------------------------------------------- /.bingo/proxy.mod: -------------------------------------------------------------------------------- 1 | module _ // Auto generated by https://github.com/bwplotka/bingo. DO NOT EDIT 2 | 3 | go 1.15 4 | 5 | require github.com/gomods/athens v0.10.0 // cmd/proxy 6 | -------------------------------------------------------------------------------- /.bingo/variables.env: -------------------------------------------------------------------------------- 1 | # Auto generated binary variables helper managed by https://github.com/bwplotka/bingo v0.7. DO NOT EDIT. 2 | # All tools are designed to be build inside $GOBIN. 3 | # Those variables will work only until 'bingo get' was invoked, or if tools were installed via Makefile's Variables.mk. 4 | GOBIN=${GOBIN:=$(go env GOBIN)} 5 | 6 | if [ -z "$GOBIN" ]; then 7 | GOBIN="$(go env GOPATH)/bin" 8 | fi 9 | 10 | 11 | COPYRIGHT="${GOBIN}/copyright-v0.0.0-20210112004814-138d5e5695fe" 12 | 13 | EMBEDMD="${GOBIN}/embedmd-v1.0.0" 14 | 15 | FAILLINT="${GOBIN}/faillint-v1.11.0" 16 | 17 | GOIMPORTS="${GOBIN}/goimports-v0.0.0-20210112230658-8b4aab62c064" 18 | 19 | GOLANGCI_LINT="${GOBIN}/golangci-lint-v1.51.2" 20 | 21 | MDOX="${GOBIN}/mdox-v0.2.1" 22 | 23 | MISSPELL="${GOBIN}/misspell-v0.3.4" 24 | 25 | PROXY="${GOBIN}/proxy-v0.10.0" 26 | 27 | -------------------------------------------------------------------------------- /.errcheck_excludes.txt: -------------------------------------------------------------------------------- 1 | (github.com/go-kit/log/log.Logger).Log -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/bug-report.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: "\U0001F41B Bug Report" 3 | about: Something isn't working as expected 4 | title: '' 5 | assignees: '' 6 | 7 | --- 8 | 9 | **`bingo version` output**: 10 | 11 | **`go version` output**: 12 | 13 | **What happened**: 14 | 15 | **What you expected to happen**: 16 | 17 | **How to reproduce it (as minimally and precisely as possible)**: 18 | 19 | **Logs (use `bingo get -v ` for verbose output)**: 20 | 21 | **Anything else we need to know**: 22 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/feature-request.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: "\U0001F680 Feature Request" 3 | about: Suggest an idea for improving Thanos 4 | title: '' 5 | labels: "feature request / improvement" 6 | assignees: '' 7 | 8 | --- 9 | -------------------------------------------------------------------------------- /.github/workflows/go.yaml: -------------------------------------------------------------------------------- 1 | name: go 2 | 3 | on: 4 | push: 5 | branches: 6 | - main 7 | tags: 8 | pull_request: 9 | 10 | jobs: 11 | lint: 12 | runs-on: ubuntu-latest 13 | name: Linters (Static Analysis) for Go 14 | steps: 15 | - name: Checkout code into the Go module directory. 16 | uses: actions/checkout@v3 17 | 18 | - name: Install Go 19 | uses: actions/setup-go@v3 20 | with: 21 | go-version: 1.20.x 22 | 23 | - uses: actions/cache@v3 24 | with: 25 | path: ~/go/pkg/mod 26 | key: ${{ runner.os }}-go-${{ hashFiles('**/go.sum') }} 27 | 28 | - name: Linting & vetting. 29 | env: 30 | GOBIN: /tmp/.bin 31 | run: make lint 32 | tests: 33 | runs-on: ${{ matrix.platform }} 34 | strategy: 35 | fail-fast: false 36 | matrix: 37 | go: ['1.20.x'] 38 | platform: [ubuntu-latest, macos-latest] 39 | 40 | name: Unit tests on Go ${{ matrix.go }} ${{ matrix.platform }} 41 | steps: 42 | - name: Checkout code into the Go module directory. 43 | uses: actions/checkout@v3 44 | 45 | - name: Install Go 46 | uses: actions/setup-go@v3 47 | with: 48 | go-version: ${{ matrix.go }} 49 | 50 | - uses: actions/cache@v3 51 | with: 52 | path: ~/go/pkg/mod 53 | key: ${{ runner.os }}-go-${{ hashFiles('**/go.sum') }} 54 | 55 | - name: Run unit tests. 56 | env: 57 | GOBIN: /tmp/.bin 58 | run: make test 59 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Binaries for programs and plugins 2 | *.exe 3 | *.exe~ 4 | *.dll 5 | *.so 6 | *.dylib 7 | 8 | # Test binary, build with `go test -c` 9 | *.test 10 | 11 | # Output of the go coverage tool, specifically when used with LiteIDE 12 | *.out 13 | .idea/* 14 | .bin/* 15 | 16 | gen 17 | .envrc 18 | vendor 19 | 20 | -------------------------------------------------------------------------------- /.golangci.yml: -------------------------------------------------------------------------------- 1 | linters-settings: 2 | errcheck: 3 | exclude: ./.errcheck_excludes.txt -------------------------------------------------------------------------------- /COPYRIGHT: -------------------------------------------------------------------------------- 1 | Copyright (c) bwplotka/mimic Authors 2 | Licensed under the Apache License 2.0. -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Apache License 2 | Version 2.0, January 2004 3 | http://www.apache.org/licenses/ 4 | 5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 6 | 7 | 1. Definitions. 8 | 9 | "License" shall mean the terms and conditions for use, reproduction, 10 | and distribution as defined by Sections 1 through 9 of this document. 11 | 12 | "Licensor" shall mean the copyright owner or entity authorized by 13 | the copyright owner that is granting the License. 14 | 15 | "Legal Entity" shall mean the union of the acting entity and all 16 | other entities that control, are controlled by, or are under common 17 | control with that entity. For the purposes of this definition, 18 | "control" means (i) the power, direct or indirect, to cause the 19 | direction or management of such entity, whether by contract or 20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 21 | outstanding shares, or (iii) beneficial ownership of such entity. 22 | 23 | "You" (or "Your") shall mean an individual or Legal Entity 24 | exercising permissions granted by this License. 25 | 26 | "Source" form shall mean the preferred form for making modifications, 27 | including but not limited to software source code, documentation 28 | source, and configuration files. 29 | 30 | "Object" form shall mean any form resulting from mechanical 31 | transformation or translation of a Source form, including but 32 | not limited to compiled object code, generated documentation, 33 | and conversions to other media types. 34 | 35 | "Work" shall mean the work of authorship, whether in Source or 36 | Object form, made available under the License, as indicated by a 37 | copyright notice that is included in or attached to the work 38 | (an example is provided in the Appendix below). 39 | 40 | "Derivative Works" shall mean any work, whether in Source or Object 41 | form, that is based on (or derived from) the Work and for which the 42 | editorial revisions, annotations, elaborations, or other modifications 43 | represent, as a whole, an original work of authorship. For the purposes 44 | of this License, Derivative Works shall not include works that remain 45 | separable from, or merely link (or bind by name) to the interfaces of, 46 | the Work and Derivative Works thereof. 47 | 48 | "Contribution" shall mean any work of authorship, including 49 | the original version of the Work and any modifications or additions 50 | to that Work or Derivative Works thereof, that is intentionally 51 | submitted to Licensor for inclusion in the Work by the copyright owner 52 | or by an individual or Legal Entity authorized to submit on behalf of 53 | the copyright owner. For the purposes of this definition, "submitted" 54 | means any form of electronic, verbal, or written communication sent 55 | to the Licensor or its representatives, including but not limited to 56 | communication on electronic mailing lists, source code control systems, 57 | and issue tracking systems that are managed by, or on behalf of, the 58 | Licensor for the purpose of discussing and improving the Work, but 59 | excluding communication that is conspicuously marked or otherwise 60 | designated in writing by the copyright owner as "Not a Contribution." 61 | 62 | "Contributor" shall mean Licensor and any individual or Legal Entity 63 | on behalf of whom a Contribution has been received by Licensor and 64 | subsequently incorporated within the Work. 65 | 66 | 2. Grant of Copyright License. Subject to the terms and conditions of 67 | this License, each Contributor hereby grants to You a perpetual, 68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 69 | copyright license to reproduce, prepare Derivative Works of, 70 | publicly display, publicly perform, sublicense, and distribute the 71 | Work and such Derivative Works in Source or Object form. 72 | 73 | 3. Grant of Patent License. Subject to the terms and conditions of 74 | this License, each Contributor hereby grants to You a perpetual, 75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 76 | (except as stated in this section) patent license to make, have made, 77 | use, offer to sell, sell, import, and otherwise transfer the Work, 78 | where such license applies only to those patent claims licensable 79 | by such Contributor that are necessarily infringed by their 80 | Contribution(s) alone or by combination of their Contribution(s) 81 | with the Work to which such Contribution(s) was submitted. If You 82 | institute patent litigation against any entity (including a 83 | cross-claim or counterclaim in a lawsuit) alleging that the Work 84 | or a Contribution incorporated within the Work constitutes direct 85 | or contributory patent infringement, then any patent licenses 86 | granted to You under this License for that Work shall terminate 87 | as of the date such litigation is filed. 88 | 89 | 4. Redistribution. You may reproduce and distribute copies of the 90 | Work or Derivative Works thereof in any medium, with or without 91 | modifications, and in Source or Object form, provided that You 92 | meet the following conditions: 93 | 94 | (a) You must give any other recipients of the Work or 95 | Derivative Works a copy of this License; and 96 | 97 | (b) You must cause any modified files to carry prominent notices 98 | stating that You changed the files; and 99 | 100 | (c) You must retain, in the Source form of any Derivative Works 101 | that You distribute, all copyright, patent, trademark, and 102 | attribution notices from the Source form of the Work, 103 | excluding those notices that do not pertain to any part of 104 | the Derivative Works; and 105 | 106 | (d) If the Work includes a "NOTICE" text file as part of its 107 | distribution, then any Derivative Works that You distribute must 108 | include a readable copy of the attribution notices contained 109 | within such NOTICE file, excluding those notices that do not 110 | pertain to any part of the Derivative Works, in at least one 111 | of the following places: within a NOTICE text file distributed 112 | as part of the Derivative Works; within the Source form or 113 | documentation, if provided along with the Derivative Works; or, 114 | within a display generated by the Derivative Works, if and 115 | wherever such third-party notices normally appear. The contents 116 | of the NOTICE file are for informational purposes only and 117 | do not modify the License. You may add Your own attribution 118 | notices within Derivative Works that You distribute, alongside 119 | or as an addendum to the NOTICE text from the Work, provided 120 | that such additional attribution notices cannot be construed 121 | as modifying the License. 122 | 123 | You may add Your own copyright statement to Your modifications and 124 | may provide additional or different license terms and conditions 125 | for use, reproduction, or distribution of Your modifications, or 126 | for any such Derivative Works as a whole, provided Your use, 127 | reproduction, and distribution of the Work otherwise complies with 128 | the conditions stated in this License. 129 | 130 | 5. Submission of Contributions. Unless You explicitly state otherwise, 131 | any Contribution intentionally submitted for inclusion in the Work 132 | by You to the Licensor shall be under the terms and conditions of 133 | this License, without any additional terms or conditions. 134 | Notwithstanding the above, nothing herein shall supersede or modify 135 | the terms of any separate license agreement you may have executed 136 | with Licensor regarding such Contributions. 137 | 138 | 6. Trademarks. This License does not grant permission to use the trade 139 | names, trademarks, service marks, or product names of the Licensor, 140 | except as required for reasonable and customary use in describing the 141 | origin of the Work and reproducing the content of the NOTICE file. 142 | 143 | 7. Disclaimer of Warranty. Unless required by applicable law or 144 | agreed to in writing, Licensor provides the Work (and each 145 | Contributor provides its Contributions) on an "AS IS" BASIS, 146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 147 | implied, including, without limitation, any warranties or conditions 148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 149 | PARTICULAR PURPOSE. You are solely responsible for determining the 150 | appropriateness of using or redistributing the Work and assume any 151 | risks associated with Your exercise of permissions under this License. 152 | 153 | 8. Limitation of Liability. In no event and under no legal theory, 154 | whether in tort (including negligence), contract, or otherwise, 155 | unless required by applicable law (such as deliberate and grossly 156 | negligent acts) or agreed to in writing, shall any Contributor be 157 | liable to You for damages, including any direct, indirect, special, 158 | incidental, or consequential damages of any character arising as a 159 | result of this License or out of the use or inability to use the 160 | Work (including but not limited to damages for loss of goodwill, 161 | work stoppage, computer failure or malfunction, or any and all 162 | other commercial damages or losses), even if such Contributor 163 | has been advised of the possibility of such damages. 164 | 165 | 9. Accepting Warranty or Additional Liability. While redistributing 166 | the Work or Derivative Works thereof, You may choose to offer, 167 | and charge a fee for, acceptance of support, warranty, indemnity, 168 | or other liability obligations and/or rights consistent with this 169 | License. However, in accepting such obligations, You may act only 170 | on Your own behalf and on Your sole responsibility, not on behalf 171 | of any other Contributor, and only if You agree to indemnify, 172 | defend, and hold each Contributor harmless for any liability 173 | incurred by, or claims asserted against, such Contributor by reason 174 | of your accepting any such warranty or additional liability. 175 | 176 | END OF TERMS AND CONDITIONS 177 | 178 | APPENDIX: How to apply the Apache License to your work. 179 | 180 | To apply the Apache License to your work, attach the following 181 | boilerplate notice, with the fields enclosed by brackets "[]" 182 | replaced with your own identifying information. (Don't include 183 | the brackets!) The text should be enclosed in the appropriate 184 | comment syntax for the file format. We also recommend that a 185 | file or class name and description of purpose be included on the 186 | same "printed page" as the copyright notice for easier 187 | identification within third-party archives. 188 | 189 | Copyright [yyyy] [name of copyright owner] 190 | 191 | Licensed under the Apache License, Version 2.0 (the "License"); 192 | you may not use this file except in compliance with the License. 193 | You may obtain a copy of the License at 194 | 195 | http://www.apache.org/licenses/LICENSE-2.0 196 | 197 | Unless required by applicable law or agreed to in writing, software 198 | distributed under the License is distributed on an "AS IS" BASIS, 199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 200 | See the License for the specific language governing permissions and 201 | limitations under the License. 202 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | include .bingo/Variables.mk 2 | 3 | GO ?= $(shell which go) 4 | FILES_TO_FMT ?= $(shell find . -path ./vendor -prune -o -name '*.go' -print) 5 | 6 | GO111MODULE ?= on 7 | export GO111MODULE 8 | 9 | GOBIN ?= $(firstword $(subst :, ,${GOPATH}))/bin 10 | 11 | # Tools. 12 | GIT ?= $(shell which git) 13 | 14 | # Support gsed on OSX (installed via brew), falling back to sed. On Linux 15 | # systems gsed won't be installed, so will use sed as expected. 16 | SED ?= $(shell which gsed 2>/dev/null || which sed) 17 | 18 | define require_clean_work_tree 19 | @git update-index -q --ignore-submodules --refresh 20 | 21 | @if ! git diff-files --quiet --ignore-submodules --; then \ 22 | echo >&2 "cannot $1: you have unstaged changes."; \ 23 | git diff-files --name-status -r --ignore-submodules -- >&2; \ 24 | echo >&2 "Please commit or stash them."; \ 25 | exit 1; \ 26 | fi 27 | 28 | @if ! git diff-index --cached --quiet HEAD --ignore-submodules --; then \ 29 | echo >&2 "cannot $1: your index contains uncommitted changes."; \ 30 | git diff-index --cached --name-status -r --ignore-submodules HEAD -- >&2; \ 31 | echo >&2 "Please commit or stash them."; \ 32 | exit 1; \ 33 | fi 34 | 35 | endef 36 | 37 | help: ## Displays help. 38 | @awk 'BEGIN {FS = ":.*##"; printf "\nUsage:\n make \033[36m\033[0m\n\nTargets:\n"} /^[a-zA-Z_-]+:.*?##/ { printf " \033[36m%-10s\033[0m %s\n", $$1, $$2 }' $(MAKEFILE_LIST) 39 | 40 | .PHONY: all 41 | all: format test 42 | 43 | .PHONY: update-go-deps 44 | update-go-deps: 45 | @echo ">> updating Go dependencies" 46 | @for m in $$($(GO) list -mod=readonly -m -f '{{ if and (not .Indirect) (not .Main)}}{{.Path}}{{end}}' all); do \ 47 | $(GO) get $$m; \ 48 | done 49 | @$(GO) mod tidy 50 | 51 | .PHONY: test 52 | test: 53 | @echo ">> testing binaries" 54 | @go test ./... 55 | @cd examples/kubernetes-statefulset && go run example.go generate 56 | @cd examples/prometheus-rem-read-benchmark && go run main.go generate 57 | @cd examples/terraform && go run main.go generate 58 | 59 | 60 | .PHONY: deps 61 | deps: ## Ensures fresh go.mod and go.sum. 62 | @go mod tidy 63 | @go mod verify 64 | 65 | .PHONY: format 66 | format: ## Formats Go code including imports and cleans up white noise. 67 | format: $(GOIMPORTS) 68 | @echo ">> formatting code" 69 | @$(GOIMPORTS) -w $(FILES_TO_FMT) 70 | 71 | .PHONY: check-git 72 | check-git: 73 | ifneq ($(GIT),) 74 | @test -x $(GIT) || (echo >&2 "No git executable binary found at $(GIT)."; exit 1) 75 | else 76 | @echo >&2 "No git binary found."; exit 1 77 | endif 78 | 79 | # PROTIP: 80 | # Add 81 | # --cpu-profile-path string Path to CPU profile output file 82 | # --mem-profile-path string Path to memory profile output file 83 | # to debug big allocations during linting. 84 | lint: ## Runs various static analysis against our code. 85 | lint: $(FAILLINT) $(GOLANGCI_LINT) $(COPYRIGHT) $(MISSPELL) format check-git deps 86 | $(call require_clean_work_tree,"detected not clean master before running lint") 87 | @echo ">> verifying modules being imported" 88 | @$(FAILLINT) -paths "github.com/pkg/errors=errors" ./... 89 | @$(FAILLINT) -paths "fmt.{Print,PrintfPrintln,Sprint}" -ignore-tests ./... 90 | @echo ">> examining all of the Go files" 91 | @go vet -stdmethods=false ./... 92 | @echo ">> linting all of the Go files GOGC=${GOGC}" 93 | @$(GOLANGCI_LINT) run 94 | @echo ">> detecting misspells" 95 | @find . -type f | grep -v vendor/ | grep -vE '\./\..*' | xargs $(MISSPELL) -error 96 | @echo ">> ensuring Copyright headers" 97 | @$(COPYRIGHT) $(shell go list -f "{{.Dir}}" ./... | xargs -i find "{}" -name "*.go") 98 | $(call require_clean_work_tree,"detected white noise or/and files without copyright; run 'make lint' file and commit changes.") 99 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Mimic - Define your Configuration, Infrastructure and Deployments as Go Code 2 | 3 | [![Go Report Card](https://goreportcard.com/badge/github.com/bwplotka/mimic)](https://goreportcard.com/report/github.com/bwplotka/mimic) 4 | [![GoDoc](https://godoc.org/github.com/bwplotka/mimic?status.svg)](https://pkg.go.dev/github.com/bwplotka/mimic) 5 | 6 | `mimic`: A Go module for defining, templating and generating configuration in Go: 7 | 8 | * Define your Configuration (e.g Envoy, Prometheus, Alertmanager, Nginx, Prometheus Alerts, Rules, Grafana Dashaboards etc.) 9 | * Define your Infrastructure (e.g Terraform, Ansible, Puppet, Chef, Kubernetes etc) 10 | * Define any other file that you can imagine. 11 | 12 | ...using simple, typed and testable Go code! 13 | 14 | _`mimic`: [Mimic is a super-human with the ability to copy the powers and abilities of others](https://marvel.fandom.com/wiki/Power_Mimicry)._ 15 | 16 | ## Getting Started 17 | 18 | 1. Create a new `.go` file for your config e.g `config/example.go` 19 | 2. Import mimic using Go 1.17+ e.g `go get github.com/bwplotka/mimic@latest` 20 | 3. Instantiate mimic and defer generation in your `main` function using the `mimic` module: 21 | 22 | ```go 23 | package main 24 | 25 | import ( 26 | "github.com/bwplotka/mimic" 27 | ) 28 | 29 | func main() { 30 | generator := mimic.New() 31 | 32 | // Defer Generate to ensure we generate the output. 33 | defer generator.Generate() 34 | 35 | //... 36 | ``` 37 | 38 | 4. Add typed configuration in your `main` to each file using encoding you want using `With` method: `generator.With("config").Add("some.yaml", encoding.GhodssYAML(set))` 39 | 5. Run `go run config/example.go generate` 40 | 6. You will now see the generated Kubernetes YAML file here: `cat gen/config/some.yaml` 41 | 42 | See full [example](examples/kubernetes-statefulset/example.go) here: 43 | 44 | ```go 45 | package main 46 | 47 | import ( 48 | "github.com/bwplotka/mimic" 49 | "github.com/bwplotka/mimic/encoding" 50 | "github.com/go-openapi/swag" 51 | appsv1 "k8s.io/api/apps/v1" 52 | corev1 "k8s.io/api/core/v1" 53 | metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" 54 | ) 55 | 56 | func main() { 57 | generator := mimic.New() 58 | 59 | // Defer Generate to ensure we generate the output. 60 | defer generator.Generate() 61 | 62 | // Hook in your config below. 63 | // As an example Kubernetes configuration! 64 | const name = "some-statefulset" 65 | 66 | // Create some containers ... (imagine for now). 67 | var container1, container2, container3 corev1.Container 68 | var volume1 corev1.Volume 69 | 70 | // Configure a statefulset using native Kubernetes structs. 71 | set := appsv1.StatefulSet{ 72 | TypeMeta: metav1.TypeMeta{ 73 | Kind: "StatefulSet", 74 | APIVersion: "apps/v1", 75 | }, 76 | ObjectMeta: metav1.ObjectMeta{ 77 | Name: name, 78 | Labels: map[string]string{ 79 | "app": name, 80 | }, 81 | }, 82 | Spec: appsv1.StatefulSetSpec{ 83 | Replicas: swag.Int32(2), 84 | ServiceName: name, 85 | Template: corev1.PodTemplateSpec{ 86 | ObjectMeta: metav1.ObjectMeta{ 87 | Labels: map[string]string{ 88 | "app": name, 89 | }, 90 | }, 91 | Spec: corev1.PodSpec{ 92 | InitContainers: []corev1.Container{container1}, 93 | Containers: []corev1.Container{container2, container3}, 94 | Volumes: []corev1.Volume{volume1}, 95 | }, 96 | }, 97 | Selector: &metav1.LabelSelector{ 98 | MatchLabels: map[string]string{ 99 | "app": name, 100 | }, 101 | }, 102 | }, 103 | } 104 | // Now Add some-statefulset.yaml to the config folder. 105 | generator.With("config").Add(name+".yaml", encoding.GhodssYAML(set)) 106 | } 107 | ``` 108 | 109 | Now you are ready to start defining your own resources! 110 | 111 | Other examples can be found in [here](examples). 112 | 113 | ## What is `mimic`? 114 | 115 | `mimic` is a package that allows you to define your configuration using Go and generate this into configuration files 116 | your application and tooling understands. 117 | 118 | ## Why was `mimic` created? 119 | 120 | `mimic` has been built from our past experience using this concept to configure our applications and infrastructure. 121 | 122 | It offers not only to show the concept and an implementation example but also to share what we have learned, best practice and patterns that we believe are valuable for everyone. 123 | 124 | ## But Why Go? 125 | 126 | Why you should define your templates/infra/configs in Go? 127 | 128 | 129 | * Configuration as code ... like actual code, not json, yaml or tf. 130 | 131 | * Go is a strongly **typed** language. This means that compiler and IDE of your choice will *massively* help you 132 | find what config fields are allowed, what values enum expects and what is the type of each field. 133 | 134 | * Unit/Integration test your configuration, infrastructure and deployment. 135 | For example: 136 | * Test your PromQL queries in Prometheus alerts works as expected? Just write unit test for those using e.g [this](https://github.com/prometheus/prometheus/blob/f678e27eb62ecf56e2b0bad82345925a4d6162a2/cmd/promtool/unittest.go#L37) 137 | * Enforce conventions such as service naming conventions via tests. 138 | 139 | * Import configuration structs directly from the project you are configurating for example bring in Kubernestes, Prometheus or 140 | any other structs that are exported. Allowing you to ensure your config matches the project. 141 | 142 | No more blind searches and surprises. It cannot be safer or simpler than this. 143 | 144 | * Versioning and dependency management. Utilize go modules to ensure you are using the correct version of the configuration 145 | for the project version you are running. 146 | 147 | * Documentation of your config, Go recommends [goDoc formatting](https://blog.golang.org/godoc-documenting-go-code), so 148 | you can leverage native comments for each struct's fields to document behaviour or details related to the config field. 149 | Giving you visibility in your config of exactly what your defining. See [this great Kubernetes struct](https://github.com/kubernetes/apimachinery/blob/master/pkg/apis/meta/v1/types.go#L55) as an example. 150 | 151 | * Quick feedback loop. Catch most mistakes and incompatibilities in Go compile time, before you even deploy it further. 152 | As you probably know one of Go goal is to have very fas compilation time, which feels like you are running a script. 153 | 154 | * Keep the set of the languages used in your organization to a minimum - just one: Go, one of the cleanest, simplest and developer friendly languages around. 155 | 156 | ## What `mimic` is **NOT** 157 | 158 | * It does NOT implement any deployment/distribution logic. 159 | * It is NOT intended to trigger any changes. Instead use the right tool for the job e.g. `kubectl apply`, `ansible`, `puppet`, `chef`, `terraform` 160 | * It is NOT (yet) a registry for reusable templates, however we encourage the community to create public repositories for those! 161 | 162 | ## What does `mimic` include? 163 | 164 | * [x] [providers](providers) go structs representing configuration for applications, infrastructure and container management. 165 | * Included are a set of go providers that do not have native structs OR are not easily importable (yet). 166 | * [x] [encoding](encoding) a way to transform your go config struts into specific file types. 167 | * Included are json, yaml and jsonpb. 168 | * [x] [abstractions](abstractions) a way to abstract concepts to a higher level if really needed (see best practice). 169 | * [x] Examples: 170 | * [Infra definitions for Prometheus remote read benchmarks on Kubernetes](examples/prometheus-remote-read-benchmark) 171 | * You want to add your own example here? Write to us on Slack or file GH issue! 172 | 173 | ## Want to help us and Contribute? 174 | 175 | Please do! 176 | 177 | First start defining your configuration, infra and deployment as Go code! 178 | 179 | Share with the community: 180 | * Share the Go templates you create. 181 | * Share the Go configuration structs for non-Go projects. 182 | * Share the Go unit/integration/acceptance tests against certain providers's definitions. 183 | * Share best practices and your experience! 184 | 185 | Please use GitHub issues and our slack `#mimic` for feedback and questions. 186 | 187 | As always pull requests are VERY welcome as well! 188 | 189 | ## Have a project written in Go? 190 | 191 | If you maintain your own project using Go it would be great to help the effort of making config as go a reality by 192 | exposing your configuration structs for users to import. 193 | 194 | How: 195 | * Maintain and export your config structs like Kubernetes does (it is an API and well documented types) 196 | * Define configuration file via [protobuf]() e.g like envoy [here](https://github.com/envoyproxy/envoy/tree/507191a36958bbeb1b11143fe0acb149f3f2fb00/api/envoy/config) 197 | 198 | ## Problems: 199 | 200 | * What if project has only json schema? or no schema at all, just project written in different language: 201 | 202 | Answer: Generate it yourself from YAML (e.g using [this online tool](https://mengzhuo.github.io/yaml-to-go/)). 203 | Answer2: At some point if this concept will be big enough anyone can maintain useful Go module with typed, 204 | documented and testable config for some providers like we have [in providers package](providers) 205 | 206 | * Importing native Go structs is the dream, however: 207 | 208 | * Not all project's config are prepared to be imported (config tied to implementation, huge deps, secret masked, no marshaling etc): 209 | See: https://github.com/prometheus/alertmanager/pull/1804 210 | * This is where providers come in and we can define a set of structs to meet the config specified for your needs. 211 | 212 | ## Documentation 213 | 214 | * [Best Practice](docs/best_practice.md) 215 | 216 | ## Other solutions 217 | 218 | * [Cue](https://github.com/cuelang/cue) 219 | * mixins 220 | * jsonnet 221 | * Pullumi (Paid) 222 | -------------------------------------------------------------------------------- /doc.go: -------------------------------------------------------------------------------- 1 | // Copyright (c) bwplotka/mimic Authors 2 | // Licensed under the Apache License 2.0. 3 | 4 | /* 5 | `mimic`: A Go module for defining and generating config in Go: 6 | 7 | * Define your Configuration (e.g Envoy, Prometheus, Alertmanager, Nginx, Prometheus Alerts, Rules, Grafana Dashaboards etc.) 8 | * Define your Infrastructure (e.g Terraform, Ansible, Puppet, Chef, etc) 9 | * Define your Container Management (e.g Docker compose, Kubernetes, etc) 10 | * Define any other file that you can imagine 11 | 12 | ... using simple, typed and testable Go code! 13 | */ 14 | package mimic 15 | -------------------------------------------------------------------------------- /docs/best_practice.md: -------------------------------------------------------------------------------- 1 | # Guide & Best Practices 2 | 3 | **TL:DR; defining configuration in Go code *is different* than writing robust production go code for an application.** 4 | 5 | This code serves a certain goals like command-line only based file generation, configuring and defining files that will be 6 | consumed by other systems. This means that you need to switch context from other Go code you might write for different purposes. 7 | 8 | In details this means: 9 | 10 | * **DO NOT** try to circumvent the need to understand the upstream product. As with any configuration of a 11 | product, you need to understand how to use that product just as if you were 12 | configuring it directly. 13 | 14 | * Use native structs as much as possible as this e.g Kubernetes struts directly: 15 | * Immediately maps with what you will see once file is deployed. (e.g if you do `kubectl get po -o yaml` someday) 16 | It helps to debug in future and allows others to quickly tweak it even if you are from different team. 17 | * Helps to reuse other templates/patterns from upstream in future 18 | 19 | * Use `panic` as your error handling for unexpected input. Normally it's never acceptable but in this case, it gives you quick feedback on what 20 | is wrong with your configuration/generation and immediately HALTS the generation which is desired. 21 | 22 | * Don't use concurrency. Avoid unnecessary magic. 23 | 24 | * Minimalise unnecessary abstractions. Your configs, infra, deployments should be as verbose as possible. AVOID using `if` 25 | conditions, prefer consistent environments etc. It's *important* as with a powerful language it's easy and tempting to 26 | add abstraction layers and special cases. This is your DEFINITIONS. It should be verbose. 27 | 28 | **300 hundreds lines functions ARE acceptable here.** 29 | 30 | * Where the overhead is not prohibitive, avoid primitive obsession, config structure and values should be written with an 31 | appropriate type. In particular, large string blobs and using strings to specify non-string (e.g. integer, boolean) 32 | options should be avoided. This will also give you strong typing for your configuration. 33 | 34 | * Associate and reference keys together. For example if you some Kubernetes deployment expects ConfigMap called "my-conf", 35 | consider putting "my-conf" in constant and reference it in deployment, or even better, reference ConfigMap.Name directly! 36 | 37 | * Factor out and re-use a constant or parameter if and only if it is required by the system being configured 38 | 39 | * Do not refactor out a common value just because the value occurs in multiple places. 40 | * If a system requires the same value at multiple locations to work correctly, factor that out into 41 | a constant or parameter. 42 | * If you factor out a value into a constant or parameter, that constant or parameter should have 43 | clearly defined semantics for the system being configured, usually reflected by the name given to 44 | the constant or parameter. 45 | * If a value (or substring) occurs in multiple locations with no connection between them: 46 | 47 | * If the values do not not need to be parametrised, use separate literals. 48 | * If the values need to be parameterised, use separate parameters. 49 | 50 | This is important to keep in mind in configuration-oriented code. Trying to refactor anything 51 | similar-looking will result in a spaghetti of dependencies where it is hard for maintainers to 52 | figure out which dependencies are required by the system and which happen to be an artifact of 53 | implementation. The more declarative nature of this code also means that many literals are described 54 | by the field they are being assigned to, and do not need further naming to clarify their purpose. 55 | 56 | * Treat parameters and returned structs as immutable. 57 | 58 | i.e. you may update fields on a struct only in the function containing the literal that created the 59 | struct. 60 | 61 | * Avoid basing configuration/behaviour on the environment or cluster 62 | 63 | i.e. avoid code like “if running in staging do X, if running in production to Y”. Refactor such code 64 | to take a parameter for this behaviour and have the definition of staging and production set the 65 | parameter appropriately. 66 | 67 | * Avoid basing any output or configuration of your applications or infrastructure on your organisational structure ... this will 68 | and does change often so don't bake it into your configuration. 69 | 70 | * **DO NOT** put secrets (tokens, private keys, etc.) in your config definition or output (or anywhere else in your code!) 71 | 72 | i.e For kubernetes you could put secrets in via Kubernetes Secrets. Alternatively define env variables and 73 | use env vars substitution. 74 | 75 | Ultimately use the best tools for this! See [vault](https://www.vaultproject.io/) 76 | 77 | * Do not fetch inputs from outside. 78 | 79 | i.e. do not run external commands or make web requests. 80 | 81 | * Apply YAGNI/KISS/etc. 82 | 83 | (“You ain’t gonna need it”, “Keep it simple, stupid”) 84 | 85 | Aim for simplicity, e.g. do not create a new helper if you are going to use it only in one location. 86 | You can always refactor it out later. 87 | -------------------------------------------------------------------------------- /encoding/doc.go: -------------------------------------------------------------------------------- 1 | // Copyright (c) bwplotka/mimic Authors 2 | // Licensed under the Apache License 2.0. 3 | 4 | /* 5 | encoding is a package of default encodings supplied with mimic. 6 | 7 | Each of the encodings match the following func declaration: 8 | ``` 9 | func XXX(in interface{}) io.Reader { 10 | ``` 11 | 12 | Encodings are called when generating the desired output for a configuration. 13 | 14 | Additional encoders should return `io.Reader` and can be imported directly into the configuration. 15 | */ 16 | package encoding 17 | -------------------------------------------------------------------------------- /encoding/encoder.go: -------------------------------------------------------------------------------- 1 | // Copyright (c) bwplotka/mimic Authors 2 | // Licensed under the Apache License 2.0. 3 | 4 | package encoding 5 | 6 | import "io" 7 | 8 | // Encoder implements the needed functions to encode a Go struct to a particular config language. 9 | type Encoder interface { 10 | io.Reader 11 | 12 | // EncodeComment returns a slice of bytes that represents `lines` as a comment string 13 | // in a particular config language. `lines` can be a single or multiple line comment, separated by '\n'. 14 | EncodeComment(lines string) []byte 15 | } 16 | -------------------------------------------------------------------------------- /encoding/encoding_test.go: -------------------------------------------------------------------------------- 1 | // Copyright (c) bwplotka/mimic Authors 2 | // Licensed under the Apache License 2.0. 3 | 4 | package encoding 5 | 6 | import ( 7 | "io" 8 | "testing" 9 | 10 | "github.com/efficientgo/tools/core/pkg/testutil" 11 | ) 12 | 13 | type A struct { 14 | Field1 string `yaml:"FieldYolo1"` 15 | Field2 int `yaml:",omitempty"` 16 | Inner *A 17 | InnerSlice []A `yaml:",omitempty"` 18 | } 19 | 20 | var testA = []interface{}{ 21 | A{ 22 | Field1: "1", 23 | Field2: 1, 24 | Inner: &A{ 25 | Field1: "inner1", 26 | Field2: 11, 27 | }, 28 | }, 29 | A{ 30 | Field1: "2", 31 | Field2: 2, 32 | InnerSlice: []A{ 33 | {Field2: 3}, 34 | {Field2: 3}, 35 | }, 36 | }, 37 | } 38 | 39 | func TestYaml_EncodingToStructs(t *testing.T) { 40 | for _, tcase := range []struct { 41 | encoder io.Reader 42 | expected string 43 | }{ 44 | { 45 | encoder: GhodssYAML(testA...), 46 | expected: `Field1: "1" 47 | Field2: 1 48 | Inner: 49 | Field1: inner1 50 | Field2: 11 51 | Inner: null 52 | InnerSlice: null 53 | InnerSlice: null 54 | --- 55 | Field1: "2" 56 | Field2: 2 57 | Inner: null 58 | InnerSlice: 59 | - Field1: "" 60 | Field2: 3 61 | Inner: null 62 | InnerSlice: null 63 | - Field1: "" 64 | Field2: 3 65 | Inner: null 66 | InnerSlice: null 67 | `, 68 | }, 69 | { 70 | encoder: YAML(testA...), 71 | expected: `FieldYolo1: "1" 72 | field2: 1 73 | inner: 74 | FieldYolo1: inner1 75 | field2: 11 76 | inner: null 77 | --- 78 | FieldYolo1: "2" 79 | field2: 2 80 | inner: null 81 | innerslice: 82 | - FieldYolo1: "" 83 | field2: 3 84 | inner: null 85 | - FieldYolo1: "" 86 | field2: 3 87 | inner: null 88 | `, 89 | }, 90 | { 91 | encoder: YAML(testA...), 92 | expected: `FieldYolo1: "1" 93 | field2: 1 94 | inner: 95 | FieldYolo1: inner1 96 | field2: 11 97 | inner: null 98 | --- 99 | FieldYolo1: "2" 100 | field2: 2 101 | inner: null 102 | innerslice: 103 | - FieldYolo1: "" 104 | field2: 3 105 | inner: null 106 | - FieldYolo1: "" 107 | field2: 3 108 | inner: null 109 | `, 110 | }, 111 | } { 112 | if ok := t.Run("", func(t *testing.T) { 113 | actual, err := io.ReadAll(tcase.encoder) 114 | testutil.Ok(t, err) 115 | testutil.Equals(t, tcase.expected, string(actual)) 116 | }); !ok { 117 | return 118 | } 119 | } 120 | } 121 | 122 | func TestHCL_EncodingToStructs(t *testing.T) { 123 | type Inner struct { 124 | Key string `hcl:",key"` 125 | Field1 string `hcl:"field1"` 126 | Field2 int `hcl:"field2"` 127 | } 128 | 129 | actual, err := io.ReadAll(HCL( 130 | struct { 131 | Inner `hcl:"inner"` 132 | }{Inner{ 133 | Key: "test", 134 | Field1: "first", 135 | Field2: 12, 136 | }, 137 | }, 138 | )) 139 | testutil.Ok(t, err) 140 | testutil.Equals(t, `inner "test" { 141 | field1 = "first" 142 | field2 = 12 143 | } 144 | `, string(actual)) 145 | } 146 | 147 | func TestEncodingComments(t *testing.T) { 148 | for _, tcase := range []struct { 149 | name string 150 | encoder Encoder 151 | comment string 152 | expected string 153 | }{ 154 | { 155 | name: "single line ghodss", 156 | encoder: GhodssYAML(), 157 | comment: "This is a single line comment.", 158 | expected: "# This is a single line comment.\n", 159 | }, 160 | { 161 | name: "multi line ghodss", 162 | encoder: GhodssYAML(), 163 | comment: "This is a multi\n line comment.", 164 | expected: "# This is a multi\n# line comment.\n", 165 | }, 166 | { 167 | name: "single line yaml2", 168 | encoder: YAML2(), 169 | comment: "This is a single line comment.", 170 | expected: "# This is a single line comment.\n", 171 | }, 172 | { 173 | name: "multi line yaml2", 174 | encoder: YAML2(), 175 | comment: "This is a multi\n line comment.", 176 | expected: "# This is a multi\n# line comment.\n", 177 | }, 178 | { 179 | name: "single line hcl", 180 | encoder: HCL(testA), 181 | comment: "This is a single line comment.", 182 | expected: "# This is a single line comment.\n", 183 | }, 184 | { 185 | name: "multi line hcl", 186 | encoder: HCL(testA), 187 | comment: "This is a multi\n line comment.", 188 | expected: "# This is a multi\n# line comment.\n", 189 | }, 190 | { 191 | name: "single line json", 192 | encoder: JSON(testA), 193 | comment: "This is a single line comment.", 194 | expected: "", 195 | }, 196 | { 197 | name: "multi line json", 198 | encoder: JSON(testA), 199 | comment: "This is a multi\n line comment.", 200 | expected: "", 201 | }, 202 | } { 203 | if ok := t.Run(tcase.name, func(t *testing.T) { 204 | actual := tcase.encoder.EncodeComment(tcase.comment) 205 | testutil.Equals(t, tcase.expected, string(actual)) 206 | }); !ok { 207 | return 208 | } 209 | } 210 | } 211 | -------------------------------------------------------------------------------- /encoding/errreader.go: -------------------------------------------------------------------------------- 1 | // Copyright (c) bwplotka/mimic Authors 2 | // Licensed under the Apache License 2.0. 3 | 4 | package encoding 5 | 6 | type errReader struct{ err error } 7 | 8 | func (r errReader) Read(_ []byte) (int, error) { return 0, r.err } 9 | -------------------------------------------------------------------------------- /encoding/hcl.go: -------------------------------------------------------------------------------- 1 | // Copyright (c) bwplotka/mimic Authors 2 | // Licensed under the Apache License 2.0. 3 | 4 | package encoding 5 | 6 | import ( 7 | "bytes" 8 | "fmt" 9 | "io" 10 | 11 | "github.com/rodaine/hclencoder" 12 | ) 13 | 14 | // hclEncoder implements the Encoder interface. 15 | type hclEncoder struct { 16 | io.Reader 17 | } 18 | 19 | // EncodeComment returns byte slice that represents a HCL comment (same as YAML). 20 | // We split `lines` by '\n' and encode as a single/multi line comment. 21 | func (hclEncoder) EncodeComment(lines string) []byte { 22 | return YAML().EncodeComment(lines) 23 | } 24 | 25 | func HCL(in interface{}) hclEncoder { 26 | b, err := hclencoder.Encode(in) 27 | if err != nil { 28 | return hclEncoder{Reader: errReader{err: fmt.Errorf("unable to marshal to HCL: %v: %w", in, err)}} 29 | } 30 | return hclEncoder{Reader: bytes.NewBuffer(b)} 31 | } 32 | -------------------------------------------------------------------------------- /encoding/json.go: -------------------------------------------------------------------------------- 1 | // Copyright (c) bwplotka/mimic Authors 2 | // Licensed under the Apache License 2.0. 3 | 4 | package encoding 5 | 6 | import ( 7 | "bytes" 8 | "encoding/json" 9 | "fmt" 10 | "io" 11 | ) 12 | 13 | // jsonEncoder implements the Encoder interface. 14 | type jsonEncoder struct { 15 | io.Reader 16 | } 17 | 18 | // EncodeComment is a no-op for JSON encoder, as JSON doesn't support comments. 19 | func (jsonEncoder) EncodeComment(lines string) []byte { 20 | return []byte{} 21 | } 22 | 23 | // JSON returns reader that encodes anything to JSON. 24 | func JSON(in interface{}) jsonEncoder { 25 | b, err := json.MarshalIndent(in, "", " ") 26 | if err != nil { 27 | return jsonEncoder{Reader: errReader{err: fmt.Errorf("unable to marshal to JSON: %v: %w", in, err)}} 28 | } 29 | 30 | return jsonEncoder{Reader: bytes.NewBuffer(b)} 31 | } 32 | -------------------------------------------------------------------------------- /encoding/yaml.go: -------------------------------------------------------------------------------- 1 | // Copyright (c) bwplotka/mimic Authors 2 | // Licensed under the Apache License 2.0. 3 | 4 | package encoding 5 | 6 | import ( 7 | "bytes" 8 | "errors" 9 | "fmt" 10 | "io" 11 | "strings" 12 | 13 | ghodssyaml "github.com/ghodss/yaml" 14 | yaml2 "gopkg.in/yaml.v3" 15 | yaml3 "gopkg.in/yaml.v3" 16 | ) 17 | 18 | // yamlEncoder implements the Encoder interface. 19 | type yamlEncoder struct { 20 | io.Reader 21 | } 22 | 23 | // EncodeComment returns byte slice that represents a YAML comment. 24 | // We split `lines` by '\n' and encode as a single/multi line comment. 25 | func (yamlEncoder) EncodeComment(lines string) []byte { 26 | commentLines := strings.Split(lines, "\n") 27 | 28 | finalString := "" 29 | for _, comment := range commentLines { 30 | if comment == "" { 31 | continue 32 | } 33 | 34 | if finalString == "" { 35 | finalString = "# " + strings.TrimLeft(comment, " ") 36 | } else { 37 | finalString = finalString + "\n" + "# " + strings.TrimLeft(comment, " ") 38 | } 39 | } 40 | 41 | if finalString == "" { 42 | return []byte{} 43 | } 44 | 45 | finalString = finalString + "\n" 46 | return []byte(finalString) 47 | } 48 | 49 | // GhodssYAML returns reader that encodes anything to YAML using github.com/ghodss/yaml. 50 | // It works by first marshalling to JSON, so no `yaml` directive will work (it accepts `json` though). 51 | // 52 | // Recommended for: 53 | // * Kubernetes 54 | func GhodssYAML(in ...interface{}) yamlEncoder { 55 | return yaml(ghodssyaml.Marshal, in...) 56 | } 57 | 58 | // YAML returns reader that encodes anything to YAML using gopkg.in/yaml.v3. 59 | // NOTE: Indentations are currently "weird": https://github.com/go-yaml/yaml/issues/661 60 | func YAML(in ...interface{}) yamlEncoder { 61 | return yaml(yaml3.Marshal, in...) 62 | } 63 | 64 | // YAML2 returns reader that encodes anything to YAML using gopkg.in/yaml.v2. 65 | // NOTE: Indentations are currently "weird": https://github.com/go-yaml/yaml/issues/661 66 | // Recommended for: 67 | // * Prometheus, Alertmanager configuration 68 | func YAML2(in ...interface{}) yamlEncoder { 69 | return yaml(yaml2.Marshal, in...) 70 | } 71 | 72 | type MarshalFunc func(o interface{}) ([]byte, error) 73 | 74 | func yaml(marshalFn MarshalFunc, in ...interface{}) yamlEncoder { 75 | var concatDelim = []byte("---\n") 76 | 77 | if len(in) == 0 { 78 | return yamlEncoder{Reader: errReader{err: errors.New("nothing to output")}} 79 | } 80 | var res [][]byte 81 | for _, entry := range in { 82 | var entryBytes []byte 83 | 84 | // Do not marshal strings - they should be appended directly 85 | if extraString, ok := entry.(string); ok { 86 | entryBytes = []byte(extraString) 87 | } else { 88 | b, err := marshalFn(entry) 89 | if err != nil { 90 | return yamlEncoder{Reader: errReader{err: fmt.Errorf("unable to marshal to YAML: %v: %w", in, err)}} 91 | } 92 | entryBytes = b 93 | } 94 | res = append(res, entryBytes) 95 | } 96 | 97 | if len(res) == 1 { 98 | return yamlEncoder{ 99 | Reader: bytes.NewBuffer(res[0]), 100 | } 101 | } 102 | 103 | return yamlEncoder{ 104 | Reader: bytes.NewBuffer(bytes.Join(res, concatDelim)), 105 | } 106 | } 107 | -------------------------------------------------------------------------------- /examples/kubernetes-statefulset/example.go: -------------------------------------------------------------------------------- 1 | // Copyright (c) bwplotka/mimic Authors 2 | // Licensed under the Apache License 2.0. 3 | 4 | package main 5 | 6 | import ( 7 | "github.com/bwplotka/mimic" 8 | "github.com/bwplotka/mimic/encoding" 9 | "github.com/go-openapi/swag" 10 | appsv1 "k8s.io/api/apps/v1" 11 | corev1 "k8s.io/api/core/v1" 12 | metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" 13 | ) 14 | 15 | func main() { 16 | generator := mimic.New().WithTopLevelComment(mimic.GeneratedComment) 17 | 18 | // Defer Generate to ensure we generate the output. 19 | defer generator.Generate() 20 | 21 | // Hook in your config below. 22 | // As an example Kubernetes configuration! 23 | const name = "some-statefulset" 24 | 25 | // Create some containers ... (imagine for now). 26 | var container1, container2, container3 corev1.Container 27 | var volume1 corev1.Volume 28 | 29 | // Configure a statefulset using native Kubernetes structs. 30 | set := appsv1.StatefulSet{ 31 | TypeMeta: metav1.TypeMeta{ 32 | Kind: "StatefulSet", 33 | APIVersion: "apps/v1", 34 | }, 35 | ObjectMeta: metav1.ObjectMeta{ 36 | Name: name, 37 | Labels: map[string]string{ 38 | "app": name, 39 | }, 40 | }, 41 | Spec: appsv1.StatefulSetSpec{ 42 | Replicas: swag.Int32(2), 43 | ServiceName: name, 44 | Template: corev1.PodTemplateSpec{ 45 | ObjectMeta: metav1.ObjectMeta{ 46 | Labels: map[string]string{ 47 | "app": name, 48 | }, 49 | }, 50 | Spec: corev1.PodSpec{ 51 | InitContainers: []corev1.Container{container1}, 52 | Containers: []corev1.Container{container2, container3}, 53 | Volumes: []corev1.Volume{volume1}, 54 | }, 55 | }, 56 | Selector: &metav1.LabelSelector{ 57 | MatchLabels: map[string]string{ 58 | "app": name, 59 | }, 60 | }, 61 | }, 62 | } 63 | // Now Add some-statefulset.yaml to the config folder. 64 | generator.With("config").WithTopLevelComment("Represents a K8s StatefulSet \nwith two containers.").Add(name+".yaml", encoding.GhodssYAML(set)) 65 | } 66 | -------------------------------------------------------------------------------- /examples/kubernetes-statefulset/go.mod: -------------------------------------------------------------------------------- 1 | module github.com/bwplotka/mimic/examples/kubernetes-statefulset 2 | 3 | go 1.16 4 | 5 | require ( 6 | github.com/bwplotka/mimic v0.0.0-20190730202618-06ab9976e8ef 7 | github.com/go-openapi/swag v0.19.15 8 | k8s.io/api v0.20.5 9 | k8s.io/apimachinery v0.20.5 10 | ) 11 | 12 | // This module is meant to be executed from repo root. 13 | replace github.com/bwplotka/mimic => ../../ 14 | -------------------------------------------------------------------------------- /examples/kubernetes-statefulset/go.sum: -------------------------------------------------------------------------------- 1 | cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= 2 | github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= 3 | github.com/NYTimes/gziphandler v0.0.0-20170623195520-56545f4a5d46/go.mod h1:3wb06e3pkSAbeQ52E9H9iFoQsEEwGN64994WTCIhntQ= 4 | github.com/PuerkitoBio/purell v1.1.1/go.mod h1:c11w/QuzBsJSee3cPx9rAFu61PvFxuPbtSwDGJws/X0= 5 | github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578/go.mod h1:uGdkoq3SwY9Y+13GIhn11/XLaGBb4BfwItxLd5jeuXE= 6 | github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751 h1:JYp7IbQjafoB+tBA3gMyHYHrpOtNuDiK/uB5uXxq5wM= 7 | github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= 8 | github.com/alecthomas/units v0.0.0-20211218093645-b94a6e3cc137 h1:s6gZFSlWYmbqAuRjVTiNNhvNRfY2Wxp9nhfyel4rklc= 9 | github.com/alecthomas/units v0.0.0-20211218093645-b94a6e3cc137/go.mod h1:OMCwj8VM1Kc9e19TLln2VL61YJF0x1XFtfdL4JdbSyE= 10 | github.com/asaskevich/govalidator v0.0.0-20190424111038-f61b66f89f4a/go.mod h1:lB+ZfQJz7igIIfQNfa7Ml4HSf2uFQQRzpGGRXenZAgY= 11 | github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= 12 | github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= 13 | github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= 14 | github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= 15 | github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= 16 | github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= 17 | github.com/docker/spdystream v0.0.0-20160310174837-449fdfce4d96/go.mod h1:Qh8CwZgvJUkLughtfhJv5dyTYa91l1fOUCrgjqmcifM= 18 | github.com/docopt/docopt-go v0.0.0-20180111231733-ee0de3bc6815/go.mod h1:WwZ+bS3ebgob9U8Nd0kOddGdZWjyMGR8Wziv+TBNwSE= 19 | github.com/efficientgo/tools/core v0.0.0-20220225185207-fe763185946b h1:ZHiD4/yE4idlbqvAO6iYCOYRzOMRpxkW+FKasRA3tsQ= 20 | github.com/efficientgo/tools/core v0.0.0-20220225185207-fe763185946b/go.mod h1:OmVcnJopJL8d3X3sSXTiypGoUSgFq1aDGmlrdi9dn/M= 21 | github.com/elazarl/goproxy v0.0.0-20180725130230-947c36da3153/go.mod h1:/Zj4wYkgs4iZTTu3o/KG3Itv/qCCa8VVMlb3i9OVuzc= 22 | github.com/emicklei/go-restful v0.0.0-20170410110728-ff4f55a20633/go.mod h1:otzb+WCGbkyDHkqmQmT5YD2WR4BBwUdeQoFo8l/7tVs= 23 | github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= 24 | github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= 25 | github.com/evanphx/json-patch v4.9.0+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk= 26 | github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= 27 | github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ= 28 | github.com/ghodss/yaml v0.0.0-20150909031657-73d445a93680/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= 29 | github.com/ghodss/yaml v1.0.0 h1:wQHKEahhL6wmXdzwWG11gIVCkOv05bNOh+Rxn0yngAk= 30 | github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= 31 | github.com/go-kit/log v0.2.1 h1:MRVx0/zhvdseW+Gza6N9rVzU/IVzaeE1SFI4raAhmBU= 32 | github.com/go-kit/log v0.2.1/go.mod h1:NwTd00d/i8cPZ3xOwwiv2PO5MOcx78fFErGNcVmBjv0= 33 | github.com/go-logfmt/logfmt v0.5.1 h1:otpy5pqBCBZ1ng9RQ0dPu4PN7ba75Y/aA+UpowDyNVA= 34 | github.com/go-logfmt/logfmt v0.5.1/go.mod h1:WYhtIu8zTZfxdn5+rREduYbwxfcBr/Vr6KEVveWlfTs= 35 | github.com/go-logr/logr v0.1.0/go.mod h1:ixOQHD9gLJUVQQ2ZOR7zLEifBX6tGkNJF4QyIY7sIas= 36 | github.com/go-logr/logr v0.2.0 h1:QvGt2nLcHH0WK9orKa+ppBPAxREcH364nPUedEpK0TY= 37 | github.com/go-logr/logr v0.2.0/go.mod h1:z6/tIYblkpsD+a4lm/fGIIU9mZ+XfAiaFtq7xTgseGU= 38 | github.com/go-openapi/jsonpointer v0.19.2/go.mod h1:3akKfEdA7DF1sugOqz1dVQHBcuDBPKZGEoHC/NkiQRg= 39 | github.com/go-openapi/jsonpointer v0.19.3/go.mod h1:Pl9vOtqEWErmShwVjC8pYs9cog34VGT37dQOVbmoatg= 40 | github.com/go-openapi/jsonreference v0.19.2/go.mod h1:jMjeRr2HHw6nAVajTXJ4eiUwohSTlpa0o73RUL1owJc= 41 | github.com/go-openapi/jsonreference v0.19.3/go.mod h1:rjx6GuL8TTa9VaixXglHmQmIL98+wF9xc8zWvFonSJ8= 42 | github.com/go-openapi/spec v0.19.3/go.mod h1:FpwSN1ksY1eteniUU7X0N/BgJ7a4WvBFVA8Lj9mJglo= 43 | github.com/go-openapi/swag v0.19.2/go.mod h1:POnQmlKehdgb5mhVOsnJFsivZCEZ/vjK9gh66Z9tfKk= 44 | github.com/go-openapi/swag v0.19.5/go.mod h1:POnQmlKehdgb5mhVOsnJFsivZCEZ/vjK9gh66Z9tfKk= 45 | github.com/go-openapi/swag v0.19.15 h1:D2NRCBzS9/pEY3gP9Nl8aDqGUcPFrwG2p+CNFrLyrCM= 46 | github.com/go-openapi/swag v0.19.15/go.mod h1:QYRuS/SOXUCsnplDa677K7+DxSOj6IPNl/eQntq43wQ= 47 | github.com/gogo/protobuf v1.3.1 h1:DqDEcV5aeaTmdFBePNpYsp3FlcVH/2ISVVM9Qf8PSls= 48 | github.com/gogo/protobuf v1.3.1/go.mod h1:SlYgWuQ5SjCEi6WLHjHCa1yvBfUnHcTbrrZtXPKa29o= 49 | github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= 50 | github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= 51 | github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= 52 | github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= 53 | github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= 54 | github.com/golang/protobuf v1.3.3/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw= 55 | github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8= 56 | github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA= 57 | github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs= 58 | github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w= 59 | github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0= 60 | github.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QDs8UjoX8= 61 | github.com/golang/protobuf v1.4.3/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= 62 | github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= 63 | github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= 64 | github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= 65 | github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= 66 | github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= 67 | github.com/google/go-cmp v0.5.2 h1:X2ev0eStA3AbceY54o37/0PQ/UWqKEiiO2dKL5OPaFM= 68 | github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= 69 | github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= 70 | github.com/google/gofuzz v1.1.0 h1:Hsa8mG0dQ46ij8Sl2AYJDUv1oA9/d6Vk+3LG99Oe02g= 71 | github.com/google/gofuzz v1.1.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= 72 | github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= 73 | github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= 74 | github.com/googleapis/gnostic v0.4.1/go.mod h1:LRhVm6pbyptWbWbuZ38d1eyptfvIytN3ir6b65WBswg= 75 | github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= 76 | github.com/hashicorp/hcl v1.0.0 h1:0Anlzjpi4vEasTeNFn2mLJgTSwt0+6sfsiTG8qcWGx4= 77 | github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ= 78 | github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU= 79 | github.com/josharian/intern v1.0.0 h1:vlS4z54oSdjm0bgjRigI+G1HpF+tI+9rE5LLzOg8HmY= 80 | github.com/josharian/intern v1.0.0/go.mod h1:5DoeVV0s6jJacbCEi61lwdGj/aVlrQvzHFFd8Hwg//Y= 81 | github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU= 82 | github.com/json-iterator/go v1.1.10 h1:Kz6Cvnvv2wGdaG/V8yMvfkmNiXq9Ya2KUv4rouJJr68= 83 | github.com/json-iterator/go v1.1.10/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= 84 | github.com/kisielk/errcheck v1.2.0/go.mod h1:/BMXB+zMLi60iA8Vv6Ksmxu/1UDYcXs4uQLJ+jE2L00= 85 | github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= 86 | github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= 87 | github.com/kr/pretty v0.2.0/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= 88 | github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= 89 | github.com/kr/pty v1.1.5/go.mod h1:9r2w37qlBe7rQ6e1fg1S/9xpWHSnaqNdHD3WcMdbPDA= 90 | github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= 91 | github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= 92 | github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= 93 | github.com/mailru/easyjson v0.0.0-20190614124828-94de47d64c63/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= 94 | github.com/mailru/easyjson v0.0.0-20190626092158-b2ccc519800e/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= 95 | github.com/mailru/easyjson v0.7.6 h1:8yTIVnZgCoiM1TgqoeTl+LfU5Jg6/xL3QhGQnimLYnA= 96 | github.com/mailru/easyjson v0.7.6/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc= 97 | github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= 98 | github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= 99 | github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg= 100 | github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= 101 | github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= 102 | github.com/modern-go/reflect2 v1.0.1 h1:9f412s+6RmYXLWZSEzVVgPGK7C2PphHj5RJrvfx9AWI= 103 | github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= 104 | github.com/munnerz/goautoneg v0.0.0-20120707110453-a547fc61f48d/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ= 105 | github.com/mxk/go-flowrate v0.0.0-20140419014527-cca7078d478f/go.mod h1:ZdcZmHo+o7JKHSa8/e818NopupXU1YMK5fe1lsApnBw= 106 | github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e h1:fD57ERR4JtEqsWbfPhv4DMiApHyliiK5xCTNVSPiaAs= 107 | github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno= 108 | github.com/onsi/ginkgo v0.0.0-20170829012221-11459a886d9c/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= 109 | github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= 110 | github.com/onsi/ginkgo v1.11.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= 111 | github.com/onsi/gomega v0.0.0-20170829124025-dcabb60a477c/go.mod h1:C1qb7wdrVGGVU+Z6iS04AVkA3Q65CEZX59MT0QO5uiA= 112 | github.com/onsi/gomega v1.7.0/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY= 113 | github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= 114 | github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= 115 | github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= 116 | github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= 117 | github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= 118 | github.com/rodaine/hclencoder v0.0.1 h1:1jK2rGFxSDT1eU9oVjK4ewrIhMWTcc0yCfZMiN6xRJM= 119 | github.com/rodaine/hclencoder v0.0.1/go.mod h1:XKt85p0Ifyt0pr1KVeB3eL+dUFAKa+IA637lLahBcOQ= 120 | github.com/spf13/pflag v0.0.0-20170130214245-9ff6c6923cff/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= 121 | github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA= 122 | github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= 123 | github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= 124 | github.com/stretchr/objx v0.2.0/go.mod h1:qt09Ya8vawLte6SNmTgCsAVtYtaKzEcn8ATUoHMkEqE= 125 | github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= 126 | github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= 127 | github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= 128 | github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= 129 | github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= 130 | github.com/stretchr/testify v1.7.4 h1:wZRexSlwd7ZXfKINDLsO4r7WBt3gTKONc6K/VesHvHM= 131 | github.com/stretchr/testify v1.7.4/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= 132 | go.uber.org/goleak v1.1.10 h1:z+mqJhf6ss6BSfSM671tgKyZBFPTTJM+HLxnhPC3wu0= 133 | go.uber.org/goleak v1.1.10/go.mod h1:8a7PlsEVH3e/a/GLqe5IIrQx6GzcnRmZEufDUTk4A7A= 134 | golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= 135 | golang.org/x/crypto v0.0.0-20190611184440-5c40567a22f8/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= 136 | golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= 137 | golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= 138 | golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= 139 | golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU= 140 | golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= 141 | golang.org/x/lint v0.0.0-20190930215403-16217165b5de h1:5hukYrvBGR8/eNkX5mdUezrA6JiaEZDtJb9Ei+1LlBs= 142 | golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= 143 | golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= 144 | golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= 145 | golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= 146 | golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= 147 | golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= 148 | golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= 149 | golang.org/x/net v0.0.0-20190613194153-d28f0bde5980/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= 150 | golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= 151 | golang.org/x/net v0.0.0-20190827160401-ba9fcec4b297/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= 152 | golang.org/x/net v0.0.0-20200324143707-d3edc9973b7e/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= 153 | golang.org/x/net v0.0.0-20201110031124-69a78807bb2b h1:uwuIcX0g4Yl1NC5XAz37xsr2lTtcqevgzYNVt49waME= 154 | golang.org/x/net v0.0.0-20201110031124-69a78807bb2b/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= 155 | golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= 156 | golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= 157 | golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= 158 | golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= 159 | golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= 160 | golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= 161 | golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= 162 | golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 163 | golang.org/x/sys v0.0.0-20190616124812-15dcb6c0061f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 164 | golang.org/x/sys v0.0.0-20191005200804-aed5e4c7ecf9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 165 | golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 166 | golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 167 | golang.org/x/sys v0.0.0-20201112073958-5cba982894dd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 168 | golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= 169 | golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= 170 | golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= 171 | golang.org/x/text v0.3.4 h1:0YWbFKbhXG/wIiuHDSKpS0Iy7FSA+u45VtBMfQcFTTc= 172 | golang.org/x/text v0.3.4/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= 173 | golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= 174 | golang.org/x/tools v0.0.0-20181030221726-6c7e314b6563/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= 175 | golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= 176 | golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY= 177 | golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= 178 | golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= 179 | golang.org/x/tools v0.0.0-20190614205625-5aca471b1d59/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= 180 | golang.org/x/tools v0.0.0-20191108193012-7d206e10da11 h1:Yq9t9jnGoR+dBuitxdo9l6Q7xh/zOyNnYUtDKaQ3x0E= 181 | golang.org/x/tools v0.0.0-20191108193012-7d206e10da11/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= 182 | golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= 183 | golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= 184 | golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= 185 | google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= 186 | google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= 187 | google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= 188 | google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= 189 | google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo= 190 | google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= 191 | google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= 192 | google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= 193 | google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= 194 | google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0= 195 | google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM= 196 | google.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miEFZTKqfCUM6K7xSMQL9OKL/b6hQv+e19PK+JZNE= 197 | google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo= 198 | google.golang.org/protobuf v1.22.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= 199 | google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= 200 | google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= 201 | google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c= 202 | gopkg.in/alecthomas/kingpin.v2 v2.2.6 h1:jMFz6MfLP0/4fUyZle81rXUoxOBFi19VUFKVDOQfozc= 203 | gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw= 204 | gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= 205 | gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= 206 | gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= 207 | gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f h1:BLraFXnmrev5lT+xlilqcH8XK9/i0At2xKjWk4p6zsU= 208 | gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= 209 | gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys= 210 | gopkg.in/inf.v0 v0.9.1 h1:73M5CoZyi3ZLMOyDlQh031Cx6N9NDJ2Vvfl76EDAgDc= 211 | gopkg.in/inf.v0 v0.9.1/go.mod h1:cWUDdTG/fYaXco+Dcufb5Vnc6Gp2YChqWtbxRZE0mXw= 212 | gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw= 213 | gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= 214 | gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= 215 | gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= 216 | gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY= 217 | gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= 218 | gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= 219 | gopkg.in/yaml.v3 v3.0.0-20200615113413-eeeca48fe776/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= 220 | gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= 221 | gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= 222 | honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= 223 | honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= 224 | k8s.io/api v0.20.5 h1:zsMTffV0Le2EiI0aKvlTHEnXGxk1HiqGRhJcCPiI7JI= 225 | k8s.io/api v0.20.5/go.mod h1:FQjAceXnVaWDeov2YUWhOb6Yt+5UjErkp6UO3nczO1Y= 226 | k8s.io/apimachinery v0.20.5 h1:wO/FxMVRn223rAKxnBbwCyuN96bS9MFTIvP0e/V7cps= 227 | k8s.io/apimachinery v0.20.5/go.mod h1:WlLqWAHZGg07AeltaI0MV5uk1Omp8xaN0JGLY6gkRpU= 228 | k8s.io/gengo v0.0.0-20200413195148-3a45101e95ac/go.mod h1:ezvh/TsK7cY6rbqRK0oQQ8IAqLxYwwyPxAX1Pzy0ii0= 229 | k8s.io/klog/v2 v2.0.0/go.mod h1:PBfzABfn139FHAV07az/IF9Wp1bkk3vpT2XSJ76fSDE= 230 | k8s.io/klog/v2 v2.4.0 h1:7+X0fUguPyrKEC4WjH8iGDg3laWgMo5tMnRTIGTTxGQ= 231 | k8s.io/klog/v2 v2.4.0/go.mod h1:Od+F08eJP+W3HUb4pSrPpgp9DGU4GzlpG/TmITuYh/Y= 232 | k8s.io/kube-openapi v0.0.0-20201113171705-d219536bb9fd/go.mod h1:WOJ3KddDSol4tAGcJo0Tvi+dK12EcqSLqcWsryKMpfM= 233 | sigs.k8s.io/structured-merge-diff/v4 v4.0.2 h1:YHQV7Dajm86OuqnIR6zAelnDWBRjo+YhYV9PmGrh1s8= 234 | sigs.k8s.io/structured-merge-diff/v4 v4.0.2/go.mod h1:bJZC9H9iH24zzfZ/41RGcq60oK1F7G282QMXDPYydCw= 235 | sigs.k8s.io/yaml v1.1.0/go.mod h1:UJmg0vDUVViEyp3mgSv9WPwZCDxu4rQW1olrI1uml+o= 236 | sigs.k8s.io/yaml v1.2.0 h1:kr/MCeFWJWTwyaHoR9c8EjH9OumOmoF9YGiZd7lFm/Q= 237 | sigs.k8s.io/yaml v1.2.0/go.mod h1:yfXDCHCao9+ENCvLSE62v9VSji2MKu5jeNfTrofGhJc= 238 | -------------------------------------------------------------------------------- /examples/prometheus-rem-read-benchmark/README.md: -------------------------------------------------------------------------------- 1 | # Prometheus definitions for remote read. 2 | 3 | This definition contains Prometheus statefulsets definitions set up to test remote read changes described [here](https://docs.google.com/document/d/1JqrU3NjM9HoGLSTPYOvR217f5HBKBiJTqikEB9UiJL0/edit#). 4 | 5 | ## Usage 6 | 7 | Generate Kubernetes YAML: 8 | 9 | `go run examples/prometheus-remote-read-benchmark/main.go generate` 10 | 11 | See the `gen` directory. `ls gen` should give you `prom-rr-test-streamed.yaml prom-rr-test.yaml` 12 | 13 | Those are 2 Prometheus + Thanos. One is baseline, second is a version with modified remote read that allows streaming encoded chunks. 14 | You can use `kubectl apply` to deploy those. 15 | 16 | Those resources are crafted for benchmark purposes -> they generate artificial metric data. 17 | 18 | [@bwplotka](https://bwplotka.dev/) is using those to benchmark new remote read with Thanos sidecar on live Kubernetes cluster. -------------------------------------------------------------------------------- /examples/prometheus-rem-read-benchmark/abstr/doc.go: -------------------------------------------------------------------------------- 1 | // Copyright (c) bwplotka/mimic Authors 2 | // Licensed under the Apache License 2.0. 3 | 4 | /* 5 | Abstractions are used to (as the name suggests) abstract away the underlying config and structs to the caller allowing 6 | complex configurations or concepts to be created with minimal code. 7 | 8 | Abstraction packages should follow a folder structure that allows clear understanding of the abstraction. 9 | ``` 10 | abstractions 11 | - prometheus // Abstraction for generation of Prometheus configuration for Prometheus to consume. 12 | - kubernetes 13 | - prometheus // Kubernetes abstractions for the deployment of Prometheus. 14 | 15 | ``` 16 | */ 17 | package abstr 18 | -------------------------------------------------------------------------------- /examples/prometheus-rem-read-benchmark/abstr/kubernetes/volumes/volumes.go: -------------------------------------------------------------------------------- 1 | // Copyright (c) bwplotka/mimic Authors 2 | // Licensed under the Apache License 2.0. 3 | 4 | package volumes 5 | 6 | import ( 7 | "crypto/sha256" 8 | "encoding/base64" 9 | "encoding/json" 10 | 11 | "github.com/bwplotka/mimic" 12 | corev1 "k8s.io/api/core/v1" 13 | metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" 14 | ) 15 | 16 | type VolumeAndMount struct { 17 | corev1.VolumeMount 18 | // corev1.Volume has just Name and VolumeSource. A name field is already present in the VolumeMount, so we just add 19 | // the VolumeSource field here directly. 20 | VolumeSource corev1.VolumeSource 21 | } 22 | 23 | type VolumesAndMounts []VolumeAndMount 24 | 25 | func (vam VolumeAndMount) Volume() corev1.Volume { 26 | return corev1.Volume{ 27 | Name: vam.Name, 28 | VolumeSource: vam.VolumeSource, 29 | } 30 | } 31 | 32 | func (vams VolumesAndMounts) Volumes() []corev1.Volume { 33 | volumes := make([]corev1.Volume, 0, len(vams)) 34 | for _, vam := range vams { 35 | volumes = append(volumes, vam.Volume()) 36 | } 37 | return volumes 38 | } 39 | 40 | func (vams VolumesAndMounts) VolumeMounts() []corev1.VolumeMount { 41 | mounts := make([]corev1.VolumeMount, 0, len(vams)) 42 | for _, vam := range vams { 43 | mounts = append(mounts, vam.VolumeMount) 44 | } 45 | return mounts 46 | } 47 | 48 | type ConfigAndMount struct { 49 | metav1.ObjectMeta 50 | corev1.VolumeMount //nolint:govet 51 | Data map[string]string 52 | } 53 | 54 | func (m ConfigAndMount) ConfigMap() corev1.ConfigMap { 55 | return corev1.ConfigMap{ 56 | TypeMeta: metav1.TypeMeta{ 57 | APIVersion: "v1", 58 | Kind: "ConfigMap", 59 | }, 60 | ObjectMeta: m.ObjectMeta, 61 | Data: m.Data, 62 | } 63 | } 64 | 65 | func (m ConfigAndMount) VolumeAndMount() VolumeAndMount { 66 | return VolumeAndMount{ 67 | VolumeSource: corev1.VolumeSource{ 68 | ConfigMap: &corev1.ConfigMapVolumeSource{ 69 | LocalObjectReference: corev1.LocalObjectReference{Name: m.ObjectMeta.Name}, 70 | }, 71 | }, 72 | VolumeMount: m.VolumeMount, 73 | } 74 | } 75 | 76 | func (m ConfigAndMount) HashEnv(name string) corev1.EnvVar { 77 | h := sha256.New() 78 | if err := json.NewEncoder(h).Encode(m.Data); err != nil { 79 | mimic.Panicf("failed to JSON encode & hash configMap data for %s, err: %v", m.VolumeMount.Name, err) 80 | } 81 | 82 | return corev1.EnvVar{ 83 | Name: name, 84 | Value: base64.URLEncoding.EncodeToString(h.Sum(nil)), 85 | } 86 | } 87 | -------------------------------------------------------------------------------- /examples/prometheus-rem-read-benchmark/go.mod: -------------------------------------------------------------------------------- 1 | module github.com/bwplotka/mimic/examples/prometheus-rem-read-benchmark 2 | 3 | go 1.17 4 | 5 | require ( 6 | github.com/bwplotka/mimic v0.0.0-20190730202618-06ab9976e8ef 7 | github.com/bwplotka/mimic/lib/schemas/prometheus v0.0.0-20210423144650-c81ccdd3db1c 8 | github.com/go-openapi/swag v0.19.15 9 | github.com/prometheus/common v0.20.0 10 | k8s.io/api v0.20.5 11 | k8s.io/apimachinery v0.20.5 12 | ) 13 | 14 | require ( 15 | github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751 // indirect 16 | github.com/alecthomas/units v0.0.0-20211218093645-b94a6e3cc137 // indirect 17 | github.com/beorn7/perks v1.0.1 // indirect 18 | github.com/cespare/xxhash/v2 v2.1.1 // indirect 19 | github.com/ghodss/yaml v1.0.0 // indirect 20 | github.com/go-kit/log v0.2.1 // indirect 21 | github.com/go-logfmt/logfmt v0.5.1 // indirect 22 | github.com/go-logr/logr v0.2.0 // indirect 23 | github.com/gogo/protobuf v1.3.1 // indirect 24 | github.com/golang/protobuf v1.4.3 // indirect 25 | github.com/google/gofuzz v1.1.0 // indirect 26 | github.com/hashicorp/hcl v1.0.0 // indirect 27 | github.com/josharian/intern v1.0.0 // indirect 28 | github.com/jpillora/backoff v1.0.0 // indirect 29 | github.com/json-iterator/go v1.1.10 // indirect 30 | github.com/mailru/easyjson v0.7.6 // indirect 31 | github.com/matttproud/golang_protobuf_extensions v1.0.1 // indirect 32 | github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect 33 | github.com/modern-go/reflect2 v1.0.1 // indirect 34 | github.com/mwitkow/go-conntrack v0.0.0-20190716064945-2f068394615f // indirect 35 | github.com/prometheus/client_golang v1.7.1 // indirect 36 | github.com/prometheus/client_model v0.2.0 // indirect 37 | github.com/prometheus/procfs v0.1.3 // indirect 38 | github.com/rodaine/hclencoder v0.0.1 // indirect 39 | golang.org/x/net v0.0.0-20201110031124-69a78807bb2b // indirect 40 | golang.org/x/sys v0.0.0-20220615213510-4f61da869c0c // indirect 41 | golang.org/x/text v0.3.4 // indirect 42 | google.golang.org/protobuf v1.25.0 // indirect 43 | gopkg.in/alecthomas/kingpin.v2 v2.2.6 // indirect 44 | gopkg.in/inf.v0 v0.9.1 // indirect 45 | gopkg.in/yaml.v2 v2.4.0 // indirect 46 | gopkg.in/yaml.v3 v3.0.1 // indirect 47 | k8s.io/klog/v2 v2.4.0 // indirect 48 | sigs.k8s.io/structured-merge-diff/v4 v4.0.2 // indirect 49 | ) 50 | 51 | // This module is meant to be executed from repo root. 52 | replace github.com/bwplotka/mimic => ../../ 53 | -------------------------------------------------------------------------------- /examples/prometheus-rem-read-benchmark/main.go: -------------------------------------------------------------------------------- 1 | // Copyright (c) bwplotka/mimic Authors 2 | // Licensed under the Apache License 2.0. 3 | 4 | package main 5 | 6 | import ( 7 | "fmt" 8 | "io" 9 | "path" 10 | 11 | "github.com/prometheus/common/model" 12 | 13 | "github.com/bwplotka/mimic/examples/prometheus-rem-read-benchmark/abstr/kubernetes/volumes" 14 | "github.com/bwplotka/mimic/examples/prometheus-rem-read-benchmark/schemas/prometheus" 15 | "github.com/go-openapi/swag" 16 | appsv1 "k8s.io/api/apps/v1" 17 | corev1 "k8s.io/api/core/v1" 18 | "k8s.io/apimachinery/pkg/api/resource" 19 | metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" 20 | 21 | "k8s.io/apimachinery/pkg/util/intstr" 22 | 23 | "github.com/bwplotka/mimic" 24 | "github.com/bwplotka/mimic/encoding" 25 | ) 26 | 27 | const ( 28 | selectorName = "app" 29 | ) 30 | 31 | /* 32 | 33 | Test procedure: 34 | 35 | * Generate YAMLs from definitions: 36 | * `go run github.com/bwplotka/mimic/projects/prom-remote-read-bench generate` 37 | 38 | * Apply baseline: 39 | * `kubectl apply -f gen/prom-rr-test.yaml` 40 | 41 | * Forward gRPC sidecar port: 42 | * `kubectl port-forward pod/prom-rr-test-0 1234:19090` 43 | 44 | * Perform tests using test.sh (modifying parameters in script itself - heavy queries!) 45 | * This performs heavy queries against Thanos gRPC Store.Series of sidecar which will proxy 46 | requests as remote read to Prometheus 47 | * `bash ./projects/prom-remote-read-bench/test.sh localhost:1234` 48 | 49 | */ 50 | 51 | func main() { 52 | generator := mimic.New() 53 | 54 | // Make sure to generate at the very end. 55 | defer generator.Generate() 56 | 57 | // Generate resources for remote read tests. 58 | 59 | // Baseline. 60 | genRRTestPrometheus( 61 | generator, 62 | "prom-rr-test", 63 | "v2.11.0-rc.0-clear", 64 | "v0.5.0", 65 | ) 66 | 67 | // Streamed. 68 | genRRTestPrometheus( 69 | generator, 70 | "prom-rr-test-streamed", 71 | "v2.11.0-rc.0-rr-streaming", 72 | "v0.5.0-rr-streamed2", 73 | ) 74 | } 75 | 76 | func genRRTestPrometheus(generator *mimic.Generator, name string, promVersion string, thanosVersion string) { 77 | const ( 78 | replicas = 1 79 | 80 | configVolumeName = "prometheus-config" 81 | configVolumeMount = "/etc/prometheus" 82 | sharedDataPath = "/data-shared" 83 | 84 | namespace = "rr-test" 85 | 86 | httpPort = 9090 87 | httpSidecarPort = 19190 88 | grpcSidecarPort = 19090 89 | blockgenImage = "improbable/blockgen:master-894c9481c4" 90 | // Generate 10k series. 91 | blockgenInput = `[{ 92 | "type": "gauge", 93 | "jitter": 20, 94 | "max": 200000000, 95 | "min": 100000000, 96 | "result": {"multiplier":10000,"resultType":"vector","result":[{"metric":{"__name__":"kube_pod_container_resource_limits_memory_bytes","cluster":"eu1","container":"addon-resizer","instance":"172.17.0.9:8080","job":"kube-state-metrics","namespace":"kube-system","node":"minikube","pod":"kube-state-metrics-68f6cc566c-vp566"}}]} 97 | }]` 98 | ) 99 | var ( 100 | promDataPath = path.Join(sharedDataPath, "prometheus") 101 | prometheusImage = fmt.Sprintf("bplotka/prometheus:%s", promVersion) 102 | thanosImage = fmt.Sprintf("improbable/thanos:%s", thanosVersion) 103 | ) 104 | 105 | // Empty configuration, we don't need any scrape. 106 | cfgBytes, err := io.ReadAll(encoding.YAML(prometheus.Config{ 107 | GlobalConfig: prometheus.GlobalConfig{ 108 | ExternalLabels: map[model.LabelName]model.LabelValue{ 109 | "replica": "0", 110 | }, 111 | }, 112 | })) 113 | mimic.PanicOnErr(err) 114 | 115 | promConfigAndMount := volumes.ConfigAndMount{ 116 | ObjectMeta: metav1.ObjectMeta{ 117 | Name: configVolumeName, 118 | Namespace: namespace, 119 | Labels: map[string]string{ 120 | selectorName: name, 121 | }, 122 | }, 123 | VolumeMount: corev1.VolumeMount{ 124 | Name: configVolumeName, 125 | MountPath: configVolumeMount, 126 | }, 127 | Data: map[string]string{ 128 | "prometheus.yaml": string(cfgBytes), 129 | }, 130 | } 131 | 132 | sharedVM := volumes.VolumeAndMount{ 133 | VolumeMount: corev1.VolumeMount{ 134 | Name: name, 135 | MountPath: sharedDataPath, 136 | }, 137 | } 138 | 139 | srv := corev1.Service{ 140 | TypeMeta: metav1.TypeMeta{ 141 | Kind: "Service", 142 | APIVersion: "v1", 143 | }, 144 | ObjectMeta: metav1.ObjectMeta{ 145 | Name: name, 146 | Namespace: namespace, 147 | Labels: map[string]string{ 148 | selectorName: name, 149 | }, 150 | }, 151 | Spec: corev1.ServiceSpec{ 152 | Type: corev1.ServiceTypeClusterIP, 153 | ClusterIP: "None", 154 | Selector: map[string]string{ 155 | selectorName: name, 156 | }, 157 | Ports: []corev1.ServicePort{ 158 | { 159 | Name: "http", 160 | Port: httpPort, 161 | TargetPort: intstr.FromInt(httpPort), 162 | }, 163 | { 164 | Name: "grpc-sidecar", 165 | Port: grpcSidecarPort, 166 | TargetPort: intstr.FromInt(grpcSidecarPort), 167 | }, 168 | { 169 | Name: "http-sidecar", 170 | Port: httpSidecarPort, 171 | TargetPort: intstr.FromInt(httpSidecarPort), 172 | }, 173 | }, 174 | }, 175 | } 176 | 177 | blockgenInitContainer := corev1.Container{ 178 | Name: "blockgen", 179 | Image: blockgenImage, 180 | Command: []string{"/bin/blockgen"}, 181 | Args: []string{ 182 | "synthetic", 183 | fmt.Sprintf("--input=%s", blockgenInput), 184 | fmt.Sprintf("--output-dir=%s", promDataPath), 185 | "--retention=24h", 186 | }, 187 | VolumeMounts: []corev1.VolumeMount{sharedVM.VolumeMount}, 188 | Resources: corev1.ResourceRequirements{ 189 | Requests: corev1.ResourceList{ 190 | corev1.ResourceCPU: resource.MustParse("1"), 191 | corev1.ResourceMemory: resource.MustParse("10Gi"), 192 | }, 193 | Limits: corev1.ResourceList{ 194 | corev1.ResourceCPU: resource.MustParse("1"), 195 | corev1.ResourceMemory: resource.MustParse("10Gi"), 196 | }, 197 | }, 198 | } 199 | 200 | prometheusContainer := corev1.Container{ 201 | Name: "prometheus", 202 | Image: prometheusImage, 203 | Args: []string{ 204 | fmt.Sprintf("--config.file=%v/prometheus.yaml", configVolumeMount), 205 | "--log.level=info", 206 | // Unlimited RR. 207 | "--storage.remote.read-concurrent-limit=99999", 208 | "--storage.remote.read-sample-limit=9999999999999999", 209 | fmt.Sprintf("--storage.tsdb.path=%s", promDataPath), 210 | "--storage.tsdb.min-block-duration=2h", 211 | // Avoid compaction for less moving parts in results. 212 | "--storage.tsdb.max-block-duration=2h", 213 | "--storage.tsdb.retention.time=2d", 214 | "--web.enable-lifecycle", 215 | "--web.enable-admin-api", 216 | }, 217 | Env: []corev1.EnvVar{ 218 | {Name: "HOSTNAME", ValueFrom: &corev1.EnvVarSource{ 219 | FieldRef: &corev1.ObjectFieldSelector{ 220 | FieldPath: "metadata.name", 221 | }, 222 | }}, 223 | //{Name: "GODEBUG", Value:"madvdontneed=1"}, 224 | }, 225 | ImagePullPolicy: corev1.PullAlways, 226 | ReadinessProbe: &corev1.Probe{ 227 | Handler: corev1.Handler{ 228 | HTTPGet: &corev1.HTTPGetAction{ 229 | Port: intstr.FromInt(int(httpPort)), 230 | Path: "-/ready", 231 | }, 232 | }, 233 | SuccessThreshold: 3, 234 | }, 235 | Ports: []corev1.ContainerPort{ 236 | { 237 | Name: "http", 238 | ContainerPort: httpPort, 239 | }, 240 | }, 241 | VolumeMounts: volumes.VolumesAndMounts{promConfigAndMount.VolumeAndMount(), sharedVM}.VolumeMounts(), 242 | SecurityContext: &corev1.SecurityContext{ 243 | RunAsNonRoot: swag.Bool(false), 244 | RunAsUser: swag.Int64(1000), 245 | }, 246 | Resources: corev1.ResourceRequirements{ 247 | Requests: corev1.ResourceList{ 248 | corev1.ResourceCPU: resource.MustParse("1"), 249 | corev1.ResourceMemory: resource.MustParse("10Gi"), 250 | }, 251 | Limits: corev1.ResourceList{ 252 | corev1.ResourceCPU: resource.MustParse("1"), 253 | corev1.ResourceMemory: resource.MustParse("10Gi"), 254 | }, 255 | }, 256 | } 257 | 258 | thanosSidecarContainer := corev1.Container{ 259 | Name: "thanos", 260 | Image: thanosImage, 261 | Command: []string{"thanos"}, 262 | ImagePullPolicy: corev1.PullAlways, 263 | Args: []string{ 264 | "sidecar", 265 | "--log.level=debug", 266 | "--debug.name=$(POD_NAME)", 267 | fmt.Sprintf("--http-address=0.0.0.0:%d", httpSidecarPort), 268 | fmt.Sprintf("--grpc-address=0.0.0.0:%d", grpcSidecarPort), 269 | fmt.Sprintf("--prometheus.url=http://localhost:%d", httpPort), 270 | fmt.Sprintf("--tsdb.path=%s", promDataPath), 271 | }, 272 | Env: []corev1.EnvVar{ 273 | {Name: "POD_NAME", ValueFrom: &corev1.EnvVarSource{ 274 | FieldRef: &corev1.ObjectFieldSelector{ 275 | FieldPath: "metadata.name", 276 | }, 277 | }}, 278 | //{Name: "GODEBUG", Value:"madvdontneed=1"}, 279 | }, 280 | Ports: []corev1.ContainerPort{ 281 | { 282 | Name: "m-sidecar", 283 | ContainerPort: httpSidecarPort, 284 | }, 285 | { 286 | Name: "grpc-sidecar", 287 | ContainerPort: grpcSidecarPort, 288 | }, 289 | }, 290 | ReadinessProbe: &corev1.Probe{ 291 | Handler: corev1.Handler{ 292 | HTTPGet: &corev1.HTTPGetAction{ 293 | Port: intstr.FromInt(int(httpSidecarPort)), 294 | Path: "metrics", 295 | }, 296 | }, 297 | }, 298 | VolumeMounts: volumes.VolumesAndMounts{sharedVM}.VolumeMounts(), 299 | Resources: corev1.ResourceRequirements{ 300 | Requests: corev1.ResourceList{ 301 | corev1.ResourceCPU: resource.MustParse("1"), 302 | corev1.ResourceMemory: resource.MustParse("4Gi"), 303 | }, 304 | Limits: corev1.ResourceList{ 305 | corev1.ResourceCPU: resource.MustParse("1"), 306 | corev1.ResourceMemory: resource.MustParse("4Gi"), 307 | }, 308 | }, 309 | } 310 | 311 | set := appsv1.StatefulSet{ 312 | TypeMeta: metav1.TypeMeta{ 313 | Kind: "StatefulSet", 314 | APIVersion: "apps/v1", 315 | }, 316 | ObjectMeta: metav1.ObjectMeta{ 317 | Name: name, 318 | Namespace: namespace, 319 | Labels: map[string]string{ 320 | selectorName: name, 321 | }, 322 | }, 323 | Spec: appsv1.StatefulSetSpec{ 324 | Replicas: swag.Int32(replicas), 325 | ServiceName: name, 326 | Template: corev1.PodTemplateSpec{ 327 | ObjectMeta: metav1.ObjectMeta{ 328 | Labels: map[string]string{ 329 | selectorName: name, 330 | "version": fmt.Sprintf("prometheus%s_thanos%s", promVersion, thanosVersion), 331 | }, 332 | }, 333 | Spec: corev1.PodSpec{ 334 | InitContainers: []corev1.Container{blockgenInitContainer}, 335 | Containers: []corev1.Container{prometheusContainer, thanosSidecarContainer}, 336 | Volumes: volumes.VolumesAndMounts{promConfigAndMount.VolumeAndMount(), sharedVM}.Volumes(), 337 | }, 338 | }, 339 | Selector: &metav1.LabelSelector{ 340 | MatchLabels: map[string]string{ 341 | selectorName: name, 342 | }, 343 | }, 344 | }, 345 | } 346 | 347 | generator.Add(name+".yaml", encoding.GhodssYAML(set, srv, promConfigAndMount.ConfigMap())) 348 | } 349 | -------------------------------------------------------------------------------- /examples/prometheus-rem-read-benchmark/rpc.proto: -------------------------------------------------------------------------------- 1 | syntax = "proto3"; 2 | package thanos; 3 | 4 | import "types.proto"; 5 | import "gogoproto/gogo.proto"; 6 | 7 | option go_package = "storepb"; 8 | 9 | option (gogoproto.sizer_all) = true; 10 | option (gogoproto.marshaler_all) = true; 11 | option (gogoproto.unmarshaler_all) = true; 12 | option (gogoproto.goproto_getters_all) = false; 13 | 14 | /// Store reprents API against instance that stores XOR encoded values with label set metadata (e.g Prometheus metrics). 15 | service Store { 16 | /// Info returns meta information about a store e.g labels that makes that store unique as well as time range that is 17 | /// available. 18 | rpc Info(InfoRequest) returns (InfoResponse); 19 | 20 | /// Series streams each Series (Labels and chunk/downsampling chunk) for given label matchers and time range. 21 | rpc Series(SeriesRequest) returns (stream SeriesResponse); 22 | 23 | /// LabelNames returns all label names that is available. 24 | /// Currently unimplemented in all Thanos implementations, because Query API does not implement this either. 25 | rpc LabelNames(LabelNamesRequest) returns (LabelNamesResponse); 26 | 27 | /// LabelValues returns all label values for given label name. 28 | rpc LabelValues(LabelValuesRequest) returns (LabelValuesResponse); 29 | } 30 | 31 | message InfoRequest { 32 | } 33 | 34 | enum StoreType { 35 | UNKNOWN = 0; 36 | QUERY = 1; 37 | RULE = 2; 38 | SIDECAR = 3; 39 | STORE = 4; 40 | RECEIVE = 5; 41 | } 42 | 43 | message InfoResponse { 44 | repeated Label labels = 1 [(gogoproto.nullable) = false]; 45 | int64 min_time = 2; 46 | int64 max_time = 3; 47 | StoreType storeType = 4; 48 | } 49 | 50 | /// PartialResponseStrategy controls partial response handling. 51 | enum PartialResponseStrategy { 52 | /// WARN strategy tells server to treat any error that will related to single StoreAPI (e.g missing chunk series because of underlying 53 | /// storeAPI is temporarily not available) as warning which will not fail the whole query (still OK response). 54 | /// Server should produce those as a warnings field in response. 55 | WARN = 0; 56 | /// ABORT strategy tells server to treat any error that will related to single StoreAPI (e.g missing chunk series because of underlying 57 | /// storeAPI is temporarily not available) as the gRPC error that aborts the query. 58 | /// 59 | /// This is especially useful for any rule/alert evaluations on top of StoreAPI which usually does not tolerate partial 60 | /// errors. 61 | ABORT = 1; 62 | } 63 | 64 | message SeriesRequest { 65 | int64 min_time = 1; 66 | int64 max_time = 2; 67 | repeated LabelMatcher matchers = 3 [(gogoproto.nullable) = false]; 68 | 69 | int64 max_resolution_window = 4; 70 | repeated Aggr aggregates = 5; 71 | 72 | // Deprecated. Use partial_response_strategy instead. 73 | bool partial_response_disabled = 6; 74 | 75 | // TODO(bwplotka): Move Thanos components to use strategy instead. Including QueryAPI. 76 | PartialResponseStrategy partial_response_strategy = 7; 77 | } 78 | 79 | enum Aggr { 80 | RAW = 0; 81 | COUNT = 1; 82 | SUM = 2; 83 | MIN = 3; 84 | MAX = 4; 85 | COUNTER = 5; 86 | } 87 | 88 | message SeriesResponse { 89 | oneof result { 90 | Series series = 1; 91 | 92 | /// warning is considered an information piece in place of series for warning purposes. 93 | /// It is used to warn query customer about suspicious cases or partial response (if enabled). 94 | string warning = 2; 95 | } 96 | } 97 | 98 | message LabelNamesRequest { 99 | bool partial_response_disabled = 1; 100 | 101 | // TODO(bwplotka): Move Thanos components to use strategy instead. Including QueryAPI. 102 | PartialResponseStrategy partial_response_strategy = 2; 103 | } 104 | 105 | message LabelNamesResponse { 106 | repeated string names = 1; 107 | repeated string warnings = 2; 108 | } 109 | 110 | message LabelValuesRequest { 111 | string label = 1; 112 | 113 | bool partial_response_disabled = 2; 114 | 115 | // TODO(bwplotka): Move Thanos components to use strategy instead. Including QueryAPI. 116 | PartialResponseStrategy partial_response_strategy = 3; 117 | } 118 | 119 | message LabelValuesResponse { 120 | repeated string values = 1; 121 | repeated string warnings = 2; 122 | } 123 | -------------------------------------------------------------------------------- /examples/prometheus-rem-read-benchmark/schemas/doc.go: -------------------------------------------------------------------------------- 1 | // Copyright (c) bwplotka/mimic Authors 2 | // Licensed under the Apache License 2.0. 3 | 4 | /* 5 | Providers are a way of defining a configuration specification in Go structs for projects that either do not currently 6 | expose their configuration structs or are difficult to work with (due to deps, complexity etc.). 7 | 8 | Each Provider should be as simple as possible and map as closely to the specification of the configuration that the 9 | project documents. 10 | 11 | Do not add abstractions, opinions or validation into the providers as this should be done by an abstraction or the definition itself. 12 | This avoids magic like the transforming of a property on a struct from one value to 13 | another without the knowledge of the user. 14 | 15 | Providers will be created by a caller wanting to generate specific config and the caller should `Add` this struct explicitly 16 | to the Generator and not be done in the provider code. 17 | 18 | As Providers should be basic structs you should be able to do away with the vast majority of conditionals or funcs within 19 | these packages. 20 | 21 | Use the folder structure to help highlight what config the code will produce: 22 | ``` 23 | providers 24 | - vault // Configuration passed to the vault product itself. 25 | - terraform 26 | - vault // Terraform provider/resource configuration used by terraform. 27 | 28 | ``` 29 | */ 30 | package schemas 31 | -------------------------------------------------------------------------------- /examples/prometheus-rem-read-benchmark/schemas/prometheus/discovery/azure/azure.go: -------------------------------------------------------------------------------- 1 | // Copyright (c) bwplotka/mimic Authors 2 | // Licensed under the Apache License 2.0. 3 | 4 | // Copyright 2015 The Prometheus Authors 5 | // Licensed under the Apache License, Version 2.0 (the "License"); 6 | // you may not use this file except in compliance with the License. 7 | // You may obtain a copy of the License at 8 | // 9 | // http://www.apache.org/licenses/LICENSE-2.0 10 | // 11 | // Unless required by applicable law or agreed to in writing, software 12 | // distributed under the License is distributed on an "AS IS" BASIS, 13 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | // See the License for the specific language governing permissions and 15 | // limitations under the License. 16 | 17 | package azure 18 | 19 | import ( 20 | config_util "github.com/prometheus/common/config" 21 | "github.com/prometheus/common/model" 22 | ) 23 | 24 | // SDConfig is the configuration for Azure based service discovery. 25 | type SDConfig struct { 26 | Environment string `yaml:"environment,omitempty"` 27 | Port int `yaml:"port"` 28 | SubscriptionID string `yaml:"subscription_id"` 29 | TenantID string `yaml:"tenant_id,omitempty"` 30 | ClientID string `yaml:"client_id,omitempty"` 31 | ClientSecret config_util.Secret `yaml:"client_secret,omitempty"` 32 | RefreshInterval model.Duration `yaml:"refresh_interval,omitempty"` 33 | } 34 | -------------------------------------------------------------------------------- /examples/prometheus-rem-read-benchmark/schemas/prometheus/discovery/config/config.go: -------------------------------------------------------------------------------- 1 | // Copyright (c) bwplotka/mimic Authors 2 | // Licensed under the Apache License 2.0. 3 | 4 | // Copyright 2016 The Prometheus Authors 5 | // Licensed under the Apache License, Version 2.0 (the "License"); 6 | // you may not use this file except in compliance with the License. 7 | // You may obtain a copy of the License at 8 | // 9 | // http://www.apache.org/licenses/LICENSE-2.0 10 | // 11 | // Unless required by applicable law or agreed to in writing, software 12 | // distributed under the License is distributed on an "AS IS" BASIS, 13 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | // See the License for the specific language governing permissions and 15 | // limitations under the License. 16 | 17 | package sdconfig 18 | 19 | import ( 20 | "github.com/bwplotka/mimic/lib/schemas/prometheus/discovery/azure" 21 | "github.com/bwplotka/mimic/lib/schemas/prometheus/discovery/consul" 22 | "github.com/bwplotka/mimic/lib/schemas/prometheus/discovery/dns" 23 | "github.com/bwplotka/mimic/lib/schemas/prometheus/discovery/ec2" 24 | "github.com/bwplotka/mimic/lib/schemas/prometheus/discovery/file" 25 | "github.com/bwplotka/mimic/lib/schemas/prometheus/discovery/gce" 26 | "github.com/bwplotka/mimic/lib/schemas/prometheus/discovery/kubernetes" 27 | "github.com/bwplotka/mimic/lib/schemas/prometheus/discovery/marathon" 28 | "github.com/bwplotka/mimic/lib/schemas/prometheus/discovery/openstack" 29 | "github.com/bwplotka/mimic/lib/schemas/prometheus/discovery/targetgroup" 30 | "github.com/bwplotka/mimic/lib/schemas/prometheus/discovery/triton" 31 | "github.com/bwplotka/mimic/lib/schemas/prometheus/discovery/zookeeper" 32 | ) 33 | 34 | // ServiceDiscoveryConfig configures lists of different service discovery mechanisms. 35 | type ServiceDiscoveryConfig struct { 36 | // List of labeled target groups for this job. 37 | StaticConfigs []*targetgroup.Group `yaml:"static_configs,omitempty"` 38 | // List of DNS service discovery configurations. 39 | DNSSDConfigs []*dns.SDConfig `yaml:"dns_sd_configs,omitempty"` 40 | // List of file service discovery configurations. 41 | FileSDConfigs []*file.SDConfig `yaml:"file_sd_configs,omitempty"` 42 | // List of Consul service discovery configurations. 43 | ConsulSDConfigs []*consul.SDConfig `yaml:"consul_sd_configs,omitempty"` 44 | // List of Serverset service discovery configurations. 45 | ServersetSDConfigs []*zookeeper.ServersetSDConfig `yaml:"serverset_sd_configs,omitempty"` 46 | // NerveSDConfigs is a list of Nerve service discovery configurations. 47 | NerveSDConfigs []*zookeeper.NerveSDConfig `yaml:"nerve_sd_configs,omitempty"` 48 | // MarathonSDConfigs is a list of Marathon service discovery configurations. 49 | MarathonSDConfigs []*marathon.SDConfig `yaml:"marathon_sd_configs,omitempty"` 50 | // List of Kubernetes service discovery configurations. 51 | KubernetesSDConfigs []*kubernetes.SDConfig `yaml:"kubernetes_sd_configs,omitempty"` 52 | // List of GCE service discovery configurations. 53 | GCESDConfigs []*gce.SDConfig `yaml:"gce_sd_configs,omitempty"` 54 | // List of EC2 service discovery configurations. 55 | EC2SDConfigs []*ec2.SDConfig `yaml:"ec2_sd_configs,omitempty"` 56 | // List of OpenStack service discovery configurations. 57 | OpenstackSDConfigs []*openstack.SDConfig `yaml:"openstack_sd_configs,omitempty"` 58 | // List of Azure service discovery configurations. 59 | AzureSDConfigs []*azure.SDConfig `yaml:"azure_sd_configs,omitempty"` 60 | // List of Triton service discovery configurations. 61 | TritonSDConfigs []*triton.SDConfig `yaml:"triton_sd_configs,omitempty"` 62 | } 63 | -------------------------------------------------------------------------------- /examples/prometheus-rem-read-benchmark/schemas/prometheus/discovery/consul/consul.go: -------------------------------------------------------------------------------- 1 | // Copyright (c) bwplotka/mimic Authors 2 | // Licensed under the Apache License 2.0. 3 | 4 | // Copyright 2015 The Prometheus Authors 5 | // Licensed under the Apache License, Version 2.0 (the "License"); 6 | // you may not use this file except in compliance with the License. 7 | // You may obtain a copy of the License at 8 | // 9 | // http://www.apache.org/licenses/LICENSE-2.0 10 | // 11 | // Unless required by applicable law or agreed to in writing, software 12 | // distributed under the License is distributed on an "AS IS" BASIS, 13 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | // See the License for the specific language governing permissions and 15 | // limitations under the License. 16 | 17 | package consul 18 | 19 | import ( 20 | config_util "github.com/prometheus/common/config" 21 | "github.com/prometheus/common/model" 22 | ) 23 | 24 | // SDConfig is the configuration for Consul service discovery. 25 | type SDConfig struct { 26 | Server string `yaml:"server,omitempty"` 27 | Token config_util.Secret `yaml:"token,omitempty"` 28 | Datacenter string `yaml:"datacenter,omitempty"` 29 | TagSeparator string `yaml:"tag_separator,omitempty"` 30 | Scheme string `yaml:"scheme,omitempty"` 31 | Username string `yaml:"username,omitempty"` 32 | Password config_util.Secret `yaml:"password,omitempty"` 33 | 34 | // See https://www.consul.io/docs/internals/consensus.html#consistency-modes, 35 | // stale reads are a lot cheaper and are a necessity if you have >5k targets. 36 | AllowStale bool `yaml:"allow_stale"` 37 | // By default use blocking queries (https://www.consul.io/api/index.html#blocking-queries) 38 | // but allow users to throttle updates if necessary. This can be useful because of "bugs" like 39 | // https://github.com/hashicorp/consul/issues/3712 which cause an un-necessary 40 | // amount of requests on consul. 41 | RefreshInterval model.Duration `yaml:"refresh_interval,omitempty"` 42 | 43 | // See https://www.consul.io/api/catalog.html#list-services 44 | // The list of services for which targets are discovered. 45 | // Defaults to all services if empty. 46 | Services []string `yaml:"services,omitempty"` 47 | // An optional tag used to filter instances inside a service. A single tag is supported 48 | // here to match the Consul API. 49 | ServiceTag string `yaml:"tag,omitempty"` 50 | // Desired node metadata. 51 | NodeMeta map[string]string `yaml:"node_meta,omitempty"` 52 | 53 | TLSConfig config_util.TLSConfig `yaml:"tls_config,omitempty"` 54 | } 55 | -------------------------------------------------------------------------------- /examples/prometheus-rem-read-benchmark/schemas/prometheus/discovery/dns/dns.go: -------------------------------------------------------------------------------- 1 | // Copyright (c) bwplotka/mimic Authors 2 | // Licensed under the Apache License 2.0. 3 | 4 | // Copyright 2016 The Prometheus Authors 5 | // Licensed under the Apache License, Version 2.0 (the "License"); 6 | // you may not use this file except in compliance with the License. 7 | // You may obtain a copy of the License at 8 | // 9 | // http://www.apache.org/licenses/LICENSE-2.0 10 | // 11 | // Unless required by applicable law or agreed to in writing, software 12 | // distributed under the License is distributed on an "AS IS" BASIS, 13 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | // See the License for the specific language governing permissions and 15 | // limitations under the License. 16 | 17 | package dns 18 | 19 | import ( 20 | "github.com/prometheus/common/model" 21 | ) 22 | 23 | // SDConfig is the configuration for DNS based service discovery. 24 | type SDConfig struct { 25 | Names []string `yaml:"names"` 26 | RefreshInterval model.Duration `yaml:"refresh_interval,omitempty"` 27 | Type string `yaml:"type"` 28 | Port int `yaml:"port"` // Ignored for SRV records 29 | } 30 | -------------------------------------------------------------------------------- /examples/prometheus-rem-read-benchmark/schemas/prometheus/discovery/ec2/ec2.go: -------------------------------------------------------------------------------- 1 | // Copyright (c) bwplotka/mimic Authors 2 | // Licensed under the Apache License 2.0. 3 | 4 | // Copyright 2015 The Prometheus Authors 5 | // Licensed under the Apache License, Version 2.0 (the "License"); 6 | // you may not use this file except in compliance with the License. 7 | // You may obtain a copy of the License at 8 | // 9 | // http://www.apache.org/licenses/LICENSE-2.0 10 | // 11 | // Unless required by applicable law or agreed to in writing, software 12 | // distributed under the License is distributed on an "AS IS" BASIS, 13 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | // See the License for the specific language governing permissions and 15 | // limitations under the License. 16 | 17 | package ec2 18 | 19 | import ( 20 | "github.com/prometheus/common/model" 21 | 22 | config_util "github.com/prometheus/common/config" 23 | ) 24 | 25 | // Filter is the configuration for filtering EC2 instances. 26 | type Filter struct { 27 | Name string `yaml:"name"` 28 | Values []string `yaml:"values"` 29 | } 30 | 31 | // SDConfig is the configuration for EC2 based service discovery. 32 | type SDConfig struct { 33 | Endpoint string `yaml:"endpoint"` 34 | Region string `yaml:"region"` 35 | AccessKey string `yaml:"access_key,omitempty"` 36 | SecretKey config_util.Secret `yaml:"secret_key,omitempty"` 37 | Profile string `yaml:"profile,omitempty"` 38 | RoleARN string `yaml:"role_arn,omitempty"` 39 | RefreshInterval model.Duration `yaml:"refresh_interval,omitempty"` 40 | Port int `yaml:"port"` 41 | Filters []*Filter `yaml:"filters"` 42 | } 43 | -------------------------------------------------------------------------------- /examples/prometheus-rem-read-benchmark/schemas/prometheus/discovery/file/file.go: -------------------------------------------------------------------------------- 1 | // Copyright (c) bwplotka/mimic Authors 2 | // Licensed under the Apache License 2.0. 3 | 4 | // Copyright 2015 The Prometheus Authors 5 | // Licensed under the Apache License, Version 2.0 (the "License"); 6 | // you may not use this file except in compliance with the License. 7 | // You may obtain a copy of the License at 8 | // 9 | // http://www.apache.org/licenses/LICENSE-2.0 10 | // 11 | // Unless required by applicable law or agreed to in writing, software 12 | // distributed under the License is distributed on an "AS IS" BASIS, 13 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | // See the License for the specific language governing permissions and 15 | // limitations under the License. 16 | 17 | package file 18 | 19 | import ( 20 | "github.com/prometheus/common/model" 21 | ) 22 | 23 | // SDConfig is the configuration for file based discovery. 24 | type SDConfig struct { 25 | Files []string `yaml:"files"` 26 | RefreshInterval model.Duration `yaml:"refresh_interval,omitempty"` 27 | } 28 | -------------------------------------------------------------------------------- /examples/prometheus-rem-read-benchmark/schemas/prometheus/discovery/gce/gce.go: -------------------------------------------------------------------------------- 1 | // Copyright (c) bwplotka/mimic Authors 2 | // Licensed under the Apache License 2.0. 3 | 4 | // Copyright 2015 The Prometheus Authors 5 | // Licensed under the Apache License, Version 2.0 (the "License"); 6 | // you may not use this file except in compliance with the License. 7 | // You may obtain a copy of the License at 8 | // 9 | // http://www.apache.org/licenses/LICENSE-2.0 10 | // 11 | // Unless required by applicable law or agreed to in writing, software 12 | // distributed under the License is distributed on an "AS IS" BASIS, 13 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | // See the License for the specific language governing permissions and 15 | // limitations under the License. 16 | 17 | package gce 18 | 19 | import ( 20 | "github.com/prometheus/common/model" 21 | ) 22 | 23 | // SDConfig is the configuration for GCE based service discovery. 24 | type SDConfig struct { 25 | // Project: The Google Cloud Project ID 26 | Project string `yaml:"project"` 27 | 28 | // Zone: The zone of the scrape targets. 29 | // If you need to configure multiple zones use multiple gce_sd_configs 30 | Zone string `yaml:"zone"` 31 | 32 | // Filter: Can be used optionally to filter the instance list by other criteria. 33 | // Syntax of this filter string is described here in the filter query parameter section: 34 | // https://cloud.google.com/compute/docs/reference/latest/instances/list 35 | Filter string `yaml:"filter,omitempty"` 36 | 37 | RefreshInterval model.Duration `yaml:"refresh_interval,omitempty"` 38 | Port int `yaml:"port"` 39 | TagSeparator string `yaml:"tag_separator,omitempty"` 40 | } 41 | -------------------------------------------------------------------------------- /examples/prometheus-rem-read-benchmark/schemas/prometheus/discovery/kubernetes/kubernetes.go: -------------------------------------------------------------------------------- 1 | // Copyright (c) bwplotka/mimic Authors 2 | // Licensed under the Apache License 2.0. 3 | 4 | // Copyright 2016 The Prometheus Authors 5 | // Licensed under the Apache License, Version 2.0 (the "License"); 6 | // you may not use this file except in compliance with the License. 7 | // You may obtain a copy of the License at 8 | // 9 | // http://www.apache.org/licenses/LICENSE-2.0 10 | // 11 | // Unless required by applicable law or agreed to in writing, software 12 | // distributed under the License is distributed on an "AS IS" BASIS, 13 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | // See the License for the specific language governing permissions and 15 | // limitations under the License. 16 | 17 | package kubernetes 18 | 19 | import ( 20 | config_util "github.com/prometheus/common/config" 21 | ) 22 | 23 | // Role is role of the service in Kubernetes. 24 | type Role string 25 | 26 | // The valid options for Role. 27 | const ( 28 | RoleNode Role = "node" 29 | RolePod Role = "pod" 30 | RoleService Role = "service" 31 | RoleEndpoint Role = "endpoints" 32 | RoleIngress Role = "ingress" 33 | ) 34 | 35 | // SDConfig is the configuration for Kubernetes service discovery. 36 | type SDConfig struct { 37 | APIServer config_util.URL `yaml:"api_server,omitempty"` 38 | Role Role `yaml:"role"` 39 | BasicAuth *config_util.BasicAuth `yaml:"basic_auth,omitempty"` 40 | BearerToken config_util.Secret `yaml:"bearer_token,omitempty"` 41 | BearerTokenFile string `yaml:"bearer_token_file,omitempty"` 42 | TLSConfig config_util.TLSConfig `yaml:"tls_config,omitempty"` 43 | NamespaceDiscovery NamespaceDiscovery `yaml:"namespaces,omitempty"` 44 | } 45 | 46 | // NamespaceDiscovery is the configuration for discovering 47 | // Kubernetes namespaces. 48 | type NamespaceDiscovery struct { 49 | Names []string `yaml:"names"` 50 | } 51 | 52 | // UnmarshalYAML implements the yaml.Unmarshaler interface. 53 | func (c *NamespaceDiscovery) UnmarshalYAML(unmarshal func(interface{}) error) error { 54 | *c = NamespaceDiscovery{} 55 | type plain NamespaceDiscovery 56 | return unmarshal((*plain)(c)) 57 | } 58 | -------------------------------------------------------------------------------- /examples/prometheus-rem-read-benchmark/schemas/prometheus/discovery/marathon/marathon.go: -------------------------------------------------------------------------------- 1 | // Copyright (c) bwplotka/mimic Authors 2 | // Licensed under the Apache License 2.0. 3 | 4 | // Copyright 2016 The Prometheus Authors 5 | // Licensed under the Apache License, Version 2.0 (the "License"); 6 | // you may not use this file except in compliance with the License. 7 | // You may obtain a copy of the License at 8 | // 9 | // http://www.apache.org/licenses/LICENSE-2.0 10 | // 11 | // Unless required by applicable law or agreed to in writing, software 12 | // distributed under the License is distributed on an "AS IS" BASIS, 13 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | // See the License for the specific language governing permissions and 15 | // limitations under the License. 16 | 17 | package marathon 18 | 19 | import ( 20 | config_util "github.com/prometheus/common/config" 21 | "github.com/prometheus/common/model" 22 | ) 23 | 24 | // SDConfig is the configuration for services running on Marathon. 25 | type SDConfig struct { 26 | Servers []string `yaml:"servers,omitempty"` 27 | RefreshInterval model.Duration `yaml:"refresh_interval,omitempty"` 28 | AuthToken config_util.Secret `yaml:"auth_token,omitempty"` 29 | AuthTokenFile string `yaml:"auth_token_file,omitempty"` 30 | HTTPClientConfig config_util.HTTPClientConfig `yaml:",inline"` 31 | } 32 | -------------------------------------------------------------------------------- /examples/prometheus-rem-read-benchmark/schemas/prometheus/discovery/openstack/openstack.go: -------------------------------------------------------------------------------- 1 | // Copyright (c) bwplotka/mimic Authors 2 | // Licensed under the Apache License 2.0. 3 | 4 | // Copyright 2017 The Prometheus Authors 5 | // Licensed under the Apache License, Version 2.0 (the "License"); 6 | // you may not use this file except in compliance with the License. 7 | // You may obtain a copy of the License at 8 | // 9 | // http://www.apache.org/licenses/LICENSE-2.0 10 | // 11 | // Unless required by applicable law or agreed to in writing, software 12 | // distributed under the License is distributed on an "AS IS" BASIS, 13 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | // See the License for the specific language governing permissions and 15 | // limitations under the License. 16 | 17 | package openstack 18 | 19 | import ( 20 | config_util "github.com/prometheus/common/config" 21 | "github.com/prometheus/common/model" 22 | ) 23 | 24 | // SDConfig is the configuration for OpenStack based service discovery. 25 | type SDConfig struct { 26 | IdentityEndpoint string `yaml:"identity_endpoint"` 27 | Username string `yaml:"username"` 28 | UserID string `yaml:"userid"` 29 | Password config_util.Secret `yaml:"password"` 30 | ProjectName string `yaml:"project_name"` 31 | ProjectID string `yaml:"project_id"` 32 | DomainName string `yaml:"domain_name"` 33 | DomainID string `yaml:"domain_id"` 34 | Role Role `yaml:"role"` 35 | Region string `yaml:"region"` 36 | RefreshInterval model.Duration `yaml:"refresh_interval,omitempty"` 37 | Port int `yaml:"port"` 38 | AllTenants bool `yaml:"all_tenants,omitempty"` 39 | TLSConfig config_util.TLSConfig `yaml:"tls_config,omitempty"` 40 | } 41 | 42 | // OpenStackRole is role of the target in OpenStack. 43 | type Role string 44 | 45 | // The valid options for OpenStackRole. 46 | const ( 47 | // OpenStack document reference 48 | // https://docs.openstack.org/nova/pike/admin/arch.html#hypervisors 49 | OpenStackRoleHypervisor Role = "hypervisor" 50 | // OpenStack document reference 51 | // https://docs.openstack.org/horizon/pike/user/launch-instances.html 52 | OpenStackRoleInstance Role = "instance" 53 | ) 54 | -------------------------------------------------------------------------------- /examples/prometheus-rem-read-benchmark/schemas/prometheus/discovery/targetgroup/targetgroup.go: -------------------------------------------------------------------------------- 1 | // Copyright (c) bwplotka/mimic Authors 2 | // Licensed under the Apache License 2.0. 3 | 4 | // Copyright 2013 The Prometheus Authors 5 | // Licensed under the Apache License, Version 2.0 (the "License"); 6 | // you may not use this file except in compliance with the License. 7 | // You may obtain a copy of the License at 8 | // 9 | // http://www.apache.org/licenses/LICENSE-2.0 10 | // 11 | // Unless required by applicable law or agreed to in writing, software 12 | // distributed under the License is distributed on an "AS IS" BASIS, 13 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | // See the License for the specific language governing permissions and 15 | // limitations under the License. 16 | 17 | package targetgroup 18 | 19 | import ( 20 | "bytes" 21 | "encoding/json" 22 | 23 | "github.com/prometheus/common/model" 24 | ) 25 | 26 | // Group is a set of targets with a common label set(production , test, staging etc.). 27 | type Group struct { 28 | // Targets is a list of targets identified by a label set. Each target is 29 | // uniquely identifiable in the group by its address label. 30 | Targets []model.LabelSet 31 | // Labels is a set of labels that is common across all targets in the group. 32 | Labels model.LabelSet 33 | 34 | // Source is an identifier that describes a group of targets. 35 | Source string 36 | } 37 | 38 | func (tg Group) String() string { 39 | return tg.Source 40 | } 41 | 42 | // UnmarshalYAML implements the yaml.Unmarshaler interface. 43 | func (tg *Group) UnmarshalYAML(unmarshal func(interface{}) error) error { 44 | g := struct { 45 | Targets []string `yaml:"targets"` 46 | Labels model.LabelSet `yaml:"labels"` 47 | }{} 48 | if err := unmarshal(&g); err != nil { 49 | return err 50 | } 51 | tg.Targets = make([]model.LabelSet, 0, len(g.Targets)) 52 | for _, t := range g.Targets { 53 | tg.Targets = append(tg.Targets, model.LabelSet{ 54 | model.AddressLabel: model.LabelValue(t), 55 | }) 56 | } 57 | tg.Labels = g.Labels 58 | return nil 59 | } 60 | 61 | // MarshalYAML implements the yaml.Marshaler interface. 62 | func (tg Group) MarshalYAML() (interface{}, error) { 63 | g := &struct { 64 | Targets []string `yaml:"targets"` 65 | Labels model.LabelSet `yaml:"labels,omitempty"` 66 | }{ 67 | Targets: make([]string, 0, len(tg.Targets)), 68 | Labels: tg.Labels, 69 | } 70 | for _, t := range tg.Targets { 71 | g.Targets = append(g.Targets, string(t[model.AddressLabel])) 72 | } 73 | return g, nil 74 | } 75 | 76 | // UnmarshalJSON implements the json.Unmarshaler interface. 77 | func (tg *Group) UnmarshalJSON(b []byte) error { 78 | g := struct { 79 | Targets []string `json:"targets"` 80 | Labels model.LabelSet `json:"labels"` 81 | }{} 82 | 83 | dec := json.NewDecoder(bytes.NewReader(b)) 84 | dec.DisallowUnknownFields() 85 | if err := dec.Decode(&g); err != nil { 86 | return err 87 | } 88 | tg.Targets = make([]model.LabelSet, 0, len(g.Targets)) 89 | for _, t := range g.Targets { 90 | tg.Targets = append(tg.Targets, model.LabelSet{ 91 | model.AddressLabel: model.LabelValue(t), 92 | }) 93 | } 94 | tg.Labels = g.Labels 95 | return nil 96 | } 97 | -------------------------------------------------------------------------------- /examples/prometheus-rem-read-benchmark/schemas/prometheus/discovery/triton/triton.go: -------------------------------------------------------------------------------- 1 | // Copyright (c) bwplotka/mimic Authors 2 | // Licensed under the Apache License 2.0. 3 | 4 | // Copyright 2017 The Prometheus Authors 5 | // Licensed under the Apache License, Version 2.0 (the "License"); 6 | // you may not use this file except in compliance with the License. 7 | // You may obtain a copy of the License at 8 | // 9 | // http://www.apache.org/licenses/LICENSE-2.0 10 | // 11 | // Unless required by applicable law or agreed to in writing, software 12 | // distributed under the License is distributed on an "AS IS" BASIS, 13 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | // See the License for the specific language governing permissions and 15 | // limitations under the License. 16 | 17 | package triton 18 | 19 | import ( 20 | "github.com/prometheus/common/model" 21 | 22 | config_util "github.com/prometheus/common/config" 23 | ) 24 | 25 | // SDConfig is the configuration for Triton based service discovery. 26 | type SDConfig struct { 27 | Account string `yaml:"account"` 28 | DNSSuffix string `yaml:"dns_suffix"` 29 | Endpoint string `yaml:"endpoint"` 30 | Groups []string `yaml:"groups,omitempty"` 31 | Port int `yaml:"port"` 32 | RefreshInterval model.Duration `yaml:"refresh_interval,omitempty"` 33 | TLSConfig config_util.TLSConfig `yaml:"tls_config,omitempty"` 34 | Version int `yaml:"version"` 35 | } 36 | -------------------------------------------------------------------------------- /examples/prometheus-rem-read-benchmark/schemas/prometheus/discovery/zookeeper/zookeeper.go: -------------------------------------------------------------------------------- 1 | // Copyright (c) bwplotka/mimic Authors 2 | // Licensed under the Apache License 2.0. 3 | 4 | // Copyright 2015 The Prometheus Authors 5 | // Licensed under the Apache License, Version 2.0 (the "License"); 6 | // you may not use this file except in compliance with the License. 7 | // You may obtain a copy of the License at 8 | // 9 | // http://www.apache.org/licenses/LICENSE-2.0 10 | // 11 | // Unless required by applicable law or agreed to in writing, software 12 | // distributed under the License is distributed on an "AS IS" BASIS, 13 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | // See the License for the specific language governing permissions and 15 | // limitations under the License. 16 | 17 | package zookeeper 18 | 19 | import ( 20 | "github.com/prometheus/common/model" 21 | ) 22 | 23 | // ServersetSDConfig is the configuration for Twitter serversets in Zookeeper based discovery. 24 | type ServersetSDConfig struct { 25 | Servers []string `yaml:"servers"` 26 | Paths []string `yaml:"paths"` 27 | Timeout model.Duration `yaml:"timeout,omitempty"` 28 | } 29 | 30 | // NerveSDConfig is the configuration for AirBnB's Nerve in Zookeeper based discovery. 31 | type NerveSDConfig struct { 32 | Servers []string `yaml:"servers"` 33 | Paths []string `yaml:"paths"` 34 | Timeout model.Duration `yaml:"timeout,omitempty"` 35 | } 36 | -------------------------------------------------------------------------------- /examples/prometheus-rem-read-benchmark/schemas/prometheus/prometheus.go: -------------------------------------------------------------------------------- 1 | // Copyright (c) bwplotka/mimic Authors 2 | // Licensed under the Apache License 2.0. 3 | 4 | package prometheus 5 | 6 | import ( 7 | "fmt" 8 | "net/url" 9 | "regexp" 10 | "strings" 11 | 12 | sdconfig "github.com/bwplotka/mimic/lib/schemas/prometheus/discovery/config" 13 | config_util "github.com/prometheus/common/config" 14 | "github.com/prometheus/common/model" 15 | ) 16 | 17 | // NOTE(bwplotka): Stripped out Prometheus configuration from: https://github.com/prometheus/prometheus/blob/master/config/config.go 18 | // We cannot import them directly easily as config package has cosmic number of dependencies (50+), dependency hell. 19 | // TODO(bwplotka): Contribute and strip deps in Prometheus upstream once we agree as Prometheus maintainers if that use case we want to be support. 20 | 21 | // Config is the top-level configuration for Prometheus's config files. 22 | type Config struct { 23 | GlobalConfig GlobalConfig `yaml:"global"` 24 | AlertingConfig AlertingConfig `yaml:"alerting,omitempty"` 25 | RuleFiles []string `yaml:"rule_files,omitempty"` 26 | ScrapeConfigs []*ScrapeConfig `yaml:"scrape_configs,omitempty"` 27 | 28 | RemoteWriteConfigs []*RemoteWriteConfig `yaml:"remote_write,omitempty"` 29 | RemoteReadConfigs []*RemoteReadConfig `yaml:"remote_read,omitempty"` 30 | } 31 | 32 | // GlobalConfig configures values that are used across other configuration 33 | // objects. 34 | type GlobalConfig struct { 35 | // How frequently to scrape targets by default. 36 | ScrapeInterval model.Duration `yaml:"scrape_interval,omitempty"` 37 | // The default timeout when scraping targets. 38 | ScrapeTimeout model.Duration `yaml:"scrape_timeout,omitempty"` 39 | // How frequently to evaluate rules by default. 40 | EvaluationInterval model.Duration `yaml:"evaluation_interval,omitempty"` 41 | // The labels to add to any timeseries that this Prometheus instance scrapes. 42 | ExternalLabels model.LabelSet `yaml:"external_labels,omitempty"` 43 | } 44 | 45 | // ScrapeConfig configures a scraping unit for Prometheus. 46 | type ScrapeConfig struct { 47 | // The job name to which the job label is set by default. 48 | JobName string `yaml:"job_name"` 49 | // Indicator whether the scraped metrics should remain unmodified. 50 | HonorLabels bool `yaml:"honor_labels,omitempty"` 51 | // A set of query parameters with which the target is scraped. 52 | Params url.Values `yaml:"params,omitempty"` 53 | // How frequently to scrape the targets of this scrape config. 54 | ScrapeInterval model.Duration `yaml:"scrape_interval,omitempty"` 55 | // The timeout for scraping targets of this config. 56 | ScrapeTimeout model.Duration `yaml:"scrape_timeout,omitempty"` 57 | // The HTTP resource path on which to fetch metrics from targets. 58 | MetricsPath string `yaml:"metrics_path,omitempty"` 59 | // The URL scheme with which to fetch metrics from targets. 60 | Scheme string `yaml:"scheme,omitempty"` 61 | // More than this many samples post metric-relabelling will cause the scrape to fail. 62 | SampleLimit uint `yaml:"sample_limit,omitempty"` 63 | 64 | // We cannot do proper Go type embedding below as the parser will then parse 65 | // values arbitrarily into the overflow maps of further-down types. 66 | 67 | ServiceDiscoveryConfig sdconfig.ServiceDiscoveryConfig `yaml:",inline"` 68 | HTTPClientConfig config_util.HTTPClientConfig `yaml:",inline"` 69 | 70 | // List of target relabel configurations. 71 | RelabelConfigs []*RelabelConfig `yaml:"relabel_configs,omitempty"` 72 | // List of metric relabel configurations. 73 | MetricRelabelConfigs []*RelabelConfig `yaml:"metric_relabel_configs,omitempty"` 74 | } 75 | 76 | // AlertingConfig configures alerting and alertmanager related configs. 77 | type AlertingConfig struct { 78 | AlertRelabelConfigs []*RelabelConfig `yaml:"alert_relabel_configs,omitempty"` 79 | AlertmanagerConfigs []*AlertmanagerConfig `yaml:"alertmanagers,omitempty"` 80 | } 81 | 82 | // AlertmanagerConfig configures how Alertmanagers can be discovered and communicated with. 83 | type AlertmanagerConfig struct { 84 | // We cannot do proper Go type embedding below as the parser will then parse 85 | // values arbitrarily into the overflow maps of further-down types. 86 | 87 | ServiceDiscoveryConfig sdconfig.ServiceDiscoveryConfig `yaml:",inline"` 88 | HTTPClientConfig config_util.HTTPClientConfig `yaml:",inline"` 89 | 90 | // The URL scheme to use when talking to Alertmanagers. 91 | Scheme string `yaml:"scheme,omitempty"` 92 | // Path prefix to add in front of the push endpoint path. 93 | PathPrefix string `yaml:"path_prefix,omitempty"` 94 | // The timeout used when sending alerts. 95 | Timeout model.Duration `yaml:"timeout,omitempty"` 96 | 97 | // List of Alertmanager relabel configurations. 98 | RelabelConfigs []*RelabelConfig `yaml:"relabel_configs,omitempty"` 99 | } 100 | 101 | // ClientCert contains client cert credentials. 102 | type ClientCert struct { 103 | Cert string `yaml:"cert"` 104 | Key config_util.Secret `yaml:"key"` 105 | } 106 | 107 | // FileSDConfig is the configuration for file based discovery. 108 | type FileSDConfig struct { 109 | Files []string `yaml:"files"` 110 | RefreshInterval model.Duration `yaml:"refresh_interval,omitempty"` 111 | } 112 | 113 | // RelabelAction is the action to be performed on relabeling. 114 | type RelabelAction string 115 | 116 | const ( 117 | // RelabelReplace performs a regex replacement. 118 | RelabelReplace RelabelAction = "replace" 119 | // RelabelKeep drops targets for which the input does not match the regex. 120 | RelabelKeep RelabelAction = "keep" 121 | // RelabelDrop drops targets for which the input does match the regex. 122 | RelabelDrop RelabelAction = "drop" 123 | // RelabelHashMod sets a label to the modulus of a hash of labels. 124 | RelabelHashMod RelabelAction = "hashmod" 125 | // RelabelLabelMap copies labels to other labelnames based on a regex. 126 | RelabelLabelMap RelabelAction = "labelmap" 127 | // RelabelLabelDrop drops any label matching the regex. 128 | RelabelLabelDrop RelabelAction = "labeldrop" 129 | // RelabelLabelKeep drops any label not matching the regex. 130 | RelabelLabelKeep RelabelAction = "labelkeep" 131 | ) 132 | 133 | // UnmarshalYAML implements the yaml.Unmarshaler interface. 134 | func (a *RelabelAction) UnmarshalYAML(unmarshal func(interface{}) error) error { 135 | var s string 136 | if err := unmarshal(&s); err != nil { 137 | return err 138 | } 139 | switch act := RelabelAction(strings.ToLower(s)); act { 140 | case RelabelReplace, RelabelKeep, RelabelDrop, RelabelHashMod, RelabelLabelMap, RelabelLabelDrop, RelabelLabelKeep: 141 | *a = act 142 | return nil 143 | } 144 | return fmt.Errorf("unknown relabel action %q", s) 145 | } 146 | 147 | // RelabelConfig is the configuration for relabeling of target label sets. 148 | type RelabelConfig struct { 149 | // A list of labels from which values are taken and concatenated 150 | // with the configured separator in order. 151 | SourceLabels model.LabelNames `yaml:"source_labels,flow,omitempty"` 152 | // Separator is the string between concatenated values from the source labels. 153 | Separator string `yaml:"separator,omitempty"` 154 | // Regex against which the concatenation is matched. 155 | Regex Regexp `yaml:"regex,omitempty"` 156 | // Modulus to take of the hash of concatenated values from the source labels. 157 | Modulus uint64 `yaml:"modulus,omitempty"` 158 | // TargetLabel is the label to which the resulting string is written in a replacement. 159 | // Regexp interpolation is allowed for the replace action. 160 | TargetLabel string `yaml:"target_label,omitempty"` 161 | // Replacement is the regex replacement pattern to be used. 162 | Replacement string `yaml:"replacement,omitempty"` 163 | // Action is the action to be performed for the relabeling. 164 | Action RelabelAction `yaml:"action,omitempty"` 165 | } 166 | 167 | // Regexp encapsulates a regexp.Regexp and makes it YAML marshallable. 168 | type Regexp struct { 169 | *regexp.Regexp 170 | original string 171 | } 172 | 173 | // NewRegexp creates a new anchored Regexp and returns an error if the 174 | // passed-in regular expression does not compile. 175 | func NewRegexp(s string) (Regexp, error) { 176 | regex, err := regexp.Compile("^(?:" + s + ")$") 177 | return Regexp{ 178 | Regexp: regex, 179 | original: s, 180 | }, err 181 | } 182 | 183 | // MustNewRegexp works like NewRegexp, but panics if the regular expression does not compile. 184 | func MustNewRegexp(s string) Regexp { 185 | re, err := NewRegexp(s) 186 | if err != nil { 187 | panic(err) 188 | } 189 | return re 190 | } 191 | 192 | // UnmarshalYAML implements the yaml.Unmarshaler interface. 193 | func (re *Regexp) UnmarshalYAML(unmarshal func(interface{}) error) error { 194 | var s string 195 | if err := unmarshal(&s); err != nil { 196 | return err 197 | } 198 | r, err := NewRegexp(s) 199 | if err != nil { 200 | return err 201 | } 202 | *re = r 203 | return nil 204 | } 205 | 206 | // MarshalYAML implements the yaml.Marshaler interface. 207 | func (re Regexp) MarshalYAML() (interface{}, error) { 208 | if re.original != "" { 209 | return re.original, nil 210 | } 211 | return nil, nil 212 | } 213 | 214 | // RemoteWriteConfig is the configuration for writing to remote storage. 215 | type RemoteWriteConfig struct { 216 | URL *config_util.URL `yaml:"url"` 217 | RemoteTimeout model.Duration `yaml:"remote_timeout,omitempty"` 218 | WriteRelabelConfigs []*RelabelConfig `yaml:"write_relabel_configs,omitempty"` 219 | 220 | // We cannot do proper Go type embedding below as the parser will then parse 221 | // values arbitrarily into the overflow maps of further-down types. 222 | HTTPClientConfig config_util.HTTPClientConfig `yaml:",inline"` 223 | QueueConfig QueueConfig `yaml:"queue_config,omitempty"` 224 | } 225 | 226 | // QueueConfig is the configuration for the queue used to write to remote 227 | // storage. 228 | type QueueConfig struct { 229 | // Number of samples to buffer per shard before we start dropping them. 230 | Capacity int `yaml:"capacity,omitempty"` 231 | 232 | // Max number of shards, i.e. amount of concurrency. 233 | MaxShards int `yaml:"max_shards,omitempty"` 234 | 235 | // Maximum number of samples per send. 236 | MaxSamplesPerSend int `yaml:"max_samples_per_send,omitempty"` 237 | 238 | // Maximum time sample will wait in buffer. 239 | BatchSendDeadline model.Duration `yaml:"batch_send_deadline,omitempty"` 240 | 241 | // Max number of times to retry a batch on recoverable errors. 242 | MaxRetries int `yaml:"max_retries,omitempty"` 243 | 244 | // On recoverable errors, backoff exponentially. 245 | MinBackoff model.Duration `yaml:"min_backoff,omitempty"` 246 | MaxBackoff model.Duration `yaml:"max_backoff,omitempty"` 247 | } 248 | 249 | // RemoteReadConfig is the configuration for reading from remote storage. 250 | type RemoteReadConfig struct { 251 | URL *config_util.URL `yaml:"url"` 252 | RemoteTimeout model.Duration `yaml:"remote_timeout,omitempty"` 253 | ReadRecent bool `yaml:"read_recent,omitempty"` 254 | // We cannot do proper Go type embedding below as the parser will then parse 255 | // values arbitrarily into the overflow maps of further-down types. 256 | HTTPClientConfig config_util.HTTPClientConfig `yaml:",inline"` 257 | 258 | // RequiredMatchers is an optional list of equality matchers which have to 259 | // be present in a selector to query the remote read endpoint. 260 | RequiredMatchers model.LabelSet `yaml:"required_matchers,omitempty"` 261 | } 262 | -------------------------------------------------------------------------------- /examples/prometheus-rem-read-benchmark/test.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | set -e 4 | 5 | DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" 6 | 7 | cd ${DIR} 8 | 9 | TARGET_URL=$1 10 | 11 | MIN_TDIFF="-12 hours" 12 | MAX_TDIFF="-4 hours" 13 | 14 | MIN_T=$(($(date +%s%N -d "${MIN_TDIFF}")/1000000)) 15 | MAX_T=$(($(date +%s%N -d "${MAX_TDIFF}")/1000000)) 16 | 17 | date 18 | echo "Fetching 10k series StoreAPI.Series from sidecar via RR" 19 | echo "'min_time'=${MIN_T} ${MIN_TDIFF} 'max_time'=${MAX_T} ${MAX_TDIFF}" 20 | GOGOPROTO_ROOT="$(GO111MODULE=on go list -f '{{ .Dir }}' -m github.com/gogo/protobuf)" 21 | 22 | time /home/bartek/Repos/mimic/.bin/grpcurl \ 23 | -plaintext -proto \ 24 | ./rpc.proto -proto ./types.proto \ 25 | -import-path . \ 26 | -import-path ${GOGOPROTO_ROOT} \ 27 | -import-path ${GOGOPROTO_ROOT}/protobuf \ 28 | -d @ \ 29 | ${TARGET_URL} thanos.Store/Series </dev/null 30 | { 31 | "minTime": ${MIN_T}, 32 | "maxTime": ${MAX_T}, 33 | "matchers": [{ 34 | "type": 1, 35 | "name": "__name__", 36 | "value": "unlikely" 37 | }] 38 | } 39 | EOM 40 | 41 | ### 42 | # int64 min_time = 1; 43 | # int64 max_time = 2; 44 | # repeated LabelMatcher matchers = 3 [(gogoproto.nullable) = false]; 45 | # 46 | # int64 max_resolution_window = 4; 47 | # repeated Aggr aggregates = 5; 48 | # 49 | # // Deprecated. Use partial_response_strategy instead. 50 | # bool partial_response_disabled = 6; 51 | ### 52 | 53 | ### 54 | #// Matcher specifies a rule, which can match or set of labels or not. 55 | # enum Type { 56 | # EQ = 0; // = 57 | # NEQ = 1; // != 58 | # RE = 2; // =~ 59 | # NRE = 3; // !~ 60 | # } 61 | # Type type = 1; 62 | # string name = 2; 63 | # string value = 3; 64 | ### -------------------------------------------------------------------------------- /examples/prometheus-rem-read-benchmark/types.proto: -------------------------------------------------------------------------------- 1 | syntax = "proto3"; 2 | package thanos; 3 | 4 | option go_package = "storepb"; 5 | 6 | import "gogoproto/gogo.proto"; 7 | 8 | option (gogoproto.sizer_all) = true; 9 | option (gogoproto.marshaler_all) = true; 10 | option (gogoproto.unmarshaler_all) = true; 11 | option (gogoproto.goproto_getters_all) = false; 12 | 13 | message Label { 14 | string name = 1; 15 | string value = 2; 16 | } 17 | 18 | message Chunk { 19 | enum Encoding { 20 | XOR = 0; 21 | } 22 | Encoding type = 1; 23 | bytes data = 2; 24 | } 25 | 26 | message Series { 27 | repeated Label labels = 1 [(gogoproto.nullable) = false]; 28 | repeated AggrChunk chunks = 2 [(gogoproto.nullable) = false]; 29 | } 30 | 31 | message AggrChunk { 32 | int64 min_time = 1; 33 | int64 max_time = 2; 34 | 35 | Chunk raw = 3; 36 | Chunk count = 4; 37 | Chunk sum = 5; 38 | Chunk min = 6; 39 | Chunk max = 7; 40 | Chunk counter = 8; 41 | } 42 | 43 | // Matcher specifies a rule, which can match or set of labels or not. 44 | message LabelMatcher { 45 | enum Type { 46 | EQ = 0; // = 47 | NEQ = 1; // != 48 | RE = 2; // =~ 49 | NRE = 3; // !~ 50 | } 51 | Type type = 1; 52 | string name = 2; 53 | string value = 3; 54 | } 55 | -------------------------------------------------------------------------------- /examples/terraform/go.mod: -------------------------------------------------------------------------------- 1 | module github.com/bwplotka/mimic/examples/terraform 2 | 3 | go 1.16 4 | 5 | require ( 6 | github.com/bwplotka/mimic v0.0.0-20190730202618-06ab9976e8ef 7 | github.com/kr/text v0.2.0 // indirect 8 | github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e // indirect 9 | gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f // indirect 10 | ) 11 | 12 | // This module is meant to be executed from repo root. 13 | replace github.com/bwplotka/mimic => ../../ 14 | -------------------------------------------------------------------------------- /examples/terraform/go.sum: -------------------------------------------------------------------------------- 1 | github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751 h1:JYp7IbQjafoB+tBA3gMyHYHrpOtNuDiK/uB5uXxq5wM= 2 | github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= 3 | github.com/alecthomas/units v0.0.0-20211218093645-b94a6e3cc137 h1:s6gZFSlWYmbqAuRjVTiNNhvNRfY2Wxp9nhfyel4rklc= 4 | github.com/alecthomas/units v0.0.0-20211218093645-b94a6e3cc137/go.mod h1:OMCwj8VM1Kc9e19TLln2VL61YJF0x1XFtfdL4JdbSyE= 5 | github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= 6 | github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= 7 | github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= 8 | github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= 9 | github.com/efficientgo/tools/core v0.0.0-20220225185207-fe763185946b h1:ZHiD4/yE4idlbqvAO6iYCOYRzOMRpxkW+FKasRA3tsQ= 10 | github.com/efficientgo/tools/core v0.0.0-20220225185207-fe763185946b/go.mod h1:OmVcnJopJL8d3X3sSXTiypGoUSgFq1aDGmlrdi9dn/M= 11 | github.com/ghodss/yaml v1.0.0 h1:wQHKEahhL6wmXdzwWG11gIVCkOv05bNOh+Rxn0yngAk= 12 | github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= 13 | github.com/go-kit/log v0.2.1 h1:MRVx0/zhvdseW+Gza6N9rVzU/IVzaeE1SFI4raAhmBU= 14 | github.com/go-kit/log v0.2.1/go.mod h1:NwTd00d/i8cPZ3xOwwiv2PO5MOcx78fFErGNcVmBjv0= 15 | github.com/go-logfmt/logfmt v0.5.1 h1:otpy5pqBCBZ1ng9RQ0dPu4PN7ba75Y/aA+UpowDyNVA= 16 | github.com/go-logfmt/logfmt v0.5.1/go.mod h1:WYhtIu8zTZfxdn5+rREduYbwxfcBr/Vr6KEVveWlfTs= 17 | github.com/hashicorp/hcl v1.0.0 h1:0Anlzjpi4vEasTeNFn2mLJgTSwt0+6sfsiTG8qcWGx4= 18 | github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ= 19 | github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= 20 | github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= 21 | github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= 22 | github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= 23 | github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= 24 | github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e h1:fD57ERR4JtEqsWbfPhv4DMiApHyliiK5xCTNVSPiaAs= 25 | github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno= 26 | github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= 27 | github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= 28 | github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= 29 | github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= 30 | github.com/rodaine/hclencoder v0.0.1 h1:1jK2rGFxSDT1eU9oVjK4ewrIhMWTcc0yCfZMiN6xRJM= 31 | github.com/rodaine/hclencoder v0.0.1/go.mod h1:XKt85p0Ifyt0pr1KVeB3eL+dUFAKa+IA637lLahBcOQ= 32 | github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= 33 | github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= 34 | github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= 35 | github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= 36 | github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= 37 | github.com/stretchr/testify v1.7.4 h1:wZRexSlwd7ZXfKINDLsO4r7WBt3gTKONc6K/VesHvHM= 38 | github.com/stretchr/testify v1.7.4/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= 39 | go.uber.org/goleak v1.1.10 h1:z+mqJhf6ss6BSfSM671tgKyZBFPTTJM+HLxnhPC3wu0= 40 | go.uber.org/goleak v1.1.10/go.mod h1:8a7PlsEVH3e/a/GLqe5IIrQx6GzcnRmZEufDUTk4A7A= 41 | golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= 42 | golang.org/x/lint v0.0.0-20190930215403-16217165b5de h1:5hukYrvBGR8/eNkX5mdUezrA6JiaEZDtJb9Ei+1LlBs= 43 | golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= 44 | golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= 45 | golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= 46 | golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= 47 | golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= 48 | golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= 49 | golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= 50 | golang.org/x/tools v0.0.0-20191108193012-7d206e10da11 h1:Yq9t9jnGoR+dBuitxdo9l6Q7xh/zOyNnYUtDKaQ3x0E= 51 | golang.org/x/tools v0.0.0-20191108193012-7d206e10da11/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= 52 | golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= 53 | gopkg.in/alecthomas/kingpin.v2 v2.2.6 h1:jMFz6MfLP0/4fUyZle81rXUoxOBFi19VUFKVDOQfozc= 54 | gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw= 55 | gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= 56 | gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= 57 | gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f h1:BLraFXnmrev5lT+xlilqcH8XK9/i0At2xKjWk4p6zsU= 58 | gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= 59 | gopkg.in/yaml.v2 v2.2.2 h1:ZCJp+EgiOT7lHqUV2J862kp8Qj64Jo6az82+3Td9dZw= 60 | gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= 61 | gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= 62 | gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= 63 | gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= 64 | -------------------------------------------------------------------------------- /examples/terraform/main.go: -------------------------------------------------------------------------------- 1 | // Copyright (c) bwplotka/mimic Authors 2 | // Licensed under the Apache License 2.0. 3 | 4 | package main 5 | 6 | import ( 7 | "github.com/bwplotka/mimic" 8 | "github.com/bwplotka/mimic/encoding" 9 | ) 10 | 11 | type Listener struct { 12 | InstancePort int `hcl:"instance_port"` 13 | InstanceProtocol string `hcl:"instance_protocol"` 14 | LBPort int `hcl:"lb_port"` 15 | LBProtocol string `hcl:"lb_protocol"` 16 | } 17 | 18 | type AWSELB struct { 19 | Key string `hcl:",key"` 20 | Name string `hcl:"name"` 21 | Listener Listener `hcl:"listener"` 22 | Instances []string `hcl:"instances"` 23 | } 24 | 25 | type AWSInstance struct { 26 | Key string `hcl:",key"` 27 | Count int `hcl:"count"` 28 | AMI string `hcl:"ami"` 29 | InstanceType string `hcl:"instance_type"` 30 | } 31 | 32 | func main() { 33 | generator := mimic.New() 34 | 35 | // Defer Generate to ensure we generate the output. 36 | defer generator.Generate() 37 | 38 | // Example taken from https://www.terraform.io/. 39 | instance := struct { 40 | AWSELB AWSELB `hcl:"resource \"aws_elb\""` 41 | AWSInstanceResource AWSInstance `hcl:"resource \"aws_instance\""` 42 | }{ 43 | AWSELB: AWSELB{ 44 | Key: "frontend", 45 | Name: "frontend-load-balancer", 46 | Listener: Listener{ 47 | InstancePort: 8080, 48 | InstanceProtocol: "http", 49 | LBPort: 80, 50 | LBProtocol: "http", 51 | }, 52 | Instances: []string{"${aws_instance.app.*.id}"}, 53 | }, 54 | AWSInstanceResource: AWSInstance{ 55 | Key: "app", 56 | Count: 5, 57 | AMI: "ami-408c7f28", 58 | InstanceType: "t1.micro", 59 | }, 60 | } 61 | 62 | // Now Add some-statefulset.yaml to the config folder. 63 | generator.With("terraform").Add("example.tf", encoding.HCL(instance)) 64 | } 65 | -------------------------------------------------------------------------------- /files.go: -------------------------------------------------------------------------------- 1 | // Copyright (c) bwplotka/mimic Authors 2 | // Licensed under the Apache License 2.0. 3 | 4 | package mimic 5 | 6 | import ( 7 | "fmt" 8 | "io" 9 | "os" 10 | "path/filepath" 11 | 12 | "github.com/bwplotka/mimic/encoding" 13 | "github.com/go-kit/log" 14 | "github.com/go-kit/log/level" 15 | ) 16 | 17 | const GeneratedComment = "Generated by mimic. DO NOT EDIT." 18 | 19 | // FilePool is a struct for storing and managing files to be generated as part of generation. 20 | type FilePool struct { 21 | Logger log.Logger 22 | 23 | path []string 24 | 25 | m map[string]string 26 | 27 | topLevelComments []string 28 | } 29 | 30 | // Add adds a file to the file pool at the current path. The file is identified by filename. 31 | // Content of the file is passed via an io.Reader. 32 | // 33 | // If the file with the given name has already been added at this path the code will `panic`. 34 | // NOTE: See mimic/encoding for different marshallers to use as io.Reader. 35 | func (f *FilePool) Add(fileName string, e encoding.Encoder) { 36 | if filepath.Base(fileName) != fileName { 37 | Panicf("") 38 | } 39 | 40 | b, err := io.ReadAll(e) 41 | if err != nil { 42 | Panicf("failed to output: %s", err) 43 | } 44 | 45 | if len(f.topLevelComments) > 0 { 46 | commentBytes := []byte{} 47 | for _, comment := range f.topLevelComments { 48 | commentBytes = append(commentBytes, e.EncodeComment(comment)...) 49 | } 50 | b = append(commentBytes, b...) 51 | } 52 | 53 | output := filepath.Join(append(f.path, fileName)...) 54 | 55 | // Check whether we have already written something into this file. 56 | if _, ok := f.m[output]; ok { 57 | Panicf("filename clash: %s", output) 58 | } 59 | f.m[output] = string(b) 60 | } 61 | 62 | func (f *FilePool) write(outputDir string) { 63 | for file, contents := range f.m { 64 | out := filepath.Join(outputDir, file) 65 | if err := os.MkdirAll(filepath.Dir(out), 0755); err != nil { 66 | PanicErr(fmt.Errorf("create directory %s: %w", filepath.Dir(out), err)) 67 | } 68 | 69 | // TODO(https://github.com/bwplotka/mimic/issues/11): Diff the things if something is already here and remove. 70 | 71 | _ = level.Debug(f.Logger).Log("msg", "writing file", "file", out) 72 | if err := os.WriteFile(out, []byte(contents), 0755); err != nil { 73 | PanicErr(fmt.Errorf("write file to %s: %w", out, err)) 74 | } 75 | } 76 | } 77 | -------------------------------------------------------------------------------- /gen.go: -------------------------------------------------------------------------------- 1 | // Copyright (c) bwplotka/mimic Authors 2 | // Licensed under the Apache License 2.0. 3 | 4 | package mimic 5 | 6 | import ( 7 | "errors" 8 | "fmt" 9 | "os" 10 | 11 | "github.com/go-kit/log" 12 | "github.com/go-kit/log/level" 13 | "gopkg.in/alecthomas/kingpin.v2" 14 | ) 15 | 16 | // Generator manages a pool of generated files. 17 | type Generator struct { 18 | FilePool 19 | 20 | out string 21 | generated bool 22 | } 23 | 24 | // New returns a new Generator that parses os.Args as command line arguments. 25 | // It allows passing closure BEFORE parsing the flags to allow defining additional flags. 26 | // 27 | // NOTE: Read README.md before using. This is intentionally NOT following Go library patterns like: 28 | // * It uses panics as the main error handling way. 29 | // * It creates CLI command inside constructor. 30 | // * It does not allow custom loggers etc 31 | func New(injs ...func(cmd *kingpin.CmdClause)) *Generator { 32 | app := kingpin.New("mimic", "mimic: https://github.com/bwplotka/mimic") 33 | app.HelpFlag.Short('h') 34 | 35 | gen := app.Command("generate", "generates output files from all registered files via Add method.") 36 | out := gen.Flag("output", "output directory for generated files.").Short('o').Default("gen").String() 37 | 38 | for _, inj := range injs { 39 | inj(gen) 40 | } 41 | 42 | logLevel := app.Flag("log.level", "Log filtering level."). 43 | Default("info").Enum("error", "warn", "info", "debug") 44 | 45 | cmd, err := app.Parse(os.Args[1:]) 46 | if err != nil { 47 | _, _ = fmt.Fprintln(os.Stderr, fmt.Errorf("error parsing commandline arguments: %v", err)) 48 | app.Usage(os.Args[1:]) 49 | os.Exit(2) 50 | } 51 | 52 | var logger log.Logger 53 | { 54 | var lvl level.Option 55 | switch *logLevel { 56 | case "error": 57 | lvl = level.AllowError() 58 | case "warn": 59 | lvl = level.AllowWarn() 60 | case "info": 61 | lvl = level.AllowInfo() 62 | case "debug": 63 | lvl = level.AllowDebug() 64 | default: 65 | panic("unexpected log level") 66 | } 67 | logger = log.NewLogfmtLogger(log.NewSyncWriter(os.Stderr)) 68 | logger = level.NewFilter(logger, lvl) 69 | logger = log.With(logger, "ts", log.DefaultTimestampUTC, "caller", log.DefaultCaller) 70 | } 71 | 72 | a := &Generator{out: *out} 73 | switch cmd { 74 | case gen.FullCommand(): 75 | a.FilePool = FilePool{Logger: logger, m: map[string]string{}} 76 | return a 77 | } 78 | 79 | _ = level.Error(logger).Log("err", "command not found", "command", cmd) 80 | os.Exit(2) 81 | 82 | return nil 83 | } 84 | 85 | // With behaves like linux `cd` command. It allows to "walk" & organize output files in a desired way for ease of use. 86 | // Example: 87 | // 88 | // ``` 89 | // 90 | // gen := gen.With("mycompany.com", "production", "eu1", "kubernetes", "thanos") 91 | // 92 | // ``` 93 | // Giving the path `mycompany.com/production/eu1/kubernetes/thanos`. 94 | // 95 | // With return a Generator pointing at the specified path which can be specified even further: 96 | // Example: 97 | // ``` 98 | // 99 | // gen := mimic.New() 100 | // // gen/ 101 | // ... 102 | // gen = gen.With('foo') 103 | // // gen/foo 104 | // ... 105 | // { 106 | // gen := gen.With('bar') 107 | // // gen/foo/bar 108 | // } 109 | // // gen/foo 110 | // 111 | // ``` 112 | func (g *Generator) With(parts ...string) *Generator { 113 | // TODO(bwplotka): Support "..", to get back? 114 | 115 | return &Generator{ 116 | out: g.out, 117 | FilePool: FilePool{ 118 | Logger: g.Logger, 119 | path: append(g.path, parts...), 120 | m: g.m, 121 | topLevelComments: g.topLevelComments, 122 | }, 123 | } 124 | } 125 | 126 | // WithTopLevelComment enables mimic to add any string as a header comment for a genenrated 127 | // file. Follows same usage semantics as With(). 128 | // 129 | // Example: 130 | // 131 | // gen := mimic.New() 132 | // defer gen.Generate() 133 | // 134 | // gen.With("config").WithTopLevelComment(mimic.GeneratedComment).Add(name+".yaml", encoding.GhodssYAML(config)) 135 | // 136 | // Like With, you can also chain multiple WithTopLevelComment(), which will be added to the top of a file in that order. 137 | // 138 | // Example: 139 | // 140 | // gen := mimic.New() 141 | // 142 | // defer gen.Generate() 143 | // gen = gen.WithTopLevelComment("Foo.") 144 | // 145 | // gen.With("config").WithTopLevelComment("Bar.").Add(name+".yaml", encoding.GhodssYAML(config)) 146 | // 147 | // This will result in a YAML file like, 148 | // 149 | // # Foo. 150 | // # Bar. 151 | // config: 152 | // - prometheus: 153 | // 154 | // NOTE: This option will be noop for encodings that does not support comment (e.g. encoding.JSON). 155 | func (g *Generator) WithTopLevelComment(content string) *Generator { 156 | return &Generator{ 157 | out: g.out, 158 | FilePool: FilePool{ 159 | Logger: g.Logger, 160 | path: g.path, 161 | m: g.m, 162 | topLevelComments: append(g.topLevelComments, content), 163 | }, 164 | } 165 | } 166 | 167 | // Generate generates the configuration files that have been defined and added to a generator. 168 | func (g *Generator) Generate() { 169 | if g.generated { 170 | PanicErr(errors.New("generate method already invoked once")) 171 | } 172 | defer func() { g.generated = true }() 173 | 174 | _ = level.Info(g.Logger).Log("msg", "generated output", "dir", g.out) 175 | g.write(g.out) 176 | } 177 | -------------------------------------------------------------------------------- /go.mod: -------------------------------------------------------------------------------- 1 | module github.com/bwplotka/mimic 2 | 3 | go 1.17 4 | 5 | require ( 6 | github.com/efficientgo/tools/core v0.0.0-20220225185207-fe763185946b 7 | github.com/ghodss/yaml v1.0.0 8 | github.com/go-kit/log v0.2.1 9 | github.com/rodaine/hclencoder v0.0.1 10 | gopkg.in/alecthomas/kingpin.v2 v2.2.6 11 | gopkg.in/yaml.v3 v3.0.1 12 | ) 13 | 14 | require ( 15 | github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751 // indirect 16 | github.com/alecthomas/units v0.0.0-20211218093645-b94a6e3cc137 // indirect 17 | github.com/davecgh/go-spew v1.1.1 // indirect 18 | github.com/go-logfmt/logfmt v0.5.1 // indirect 19 | github.com/hashicorp/hcl v1.0.0 // indirect 20 | github.com/pkg/errors v0.9.1 // indirect 21 | github.com/pmezard/go-difflib v1.0.0 // indirect 22 | github.com/stretchr/testify v1.7.4 // indirect; what? 23 | go.uber.org/goleak v1.1.10 // indirect 24 | golang.org/x/lint v0.0.0-20190930215403-16217165b5de // indirect 25 | golang.org/x/tools v0.0.0-20191108193012-7d206e10da11 // indirect 26 | gopkg.in/yaml.v2 v2.2.2 // indirect 27 | ) 28 | -------------------------------------------------------------------------------- /go.sum: -------------------------------------------------------------------------------- 1 | github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751 h1:JYp7IbQjafoB+tBA3gMyHYHrpOtNuDiK/uB5uXxq5wM= 2 | github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= 3 | github.com/alecthomas/units v0.0.0-20211218093645-b94a6e3cc137 h1:s6gZFSlWYmbqAuRjVTiNNhvNRfY2Wxp9nhfyel4rklc= 4 | github.com/alecthomas/units v0.0.0-20211218093645-b94a6e3cc137/go.mod h1:OMCwj8VM1Kc9e19TLln2VL61YJF0x1XFtfdL4JdbSyE= 5 | github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= 6 | github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= 7 | github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= 8 | github.com/efficientgo/tools/core v0.0.0-20220225185207-fe763185946b h1:ZHiD4/yE4idlbqvAO6iYCOYRzOMRpxkW+FKasRA3tsQ= 9 | github.com/efficientgo/tools/core v0.0.0-20220225185207-fe763185946b/go.mod h1:OmVcnJopJL8d3X3sSXTiypGoUSgFq1aDGmlrdi9dn/M= 10 | github.com/ghodss/yaml v1.0.0 h1:wQHKEahhL6wmXdzwWG11gIVCkOv05bNOh+Rxn0yngAk= 11 | github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= 12 | github.com/go-kit/log v0.2.1 h1:MRVx0/zhvdseW+Gza6N9rVzU/IVzaeE1SFI4raAhmBU= 13 | github.com/go-kit/log v0.2.1/go.mod h1:NwTd00d/i8cPZ3xOwwiv2PO5MOcx78fFErGNcVmBjv0= 14 | github.com/go-logfmt/logfmt v0.5.1 h1:otpy5pqBCBZ1ng9RQ0dPu4PN7ba75Y/aA+UpowDyNVA= 15 | github.com/go-logfmt/logfmt v0.5.1/go.mod h1:WYhtIu8zTZfxdn5+rREduYbwxfcBr/Vr6KEVveWlfTs= 16 | github.com/hashicorp/hcl v1.0.0 h1:0Anlzjpi4vEasTeNFn2mLJgTSwt0+6sfsiTG8qcWGx4= 17 | github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ= 18 | github.com/kr/pretty v0.1.0 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI= 19 | github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= 20 | github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= 21 | github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE= 22 | github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= 23 | github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= 24 | github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= 25 | github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= 26 | github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= 27 | github.com/rodaine/hclencoder v0.0.1 h1:1jK2rGFxSDT1eU9oVjK4ewrIhMWTcc0yCfZMiN6xRJM= 28 | github.com/rodaine/hclencoder v0.0.1/go.mod h1:XKt85p0Ifyt0pr1KVeB3eL+dUFAKa+IA637lLahBcOQ= 29 | github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= 30 | github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= 31 | github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= 32 | github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= 33 | github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= 34 | github.com/stretchr/testify v1.7.4 h1:wZRexSlwd7ZXfKINDLsO4r7WBt3gTKONc6K/VesHvHM= 35 | github.com/stretchr/testify v1.7.4/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= 36 | go.uber.org/goleak v1.1.10 h1:z+mqJhf6ss6BSfSM671tgKyZBFPTTJM+HLxnhPC3wu0= 37 | go.uber.org/goleak v1.1.10/go.mod h1:8a7PlsEVH3e/a/GLqe5IIrQx6GzcnRmZEufDUTk4A7A= 38 | golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= 39 | golang.org/x/lint v0.0.0-20190930215403-16217165b5de h1:5hukYrvBGR8/eNkX5mdUezrA6JiaEZDtJb9Ei+1LlBs= 40 | golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= 41 | golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= 42 | golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= 43 | golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= 44 | golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= 45 | golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= 46 | golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= 47 | golang.org/x/tools v0.0.0-20191108193012-7d206e10da11 h1:Yq9t9jnGoR+dBuitxdo9l6Q7xh/zOyNnYUtDKaQ3x0E= 48 | golang.org/x/tools v0.0.0-20191108193012-7d206e10da11/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= 49 | golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= 50 | gopkg.in/alecthomas/kingpin.v2 v2.2.6 h1:jMFz6MfLP0/4fUyZle81rXUoxOBFi19VUFKVDOQfozc= 51 | gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw= 52 | gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= 53 | gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 h1:qIbj1fsPNlZgppZ+VLlY7N33q108Sa+fhmuc+sWQYwY= 54 | gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= 55 | gopkg.in/yaml.v2 v2.2.2 h1:ZCJp+EgiOT7lHqUV2J862kp8Qj64Jo6az82+3Td9dZw= 56 | gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= 57 | gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= 58 | gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= 59 | gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= 60 | -------------------------------------------------------------------------------- /panic.go: -------------------------------------------------------------------------------- 1 | // Copyright (c) bwplotka/mimic Authors 2 | // Licensed under the Apache License 2.0. 3 | 4 | package mimic 5 | 6 | import "fmt" 7 | 8 | // Panicf allows panic error propagation using sprintf-like formatting. 9 | func Panicf(format string, a ...interface{}) { 10 | panic(fmt.Sprintf("mimic: "+format, a...)) 11 | } 12 | 13 | // PanicErr allows to panic because of certain error. 14 | func PanicErr(err error) { 15 | Panicf("failed to execute; err: %v", err) 16 | } 17 | 18 | // PanicOnErr allows to panic on error. 19 | func PanicOnErr(err error) { 20 | if err == nil { 21 | return 22 | } 23 | PanicErr(err) 24 | } 25 | --------------------------------------------------------------------------------