1
0
Fork 0
mirror of https://github.com/eosswedenorg/antelope-api-healthcheck synced 2026-07-02 11:43:42 +02:00

Compare commits

...

157 commits

Author SHA1 Message Date
77f3fbde85 remove .github/dependabot.yml 2025-04-29 06:12:06 +02:00
efa0e71f03 Merge branch 'dev' 2025-04-29 06:05:23 +02:00
d37e4c28e7
Merge pull request #25 from eosswedenorg/dependabot/go_modules/golang.org/x/net-0.23.0
build(deps): bump golang.org/x/net from 0.17.0 to 0.23.0
2025-04-29 05:23:42 +02:00
e331b9e2e5
Merge pull request #29 from eosswedenorg/dependabot/go_modules/dev/github.com/panjf2000/gnet/v2-2.5.3
build(deps): bump github.com/panjf2000/gnet/v2 from 2.3.5 to 2.5.3
2025-04-29 05:23:13 +02:00
dependabot[bot]
067aa54095
build(deps): bump github.com/panjf2000/gnet/v2 from 2.3.5 to 2.5.3
Bumps [github.com/panjf2000/gnet/v2](https://github.com/panjf2000/gnet) from 2.3.5 to 2.5.3.
- [Release notes](https://github.com/panjf2000/gnet/releases)
- [Commits](https://github.com/panjf2000/gnet/compare/v2.3.5...v2.5.3)

---
updated-dependencies:
- dependency-name: github.com/panjf2000/gnet/v2
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-06-04 08:56:38 +00:00
dependabot[bot]
e2d6f8f2cd
build(deps): bump golang.org/x/net from 0.17.0 to 0.23.0
Bumps [golang.org/x/net](https://github.com/golang/net) from 0.17.0 to 0.23.0.
- [Commits](https://github.com/golang/net/compare/v0.17.0...v0.23.0)

---
updated-dependencies:
- dependency-name: golang.org/x/net
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-04-19 12:31:09 +00:00
bc5e9c13eb
Merge pull request #19 from eosswedenorg/dependabot/go_modules/dev/github.com/panjf2000/gnet/v2-2.3.5
build(deps): bump github.com/panjf2000/gnet/v2 from 2.3.4 to 2.3.5
2024-03-07 21:48:05 +01:00
8e45579eb9
Merge pull request #20 from eosswedenorg/dependabot/go_modules/dev/github.com/stretchr/testify-1.9.0
build(deps): bump github.com/stretchr/testify from 1.8.4 to 1.9.0
2024-03-07 21:47:57 +01:00
dependabot[bot]
c008a3ec1e
build(deps): bump github.com/stretchr/testify from 1.8.4 to 1.9.0
Bumps [github.com/stretchr/testify](https://github.com/stretchr/testify) from 1.8.4 to 1.9.0.
- [Release notes](https://github.com/stretchr/testify/releases)
- [Commits](https://github.com/stretchr/testify/compare/v1.8.4...v1.9.0)

---
updated-dependencies:
- dependency-name: github.com/stretchr/testify
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-03-05 08:05:48 +00:00
dependabot[bot]
40fb0349ed
build(deps): bump github.com/panjf2000/gnet/v2 from 2.3.4 to 2.3.5
Bumps [github.com/panjf2000/gnet/v2](https://github.com/panjf2000/gnet) from 2.3.4 to 2.3.5.
- [Release notes](https://github.com/panjf2000/gnet/releases)
- [Commits](https://github.com/panjf2000/gnet/compare/v2.3.4...v2.3.5)

---
updated-dependencies:
- dependency-name: github.com/panjf2000/gnet/v2
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-03-05 08:05:37 +00:00
5ef28b0a06
Merge pull request #17 from eosswedenorg/dependabot/go_modules/dev/github.com/panjf2000/gnet/v2-2.3.4
build(deps): bump github.com/panjf2000/gnet/v2 from 2.3.3 to 2.3.4
2024-01-10 16:27:28 +01:00
dependabot[bot]
65d3359f1b
build(deps): bump github.com/panjf2000/gnet/v2 from 2.3.3 to 2.3.4
Bumps [github.com/panjf2000/gnet/v2](https://github.com/panjf2000/gnet) from 2.3.3 to 2.3.4.
- [Release notes](https://github.com/panjf2000/gnet/releases)
- [Commits](https://github.com/panjf2000/gnet/compare/v2.3.3...v2.3.4)

---
updated-dependencies:
- dependency-name: github.com/panjf2000/gnet/v2
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-01-09 08:17:45 +00:00
79e53ff89e
Merge pull request #16 from eosswedenorg/dependabot/go_modules/golang.org/x/crypto-0.17.0
build(deps): bump golang.org/x/crypto from 0.4.0 to 0.17.0
2023-12-19 12:55:53 +01:00
dependabot[bot]
ee40a7066c
build(deps): bump golang.org/x/crypto from 0.4.0 to 0.17.0
Bumps [golang.org/x/crypto](https://github.com/golang/crypto) from 0.4.0 to 0.17.0.
- [Commits](https://github.com/golang/crypto/compare/v0.4.0...v0.17.0)

---
updated-dependencies:
- dependency-name: golang.org/x/crypto
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-12-19 11:54:56 +00:00
84888c7bed
Merge pull request #15 from eosswedenorg/dependabot/go_modules/golang.org/x/net-0.17.0
build(deps): bump golang.org/x/net from 0.7.0 to 0.17.0
2023-12-19 12:53:42 +01:00
dependabot[bot]
5e73f6799f
build(deps): bump golang.org/x/net from 0.7.0 to 0.17.0
Bumps [golang.org/x/net](https://github.com/golang/net) from 0.7.0 to 0.17.0.
- [Commits](https://github.com/golang/net/compare/v0.7.0...v0.17.0)

---
updated-dependencies:
- dependency-name: golang.org/x/net
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-10-11 23:27:06 +00:00
fa9e87a90f
Merge pull request #14 from eosswedenorg/dependabot/go_modules/dev/github.com/panjf2000/gnet/v2-2.3.3
build(deps): bump github.com/panjf2000/gnet/v2 from 2.3.2 to 2.3.3
2023-09-20 14:49:54 +02:00
dependabot[bot]
828e38797a
build(deps): bump github.com/panjf2000/gnet/v2 from 2.3.2 to 2.3.3
Bumps [github.com/panjf2000/gnet/v2](https://github.com/panjf2000/gnet) from 2.3.2 to 2.3.3.
- [Release notes](https://github.com/panjf2000/gnet/releases)
- [Commits](https://github.com/panjf2000/gnet/compare/v2.3.2...v2.3.3)

---
updated-dependencies:
- dependency-name: github.com/panjf2000/gnet/v2
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-09-19 08:14:04 +00:00
8a0ab6bb7b
Merge pull request #13 from eosswedenorg/dependabot/go_modules/dev/github.com/panjf2000/gnet/v2-2.3.2
build(deps): bump github.com/panjf2000/gnet/v2 from 2.3.1 to 2.3.2
2023-09-13 04:31:24 +00:00
dependabot[bot]
65fd7cff9c
build(deps): bump github.com/panjf2000/gnet/v2 from 2.3.1 to 2.3.2
Bumps [github.com/panjf2000/gnet/v2](https://github.com/panjf2000/gnet) from 2.3.1 to 2.3.2.
- [Release notes](https://github.com/panjf2000/gnet/releases)
- [Commits](https://github.com/panjf2000/gnet/compare/v2.3.1...v2.3.2)

---
updated-dependencies:
- dependency-name: github.com/panjf2000/gnet/v2
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-09-12 08:55:43 +00:00
a024913244
Adding internal/api/make_test.go 2023-08-24 19:35:13 +02:00
b98164116e
Makefile: Indent fixes. 2023-08-15 09:46:03 +02:00
4e56ee60fc
README.md: minor fixes. 2023-08-15 09:45:42 +02:00
eaeec1645d
Version 1.4.6 2023-07-25 17:31:03 +02:00
e461d20125
Merge pull request #12 from eosswedenorg/dependabot/go_modules/dev/github.com/panjf2000/gnet/v2-2.3.1
build(deps): bump github.com/panjf2000/gnet/v2 from 2.3.0 to 2.3.1
2023-07-25 17:27:33 +02:00
dependabot[bot]
18a3a8a3d5
build(deps): bump github.com/panjf2000/gnet/v2 from 2.3.0 to 2.3.1
Bumps [github.com/panjf2000/gnet/v2](https://github.com/panjf2000/gnet) from 2.3.0 to 2.3.1.
- [Release notes](https://github.com/panjf2000/gnet/releases)
- [Commits](https://github.com/panjf2000/gnet/compare/v2.3.0...v2.3.1)

---
updated-dependencies:
- dependency-name: github.com/panjf2000/gnet/v2
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-07-25 08:19:32 +00:00
61724eb8d2
Merge pull request #11 from eosswedenorg/dependabot/go_modules/dev/github.com/panjf2000/gnet/v2-2.3.0
build(deps): bump github.com/panjf2000/gnet/v2 from 2.2.9 to 2.3.0
2023-07-05 04:49:35 +02:00
dependabot[bot]
6fe3d2572a
build(deps): bump github.com/panjf2000/gnet/v2 from 2.2.9 to 2.3.0
Bumps [github.com/panjf2000/gnet/v2](https://github.com/panjf2000/gnet) from 2.2.9 to 2.3.0.
- [Release notes](https://github.com/panjf2000/gnet/releases)
- [Commits](https://github.com/panjf2000/gnet/compare/v2.2.9...v2.3.0)

---
updated-dependencies:
- dependency-name: github.com/panjf2000/gnet/v2
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-07-04 08:20:18 +00:00
9eda495d4e
Merge pull request #10 from eosswedenorg/dependabot/go_modules/dev/github.com/stretchr/testify-1.8.4
build(deps): bump github.com/stretchr/testify from 1.8.3 to 1.8.4
2023-06-07 10:25:18 +02:00
dependabot[bot]
75b8a7bab1
build(deps): bump github.com/stretchr/testify from 1.8.3 to 1.8.4
Bumps [github.com/stretchr/testify](https://github.com/stretchr/testify) from 1.8.3 to 1.8.4.
- [Release notes](https://github.com/stretchr/testify/releases)
- [Commits](https://github.com/stretchr/testify/compare/v1.8.3...v1.8.4)

---
updated-dependencies:
- dependency-name: github.com/stretchr/testify
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-06-06 08:57:16 +00:00
3b497afd76
debian/copyright: update year 2023-05-24 13:05:55 +02:00
dd76ae2b19
Version 1.4.5 2023-05-23 17:23:25 +02:00
d253128d6d
Merge pull request #9 from eosswedenorg/dependabot/go_modules/dev/github.com/stretchr/testify-1.8.3
build(deps): bump github.com/stretchr/testify from 1.8.2 to 1.8.3
2023-05-23 16:18:25 +02:00
dependabot[bot]
2299331321
build(deps): bump github.com/stretchr/testify from 1.8.2 to 1.8.3
Bumps [github.com/stretchr/testify](https://github.com/stretchr/testify) from 1.8.2 to 1.8.3.
- [Release notes](https://github.com/stretchr/testify/releases)
- [Commits](https://github.com/stretchr/testify/compare/v1.8.2...v1.8.3)

---
updated-dependencies:
- dependency-name: github.com/stretchr/testify
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-05-23 13:47:50 +00:00
232aa7df65
Merge pull request #8 from eosswedenorg/dependabot/go_modules/dev/github.com/panjf2000/gnet/v2-2.2.9
build(deps): bump github.com/panjf2000/gnet/v2 from 2.2.7 to 2.2.9
2023-05-23 15:47:11 +02:00
dependabot[bot]
2d6e768e2a
build(deps): bump github.com/panjf2000/gnet/v2 from 2.2.7 to 2.2.9
Bumps [github.com/panjf2000/gnet/v2](https://github.com/panjf2000/gnet) from 2.2.7 to 2.2.9.
- [Release notes](https://github.com/panjf2000/gnet/releases)
- [Commits](https://github.com/panjf2000/gnet/compare/v2.2.7...v2.2.9)

---
updated-dependencies:
- dependency-name: github.com/panjf2000/gnet/v2
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-05-23 08:57:17 +00:00
80ba31050e
Merge pull request #7 from eosswedenorg/dependabot/go_modules/dev/github.com/eosswedenorg-go/atomicasset-0.1.2
build(deps): bump github.com/eosswedenorg-go/atomicasset from 0.1.1 to 0.1.2
2023-05-10 07:13:50 +02:00
dependabot[bot]
5dc14716c5
build(deps): bump github.com/eosswedenorg-go/atomicasset
Bumps [github.com/eosswedenorg-go/atomicasset](https://github.com/eosswedenorg-go/atomicasset) from 0.1.1 to 0.1.2.
- [Release notes](https://github.com/eosswedenorg-go/atomicasset/releases)
- [Commits](https://github.com/eosswedenorg-go/atomicasset/compare/v0.1.1...v0.1.2)

---
updated-dependencies:
- dependency-name: github.com/eosswedenorg-go/atomicasset
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-05-10 05:12:43 +00:00
c8dd655e36
internal/api/atomicasset_test.go: minor style fix. 2023-05-10 07:03:49 +02:00
10f3a4d4be
internal/api/atomicasset_test.go: Bugfix in calls to time.Date(), ment to pass 500 milliseconds, not microseconds. 2023-05-10 07:01:53 +02:00
995f6a8629
Merge pull request #6 from eosswedenorg/dependabot/go_modules/dev/github.com/panjf2000/gnet/v2-2.2.7
build(deps): bump github.com/panjf2000/gnet/v2 from 2.2.6 to 2.2.7
2023-04-19 08:48:54 +02:00
dependabot[bot]
c53cb4fe1f
build(deps): bump github.com/panjf2000/gnet/v2 from 2.2.6 to 2.2.7
Bumps [github.com/panjf2000/gnet/v2](https://github.com/panjf2000/gnet) from 2.2.6 to 2.2.7.
- [Release notes](https://github.com/panjf2000/gnet/releases)
- [Commits](https://github.com/panjf2000/gnet/compare/v2.2.6...v2.2.7)

---
updated-dependencies:
- dependency-name: github.com/panjf2000/gnet/v2
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-04-18 08:57:24 +00:00
824ae9ca9d
Version 1.4.4 2023-04-04 07:47:16 +02:00
f377538f4c
go.mod: Update github.com/eosswedenorg-go/atomicasset to v0.1.1 2023-04-04 06:54:35 +02:00
92e7b89f81
Merge pull request #5 from eosswedenorg/dependabot/go_modules/golang.org/x/net-0.7.0
build(deps): bump golang.org/x/net from 0.4.0 to 0.7.0
2023-04-04 06:19:18 +02:00
dependabot[bot]
320b54cce8
build(deps): bump golang.org/x/net from 0.4.0 to 0.7.0
Bumps [golang.org/x/net](https://github.com/golang/net) from 0.4.0 to 0.7.0.
- [Release notes](https://github.com/golang/net/releases)
- [Commits](https://github.com/golang/net/compare/v0.4.0...v0.7.0)

---
updated-dependencies:
- dependency-name: golang.org/x/net
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-04-04 04:13:45 +00:00
9a34d2647d
Version 1.4.3 2023-04-04 06:12:04 +02:00
37c8bbc357
.github/dependabot.yml: Set target branch to dev. 2023-04-04 06:05:55 +02:00
528461ebe4
Merge pull request #4 from eosswedenorg/dependabot/go_modules/github.com/panjf2000/gnet/v2-2.2.6
build(deps): bump github.com/panjf2000/gnet/v2 from 2.2.4 to 2.2.6
2023-04-04 06:02:12 +02:00
ad596c15ad
Merge branch 'dev' into dependabot/go_modules/github.com/panjf2000/gnet/v2-2.2.6 2023-04-04 06:01:25 +02:00
8ef31fc4e7
Merge pull request #3 from eosswedenorg/dependabot/go_modules/github.com/inconshreveable/log15-3.0.0-testing.5incompatible
build(deps): bump github.com/inconshreveable/log15 from 0.0.0-20221122034931-555555054819 to 3.0.0-testing.5+incompatible
2023-04-04 06:00:02 +02:00
b8b61d5064
Merge pull request #2 from eosswedenorg/dependabot/go_modules/github.com/stretchr/testify-1.8.2
build(deps): bump github.com/stretchr/testify from 1.8.1 to 1.8.2
2023-04-04 05:59:00 +02:00
dependabot[bot]
03ec91a675
build(deps): bump github.com/panjf2000/gnet/v2 from 2.2.4 to 2.2.6
Bumps [github.com/panjf2000/gnet/v2](https://github.com/panjf2000/gnet) from 2.2.4 to 2.2.6.
- [Release notes](https://github.com/panjf2000/gnet/releases)
- [Commits](https://github.com/panjf2000/gnet/compare/v2.2.4...v2.2.6)

---
updated-dependencies:
- dependency-name: github.com/panjf2000/gnet/v2
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-04-04 03:48:15 +00:00
dependabot[bot]
b8b44ecf24
build(deps): bump github.com/inconshreveable/log15
Bumps [github.com/inconshreveable/log15](https://github.com/inconshreveable/log15) from 0.0.0-20221122034931-555555054819 to 3.0.0-testing.5+incompatible.
- [Release notes](https://github.com/inconshreveable/log15/releases)
- [Commits](https://github.com/inconshreveable/log15/commits/v3.0.0-testing.5)

---
updated-dependencies:
- dependency-name: github.com/inconshreveable/log15
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-04-04 03:48:08 +00:00
dependabot[bot]
df0f8b0c43
build(deps): bump github.com/stretchr/testify from 1.8.1 to 1.8.2
Bumps [github.com/stretchr/testify](https://github.com/stretchr/testify) from 1.8.1 to 1.8.2.
- [Release notes](https://github.com/stretchr/testify/releases)
- [Commits](https://github.com/stretchr/testify/compare/v1.8.1...v1.8.2)

---
updated-dependencies:
- dependency-name: github.com/stretchr/testify
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-04-04 03:48:05 +00:00
7f68732eae
Adding .github/dependabot.yml 2023-04-04 05:44:06 +02:00
6b0776937a
cmd/antelope-api-healtcheck/main.go: Typo fix. 2023-02-15 18:09:20 +01:00
cf2aef149a
Version 1.4.2 2023-02-14 09:35:47 +01:00
4b15a56804
cmd/antelope-api-healtcheck/main.go: Change default timeout to 2 seconds. 2023-02-14 09:10:56 +01:00
8deb0b9bf3
scripts/install_linux.sh: Install syslog-ng config files. 2023-02-14 09:00:03 +01:00
a632ba914f
Adding scripts/templates/syslog-ng.conf 2023-02-14 08:59:32 +01:00
5bf880b0d0
cmd/antelope-api-healtcheck/main.go: exit with status 1 if srv.Run() fails. 2023-02-07 16:42:00 +01:00
318d14f44b
Makefile: use $GO variable when setting GOOS and GOARCH 2023-02-07 16:29:31 +01:00
9814f07612
Version 1.4.0 2023-02-07 12:36:45 +01:00
9b28e45295
cmd/antelope-v1-mock-server/main.go: adding -d flag for random delays. 2023-02-07 12:32:43 +01:00
228d7ae731
cmd/antelope-api-healtcheck/main.go: req_timeout.Minutes() returns a float, so must check for greater than 1.0 instead of 0. 2023-02-07 12:25:03 +01:00
adf9508197
cmd/antelope-api-healtcheck/main.go: srv.Run() does not only return error on server shutdown. so modify the message. 2023-02-07 09:23:37 +01:00
550cabc64b
cmd/antelope-api-healtcheck/main.go: adding -t,--timeout cli flag. 2023-02-07 09:22:15 +01:00
d73187ec38
internal/server/server.go: Make context timeout configurable. 2023-02-07 09:21:10 +01:00
6030981ba5
internal/server/server.go: Implement options using the functional pattern. 2023-02-07 09:11:17 +01:00
6b561bdf25
internal/api/atomicasset_test.go: Add LogInfoWithHost test 2023-02-07 08:43:29 +01:00
0448ea4781
internal/api/atomicasset.go: In LogInfo() add host parameter. 2023-02-07 08:43:02 +01:00
afd79110f9
internal/server/parse_request_test.go: Adding AtomicAssetWithHost test. 2023-02-07 08:38:51 +01:00
59399c7cf4
internal/api/atomicasset.go: Support host parameter. 2023-02-07 08:38:21 +01:00
f0ab79ef06
internal/api/atomicasset.go: Pass context to atomicasset api. 2023-02-07 08:32:44 +01:00
919599f86d
go mod: Update github.com/eosswedenorg-go/atomicasset to v0.1.1-0.20230206134606-4577244fa67a 2023-02-06 19:02:53 +01:00
d67864dadf
go.mod: Update github.com/eosswedenorg-go/leapapi to v0.2.3 2023-02-06 16:31:44 +01:00
dbf59d1305
internal/api/interface.go: make Call() accept a context as parameter. 2023-02-06 14:21:29 +01:00
b815bcee44
internal/server/server.go: Adding request duration to log row. 2023-02-06 14:15:06 +01:00
12bd16399b
internal/server/server.go: Adding OnClose() 2023-02-06 12:52:13 +01:00
83fd4826d7
internal/server/server.go: need to provide a callback to AsyncWrite to close the connection. 2023-02-06 12:45:50 +01:00
5ed22bfdc6
Makefile add build/antelope-v1-mock-server to .PHONY target 2023-02-06 10:01:11 +01:00
df1476355f
cmd/antelope-api-healtcheck/main.go: Comment fix. 2023-02-02 18:55:39 +01:00
4cdae2d3f1
internal/api/debug.go: no need to return error in parseResponse() as it is always nil. 2023-02-02 18:52:36 +01:00
aff3737f67
internal/server/parse_request.go: remove weird comment 2023-02-02 18:51:44 +01:00
9456b8acbb
cmd/antelope-api-healtcheck/main.go: in signalEventLoop() no need to wrap the for loop in a anonymous function. 2023-02-02 18:19:53 +01:00
fba9402584
cmd/antelope-api-healtcheck/main.go: Minor fix. 2023-02-02 18:18:49 +01:00
755438408b
go.mod: Update github.com/panjf2000/gnet/v2 to v2.2.4 2023-01-19 13:01:13 +01:00
a811f82028
go.mod: update github.com/eosswedenorg-go/gnet/v2@v2.2.2-kqueue-fix to github.com/panjf2000/gnet/v2@v2.2.3-0.20230105151625-72b6e726ce32
This commit fixes the kqueue 32-bit bug in upstream.
2023-01-19 12:56:29 +01:00
46fe9b3e47
.github/workflows/test.yml: Also cross-compile to make sure it builds on everything. 2023-01-05 14:29:32 +01:00
b9b1e71bcd
go mod: replace github.com/panjf2000/gnet/v2 v2.2.2 with github.com/eosswedenorg-go/gnet/v2 v2.2.2-kqueue-fix
There is a bug in panjf2000/gnet currently that affects compilation on BSD 32-bit systems. Its temporary fixes in eosswedenorg-go/gnet fork.
2023-01-05 14:26:43 +01:00
1f6811c3b6
.github/workflows/release.yml: Adding fail-fast: false to strategy. 2023-01-05 13:02:31 +01:00
852a17bf9e
.github/workflows/release.yml: Setup go v1.18 2023-01-05 12:48:32 +01:00
32178dd47f
.github/workflows/test.yml: Update actions/checkout and actions/setup-go to v3. 2023-01-05 12:46:45 +01:00
dcf035ec6c
.github/workflows/release.yml: Update actions/checkout to v3 2023-01-05 12:46:15 +01:00
29ed2d790b
Version 1.4.0 2023-01-04 14:09:06 +01:00
62d039deb2
internal/server/server.go: Make OnTick() interval configurable. 2023-01-04 14:02:43 +01:00
a73f1eae8b
internal/server/server.go: Some documentation. 2023-01-04 13:55:07 +01:00
1f22435dfa
internal/server/server.go: count number of connections and send a log message in OnTick() 2023-01-04 13:53:29 +01:00
1db04c0e76
replace github.com/eosswedenorg-go/tcp_server with github.com/panjf2000/gnet 2023-01-03 17:45:56 +01:00
be7a246317
Makefile: adding "test-utils" target. 2023-01-02 19:12:56 +01:00
d365b5deb1
Adding cmd/antelope-v1-mock-server/main.go 2023-01-02 19:12:33 +01:00
a6b0575cf7
LICENSE: Update copyright year. 2023-01-02 12:56:04 +01:00
28d4ab3437
go.mod: Update github.com/eosswedenorg-go/leapapi to v0.2.2 2023-01-02 12:55:33 +01:00
d752839f0b
go.sum: cleanup old packages. 2023-01-02 12:54:09 +01:00
86e87d8245
internal/api: rename eosio_*.go to antelope_*.go 2022-12-22 14:17:22 +01:00
1fc8c927aa
go mod: Upgrade indirect packages. 2022-12-22 12:46:09 +01:00
2caad14e44
go mod: Update github.com/eosswedenorg-go/haproxy to v1.0.1 2022-12-22 12:41:26 +01:00
64d46ed460
go mod: Update github.com/eosswedenorg-go/atomicasset to v0.1.0 2022-12-22 12:04:31 +01:00
142465ac16
Version 1.3.1 2022-12-12 16:24:48 +01:00
4f77e23797
go mod: upgrade github.com/eosswedenorg-go/leapapi to v0.2.1 2022-12-12 15:06:08 +01:00
c19dc9a63b
README.md: Adding cool badges. 2022-12-09 13:08:00 +01:00
f0db33f9b1
Require a minimum go version of 1.18 2022-12-06 15:21:38 +01:00
a771b25415
Version 1.3.0 2022-11-25 12:41:31 +01:00
22b10006d7
go.sum: Remove old packages. 2022-11-25 12:39:51 +01:00
005ad9fcd0
go mod: change github.com/eosswedenorg-go/eosapi v0.1.3 to github.com/eosswedenorg-go/leapapi v0.2.0 2022-11-25 12:39:51 +01:00
61cb49f8be
Rename project from eosio-api-healthcheck to antelope-api-healthcheck 2022-11-25 12:39:51 +01:00
e0a7a10662
README.md: Update documentation to reflect the name change from contract to atomic. 2022-11-25 10:24:43 +01:00
881e7cd760
internal/server/parse_request_test.go: Remove out commented import. 2022-11-24 15:06:58 +01:00
9109bef803
internal/api/make.go: remove "contract" api in favor for the new "atomic" name. 2022-11-24 15:06:02 +01:00
0f5fdedd91
Version 1.2.6 2022-11-24 15:04:10 +01:00
c89da02738
Cleanup test names. 2022-11-24 14:56:22 +01:00
d2b8e7d0dc
internal/api/eosio_v2_test.go: Assert any errors from http.ResponseWriter.Write() 2022-11-24 14:51:17 +01:00
bcd9a93a35
internal/api/eosio_v1_test.go: Assert any errors from http.ResponseWriter.Write() 2022-11-24 14:51:17 +01:00
c48162742f
internal/api/atomicasset_test.go: Assert any errors from http.ResponseWriter.Write() 2022-11-24 14:45:46 +01:00
a768d89909
cmd/eosio-api-healtcheck/main.go: store server object returned from server.Start() and call Close() after event loop. 2022-11-24 14:39:03 +01:00
2daa5801c1
internal/server/server.go: Make Start() return an tcp_server.Server object. 2022-11-24 14:37:57 +01:00
34814dae05
go: upgrade github.com/eosswedenorg-go/tcp_server to v0.2.1 2022-11-24 14:37:10 +01:00
72bdde0457
internal/server/server.go: in Start() no need to spawn server.Listen() in a go routine as that function is already non-blocking. 2022-11-23 17:22:44 +01:00
8feca959d4
internal/server/parse_request.go: move api factory code into its own function in api package: api.Make() 2022-11-23 17:14:51 +01:00
1fb48800a1
internal/server/parse_request.go: Add AtomicAsset in factories with "atomic" as key. 2022-11-23 17:07:39 +01:00
2b0b32b5ab
rename EosioContract to AtomicAsset. 2022-11-23 17:04:54 +01:00
1b1f601678
move internal/*.go files into internal/server 2022-11-23 16:54:22 +01:00
e9976fbbee
Change github.com/eosswedenorg-go/eos-contract-api-client to github.com/eosswedenorg-go/atomicasset 2022-11-23 16:04:23 +01:00
bcc704c4c0
internal/server.go: in onTcpMessage() check error return value of c.WriteString() 2022-11-23 15:56:59 +01:00
adb1ad3c6d
Fix code formatting 2022-11-23 15:53:26 +01:00
b0e5b455ca
go: update github.com/inconshreveable/log15 to v0.0.0-20221122034931-555555054819 2022-11-22 10:10:00 +01:00
b09e5ba463
go: update github.com/eosswedenorg-go/eosapi to v0.1.3 2022-11-22 10:08:47 +01:00
a17e2929e3
internal/api/eosio_v1.go: HTTP Errors are now handled in eosapi. This changes the log message abit and return haproxy status from "Down" to "Fail" 2022-11-18 15:40:55 +01:00
9102240837
internal/api/eosio_v2.go: HTTP Errors are now handled in the eosapi. This changes the log message abit and return haproxy status from "Down" to "Fail" 2022-11-18 15:40:55 +01:00
0b463e5111
go.mod: Update github.com/eosswedenorg-go/eosapi to v0.1.2 2022-11-18 15:37:41 +01:00
d8d872adae
go.mod: update github.com/stretchr/testify to v1.8.1 2022-10-27 12:58:56 +02:00
6448aeb0f7
Refactor: move internal package from src/ to internal/ and move src/main.go to cmd/eosio-api-healthcheck/main.go 2022-10-27 12:58:30 +02:00
c27abb5ed9
.gitignore: ignore .vscode directory 2022-10-26 14:27:17 +02:00
cb8eec6ff6
Merge branch 'api-refactor' into dev 2022-10-26 10:31:42 +02:00
c168e263df
src/server.go: in onTcpMessage() cleanup logging calls using api.LogParams Add and Combine functions. 2022-10-26 10:29:25 +02:00
15ff583035
src/parse_request.go: in ParseRequest() change switch case into a map with factory functions. 2022-10-25 17:49:22 +02:00
b41fb21f6a
src/parse_request.go: use api.ApiArguments instead of arguments struct 2022-10-25 17:46:32 +02:00
d8c8c14edc
src/api/eosio_contract.go: Adding EosioContractFactory function 2022-10-25 17:43:16 +02:00
9fcffe375a
src/api/eosio_v2.go: Adding EosioV2Factory function 2022-10-25 17:42:46 +02:00
7b78d2632b
src/api/eosio_v1.go: Adding EosioV1Factory function 2022-10-25 17:42:30 +02:00
39927a2441
src/api/debug.go: Adding DebugApiFactory function 2022-10-25 17:31:36 +02:00
6e8ffe718e
src/api/interface.go: Adding Factory function type. 2022-10-25 17:22:33 +02:00
0081f86f0d
src/api/interface.go: Adding ApiArguments struct. 2022-10-25 17:21:56 +02:00
8079962be8
src/api/log_params.go: Adding Combine() 2022-10-21 15:08:33 +02:00
8d2c1c8fa3
src/api/log_params.go: Don't need a ToSlice() function as LogParams is already a slice. 2022-10-21 15:08:00 +02:00
3ab2db7cb3
src/api/log_params_test.go: change assert.Equal() to assert.ElementsMatch() to ignore slice order. 2022-10-21 14:29:02 +02:00
60 changed files with 2234 additions and 1831 deletions

View file

@ -7,13 +7,19 @@ on:
jobs: jobs:
cross-compile: cross-compile:
strategy: strategy:
fail-fast: false
matrix: matrix:
os: [ linux, freebsd ] os: [ linux, freebsd ]
arch: [ 386, amd64, arm, arm64 ] arch: [ 386, amd64, arm, arm64 ]
name: Crosscompile - ${{matrix.os}}-${{matrix.arch}} name: Crosscompile - ${{matrix.os}}-${{matrix.arch}}
runs-on: ubuntu-20.04 runs-on: ubuntu-20.04
steps: steps:
- uses: actions/checkout@v1 - uses: actions/checkout@v3
- name: Set up Go
uses: actions/setup-go@v3
with:
go-version: 1.18
- name: compile - name: compile
id: compile id: compile
@ -37,12 +43,18 @@ jobs:
package-ubuntu: package-ubuntu:
strategy: strategy:
fail-fast: false
matrix: matrix:
os: [ ubuntu-20.04 ] os: [ ubuntu-20.04 ]
name: Package - ${{matrix.os}} name: Package - ${{matrix.os}}
runs-on: ${{matrix.os}} runs-on: ${{matrix.os}}
steps: steps:
- uses: actions/checkout@v1 - uses: actions/checkout@v3
- name: Set up Go
uses: actions/setup-go@v3
with:
go-version: 1.18
- name: Install build dependencies - name: Install build dependencies
run: | run: |
@ -95,12 +107,18 @@ jobs:
package-freebsd: package-freebsd:
strategy: strategy:
fail-fast: false
matrix: matrix:
arch: [ 386, amd64, arm, arm64 ] arch: [ 386, amd64, arm, arm64 ]
name: Package - FreeBSD (${{matrix.arch}}) name: Package - FreeBSD (${{matrix.arch}})
runs-on: ubuntu-20.04 runs-on: ubuntu-20.04
steps: steps:
- uses: actions/checkout@v1 - uses: actions/checkout@v3
- name: Set up Go
uses: actions/setup-go@v3
with:
go-version: 1.18
- name: Package - name: Package
id: package id: package

View file

@ -5,16 +5,36 @@ on:
- pull_request - pull_request
jobs: jobs:
cross-compile:
strategy:
fail-fast: false
matrix:
os: [ linux, freebsd ]
arch: [ 386, amd64, arm, arm64 ]
name: Crosscompile - ${{matrix.os}}-${{matrix.arch}}
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: Set up Go
uses: actions/setup-go@v3
with:
go-version: 1.18
- name: compile
id: compile
run: |
./compile.sh --target ${{matrix.os}} -a ${{matrix.arch}}
test: test:
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- uses: actions/checkout@v2 - uses: actions/checkout@v3
- name: Set up Go - name: Set up Go
uses: actions/setup-go@v2 uses: actions/setup-go@v3
with: with:
go-version: 1.16 go-version: 1.18
- name: Test - name: Test
run: go test -v ./... run: go test -v ./...

1
.gitignore vendored
View file

@ -1,2 +1,3 @@
*.swp *.swp
.vscode/
build/ build/

View file

@ -1,6 +1,6 @@
MIT License MIT License
Copyright (c) 2020-2022 Sw/eden Copyright (c) 2020-2023 Sw/eden
Permission is hereby granted, free of charge, to any person obtaining a copy Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal of this software and associated documentation files (the "Software"), to deal

View file

@ -1,24 +1,27 @@
PROGRAM_NAME = eosio-api-healthcheck PROGRAM_NAME = antelope-api-healthcheck
export PROGRAM_VERSION = 1.2.5 export PROGRAM_VERSION = 1.4.6
GO = go GO = go
PREFIX = /usr/local PREFIX = /usr/local
export GOOS = $(shell go env GOOS) export GOOS = $(shell $(GO) env GOOS)
export GOARCH = $(shell go env GOARCH) export GOARCH = $(shell $(GO) env GOARCH)
GOBUILDFLAGS = -v -ldflags='-v -s -w -X main.VersionString=$(PROGRAM_VERSION)' GOBUILDFLAGS = -v -ldflags='-v -s -w -X main.VersionString=$(PROGRAM_VERSION)'
DPKG_BUILDPACKAGE = dpkg-buildpackage DPKG_BUILDPACKAGE = dpkg-buildpackage
DPKG_BUILDPACKAGE_FLAGS = -b -uc DPKG_BUILDPACKAGE_FLAGS = -b -uc
SOURCES=src/main.go src/server.go src/parse_request.go .PHONY: all build/$(PROGRAM_NAME) build/antelope-v1-mock-server clean package_debian
.PHONY: all build/$(PROGRAM_NAME) clean package_debian
all: build all: build
build: build/$(PROGRAM_NAME) build: build/$(PROGRAM_NAME)
build/$(PROGRAM_NAME) : $(SOURCES) build/$(PROGRAM_NAME) : $(SOURCES)
$(GO) build -o $@ $(GOBUILDFLAGS) $^ $(GO) build -o $@ $(GOBUILDFLAGS) cmd/antelope-api-healtcheck/main.go
build/antelope-v1-mock-server:
$(GO) build -o $@ $(GOBUILDFLAGS) cmd/antelope-v1-mock-server/main.go
test-utils: build/antelope-v1-mock-server
test: test:
$(GO) test -v ./... $(GO) test -v ./...

View file

@ -1,15 +1,18 @@
# EOSIO API Healthcheck for HAProxy # Antelope API Healthcheck for HAProxy
This program implements EOSIO healthcheck for HAProxy over TCP. [![Test](https://github.com/eosswedenorg/antelope-api-healthcheck/actions/workflows/test.yml/badge.svg)](https://github.com/eosswedenorg/antelope-api-healthcheck/actions/workflows/test.yml)
[![Report](https://goreportcard.com/badge/github.com/eosswedenorg/antelope-api-healthcheck)](https://goreportcard.com/report/github.com/eosswedenorg/antelope-api-healthcheck)
This program implements Antelope healthcheck for HAProxy over TCP.
## Compiling ## Compiling
You will need go-lang version `1.16` or later to compile the source. You will need golang version `1.16` or later to compile the source.
compile with `compile.sh` script compile with `compile.sh` script
```sh ```sh
$ ./compile.sh ./compile.sh
``` ```
Execute `./compile.sh --help` to see all available flags to crosscompile for different systems/architectures. Execute `./compile.sh --help` to see all available flags to crosscompile for different systems/architectures.
@ -27,15 +30,14 @@ The protocol is simple and has 4 rules.
3. Each parameter inside a `Request` is separated by `|` 3. Each parameter inside a `Request` is separated by `|`
4. Each response contains exactly one `status code` (see below) 4. Each response contains exactly one `status code` (see below)
### Request ### Request
The following parameters are supported in a request and are ordered from The following parameters are supported in a request and are ordered from
first to last below: first to last below:
| # | Name | Required | Description | | # | Name | Required | Description |
| - | ---------- | ----------------------- | ----------------------------------------------------------------------------------------------- | | - | ---------- | ------------------------- | -------------------------------------------------------------------------------------------- |
| 1 | api | Yes | Type of API to check against, `v1` = standard, `v2` = Hyperion, `contract` = eosio-contract-api | | 1 | api | Yes | Type of API to check against,`v1` = standard, `v2` = Hyperion, `atomic` = atomicassets |
| 2 | url | Yes (port default `80`) | http url to the api.`http(s)://<ip-or-domain>(:<port>)` | | 2 | url | Yes (port default `80`) | http url to the api.`http(s)://<ip-or-domain>(:<port>)` |
| 3 | num_blocks | No (default `10`) | Number of blocks the api can drift before reported `down` | | 3 | num_blocks | No (default `10`) | Number of blocks the api can drift before reported `down` |
| 4 | host | No (default from `url`) | Value to send in the `HTTP Host Header` to the API | | 4 | host | No (default from `url`) | Value to send in the `HTTP Host Header` to the API |
@ -46,7 +48,7 @@ The api can respond with exactly one `status code`.
See [HAproxy documentation](https://cbonte.github.io/haproxy-dconv/1.7/configuration.html#5.2-agent-check) for more information See [HAproxy documentation](https://cbonte.github.io/haproxy-dconv/1.7/configuration.html#5.2-agent-check) for more information
| code | Description | | code | Description |
| --------- | ---------------------------------------------------------- | | ----------- | ------------------------------------------------------------ |
| `up` | Api is healthy | | `up` | Api is healthy |
| `down` | Api is not healthy | | `down` | Api is not healthy |
| `fail` | The program failed to read the status from the api. | | `fail` | The program failed to read the status from the api. |

View file

@ -0,0 +1,208 @@
package main
import (
"fmt"
"os"
"os/signal"
"syscall"
"time"
"github.com/eosswedenorg-go/pid"
"github.com/eosswedenorg/antelope-api-healthcheck/internal/server"
"github.com/eosswedenorg/antelope-api-healthcheck/internal/utils"
log "github.com/inconshreveable/log15"
"github.com/pborman/getopt/v2"
)
// Command line flags
// ---------------------------------------------------------
var (
logFile string
pidFile string
)
// Global variables
// ---------------------------------------------------------
// Version string, should be updated by the go linker (by passing "-X main.VersionString=value" to the linker)
// see: https://pkg.go.dev/cmd/link
var VersionString string = "-"
// File descriptor to the current log file.
var logfd *os.File
var (
logfmt log.Format
logger log.Logger
// TCP Server
srv *server.Server
)
// argv_listen_addr
// Parse listen address from command line.
//
// ---------------------------------------------------------
func argv_listen_addr() string {
var addr string
argv := getopt.Args()
if len(argv) > 0 {
addr = argv[0]
} else {
addr = "127.0.0.1"
}
addr += ":"
if len(argv) > 1 {
addr += argv[1]
} else {
addr += "1337"
}
return addr
}
func setLogFile() {
// Open file
fd, err := os.OpenFile(logFile, os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0o644)
if err != nil {
logger.Error(err.Error())
}
// Try close if old descriptor is defined.
if logfd != nil {
if err = logfd.Close(); err != nil {
logger.Error(err.Error())
}
}
// Update variable and set log writer.
logfd = fd
logger.SetHandler(log.StreamHandler(logfd, logfmt))
}
// signalEventLoop()
// Initialize event channel for OS signals
// and runs an event loop.
//
// ---------------------------------------------------------
func signalEventLoop() {
// Setup a channel
sig_ch := make(chan os.Signal, 1)
// subscribe to SIGHUP signal.
signal.Notify(sig_ch, syscall.SIGHUP, syscall.SIGINT, syscall.SIGTERM)
// Event loop
var run bool = true
for run {
// Block until we get a signal.
sig := <-sig_ch
l := logger.New("signal", sig)
switch sig {
case syscall.SIGINT, syscall.SIGTERM:
l.Info("Program was asked to terminate.")
run = false
// Tell the server to close.
err := srv.Close()
if err != nil {
l.Error("Failed to close server", "error", err)
}
// SIGHUP is sent when logfile is rotated.
case syscall.SIGHUP:
msg := "Logfile was rotated: "
if logfd != nil {
setLogFile()
msg += "Filedescriptor was updated"
} else {
msg += "No Filedescriptor to update (most likely uses standard out/err streams)"
}
l.Info(msg)
default:
l.Warn("Unknown signal")
}
}
}
// main
//
// ---------------------------------------------------------
func main() {
var version bool
var usage bool
var logFormatter *string
// Set default timeout to 2 sec
// as haproxy "inter" parameter to healthcheck is set to 2s per default.
req_timeout := time.Second * 2
logger = log.Root()
// Command line parsing
getopt.SetParameters("[ip] [port]")
getopt.FlagLong(&usage, "help", 'h', "Print this help text")
getopt.FlagLong(&version, "version", 'v', "Print version")
getopt.FlagLong(&logFile, "log", 'l', "Path to log file", "file")
getopt.FlagLong(&pidFile, "pid", 'p', "Path to pid file", "file")
getopt.FlagLong(&req_timeout, "timeout", 't', "Set the maximum time before a request times out, valid prefixes are 's','ms','us'", "duration")
logFormatter = getopt.EnumLong("log-format", 0, []string{"term", "logfmt", "json", "json-pretty"}, "", "Log format to use: term,logfmt,json,json-pretty")
getopt.Parse()
if usage {
getopt.Usage()
return
}
if version {
fmt.Printf("Version: %s\n", VersionString)
return
}
logfmt = utils.ParseLogFormatter(*logFormatter)
// Open logfile.
if len(logFile) > 0 {
setLogFile()
} else {
logger.SetHandler(log.StreamHandler(os.Stdout, logfmt))
}
logger.Info("Process is starting", "pid", pid.Get())
if len(pidFile) > 0 {
logger.Info("Writing pidfile", "file", pidFile)
err := pid.Save(pidFile)
if err != nil {
logger.Error("Failed to write pidfile", "msg", err)
}
}
if req_timeout.Seconds() < 2 {
// Dont alow anything below 2 seconds. that is abit aggressive.
logger.Warn("Request timeout is less than the minimum. Setting it to 2 seconds", "req_timeout", req_timeout)
req_timeout = time.Second * 2
} else if req_timeout.Minutes() > 1.0 {
// Anything more than 1 min is too long :)
logger.Warn("Request timeout is more than the maximum. Setting it to 1 minute", "req_timeout", req_timeout)
req_timeout = time.Minute
}
// Create server
srv = server.New(argv_listen_addr(), server.WithTick(time.Second*10), server.WithTimeout(req_timeout))
// Run signal event loop in its own goroutine
go signalEventLoop()
// Run server
if err := srv.Run(); err != nil {
logger.Error("Server error", "error", err)
os.Exit(1)
}
}

View file

@ -0,0 +1,78 @@
package main
import (
"flag"
"fmt"
"math/rand"
"net/http"
"os"
"time"
"github.com/eosswedenorg-go/leapapi"
)
var (
listen_host = flag.String("h,host", "localhost", "Host to listen on.")
listen_port = flag.Int("p", 3333, "Port to listen to.")
delay = flag.Int("d", 0, "Delays responses randomly between 0 and int seconds.")
)
func getInfo(w http.ResponseWriter, r *http.Request) {
current_time := time.Now()
info := leapapi.Info{
ServerVersion: "c83ea9c2",
ServerVersionString: "0.0.0-debug",
ServerFullVersionString: "0.0.0-debug-c83ea9c21f60670a00627319ebbd233e6bb4f84904dbcfc894242ba38b2761d4",
HeadBlockNum: 1000,
HeadBlockID: "168d2cf232ca78e94d57a86301e35f110b6016358e05d49ab822df0a8aa988ea",
HeadBlockTime: current_time.UTC(),
ChainID: "1045fa26e1c5be590ae6114e73331152671f13c87eee60a2171387dcbc44da88",
HeadBlockProducer: "debugproducer",
LastIrreversableBlockNum: 900,
LastIrreversableBlockID: "5149254b9b6fd61a02403ebe3b45ade57642ed473295f33e2184e56966370a1f",
LastIrreversableBlockTime: current_time.Add(time.Second * -5).UTC(),
VirtualBlockCPULimit: 4000,
VirtualBlockNETLimit: 5000,
BlockCPULimit: 8000,
BlockNETLimit: 2000,
TotalCPUWeight: 60488453825414473,
TotalNETWeight: 101764028077814346,
ForkDBHeadBlockID: "7544799d7c2f511368cb94adc65223e1e2cc4cf9639ba07eef2421486a8dbfe5",
ForkDBHeadBlockNum: 100,
}
if *delay > 0 {
sleep_for := rand.Intn(*delay)
time.Sleep(time.Second * time.Duration(sleep_for))
}
payload, err := leapapi.Json().Marshal(&info)
if err != nil {
fmt.Fprintln(os.Stderr, err)
return
}
w.Header().Add("Content-Type", "application/json")
_, err = w.Write(payload)
if err != nil {
fmt.Fprintln(os.Stderr, err)
}
}
func main() {
rand.Seed(time.Now().Unix())
flag.Parse()
http.HandleFunc("/v1/chain/get_info", getInfo)
addr := fmt.Sprintf("%s:%d", *listen_host, *listen_port)
fmt.Println("Listening on:", addr)
err := http.ListenAndServe(addr, nil)
if err != nil {
panic(err)
}
}

148
debian/changelog vendored
View file

@ -1,3 +1,151 @@
antelope-api-healthcheck (1.4.6) unstable; urgency=medium
* Go Packages
- Update github.com/panjf2000/gnet/v2 from 2.2.9 to 2.3.1
- Update github.com/stretchr/testify from 1.8.3 to 1.8.4
-- Henrik Hautakoski <henrik@eossweden.org> Tue, 25 Jul 2023 17:28:29 +0200
antelope-api-healthcheck (1.4.5) unstable; urgency=medium
Maintenance release, dependancies updates.
* Go Packages
- Update github.com/panjf2000/gnet/v2 from 2.2.6 to 2.2.9
- Update github.com/stretchr/testify from 1.8.2 to 1.8.3
-- Henrik Hautakoski <henrik@eossweden.org> Tue, 23 May 2023 17:19:42 +0200
antelope-api-healthcheck (1.4.4) unstable; urgency=medium
[ Security ]
* CVE-2022-41723 - Uncontrolled Resource Consumption
Fixed by updating golang.org/x/net to patched version 0.7.0
[ Misc ]
* Go Packages
- Update golang.org/x/net from 0.4.0 to 0.7.0
- Update github.com/eosswedenorg-go/atomicasset from v0.1.1-0.20230206134606-4577244fa67a to v0.1.1
-- Henrik Hautakoski <henrik@eossweden.org> Tue, 04 Apr 2023 07:04:24 +0200
antelope-api-healthcheck (1.4.3) unstable; urgency=medium
[ Misc ]
* Typo fix.
* Go Packages
- github.com/stretchr/testify from 1.8.1 to 1.8.2
- github.com/inconshreveable/log15 from 0.0.0-20221122034931-555555054819 to 3.0.0-testing.5+incompatible
- github.com/panjf2000/gnet/v2 from 2.2.4 to 2.2.6
-- Henrik Hautakoski <henrik@eossweden.org> Tue, 04 Apr 2023 06:07:05 +0200
antelope-api-healthcheck (1.4.2) unstable; urgency=medium
[ Improvements ]
* API Check
- Default value for api timeout changed from 30s to 2s.
This makes sense because haproxy "inter" parameter is set to 2s per default.
* Linux install script
- Now installs `syslog-ng` configuration file.
* Misc
- Program now exits with correct status code "1" when an error occures.
-- Henrik Hautakoski <henrik@eossweden.org> Tue, 14 Feb 2023 09:11:43 +0100
antelope-api-healthcheck (1.4.1) unstable; urgency=medium
[ Bugfixes ]
* Fixing a bug where TCP connections were not closed after response was written.
[ Improvements ]
* API Check
- timeouts can now be configurable.
- "duration" and "duration_us" fields added to log row, these
values represents the api check duration.
* CLI
- new parameter `-t`, `--timeout` that specify the maximum duration of api checks.
[ Misc ]
* Go Packages
- Update github.com/panjf2000/gnet/v2 to v2.2.4
- Update github.com/eosswedenorg-go/leapapi to v0.2.3
- Update github.com/eosswedenorg-go/atomicassets to v0.1.1-0.20230206134606-4577244fa67a
-- Henrik Hautakoski <henrik@eossweden.org> Tue, 07 Feb 2023 09:29:40 +0100
antelope-api-healthcheck (1.4.0) unstable; urgency=medium
* Using github.com/panjf2000/gnet as tcp server library instead of github.com/eosswedenorg-go/tcp_server
[ Misc ]
* Go Packages
- Update github.com/eosswedenorg-go/haproxy to v1.0.1
- Update github.com/eosswedenorg-go/atomicasset to v0.1.0
-- Henrik Hautakoski <henrik@eossweden.org> Wed, 04 Jan 2023 14:03:41 +0100
antelope-api-healthcheck (1.3.1) unstable; urgency=medium
* Upgraded to github.com/eosswedenorg-go/leapapi@v0.2.1
That contains a bugfix for HTTP Host Header being sent without port.
This caused some antelope api's with `http-validate-host` enabled
to respond with `400 Bad Request` as the header and url did not match.
-- Henrik Hautakoski <henrik@eossweden.org> Mon, 12 Dec 2022 16:19:26 +0100
antelope-api-healthcheck (1.3.0) unstable; urgency=medium
Project and binary renamed from eosio-api-healthcheck to antelope-api-healthcheck
[ BREAKING Change: Config files ]
* Debian /etc/sysconfig/eosio-api-healthcheck
- File renamed to /etc/sysconfig/antelope-api-healthcheck
- EOSIO_API_HEALTCHECK_OPTS changed to ANTELOPE_API_HEALTCHECK_OPTS
* FreeBSD /etc/rc.conf
- eosio_api_healthcheck_args changed to antelope_api_healthcheck_args
- eosio_api_healthcheck_logfile changed to antelope_api_healthcheck_logfile
[ BREAKING Change: API ]
* Requests using "contract" as api is invalid from
this release and should use "atomic" instead.
For example: "contract|https://api.domain.com" should be changed to "atomic|https://api.domain.com"
[ Misc ]
* Go Packages
- Upgrade github.com/eosswedenorg-go/eosapi to github.com/eosswedenorg-go/leapapi v0.2.0
-- Henrik Hautakoski <henrik@eossweden.org> Fri, 25 Nov 2022 12:40:02 +0100
eosio-api-healthcheck (1.2.6) unstable; urgency=medium
* Go Packages
- Upgrade github.com/stretchr/testify to v1.8.1
- Upgrade github.com/eosswedenorg-go/eosapi to v0.1.3
- Upgrade github.com/inconshreveable/log15 to v0.0.0-20221122034931-555555054819
- Upgrade github.com/eosswedenorg-go/tcp_server to v0.2.1
* Eosio v1/v2 API's
- HTTP Errors are now handled by `eosapi`
This changes the log message abit and will report "Fail" instead of "Down" to haproxy.
-- Henrik Hautakoski <henrik@eossweden.org> Thu, 24 Nov 2022 14:57:00 +0100
eosio-api-healthcheck (1.2.5) unstable; urgency=medium eosio-api-healthcheck (1.2.5) unstable; urgency=medium
* Logging * Logging

14
debian/control vendored
View file

@ -1,19 +1,19 @@
Source: eosio-api-healthcheck Source: antelope-api-healthcheck
Section: introspection Section: introspection
Build-Depends: Build-Depends:
debhelper (>= 11) debhelper (>= 11)
Standards-Version: 4.5.0 Standards-Version: 4.5.0
Vcs-Git: https://github.com/eosswedenorg/eos-api-healthcheck.git Vcs-Git: https://github.com/eosswedenorg/antelope-api-healthcheck.git
Vcs-Browser: https://github.com/eosswedenorg/eos-api-healthcheck Vcs-Browser: https://github.com/eosswedenorg/antelope-api-healthcheck
Priority: optional Priority: optional
Maintainer: Henrik Hautakoski <henrik@eossweden.org> Maintainer: Henrik Hautakoski <henrik@eossweden.org>
Package: eosio-api-healthcheck Package: antelope-api-healthcheck
Section: introspection Section: introspection
Priority: optional Priority: optional
Architecture: amd64 Architecture: amd64
Depends: ${shlibs:Depends}, ${misc:Depends} Depends: ${shlibs:Depends}, ${misc:Depends}
Homepage: https://github.com/eosswedenorg/eos-api-healthcheck Homepage: https://github.com/eosswedenorg/antelope-api-healthcheck
Description: HAproxy healthcheck program for EOSIO API. Description: HAproxy healthcheck program for Leap API.
This package provides all the files needed to This package provides all the files needed to
run the eos-api-healthcheck TCP Server run the antelope-api-healthcheck TCP Server

6
debian/copyright vendored
View file

@ -1,10 +1,10 @@
Format: https://www.debian.org/doc/packaging-manuals/copyright-format/1.0/ Format: https://www.debian.org/doc/packaging-manuals/copyright-format/1.0/
Upstream-Name: eosio-api-healthcheck Upstream-Name: antelope-api-healthcheck
Upstream-Contact: Henrik Hautakoski <henrik@eossweden.org> Upstream-Contact: Henrik Hautakoski <henrik@eossweden.org>
Source: https://github.com/eosswedenorg/eos-api-healthcheck.git Source: https://github.com/eosswedenorg/antelope-api-healthcheck.git
Files: * Files: *
Copyright: 2020-2022 Sw/eden Copyright: 2020-2023 Sw/eden
License: MIT License: MIT
License: MIT License: MIT

63
go.mod
View file

@ -1,16 +1,59 @@
module github.com/eosswedenorg/eosio-api-healthcheck module github.com/eosswedenorg/antelope-api-healthcheck
go 1.16 go 1.18
require ( require (
github.com/eosswedenorg-go/eos-contract-api-client v0.0.0-20221012162219-7bf5d16d1d5f github.com/eosswedenorg-go/atomicasset v0.1.2
github.com/eosswedenorg-go/eosapi v0.1.1 github.com/eosswedenorg-go/haproxy v1.0.1
github.com/eosswedenorg-go/haproxy v0.1.1 github.com/eosswedenorg-go/leapapi v0.2.3
github.com/eosswedenorg-go/pid v1.0.1 github.com/eosswedenorg-go/pid v1.0.1
github.com/eosswedenorg-go/tcp_server v0.2.0 github.com/inconshreveable/log15 v3.0.0-testing.5+incompatible
github.com/go-stack/stack v1.8.1 // indirect github.com/panjf2000/gnet/v2 v2.3.1
github.com/inconshreveable/log15 v0.0.0-20201112154412-8562bdadbbac
github.com/mattn/go-colorable v0.1.13 // indirect
github.com/pborman/getopt/v2 v2.1.0 github.com/pborman/getopt/v2 v2.1.0
github.com/stretchr/testify v1.8.0 github.com/stretchr/testify v1.8.4
)
require (
github.com/davecgh/go-spew v1.1.1 // indirect
github.com/eosswedenorg-go/unixtime v0.1.1 // indirect
github.com/go-stack/stack v1.8.1 // indirect
github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0 // indirect
github.com/golang/mock v1.6.0 // indirect
github.com/google/go-cmp v0.5.9 // indirect
github.com/google/pprof v0.0.0-20221219190121-3cb0bae90811 // indirect
github.com/hashicorp/errwrap v1.1.0 // indirect
github.com/hashicorp/go-multierror v1.1.1 // indirect
github.com/imroc/req/v3 v3.33.2 // indirect
github.com/json-iterator/go v1.1.12 // indirect
github.com/liamylian/jsontime/v2 v2.0.0 // indirect
github.com/mattn/go-colorable v0.1.13 // indirect
github.com/mattn/go-isatty v0.0.16 // indirect
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
github.com/modern-go/reflect2 v1.0.2 // indirect
github.com/onsi/ginkgo/v2 v2.6.1 // indirect
github.com/pkg/errors v0.9.1 // indirect
github.com/pmezard/go-difflib v1.0.0 // indirect
github.com/quic-go/qpack v0.4.0 // indirect
github.com/quic-go/qtls-go1-18 v0.2.0 // indirect
github.com/quic-go/qtls-go1-19 v0.2.0 // indirect
github.com/quic-go/qtls-go1-20 v0.1.0 // indirect
github.com/quic-go/quic-go v0.32.0 // indirect
github.com/rogpeppe/go-internal v1.10.0 // indirect
github.com/sonh/qs v0.6.2 // indirect
github.com/valyala/bytebufferpool v1.0.0 // indirect
go.uber.org/atomic v1.10.0 // indirect
go.uber.org/multierr v1.8.0 // indirect
go.uber.org/zap v1.21.0 // indirect
golang.org/x/crypto v0.21.0 // indirect
golang.org/x/exp v0.0.0-20221217163422-3c43f8badb15 // indirect
golang.org/x/mod v0.8.0 // indirect
golang.org/x/net v0.23.0 // indirect
golang.org/x/sync v0.2.0 // indirect
golang.org/x/sys v0.18.0 // indirect
golang.org/x/term v0.18.0 // indirect
golang.org/x/text v0.14.0 // indirect
golang.org/x/tools v0.6.0 // indirect
gopkg.in/guregu/null.v4 v4.0.0 // indirect
gopkg.in/natefinch/lumberjack.v2 v2.2.1 // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect
) )

362
go.sum
View file

@ -1,358 +1,170 @@
cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= github.com/benbjohnson/clock v1.1.0 h1:Q92kusRqC1XV2MjkWETPvjJVqKetz1OzxZB7mHJLju8=
cloud.google.com/go v0.31.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= github.com/benbjohnson/clock v1.1.0/go.mod h1:J11/hYXuz8f4ySSvYwY0FKfm+ezbsZBKZxNJlLklBHA=
cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
cloud.google.com/go v0.37.0/go.mod h1:TS1dMSSfndXH133OKGwekG838Om/cQT0BUHV3HcBgoo=
dmitri.shuralyov.com/app/changes v0.0.0-20180602232624-0a106ad413e3/go.mod h1:Yl+fi1br7+Rr3LqpNJf1/uxUdtRUV+Tnj0o93V2B9MU=
dmitri.shuralyov.com/html/belt v0.0.0-20180602232347-f7d459c86be0/go.mod h1:JLBrvjyP0v+ecvNYvCpyZgu5/xkfAUhi6wJj28eUfSU=
dmitri.shuralyov.com/service/change v0.0.0-20181023043359-a85b471d5412/go.mod h1:a1inKt/atXimZ4Mv927x+r7UpyzRUf4emIoiiSC2TN4=
dmitri.shuralyov.com/state v0.0.0-20180228185332-28bcc343414c/go.mod h1:0PRwlb0D6DFvNNtx+9ybjezNCa8XF0xaYcETyp6rHWU=
git.apache.org/thrift.git v0.0.0-20180902110319-2566ecd5d999/go.mod h1:fPE2ZNJGynbRyZ4dJvy6G277gSllfV2HJqblrnkyeyg=
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
github.com/anmitsu/go-shlex v0.0.0-20161002113705-648efa622239/go.mod h1:2FmKhYUyUczH0OGQWaF5ceTx0UBShxjsH6f8oGKYe2c=
github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q=
github.com/bradfitz/go-smtpd v0.0.0-20170404230938-deb6d6237625/go.mod h1:HYsPBTaaSFSlLx/70C2HPIMNZpVV8+vt/A+FMnYP11g=
github.com/buger/jsonparser v0.0.0-20181115193947-bf1c66bbce23/go.mod h1:bbYlZJ7hK1yFx9hf58LP0zeX7UjIGs20ufpu3evjr+s=
github.com/cheekybits/genny v1.0.0 h1:uGGa4nei+j20rOSeDeP5Of12XVm7TGUd4dJA9RDitfE=
github.com/cheekybits/genny v1.0.0/go.mod h1:+tQajlRqAUrPI7DOSpB0XAqZYtQakVtB7wXkRAgjxjQ=
github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=
github.com/coreos/go-systemd v0.0.0-20181012123002-c6f51f82210d/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/dustin/go-humanize v1.0.0/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk= github.com/eosswedenorg-go/atomicasset v0.1.2 h1:bvz5tVVyP8EHSQo9CPFZjdl1lICBisfoRwJv/SURMCs=
github.com/eosswedenorg-go/eos-contract-api-client v0.0.0-20221012162219-7bf5d16d1d5f h1:28cfafllXW0tPZM+8xkwUlpMD5E+4+JLjZ2gNltVtf4= github.com/eosswedenorg-go/atomicasset v0.1.2/go.mod h1:iRs02PLQmJAFBlukjrReSwti+Ga2Rp2wtnBGQElMVg4=
github.com/eosswedenorg-go/eos-contract-api-client v0.0.0-20221012162219-7bf5d16d1d5f/go.mod h1:5MKXTTcCZ3ZPmPAfOKwgVKA5S9BUltN8hY0/U2HqdDE= github.com/eosswedenorg-go/haproxy v1.0.1 h1:N9tyQSvEDG9Fq+gBP0b7A8R5iZAqYCms2K6Nvqq8TfE=
github.com/eosswedenorg-go/eosapi v0.1.1 h1:+7DpTz6om3Xluj0ssY0LU5Tj6WKicV9Zlgr8Cso0dlw= github.com/eosswedenorg-go/haproxy v1.0.1/go.mod h1:rBXDRd72ifA/IvsZUpW8Q4gR5rbV/4DAuKC/lqDrwWQ=
github.com/eosswedenorg-go/eosapi v0.1.1/go.mod h1:5r8ukl/BXbjeydPQNG/eE3+idpuY6XR654nyfcqkZbg= github.com/eosswedenorg-go/leapapi v0.2.3 h1:2qGlP8wzZJCvjM9ol9t2uroCPMpV+wxF7lNl2NdG87M=
github.com/eosswedenorg-go/haproxy v0.1.1 h1:ClOhoK3uGn70KzGCKHdYNvHoU72whfNq3LbqT/lWlOY= github.com/eosswedenorg-go/leapapi v0.2.3/go.mod h1:hyfjHswFjcnWMqOb+cYvTrT6l34S80GrFvfOdcYugnM=
github.com/eosswedenorg-go/haproxy v0.1.1/go.mod h1:WnDKkwYbgrpuKUOtUtWlGCgj43DMV+r4VKGdWSTYQeA=
github.com/eosswedenorg-go/pid v1.0.1 h1:W4AEnnNwb041SpNR1uTZ/KbJ0OTA5eqiqIR1Q5Ah6A0= github.com/eosswedenorg-go/pid v1.0.1 h1:W4AEnnNwb041SpNR1uTZ/KbJ0OTA5eqiqIR1Q5Ah6A0=
github.com/eosswedenorg-go/pid v1.0.1/go.mod h1:wiOB/JXGt4YA3+T0j0xmCGSc3Jxzb7Ti/Ftli1fgWu4= github.com/eosswedenorg-go/pid v1.0.1/go.mod h1:wiOB/JXGt4YA3+T0j0xmCGSc3Jxzb7Ti/Ftli1fgWu4=
github.com/eosswedenorg-go/tcp_server v0.1.1 h1:jNTThJKL+5dbPBGFCAIXQRoKx9YQer3yFp4unF0+iU8= github.com/eosswedenorg-go/unixtime v0.1.1 h1:fTNxDtQOKncv/zAc3TzwLQLA/YBVM5nlbsFWVEyMkds=
github.com/eosswedenorg-go/tcp_server v0.1.1/go.mod h1:JvArWV6imAGj+NkrMJWSWTTe2a+WzqfWZUcZTH9y/+0= github.com/eosswedenorg-go/unixtime v0.1.1/go.mod h1:knU247oYvgCQD9MLYBdpi7qD1pTRgkSAWr9jbUx3S6c=
github.com/eosswedenorg-go/tcp_server v0.2.0 h1:0EHNmdrOGgYuDE+yT6N1xDdZ1Amc18w6tczDnaHdJL8= github.com/go-logr/logr v1.2.3 h1:2DntVwHkVopvECVRSlL5PSo9eG+cAkDCuckLubN+rq0=
github.com/eosswedenorg-go/tcp_server v0.2.0/go.mod h1:3+3QlVIS8UY6eGDP78lg2km6/XFEk/JLbwOr5MfwW/g=
github.com/flynn/go-shlex v0.0.0-20150515145356-3f9db97f8568/go.mod h1:xEzjJPgXI435gkrCt3MPfRiAkVrwSbHsst4LCFVfpJc=
github.com/francoispqt/gojay v1.2.13/go.mod h1:ehT5mTG4ua4581f1++1WLG0vPdaA9HaiDsoyrBGkyDY=
github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ=
github.com/fsnotify/fsnotify v1.5.4 h1:jRbGcIw6P2Meqdwuo0H1p6JVLbL5DHKAKlYndzMwVZI=
github.com/fsnotify/fsnotify v1.5.4/go.mod h1:OVB6XrOHzAwXMpEM7uPOzcehqUV2UqJxmVXmkdnm1bU=
github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04=
github.com/gliderlabs/ssh v0.1.1/go.mod h1:U7qILu1NlMHj9FlMhZLlkCdDnU1DBEAqr0aevW3Awn0=
github.com/go-errors/errors v1.0.1/go.mod h1:f4zRHt4oKfwPJE5k8C9vpYG+aDHdBFUsgrm6/TyX73Q=
github.com/go-stack/stack v1.8.1 h1:ntEHSVwIt7PNXNpgPmVfMrNhLtgjlmnZha2kOpuRiDw= github.com/go-stack/stack v1.8.1 h1:ntEHSVwIt7PNXNpgPmVfMrNhLtgjlmnZha2kOpuRiDw=
github.com/go-stack/stack v1.8.1/go.mod h1:dcoOX6HbPZSZptuspn9bctJ+N/CnF5gGygcUP3XYfe4= github.com/go-stack/stack v1.8.1/go.mod h1:dcoOX6HbPZSZptuspn9bctJ+N/CnF5gGygcUP3XYfe4=
github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0 h1:p104kn46Q8WdvHunIJ9dAyjPVtrBPhSr3KT2yUst43I= github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0 h1:p104kn46Q8WdvHunIJ9dAyjPVtrBPhSr3KT2yUst43I=
github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0/go.mod h1:fyg7847qk6SyHyPtNmDHnmrv/HOrqktSC+C9fM+CJOE= github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0/go.mod h1:fyg7847qk6SyHyPtNmDHnmrv/HOrqktSC+C9fM+CJOE=
github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ=
github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q=
github.com/golang/lint v0.0.0-20180702182130-06c8688daad7/go.mod h1:tluoj9z5200jBnyusfRPU2LqT6J+DAorxEvtC7LHB+E=
github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
github.com/golang/mock v1.2.0/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
github.com/golang/mock v1.4.4/go.mod h1:l3mdAwkq5BuhzHwde/uurv3sEJeZMXNpwsxVWU71h+4=
github.com/golang/mock v1.6.0 h1:ErTB+efbowRARo13NNdxyJji2egdxLGQhRaY+DUumQc= github.com/golang/mock v1.6.0 h1:ErTB+efbowRARo13NNdxyJji2egdxLGQhRaY+DUumQc=
github.com/golang/mock v1.6.0/go.mod h1:p6yTPP+5HYm5mzsMV8JkE6ZKdX+/wYM6Hr+LicevLPs= github.com/golang/mock v1.6.0/go.mod h1:p6yTPP+5HYm5mzsMV8JkE6ZKdX+/wYM6Hr+LicevLPs=
github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8=
github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA=
github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs=
github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w=
github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0=
github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI=
github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk=
github.com/golang/protobuf v1.5.2 h1:ROPKBNFfQgOUMifHyP+KYbvpjbdoFNs+aK7DXlji0Tw= github.com/golang/protobuf v1.5.2 h1:ROPKBNFfQgOUMifHyP+KYbvpjbdoFNs+aK7DXlji0Tw=
github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38=
github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M=
github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-github v17.0.0+incompatible/go.mod h1:zLgOLi98H3fifZn+44m+umXrS52loVEgC2AApnigrVQ=
github.com/google/go-querystring v1.0.0/go.mod h1:odCYkC5MyYFN7vkCjXpyrEuKhc/BUO6wN/zVPAxq5ck=
github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs= github.com/google/pprof v0.0.0-20221219190121-3cb0bae90811 h1:wORs2YN3R3ona/CXYuTvLM31QlgoNKHvlCNuArCDDCU=
github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= github.com/google/pprof v0.0.0-20221219190121-3cb0bae90811/go.mod h1:dDKJzRmX4S37WGHujM7tX//fmj1uioxKzKxz3lo4HJo=
github.com/googleapis/gax-go v2.0.0+incompatible/go.mod h1:SFVmujtThgffbyetf+mdk2eWhX2bMyUtNHzFKcPA9HY=
github.com/googleapis/gax-go/v2 v2.0.3/go.mod h1:LLvjysVCY1JZeum8Z6l8qUty8fiNwE08qbEPm1M08qg=
github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY=
github.com/gregjones/httpcache v0.0.0-20180305231024-9cad4c3443a7/go.mod h1:FecbI9+v66THATjSRHfNgh1IVFe/9kFxbXtjV0ctIMA=
github.com/grpc-ecosystem/grpc-gateway v1.5.0/go.mod h1:RSKVYQBd5MCa4OVpNdGskqpgL2+G+NZTnrVHpWWfpdw=
github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4=
github.com/hashicorp/errwrap v1.1.0 h1:OxrOeh75EUXMY8TBjag2fzXGZ40LB6IKw45YeGUDY2I= github.com/hashicorp/errwrap v1.1.0 h1:OxrOeh75EUXMY8TBjag2fzXGZ40LB6IKw45YeGUDY2I=
github.com/hashicorp/errwrap v1.1.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= github.com/hashicorp/errwrap v1.1.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4=
github.com/hashicorp/go-multierror v1.1.1 h1:H5DkEtf6CXdFp0N0Em5UCwQpXMWke8IA0+lD48awMYo= github.com/hashicorp/go-multierror v1.1.1 h1:H5DkEtf6CXdFp0N0Em5UCwQpXMWke8IA0+lD48awMYo=
github.com/hashicorp/go-multierror v1.1.1/go.mod h1:iw975J/qwKPdAO1clOe2L8331t/9/fmwbPZ6JB6eMoM= github.com/hashicorp/go-multierror v1.1.1/go.mod h1:iw975J/qwKPdAO1clOe2L8331t/9/fmwbPZ6JB6eMoM=
github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU=
github.com/imroc/req/v3 v3.7.6/go.mod h1:3JIicOKEDHfCSYYNLb/ObZNpx64EV5y40VlHMwhUCzU= github.com/imroc/req/v3 v3.7.6/go.mod h1:3JIicOKEDHfCSYYNLb/ObZNpx64EV5y40VlHMwhUCzU=
github.com/imroc/req/v3 v3.24.1 h1:tT5MrwwgDQTUAWZqhPnxbsnaPMThCPGqcjiBwmZJJO4= github.com/imroc/req/v3 v3.33.2 h1:mqphLIo++p+IPYdjgP/Wd5rqXUjKvuEIst2U+EsLIwQ=
github.com/imroc/req/v3 v3.24.1/go.mod h1:EluRnkfh8A39BmrCARYhcUrfGyR8qPw+O0BZyTy4j9k= github.com/imroc/req/v3 v3.33.2/go.mod h1:cZ+7C3L/AYOr4tLGG16hZF90F1WzAdAdzt1xFSlizXY=
github.com/inconshreveable/log15 v0.0.0-20201112154412-8562bdadbbac h1:n1DqxAo4oWPMvH1+v+DLYlMCecgumhhgnxAPdqDIFHI= github.com/inconshreveable/log15 v3.0.0-testing.5+incompatible h1:VryeOTiaZfAzwx8xBcID1KlJCeoWSIpsNbSk+/D2LNk=
github.com/inconshreveable/log15 v0.0.0-20201112154412-8562bdadbbac/go.mod h1:cOaXtrgN4ScfRrD9Bre7U1thNq5RtJ8ZoP4iXVGRj6o= github.com/inconshreveable/log15 v3.0.0-testing.5+incompatible/go.mod h1:cOaXtrgN4ScfRrD9Bre7U1thNq5RtJ8ZoP4iXVGRj6o=
github.com/jellevandenhooff/dkim v0.0.0-20150330215556-f50fe3d243e1/go.mod h1:E0B/fFc00Y+Rasa88328GlI/XbtyysCtTHZS8h7IrBU=
github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU=
github.com/json-iterator/go v1.1.9 h1:9yzud/Ht36ygwatGx56VwCZtlI/2AD15T1X2sjSuGns=
github.com/json-iterator/go v1.1.9/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= github.com/json-iterator/go v1.1.9/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU= github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM=
github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo=
github.com/kr/pretty v0.1.0 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI=
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE=
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
github.com/kr/pty v1.1.3/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE= github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE=
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
github.com/liamylian/jsontime/v2 v2.0.0 h1:3if2kDW/boymUdO+4Qj/m4uaXMBSF6np9KEgg90cwH0= github.com/liamylian/jsontime/v2 v2.0.0 h1:3if2kDW/boymUdO+4Qj/m4uaXMBSF6np9KEgg90cwH0=
github.com/liamylian/jsontime/v2 v2.0.0/go.mod h1:UHp1oAPqCBfspokvGmaGe0IAl2IgOpgOgDaKPcvcGGY= github.com/liamylian/jsontime/v2 v2.0.0/go.mod h1:UHp1oAPqCBfspokvGmaGe0IAl2IgOpgOgDaKPcvcGGY=
github.com/lucas-clemente/quic-go v0.28.1 h1:Uo0lvVxWg5la9gflIF9lwa39ONq85Xq2D91YNEIslzU=
github.com/lucas-clemente/quic-go v0.28.1/go.mod h1:oGz5DKK41cJt5+773+BSO9BXDsREY4HLf7+0odGAPO0=
github.com/lunixbochs/vtclean v1.0.0/go.mod h1:pHhQNgMf3btfWnGBVipUOjRYhoOsdGqdm/+2c2E2WMI=
github.com/mailru/easyjson v0.0.0-20190312143242-1de009706dbe/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc=
github.com/marten-seemann/qpack v0.2.1 h1:jvTsT/HpCn2UZJdP+UUB53FfUUgeOyG5K1ns0OJOGVs=
github.com/marten-seemann/qpack v0.2.1/go.mod h1:F7Gl5L1jIgN1D11ucXefiuJS9UMVP2opoCp2jDKb7wc=
github.com/marten-seemann/qtls-go1-16 v0.1.5 h1:o9JrYPPco/Nukd/HpOHMHZoBDXQqoNtUCmny98/1uqQ=
github.com/marten-seemann/qtls-go1-16 v0.1.5/go.mod h1:gNpI2Ol+lRS3WwSOtIUUtRwZEQMXjYK+dQSBFbethAk=
github.com/marten-seemann/qtls-go1-17 v0.1.2 h1:JADBlm0LYiVbuSySCHeY863dNkcpMmDR7s0bLKJeYlQ=
github.com/marten-seemann/qtls-go1-17 v0.1.2/go.mod h1:C2ekUKcDdz9SDWxec1N/MvcXBpaX9l3Nx67XaR84L5s=
github.com/marten-seemann/qtls-go1-18 v0.1.2 h1:JH6jmzbduz0ITVQ7ShevK10Av5+jBEKAHMntXmIV7kM=
github.com/marten-seemann/qtls-go1-18 v0.1.2/go.mod h1:mJttiymBAByA49mhlNZZGrH5u1uXYZJ+RW28Py7f4m4=
github.com/marten-seemann/qtls-go1-19 v0.1.0-beta.1 h1:7m/WlWcSROrcK5NxuXaxYD32BZqe/LEEnBrWcH/cOqQ=
github.com/marten-seemann/qtls-go1-19 v0.1.0-beta.1/go.mod h1:5HTDWtVudo/WFsHKRNuOhWlbdjrfs5JHrYb0wIJqGpI=
github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA= github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA=
github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg= github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg=
github.com/mattn/go-isatty v0.0.16 h1:bq3VjFmv/sOjHtdEhmkEV4x1AJtvUvOJ2PFAZ5+peKQ= github.com/mattn/go-isatty v0.0.16 h1:bq3VjFmv/sOjHtdEhmkEV4x1AJtvUvOJ2PFAZ5+peKQ=
github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM=
github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0=
github.com/microcosm-cc/bluemonday v1.0.1/go.mod h1:hsXNsILzKxV+sX77C5b8FSuKF00vh2OMYv+xgHpAMF4=
github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg= github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg=
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
github.com/modern-go/reflect2 v1.0.1 h1:9f412s+6RmYXLWZSEzVVgPGK7C2PphHj5RJrvfx9AWI=
github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
github.com/neelance/astrewrite v0.0.0-20160511093645-99348263ae86/go.mod h1:kHJEU3ofeGjhHklVoIGuVj85JJwZ6kWPaJwCIxgnFmo= github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9Gz0M=
github.com/neelance/sourcemap v0.0.0-20151028013722-8c68805598ab/go.mod h1:Qr6/a/Q4r9LP1IltGz7tA7iOK1WonHEYhu1HRBA7ZiM= github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk=
github.com/nxadm/tail v1.4.4/go.mod h1:kenIhsEOeOJmVchQTgglprH7qJGnHDVpk1VPCcaMI8A= github.com/onsi/ginkgo/v2 v2.6.1 h1:1xQPCjcqYw/J5LchOcp4/2q/jzJFjiAOc25chhnDw+Q=
github.com/nxadm/tail v1.4.8 h1:nPr65rt6Y5JFSKQO7qToXr7pePgD6Gwiw05lkbyAQTE= github.com/onsi/ginkgo/v2 v2.6.1/go.mod h1:yjiuMwPokqY1XauOgju45q3sJt6VzQ/Fict1LFVcsAo=
github.com/nxadm/tail v1.4.8/go.mod h1:+ncqLTQzXmGhMZNUePPaPqPvBxHAIsmXswZKocGu+AU= github.com/onsi/gomega v1.24.1 h1:KORJXNNTzJXzu4ScJWssJfJMnJ+2QJqhoQSRwNlze9E=
github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= github.com/panjf2000/ants/v2 v2.8.1 h1:C+n/f++aiW8kHCExKlpX6X+okmxKXP7DWLutxuAPuwQ=
github.com/onsi/ginkgo v1.12.1/go.mod h1:zj2OWP4+oCPe1qIXoGWkgMRwljMUYCdkwsT2108oapk= github.com/panjf2000/gnet/v2 v2.3.1 h1:J7vHkNxwsevVIw3u/6LCXgcnpGBk5iKqhQ2RMblGodc=
github.com/onsi/ginkgo v1.14.0/go.mod h1:iSB4RoI2tjJc9BBv4NKIKWKya62Rps+oPG/Lv9klQyY= github.com/panjf2000/gnet/v2 v2.3.1/go.mod h1:Ik5lTy2nmBg9Uvjfcf2KRYs+EXVNOLyxPHpFOFlqu+M=
github.com/onsi/ginkgo v1.16.2/go.mod h1:CObGmKUOKaSC0RjmoAK7tKyn4Azo5P2IWuoMnvwxz1E=
github.com/onsi/ginkgo v1.16.4/go.mod h1:dX+/inL/fNMqNlz0e9LfyB9TswhZpCVdJM/Z6Vvnwo0=
github.com/onsi/ginkgo v1.16.5 h1:8xi0RTUf59SOSfEtZMvwTvXYMzG4gV23XVHOZiXNtnE=
github.com/onsi/ginkgo v1.16.5/go.mod h1:+E8gABHa3K6zRBolWtd+ROzc/U5bkGt0FwiG042wbpU=
github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7JYyY=
github.com/onsi/gomega v1.10.1/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1ybHNo=
github.com/onsi/gomega v1.13.0 h1:7lLHu94wT9Ij0o6EWWclhu0aOh32VxhkwEJvzuWPeak=
github.com/onsi/gomega v1.13.0/go.mod h1:lRk9szgn8TxENtWd0Tp4c3wjlRfMTMH27I+3Je41yGY=
github.com/openzipkin/zipkin-go v0.1.1/go.mod h1:NtoC/o8u3JlF1lSlyPNswIbeQH9bJTmOf0Erfk+hxe8=
github.com/pborman/getopt/v2 v2.1.0 h1:eNfR+r+dWLdWmV8g5OlpyrTYHkhVNxHBdN2cCrJmOEA= github.com/pborman/getopt/v2 v2.1.0 h1:eNfR+r+dWLdWmV8g5OlpyrTYHkhVNxHBdN2cCrJmOEA=
github.com/pborman/getopt/v2 v2.1.0/go.mod h1:4NtW75ny4eBw9fO1bhtNdYTlZKYX5/tBLtsOpwKIKd0= github.com/pborman/getopt/v2 v2.1.0/go.mod h1:4NtW75ny4eBw9fO1bhtNdYTlZKYX5/tBLtsOpwKIKd0=
github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/prometheus/client_golang v0.8.0/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw= github.com/quic-go/qpack v0.4.0 h1:Cr9BXA1sQS2SmDUWjSofMPNKmvF6IiIfDRmgU0w1ZCo=
github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= github.com/quic-go/qpack v0.4.0/go.mod h1:UZVnYIfi5GRk+zI9UMaCPsmZ2xKJP7XBUvVyT1Knj9A=
github.com/prometheus/common v0.0.0-20180801064454-c7de2306084e/go.mod h1:daVV7qP5qjZbuso7PdcryaAu0sAZbrN9i7WWcTMWvro= github.com/quic-go/qtls-go1-18 v0.2.0 h1:5ViXqBZ90wpUcZS0ge79rf029yx0dYB0McyPJwqqj7U=
github.com/prometheus/procfs v0.0.0-20180725123919-05ee40e3a273/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= github.com/quic-go/qtls-go1-18 v0.2.0/go.mod h1:moGulGHK7o6O8lSPSZNoOwcLvJKJ85vVNc7oJFD65bc=
github.com/russross/blackfriday v1.5.2/go.mod h1:JO/DiYxRf+HjHt06OyowR9PTA263kcR/rfWxYHBV53g= github.com/quic-go/qtls-go1-19 v0.2.0 h1:Cvn2WdhyViFUHoOqK52i51k4nDX8EwIh5VJiVM4nttk=
github.com/sergi/go-diff v1.0.0/go.mod h1:0CfEIISq7TuYL3j771MWULgwwjU+GofnZX9QAmXWZgo= github.com/quic-go/qtls-go1-19 v0.2.0/go.mod h1:ySOI96ew8lnoKPtSqx2BlI5wCpUVPT05RMAlajtnyOI=
github.com/shurcooL/component v0.0.0-20170202220835-f88ec8f54cc4/go.mod h1:XhFIlyj5a1fBNx5aJTbKoIq0mNaPvOagO+HjB3EtxrY= github.com/quic-go/qtls-go1-20 v0.1.0 h1:d1PK3ErFy9t7zxKsG3NXBJXZjp/kMLoIb3y/kV54oAI=
github.com/shurcooL/events v0.0.0-20181021180414-410e4ca65f48/go.mod h1:5u70Mqkb5O5cxEA8nxTsgrgLehJeAw6Oc4Ab1c/P1HM= github.com/quic-go/qtls-go1-20 v0.1.0/go.mod h1:JKtK6mjbAVcUTN/9jZpvLbGxvdWIKS8uT7EiStoU1SM=
github.com/shurcooL/github_flavored_markdown v0.0.0-20181002035957-2122de532470/go.mod h1:2dOwnU2uBioM+SGy2aZoq1f/Sd1l9OkAeAUvjSyvgU0= github.com/quic-go/quic-go v0.32.0 h1:lY02md31s1JgPiiyfqJijpu/UX/Iun304FI3yUqX7tA=
github.com/shurcooL/go v0.0.0-20180423040247-9e1955d9fb6e/go.mod h1:TDJrrUr11Vxrven61rcy3hJMUqaf/CLWYhHNPmT14Lk= github.com/quic-go/quic-go v0.32.0/go.mod h1:/fCsKANhQIeD5l76c2JFU+07gVE3KaA0FP+0zMWwfwo=
github.com/shurcooL/go-goon v0.0.0-20170922171312-37c2f522c041/go.mod h1:N5mDOmsrJOB+vfqUK+7DmDyjhSLIIBnXo9lvZJj3MWQ= github.com/rogpeppe/go-internal v1.10.0 h1:TMyTOH3F/DB16zRVcYyreMH6GnZZrwQVAoYjRBZyWFQ=
github.com/shurcooL/gofontwoff v0.0.0-20180329035133-29b52fc0a18d/go.mod h1:05UtEgK5zq39gLST6uB0cf3NEHjETfB4Fgr3Gx5R9Vw= github.com/rogpeppe/go-internal v1.10.0/go.mod h1:UQnix2H7Ngw/k4C5ijL5+65zddjncjaFoBhdsK/akog=
github.com/shurcooL/gopherjslib v0.0.0-20160914041154-feb6d3990c2c/go.mod h1:8d3azKNyqcHP1GaQE/c6dDgjkgSx2BZ4IoEi4F1reUI= github.com/sonh/qs v0.6.2 h1:ao0XNj2hXNdLW9Xk0L8zzEj1s3DjI7bDdG5QU8WUyxY=
github.com/shurcooL/highlight_diff v0.0.0-20170515013008-09bb4053de1b/go.mod h1:ZpfEhSmds4ytuByIcDnOLkTHGUI6KNqRNPDLHDk+mUU= github.com/sonh/qs v0.6.2/go.mod h1:ywKyX7vSo9R5dfgEQSCZ75tFzNkVUJZyK3/W6qGeHMQ=
github.com/shurcooL/highlight_go v0.0.0-20181028180052-98c3abbbae20/go.mod h1:UDKB5a1T23gOMUJrI+uSuH0VRDStOiUVSjBTRDVBVag=
github.com/shurcooL/home v0.0.0-20181020052607-80b7ffcb30f9/go.mod h1:+rgNQw2P9ARFAs37qieuu7ohDNQ3gds9msbT2yn85sg=
github.com/shurcooL/htmlg v0.0.0-20170918183704-d01228ac9e50/go.mod h1:zPn1wHpTIePGnXSHpsVPWEktKXHr6+SS6x/IKRb7cpw=
github.com/shurcooL/httperror v0.0.0-20170206035902-86b7830d14cc/go.mod h1:aYMfkZ6DWSJPJ6c4Wwz3QtW22G7mf/PEgaB9k/ik5+Y=
github.com/shurcooL/httpfs v0.0.0-20171119174359-809beceb2371/go.mod h1:ZY1cvUeJuFPAdZ/B6v7RHavJWZn2YPVFQ1OSXhCGOkg=
github.com/shurcooL/httpgzip v0.0.0-20180522190206-b1c53ac65af9/go.mod h1:919LwcH0M7/W4fcZ0/jy0qGght1GIhqyS/EgWGH2j5Q=
github.com/shurcooL/issues v0.0.0-20181008053335-6292fdc1e191/go.mod h1:e2qWDig5bLteJ4fwvDAc2NHzqFEthkqn7aOZAOpj+PQ=
github.com/shurcooL/issuesapp v0.0.0-20180602232740-048589ce2241/go.mod h1:NPpHK2TI7iSaM0buivtFUc9offApnI0Alt/K8hcHy0I=
github.com/shurcooL/notifications v0.0.0-20181007000457-627ab5aea122/go.mod h1:b5uSkrEVM1jQUspwbixRBhaIjIzL2xazXp6kntxYle0=
github.com/shurcooL/octicon v0.0.0-20181028054416-fa4f57f9efb2/go.mod h1:eWdoE5JD4R5UVWDucdOPg1g2fqQRq78IQa9zlOV1vpQ=
github.com/shurcooL/reactions v0.0.0-20181006231557-f2e0b4ca5b82/go.mod h1:TCR1lToEk4d2s07G3XGfz2QrgHXg4RJBvjrOozvoWfk=
github.com/shurcooL/sanitized_anchor_name v0.0.0-20170918181015-86672fcb3f95/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc=
github.com/shurcooL/users v0.0.0-20180125191416-49c67e49c537/go.mod h1:QJTqeLYEDaXHZDBsXlPCDqdhQuJkuw4NOtaxYe3xii4=
github.com/shurcooL/webdavfs v0.0.0-20170829043945-18c3829fa133/go.mod h1:hKmq5kWdCj2z2KEozexVbfEZIWiTjhE0+UjmZgPqehw=
github.com/sourcegraph/annotate v0.0.0-20160123013949-f4cad6c6324d/go.mod h1:UdhH50NIW0fCiwBSr0co2m7BnFLdv4fQTgdqdJTHFeE=
github.com/sourcegraph/syntaxhighlight v0.0.0-20170531221838-bd320f5d308e/go.mod h1:HuIsMU8RRBOtsCgI77wP899iHVBQpCmg4ErYMZB+2IA=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA= github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA=
github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk=
github.com/stretchr/testify v1.8.0 h1:pSgiaMZlXftHpm5L7V1+rVB+AZJydKsMxsQBIJw4PKk= github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo=
github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= github.com/valyala/bytebufferpool v1.0.0 h1:GqA5TC/0021Y/b9FG4Oi9Mr3q7XYx6KllzawFIhcdPw=
github.com/tarm/serial v0.0.0-20180830185346-98f6abe2eb07/go.mod h1:kDXzergiv9cbyO7IOYJZWg1U88JhDg3PB6klq9Hg2pA= github.com/valyala/bytebufferpool v1.0.0/go.mod h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyCJ6HpOuEn7z0Csc=
github.com/viant/assertly v0.4.8/go.mod h1:aGifi++jvCrUaklKEKT0BU95igDNaqkvz+49uaYMPRU=
github.com/viant/toolbox v0.24.0/go.mod h1:OxMCG57V0PXuIP2HNQrtJf2CjqdmbrOx5EkMILuUhzM=
github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k=
github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY= go.uber.org/atomic v1.7.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc=
go.opencensus.io v0.18.0/go.mod h1:vKdFvxhtzZ9onBp9VKHK8z/sRpBMnKAsufL7wlDrCOA= go.uber.org/atomic v1.10.0 h1:9qC72Qh0+3MqyJbAn8YU5xVq1frD8bn3JtD2oXtafVQ=
go4.org v0.0.0-20180809161055-417644f6feb5/go.mod h1:MkTOUMDaeVYJUOUsaDXIhWPZYa1yOyC1qaOBpL57BhE= go.uber.org/atomic v1.10.0/go.mod h1:LUxbIzbOniOlMKjJjyPfpl4v+PKK2cNJn91OQbhoJI0=
golang.org/x/build v0.0.0-20190111050920-041ab4dc3f9d/go.mod h1:OWs+y06UdEOHN4y+MfF/py+xQ/tYqIWW03b70/CG9Rw= go.uber.org/goleak v1.1.11 h1:wy28qYRKZgnJTxGxvye5/wgWr1EKjmUDGYox5mGlRlI=
golang.org/x/crypto v0.0.0-20181030102418-4d3f4d9ffa16/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= go.uber.org/goleak v1.1.11/go.mod h1:cwTWslyiVhfpKIDGSZEM2HlOvcqm+tG4zioyIeLoqMQ=
go.uber.org/multierr v1.6.0/go.mod h1:cdWPpRnG4AhwMwsgIHip0KRBQjJy5kYEpYjJxpXp9iU=
go.uber.org/multierr v1.8.0 h1:dg6GjLku4EH+249NNmoIciG9N/jURbDG+pFlTkhzIC8=
go.uber.org/multierr v1.8.0/go.mod h1:7EAYxJLBy9rStEaz58O2t4Uvip6FSURkq8/ppBp95ak=
go.uber.org/zap v1.21.0 h1:WefMeulhovoZ2sYXz7st6K0sLj7bBhpiFaud4r4zST8=
go.uber.org/zap v1.21.0/go.mod h1:wjWOCqI0f2ZZrJF/UufIOkiC8ii6tm1iqIsLo76RfJw=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/crypto v0.0.0-20190313024323-a1f597ede03a/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20200221231518-2aa609cf4a9d/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.21.0 h1:X31++rzVUdKhX5sWmSOFZxx8UW/ldWx55cbf08iNAMA=
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.21.0/go.mod h1:0BP7YvVV9gBbVKyeTG0Gyn+gZm94bibOW5BjDEYAOMs=
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= golang.org/x/exp v0.0.0-20221217163422-3c43f8badb15 h1:5oN1Pz/eDhCpbMbLstvIPa0b/BEQo6g6nwV3pLjfM6w=
golang.org/x/crypto v0.0.0-20220722155217-630584e8d5aa h1:zuSxTR4o9y82ebqCUJYNGJbGPo6sKVl54f/TVDObg1c= golang.org/x/exp v0.0.0-20221217163422-3c43f8badb15/go.mod h1:CxIveKay+FTh1D0yPZemJVgC/95VzuuOLq5Qi4xnoYc=
golang.org/x/crypto v0.0.0-20220722155217-630584e8d5aa/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
golang.org/x/lint v0.0.0-20180702182130-06c8688daad7/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU=
golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4 h1:6zppjxzCulZykYSLyVDYbneBfbaBIQPYMevg0bEwv2s= golang.org/x/mod v0.8.0 h1:LUYupSeNrTNCGzR/hVBk2NHZO4hXcVaW1k4Qx7rjPx8=
golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20181029044818-c44066c5c816/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20181106065722-10aee1819953/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20190313220215-9f648a60d977/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20200520004742-59133d7f0dd7/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
golang.org/x/net v0.0.0-20200707034311-ab3426394381/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM= golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM=
golang.org/x/net v0.0.0-20210428140749-89ef3d95e781/go.mod h1:OJAsFXCWl8Ukc7SiCT/9KSuxbyM7479/AVlXFRxuMCk=
golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
golang.org/x/net v0.0.0-20220111093109-d55c255bac03/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20220111093109-d55c255bac03/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
golang.org/x/net v0.0.0-20220624214902-1bab6f366d9e/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= golang.org/x/net v0.23.0 h1:7EYJ93RZ9vYSZAIb2x3lnuvqO5zneoD6IvWjuhfxjTs=
golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= golang.org/x/net v0.23.0/go.mod h1:JKghWKKOSdJwpW2GEx0Ja7fmaKnMsbu+MWVZTokSYmg=
golang.org/x/net v0.0.0-20220802222814-0bcc04d9c69b h1:3ogNYyK4oIQdIKzTu68hQrr4iuVxF3AxKl9Aj/eDrw0=
golang.org/x/net v0.0.0-20220802222814-0bcc04d9c69b/go.mod h1:YDH+HFinaLZZlnHAfSS6ZXJJ9M9t4Dl22yv3iI2vPwk=
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
golang.org/x/oauth2 v0.0.0-20181017192945-9dcd33a902f4/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
golang.org/x/oauth2 v0.0.0-20181203162652-d668ce993890/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
golang.org/x/perf v0.0.0-20180704124530-6e6d33e29852/go.mod h1:JLpeXjPJfIyPr5TlbXLkXWLhP8nz10XfvxElABhCtcw=
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.2.0 h1:PUR+T4wwASmuSTYdKjYHI5TD22Wy5ogLU5qZCOLxBrI=
golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sync v0.2.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20181029174526-d69651ed3497/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190316082340-a2f829d7f35f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190904154756-749cb33beabd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20191005200804-aed5e4c7ecf9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20191120155948-bd437916bb0e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200519105757-fe76b779f299/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210112080510-489259a85091/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220412211240-33da011f77ad/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220728004956-3c1f35247d10/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220731174439-a90be440212d/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab h1:2QkjZIsXupsJbJIdSjjUOgWK3aEtzyuh2mPt3l/CkeU=
golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.18.0 h1:DBdB3niSjOA/O0blCZBqDefyWNYveAYMNF1Wum0DYQ4=
golang.org/x/sys v0.18.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= golang.org/x/term v0.18.0 h1:FcHjZXDMxI8mM3nwhX9HlKop4C0YQvCVCdwYl2wOtE8=
golang.org/x/term v0.18.0/go.mod h1:ILwASektA3OnRv7amZ1xhE/KTR+u50pbXfZ03+6Nx58=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.3.7 h1:olpwvP2KacW1ZWvsR7uQhoyTYvKAupfQrRGBFM352Gk=
golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
golang.org/x/time v0.0.0-20180412165947-fbb02b2291d2/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/text v0.14.0 h1:ScX5w1eTa3QqT8oi6+ziP7dTV1S2+ALU0bI+0zXKWiQ=
golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
golang.org/x/tools v0.0.0-20180828015842-6cd1fcedba52/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20181030000716-a0a13e073c7b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY=
golang.org/x/tools v0.0.0-20190425150028-36563e24a262/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20201224043029-2b0845dc783e/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
golang.org/x/tools v0.1.1/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= golang.org/x/tools v0.1.1/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
golang.org/x/tools v0.1.12 h1:VveCTK38A2rkS8ZqFY25HIDFscX5X9OoEhJd3quQmXU= golang.org/x/tools v0.1.5/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc= golang.org/x/tools v0.6.0 h1:BOw41kyTf3PuCW1pVQf8+Cyg8pMlkYB1oo9iJ6D/lKM=
golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU=
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20220609144429-65e65417b02f/go.mod h1:K8+ghG5WaK9qNqU5K3HdILfMLy1f3aNYFI/wnl100a8= google.golang.org/protobuf v1.28.0 h1:w43yiav+6bVFTBQFZX0r7ipe9JQ1QsbMgHwbBziscLw=
google.golang.org/api v0.0.0-20180910000450-7ca32eb868bf/go.mod h1:4mhQ8q/RsB7i+udVvVy5NUi08OU8ZlA0gRVgrF7VFY0=
google.golang.org/api v0.0.0-20181030000543-1d582fd0359e/go.mod h1:4mhQ8q/RsB7i+udVvVy5NUi08OU8ZlA0gRVgrF7VFY0=
google.golang.org/api v0.1.0/go.mod h1:UGEZY7KEX120AnNLIHFMKIo4obdJhkp2tPbaPlQx13Y=
google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM=
google.golang.org/appengine v1.2.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
google.golang.org/appengine v1.3.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc=
google.golang.org/genproto v0.0.0-20180831171423-11092d34479b/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc=
google.golang.org/genproto v0.0.0-20181029155118-b69ba1387ce2/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc=
google.golang.org/genproto v0.0.0-20181202183823-bd91e49a0898/go.mod h1:7Ep/1NZk928CDR8SjdVbjWNpdIf6nzjE3BTgJDr2Atg=
google.golang.org/genproto v0.0.0-20190306203927-b5d61aea6440/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
google.golang.org/grpc v1.14.0/go.mod h1:yo6s7OP7yaDglbqo1J04qKzAhqBH6lvTonzMVmEdcZw=
google.golang.org/grpc v1.16.0/go.mod h1:0JHn/cJsOMiMfNA9+DeHDlAU7KAAB5GDlYFpa9MZMio=
google.golang.org/grpc v1.17.0/go.mod h1:6QZJwpn2B+Zp71q/5VxRsJ6NXXVCE5NRUHRo+f3cWCs=
google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=
google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8=
google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0=
google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM=
google.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miEFZTKqfCUM6K7xSMQL9OKL/b6hQv+e19PK+JZNE=
google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo=
google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw=
google.golang.org/protobuf v1.26.0 h1:bxAC2xTBsZGibn2RTntX0oH50xLsqy1OxA9tTL3p/lk=
google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 h1:qIbj1fsPNlZgppZ+VLlY7N33q108Sa+fhmuc+sWQYwY= gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 h1:qIbj1fsPNlZgppZ+VLlY7N33q108Sa+fhmuc+sWQYwY=
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys=
gopkg.in/guregu/null.v4 v4.0.0 h1:1Wm3S1WEA2I26Kq+6vcW+w0gcDo44YKYD7YIEJNHDjg= gopkg.in/guregu/null.v4 v4.0.0 h1:1Wm3S1WEA2I26Kq+6vcW+w0gcDo44YKYD7YIEJNHDjg=
gopkg.in/guregu/null.v4 v4.0.0/go.mod h1:YoQhUrADuG3i9WqesrCmpNRwm1ypAgSHYqoOcTu/JrI= gopkg.in/guregu/null.v4 v4.0.0/go.mod h1:YoQhUrADuG3i9WqesrCmpNRwm1ypAgSHYqoOcTu/JrI=
gopkg.in/inf.v0 v0.9.1/go.mod h1:cWUDdTG/fYaXco+Dcufb5Vnc6Gp2YChqWtbxRZE0mXw= gopkg.in/natefinch/lumberjack.v2 v2.2.1 h1:bBRl1b0OH9s/DuPhuXpNl+VtCaJXFZ5/uEFST95x9zc=
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ= gopkg.in/natefinch/lumberjack.v2 v2.2.1/go.mod h1:YD8tP3GAjkrDg1eZH7EGmyESg/lsYskCTPBJVb9jqSc=
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw=
gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY= gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY=
gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ=
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
grpc.go4.org v0.0.0-20170609214715-11d0a25b4919/go.mod h1:77eQGdRu53HpSqPFJFmuJdjuHRquDANNeA4x7B8WQ9o=
honnef.co/go/tools v0.0.0-20180728063816-88497007e858/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
sourcegraph.com/sourcegraph/go-diff v0.5.0/go.mod h1:kuch7UrkMzY0X+p9CRK03kfuPQ2zzQcaEFbx8wA8rck=
sourcegraph.com/sqs/pbtypes v0.0.0-20180604144634-d3ebe8f20ae4/go.mod h1:ketZ/q3QxT9HOBeFhu6RdvsftgpsbFHBF5Cas6cDKZ0=

View file

@ -0,0 +1,72 @@
package api
import (
"context"
"fmt"
"github.com/eosswedenorg-go/haproxy/agentcheck"
"github.com/eosswedenorg-go/leapapi"
"github.com/eosswedenorg/antelope-api-healthcheck/internal/utils"
)
type AntelopeV1 struct {
utils.Time
client leapapi.Client
block_time float64
}
func AntelopeV1Factory(args ApiArguments) ApiInterface {
return NewAntelopeV1(args.Url, args.Host, float64(args.NumBlocks/2))
}
func NewAntelopeV1(url string, host string, block_time float64) AntelopeV1 {
api := AntelopeV1{
client: *leapapi.New(url),
block_time: block_time,
}
api.client.Host = host
return api
}
func (e AntelopeV1) LogInfo() LogParams {
p := LogParams{
"type", "antelope-v1",
"url", e.client.Url,
}
if len(e.client.Host) > 0 {
p.Add("host", e.client.Host)
}
p.Add("block_time", e.block_time)
return p
}
func (e AntelopeV1) Call(ctx context.Context) (agentcheck.Response, string) {
info, err := e.client.GetInfo(ctx)
if err != nil {
resp := agentcheck.NewStatusMessageResponse(agentcheck.Fail, "")
return resp, err.Error()
}
// Validate head block.
diff := e.GetTime().Sub(info.HeadBlockTime).Seconds()
if diff > e.block_time {
resp := agentcheck.NewStatusMessageResponse(agentcheck.Down, "")
msg := "Taking offline because head block is lagging %.0f seconds"
return resp, fmt.Sprintf(msg, diff)
} else if diff < -e.block_time {
resp := agentcheck.NewStatusMessageResponse(agentcheck.Down, "")
msg := "Taking offline because head block is %.0f seconds into the future"
return resp, fmt.Sprintf(msg, diff)
}
return agentcheck.NewStatusResponse(agentcheck.Up), "OK"
}

View file

@ -0,0 +1,171 @@
package api
import (
"context"
"net/http"
"net/http/httptest"
"testing"
"time"
"github.com/eosswedenorg-go/haproxy/agentcheck"
"github.com/stretchr/testify/assert"
)
func TestAntelopeV1_Factory(t *testing.T) {
api := AntelopeV1Factory(ApiArguments{
Url: "https://api.v1.example.com",
Host: "host.example.com",
NumBlocks: 120,
})
expected := NewAntelopeV1("https://api.v1.example.com", "host.example.com", 60)
assert.IsType(t, expected, api)
assert.Equal(t, expected.client.Url, api.(AntelopeV1).client.Url)
assert.Equal(t, expected.client.Host, api.(AntelopeV1).client.Host)
assert.Equal(t, expected.block_time, api.(AntelopeV1).block_time)
}
func TestAntelopeV1_LogInfo(t *testing.T) {
api := NewAntelopeV1("https://api.v1.example.com", "host.example.com", 120)
expected := LogParams{"type", "antelope-v1", "url", "https://api.v1.example.com", "host", "host.example.com", "block_time", float64(120)}
assert.Equal(t, expected, api.LogInfo())
}
func TestAntelopeV1_SetTime(t *testing.T) {
expected := time.Date(2022, 2, 24, 13, 38, 0, 0, time.UTC)
api := NewAntelopeV1("", "", 60)
// Assert that time is NOW (+-10 seconds)
assert.InDelta(t, api.GetTime().Unix(), time.Now().In(time.UTC).Unix(), float64(10))
api.SetTime(expected)
assert.Equal(t, expected, api.GetTime())
}
func TestAntelopeV1_JsonFailure(t *testing.T) {
srv := httptest.NewServer(http.HandlerFunc(func(res http.ResponseWriter, req *http.Request) {
_, err := res.Write([]byte(`!//{invalid-json}!##`))
assert.NoError(t, err)
}))
api := NewAntelopeV1(srv.URL, "", 120)
check, _ := api.Call(context.Background())
expected := agentcheck.NewStatusMessageResponse(agentcheck.Fail, "")
assert.Equal(t, expected, check)
}
func TestAntelopeV1_HTTP500Failed(t *testing.T) {
srv := httptest.NewServer(http.HandlerFunc(func(res http.ResponseWriter, req *http.Request) {
res.WriteHeader(500)
_, err := res.Write([]byte(`{}`))
assert.NoError(t, err)
}))
api := NewAntelopeV1(srv.URL, "", 120)
check, status := api.Call(context.Background())
assert.Equal(t, "server returned HTTP 500 Internal Server Error", status)
expected := agentcheck.NewStatusMessageResponse(agentcheck.Fail, "")
assert.Equal(t, expected, check)
}
func TestAntelopeV1_LaggingUp(t *testing.T) {
srv := httptest.NewServer(http.HandlerFunc(func(res http.ResponseWriter, req *http.Request) {
if req.URL.String() == "/v1/chain/get_info" {
info := `{
"server_version": "8f613ec9",
"head_block_num": 7272812,
"head_block_time": "2022-02-24T13:37:00"
}`
_, err := res.Write([]byte(info))
assert.NoError(t, err)
}
}))
api := NewAntelopeV1(srv.URL, "", 60)
api.SetTime(time.Date(2022, 2, 24, 13, 38, 0, 0, time.UTC))
check, status := api.Call(context.Background())
assert.Equal(t, "OK", status)
expected := agentcheck.NewStatusResponse(agentcheck.Up)
assert.Equal(t, expected, check)
}
func TestAntelopeV1_LaggingDown(t *testing.T) {
srv := httptest.NewServer(http.HandlerFunc(func(res http.ResponseWriter, req *http.Request) {
if req.URL.String() == "/v1/chain/get_info" {
info := `{
"server_version": "9a607cce",
"head_block_num": 87263,
"head_block_time": "2018-01-01T13:37:01"
}`
_, err := res.Write([]byte(info))
assert.NoError(t, err)
}
}))
api := NewAntelopeV1(srv.URL, "", 60)
api.SetTime(time.Date(2018, time.January, 1, 13, 38, 2, 0, time.UTC))
check, status := api.Call(context.Background())
assert.Equal(t, "Taking offline because head block is lagging 61 seconds", status)
expected := agentcheck.NewStatusMessageResponse(agentcheck.Down, "")
assert.Equal(t, expected, check)
}
func TestAntelopeV1_TimeInFutureUP(t *testing.T) {
srv := httptest.NewServer(http.HandlerFunc(func(res http.ResponseWriter, req *http.Request) {
if req.URL.String() == "/v1/chain/get_info" {
info := `{
"server_version": "d1bec8d3",
"head_block_num": 548847,
"head_block_time": "2020-09-22T09:32:00"
}`
_, err := res.Write([]byte(info))
assert.NoError(t, err)
}
}))
api := NewAntelopeV1(srv.URL, "", 120)
api.SetTime(time.Date(2020, 9, 22, 9, 30, 0, 0, time.UTC))
check, status := api.Call(context.Background())
assert.Equal(t, "OK", status)
expected := agentcheck.NewStatusResponse(agentcheck.Up)
assert.Equal(t, expected, check)
}
func TestAntelopeV1_TimeInFutureDown(t *testing.T) {
srv := httptest.NewServer(http.HandlerFunc(func(res http.ResponseWriter, req *http.Request) {
if req.URL.String() == "/v1/chain/get_info" {
info := `{
"server_version": "c879d231",
"head_block_num": 2637621,
"head_block_time": "2019-04-14T12:02:01"
}`
_, err := res.Write([]byte(info))
assert.NoError(t, err)
}
}))
api := NewAntelopeV1(srv.URL, "", 120)
api.SetTime(time.Date(2019, time.April, 14, 12, 0, 0, 0, time.UTC))
check, status := api.Call(context.Background())
assert.Equal(t, "Taking offline because head block is -121 seconds into the future", status)
expected := agentcheck.NewStatusMessageResponse(agentcheck.Down, "")
assert.Equal(t, expected, check)
}

View file

@ -0,0 +1,85 @@
package api
import (
"context"
"fmt"
"github.com/eosswedenorg-go/haproxy/agentcheck"
"github.com/eosswedenorg-go/leapapi"
"github.com/eosswedenorg/antelope-api-healthcheck/internal/utils"
)
type AntelopeV2 struct {
client leapapi.Client
offset int64
}
func AntelopeV2Factory(args ApiArguments) ApiInterface {
return NewAntelopeV2(args.Url, args.Host, int64(args.NumBlocks))
}
func NewAntelopeV2(url string, host string, offset int64) AntelopeV2 {
api := AntelopeV2{
client: *leapapi.New(url),
offset: offset,
}
api.client.Host = host
return api
}
func (e AntelopeV2) LogInfo() LogParams {
p := LogParams{
"type", "antelope-v2",
"url", e.client.Url,
}
if len(e.client.Host) > 0 {
p.Add("host", e.client.Host)
}
p.Add("offset", e.offset)
return p
}
func (e AntelopeV2) Call(ctx context.Context) (agentcheck.Response, string) {
health, err := e.client.GetHealth(ctx)
if err != nil {
resp := agentcheck.NewStatusMessageResponse(agentcheck.Fail, "")
return resp, err.Error()
}
// Fetch elasticsearch and nodeos block numbers from json.
var es_block int64 = 0
var node_block int64 = 0
for _, v := range health.Health {
if v.Name == "Elasticsearch" {
es_block = utils.JsonGetInt64(v.Data["last_indexed_block"])
} else if v.Name == "NodeosRPC" {
node_block = utils.JsonGetInt64(v.Data["head_block_num"])
}
}
// Error out if ether or both are zero.
if es_block == 0 || node_block == 0 {
msg := fmt.Sprintf("Failed to get Elasticsearch and/or nodeos "+
"block numbers (es: %d, eos: %d)", es_block, node_block)
resp := agentcheck.NewStatusMessageResponse(agentcheck.Fail, "")
return resp, msg
}
// Check if ES is behind or in the future.
diff := node_block - es_block
if diff > e.offset {
resp := agentcheck.NewStatusMessageResponse(agentcheck.Down, "")
return resp, fmt.Sprintf("Taking offline because Elastic is %d blocks behind", diff)
} else if diff < -e.offset {
resp := agentcheck.NewStatusMessageResponse(agentcheck.Down, "")
return resp, fmt.Sprintf("Taking offline because Elastic is %d blocks into the future", -1*diff)
}
return agentcheck.NewStatusResponse(agentcheck.Up), "OK"
}

View file

@ -1,55 +1,69 @@
package api package api
import ( import (
"testing" "context"
"net/http" "net/http"
"net/http/httptest" "net/http/httptest"
"github.com/stretchr/testify/assert" "testing"
"github.com/eosswedenorg-go/haproxy/agentcheck" "github.com/eosswedenorg-go/haproxy/agentcheck"
"github.com/stretchr/testify/assert"
) )
func TestEosioV2LogInfo(t *testing.T) { func TestAntelopeV2_Factory(t *testing.T) {
api := AntelopeV2Factory(ApiArguments{
Url: "https://api.v2.example.com",
Host: "host.example.com",
NumBlocks: 120,
})
api := NewEosioV2("https://api.v2.example.com", "host.example.com", 120) expected := NewAntelopeV2("https://api.v2.example.com", "host.example.com", 120)
expected := LogParams{"type","eosio-v2","url","https://api.v2.example.com","host","host.example.com","offset",int64(120)} assert.IsType(t, expected, api)
assert.Equal(t, expected.client.Url, api.(AntelopeV2).client.Url)
assert.Equal(t, expected.client.Host, api.(AntelopeV2).client.Host)
assert.Equal(t, expected.offset, api.(AntelopeV2).offset)
}
func TestAntelopeV2_LogInfo(t *testing.T) {
api := NewAntelopeV2("https://api.v2.example.com", "host.example.com", 120)
expected := LogParams{"type", "antelope-v2", "url", "https://api.v2.example.com", "host", "host.example.com", "offset", int64(120)}
assert.Equal(t, expected, api.LogInfo()) assert.Equal(t, expected, api.LogInfo())
} }
func TestEosioV2JsonFailure(t *testing.T) { func TestAntelopeV2_JsonFailure(t *testing.T) {
srv := httptest.NewServer(http.HandlerFunc(func(res http.ResponseWriter, req *http.Request) {
var srv = httptest.NewServer(http.HandlerFunc(func(res http.ResponseWriter, req *http.Request) { _, err := res.Write([]byte(`!//{invalid-json}!##`))
res.Write([]byte(`!//{invalid-json}!##`)) assert.NoError(t, err)
})) }))
api := NewEosioV2(srv.URL, "", 120) api := NewAntelopeV2(srv.URL, "", 120)
check, _ := api.Call() check, _ := api.Call(context.Background())
expected := agentcheck.NewStatusMessageResponse(agentcheck.Failed, "") expected := agentcheck.NewStatusMessageResponse(agentcheck.Fail, "")
assert.Equal(t, expected, check) assert.Equal(t, expected, check)
} }
func TestEosioV2HTTP500Down(t *testing.T) { func TestAntelopeV2_HTTP500Failed(t *testing.T) {
srv := httptest.NewServer(http.HandlerFunc(func(res http.ResponseWriter, req *http.Request) {
var srv = httptest.NewServer(http.HandlerFunc(func(res http.ResponseWriter, req *http.Request) {
res.WriteHeader(500) res.WriteHeader(500)
res.Write([]byte(`{}`)) _, err := res.Write([]byte(`{}`))
assert.NoError(t, err)
})) }))
api := NewEosioV2(srv.URL, "", 120) api := NewAntelopeV2(srv.URL, "", 120)
check, status := api.Call() check, status := api.Call(context.Background())
assert.Equal(t, "Taking offline because 500 was received from backend", status) assert.Equal(t, "server returned HTTP 500 Internal Server Error", status)
expected := agentcheck.NewStatusMessageResponse(agentcheck.Down, "") expected := agentcheck.NewStatusMessageResponse(agentcheck.Fail, "")
assert.Equal(t, expected, check) assert.Equal(t, expected, check)
} }
func TestEosioV2LaggingUp(t *testing.T) { func TestAntelopeV2_LaggingUp(t *testing.T) {
srv := httptest.NewServer(http.HandlerFunc(func(res http.ResponseWriter, req *http.Request) {
var srv = httptest.NewServer(http.HandlerFunc(func(res http.ResponseWriter, req *http.Request) {
if req.URL.String() == "/v2/health" { if req.URL.String() == "/v2/health" {
info := `{ info := `{
"version": "1.0", "version": "1.0",
@ -81,12 +95,13 @@ func TestEosioV2LaggingUp(t *testing.T) {
] ]
}` }`
res.Write([]byte(info)) _, err := res.Write([]byte(info))
assert.NoError(t, err)
} }
})) }))
api := NewEosioV2(srv.URL, "", 500) api := NewAntelopeV2(srv.URL, "", 500)
check, status := api.Call() check, status := api.Call(context.Background())
assert.Equal(t, "OK", status) assert.Equal(t, "OK", status)
@ -94,9 +109,8 @@ func TestEosioV2LaggingUp(t *testing.T) {
assert.Equal(t, expected, check) assert.Equal(t, expected, check)
} }
func TestEosioV2LaggingDown(t *testing.T) { func TestAntelopeV2_LaggingDown(t *testing.T) {
srv := httptest.NewServer(http.HandlerFunc(func(res http.ResponseWriter, req *http.Request) {
var srv = httptest.NewServer(http.HandlerFunc(func(res http.ResponseWriter, req *http.Request) {
if req.URL.String() == "/v2/health" { if req.URL.String() == "/v2/health" {
info := `{ info := `{
"version": "1.0", "version": "1.0",
@ -128,12 +142,13 @@ func TestEosioV2LaggingDown(t *testing.T) {
] ]
}` }`
res.Write([]byte(info)) _, err := res.Write([]byte(info))
assert.NoError(t, err)
} }
})) }))
api := NewEosioV2(srv.URL, "", 499) api := NewAntelopeV2(srv.URL, "", 499)
check, status := api.Call() check, status := api.Call(context.Background())
assert.Equal(t, "Taking offline because Elastic is 500 blocks behind", status) assert.Equal(t, "Taking offline because Elastic is 500 blocks behind", status)
@ -141,9 +156,8 @@ func TestEosioV2LaggingDown(t *testing.T) {
assert.Equal(t, expected, check) assert.Equal(t, expected, check)
} }
func TestEosioV2LaggingESInFutureUP(t *testing.T) { func TestAntelopeV2_LaggingESInFutureUP(t *testing.T) {
srv := httptest.NewServer(http.HandlerFunc(func(res http.ResponseWriter, req *http.Request) {
var srv = httptest.NewServer(http.HandlerFunc(func(res http.ResponseWriter, req *http.Request) {
if req.URL.String() == "/v2/health" { if req.URL.String() == "/v2/health" {
info := `{ info := `{
"version": "1.0", "version": "1.0",
@ -175,12 +189,13 @@ func TestEosioV2LaggingESInFutureUP(t *testing.T) {
] ]
}` }`
res.Write([]byte(info)) _, err := res.Write([]byte(info))
assert.NoError(t, err)
} }
})) }))
api := NewEosioV2(srv.URL, "", 200) api := NewAntelopeV2(srv.URL, "", 200)
check, status := api.Call() check, status := api.Call(context.Background())
assert.Equal(t, "OK", status) assert.Equal(t, "OK", status)
@ -188,9 +203,8 @@ func TestEosioV2LaggingESInFutureUP(t *testing.T) {
assert.Equal(t, expected, check) assert.Equal(t, expected, check)
} }
func TestEosioV2LaggingESInFutureDown(t *testing.T) { func TestAntelopeV2_LaggingESInFutureDown(t *testing.T) {
srv := httptest.NewServer(http.HandlerFunc(func(res http.ResponseWriter, req *http.Request) {
var srv = httptest.NewServer(http.HandlerFunc(func(res http.ResponseWriter, req *http.Request) {
if req.URL.String() == "/v2/health" { if req.URL.String() == "/v2/health" {
info := `{ info := `{
"version": "1.0", "version": "1.0",
@ -222,12 +236,13 @@ func TestEosioV2LaggingESInFutureDown(t *testing.T) {
] ]
}` }`
res.Write([]byte(info)) _, err := res.Write([]byte(info))
assert.NoError(t, err)
} }
})) }))
api := NewEosioV2(srv.URL, "", 200) api := NewAntelopeV2(srv.URL, "", 200)
check, status := api.Call() check, status := api.Call(context.Background())
assert.Equal(t, "Taking offline because Elastic is 201 blocks into the future", status) assert.Equal(t, "Taking offline because Elastic is 201 blocks into the future", status)
@ -235,9 +250,8 @@ func TestEosioV2LaggingESInFutureDown(t *testing.T) {
assert.Equal(t, expected, check) assert.Equal(t, expected, check)
} }
func TestEosioV2ElasticsFailed(t *testing.T) { func TestAntelopeV2_ElasticsFailed(t *testing.T) {
srv := httptest.NewServer(http.HandlerFunc(func(res http.ResponseWriter, req *http.Request) {
var srv = httptest.NewServer(http.HandlerFunc(func(res http.ResponseWriter, req *http.Request) {
if req.URL.String() == "/v2/health" { if req.URL.String() == "/v2/health" {
info := `{ info := `{
"version": "1.0", "version": "1.0",
@ -269,22 +283,22 @@ func TestEosioV2ElasticsFailed(t *testing.T) {
] ]
}` }`
res.Write([]byte(info)) _, err := res.Write([]byte(info))
assert.NoError(t, err)
} }
})) }))
api := NewEosioV2(srv.URL, "", 500) api := NewAntelopeV2(srv.URL, "", 500)
check, status := api.Call() check, status := api.Call(context.Background())
assert.Equal(t, "Failed to get Elasticsearch and/or nodeos block numbers (es: 0, eos: 263148621)", status) assert.Equal(t, "Failed to get Elasticsearch and/or nodeos block numbers (es: 0, eos: 263148621)", status)
expected := agentcheck.NewStatusMessageResponse(agentcheck.Failed, "") expected := agentcheck.NewStatusMessageResponse(agentcheck.Fail, "")
assert.Equal(t, expected, check) assert.Equal(t, expected, check)
} }
func TestEosioV2NodeosRPCFailed(t *testing.T) { func TestAntelopeV2_NodeosRPCFailed(t *testing.T) {
srv := httptest.NewServer(http.HandlerFunc(func(res http.ResponseWriter, req *http.Request) {
var srv = httptest.NewServer(http.HandlerFunc(func(res http.ResponseWriter, req *http.Request) {
if req.URL.String() == "/v2/health" { if req.URL.String() == "/v2/health" {
info := `{ info := `{
"version": "1.0", "version": "1.0",
@ -316,22 +330,22 @@ func TestEosioV2NodeosRPCFailed(t *testing.T) {
] ]
}` }`
res.Write([]byte(info)) _, err := res.Write([]byte(info))
assert.NoError(t, err)
} }
})) }))
api := NewEosioV2(srv.URL, "", 500) api := NewAntelopeV2(srv.URL, "", 500)
check, status := api.Call() check, status := api.Call(context.Background())
assert.Equal(t, "Failed to get Elasticsearch and/or nodeos block numbers (es: 263148121, eos: 0)", status) assert.Equal(t, "Failed to get Elasticsearch and/or nodeos block numbers (es: 263148121, eos: 0)", status)
expected := agentcheck.NewStatusMessageResponse(agentcheck.Failed, "") expected := agentcheck.NewStatusMessageResponse(agentcheck.Fail, "")
assert.Equal(t, expected, check) assert.Equal(t, expected, check)
} }
func TestEosioV2ElasticsNodeosRPCFailed(t *testing.T) { func TestAntelopeV2_ElasticsNodeosRPCFailed(t *testing.T) {
srv := httptest.NewServer(http.HandlerFunc(func(res http.ResponseWriter, req *http.Request) {
var srv = httptest.NewServer(http.HandlerFunc(func(res http.ResponseWriter, req *http.Request) {
if req.URL.String() == "/v2/health" { if req.URL.String() == "/v2/health" {
info := `{ info := `{
"version": "1.0", "version": "1.0",
@ -353,15 +367,16 @@ func TestEosioV2ElasticsNodeosRPCFailed(t *testing.T) {
] ]
}` }`
res.Write([]byte(info)) _, err := res.Write([]byte(info))
assert.NoError(t, err)
} }
})) }))
api := NewEosioV2(srv.URL, "", 500) api := NewAntelopeV2(srv.URL, "", 500)
check, status := api.Call() check, status := api.Call(context.Background())
assert.Equal(t, "Failed to get Elasticsearch and/or nodeos block numbers (es: 0, eos: 0)", status) assert.Equal(t, "Failed to get Elasticsearch and/or nodeos block numbers (es: 0, eos: 0)", status)
expected := agentcheck.NewStatusMessageResponse(agentcheck.Failed, "") expected := agentcheck.NewStatusMessageResponse(agentcheck.Fail, "")
assert.Equal(t, expected, check) assert.Equal(t, expected, check)
} }

View file

@ -0,0 +1,91 @@
package api
import (
"context"
"fmt"
"github.com/eosswedenorg-go/atomicasset"
"github.com/eosswedenorg-go/haproxy/agentcheck"
"github.com/eosswedenorg/antelope-api-healthcheck/internal/utils"
)
type AtomicAsset struct {
utils.Time
url string
host string
block_time float64
}
func AtomicAssetFactory(args ApiArguments) ApiInterface {
return NewAtomicAsset(args.Url, args.Host, float64(args.NumBlocks/2))
}
func NewAtomicAsset(url string, host string, block_time float64) AtomicAsset {
return AtomicAsset{
url: url,
host: host,
block_time: block_time,
}
}
func (e AtomicAsset) LogInfo() LogParams {
p := LogParams{
"type", "atomicasset",
"url", e.url,
"block_time", e.block_time,
}
if len(e.host) > 0 {
p.Add("host", e.host)
}
return p
}
func (e AtomicAsset) Call(ctx context.Context) (agentcheck.Response, string) {
client := atomicasset.NewWithContext(e.url, ctx)
client.Host = e.host
h, err := client.GetHealth()
if err != nil {
resp := agentcheck.NewStatusMessageResponse(agentcheck.Fail, "")
return resp, err.Error()
}
// Check HTTP Status Code
if h.HTTPStatusCode > 299 {
resp := agentcheck.NewStatusMessageResponse(agentcheck.Down, "")
msg := "Taking offline because %v was received from backend"
return resp, fmt.Sprintf(msg, h.HTTPStatusCode)
}
// Check postgres
if h.Data.Postgres.Status != "OK" {
resp := agentcheck.NewStatusMessageResponse(agentcheck.Down, "")
msg := "Taking offline because Postgres reported '%s'"
return resp, fmt.Sprintf(msg, h.Data.Postgres.Status)
}
// Check redis
if h.Data.Redis.Status != "OK" {
resp := agentcheck.NewStatusMessageResponse(agentcheck.Down, "")
msg := "Taking offline because Redis reported '%s'"
return resp, fmt.Sprintf(msg, h.Data.Redis.Status)
}
// Validate head block.
diff := e.GetTime().Sub(h.Data.Chain.HeadTime.Time()).Seconds()
if diff > e.block_time {
resp := agentcheck.NewStatusMessageResponse(agentcheck.Down, "")
msg := "Taking offline because head block is lagging %.0f seconds"
return resp, fmt.Sprintf(msg, diff)
} else if diff < -e.block_time {
resp := agentcheck.NewStatusMessageResponse(agentcheck.Down, "")
msg := "Taking offline because head block is %.0f seconds into the future"
return resp, fmt.Sprintf(msg, diff)
}
return agentcheck.NewStatusResponse(agentcheck.Up), "OK"
}

View file

@ -0,0 +1,316 @@
package api
import (
"context"
"net/http"
"net/http/httptest"
"testing"
"time"
"github.com/eosswedenorg-go/haproxy/agentcheck"
"github.com/stretchr/testify/assert"
)
func TestAtomicAsset_Factory(t *testing.T) {
api := AtomicAssetFactory(ApiArguments{
Url: "https://atomic.example.com",
NumBlocks: 120,
})
expected := NewAtomicAsset("https://atomic.example.com", "", 60)
assert.IsType(t, expected, api)
assert.Equal(t, expected.url, api.(AtomicAsset).url)
assert.Equal(t, expected.block_time, api.(AtomicAsset).block_time)
}
func TestAtomicAsset_LogInfo(t *testing.T) {
api := NewAtomicAsset("https://atomic.example.com", "", 120)
expected := LogParams{"type", "atomicasset", "url", "https://atomic.example.com", "block_time", float64(120)}
assert.Equal(t, expected, api.LogInfo())
}
func TestAtomicAsset_LogInfoWithHost(t *testing.T) {
api := NewAtomicAsset("https://atomic.example.com", "some.other.host", 120)
expected := LogParams{"type", "atomicasset", "url", "https://atomic.example.com", "block_time", float64(120), "host", "some.other.host"}
assert.Equal(t, expected, api.LogInfo())
}
func TestAtomicAsset_SetTime(t *testing.T) {
expected := time.Date(2019, 3, 18, 20, 29, 32, 0, time.UTC)
api := NewAtomicAsset("", "", 60)
// Assert that time is NOW (+-10 seconds)
assert.InDelta(t, api.GetTime().Unix(), time.Now().In(time.UTC).Unix(), float64(10))
api.SetTime(expected)
assert.Equal(t, expected, api.GetTime())
}
func TestAtomicAsset_JsonFailure(t *testing.T) {
srv := httptest.NewServer(http.HandlerFunc(func(res http.ResponseWriter, req *http.Request) {
_, err := res.Write([]byte(`!//{invalid-json}!##`))
assert.NoError(t, err)
}))
api := NewAtomicAsset(srv.URL, "", 120)
check, _ := api.Call(context.Background())
expected := agentcheck.NewStatusMessageResponse(agentcheck.Fail, "")
assert.Equal(t, expected, check)
}
func TestAtomicAsset_HTTP500Down(t *testing.T) {
srv := httptest.NewServer(http.HandlerFunc(func(res http.ResponseWriter, req *http.Request) {
res.Header().Add("Content-type", "application/json; charset=utf-8")
res.WriteHeader(500)
_, err := res.Write([]byte(`{}`))
assert.NoError(t, err)
}))
api := NewAtomicAsset(srv.URL, "", 120)
check, status := api.Call(context.Background())
assert.Equal(t, "Taking offline because 500 was received from backend", status)
expected := agentcheck.NewStatusMessageResponse(agentcheck.Down, "")
assert.Equal(t, expected, check)
}
func TestAtomicAsset_LaggingUp(t *testing.T) {
srv := httptest.NewServer(http.HandlerFunc(func(res http.ResponseWriter, req *http.Request) {
if req.URL.String() == "/health" {
payload := `{
"success":true,
"data":{
"version":"1.0.0",
"postgres":{
"status":"OK"
},
"redis":{
"status":"OK"
},
"chain":{
"status":"OK",
"head_block":2173612361,
"head_time":1759953927000
}
},
"query_time":1759953929542
}`
res.Header().Add("Content-type", "application/json; charset=utf-8")
_, err := res.Write([]byte(payload))
assert.NoError(t, err)
}
}))
api := NewAtomicAsset(srv.URL, "", 120)
api.SetTime(time.Date(2025, 10, 8, 20, 7, 27, 0, time.UTC))
check, status := api.Call(context.Background())
assert.Equal(t, "OK", status)
expected := agentcheck.NewStatusResponse(agentcheck.Up)
assert.Equal(t, expected, check)
}
func TestAtomicAsset_LaggingDown(t *testing.T) {
srv := httptest.NewServer(http.HandlerFunc(func(res http.ResponseWriter, req *http.Request) {
if req.URL.String() == "/health" {
payload := `{
"success":true,
"data":{
"version":"1.0.0",
"postgres":{
"status":"OK"
},
"redis":{
"status":"OK"
},
"chain":{
"status":"OK",
"head_block":213671263812,
"head_time":1533451894000
}
},
"query_time":1533451895542
}`
res.Header().Add("Content-type", "application/json; charset=utf-8")
_, err := res.Write([]byte(payload))
assert.NoError(t, err)
}
}))
api := NewAtomicAsset(srv.URL, "", 120)
api.SetTime(time.Date(2018, 8, 5, 6, 53, 35, 0, time.UTC))
check, status := api.Call(context.Background())
assert.Equal(t, "Taking offline because head block is lagging 121 seconds", status)
expected := agentcheck.NewStatusMessageResponse(agentcheck.Down, "")
assert.Equal(t, expected, check)
}
func TestAtomicAsset_InFutureUp(t *testing.T) {
srv := httptest.NewServer(http.HandlerFunc(func(res http.ResponseWriter, req *http.Request) {
if req.URL.String() == "/health" {
payload := `{
"success":true,
"data":{
"version":"1.0.0",
"postgres":{
"status":"OK"
},
"redis":{
"status":"OK"
},
"chain":{
"status":"OK",
"head_block":213671263812,
"head_time":1728954676500
}
},
"query_time":1728954678231
}`
res.Header().Add("Content-type", "application/json; charset=utf-8")
_, err := res.Write([]byte(payload))
assert.NoError(t, err)
}
}))
api := NewAtomicAsset(srv.URL, "", 120)
api.SetTime(time.Date(2024, 10, 15, 1, 9, 16, 500*int(time.Millisecond), time.UTC))
check, status := api.Call(context.Background())
assert.Equal(t, "OK", status)
expected := agentcheck.NewStatusResponse(agentcheck.Up)
assert.Equal(t, expected, check)
}
func TestAtomicAsset_InFutureDown(t *testing.T) {
srv := httptest.NewServer(http.HandlerFunc(func(res http.ResponseWriter, req *http.Request) {
if req.URL.String() == "/health" {
payload := `{
"success":true,
"data":{
"version":"1.0.0",
"postgres":{
"status":"OK"
},
"redis":{
"status":"OK"
},
"chain":{
"status":"OK",
"head_block":213671263812,
"head_time":1041122824500
}
},
"query_time":1041122832231
}`
res.Header().Add("Content-type", "application/json; charset=utf-8")
_, err := res.Write([]byte(payload))
assert.NoError(t, err)
}
}))
api := NewAtomicAsset(srv.URL, "", 120)
api.SetTime(time.Date(2002, 12, 29, 0, 45, 3, 500*int(time.Millisecond), time.UTC))
check, status := api.Call(context.Background())
assert.Equal(t, "Taking offline because head block is -121 seconds into the future", status)
expected := agentcheck.NewStatusMessageResponse(agentcheck.Down, "")
assert.Equal(t, expected, check)
}
func TestAtomicAsset_RedisDown(t *testing.T) {
srv := httptest.NewServer(http.HandlerFunc(func(res http.ResponseWriter, req *http.Request) {
if req.URL.String() == "/health" {
payload := `{
"success":true,
"data":{
"version":"1.0.0",
"postgres":{
"status":"OK"
},
"redis":{
"status":"DOWN"
},
"chain":{
"status":"OK",
"head_block":213671263812,
"head_time":1426072770500
}
},
"query_time":1426072775872
}`
res.Header().Add("Content-type", "application/json; charset=utf-8")
_, err := res.Write([]byte(payload))
assert.NoError(t, err)
}
}))
api := NewAtomicAsset(srv.URL, "", 120)
api.SetTime(time.Date(2015, 3, 11, 11, 19, 30, 500*int(time.Millisecond), time.UTC))
check, status := api.Call(context.Background())
assert.Equal(t, "Taking offline because Redis reported 'DOWN'", status)
expected := agentcheck.NewStatusMessageResponse(agentcheck.Down, "")
assert.Equal(t, expected, check)
}
func TestAtomicAsset_PostgresDown(t *testing.T) {
srv := httptest.NewServer(http.HandlerFunc(func(res http.ResponseWriter, req *http.Request) {
if req.URL.String() == "/health" {
payload := `{
"success":true,
"data":{
"version":"1.0.0",
"postgres":{
"status":"DOWN"
},
"redis":{
"status":"OK"
},
"chain":{
"status":"OK",
"head_block":213671263812,
"head_time":1562868371500
}
},
"query_time":156286837143
}`
res.Header().Add("Content-type", "application/json; charset=utf-8")
_, err := res.Write([]byte(payload))
assert.NoError(t, err)
}
}))
api := NewAtomicAsset(srv.URL, "", 120)
api.SetTime(time.Date(2019, 7, 11, 18, 6, 11, 500*int(time.Millisecond), time.UTC))
check, status := api.Call(context.Background())
assert.Equal(t, "Taking offline because Postgres reported 'DOWN'", status)
expected := agentcheck.NewStatusMessageResponse(agentcheck.Down, "")
assert.Equal(t, expected, check)
}

47
internal/api/debug.go Normal file
View file

@ -0,0 +1,47 @@
package api
import (
"context"
"strings"
"github.com/eosswedenorg-go/haproxy/agentcheck"
)
type DebugApi struct {
response agentcheck.Response
}
func parseResponse(resp string) agentcheck.Response {
parts := strings.SplitN(resp, "#", 2)
// Status with message
if len(parts) > 1 {
rtype := agentcheck.StatusMessageResponseType(parts[0])
return agentcheck.NewStatusMessageResponse(rtype, parts[1])
}
// Only status.
rtype := agentcheck.StatusResponseType(resp)
return agentcheck.NewStatusResponse(rtype)
}
func DebugApiFactory(args ApiArguments) ApiInterface {
return NewDebugApi(args.Url)
}
func NewDebugApi(response string) DebugApi {
return DebugApi{
response: parseResponse(response),
}
}
func (d DebugApi) LogInfo() LogParams {
return LogParams{
"type", "Debug",
"response", strings.TrimSpace(d.response.String()),
}
}
func (d DebugApi) Call(_ context.Context) (agentcheck.Response, string) {
return d.response, ""
}

View file

@ -1,12 +1,25 @@
package api package api
import ( import (
"context"
"reflect" "reflect"
"testing" "testing"
"github.com/stretchr/testify/assert"
"github.com/eosswedenorg-go/haproxy/agentcheck" "github.com/eosswedenorg-go/haproxy/agentcheck"
"github.com/stretchr/testify/assert"
) )
func TestDebugApi_Factory(t *testing.T) {
api := DebugApiFactory(ApiArguments{
Url: "up",
Host: "host",
NumBlocks: 40,
})
assert.IsType(t, DebugApi{}, api)
assert.Equal(t, api.(DebugApi).response, agentcheck.NewStatusResponse(agentcheck.Up))
}
func TestNewDebugApi(t *testing.T) { func TestNewDebugApi(t *testing.T) {
type args struct { type args struct {
response string response string
@ -31,7 +44,6 @@ func TestNewDebugApi(t *testing.T) {
} }
func TestDebugApi_LogInfo(t *testing.T) { func TestDebugApi_LogInfo(t *testing.T) {
expected := LogParams{"type", "Debug", "response", "up"} expected := LogParams{"type", "Debug", "response", "up"}
api := DebugApi{ api := DebugApi{
@ -42,14 +54,13 @@ func TestDebugApi_LogInfo(t *testing.T) {
} }
func TestDebugApi_Call(t *testing.T) { func TestDebugApi_Call(t *testing.T) {
expected := agentcheck.NewStatusMessageResponse(agentcheck.Stopped, "message") expected := agentcheck.NewStatusMessageResponse(agentcheck.Stopped, "message")
api := DebugApi{ api := DebugApi{
response: expected, response: expected,
} }
response, msg := api.Call() response, msg := api.Call(context.Background())
assert.Equal(t, response, expected) assert.Equal(t, response, expected)
assert.Equal(t, msg, "") assert.Equal(t, msg, "")

33
internal/api/interface.go Normal file
View file

@ -0,0 +1,33 @@
package api
import (
"context"
"github.com/eosswedenorg-go/haproxy/agentcheck"
)
/**
* Generic struct that is passed to factory functions
* to configure the API request.
*/
type ApiArguments struct {
Url string
Host string
NumBlocks int
}
/**
* Factory function
*
* Each API must implement this function and process `args`
* returing a instance of it's implementation of the ApiInterface
*/
type Factory func(args ApiArguments) ApiInterface
type ApiInterface interface {
// Returns Logging information
LogInfo() LogParams
// Call api and validate it's status.
Call(ctx context.Context) (agentcheck.Response, string)
}

View file

@ -0,0 +1,13 @@
package api
type LogParams []interface{}
func (p *LogParams) Add(field string, value interface{}) {
*p = append(*p, field, value)
}
// Syntactic sugar for append(p, other...)
// Returns a new instance of LogParams with all values from both p and other
func (p LogParams) Combine(other LogParams) LogParams {
return append(p, other...)
}

View file

@ -0,0 +1,47 @@
package api
import (
"testing"
"github.com/stretchr/testify/assert"
)
func TestLogParams(t *testing.T) {
type test_struct struct {
First string
Second int
}
p := LogParams{}
p.Add("one", 1)
p.Add("string", "str")
p.Add("struct", test_struct{First: "first_string", Second: 1234})
expected := []interface{}([]interface{}{
"one", 1,
"string", "str",
"struct",
test_struct{
First: "first_string",
Second: 1234,
},
})
assert.ElementsMatch(t, expected, p)
}
func TestLogParams_Combine(t *testing.T) {
a := LogParams{"one", 1, "string1", "str1"}
b := LogParams{"two", 2, "string2", "str2"}
expected := LogParams{
"one", 1,
"string1", "str1",
"two", 2,
"string2", "str2",
}
assert.Equal(t, expected, a.Combine(b))
}

20
internal/api/make.go Normal file
View file

@ -0,0 +1,20 @@
package api
import (
"fmt"
)
func Make(name string, args ApiArguments) (ApiInterface, error) {
factories := map[string]Factory{
"v1": AntelopeV1Factory,
"v2": AntelopeV2Factory,
"atomic": AtomicAssetFactory,
"debug": DebugApiFactory,
}
if factory, ok := factories[name]; ok {
return factory(args), nil
}
return nil, fmt.Errorf("invalid API '%s'", name)
}

37
internal/api/make_test.go Normal file
View file

@ -0,0 +1,37 @@
package api
import (
"testing"
"github.com/stretchr/testify/assert"
)
func TestMakeV1(t *testing.T) {
api, err := Make("v1", ApiArguments{})
assert.NoError(t, err)
assert.IsType(t, AntelopeV1{}, api)
}
func TestMakeV2(t *testing.T) {
api, err := Make("v2", ApiArguments{})
assert.NoError(t, err)
assert.IsType(t, AntelopeV2{}, api)
}
func TestMakeAtomic(t *testing.T) {
api, err := Make("atomic", ApiArguments{})
assert.NoError(t, err)
assert.IsType(t, AtomicAsset{}, api)
}
func TestMakeDebug(t *testing.T) {
api, err := Make("debug", ApiArguments{})
assert.NoError(t, err)
assert.IsType(t, DebugApi{}, api)
}
func TestMakeInvalid(t *testing.T) {
api, err := Make("invalid", ApiArguments{})
assert.Error(t, err)
assert.Nil(t, api)
}

View file

@ -0,0 +1,45 @@
package server
import (
"fmt"
"strconv"
"strings"
"github.com/eosswedenorg/antelope-api-healthcheck/internal/api"
)
func ParseArguments(args []string) api.ApiArguments {
a := api.ApiArguments{
NumBlocks: 10,
}
// 1. url (scheme + ip/domain + port)
a.Url = args[0]
// 2. num blocks
if len(args) > 1 {
num, err := strconv.ParseInt(args[1], 10, 32)
if err == nil {
a.NumBlocks = int(num)
}
}
// 3. Host
if len(args) > 2 {
a.Host = args[2]
}
return a
}
func ParseRequest(request string) (api.ApiInterface, error) {
p := strings.Split(strings.TrimSpace(request), "|")
if len(p) < 2 {
return nil, fmt.Errorf("invalid number of parameters in agent request")
}
a := ParseArguments(p[1:])
return api.Make(p[0], a)
}

View file

@ -0,0 +1,112 @@
package server
import (
"testing"
"github.com/eosswedenorg/antelope-api-healthcheck/internal/api"
"github.com/stretchr/testify/assert"
)
func TestParseRequest_WithInvalidApi(t *testing.T) {
api, err := ParseRequest("invalid|http://api.example.com")
assert.Error(t, err)
assert.Equal(t, err.Error(), "invalid API 'invalid'")
assert.Nil(t, api)
}
func TestParseRequest_WithInvalidParams(t *testing.T) {
api, err := ParseRequest("v1")
assert.Error(t, err)
assert.Equal(t, err.Error(), "invalid number of parameters in agent request")
assert.Nil(t, api)
}
// AntelopeV1
// --------------------------------
func TestParseRequest_AntelopeV1(t *testing.T) {
expected := api.NewAntelopeV1("http://api.example.com", "", 5)
api, err := ParseRequest("v1|http://api.example.com")
assert.NoError(t, err)
assert.Equal(t, expected.LogInfo(), api.LogInfo())
}
func TestParseRequest_AntelopeV1WithBlockNumber(t *testing.T) {
expected := api.NewAntelopeV1("http://api.example.com", "", 1000)
api, err := ParseRequest("v1|http://api.example.com|2000")
assert.NoError(t, err)
assert.Equal(t, expected.LogInfo(), api.LogInfo())
}
func TestParseRequest_AntelopeV1Full(t *testing.T) {
expected := api.NewAntelopeV1("http://api.example.com", "http://host.example.com", 500)
api, err := ParseRequest("v1|http://api.example.com|1000|http://host.example.com")
assert.NoError(t, err)
assert.Equal(t, expected.LogInfo(), api.LogInfo())
}
// AntelopeV2
// --------------------------------
func TestParseRequest_AntelopeV2(t *testing.T) {
expected := api.NewAntelopeV2("http://api.v2.example.com", "", 10)
api, err := ParseRequest("v2|http://api.v2.example.com")
assert.NoError(t, err)
assert.Equal(t, expected.LogInfo(), api.LogInfo())
}
func TestParseRequest_AntelopeV2WithOffset(t *testing.T) {
expected := api.NewAntelopeV2("http://api.v2.example.com", "", 1000)
api, err := ParseRequest("v2|http://api.v2.example.com|1000")
assert.NoError(t, err)
assert.Equal(t, expected.LogInfo(), api.LogInfo())
}
func TestParseRequest_AntelopeV2Full(t *testing.T) {
expected := api.NewAntelopeV2("http://api.v2.example.com", "http://host.example.com", 1000)
api, err := ParseRequest("v2|http://api.v2.example.com|1000|http://host.example.com")
assert.NoError(t, err)
assert.Equal(t, expected.LogInfo(), api.LogInfo())
}
// AtomicAsset
// --------------------------------
func TestParseRequest_AtomicAsset(t *testing.T) {
expected := api.NewAtomicAsset("http://api.atomicassets.io", "", 5)
api, err := ParseRequest("atomic|http://api.atomicassets.io")
assert.NoError(t, err)
assert.Equal(t, expected.LogInfo(), api.LogInfo())
}
func TestParseRequest_AtomicAssetWithBlockTime(t *testing.T) {
expected := api.NewAtomicAsset("http://api.atomicassets.io", "", 256)
api, err := ParseRequest("atomic|http://api.atomicassets.io|512")
assert.NoError(t, err)
assert.Equal(t, expected.LogInfo(), api.LogInfo())
}
func TestParseRequest_AtomicAssetWithHost(t *testing.T) {
expected := api.NewAtomicAsset("http://api.atomicassets.io", "some.other.host", 256)
api, err := ParseRequest("atomic|http://api.atomicassets.io|512|some.other.host")
assert.NoError(t, err)
assert.Equal(t, expected.LogInfo(), api.LogInfo())
}
func TestParseRequest_DebugApi(t *testing.T) {
expected := api.NewDebugApi("some_api_call")
api, err := ParseRequest("debug|some_api_call")
assert.NoError(t, err)
assert.Equal(t, expected.LogInfo(), api.LogInfo())
}

176
internal/server/server.go Normal file
View file

@ -0,0 +1,176 @@
package server
import (
"context"
"fmt"
"strings"
"sync/atomic"
"time"
"github.com/eosswedenorg-go/haproxy/agentcheck"
"github.com/eosswedenorg/antelope-api-healthcheck/internal/api"
log "github.com/inconshreveable/log15"
"github.com/panjf2000/gnet/v2"
)
type Server struct {
gnet.BuiltinEventEngine
eng gnet.Engine
// Address to bind to.
addr string
// Number of connections between each OnTick()
num_conn uint64
// Time between each call to OnTick()
tick_interval time.Duration
// API Check timeout
timeout time.Duration
}
type Option func(*Server)
func New(addr string, options ...Option) *Server {
s := &Server{
addr: fmt.Sprintf("tcp://%s", addr),
}
for _, opt := range options {
opt(s)
}
return s
}
func WithTick(interval time.Duration) Option {
return func(s *Server) {
s.tick_interval = interval
}
}
func WithTimeout(duration time.Duration) Option {
return func(s *Server) {
s.timeout = duration
}
}
// OnBoot callback function
//
// ---------------------------------------------------------
func (s *Server) OnBoot(eng gnet.Engine) gnet.Action {
s.eng = eng
log.Info("Server started", "addr", s.addr)
return gnet.None
}
func (s *Server) OnOpen(c gnet.Conn) ([]byte, gnet.Action) {
atomic.AddUint64(&s.num_conn, 1)
return nil, gnet.None
}
// OnClose callback function
//
// ---------------------------------------------------------
func (s *Server) OnClose(c gnet.Conn, err error) gnet.Action {
if err != nil {
log.Error("TCP Close", "error", err)
}
return gnet.None
}
// OnShutdown callback function
//
// ---------------------------------------------------------
func (s *Server) OnShutdown(eng gnet.Engine) {
log.Info("Server shutdown")
}
// OnTick callback function
//
// ---------------------------------------------------------
func (s *Server) OnTick() (time.Duration, gnet.Action) {
log.Info("Server info", log.Ctx{
"connections": atomic.LoadUint64(&s.num_conn),
"current_connections": s.eng.CountConnections(),
})
atomic.StoreUint64(&s.num_conn, 0)
return s.tick_interval, gnet.None
}
// OnTraffic callback function
//
// ---------------------------------------------------------
func (s *Server) OnTraffic(c gnet.Conn) gnet.Action {
logger := log.Root()
req, err := c.Next(-1)
if err != nil {
logger.Error("Read", "message", err)
return gnet.Close
}
// Check api.
// -------------------
healthCheckApi, err := ParseRequest(string(req))
if err != nil {
logger.Warn("Agent request error", "message", err)
resp := agentcheck.NewStatusMessageResponse(agentcheck.Fail, "")
_, err = c.Write([]byte(resp.String()))
if err != nil {
logger.Error("Write", "message", err)
}
return gnet.Close
}
// gnet library does not like blocking calls.
// as we do a blocking http call here, we need to wrap it in a goroutine.
go func() {
ctx := context.Background()
if s.timeout > 0 {
var cancel context.CancelFunc
ctx, cancel = context.WithTimeout(ctx, s.timeout)
defer cancel()
}
t := time.Now()
status, msg := healthCheckApi.Call(ctx)
req_time := time.Since(t)
params := api.LogParams{}
params.Add("status", strings.TrimSpace(status.String()))
params.Add("duration", req_time)
params.Add("duration_us", req_time.Microseconds())
if msg != "OK" && len(msg) > 0 {
params.Add("error", msg)
}
logger.Info("API Check", params.Combine(healthCheckApi.LogInfo())...)
// Report status to HAproxy
err = c.AsyncWrite([]byte(status.String()), func(c gnet.Conn, err error) error {
return c.Close()
})
if err != nil {
logger.Error("Write", "message", err)
}
}()
return gnet.None
}
func (s *Server) Close() error {
return s.eng.Stop(context.Background())
}
// Run the server event loop.
//
// ---------------------------------------------------------
func (s *Server) Run() error {
return gnet.Run(s, s.addr, gnet.WithMulticore(true), gnet.WithTicker(true))
}

View file

@ -1,4 +1,3 @@
package utils package utils
// JsonGetInt64 // JsonGetInt64
@ -8,7 +7,7 @@ package utils
// if the type assertion fails, the function defaults 0 (zero). // if the type assertion fails, the function defaults 0 (zero).
// --------------------------------------------------------- // ---------------------------------------------------------
func JsonGetInt64(input interface{}) (int64) { func JsonGetInt64(input interface{}) int64 {
v, res := input.(float64) v, res := input.(float64)
if res { if res {
return (int64)(v) return (int64)(v)

View file

@ -0,0 +1,22 @@
package utils
import "testing"
func TestJson_GetInt64(t *testing.T) {
tests := []struct {
name string
input interface{}
want int64
}{
{"String", "test", 0},
{"Int", 1234, 0},
{"Float", float64(1234), 1234},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
if got := JsonGetInt64(tt.input); got != tt.want {
t.Errorf("JsonGetInt64() = %v, want %v", got, tt.want)
}
})
}
}

View file

@ -0,0 +1,18 @@
package utils
import (
log "github.com/inconshreveable/log15"
)
func ParseLogFormatter(name string) log.Format {
switch name {
case "logfmt":
return log.LogfmtFormat()
case "json":
return log.JsonFormat()
case "json-pretty":
return log.JsonFormatEx(true, true)
default:
return log.TerminalFormat()
}
}

View file

@ -0,0 +1,29 @@
package utils
import (
"reflect"
"testing"
log "github.com/inconshreveable/log15"
)
func TestParseLogFormatter(t *testing.T) {
tests := []struct {
name string
arg string
want log.Format
}{
{"Default", "", log.TerminalFormat()},
{"LogFmt", "logfmt", log.LogfmtFormat()},
{"Json", "json", log.JsonFormat()},
{"JsonPretty", "json-pretty", log.JsonFormat()},
{"Unknown", "unknown", log.TerminalFormat()},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
if got := ParseLogFormatter(tt.arg); reflect.ValueOf(got).Pointer() != reflect.ValueOf(tt.want).Pointer() {
t.Errorf("parseLogFormatter() = %v, want %v", got, tt.want)
}
})
}
}

20
internal/utils/time.go Normal file
View file

@ -0,0 +1,20 @@
package utils
import (
"time"
)
type Time struct {
ts time.Time
}
func (t *Time) SetTime(value time.Time) {
t.ts = value
}
func (t Time) GetTime() time.Time {
if !t.ts.IsZero() {
return t.ts
}
return time.Now().In(time.UTC)
}

View file

@ -0,0 +1,24 @@
package utils
import (
"testing"
"time"
"github.com/stretchr/testify/assert"
)
func TestTime_GetTimeWithDefaultValue(t *testing.T) {
var ts Time
// Assert that time is NOW (+-10 seconds)
assert.InDelta(t, ts.GetTime().Unix(), time.Now().In(time.UTC).Unix(), float64(10))
}
func TestTime_GetTimeWithSetTime(t *testing.T) {
var ts Time
expected := time.Unix(1048722042, 500)
ts.SetTime(expected)
assert.Equal(t, expected, ts.GetTime())
}

View file

@ -1,5 +1,5 @@
#!/bin/bash #!/bin/bash
# Info # Info
PROGRAM_NAME=eosio-api-healthcheck PROGRAM_NAME=antelope-api-healthcheck
PROGRAM_DESCRIPTION="HAproxy healthcheck program for EOSIO API." PROGRAM_DESCRIPTION="HAproxy healthcheck program for Antelope Leap API."

View file

@ -6,6 +6,7 @@ source ${BASE_DIR}/functions/log_install.sh
SYSTEMDDIR=${DESTDIR}/lib/systemd/system SYSTEMDDIR=${DESTDIR}/lib/systemd/system
SYSTEMDLINKDIR=${DESTDIR}/etc/systemd/system SYSTEMDLINKDIR=${DESTDIR}/etc/systemd/system
RSYSLOGDIR=${DESTDIR}/etc/rsyslog.d RSYSLOGDIR=${DESTDIR}/etc/rsyslog.d
SYSLOG_NG_DIR=${DESTDIR}/etc/syslog-ng/conf.d
LOGROTATEDIR=${DESTDIR}/etc/logrotate.d LOGROTATEDIR=${DESTDIR}/etc/logrotate.d
# Create service file # Create service file
@ -37,6 +38,14 @@ cat ${TEMPLATE_DIR}/rsyslog.conf \
| sed "s~{{ LOG_FILE }}~${LOGFILE}~" \ | sed "s~{{ LOG_FILE }}~${LOGFILE}~" \
> ${RSYSLOGDIR}/49-${PROGRAM_NAME}.conf > ${RSYSLOGDIR}/49-${PROGRAM_NAME}.conf
# Create syslog-ng file
log_install ${SYSLOG_NG_DIR}/${PROGRAM_NAME}.conf
mkdir -p ${SYSLOG_NG_DIR}
cat ${TEMPLATE_DIR}/syslog-ng.conf \
| sed "s~{{ PROGRAM }}~${PROGRAM_NAME}~" \
| sed "s~{{ LOG_FILE }}~${LOGFILE}~" \
> ${SYSLOG_NG_DIR}/${PROGRAM_NAME}.conf
# Create logrotate file # Create logrotate file
log_install ${LOGROTATEDIR}/${PROGRAM_NAME}.conf log_install ${LOGROTATEDIR}/${PROGRAM_NAME}.conf
mkdir -p ${LOGROTATEDIR} mkdir -p ${LOGROTATEDIR}

View file

@ -4,4 +4,4 @@
# Command line flags to pass to {{ PROGRAM_NAME }} # Command line flags to pass to {{ PROGRAM_NAME }}
# Positional agruments are IP to listen to, then port number. # Positional agruments are IP to listen to, then port number.
EOSIO_API_HEALTCHECK_OPTS="--log-format=logfmt 127.0.0.1 1337" ANTELOPE_API_HEALTCHECK_OPTS="--log-format=logfmt 127.0.0.1 1337"

View file

@ -1,11 +1,11 @@
#!/bin/sh #!/bin/sh
# #
# Add the following lines to /etc/rc.conf to configure eosio_api_healthcheck: # Add the following lines to /etc/rc.conf to configure antelope_api_healthcheck:
# #
# eosio_api_healthcheck_args : arguments to the command. # antelope_api_healthcheck_args : arguments to the command.
# #
# eosio_api_healthcheck_logfile : file to log to (default /var/log/${name}.log) # antelope_api_healthcheck_logfile : file to log to (default /var/log/${name}.log)
# #
# PROVIDE: {{ RC_NAME }} # PROVIDE: {{ RC_NAME }}
@ -15,14 +15,14 @@
name="{{ RC_NAME }}" name="{{ RC_NAME }}"
desc="{{ PROGRAM_DESCRIPTION }}" desc="{{ PROGRAM_DESCRIPTION }}"
logfile="${eosio_api_healthcheck_logfile:-{{ LOG_FILE }}}" logfile="${antelope_api_healthcheck_logfile:-{{ LOG_FILE }}}"
pidfile="{{ PID_FILE }}" pidfile="{{ PID_FILE }}"
command="{{ PROGRAM }}" command="{{ PROGRAM }}"
command_args="-p ${pidfile} -l ${logfile} ${eosio_api_healthcheck_args}" command_args="-p ${pidfile} -l ${logfile} ${antelope_api_healthcheck_args}"
start_cmd="${name}_start" start_cmd="${name}_start"
eosio_api_healthcheck_start() antelope_api_healthcheck_start()
{ {
echo "Starting ${name}" echo "Starting ${name}"
${command} ${command_args} 2>&1 & ${command} ${command_args} 2>&1 &

View file

@ -0,0 +1,3 @@
filter f_api-healthcheck { program("{{ PROGRAM }}"); };
destination d_api-healthcheck { file("{{ LOG_FILE }}"); };
log { source(s_src); filter(f_api-healthcheck); destination(d_api-healthcheck); };

View file

@ -5,7 +5,7 @@ After=network.target
[Service] [Service]
EnvironmentFile=-/etc/sysconfig/{{ PROGRAM_NAME }} EnvironmentFile=-/etc/sysconfig/{{ PROGRAM_NAME }}
Type=simple Type=simple
ExecStart={{ PROGRAM }} $EOSIO_API_HEALTCHECK_OPTS ExecStart={{ PROGRAM }} $ANTELOPE_API_HEALTCHECK_OPTS
Restart=on-failure Restart=on-failure
[Install] [Install]

View file

@ -48,7 +48,7 @@ if [ ${WRITE_DEBCHANGES} -ne 0 ]; then
# Update debian changelog # Update debian changelog
ex debian/changelog <<EOF ex debian/changelog <<EOF
1 insert 1 insert
eosio-api-healthcheck (${VERSION}) unstable; urgency=medium antelope-api-healthcheck (${VERSION}) unstable; urgency=medium
* *

View file

@ -1,46 +0,0 @@
package api
import (
"strings"
"github.com/eosswedenorg-go/haproxy/agentcheck"
)
type DebugApi struct {
response agentcheck.Response
}
func parseResponse(resp string) (agentcheck.Response, error) {
parts := strings.SplitN(resp, "#", 2)
// Status with message
if len(parts) > 1 {
rtype := agentcheck.StatusMessageResponseType(parts[0])
return agentcheck.NewStatusMessageResponse(rtype, parts[1]), nil
}
// Only status.
rtype := agentcheck.StatusResponseType(parts[0])
return agentcheck.NewStatusResponse(rtype), nil
}
func NewDebugApi(response string) DebugApi {
resp, _ := parseResponse(response)
return DebugApi{
response: resp,
}
}
func (d DebugApi) LogInfo() LogParams {
return LogParams{
"type", "Debug",
"response", strings.TrimSpace(d.response.String()),
}
}
func (d DebugApi) Call() (agentcheck.Response, string) {
return d.response, ""
}

View file

@ -1,77 +0,0 @@
package api
import (
"fmt"
"github.com/eosswedenorg/eosio-api-healthcheck/src/utils"
"github.com/eosswedenorg-go/haproxy/agentcheck"
contract_api "github.com/eosswedenorg-go/eos-contract-api-client"
)
type EosioContract struct {
utils.Time
client contract_api.Client
block_time float64
}
func NewEosioContract(url string, block_time float64) EosioContract {
return EosioContract{
client: contract_api.Client{
Url: url,
},
block_time: block_time,
}
}
func (e EosioContract) LogInfo() LogParams {
return LogParams{
"type", "eosio-contract",
"url", e.client.Url,
"block_time", e.block_time,
}
}
func (e EosioContract) Call() (agentcheck.Response, string) {
h, err := e.client.GetHealth()
if err != nil {
resp := agentcheck.NewStatusMessageResponse(agentcheck.Failed, "")
return resp, err.Error()
}
// Check HTTP Status Code
if h.HTTPStatusCode > 299 {
resp := agentcheck.NewStatusMessageResponse(agentcheck.Down, "")
msg := "Taking offline because %v was received from backend"
return resp, fmt.Sprintf(msg, h.HTTPStatusCode)
}
// Check postgres
if h.Data.Postgres.Status != "OK" {
resp := agentcheck.NewStatusMessageResponse(agentcheck.Down, "")
msg := "Taking offline because Postgres reported '%s'"
return resp, fmt.Sprintf(msg, h.Data.Postgres.Status)
}
// Check redis
if h.Data.Redis.Status != "OK" {
resp := agentcheck.NewStatusMessageResponse(agentcheck.Down, "")
msg := "Taking offline because Redis reported '%s'"
return resp, fmt.Sprintf(msg, h.Data.Redis.Status)
}
// Validate head block.
diff := e.GetTime().Sub(h.Data.Chain.HeadTime).Seconds()
if diff > e.block_time {
resp := agentcheck.NewStatusMessageResponse(agentcheck.Down, "")
msg := "Taking offline because head block is lagging %.0f seconds"
return resp, fmt.Sprintf(msg, diff)
} else if diff < -e.block_time {
resp := agentcheck.NewStatusMessageResponse(agentcheck.Down, "")
msg := "Taking offline because head block is %.0f seconds into the future"
return resp, fmt.Sprintf(msg, diff)
}
return agentcheck.NewStatusResponse(agentcheck.Up), "OK"
}

View file

@ -1,297 +0,0 @@
package api
import (
"time"
"testing"
"net/http"
"net/http/httptest"
"github.com/stretchr/testify/assert"
"github.com/eosswedenorg-go/haproxy/agentcheck"
)
func TestEosioContractLogInfo(t *testing.T) {
api := NewEosioContract("https://atomic.example.com", 120)
expected := LogParams{"type","eosio-contract","url","https://atomic.example.com","block_time",float64(120)}
assert.Equal(t, expected, api.LogInfo())
}
func TestEosioContractSetTime(t *testing.T) {
expected := time.Date(2019, 3, 18, 20, 29, 32, 0, time.UTC)
api := NewEosioContract("", 60)
// Assert that time is NOW (+-10 seconds)
assert.InDelta(t, api.GetTime().Unix(), time.Now().In(time.UTC).Unix(), float64(10))
api.SetTime(expected)
assert.Equal(t, expected, api.GetTime())
}
func TestEosioContractJsonFailure(t *testing.T) {
var srv = httptest.NewServer(http.HandlerFunc(func(res http.ResponseWriter, req *http.Request) {
res.Write([]byte(`!//{invalid-json}!##`))
}))
api := NewEosioContract(srv.URL, 120)
check, _ := api.Call()
expected := agentcheck.NewStatusMessageResponse(agentcheck.Failed, "")
assert.Equal(t, expected, check)
}
func TestEosioContractHTTP500Down(t *testing.T) {
var srv = httptest.NewServer(http.HandlerFunc(func(res http.ResponseWriter, req *http.Request) {
res.Header().Add("Content-type", "application/json; charset=utf-8")
res.WriteHeader(500)
res.Write([]byte(`{}`))
}))
api := NewEosioContract(srv.URL, 120)
check, status := api.Call()
assert.Equal(t, "Taking offline because 500 was received from backend", status)
expected := agentcheck.NewStatusMessageResponse(agentcheck.Down, "")
assert.Equal(t, expected, check)
}
func TestEosioContractLaggingUp(t *testing.T) {
var srv = httptest.NewServer(http.HandlerFunc(func(res http.ResponseWriter, req *http.Request) {
if req.URL.String() == "/health" {
payload := `{
"success":true,
"data":{
"version":"1.0.0",
"postgres":{
"status":"OK"
},
"redis":{
"status":"OK"
},
"chain":{
"status":"OK",
"head_block":2173612361,
"head_time":1759953927000
}
},
"query_time":1759953929542
}`
res.Header().Add("Content-type", "application/json; charset=utf-8")
res.Write([]byte(payload))
}
}))
api := NewEosioContract(srv.URL, 120)
api.SetTime(time.Date(2025, 10, 8, 20, 7, 27, 0, time.UTC))
check, status := api.Call()
assert.Equal(t, "OK", status)
expected := agentcheck.NewStatusResponse(agentcheck.Up)
assert.Equal(t, expected, check)
}
func TestEosioContractLaggingDown(t *testing.T) {
var srv = httptest.NewServer(http.HandlerFunc(func(res http.ResponseWriter, req *http.Request) {
if req.URL.String() == "/health" {
payload := `{
"success":true,
"data":{
"version":"1.0.0",
"postgres":{
"status":"OK"
},
"redis":{
"status":"OK"
},
"chain":{
"status":"OK",
"head_block":213671263812,
"head_time":1533451894000
}
},
"query_time":1533451895542
}`
res.Header().Add("Content-type", "application/json; charset=utf-8")
res.Write([]byte(payload))
}
}))
api := NewEosioContract(srv.URL, 120)
api.SetTime(time.Date(2018, 8, 5, 6, 53, 35, 0, time.UTC))
check, status := api.Call()
assert.Equal(t, "Taking offline because head block is lagging 121 seconds", status)
expected := agentcheck.NewStatusMessageResponse(agentcheck.Down, "")
assert.Equal(t, expected, check)
}
func TestEosioContractInFutureUp(t *testing.T) {
var srv = httptest.NewServer(http.HandlerFunc(func(res http.ResponseWriter, req *http.Request) {
if req.URL.String() == "/health" {
payload := `{
"success":true,
"data":{
"version":"1.0.0",
"postgres":{
"status":"OK"
},
"redis":{
"status":"OK"
},
"chain":{
"status":"OK",
"head_block":213671263812,
"head_time":1728954676500
}
},
"query_time":1728954678231
}`
res.Header().Add("Content-type", "application/json; charset=utf-8")
res.Write([]byte(payload))
}
}))
api := NewEosioContract(srv.URL, 120)
api.SetTime(time.Date(2024, 10, 15, 1, 9, 16, 500, time.UTC))
check, status := api.Call()
assert.Equal(t, "OK", status)
expected := agentcheck.NewStatusResponse(agentcheck.Up)
assert.Equal(t, expected, check)
}
func TestEosioContractInFutureDown(t *testing.T) {
var srv = httptest.NewServer(http.HandlerFunc(func(res http.ResponseWriter, req *http.Request) {
if req.URL.String() == "/health" {
payload := `{
"success":true,
"data":{
"version":"1.0.0",
"postgres":{
"status":"OK"
},
"redis":{
"status":"OK"
},
"chain":{
"status":"OK",
"head_block":213671263812,
"head_time":1041122824500
}
},
"query_time":1041122832231
}`
res.Header().Add("Content-type", "application/json; charset=utf-8")
res.Write([]byte(payload))
}
}))
api := NewEosioContract(srv.URL, 120)
api.SetTime(time.Date(2002, 12, 29, 0, 45, 03, 500, time.UTC))
check, status := api.Call()
assert.Equal(t, "Taking offline because head block is -121 seconds into the future", status)
expected := agentcheck.NewStatusMessageResponse(agentcheck.Down, "")
assert.Equal(t, expected, check)
}
func TestEosioContractRedisDown(t *testing.T) {
var srv = httptest.NewServer(http.HandlerFunc(func(res http.ResponseWriter, req *http.Request) {
if req.URL.String() == "/health" {
payload := `{
"success":true,
"data":{
"version":"1.0.0",
"postgres":{
"status":"OK"
},
"redis":{
"status":"DOWN"
},
"chain":{
"status":"OK",
"head_block":213671263812,
"head_time":1426072770500
}
},
"query_time":1426072775872
}`
res.Header().Add("Content-type", "application/json; charset=utf-8")
res.Write([]byte(payload))
}
}))
api := NewEosioContract(srv.URL, 120)
api.SetTime(time.Date(2015, 3, 11, 11, 19, 30, 500, time.UTC))
check, status := api.Call()
assert.Equal(t, "Taking offline because Redis reported 'DOWN'", status)
expected := agentcheck.NewStatusMessageResponse(agentcheck.Down, "")
assert.Equal(t, expected, check)
}
func TestEosioContractPostgresDown(t *testing.T) {
var srv = httptest.NewServer(http.HandlerFunc(func(res http.ResponseWriter, req *http.Request) {
if req.URL.String() == "/health" {
payload := `{
"success":true,
"data":{
"version":"1.0.0",
"postgres":{
"status":"DOWN"
},
"redis":{
"status":"OK"
},
"chain":{
"status":"OK",
"head_block":213671263812,
"head_time":1562868371500
}
},
"query_time":156286837143
}`
res.Header().Add("Content-type", "application/json; charset=utf-8")
res.Write([]byte(payload))
}
}))
api := NewEosioContract(srv.URL, 120)
api.SetTime(time.Date(2019, 7, 11, 18, 6, 11, 500, time.UTC))
check, status := api.Call()
assert.Equal(t, "Taking offline because Postgres reported 'DOWN'", status)
expected := agentcheck.NewStatusMessageResponse(agentcheck.Down, "")
assert.Equal(t, expected, check)
}

View file

@ -1,78 +0,0 @@
package api
import (
"fmt"
"github.com/eosswedenorg/eosio-api-healthcheck/src/utils"
"github.com/eosswedenorg-go/haproxy/agentcheck"
"github.com/eosswedenorg-go/eosapi"
)
type EosioV1 struct {
utils.Time
client eosapi.Client
block_time float64
}
func NewEosioV1(url string, host string, block_time float64) EosioV1 {
api := EosioV1{
client: *eosapi.New(url),
block_time: block_time,
}
api.client.Host = host
return api
}
func (e EosioV1) LogInfo() LogParams {
p := LogParams{
"type", "eosio-v1",
"url", e.client.Url,
}
if len(e.client.Host) > 0 {
p.Add("host", e.client.Host)
}
p.Add("block_time", e.block_time)
return p
}
func (e EosioV1) Call() (agentcheck.Response, string) {
info, err := e.client.GetInfo()
if err != nil {
resp := agentcheck.NewStatusMessageResponse(agentcheck.Failed, "")
return resp, err.Error()
}
// Check HTTP Status Code
if info.HTTPStatusCode > 299 {
resp := agentcheck.NewStatusMessageResponse(agentcheck.Down, "")
msg := "Taking offline because %v was received from backend"
return resp, fmt.Sprintf(msg, info.HTTPStatusCode)
}
// Validate head block.
diff := e.GetTime().Sub(info.HeadBlockTime).Seconds()
if diff > e.block_time {
resp := agentcheck.NewStatusMessageResponse(agentcheck.Down, "")
msg := "Taking offline because head block is lagging %.0f seconds"
return resp, fmt.Sprintf(msg, diff)
} else if diff < -e.block_time {
resp := agentcheck.NewStatusMessageResponse(agentcheck.Down, "")
msg := "Taking offline because head block is %.0f seconds into the future"
return resp, fmt.Sprintf(msg, diff)
}
return agentcheck.NewStatusResponse(agentcheck.Up), "OK"
}

View file

@ -1,158 +0,0 @@
package api
import (
"time"
"testing"
"net/http"
"net/http/httptest"
"github.com/stretchr/testify/assert"
"github.com/eosswedenorg-go/haproxy/agentcheck"
)
func TestEosioV1LogInfo(t *testing.T) {
api := NewEosioV1("https://api.v1.example.com", "host.example.com", 120)
expected := LogParams{"type","eosio-v1","url","https://api.v1.example.com","host","host.example.com","block_time",float64(120)}
assert.Equal(t, expected, api.LogInfo())
}
func TestEosioV1SetTime(t *testing.T) {
expected := time.Date(2022, 2, 24, 13, 38, 0, 0, time.UTC)
api := NewEosioV1("", "", 60)
// Assert that time is NOW (+-10 seconds)
assert.InDelta(t, api.GetTime().Unix(), time.Now().In(time.UTC).Unix(), float64(10))
api.SetTime(expected)
assert.Equal(t, expected, api.GetTime())
}
func TestEosioV1JsonFailure(t *testing.T) {
var srv = httptest.NewServer(http.HandlerFunc(func(res http.ResponseWriter, req *http.Request) {
res.Write([]byte(`!//{invalid-json}!##`))
}))
api := NewEosioV1(srv.URL, "", 120)
check, _ := api.Call()
expected := agentcheck.NewStatusMessageResponse(agentcheck.Failed, "")
assert.Equal(t, expected, check)
}
func TestEosioV1HTTP500Down(t *testing.T) {
var srv = httptest.NewServer(http.HandlerFunc(func(res http.ResponseWriter, req *http.Request) {
res.WriteHeader(500)
res.Write([]byte(`{}`))
}))
api := NewEosioV1(srv.URL, "", 120)
check, status := api.Call()
assert.Equal(t, "Taking offline because 500 was received from backend", status)
expected := agentcheck.NewStatusMessageResponse(agentcheck.Down, "")
assert.Equal(t, expected, check)
}
func TestEosioV1LaggingUp(t *testing.T) {
var srv = httptest.NewServer(http.HandlerFunc(func(res http.ResponseWriter, req *http.Request) {
if req.URL.String() == "/v1/chain/get_info" {
info := `{
"server_version": "8f613ec9",
"head_block_num": 7272812,
"head_block_time": "2022-02-24T13:37:00"
}`
res.Write([]byte(info))
}
}))
api := NewEosioV1(srv.URL, "", 60)
api.SetTime(time.Date(2022, 2, 24, 13, 38, 0, 0, time.UTC))
check, status := api.Call()
assert.Equal(t, "OK", status)
expected := agentcheck.NewStatusResponse(agentcheck.Up)
assert.Equal(t, expected, check)
}
func TestEosioV1LaggingDown(t *testing.T) {
var srv = httptest.NewServer(http.HandlerFunc(func(res http.ResponseWriter, req *http.Request) {
if req.URL.String() == "/v1/chain/get_info" {
info := `{
"server_version": "9a607cce",
"head_block_num": 87263,
"head_block_time": "2018-01-01T13:37:01"
}`
res.Write([]byte(info))
}
}))
api := NewEosioV1(srv.URL, "", 60)
api.SetTime(time.Date(2018, time.January, 1, 13, 38, 2, 0, time.UTC))
check, status := api.Call()
assert.Equal(t, "Taking offline because head block is lagging 61 seconds", status)
expected := agentcheck.NewStatusMessageResponse(agentcheck.Down, "")
assert.Equal(t, expected, check)
}
func TestEosioV1TimeInFutureUP(t *testing.T) {
var srv = httptest.NewServer(http.HandlerFunc(func(res http.ResponseWriter, req *http.Request) {
if req.URL.String() == "/v1/chain/get_info" {
info := `{
"server_version": "d1bec8d3",
"head_block_num": 548847,
"head_block_time": "2020-09-22T09:32:00"
}`
res.Write([]byte(info))
}
}))
api := NewEosioV1(srv.URL, "", 120)
api.SetTime(time.Date(2020, 9, 22, 9, 30, 0, 0, time.UTC))
check, status := api.Call()
assert.Equal(t, "OK", status)
expected := agentcheck.NewStatusResponse(agentcheck.Up)
assert.Equal(t, expected, check)
}
func TestEosioV1TimeInFutureDown(t *testing.T) {
var srv = httptest.NewServer(http.HandlerFunc(func(res http.ResponseWriter, req *http.Request) {
if req.URL.String() == "/v1/chain/get_info" {
info := `{
"server_version": "c879d231",
"head_block_num": 2637621,
"head_block_time": "2019-04-14T12:02:01"
}`
res.Write([]byte(info))
}
}))
api := NewEosioV1(srv.URL, "", 120)
api.SetTime(time.Date(2019, time.April, 14, 12, 0, 0, 0, time.UTC))
check, status := api.Call()
assert.Equal(t, "Taking offline because head block is -121 seconds into the future", status)
expected := agentcheck.NewStatusMessageResponse(agentcheck.Down, "")
assert.Equal(t, expected, check)
}

View file

@ -1,88 +0,0 @@
package api
import (
"fmt"
"github.com/eosswedenorg/eosio-api-healthcheck/src/utils"
"github.com/eosswedenorg-go/haproxy/agentcheck"
"github.com/eosswedenorg-go/eosapi"
)
type EosioV2 struct {
client eosapi.Client
offset int64
}
func NewEosioV2(url string, host string, offset int64) EosioV2 {
api := EosioV2{
client: *eosapi.New(url),
offset: offset,
}
api.client.Host = host
return api
}
func (e EosioV2) LogInfo() LogParams {
p := LogParams{
"type", "eosio-v2",
"url", e.client.Url,
}
if len(e.client.Host) > 0 {
p.Add("host", e.client.Host)
}
p.Add("offset", e.offset)
return p
}
func (e EosioV2) Call() (agentcheck.Response, string) {
health, err := e.client.GetHealth()
if err != nil {
resp := agentcheck.NewStatusMessageResponse(agentcheck.Failed, "")
return resp, err.Error()
}
// Check HTTP Status Code
if health.HTTPStatusCode > 299 {
resp := agentcheck.NewStatusMessageResponse(agentcheck.Down, "")
return resp, fmt.Sprintf("Taking offline because %v was received from backend", health.HTTPStatusCode)
}
// Fetch elasticsearch and nodeos block numbers from json.
var es_block int64 = 0
var node_block int64 = 0
for _, v := range health.Health {
if v.Name == "Elasticsearch" {
es_block = utils.JsonGetInt64(v.Data["last_indexed_block"])
} else if v.Name == "NodeosRPC" {
node_block = utils.JsonGetInt64(v.Data["head_block_num"])
}
}
// Error out if ether or both are zero.
if es_block == 0 || node_block == 0 {
msg := fmt.Sprintf("Failed to get Elasticsearch and/or nodeos " +
"block numbers (es: %d, eos: %d)", es_block, node_block)
resp := agentcheck.NewStatusMessageResponse(agentcheck.Failed, "")
return resp, msg
}
// Check if ES is behind or in the future.
diff := node_block - es_block;
if diff > e.offset {
resp := agentcheck.NewStatusMessageResponse(agentcheck.Down, "")
return resp, fmt.Sprintf("Taking offline because Elastic is %d blocks behind", diff)
} else if diff < -e.offset {
resp := agentcheck.NewStatusMessageResponse(agentcheck.Down, "")
return resp, fmt.Sprintf("Taking offline because Elastic is %d blocks into the future", -1 * diff)
}
return agentcheck.NewStatusResponse(agentcheck.Up), "OK"
}

View file

@ -1,15 +0,0 @@
package api
import (
"github.com/eosswedenorg-go/haproxy/agentcheck"
)
type ApiInterface interface {
// Returns Logging information
LogInfo() LogParams
// Call api and validate it's status.
Call() (agentcheck.Response, string)
}

View file

@ -1,12 +0,0 @@
package api
type LogParams []interface{}
func (p *LogParams) Add(field string, value interface{}) {
*p = append(*p, field, value)
}
func (p LogParams) ToSlice() []interface{} {
return []interface{}(p)
}

View file

@ -1,34 +0,0 @@
package api
import (
"testing"
"github.com/stretchr/testify/assert"
)
func TestLogParams(t *testing.T) {
type test_struct struct {
First string
Second int
}
p := LogParams{}
p.Add("one", 1)
p.Add("string", "str")
p.Add("struct", test_struct{First:"first_string",Second:1234})
expected := []interface{}([]interface {}{
"one",1,
"string","str",
"struct",test_struct{
First:"first_string",
Second:1234,
},
})
assert.Equal(t, expected, p.ToSlice())
}

View file

@ -1,185 +0,0 @@
package main
import (
"fmt"
"os"
"os/signal"
"syscall"
"github.com/eosswedenorg/eosio-api-healthcheck/src/utils"
log "github.com/inconshreveable/log15"
"github.com/eosswedenorg-go/pid"
"github.com/pborman/getopt/v2"
)
// Command line flags
// ---------------------------------------------------------
var logFile string
var pidFile string
// Global variables
// ---------------------------------------------------------
// Version string, should be updated by the go linker (by passing "-X main.VersionString=value" to the linker)
// see: https://pkg.go.dev/cmd/link and
var VersionString string = "-"
// File descriptor to the current log file.
var logfd *os.File
var logfmt log.Format
var logger log.Logger
// argv_listen_addr
// Parse listen address from command line.
// ---------------------------------------------------------
func argv_listen_addr() string {
var addr string
argv := getopt.Args()
if len(argv) > 0 {
addr = argv[0]
} else {
addr = "127.0.0.1"
}
addr += ":"
if len(argv) > 1 {
addr += argv[1]
} else {
addr += "1337"
}
return addr
}
func setLogFile() {
// Open file
fd, err := os.OpenFile(logFile, os.O_APPEND | os.O_CREATE | os.O_WRONLY, 0644)
if err != nil {
logger.Error(err.Error())
}
// Try close if old descriptor is defined.
if logfd != nil {
if err = logfd.Close(); err != nil {
logger.Error(err.Error())
}
}
// Update variable and set log writer.
logfd = fd
logger.SetHandler(log.StreamHandler(logfd, logfmt))
}
// signalEventLoop()
// Initialize event channel for OS signals
// and runs an event loop.
// ---------------------------------------------------------
func signalEventLoop() {
// Setup a channel
sig_ch := make(chan os.Signal, 1)
// subscribe to SIGHUP signal.
signal.Notify(sig_ch, syscall.SIGHUP, syscall.SIGINT, syscall.SIGTERM)
// Event loop
func() {
var run bool = true
for run {
// Block until we get a signal.
sig := <- sig_ch
l := logger.New("signal", sig)
switch sig {
case syscall.SIGINT, syscall.SIGTERM :
l.Info("Program was asked to terminate.")
run = false
// SIGHUP is sent when logfile is rotated.
case syscall.SIGHUP :
msg := "Logfile was rotated: "
if logfd != nil {
setLogFile()
msg += "Filedescriptor was updated"
} else {
msg += "No Filedescriptor to update (most likely uses standard out/err streams)"
}
l.Info(msg)
default:
l.Warn("Unknown signal")
}
}
}()
}
// main
// ---------------------------------------------------------
func main() {
var version bool
var usage bool
var addr string
var logFormatter *string
logger = log.New()
// Command line parsing
getopt.SetParameters("[ip] [port]")
getopt.FlagLong(&usage, "help", 'h', "Print this help text")
getopt.FlagLong(&version, "version", 'v', "Print version")
getopt.FlagLong(&logFile, "log", 'l', "Path to log file", "file")
getopt.FlagLong(&pidFile, "pid", 'p', "Path to pid file", "file")
logFormatter = getopt.EnumLong("log-format", 0, []string{"term", "logfmt", "json", "json-pretty"}, "", "Log format to use: term,logfmt,json,json-pretty")
getopt.Parse()
if usage {
getopt.Usage()
return
}
if version {
fmt.Printf("Version: %s\n", VersionString)
return;
}
logfmt = utils.ParseLogFormatter(*logFormatter)
// Open logfile.
if len(logFile) > 0 {
setLogFile()
} else {
logger.SetHandler(log.StreamHandler(os.Stdout, logfmt))
}
logger.Info("Process is starting", "pid", pid.Get())
if len(pidFile) > 0 {
logger.Info("Writing pidfile", "file", pidFile)
err := pid.Save(pidFile)
if err != nil {
logger.Error("Failed to write pidfile", "msg", err)
}
}
addr = argv_listen_addr()
// Start listening to TCP Connections
err := spawnTcpServer(addr)
if err == nil {
logger.Info("TCP Server started", "addr", addr)
// Run the signal event loop.
signalEventLoop()
} else {
log.Error("Failed to start tcp server", "error", err)
}
logger.Info("Shutdown")
}

View file

@ -1,66 +0,0 @@
package main
import (
"strings"
"fmt"
"strconv"
"github.com/eosswedenorg/eosio-api-healthcheck/src/api"
)
type arguments struct {
url string
host string
num_blocks int
}
func ParseArguments(args []string) arguments {
a := arguments{
num_blocks: 10,
}
// 1. url (scheme + ip/domain + port)
a.url = args[0]
// 2. num blocks
if len(args) > 1 {
num, err := strconv.ParseInt(args[1], 10, 32)
if err == nil {
a.num_blocks = int(num)
}
}
// 3. Host
if len(args) > 2 {
a.host = args[2]
}
return a
}
func ParseRequest(request string) (api.ApiInterface, error) {
// Parse arguments.
// -------------------
p := strings.Split(strings.TrimSpace(request), "|")
if len(p) < 2 {
return nil, fmt.Errorf("invalid number of parameters in agent request")
}
a := ParseArguments(p[1:])
switch p[0] {
case "v1":
return api.NewEosioV1(a.url, a.host, float64(a.num_blocks / 2)), nil
case "v2":
return api.NewEosioV2(a.url, a.host, int64(a.num_blocks)), nil
case "contract":
return api.NewEosioContract(a.url, float64(a.num_blocks / 2)), nil
case "debug":
return api.NewDebugApi(a.url), nil
}
return nil, fmt.Errorf("invalid API '%s'", p[0])
}

View file

@ -1,117 +0,0 @@
package main
import (
// "fmt"
"testing"
"github.com/stretchr/testify/assert"
"github.com/eosswedenorg/eosio-api-healthcheck/src/api"
)
func TestParseWithInvalidApi(t *testing.T) {
api, err := ParseRequest("invalid|http://api.example.com")
assert.Error(t, err)
assert.Equal(t, err.Error(), "invalid API 'invalid'")
assert.Nil(t, api)
}
func TestParseWithInvalidParams(t *testing.T) {
api, err := ParseRequest("v1")
assert.Error(t, err)
assert.Equal(t, err.Error(), "invalid number of parameters in agent request")
assert.Nil(t, api)
}
// EosioV1
// --------------------------------
func TestParseEosioV1(t *testing.T) {
expected := api.NewEosioV1("http://api.example.com", "", 5)
api, err := ParseRequest("v1|http://api.example.com")
assert.NoError(t, err)
assert.Equal(t, expected.LogInfo(), api.LogInfo())
}
func TestParseEosioV1WithBlockNumber(t *testing.T) {
expected := api.NewEosioV1("http://api.example.com", "", 1000)
api, err := ParseRequest("v1|http://api.example.com|2000")
assert.NoError(t, err)
assert.Equal(t, expected.LogInfo(), api.LogInfo())
}
func TestParseEosioV1Full(t *testing.T) {
expected := api.NewEosioV1("http://api.example.com", "http://host.example.com", 500)
api, err := ParseRequest("v1|http://api.example.com|1000|http://host.example.com")
assert.NoError(t, err)
assert.Equal(t, expected.LogInfo(), api.LogInfo())
}
// EosioV2
// --------------------------------
func TestParseEosioV2(t *testing.T) {
expected := api.NewEosioV2("http://api.v2.example.com", "", 10)
api, err := ParseRequest("v2|http://api.v2.example.com")
assert.NoError(t, err)
assert.Equal(t, expected.LogInfo(), api.LogInfo())
}
func TestParseEosioV2WithOffset(t *testing.T) {
expected := api.NewEosioV2("http://api.v2.example.com", "", 1000)
api, err := ParseRequest("v2|http://api.v2.example.com|1000")
assert.NoError(t, err)
assert.Equal(t, expected.LogInfo(), api.LogInfo())
}
func TestParseEosioV2Full(t *testing.T) {
expected := api.NewEosioV2("http://api.v2.example.com", "http://host.example.com", 1000)
api, err := ParseRequest("v2|http://api.v2.example.com|1000|http://host.example.com")
assert.NoError(t, err)
assert.Equal(t, expected.LogInfo(), api.LogInfo())
}
// EosioContract
// --------------------------------
func TestParseEosioContract(t *testing.T) {
expected := api.NewEosioContract("http://api.contract.example.com", 5)
api, err := ParseRequest("contract|http://api.contract.example.com")
assert.NoError(t, err)
assert.Equal(t, expected.LogInfo(), api.LogInfo())
}
func TestParseEosioContractWithBlockTime(t *testing.T) {
expected := api.NewEosioContract("http://api.contract.example.com", 256)
api, err := ParseRequest("contract|http://api.contract.example.com|512")
assert.NoError(t, err)
assert.Equal(t, expected.LogInfo(), api.LogInfo())
}
func TestParseDebugApi(t *testing.T) {
expected := api.NewDebugApi("some_api_call")
api, err := ParseRequest("debug|some_api_call")
assert.NoError(t, err)
assert.Equal(t, expected.LogInfo(), api.LogInfo())
}

View file

@ -1,53 +0,0 @@
package main
import (
"strings"
"github.com/eosswedenorg-go/haproxy/agentcheck"
"github.com/eosswedenorg-go/tcp_server"
)
// onTcpMessage callback function
// ---------------------------------------------------------
func onTcpMessage(c *tcp_server.Client, args string) {
// Check api.
// -------------------
healthCheckApi, err := ParseRequest(args)
if err != nil {
logger.Warn("Agent request error", "message", err)
resp := agentcheck.NewStatusMessageResponse(agentcheck.Failed, "")
c.WriteString(resp.String())
c.Close()
return
}
status, msg := healthCheckApi.Call()
logger.Info("API Check", append([]interface{}{
"status", strings.TrimSpace(status.String())},
healthCheckApi.LogInfo().ToSlice()...)...)
if msg != "OK" && len(msg) > 0 {
logger.Warn("API Check Failed", "message", msg)
}
// Report status to HAproxy
c.WriteString(status.String())
c.Close()
}
// spawnTcpServer
// ---------------------------------------------------------
func spawnTcpServer(addr string) error {
server := tcp_server.New(addr)
server.OnMessage(onTcpMessage)
err := server.Connect()
if err == nil {
go server.Listen()
}
return err
}

View file

@ -1,22 +0,0 @@
package utils
import "testing"
func TestJsonGetInt64(t *testing.T) {
tests := []struct {
name string
input interface{}
want int64
}{
{"String", "test", 0 },
{"Int", 1234, 0 },
{"Float", float64(1234), 1234 },
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
if got := JsonGetInt64(tt.input); got != tt.want {
t.Errorf("JsonGetInt64() = %v, want %v", got, tt.want)
}
})
}
}

View file

@ -1,20 +0,0 @@
package utils
import (
log "github.com/inconshreveable/log15"
)
func ParseLogFormatter(name string) log.Format {
switch name {
case "logfmt" :
return log.LogfmtFormat()
case "json" :
return log.JsonFormat()
case "json-pretty" :
return log.JsonFormatEx(true, true)
default :
return log.TerminalFormat()
}
}

View file

@ -1,29 +0,0 @@
package utils
import (
"reflect"
"testing"
log "github.com/inconshreveable/log15"
)
func Test_ParseLogFormatter(t *testing.T) {
tests := []struct {
name string
arg string
want log.Format
}{
{ "Default", "", log.TerminalFormat() },
{ "LogFmt", "logfmt", log.LogfmtFormat() },
{ "Json", "json", log.JsonFormat() },
{ "JsonPretty", "json-pretty", log.JsonFormat() },
{ "Unknown", "unknown", log.TerminalFormat() },
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
if got := ParseLogFormatter(tt.arg); reflect.ValueOf(got).Pointer() != reflect.ValueOf(tt.want).Pointer() {
t.Errorf("parseLogFormatter() = %v, want %v", got, tt.want)
}
})
}
}

View file

@ -1,22 +0,0 @@
package utils
import (
"time"
)
type Time struct {
ts time.Time
}
func (t *Time) SetTime(value time.Time) {
t.ts = value
}
func (t Time) GetTime() time.Time {
if ! t.ts.IsZero() {
return t.ts
}
return time.Now().In(time.UTC)
}

View file

@ -1,26 +0,0 @@
package utils
import (
"time"
"testing"
"github.com/stretchr/testify/assert"
)
func TestTimeGetTimeWithDefaultValue(t *testing.T) {
var ts Time
// Assert that time is NOW (+-10 seconds)
assert.InDelta(t, ts.GetTime().Unix(), time.Now().In(time.UTC).Unix(), float64(10))
}
func TestTimeGetTimeWithSetTime(t *testing.T) {
var ts Time
expected := time.Unix(1048722042, 500)
ts.SetTime(expected)
assert.Equal(t, expected, ts.GetTime())
}