Compare commits

...

15 Commits

Author SHA1 Message Date
Carlos Salguero
7809e2f39f PT-1857 Updated changelog 2020-12-23 14:19:33 -03:00
Carlos Salguero
c081a59e0d PT-1857 pt-heartbeat reconnect 2020-12-23 14:18:07 -03:00
Carlos Salguero
ff6b05b381 PT-1891 Fixed mongodb-summary connection with ssl (#469)
* PT-1891 Fixed mongodb-summary connection with ssl

- Added SSL connection options
- Fixed old tests
- Replaced gofmt by gofumpt in Makefile
- There are no ssl test for mongodb-summary because the current sandbox
doesnt support it

* PT-1891 Ran gofumports

* PMM-1891 Fixes for CR

* PT-1891 Decreased minimum TLS reqs for compatibility
2020-11-02 17:13:29 -03:00
Carlos Salguero
e731cf4d83 PT-1881 Updated changelog 2020-10-27 19:17:02 -03:00
Nayuta Yanagisawa
442a099268 PT-1881: Fix missing argument error of pt-upgrade (#461)
* Fix missing argument error of pt-upgrade

* Use print rather than printf
2020-10-27 19:15:21 -03:00
Jaroslav Musil
fc4e86928b [PMM-6756] Added go 1.15.x. (#468) 2020-10-19 15:22:08 +02:00
Carlos Salguero
03bd58e3a3 Updated changelog 2020-10-13 08:26:34 -03:00
Carlos Salguero
d7a7a1c7a5 PT-169 Handle drop-swap errors in pt-online-schema-change (#467)
* PT-169 Fixed drop-swap error handling

* PT-169 Fixed drop_swap error handling
2020-10-12 15:36:45 -03:00
Carlos Salguero
1090f017a1 Updated changelog 2020-09-30 11:06:15 -03:00
Carlos Salguero
a8ea8dfe56 PT-1892 Fixed sshd process recognition (#465) 2020-09-30 11:04:34 -03:00
Carlos Salguero
0aac7b4cfc PMM-6494 Topology labels (#463)
* PMM-6494 Topology labels

Added common functions needed for topology lables in mongo exporter and
pt-mongodb-summary

* PMM-5723 Fix reviewdog.

Co-authored-by: Nurlan Moldomurov <nurlan.moldomurov@percona.com>
2020-09-08 19:48:09 +03:00
Alexey Palazhchenko
d7ece0aecc Add go.mod (#464)
* Add go.mod

* Update github.com/shirou/gopsutil

* Use released version of dep

* Disable modules in CI for now

* PMM-5723 Fix reviewdog.

Co-authored-by: Nurlan Moldomurov <nurlan.moldomurov@percona.com>
2020-09-08 17:20:19 +03:00
PaulJacobs-percona
ff8b0aff84 Update release_notes.rst
Don't expose email
2020-08-17 10:03:26 +03:00
Paul Jacobs
db7dee46b6 3.2.1 RNs 2020-08-17 10:01:02 +03:00
PaulJacobs-percona
ecaaf4cc42 Merge pull request #460 from percona/release-3.2.1
3.2.1 release branch
2020-08-17 09:39:11 +03:00
55 changed files with 1792 additions and 272 deletions

View File

@@ -1,6 +1,7 @@
language: go
go:
- 1.15.x
- 1.14.x
- tip
@@ -9,6 +10,7 @@ services:
env:
global:
- GO111MODULE: "off" # TODO test with "on" too
- DOCKER_COMPOSE_VERSION: 1.8.0
- TEST_MONGODB_FLAVOR: mongo
- TEST_PSMDB_VERSION: 4.0
@@ -27,7 +29,7 @@ env:
- TEST_MONGODB_S2_SECONDARY1_PORT: 17005
- TEST_MONGODB_S2_SECONDARY2_PORT: 17006
- TEST_MONGODB_CONFIGSVR_RS: csReplSet
- TEST_MONGODB_CONFIGSVR1_PORT: 17007
- TEST_MONGODB_CONFIGSVR1_PORT: 17007
- TEST_MONGODB_CONFIGSVR2_PORT: 17008
- TEST_MONGODB_CONFIGSVR3_PORT: 17009
- TEST_MONGODB_S3_RS: rs3
@@ -35,10 +37,10 @@ env:
- TEST_MONGODB_S3_SECONDARY1_PORT: 17022
- TEST_MONGODB_S3_SECONDARY2_PORT: 17023
# REVIEWDOG_GITHUB_API_TOKEN
- secure: "px8XYeNEAFTSTb1hYZuEOxqOXUxvp3EoU+KCtPck/KNozkoS95eBd9klgr3Os4wPKloLdMhrr0VE98lukogUxA/NmnYnos01kegjWgwwM6fkob8JxaN5KK4oUFF1wmirBlrjGlw8vUErPwINmrK4BywKpDbw6Yip6FzxdlWESHI="
secure: "iba+2pzxc/zfMxnYki9qM9pCZs1uTEoqfPTaG9qtVr8cMutDzCJvMftn0bb6gSUrglt2mjSNhV65HX7mZl0qh8p/6a46QpzFiwZmaTH+E1tGQf97Z55tx3tHgrcoFI8LGPEHpTQehcI7V0VVo69aBhz+8lNNScOuJwt8ulyuVwE="
matrix:
include:
include:
- MONGODB_IMAGE=mongo:3.0
- MONGODB_IMAGE=mongo:3.2
- MONGODB_IMAGE=mongo:3.4
@@ -61,8 +63,9 @@ before_install:
- docker-compose --version
install:
- go get -u github.com/golang/dep/cmd/dep
# install reviewdog and golangci-lin
- curl https://raw.githubusercontent.com/golang/dep/master/install.sh | sh
# install reviewdog and golangci-lint
- curl https://raw.githubusercontent.com/reviewdog/reviewdog/master/install.sh| sh -s
- curl https://raw.githubusercontent.com/golangci/golangci-lint/master/install.sh | sh -s latest

View File

@@ -1,5 +1,11 @@
Changelog for Percona Toolkit
* Fixed bug PT-1857: pt-heartbeat cannot reconnect.
* Fixed bug PT-169 : pt-online-schema-change FKs error handling.
* Fixed bug PT-1892: pt-summary says sshd not running
* Fixed bug PT-1881: pt-upgrade fails when query including format strings and SQL errors is given (Thanks Nayuta Yanagisawa)
* Fixed bug PT-1859: pt-pg-summary fails for Postgres12 (Thanks Sergey Kuzmichev)
* Improvement PT-1853: Added --no-check-foreing-keys to pt-osc
* Improvement PT-1851: Backslashes missing from documentation

45
Gopkg.lock generated
View File

@@ -202,7 +202,15 @@
version = "v1.0.0"
[[projects]]
digest = "1:55dcddb2ba6ab25098ee6b96f176f39305f1fde7ea3d138e7e10bb64a5bf45be"
digest = "1:9d1d58facb0409ecf634fec680d83b6f57f4e619458f7b7b5e4dda1665fd89ec"
name = "github.com/prometheus/common"
packages = ["log"]
pruneopts = ""
revision = "f39dfa2b000545b3a763b844012958c275a62266"
version = "v0.13.0"
[[projects]]
digest = "1:9d35a914be9b807050704f377becb1f864ee46b000f590566a8b9fb871d6c571"
name = "github.com/shirou/gopsutil"
packages = [
"cpu",
@@ -212,16 +220,8 @@
"process",
]
pruneopts = ""
revision = "e4ec7b275ada47ca32799106c2dba142d96aaf93"
version = "v2.19.8"
[[projects]]
branch = "master"
digest = "1:99c6a6dab47067c9b898e8c8b13d130c6ab4ffbcc4b7cc6236c2cd0b1e344f5b"
name = "github.com/shirou/w32"
packages = ["."]
pruneopts = ""
revision = "bb4de0191aa41b5507caa14b0650cdbddcd9280b"
revision = "9aa2bee419e8b592ecf9f46018f3f1f6a5474c10"
version = "v2.20.8"
[[projects]]
digest = "1:1a405cddcf3368445051fb70ab465ae99da56ad7be8d8ca7fc52159d1c2d873c"
@@ -324,6 +324,8 @@
packages = [
"unix",
"windows",
"windows/registry",
"windows/svc/eventlog",
]
pruneopts = ""
revision = "749cb33beabd9aa6d3178e3de05bcc914f70b2bf"
@@ -343,6 +345,25 @@
revision = "342b2e1fbaa52c93f31447ad2c6abc048c63e475"
version = "v0.3.2"
[[projects]]
digest = "1:15d017551627c8bb091bde628215b2861bed128855343fdd570c62d08871f6e1"
name = "gopkg.in/alecthomas/kingpin.v2"
packages = ["."]
pruneopts = ""
revision = "947dcec5ba9c011838740e680966fd7087a71d0d"
version = "v2.2.6"
[[projects]]
branch = "v2"
digest = "1:e56755c5336ff37d20befca76df29097085c85ea1fe58af746e3df6b815decfa"
name = "gopkg.in/mgo.v2"
packages = [
"bson",
"internal/json",
]
pruneopts = ""
revision = "a6b53ec6cb22a3699387a57a161566f9402ee85b"
[[projects]]
branch = "v3"
digest = "1:2e9c4d6def1d36dcd17730e00c06b49a2e97ea5e1e639bcd24fa60fa43e33ad6"
@@ -368,6 +389,7 @@
"github.com/pborman/getopt",
"github.com/percona/go-mysql/query",
"github.com/pkg/errors",
"github.com/prometheus/common/log",
"github.com/shirou/gopsutil/process",
"github.com/sirupsen/logrus",
"github.com/stretchr/testify/assert",
@@ -377,6 +399,7 @@
"go.mongodb.org/mongo-driver/mongo",
"go.mongodb.org/mongo-driver/mongo/options",
"golang.org/x/crypto/ssh/terminal",
"gopkg.in/mgo.v2/bson",
]
solver-name = "gps-cdcl"
solver-version = 1

View File

@@ -24,4 +24,4 @@
[[constraint]]
name = "github.com/shirou/gopsutil"
version = "2.17.11"
version = "2.20.8"

View File

@@ -5947,6 +5947,7 @@ sub main {
$dbh->{InactiveDestroy} = 1; # Don't disconnect on fork
$dbh->{FetchHashKeyName} = 'NAME_lc';
$dbh->{mysql_auto_reconnect} = 1;
$dbh->do("USE `$db`");
# ########################################################################

View File

@@ -8788,6 +8788,7 @@ sub main {
my $flow_ctl_pr; # Progress for FlowControlWaiter
my $sys_load; # MySQLStatusWaiter object
my $sys_load_pr; # Progress for MySQLStatusWaiter object
my $process_error; # Used if drop_swap fails
if ( $o->get('execute') ) {
# #####################################################################
@@ -9150,7 +9151,7 @@ sub main {
}
# No child tables and --alter-fk-method wasn't specified,
# so nothing to do.
}
}
else {
print "Child tables:\n";
foreach my $child_table ( @$child_tables ) {
@@ -9414,6 +9415,9 @@ sub main {
. "cause MySQL error 1146 (42S02): \"Table $new_tbl->{name} "
. " doesn't exist\".\n";
}
elsif ($process_error) {
print "Not dropping new table because FKs processing has failed.\n";
}
else {
print ts("Dropping new table...\n");
print $sql, "\n" if $o->get('print');
@@ -10208,8 +10212,9 @@ sub main {
}
};
if ( $EVAL_ERROR ) {
# TODO: improve error message and handling.
_die("Error updating foreign key constraints: $EVAL_ERROR", ERROR_UPDATING_FKS);
#$oktorun = 0;
$process_error = "Error updating foreign key constraints: $EVAL_ERROR";
_die($process_error, ERROR_UPDATING_FKS);
}
# --plugin hook
@@ -10273,7 +10278,8 @@ sub main {
# ########################################################################
# Done.
# ########################################################################
$orig_tbl->{success} = 1; # flag for cleanup tasks
$orig_tbl->{success} = 1; # flag for cleanup tasks
$cleanup = undef; # exec cleanup tasks
# --plugin hook

View File

@@ -1278,7 +1278,7 @@ top_processes () { local PTFUNCNAME=top_processes;
notable_processes_info () { local PTFUNCNAME=notable_processes_info;
local format="%5s %+2d %s\n"
local sshd_pid=$(ps -eo pid,args | awk '$2 ~ /\/usr\/sbin\/sshd/ { print $1; exit }')
local sshd_pid=$(ps -eo pid,args | awk '$0 ~ /\/usr\/sbin\/sshd/ { print $1; exit }')
echo " PID OOM COMMAND"

View File

@@ -6159,7 +6159,7 @@ sub _print_failures {
foreach my $failure ( @$failures ) {
print "\n-- $failno.\n";
if ( ($failure->[1] || '') eq ($failure->[2] || '') ) {
printf "\nOn both hosts:\n\n" . ($failure->[1] || '') . "\n";
print "\nOn both hosts:\n\n" . ($failure->[1] || '') . "\n";
}
else {
printf "\n%s\n\nvs.\n\n%s\n",

View File

@@ -1,6 +1,28 @@
Percona Toolkit
***************
v3.2.1 released 2020-08-13
==========================
Improvements:
* :jirabug:`PT-1836`: Review and consider lintian reported issues (Thanks to user midget for reporting this issue)
Bugs Fixed:
* :jirabug:`PT-1853`: Added --no-check-foreign-keys to pt-osc
* :jirabug:`PT-1869`: pt-osc dynamically update slave list on check slaves (Thanks to user mateus.dubiela for reporting this issue)
* :jirabug:`PT-1829`: pt-heartbeat doesn't reconnect for check-read-only
* :jirabug:`PT-1822`: pt-mongodb-summary fails on standalone mongodb instances
* :jirabug:`PT-1851`: Backslashes missing from documentation (Thanks to user billkarwin for reporting this issue)
* :jirabug:`PT-1518`: pt-table-checksum gives error CRC32 never needs BIT_XOR optimization (Thanks to user soumya_s_das (AT homedepot DOT com) for reporting this issue)
* :jirabug:`PT-1859`: pt-pg-summary fails for Postgres12
v3.2.0 released 2020-04-23
==========================
@@ -59,7 +81,7 @@ Bugs Fixed:
v3.0.13 released 2019-01-03
===========================
@@ -445,7 +467,7 @@ New Features
* 1642994: Following schemas/tables have been added to the default ignore list: ``mysql.gtid_execution``, ``sys.sys_config``, ``mysql.proc``, ``mysql.inventory``, ``mysql.plugin``, ``percona.*`` (including checksums, dsns table), ``test.*``, and ``percona_schema.*``.
* 1643940: ``pt-summary`` now provides information about Transparent huge pages.
* 1643940: ``pt-summary`` now provides information about Transparent huge pages.
* 1604834: New ``--preserve-embedded-numbers`` option has been implemented for ``pt-query-digest`` which can be used to preserve numbers in database/table names when fingerprinting queries.
@@ -454,7 +476,7 @@ Bug Fixes
* 1613915: ``pt-online-schema-change`` could miss the data due to the way ENUM values are sorted.
* 1625005: ``pt-online-schema-change`` didn't apply underscores to foreign keys individually.
* 1566556: ``pt-show-grants`` didn't work correctly with *MariaDB* 10 (*Daniël van Eeden*).
* 1634900: ``pt-upgrade`` would fail when log contained ``SELECT...INTO`` queries.
@@ -469,19 +491,19 @@ Changelog
---------
* Fixed bug 1362942: pt-slave-restart fails on MariaDB 10.0.13 (gtid_mode confusion)
* Fixed bug 1566556: pt-show-grants fails against MariaDB10+
* Fixed bug 1566556: pt-show-grants fails against MariaDB10+
* Feature 1604834: pt-query-digest numbers in table or column names converted to question marks (--preserve-embedded-numbers)
* Fixed bug 1613915: pt-online-schema-change misses data. Fixed sort order for ENUM fields
* Fixed bug 1613915: pt-online-schema-change misses data. Fixed sort order for ENUM fields
* Fixed bug 1625005: pt-online-schema-change doesn't apply underscores to foreign keys individually
* Fixed bug 1634900: pt-upgrade fails with SELECT INTO
* Fixed bug 1635734: pt-slave-restart --config does not recognize = as separator
* Fixed bug 1634900: pt-upgrade fails with SELECT INTO
* Fixed bug 1635734: pt-slave-restart --config does not recognize = as separator
* Feature 1636068: Added pause to NibbleIterator
* Feature 1638293: --data-dir parameter in order to create the table on a different partition
* Feature 1639052: with pt-table-checksum automatically exclude checking schemas named percona, percona_schema
* Feature 1639052: with pt-table-checksum automatically exclude checking schemas named percona, percona_schema
* Feature 1642364: pt-online-schema-change Added --remove-data-dir feature
* Feature 1643914: Fixed several typos in the doc (Thanks Dario Minnucci)
* Feature 1643940: Add Transparent huge pages info to pt-summary
* Feature 1643941: Add Memory management library to pt-mysql-summary
* Feature 1643941: Add Memory management library to pt-mysql-summary
v2.2.19 released 2016-08-16
===========================
@@ -548,7 +570,7 @@ New features:
* 1553340: Added "Shared" memory info to ``pt-summary``
* PT-24: Added the ``--no-vertical-format`` option for ``pt-query-digest``, allowing compatibility with non-standard MySQL clients that don't support the ``\G`` directive at the end of a statement
Bug fixes:
* 1402776: Fixed error when parsing ``tcpdump`` capture with ``pt-query-digest``
@@ -674,7 +696,7 @@ v2.2.15 released 2015-08-28
This feature was requested in the following bugs: 1413101 and 1413137.
* Added the ``--sleep`` option for ``pt-online-schema-change`` to avoid performance problems. The option accepts float values in seconds.
This feature was requested in the following bug: 1413140.
* Implemented ability to specify ``--check-slave-lag`` multiple times. The following example enables lag checks for two slaves:
@@ -686,69 +708,69 @@ v2.2.15 released 2015-08-28
This feature was requested in the following bug: 14452911.
* Added the ``--rds`` option to ``pt-kill``, which makes the tool use Amazon RDS procedure calls instead of the standard MySQL ``kill`` command.
This feature was requested in the following bug: 1470127.
**Bugs Fixed**
* 1042727: ``pt-table-checksum`` doesn't reconnect the slave $dbh
Before, the tool would die if any slave connection was lost. Now the tool waits forever for slaves.
* 1056507: ``pt-archiver --check-slave-lag`` agressiveness
The tool now checks replication lag every 100 rows instead of every row, which significantly improves efficiency.
* 1215587: Adding underscores to constraints when using ``pt-online-schema-change`` can create issues with constraint name length
Before, multiple schema changes lead to underscores stacking up on the name of the constraint until it reached the 64 character limit. Now there is a limit of two underscores in the prefix, then the tool alternately removes or adds one underscore, attempting to make the name unique.
* 1277049: ``pt-online-schema-change`` can't connect with comma in password
For all tools, documented that commas in passwords provided on the command line must be escaped.
* 1441928: Unlimited chunk size when using ``pt-online-schema-change`` with ``--chunk-size-limit=0`` inhibits checksumming of single-nibble tables
When comparing table size with the slave table, the tool now ignores ``--chunk-size-limit`` if it is set to zero to avoid multiplying by zero.
* 1443763: Update documentation and/or implentation of ``pt-archiver --check-interval``
Fixed the documentation for ``--check-interval`` to reflect its correct behavior.
* 1449226: ``pt-archiver`` dies with "MySQL server has gone away" when ``--innodb_kill_idle_transaction`` is set to a low value and ``--check-slave-lag`` is enabled
The tool now sends a dummy SQL query to avoid timing out.
The tool now sends a dummy SQL query to avoid timing out.
* 1446928: ``pt-online-schema-change`` not reporting meaningful errors
The tool now produces meaningful errors based on text from MySQL errors.
* 1450499: ReadKeyMini causes ``pt-online-schema-change`` session to lock under some circumstances
Removed ReadKeyMini, because it is no longer necessary.
* 1452914: ``--purge`` and ``--no-delete`` are mutually exclusive, but still allowed to be specified together by ``pt-archiver``
The tool now issues an error when ``--purge`` and ``--no-delete`` are specified together
* 1455486: ``pt-mysql-summary`` is missing the ``--ask-pass`` option
Added the ``--ask-pass`` option to the tool
* 1457573: ``pt-sift`` fails to download ``pt-diskstats`` ``pt-pmp`` ``pt-mext`` ``pt-align``
Added the ``-L`` option to ``curl`` and changed download address to use HTTPS.
* 1462904: ``pt-duplicate-key-checker`` doesn't support triple quote in column name
Updated TableParser module to handle literal backticks.
* 1488600: ``pt-stalk`` doesn't check TokuDB status
Implemented status collection similar to how it is performed for InnoDB.
* 1488611: various testing bugs related to newer perl versions
Fixed test failures related to new Perl versions.
v2.2.14 released 2015-04-14
@@ -758,7 +780,7 @@ Percona Toolkit 2.2.14 has been released. This release contains two new features
New Features:
* pt-slave-find can now resolve the IP address and show the slave's hostname. This can be done with the new ``--resolve-address`` option.
* pt-slave-find can now resolve the IP address and show the slave's hostname. This can be done with the new ``--resolve-address`` option.
* pt-table-sync can now ignore the tables whose names match specific Perl regex with the ``--ignore-tables-regex`` option.
@@ -778,7 +800,7 @@ Bugs Fixed:
* Fixed bug 1417558: pt-stalk when used along with ``--collect-strace`` didn't write the strace output to the expected destination file.
* Fixed bug 1421025: Missing dependency for ``perl-TermReadKey`` RPM package was causing toolkit commands to fail when they were run with ``--ask-pass`` option.
* Fixed bug 1421025: Missing dependency for ``perl-TermReadKey`` RPM package was causing toolkit commands to fail when they were run with ``--ask-pass`` option.
* Fixed bug 1421781: pt-upgrade would fail when log contained ``SELECT...INTO`` queries. Fixed by ignoring/skipping those queries.
@@ -815,11 +837,11 @@ Percona Toolkit 2.2.13 has been released. This release contains one new feature
New Features:
* pt-kill now supports new ``--query-id`` option. This option can be used to print a query fingerprint hash after killing a query to enable the cross-referencing with the pt-query-digest output. This option can be used along with ``--print`` option as well.
* pt-kill now supports new ``--query-id`` option. This option can be used to print a query fingerprint hash after killing a query to enable the cross-referencing with the pt-query-digest output. This option can be used along with ``--print`` option as well.
Bugs Fixed:
* Fixed bug 1019479: pt-table-checksum now works with ``ONLY_FULL_GROUP_BY`` sql_mode.
* Fixed bug 1019479: pt-table-checksum now works with ``ONLY_FULL_GROUP_BY`` sql_mode.
* Fixed bug 1394934: running pt-table-checksum in debug mode would cause an error.
@@ -829,9 +851,9 @@ Bugs Fixed:
* Fixed bug 1408375: Percona Toolkit was vulnerable to MITM attack which could allow exfiltration of MySQL configuration information via ``--version-check`` option. This vulnerability was logged as `CVE 2015-1027 <http://www.cve.mitre.org/cgi-bin/cvename.cgi?name=2015-1027>_`
* Fixed bug 1321297: pt-table-checksum was reporting differences on timestamp columns with replication from 5.5 to 5.6 server version, although the data was identical.
* Fixed bug 1321297: pt-table-checksum was reporting differences on timestamp columns with replication from 5.5 to 5.6 server version, although the data was identical.
* Fixed bug 1388870: pt-table-checksum was showing differences if the master and slave were in different time zone.
* Fixed bug 1388870: pt-table-checksum was showing differences if the master and slave were in different time zone.
* Fixed bug 1402668: pt-mysql-summary would exit if Percona XtraDB Cluster was in ``Donor/Desynced`` state.
@@ -840,19 +862,19 @@ Bugs Fixed:
Changelog
---------
* Feature 1391240: pt-kill added query fingerprint hash to output
* Fixed bug 1402668: pt-mysql-summary fails on cluster in Donor/Desynced status
* Fixed bug 1396870: pt-online-schema-change CTRL+C leaves terminal in inconsistent state
* Feature 1391240: pt-kill added query fingerprint hash to output
* Fixed bug 1402668: pt-mysql-summary fails on cluster in Donor/Desynced status
* Fixed bug 1396870: pt-online-schema-change CTRL+C leaves terminal in inconsistent state
* Fixed bug 1396868: pt-online-schema-change --ask-pass option error
* Fixed bug 1266869: pt-stalk fails to start if $HOME environment variable is not set
* Fixed bug 1266869: pt-stalk fails to start if $HOME environment variable is not set
* Fixed bug 1019479: pt-table-checksum does not work with sql_mode ONLY_FULL_GROUP_BY
* Fixed bug 1394934: pt-table-checksum error in debug mode
* Fixed bug 1321297: pt-table-checksum reports diffs on timestamp columns in 5.5 vs 5.6
* Fixed bug 1321297: pt-table-checksum reports diffs on timestamp columns in 5.5 vs 5.6
* Fixed bug 1399789: pt-table-checksum fails to find pxc nodes when wsrep_node_incoming_address is set to AUTO
* Fixed bug 1388870: pt-table-checksum has some errors with different time zones
* Fixed bug 1408375: vulnerable to MITM attack which would allow exfiltration of MySQL configuration information via --version-check
* Fixed bug 1404298: missing MySQL5.7 test files for pt-table-checksum
* Fixed bug 1403900: added sandbox and fixed sakila test db for 5.7
* Fixed bug 1404298: missing MySQL5.7 test files for pt-table-checksum
* Fixed bug 1403900: added sandbox and fixed sakila test db for 5.7
v2.2.12 released 2014-11-14
===========================
@@ -861,7 +883,7 @@ Percona Toolkit 2.2.12 has been released. This release contains one new feature
New Features:
* pt-stalk now gathers ``dmesg`` output from up to 60 seconds before the triggering event.
* pt-stalk now gathers ``dmesg`` output from up to 60 seconds before the triggering event.
Bugs Fixed:
@@ -873,7 +895,7 @@ Bugs Fixed:
* Fixed bug 1328686: Running pt-hearbeat with --check-read-only option would cause an error when running on server with ``read_only`` option. Tool now waits for server ``read_only`` status to be disabled before starting to run.
* Fixed bug 1373937: pt-table-checksum now supports ``none`` as valid ``--recursion-method`` when using with Percona XtraDB Cluster.
* Fixed bug 1373937: pt-table-checksum now supports ``none`` as valid ``--recursion-method`` when using with Percona XtraDB Cluster.
* Fixed bug 1377888: Documentation was stating that pt-query-digest is able to parse a raw binary log file, while it can only parse a file which was decoded with ``mysqlbinlog`` tool before. Fixed by improving the documentation and adding a check for binary file and providing a relevant error message.
@@ -886,7 +908,7 @@ Changelog
* Fixed bug 1217466: pt-table-checksum refuses to run on PXC if server_id is the same on all nodes
* Fixed bug 1373937: pt-table-checksum requires recursion when working with and XtraDB Cluster node
* Fixed bug 1377888: pt-query-digest manual for --type binlog is ambiguous
* Fixed bug 1349086: pt-stalk should also gather dmesg output
* Fixed bug 1349086: pt-stalk should also gather dmesg output
* Fixed bug 1361293: Some scripts fail when no-version-check option is put in global config file
v2.2.11 released 2014-09-26
@@ -939,12 +961,12 @@ Bugs Fixed:
Changelog
---------
* Fixed bug 1287253: pt-table-checksum deadlock
* Fixed bug 1287253: pt-table-checksum deadlock
* Fixed bug 1299387: 5.6 slow query log Thead_id becomes Id
* Fixed bug 1311654: pt-table-checksum + PXC inconsistent results upon --resume
* Fixed bug 1340728: pt-online-schema-change doesn't work with HASH indexes
* Fixed bug 1253872: pt-table-checksum max load 20% rounds down
* Fixed bug 1340364: some shell tools output error when queried for --version
* Fixed bug 1340364: some shell tools output error when queried for --version
v2.2.9 released 2014-07-08
==========================
@@ -967,10 +989,10 @@ Changelog
---------
* Fixed bug 1258135: pt-deadlock-logger introduces a noise to MySQL
* Fixed bug 1329422: pt-online-schema-change foreign-keys-method=none breaks constraints
* Fixed bug 1315130: pt-online-schema-change not properly detecting foreign keys
* Fixed bug 1329422: pt-online-schema-change foreign-keys-method=none breaks constraints
* Fixed bug 1315130: pt-online-schema-change not properly detecting foreign keys
* Fixed bug 1335960: pt-query-digest cannot parse binlogs from 5.6
* Fixed bug 1335322: pt-stalk fails when variable or threshold is non-integer
* Fixed bug 1335322: pt-stalk fails when variable or threshold is non-integer
v2.2.8 released 2014-06-04
==========================
@@ -992,7 +1014,7 @@ Bugs Fixed:
* Fixed bug 1286250: pt-online-schema-change was requesting password twice.
* Fixed bug 1295667: pt-deadlock-logger was logging incorrect timestamp because tool wasn't aware of the time-zones.
* Fixed bug 1295667: pt-deadlock-logger was logging incorrect timestamp because tool wasn't aware of the time-zones.
* Fixed bug 1304062: when multiple tables were specified with pt-table-checksum --ignore-tables, only one of them would be ignored.
@@ -1016,7 +1038,7 @@ Changelog
v2.2.7 released 2014-02-20
==========================
Percona Toolkit 2.2.7 has been released. This release has only one bug fix.
Percona Toolkit 2.2.7 has been released. This release has only one bug fix.
* Fixed bug 1279502: --version-check behaves like spyware
@@ -1130,9 +1152,9 @@ Changelog
v2.2.4 released 2013-07-18
==========================
Percona Toolkit 2.2.4 has been released. This release two new features and a number of bugfixes.
Percona Toolkit 2.2.4 has been released. This release two new features and a number of bugfixes.
pt-query-digest --output json includes query examples as of v2.2.3. Some people might not want this because it exposes real data. New option, --output json-anon, has been implemented. This option will provide the same data without query examples. It's "anonymous" in the sense that there's no identifying data; nothing more than schema and table structs can be inferred from fingerprints.
pt-query-digest --output json includes query examples as of v2.2.3. Some people might not want this because it exposes real data. New option, --output json-anon, has been implemented. This option will provide the same data without query examples. It's "anonymous" in the sense that there's no identifying data; nothing more than schema and table structs can be inferred from fingerprints.
When using drop swap with pt-online-schema-change there is some production impact. This impact can be measured because tool outputs the current timestamp on lines for operations that may take awhile.
@@ -1140,7 +1162,7 @@ When using drop swap with pt-online-schema-change there is some production impac
pt-table-checksum would fail if variable explicit_defaults_for_timestamp was enabled in MySQL 5.6.
* Fixed bug #1182856: Zero values causes "Invalid --set-vars value: var=0"
Trying to assign 0 to any variable by using --set-vars option would cause “Invalid --set-vars value” message.
Trying to assign 0 to any variable by using --set-vars option would cause “Invalid --set-vars value” message.
* Fixed bug #1188264: pt-online-schema-change error copying rows: Undefined subroutine &pt_online_schema_change::get
@@ -1844,7 +1866,7 @@ Changelog
* Fixed bug 954990: pt-stalk --nostalk does not work
* Fixed bug 977226: pt-summary doesn't detect LSI RAID control
* Fixed bug 1030031: pt-table-checksum reports wrong number of DIFFS
* Fixed bug 916168: pt-table-checksum privilege check fails on MySQL 5.5
* Fixed bug 916168: pt-table-checksum privilege check fails on MySQL 5.5
* Fixed bug 950294: pt-table-checksum should always create schema and tables with IF NOT EXISTS
* Fixed bug 953141: pt-table-checksum ignores its default and explicit --recursion-method
* Fixed bug 1030975: pt-table-sync crashes if sql_mode includes ANSI_QUOTES
@@ -2204,7 +2226,7 @@ Changelog
* Fixed bug 1402776: Improved fix (protocol parser fix): error when parsing tcpdump capture with pt-query-digest
* Fixed bug 1632522: pt-osc: Fails with duplicate key in table for self-referencing (Thanks Amiel Marqeta)
* Fixed bug 1654668: pt-summary exists with an error (Thanks Marcelo Altmann)
* New tool : pt-mongodb-summary
* New tool : pt-mongodb-summary
* New tool : pt-mongodb-query-digest
Percona Toolkit 3.0.0 RC includes the following changes:

28
docs/rn.3-2-1.txt Normal file
View File

@@ -0,0 +1,28 @@
.. _PT-3.2.1:
================================================================================
*Percona Toolkit* 3.2.1
================================================================================
:Date: August 13, 2020
:Installation: `Installing Percona Toolkit <https://www.percona.com/doc/percona-toolkit/LATEST/installation.html>`_
Improvements
================================================================================
* :jirabug:`PT-1836`: Review and consider lintian reported issues (Thanks to user midget for reporting this issue)
Bugs Fixed
================================================================================
* :jirabug:`PT-1853`: Added --no-check-foreign-keys to pt-osc
* :jirabug:`PT-1869`: pt-osc dynamically update slave list on check slaves (Thanks to user mateus.dubiela for reporting this issue)
* :jirabug:`PT-1829`: pt-heartbeat doesn't reconnect for check-read-only
* :jirabug:`PT-1822`: pt-mongodb-summary fails on standalone mongodb instances
* :jirabug:`PT-1851`: Backslashes missing from documentation (Thanks to user billkarwin for reporting this issue)
* :jirabug:`PT-1518`: pt-table-checksum gives error CRC32 never needs BIT_XOR optimization (Thanks to user soumya_s_das@homedepot.com for reporting this issue)
* :jirabug:`PT-1859`: pt-pg-summary fails for Postgres12

40
go.mod Normal file
View File

@@ -0,0 +1,40 @@
module github.com/percona/percona-toolkit
go 1.14
require (
github.com/Masterminds/semver v1.4.2
github.com/StackExchange/wmi v0.0.0-20180116203802-5d049714c4a6 // indirect
github.com/alecthomas/kingpin v2.2.6+incompatible
github.com/go-ini/ini v1.46.0
github.com/go-ole/go-ole v1.2.4 // indirect
github.com/golang/mock v1.3.1-0.20190508161146-9fa652df1129
github.com/golang/snappy v0.0.2-0.20190904063534-ff6b7dc882cf // indirect
github.com/google/go-cmp v0.5.2 // indirect
github.com/google/uuid v1.1.1
github.com/hashicorp/go-version v1.2.1-0.20190424083514-192140e6f3e6
github.com/howeyc/gopass v0.0.0-20170109162249-bf9dde6d0d2c
github.com/klauspost/compress v1.10.10 // indirect
github.com/lib/pq v1.2.0
github.com/mattn/go-shellwords v1.0.6
github.com/montanaflynn/stats v0.0.0-20171201202039-1bf9dbcd8cbe
github.com/pborman/getopt v0.0.0-20190409184431-ee0cd42419d3
github.com/percona/go-mysql v0.0.0-20190903141930-197f4ad8db8d
github.com/pkg/errors v0.9.1
github.com/prometheus/common v0.13.0
github.com/shirou/gopsutil v2.20.8+incompatible
github.com/sirupsen/logrus v1.6.0
github.com/stretchr/testify v1.6.1
github.com/xdg/stringprep v1.0.1-0.20180714160509-73f8eece6fdc // indirect
go.mongodb.org/mongo-driver v1.3.4
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9
golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9 // indirect
golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f // indirect
golang.org/x/text v0.3.3 // indirect
golang.org/x/tools v0.0.0-20201023174141-c8cfbd0f21e6 // indirect
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 // indirect
gopkg.in/ini.v1 v1.61.0 // indirect
gopkg.in/mgo.v2 v2.0.0-20190816093944-a6b53ec6cb22
gopkg.in/yaml.v3 v3.0.0-20200615113413-eeeca48fe776 // indirect
mvdan.cc/gofumpt v0.0.0-20200927160801-5bfeb2e70dd6 // indirect
)

539
go.sum Normal file
View File

@@ -0,0 +1,539 @@
cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
github.com/Knetic/govaluate v3.0.1-0.20171022003610-9aa49832a739+incompatible/go.mod h1:r7JcOSlj0wfOMncg0iLm8Leh48TZaKVeNIfJntJ2wa0=
github.com/Masterminds/semver v1.4.2 h1:WBLTQ37jOCzSLtXNdoo8bNM8876KhNqOKvrlGITgsTc=
github.com/Masterminds/semver v1.4.2/go.mod h1:MB6lktGJrhw8PrUyiEoblNEGEQ+RzHPF078ddwwvV3Y=
github.com/Shopify/sarama v1.19.0/go.mod h1:FVkBWblsNy7DGZRfXLU0O9RCGt5g3g3yEuWXgklEdEo=
github.com/Shopify/toxiproxy v2.1.4+incompatible/go.mod h1:OXgGpZ6Cli1/URJOF1DMxUHB2q5Ap20/P/eIdh4G0pI=
github.com/StackExchange/wmi v0.0.0-20180116203802-5d049714c4a6 h1:fLjPD/aNc3UIOA6tDi6QXUemppXK3P9BI7mr2hd6gx8=
github.com/StackExchange/wmi v0.0.0-20180116203802-5d049714c4a6/go.mod h1:3eOhrUMpNV+6aFIbp5/iudMxNCF27Vw2OZgy4xEx0Fg=
github.com/VividCortex/gohistogram v1.0.0/go.mod h1:Pf5mBqqDxYaXu3hDrrU+w6nw50o/4+TcAqDqk/vUH7g=
github.com/afex/hystrix-go v0.0.0-20180502004556-fa1af6a1f4f5/go.mod h1:SkGFH1ia65gfNATL8TAiHDNxPzPdmEL5uirI2Uyuz6c=
github.com/alecthomas/kingpin v2.2.6+incompatible h1:5svnBTFgJjZvGKyYBtMB0+m5wvrbUHiqye8wRJMlnYI=
github.com/alecthomas/kingpin v2.2.6+incompatible/go.mod h1:59OFYbFVLKQKq+mqrL6Rw5bR0c3ACQaawgXx0QYndlE=
github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc=
github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751 h1:JYp7IbQjafoB+tBA3gMyHYHrpOtNuDiK/uB5uXxq5wM=
github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc=
github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0=
github.com/alecthomas/units v0.0.0-20190717042225-c3de453c63f4 h1:Hs82Z41s6SdL1CELW+XaDYmOH4hkBN4/N9og/AsOv7E=
github.com/alecthomas/units v0.0.0-20190717042225-c3de453c63f4/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0=
github.com/alecthomas/units v0.0.0-20190924025748-f65c72e2690d h1:UQZhZ2O0vMHr2cI+DC1Mbh0TJxzA3RcLoMsFw+aXw7E=
github.com/alecthomas/units v0.0.0-20190924025748-f65c72e2690d/go.mod h1:rBZYJk541a8SKzHPHnH3zbiI+7dagKZ0cgpgrD7Fyho=
github.com/apache/thrift v0.12.0/go.mod h1:cp2SuWMxlEZw2r+iP2GNCdIi4C1qmUzdZFSVb+bacwQ=
github.com/apache/thrift v0.13.0/go.mod h1:cp2SuWMxlEZw2r+iP2GNCdIi4C1qmUzdZFSVb+bacwQ=
github.com/armon/circbuf v0.0.0-20150827004946-bbbad097214e/go.mod h1:3U/XgcO3hCbHZ8TKRvWD2dDTCfh9M9ya+I9JpbB7O8o=
github.com/armon/go-metrics v0.0.0-20180917152333-f0300d1749da/go.mod h1:Q73ZrmVTwzkszR9V5SSuryQ31EELlFMUz1kKyl939pY=
github.com/armon/go-radix v0.0.0-20180808171621-7fddfc383310/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8=
github.com/aryann/difflib v0.0.0-20170710044230-e206f873d14a/go.mod h1:DAHtR1m6lCRdSC2Tm3DSWRPvIPr6xNKyeHdqDQSQT+A=
github.com/aws/aws-lambda-go v1.13.3/go.mod h1:4UKl9IzQMoD+QF79YdCuzCwp8VbmG4VAQwij/eHl5CU=
github.com/aws/aws-sdk-go v1.27.0/go.mod h1:KmX6BPdI08NWTb3/sm4ZGu5ShLoqVDhKgpiN924inxo=
github.com/aws/aws-sdk-go-v2 v0.18.0/go.mod h1:JWVYvqSMppoMJC0x5wdwiImzgXTI9FuZwxzkQq9wy+g=
github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q=
github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8=
github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw=
github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs=
github.com/casbin/casbin/v2 v2.1.2/go.mod h1:YcPU1XXisHhLzuxH9coDNf2FbKpjGlbCg3n9yuLkIJQ=
github.com/cenkalti/backoff v2.2.1+incompatible/go.mod h1:90ReRw6GdpyfrHakVjL/QHaoyV4aDUVVkXQJJJ3NXXM=
github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU=
github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
github.com/clbanning/x2j v0.0.0-20191024224557-825249438eec/go.mod h1:jMjuTZXRI4dUb/I5gc9Hdhagfvm9+RyrPryS/auMzxE=
github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=
github.com/cockroachdb/datadriven v0.0.0-20190809214429-80d97fb3cbaa/go.mod h1:zn76sxSg3SzpJ0PPJaLDCu+Bu0Lg3sKTORVIj19EIF8=
github.com/codahale/hdrhistogram v0.0.0-20161010025455-3a0bb77429bd/go.mod h1:sE/e/2PUdi/liOCUjSTXgM1o87ZssimdTWN964YiIeI=
github.com/coreos/go-semver v0.2.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk=
github.com/coreos/go-systemd v0.0.0-20180511133405-39ca1b05acc7/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4=
github.com/coreos/pkg v0.0.0-20160727233714-3ac0863d7acf/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA=
github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU=
github.com/creack/pty v1.1.7/go.mod h1:lj5s0c3V2DBrqTV7llrYr5NG6My20zk30Fl46Y7DoTY=
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/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ=
github.com/dustin/go-humanize v0.0.0-20171111073723-bb3d318650d4/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk=
github.com/eapache/go-resiliency v1.1.0/go.mod h1:kFI+JgMyC7bLPUVY133qvEBtVayf5mFgVsvEsIPBvNs=
github.com/eapache/go-xerial-snappy v0.0.0-20180814174437-776d5712da21/go.mod h1:+020luEh2TKB4/GOp8oxxtq0Daoen/Cii55CzbTV6DU=
github.com/eapache/queue v1.1.0/go.mod h1:6eCeP0CKFpHLu8blIFXhExK/dRa7WDZfr6jVFPTqq+I=
github.com/edsrzf/mmap-go v1.0.0/go.mod h1:YO35OhQPt3KJa3ryjFM5Bs14WD66h8eGKpfaBNrHW5M=
github.com/envoyproxy/go-control-plane v0.6.9/go.mod h1:SBwIajubJHhxtWwsL9s8ss4safvEdbitLhGGK48rN6g=
github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c=
github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4=
github.com/franela/goblin v0.0.0-20200105215937-c9ffbefa60db/go.mod h1:7dvUGVsVBjqR7JHJk0brhHOZYGmfBYOrK0ZhYMEtBr4=
github.com/franela/goreq v0.0.0-20171204163338-bcd34c9993f8/go.mod h1:ZhphrRTfi2rbfLwlschooIH4+wKKDR4Pdxhh+TRoA20=
github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04=
github.com/go-ini/ini v1.46.0 h1:hDJFfs/9f75875scvqLkhNB5Jz5/DybKEOZ5MLF+ng4=
github.com/go-ini/ini v1.46.0/go.mod h1:ByCAeIL28uOIIG0E3PJtZPDL8WnHpFKFOtgjp+3Ies8=
github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as=
github.com/go-kit/kit v0.9.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as=
github.com/go-kit/kit v0.10.0/go.mod h1:xUsJbQ/Fp4kEt7AFgCuvyX4a71u8h9jB8tj/ORgOZ7o=
github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE=
github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk=
github.com/go-logfmt/logfmt v0.5.0/go.mod h1:wCYkCAKZfumFQihp8CzCvQ3paCTfi41vtzG1KdI/P7A=
github.com/go-ole/go-ole v1.2.4 h1:nNBDSCOigTSiarFpYE9J/KtEA1IOW4CNeqT9TQDqCxI=
github.com/go-ole/go-ole v1.2.4/go.mod h1:XCwSNxSkXRo4vlyPy93sltvi/qJq0jqQhjqQNIwKuxM=
github.com/go-sql-driver/mysql v1.4.0/go.mod h1:zAC/RDZ24gD3HViQzih4MyKcchzm+sOG5ZlKdlhCg5w=
github.com/go-stack/stack v1.8.0 h1:5SgMzNM5HxrEjV0ww2lTmX6E2Izsfxas4+YHWRs3Lsk=
github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY=
github.com/gobuffalo/attrs v0.0.0-20190224210810-a9411de4debd/go.mod h1:4duuawTqi2wkkpB4ePgWMaai6/Kc6WEz83bhFwpHzj0=
github.com/gobuffalo/depgen v0.0.0-20190329151759-d478694a28d3/go.mod h1:3STtPUQYuzV0gBVOY3vy6CfMm/ljR4pABfrTeHNLHUY=
github.com/gobuffalo/depgen v0.1.0/go.mod h1:+ifsuy7fhi15RWncXQQKjWS9JPkdah5sZvtHc2RXGlg=
github.com/gobuffalo/envy v1.6.15/go.mod h1:n7DRkBerg/aorDM8kbduw5dN3oXGswK5liaSCx4T5NI=
github.com/gobuffalo/envy v1.7.0/go.mod h1:n7DRkBerg/aorDM8kbduw5dN3oXGswK5liaSCx4T5NI=
github.com/gobuffalo/flect v0.1.0/go.mod h1:d2ehjJqGOH/Kjqcoz+F7jHTBbmDb38yXA598Hb50EGs=
github.com/gobuffalo/flect v0.1.1/go.mod h1:8JCgGVbRjJhVgD6399mQr4fx5rRfGKVzFjbj6RE/9UI=
github.com/gobuffalo/flect v0.1.3/go.mod h1:8JCgGVbRjJhVgD6399mQr4fx5rRfGKVzFjbj6RE/9UI=
github.com/gobuffalo/genny v0.0.0-20190329151137-27723ad26ef9/go.mod h1:rWs4Z12d1Zbf19rlsn0nurr75KqhYp52EAGGxTbBhNk=
github.com/gobuffalo/genny v0.0.0-20190403191548-3ca520ef0d9e/go.mod h1:80lIj3kVJWwOrXWWMRzzdhW3DsrdjILVil/SFKBzF28=
github.com/gobuffalo/genny v0.1.0/go.mod h1:XidbUqzak3lHdS//TPu2OgiFB+51Ur5f7CSnXZ/JDvo=
github.com/gobuffalo/genny v0.1.1/go.mod h1:5TExbEyY48pfunL4QSXxlDOmdsD44RRq4mVZ0Ex28Xk=
github.com/gobuffalo/gitgen v0.0.0-20190315122116-cc086187d211/go.mod h1:vEHJk/E9DmhejeLeNt7UVvlSGv3ziL+djtTr3yyzcOw=
github.com/gobuffalo/gogen v0.0.0-20190315121717-8f38393713f5/go.mod h1:V9QVDIxsgKNZs6L2IYiGR8datgMhB577vzTDqypH360=
github.com/gobuffalo/gogen v0.1.0/go.mod h1:8NTelM5qd8RZ15VjQTFkAW6qOMx5wBbW4dSCS3BY8gg=
github.com/gobuffalo/gogen v0.1.1/go.mod h1:y8iBtmHmGc4qa3urIyo1shvOD8JftTtfcKi+71xfDNE=
github.com/gobuffalo/logger v0.0.0-20190315122211-86e12af44bc2/go.mod h1:QdxcLw541hSGtBnhUc4gaNIXRjiDppFGaDqzbrBd3v8=
github.com/gobuffalo/mapi v1.0.1/go.mod h1:4VAGh89y6rVOvm5A8fKFxYG+wIW6LO1FMTG9hnKStFc=
github.com/gobuffalo/mapi v1.0.2/go.mod h1:4VAGh89y6rVOvm5A8fKFxYG+wIW6LO1FMTG9hnKStFc=
github.com/gobuffalo/packd v0.0.0-20190315124812-a385830c7fc0/go.mod h1:M2Juc+hhDXf/PnmBANFCqx4DM3wRbgDvnVWeG2RIxq4=
github.com/gobuffalo/packd v0.1.0/go.mod h1:M2Juc+hhDXf/PnmBANFCqx4DM3wRbgDvnVWeG2RIxq4=
github.com/gobuffalo/packr/v2 v2.0.9/go.mod h1:emmyGweYTm6Kdper+iywB6YK5YzuKchGtJQZ0Odn4pQ=
github.com/gobuffalo/packr/v2 v2.2.0/go.mod h1:CaAwI0GPIAv+5wKLtv8Afwl+Cm78K/I/VCm/3ptBN+0=
github.com/gobuffalo/syncx v0.0.0-20190224160051-33c29581e754/go.mod h1:HhnNqWY95UYwwW3uSASeV7vtgYkT2t16hJgV3AEPUpw=
github.com/gogo/googleapis v1.1.0/go.mod h1:gf4bu3Q80BeJ6H1S1vYPm8/ELATdvryBaNFGgqEef3s=
github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ=
github.com/gogo/protobuf v1.2.0/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ=
github.com/gogo/protobuf v1.2.1/go.mod h1:hp+jE20tsWTFYpLwKvXlhS1hjn+gTNwPg2I6zVXpSg4=
github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q=
github.com/golang/groupcache v0.0.0-20160516000752-02826c3e7903/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
github.com/golang/mock v1.3.1-0.20190508161146-9fa652df1129 h1:tT8iWCYw4uOem71yYA3htfH+LNopJvcqZQshm56G5L4=
github.com/golang/mock v1.3.1-0.20190508161146-9fa652df1129/go.mod h1:sBzyDLLjw3U8JLTeZvSv8jJB+tU5PVekmnlKIyFUx0Y=
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.3.2/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/snappy v0.0.0-20180518054509-2e65f85255db/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
github.com/golang/snappy v0.0.1/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
github.com/golang/snappy v0.0.2-0.20190904063534-ff6b7dc882cf h1:gFVkHXmVAhEbxZVDln5V9GKrLaluNoFHDbrZwAWZgws=
github.com/golang/snappy v0.0.2-0.20190904063534-ff6b7dc882cf/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
github.com/google/go-cmp v0.2.0 h1:+dTQ8DZQJz0Mb/HjFlkptS1FeQ4cWSnN941F8aEG4SQ=
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.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.5.2 h1:X2ev0eStA3AbceY54o37/0PQ/UWqKEiiO2dKL5OPaFM=
github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI=
github.com/google/uuid v1.0.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
github.com/google/uuid v1.1.1 h1:Gkbcsh/GbpXz7lPftLA3P6TYMwjCLYm83jiFQZF/3gY=
github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1 h1:EGx4pi6eqNxGaHF6qqu48+N2wcFQ5qg5FXgOdqsJ5d8=
github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY=
github.com/gorilla/context v1.1.1/go.mod h1:kBGZzfjB9CEq2AlWe17Uuf7NDRt0dE0s8S51q0aT7Yg=
github.com/gorilla/mux v1.6.2/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2zaAs=
github.com/gorilla/mux v1.7.3/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2zaAs=
github.com/gorilla/websocket v0.0.0-20170926233335-4201258b820c/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ=
github.com/grpc-ecosystem/go-grpc-middleware v1.0.1-0.20190118093823-f849b5445de4/go.mod h1:FiyG127CGDf3tlThmgyCl78X/SZQqEOJBCDaAfeWzPs=
github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0/go.mod h1:8NvIoxWQoOIhqOTXgfV/d3M/q6VIi02HzZEHgUlZvzk=
github.com/grpc-ecosystem/grpc-gateway v1.9.5/go.mod h1:vNeuVxBJEsws4ogUvrchl83t/GYV9WGTSLVdBhOQFDY=
github.com/hashicorp/consul/api v1.3.0/go.mod h1:MmDNSzIMUjNpY/mQ398R4bk2FnqQLoPndWW5VkKPlCE=
github.com/hashicorp/consul/sdk v0.3.0/go.mod h1:VKf9jXwCTEY1QZP2MOLRhb5i/I/ssyNV1vwHyQBF0x8=
github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4=
github.com/hashicorp/go-cleanhttp v0.5.1/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80=
github.com/hashicorp/go-immutable-radix v1.0.0/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60=
github.com/hashicorp/go-msgpack v0.5.3/go.mod h1:ahLV/dePpqEmjfWmKiqvPkv/twdG7iPBM1vqhUKIvfM=
github.com/hashicorp/go-multierror v1.0.0/go.mod h1:dHtQlpGsu+cZNNAkkCN/P3hoUDHhCYQXV3UM06sGGrk=
github.com/hashicorp/go-rootcerts v1.0.0/go.mod h1:K6zTfqpRlCUIjkwsN4Z+hiSfzSTQa6eBIzfwKfwNnHU=
github.com/hashicorp/go-sockaddr v1.0.0/go.mod h1:7Xibr9yA9JjQq1JpNB2Vw7kxv8xerXegt+ozgdvDeDU=
github.com/hashicorp/go-syslog v1.0.0/go.mod h1:qPfqrKkXGihmCqbJM2mZgkZGvKG1dFdvsLplgctolz4=
github.com/hashicorp/go-uuid v1.0.0/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro=
github.com/hashicorp/go-uuid v1.0.1/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro=
github.com/hashicorp/go-version v1.2.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA=
github.com/hashicorp/go-version v1.2.1-0.20190424083514-192140e6f3e6 h1:rL76JewpeImeqMtpkAHVZkHrXWt6B5sGSj6sAsL0VnI=
github.com/hashicorp/go-version v1.2.1-0.20190424083514-192140e6f3e6/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA=
github.com/hashicorp/go.net v0.0.1/go.mod h1:hjKkEWcCURg++eb33jQU7oqQcI9XDCnUzHA0oac0k90=
github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
github.com/hashicorp/logutils v1.0.0/go.mod h1:QIAnNjmIWmVIIkWDTG1z5v++HQmx9WQRO+LraFDTW64=
github.com/hashicorp/mdns v1.0.0/go.mod h1:tL+uN++7HEJ6SQLQ2/p+z2pH24WQKWjBPkE0mNTz8vQ=
github.com/hashicorp/memberlist v0.1.3/go.mod h1:ajVTdAv/9Im8oMAAj5G31PhhMCZJV2pPBoIllUwCN7I=
github.com/hashicorp/serf v0.8.2/go.mod h1:6hOLApaqBFA1NXqRQAsxw9QxuDEvNxSQRwA/JwenrHc=
github.com/howeyc/gopass v0.0.0-20170109162249-bf9dde6d0d2c h1:kQWxfPIHVLbgLzphqk3QUflDy9QdksZR4ygR807bpy0=
github.com/howeyc/gopass v0.0.0-20170109162249-bf9dde6d0d2c/go.mod h1:lADxMC39cJJqL93Duh1xhAs4I2Zs8mKS89XWXFGp9cs=
github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU=
github.com/hudl/fargo v1.3.0/go.mod h1:y3CKSmjA+wD2gak7sUSXTAoopbhU08POFhmITJgmKTg=
github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8=
github.com/influxdata/influxdb1-client v0.0.0-20191209144304-8bf82d3c094d/go.mod h1:qj24IKcXYK6Iy9ceXlo3Tc+vtHo9lIhSX5JddghvEPo=
github.com/jmespath/go-jmespath v0.0.0-20180206201540-c2b33e8439af/go.mod h1:Nht3zPeWKUH0NzdCt2Blrr5ys8VGpn0CEB0cQHVjt7k=
github.com/joho/godotenv v1.3.0/go.mod h1:7hK45KPybAkOC6peb+G5yklZfMxEjkZhHbwpqxOKXbg=
github.com/jonboulle/clockwork v0.1.0/go.mod h1:Ii8DK3G1RaLaWxj9trq07+26W01tbo22gdxWY5EU2bo=
github.com/jpillora/backoff v1.0.0/go.mod h1:J/6gKK9jxlEcS3zixgDgUAsiuZ7yrSoa/FX5e0EB2j4=
github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU=
github.com/json-iterator/go v1.1.7/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
github.com/json-iterator/go v1.1.8/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
github.com/json-iterator/go v1.1.10/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
github.com/jtolds/gls v4.20.0+incompatible h1:xdiiI2gbIgH/gLH7ADydsJ1uDOEzR8yvV7C0MuV77Wo=
github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU=
github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w=
github.com/julienschmidt/httprouter v1.3.0/go.mod h1:JR6WtHb+2LUe8TCKY3cZOxFyyO8IZAc4RVcycCCAKdM=
github.com/karrick/godirwalk v1.8.0/go.mod h1:H5KPZjojv4lE+QYImBI8xVtrBRgYrIVsaRPx4tDPEn4=
github.com/karrick/godirwalk v1.10.3/go.mod h1:RoGL9dQei4vP9ilrpETWE8CLOZ1kiN0LhBygSwrAsHA=
github.com/kisielk/errcheck v1.1.0/go.mod h1:EZBBE59ingxPouuu3KfxchcWSUPOHkagtvWXihfKN4Q=
github.com/kisielk/errcheck v1.2.0/go.mod h1:/BMXB+zMLi60iA8Vv6Ksmxu/1UDYcXs4uQLJ+jE2L00=
github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
github.com/klauspost/compress v1.9.5/go.mod h1:RyIbtBH6LamlWaDj8nUwkbUhJ87Yi3uG0guNDohfE1A=
github.com/klauspost/compress v1.10.10 h1:a/y8CglcM7gLGYmlbP/stPE5sR3hbhFRUjCBfd/0B3I=
github.com/klauspost/compress v1.10.10/go.mod h1:aoV0uJVorq1K+umq18yTdKaF57EivdYsUV+/s2qKfXs=
github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
github.com/konsorten/go-windows-terminal-sequences v1.0.2 h1:DB17ag19krx9CFsz4o3enTrPXyIXCl+2iCXH/aMAp9s=
github.com/konsorten/go-windows-terminal-sequences v1.0.2/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
github.com/konsorten/go-windows-terminal-sequences v1.0.3 h1:CE8S1cTafDpPvMhIxNJKvHsGVBgn1xWYf1NbHQhywc8=
github.com/konsorten/go-windows-terminal-sequences v1.0.3/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc=
github.com/kr/pretty v0.1.0 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI=
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
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/lib/pq v1.2.0 h1:LXpIM/LZ5xGFhOpXAQUIMM1HdyqzVYM13zNdjCEEcA0=
github.com/lib/pq v1.2.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo=
github.com/lightstep/lightstep-tracer-common/golang/gogo v0.0.0-20190605223551-bc2310a04743/go.mod h1:qklhhLq1aX+mtWk9cPHPzaBjWImj5ULL6C7HFJtXQMM=
github.com/lightstep/lightstep-tracer-go v0.18.1/go.mod h1:jlF1pusYV4pidLvZ+XD0UBX0ZE6WURAspgAczcDHrL4=
github.com/lyft/protoc-gen-validate v0.0.13/go.mod h1:XbGvPuh87YZc5TdIa2/I4pLk0QoUACkjt2znoq26NVQ=
github.com/markbates/oncer v0.0.0-20181203154359-bf2de49a0be2/go.mod h1:Ld9puTsIW75CHf65OeIOkyKbteujpZVXDpWK6YGZbxE=
github.com/markbates/safe v1.0.1/go.mod h1:nAqgmRi7cY2nqMc92/bSEeQA+R4OheNU2T1kNSCBdG0=
github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU=
github.com/mattn/go-isatty v0.0.3/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4=
github.com/mattn/go-isatty v0.0.4/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4=
github.com/mattn/go-runewidth v0.0.2/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU=
github.com/mattn/go-shellwords v1.0.6 h1:9Jok5pILi5S1MnDirGVTufYGtksUs/V2BWUP3ZkeUUI=
github.com/mattn/go-shellwords v1.0.6/go.mod h1:3xCvwCdWdlDJUrvuMn7Wuy9eWs4pE8vqg+NOMyg4B2o=
github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0=
github.com/miekg/dns v1.0.14/go.mod h1:W1PPwlIAgtquWBMBEV9nkV9Cazfe8ScdGz/Lj7v3Nrg=
github.com/mitchellh/cli v1.0.0/go.mod h1:hNIlj7HEI86fIcpObd7a0FcrxTWetlwJDGcceTlRvqc=
github.com/mitchellh/go-homedir v1.0.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0=
github.com/mitchellh/go-testing-interface v1.0.0/go.mod h1:kRemZodwjscx+RGhAo8eIhFbs2+BFgRtFPeD/KE+zxI=
github.com/mitchellh/gox v0.4.0/go.mod h1:Sd9lOJ0+aimLBi73mGofS1ycjY8lL3uZM3JPS42BGNg=
github.com/mitchellh/iochan v1.0.0/go.mod h1:JwYml1nuB7xOzsp52dPpHFffvOCDupsG0QubkSMEySY=
github.com/mitchellh/mapstructure v0.0.0-20160808181253-ca63d7c062ee/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y=
github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y=
github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
github.com/montanaflynn/stats v0.0.0-20171201202039-1bf9dbcd8cbe h1:iruDEfMl2E6fbMZ9s0scYfZQ84/6SPL6zC8ACM2oIL0=
github.com/montanaflynn/stats v0.0.0-20171201202039-1bf9dbcd8cbe/go.mod h1:wL8QJuTMNUDYhXwkmfOly8iTdp5TEcJFWZD2D7SIkUc=
github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U=
github.com/mwitkow/go-conntrack v0.0.0-20190716064945-2f068394615f/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U=
github.com/nats-io/jwt v0.3.0/go.mod h1:fRYCDE99xlTsqUzISS1Bi75UBJ6ljOJQOAAu5VglpSg=
github.com/nats-io/jwt v0.3.2/go.mod h1:/euKqTS1ZD+zzjYrY7pseZrTtWQSjujC7xjPc8wL6eU=
github.com/nats-io/nats-server/v2 v2.1.2/go.mod h1:Afk+wRZqkMQs/p45uXdrVLuab3gwv3Z8C4HTBu8GD/k=
github.com/nats-io/nats.go v1.9.1/go.mod h1:ZjDU1L/7fJ09jvUSRVBR2e7+RnLiiIQyqyzEE/Zbp4w=
github.com/nats-io/nkeys v0.1.0/go.mod h1:xpnFELMwJABBLVhffcfd1MZx6VsNRFpEugbxziKVo7w=
github.com/nats-io/nkeys v0.1.3/go.mod h1:xpnFELMwJABBLVhffcfd1MZx6VsNRFpEugbxziKVo7w=
github.com/nats-io/nuid v1.0.1/go.mod h1:19wcPz3Ph3q0Jbyiqsd0kePYG7A95tJPxeL+1OSON2c=
github.com/oklog/oklog v0.3.2/go.mod h1:FCV+B7mhrz4o+ueLpx+KqkyXRGMWOYEvfiXtdGtbWGs=
github.com/oklog/run v1.0.0/go.mod h1:dlhp/R75TPv97u0XWUtDeV/lRKWPKSdTuV0TZvrmrQA=
github.com/olekukonko/tablewriter v0.0.0-20170122224234-a0225b3f23b5/go.mod h1:vsDQFd/mU46D+Z4whnwzcISnGGzXWMclvtLoiIKAKIo=
github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
github.com/onsi/ginkgo v1.7.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
github.com/onsi/gomega v1.4.3/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY=
github.com/op/go-logging v0.0.0-20160315200505-970db520ece7/go.mod h1:HzydrMdWErDVzsI23lYNej1Htcns9BCg93Dk0bBINWk=
github.com/opentracing-contrib/go-observer v0.0.0-20170622124052-a52f23424492/go.mod h1:Ngi6UdF0k5OKD5t5wlmGhe/EDKPoUM3BXZSSfIuJbis=
github.com/opentracing/basictracer-go v1.0.0/go.mod h1:QfBfYuafItcjQuMwinw9GhYKwFXS9KnPs5lxoYwgW74=
github.com/opentracing/opentracing-go v1.0.2/go.mod h1:UkNAQd3GIcIGf0SeVgPpRdFStlNbqXla1AfSYxPUl2o=
github.com/opentracing/opentracing-go v1.1.0/go.mod h1:UkNAQd3GIcIGf0SeVgPpRdFStlNbqXla1AfSYxPUl2o=
github.com/openzipkin-contrib/zipkin-go-opentracing v0.4.5/go.mod h1:/wsWhb9smxSfWAKL3wpBW7V8scJMt8N8gnaMCS9E/cA=
github.com/openzipkin/zipkin-go v0.1.6/go.mod h1:QgAqvLzwWbR/WpD4A3cGpPtJrZXNIiJc5AZX7/PBEpw=
github.com/openzipkin/zipkin-go v0.2.1/go.mod h1:NaW6tEwdmWMaCDZzg8sh+IBNOxHMPnhQw8ySjnjRyN4=
github.com/openzipkin/zipkin-go v0.2.2/go.mod h1:NaW6tEwdmWMaCDZzg8sh+IBNOxHMPnhQw8ySjnjRyN4=
github.com/pact-foundation/pact-go v1.0.4/go.mod h1:uExwJY4kCzNPcHRj+hCR/HBbOOIwwtUjcrb0b5/5kLM=
github.com/pascaldekloe/goe v0.0.0-20180627143212-57f6aae5913c/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc=
github.com/pborman/getopt v0.0.0-20190409184431-ee0cd42419d3 h1:YtFkrqsMEj7YqpIhRteVxJxCeC3jJBieuLr0d4C4rSA=
github.com/pborman/getopt v0.0.0-20190409184431-ee0cd42419d3/go.mod h1:85jBQOZwpVEaDAr341tbn15RS4fCAsIst0qp7i8ex1o=
github.com/pborman/uuid v1.2.0/go.mod h1:X/NO0urCmaxf9VXbdlT7C2Yzkj2IKimNn4k+gtPdI/k=
github.com/pelletier/go-toml v1.4.0/go.mod h1:PN7xzY2wHTK0K9p34ErDQMlFxa51Fk0OUruD3k1mMwo=
github.com/percona/go-mysql v0.0.0-20190903141930-197f4ad8db8d h1:ZkztfR4jYDnkFQtZfwMVm9z7wkK/WiCXRQ7l1CB1/1M=
github.com/percona/go-mysql v0.0.0-20190903141930-197f4ad8db8d/go.mod h1:/SGLf9OMxlnK6jq4mkFiImBcJXXk5jwD+lDrwDaGXcw=
github.com/performancecopilot/speed v3.0.0+incompatible/go.mod h1:/CLtqpZ5gBg1M9iaPbIdPPGyKcA8hKdoy6hAWba7Yac=
github.com/pierrec/lz4 v1.0.2-0.20190131084431-473cd7ce01a1/go.mod h1:3/3N9NVKO0jef7pBehbT1qWhCMrIgbYNnFAZCqQ5LRc=
github.com/pierrec/lz4 v2.0.5+incompatible/go.mod h1:pdkljMzZIN41W+lC3N2tnIh5sFi+IEE17M5jbnwPHcY=
github.com/pkg/errors v0.8.0/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/pkg/profile v1.2.1/go.mod h1:hJw3o1OdXxsrSjjVksARp5W95eeEaEfptyVZyv6JUPA=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/posener/complete v1.1.1/go.mod h1:em0nMJCgc9GFtwrmVmEMR/ZL6WyhyjMBndrE9hABlRI=
github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw=
github.com/prometheus/client_golang v0.9.3-0.20190127221311-3c4408c8b829/go.mod h1:p2iRAGwDERtqlqzRXnrOVns+ignqQo//hLXqYxZYVNs=
github.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5FsnadC4Ky3P0J6CfImo=
github.com/prometheus/client_golang v1.3.0/go.mod h1:hJaj2vgQTGQmVCsAACORcieXFeDPbaTKGT+JTgUa3og=
github.com/prometheus/client_golang v1.7.1/go.mod h1:PY5Wy2awLA44sXw4AOSfFBetzPP4j5+D6mVACh+pe2M=
github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo=
github.com/prometheus/client_model v0.0.0-20190115171406-56726106282f/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo=
github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
github.com/prometheus/client_model v0.1.0/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
github.com/prometheus/client_model v0.2.0/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
github.com/prometheus/common v0.2.0/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4=
github.com/prometheus/common v0.4.1/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4=
github.com/prometheus/common v0.7.0/go.mod h1:DjGbpBbp5NYNiECxcL/VnbXCCaQpKd3tt26CguLLsqA=
github.com/prometheus/common v0.10.0/go.mod h1:Tlit/dnDKsSWFlCLTWaA1cyBgKHSMdTB80sz/V91rCo=
github.com/prometheus/common v0.13.0 h1:vJlpe9wPgDRM1Z+7Wj3zUUjY1nr6/1jNKyl7llliccg=
github.com/prometheus/common v0.13.0/go.mod h1:U+gB1OBLb1lF3O42bTCL+FK18tX9Oar16Clt/msog/s=
github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk=
github.com/prometheus/procfs v0.0.0-20190117184657-bf6a532e95b1/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk=
github.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA=
github.com/prometheus/procfs v0.0.8/go.mod h1:7Qr8sr6344vo1JqZ6HhLceV9o3AJ1Ff+GxbHq6oeK9A=
github.com/prometheus/procfs v0.1.3/go.mod h1:lV6e/gmhEcM9IjHGsFOCxxuZ+z1YqCvr4OA4YeYWdaU=
github.com/rcrowley/go-metrics v0.0.0-20181016184325-3113b8401b8a/go.mod h1:bCqnVzQkZxMG4s8nGwiZ5l3QUCyqpo9Y+/ZMZ9VjZe4=
github.com/rogpeppe/fastuuid v0.0.0-20150106093220-6724a57986af/go.mod h1:XWv6SoW27p1b0cqNHllgS5HIMJraePCO15w5zCzIWYg=
github.com/rogpeppe/go-internal v1.1.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4=
github.com/rogpeppe/go-internal v1.2.2/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4=
github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4=
github.com/rogpeppe/go-internal v1.6.1/go.mod h1:xXDCJY+GAPziupqXw64V24skbSoqbTEfhy4qGm1nDQc=
github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
github.com/ryanuber/columnize v0.0.0-20160712163229-9b3edd62028f/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts=
github.com/samuel/go-zookeeper v0.0.0-20190923202752-2cc03de413da/go.mod h1:gi+0XIa01GRL2eRQVjQkKGqKF3SF9vZR/HnPullcV2E=
github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529/go.mod h1:DxrIzT+xaE7yg65j358z/aeFdxmN0P9QXhEzd20vsDc=
github.com/shirou/gopsutil v2.20.8+incompatible h1:8c7Atn0FAUZJo+f4wYbN0iVpdWniCQk7IYwGtgdh1mY=
github.com/shirou/gopsutil v2.20.8+incompatible/go.mod h1:5b4v6he4MtMOwMlS0TUMTu2PcXUg8+E1lC7eC3UO/RA=
github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc=
github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo=
github.com/sirupsen/logrus v1.4.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo=
github.com/sirupsen/logrus v1.4.1/go.mod h1:ni0Sbl8bgC9z8RoU9G6nDWqqs/fq4eDPysMBDgk/93Q=
github.com/sirupsen/logrus v1.4.2 h1:SPIRibHv4MatM3XXNO2BJeFLZwZ2LvZgfQ5+UNI2im4=
github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE=
github.com/sirupsen/logrus v1.6.0 h1:UBcNElsrwanuuMsnGSlYmtmgbb23qDR5dG+6X6Oo89I=
github.com/sirupsen/logrus v1.6.0/go.mod h1:7uNnSEd1DgxDLC74fIahvMZmmYsHGZGEOFrfsX/uA88=
github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d h1:zE9ykElWQ6/NYmHa3jpm/yHnI4xSofP+UP6SpjHcSeM=
github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc=
github.com/smartystreets/goconvey v1.6.4 h1:fv0U8FUIMPNf1L9lnHLvLhgicrIVChEkdzIKYqbNC9s=
github.com/smartystreets/goconvey v1.6.4/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA=
github.com/soheilhy/cmux v0.1.4/go.mod h1:IM3LyeVVIOuxMH7sFAkER9+bJ4dT7Ms6E4xg4kGIyLM=
github.com/sony/gobreaker v0.4.1/go.mod h1:ZKptC7FHNvhBz7dN2LGjPVBz2sZJmc0/PkyDJOjmxWY=
github.com/spf13/cobra v0.0.3/go.mod h1:1l0Ry5zgKvJasoi3XT1TypsSe7PqH0Sj9dhYf7v3XqQ=
github.com/spf13/pflag v1.0.1/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4=
github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4=
github.com/streadway/amqp v0.0.0-20190404075320-75d898a42a94/go.mod h1:AZpEONHx3DKn8O/DFsRAY58/XVQiIPMTMB1SddzLXVw=
github.com/streadway/amqp v0.0.0-20190827072141-edfb9018d271/go.mod h1:AZpEONHx3DKn8O/DFsRAY58/XVQiIPMTMB1SddzLXVw=
github.com/streadway/handy v0.0.0-20190108123426-d5acb3125c2a/go.mod h1:qNTQ5P5JnDBl6z3cMAg/SywNDC5ABu5ApDIw6lUbRmI=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
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.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
github.com/stretchr/testify v1.6.1 h1:hDPOHmpOpP40lSULcqw7IrRb/u7w6RpDC9399XyoNd0=
github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/tidwall/pretty v1.0.0 h1:HsD+QiTn7sK6flMKIvNmpqz1qrpP3Ps6jOKIKMooyg4=
github.com/tidwall/pretty v1.0.0/go.mod h1:XNkn88O1ChpSDQmQeStsy+sBenx6DDtFZJxhVysOjyk=
github.com/tmc/grpc-websocket-proxy v0.0.0-20170815181823-89b8d40f7ca8/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U=
github.com/urfave/cli v1.20.0/go.mod h1:70zkFmudgCuE/ngEzBv17Jvp/497gISqfk5gWijbERA=
github.com/urfave/cli v1.22.1/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0=
github.com/xdg/scram v0.0.0-20180814205039-7eeb5667e42c h1:u40Z8hqBAAQyv+vATcGgV0YCnDjqSL7/q/JyPhhJSPk=
github.com/xdg/scram v0.0.0-20180814205039-7eeb5667e42c/go.mod h1:lB8K/P019DLNhemzwFU4jHLhdvlE6uDZjXFejJXr49I=
github.com/xdg/stringprep v0.0.0-20180714160509-73f8eece6fdc/go.mod h1:Jhud4/sHMO4oL310DaZAKk9ZaJ08SJfe+sJh0HrGL1Y=
github.com/xdg/stringprep v1.0.1-0.20180714160509-73f8eece6fdc h1:vIp1tjhVogU0yBy7w96P027ewvNPeH6gzuNcoc+NReU=
github.com/xdg/stringprep v1.0.1-0.20180714160509-73f8eece6fdc/go.mod h1:Jhud4/sHMO4oL310DaZAKk9ZaJ08SJfe+sJh0HrGL1Y=
github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU=
github.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
go.etcd.io/bbolt v1.3.3/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU=
go.etcd.io/etcd v0.0.0-20191023171146-3cf2f69b5738/go.mod h1:dnLIgRNXwCJa5e+c6mIZCrds/GIG4ncV9HhK5PX7jPg=
go.mongodb.org/mongo-driver v1.3.4 h1:zs/dKNwX0gYUtzwrN9lLiR15hCO0nDwQj5xXx+vjCdE=
go.mongodb.org/mongo-driver v1.3.4/go.mod h1:MSWZXKOynuguX+JSvwP8i+58jYCXxbia8HS3gZBapIE=
go.opencensus.io v0.20.1/go.mod h1:6WKK9ahsWS3RSO+PY9ZHZUfv2irvY6gN279GOPZjmmk=
go.opencensus.io v0.20.2/go.mod h1:6WKK9ahsWS3RSO+PY9ZHZUfv2irvY6gN279GOPZjmmk=
go.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw=
go.uber.org/atomic v1.3.2/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE=
go.uber.org/atomic v1.5.0/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ=
go.uber.org/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0=
go.uber.org/multierr v1.3.0/go.mod h1:VgVr7evmIr6uPjLBxg28wmKNXyqE9akIJ5XnfpiKl+4=
go.uber.org/tools v0.0.0-20190618225709-2cfd321de3ee/go.mod h1:vJERXedbb3MVM5f9Ejo0C68/HhF8uaILCdgjnY+goOA=
go.uber.org/zap v1.10.0/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q=
go.uber.org/zap v1.13.0/go.mod h1:zwrFLgMcdUuIBviXEYEH1YKNaOBnKXsx2IPda5bBwHM=
golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
golang.org/x/crypto v0.0.0-20181029021203-45a5f77698d3/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/crypto v0.0.0-20190422162423-af44ce270edf/go.mod h1:WFFai1msRO1wXaEeE5yQxYXgSfI8pQAWXbQop6sCtWE=
golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20190530122614-20be4c3c3ed5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20190701094942-4def268fd1a4/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9 h1:psW17arqaxU48Z5kZ0CQnkZWQJsqcURM6tKiBApRjXI=
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
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/lint v0.0.0-20190301231843-5614ed5bae6f/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc=
golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg=
golang.org/x/mod v0.3.0 h1:RM4zey1++hCTbCVQfnWeKs9/IEsaBLA8vTkd0WVtmH4=
golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
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-20181023162649-9b4f9f5ad519/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20181201002055-351d144fa1fc/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20181220203305-927f97764cc3/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-20190125091013-d26f9f9a57f3/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-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks=
golang.org/x/net v0.0.0-20190613194153-d28f0bde5980/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-20190813141303-74dc4d7220e7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20200625001655-4c5254603344/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
golang.org/x/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-20190412183630-56d357773e84/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20190423024810-112230192c58 h1:8gQV6CLnAEikrhgkHFbMAEhagSSnXWGV915qUMm9mrU=
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20200625203802-6e8e738ad208/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9 h1:SQFwaSi55rU7vdNs9Yr0Z324VNlrF+0wMqRXT4St8ck=
golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20181026203630-95b1ffbd15a5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20181107165924-66b7b1311ac8/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20181122145206-62eef0e2fa9b/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-20190403152447-81d4e9dc473e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190419153524-e8e3143a4f4a/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190502145724-3ef323f4f1fd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190531175056-4c3a928424d2/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190726091711-fc99dfbffb4e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190826190057-c7b8b68b1456/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20191220142924-d4481acd189f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200106162015-b016eb3dc98e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200615200032-f1bc736245b1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200625212154-ddb9806d33ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f h1:+Nyd8tzPX9R7BWHguqsrbFdRx3WQ/1ib8I44HXV5yTA=
golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.2 h1:tW2bmiBqwgJj/UpqtC8EpXEZVYOwU0yG4iWbprSVAcs=
golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
golang.org/x/text v0.3.3 h1:cokOdA+Jmi5PJGXLlLllQSgYigAEfHXJAERHVMaCc2k=
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/time v0.0.0-20180412165947-fbb02b2291d2/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/tools v0.0.0-20180221164845-07fd8470d635/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-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-20181030221726-6c7e314b6563/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
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-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
golang.org/x/tools v0.0.0-20190312170243-e65039ee4138/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
golang.org/x/tools v0.0.0-20190328211700-ab21143f2384/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
golang.org/x/tools v0.0.0-20190329151228-23e29df326fe/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
golang.org/x/tools v0.0.0-20190416151739-9c9e1878f421/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
golang.org/x/tools v0.0.0-20190420181800-aa740d480789/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
golang.org/x/tools v0.0.0-20190425150028-36563e24a262/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
golang.org/x/tools v0.0.0-20190531172133-b3315ee88b7d/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
golang.org/x/tools v0.0.0-20190621195816-6e04913cbbac/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
golang.org/x/tools v0.0.0-20191029041327-9cc4af7d6b2c/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20191029190741-b9c20aec41a5/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20200103221440-774c71fcf114/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
golang.org/x/tools v0.0.0-20200731060945-b5fad4ed8dd6 h1:qKpj8TpV+LEhel7H/fR788J+KvhWZ3o3V6N2fU/iuLU=
golang.org/x/tools v0.0.0-20200731060945-b5fad4ed8dd6/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA=
golang.org/x/tools v0.0.0-20201023174141-c8cfbd0f21e6 h1:rbvTkL9AkFts1cgI78+gG6Yu1pwaqX6hjSJAatB78E4=
golang.org/x/tools v0.0.0-20201023174141-c8cfbd0f21e6/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
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-20191204190536-9bdfabe68543 h1:E7g+9GITq07hpfrRu66IVDexMakfv52eLZ2CXBWiKr4=
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 h1:go1bK/D/BFZV2I8cIQd1NKEZ+0owSTG1fDTci4IqFcE=
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
google.golang.org/api v0.3.1/go.mod h1:6wY9I6uQWHQ8EM57III9mq/AjF+i8G65rmVagqKMtkk=
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.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-20190307195333-5fe7a883aa19/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
google.golang.org/genproto v0.0.0-20190425155659-357c62f0e4bb/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
google.golang.org/genproto v0.0.0-20190530194941-fb225487d101/go.mod h1:z3L6/3dTEVtUr6QSP8miRzeRqwQOioJ9I66odjN4I7s=
google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc=
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/grpc v1.20.0/go.mod h1:chYK+tFQF0nDUGJgXMSgLCQk3phJEuONr2DCgLDdAQM=
google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38=
google.golang.org/grpc v1.21.0/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM=
google.golang.org/grpc v1.22.1/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg=
google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg=
google.golang.org/grpc v1.23.1/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg=
google.golang.org/grpc v1.26.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk=
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=
gopkg.in/alecthomas/kingpin.v2 v2.2.6 h1:jMFz6MfLP0/4fUyZle81rXUoxOBFi19VUFKVDOQfozc=
gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 h1:qIbj1fsPNlZgppZ+VLlY7N33q108Sa+fhmuc+sWQYwY=
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15 h1:YR8cESwS4TdDjEe65xsg0ogRM/Nc3DYOhEAlW+xobZo=
gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/cheggaaa/pb.v1 v1.0.25/go.mod h1:V/YB90LKu/1FcN3WVnfiiE5oMCibMjukxqG/qStrOgw=
gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI=
gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys=
gopkg.in/gcfg.v1 v1.2.3/go.mod h1:yesOnuUOFQAhST5vPY4nbZsb/huCgGGXlipJsBn0b3o=
gopkg.in/ini.v1 v1.61.0 h1:LBCdW4FmFYL4s/vDZD1RQYX7oAR6IjujCYgMdbHBR10=
gopkg.in/ini.v1 v1.61.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k=
gopkg.in/mgo.v2 v2.0.0-20190816093944-a6b53ec6cb22 h1:VpOs+IwYnYBaFnrNAeB8UUWtL3vEUnzSCL1nVjPhqrw=
gopkg.in/mgo.v2 v2.0.0-20190816093944-a6b53ec6cb22/go.mod h1:yeKp02qBN3iKW1OzL3MGk2IdtZzaj7SFntXj72NppTA=
gopkg.in/resty.v1 v1.12.0/go.mod h1:mDo4pnntr5jdWRML875a/NmxYqAlA73dVijT2AXvQQo=
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw=
gopkg.in/warnings.v0 v0.1.2/go.mod h1:jksf8JmL6Qr/oQM2OXTHunEvvTAsrWBLb6OOjuVWRNI=
gopkg.in/yaml.v2 v2.0.0-20170812160011-eb3733d160e7/go.mod h1:JAlM8MvJe8wmxCU4Bli9HhUf9+ttbYbLASfIpnQbh74=
gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.2.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.5/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.3.0 h1:clyUAQHOM3G0M3f5vQj7LuJrETvjVot3Z5el9nffUtU=
gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
gopkg.in/yaml.v3 v3.0.0-20200615113413-eeeca48fe776 h1:tQIYjPdBoyREyB9XMu+nnTclpTYkz2zFM+lzLJFO4gQ=
gopkg.in/yaml.v3 v3.0.0-20200615113413-eeeca48fe776/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
honnef.co/go/tools v0.0.0-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-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg=
mvdan.cc/gofumpt v0.0.0-20200927160801-5bfeb2e70dd6 h1:z+/YqapuV7VZPvBb3GYmuEJbA88M3PFUxaHilHYVCpQ=
mvdan.cc/gofumpt v0.0.0-20200927160801-5bfeb2e70dd6/go.mod h1:bzrjFmaD6+xqohD3KYP0H2FEuxknnBmyyOxdhLdaIws=
sigs.k8s.io/yaml v1.1.0/go.mod h1:UJmg0vDUVViEyp3mgSv9WPwZCDxu4rQW1olrI1uml+o=
sourcegraph.com/sourcegraph/appdash v0.0.0-20190731080439-ebfcffb1b5c0/go.mod h1:hI742Nqp5OhwiqlzhgfbWU4mW4yO10fP+LoT9WOswdU=

View File

@@ -405,7 +405,7 @@ sub _print_failures {
foreach my $failure ( @$failures ) {
print "\n-- $failno.\n";
if ( ($failure->[1] || '') eq ($failure->[2] || '') ) {
printf "\nOn both hosts:\n\n" . ($failure->[1] || '') . "\n";
print "\nOn both hosts:\n\n" . ($failure->[1] || '') . "\n";
}
else {
printf "\n%s\n\nvs.\n\n%s\n",

View File

@@ -138,8 +138,8 @@ test: ## Run tests
@./runtests.sh
format: ## Format source code.
gofmt -w -s $(FILES)
goimports -local github.com/percona/pmm-managed -l -w $(FILES)
gofumpt -w -s $(FILES)
gofumports -local github.com/percona/pmm-managed -l -w $(FILES)
vet: ## Run vet on Go code
@echo ">> vetting code"

View File

@@ -1,11 +1,16 @@
package testutils
import (
"context"
"net"
"os"
"os/exec"
"path/filepath"
"strings"
"time"
"go.mongodb.org/mongo-driver/mongo"
"go.mongodb.org/mongo-driver/mongo/options"
)
const (
@@ -143,30 +148,70 @@ func BaseDir() string {
}
basedir = strings.TrimSpace(string(out))
return basedir
}
// GetMongoDBAddr returns the address of an instance by replicaset name and instance type like
// (rs1, primary) or (rs1, secondary1)
// (rs1, primary) or (rs1, secondary1).
func GetMongoDBAddr(rs, name string) string {
if _, ok := hosts[rs]; !ok {
return ""
}
replset := hosts[rs]
if host, ok := replset[name]; ok {
return host
}
return ""
}
// GetMongoDBReplsetAddrs return the addresses of all instances for a replicaset name
// GetMongoDBReplsetAddrs return the addresses of all instances for a replicaset name.
func GetMongoDBReplsetAddrs(rs string) []string {
addrs := []string{}
if _, ok := hosts[rs]; !ok {
return addrs
}
for _, host := range hosts[rs] {
addrs = append(addrs, host)
}
return addrs
}
// TestClient returns a new MongoDB connection to the specified server port.
func TestClient(ctx context.Context, port string) (*mongo.Client, error) {
if port == "" {
port = MongoDBShard1PrimaryPort
}
hostname := "127.0.0.1"
direct := true
to := time.Second
co := &options.ClientOptions{
ConnectTimeout: &to,
Hosts: []string{net.JoinHostPort(hostname, port)},
Direct: &direct,
Auth: &options.Credential{
Username: MongoDBUser,
Password: MongoDBPassword,
PasswordSet: true,
},
}
client, err := mongo.Connect(ctx, co)
if err != nil {
return nil, err
}
err = client.Ping(ctx, nil)
if err != nil {
return nil, err
}
return client, nil
}

View File

@@ -75,10 +75,8 @@ func DefaultConfigFiles(toolName string) ([]string, error) {
}
func DefaultConfig(toolname string) *Config {
files, _ := DefaultConfigFiles(toolname)
return NewConfig(files...)
}
func NewConfig(files ...string) *Config {
@@ -94,7 +92,6 @@ func NewConfig(files ...string) *Config {
}
func read(filename string, opts map[string]interface{}) error {
f, err := os.Open(filename)
if err != nil {
return err
@@ -135,7 +132,7 @@ func read(filename string, opts map[string]interface{}) error {
}
if f == float64(int64(f)) {
opts[key] = int64(f) //int64
opts[key] = int64(f) // int64
continue
}

View File

@@ -11,7 +11,6 @@ import (
)
func TestReadConfig(t *testing.T) {
rootPath, err := tutil.RootPath()
if err != nil {
t.Errorf("cannot get root path: %s", err)
@@ -69,7 +68,6 @@ func TestReadConfig(t *testing.T) {
}
func TestOverrideConfig(t *testing.T) {
rootPath, err := tutil.RootPath()
if err != nil {
t.Errorf("cannot get root path: %s", err)
@@ -131,7 +129,6 @@ func TestOverrideConfig(t *testing.T) {
}
func TestDefaultFiles(t *testing.T) {
user, _ := user.Current()
toolname := "pt-testing"
@@ -150,5 +147,4 @@ func TestDefaultFiles(t *testing.T) {
if !reflect.DeepEqual(got, want) {
t.Errorf("got %#v\nwant: %#v\n", got, want)
}
}

View File

@@ -5,8 +5,8 @@ import (
"regexp"
"time"
"github.com/percona/percona-toolkit/src/go/pt-pg-summary/models"
"github.com/hashicorp/go-version"
"github.com/percona/percona-toolkit/src/go/pt-pg-summary/models"
"github.com/pkg/errors"
"github.com/shirou/gopsutil/process"
"github.com/sirupsen/logrus"

View File

@@ -108,17 +108,15 @@ func LoadBson(filename string, destination interface{}) error {
}
func WriteJson(filename string, data interface{}) error {
buf, err := json.MarshalIndent(data, "", " ")
if err != nil {
return err
}
err = ioutil.WriteFile(filename, buf, 0777)
err = ioutil.WriteFile(filename, buf, 0o777)
if err != nil {
return err
}
return nil
}
func ShouldUpdateSamples() bool {

View File

@@ -12,7 +12,6 @@ import (
)
func TestCheckUpdates(t *testing.T) {
ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
body, _ := ioutil.ReadAll(r.Body)
m := strings.Split(string(body), ";")
@@ -39,11 +38,9 @@ func TestCheckUpdates(t *testing.T) {
if msg == "" {
t.Error("got empty response")
}
}
func TestEmptyResponse(t *testing.T) {
ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
fmt.Fprint(w, "")
}))
@@ -57,5 +54,4 @@ func TestEmptyResponse(t *testing.T) {
if msg != "" {
t.Error("response should return error due to empty body")
}
}

View File

@@ -11,10 +11,8 @@ import (
"go.mongodb.org/mongo-driver/mongo"
)
var (
// DocsBufferSize is the buffer size to store documents from the MongoDB profiler
DocsBufferSize = 100
)
// DocsBufferSize is the buffer size to store documents from the MongoDB profiler
var DocsBufferSize = 100
// Profiler interface
type Profiler interface {

View File

@@ -34,9 +34,11 @@ type OpLogs []OplogInfo
func (s OpLogs) Len() int {
return len(s)
}
func (s OpLogs) Swap(i, j int) {
s[i], s[j] = s[j], s[i]
}
func (s OpLogs) Less(i, j int) bool {
return s[i].TimeDiffHours < s[j].TimeDiffHours
}

View File

@@ -0,0 +1,30 @@
package proto
import "time"
type ProcInfo struct {
CreateTime time.Time
Path string
UserName string
Error error
}
type GetHostInfo struct {
Hostname string
HostOsType string
HostSystemCPUArch string
HostDatabases int
HostCollections int
DBPath string
ProcPath string
ProcUserName string
ProcCreateTime time.Time
ProcProcessCount int
// Server Status
ProcessName string
ReplicasetName string
Version string
NodeType string
}

View File

@@ -4,8 +4,11 @@ import (
"go.mongodb.org/mongo-driver/bson/primitive"
)
type ReplicaSetConfigTags map[string]string
type GetLastErrorModes map[string]*ReplicaSetConfigTags
type (
ReplicaSetConfigTags map[string]string
GetLastErrorModes map[string]*ReplicaSetConfigTags
)
// https://docs.mongodb.com/v3.2/reference/command/getLastError/#dbcmd.getLastError
type GetLastErrorDefaults struct {

View File

@@ -1,6 +1,9 @@
package proto
import "go.mongodb.org/mongo-driver/bson/primitive"
import (
"go.mongodb.org/mongo-driver/bson/primitive"
"gopkg.in/mgo.v2/bson"
)
const (
REPLICA_SET_MEMBER_STARTUP = iota
@@ -48,3 +51,83 @@ type ReplicaSetStatus struct {
Ok float64 `bson:"ok"` //
Set string `bson:"set"` // Replica set name
}
type Member struct {
Host string `bson:"host"`
Votes int32 `bson:"votes"`
ID int32 `bson:"_id"`
SlaveDelay int64 `bson:"slaveDelay"`
Priority float64 `bson:"priority"`
BuildIndexes bool `bson:"buildIndexes"`
ArbiterOnly bool `bson:"arbiterOnly"`
Hidden bool `bson:"hidden"`
Tags bson.M `bson:"tags"`
}
type RSConfig struct {
ID string `bson:"_id"`
ConfigServer bool `bson:"configsvr"`
WriteConcernMajorityJournalDefault bool `bson:"writeConcernMajorityJournalDefault"`
Version int32 `bson:"version"`
ProtocolVersion int64 `bson:"protocolVersion"`
Settings RSSettings `bson:"settings"`
Members []Member `bson:"members"`
}
type LastErrorDefaults struct {
W int32 `bson:"w"`
WTimeout int32 `bson:"wtimeout"`
}
type RSSettings struct {
HeartbeatTimeoutSecs int32 `bson:"heartbeatTimeoutSecs"`
ElectionTimeoutMillis int32 `bson:"electionTimeoutMillis"`
CatchUpTimeoutMillis int32 `bson:"catchUpTimeoutMillis"`
GetLastErrorModes bson.M `bson:"getLastErrorModes"`
ChainingAllowed bool `bson:"chainingAllowed"`
HeartbeatIntervalMillis int32 `bson:"heartbeatIntervalMillis"`
CatchUpTakeoverDelayMillis int32 `bson:"catchUpTakeoverDelayMillis"`
GetLastErrorDefaults LastErrorDefaults `bson:"getLastErrorDefaults"`
ReplicaSetID primitive.ObjectID `bson:"replicaSetId"`
}
type Signature struct {
Hash primitive.Binary `bson:"hash"`
KeyID int64 `bson:"keyId"`
}
type ClusterTime struct {
ClusterTime primitive.Timestamp `bson:"clusterTime"`
Signature Signature `bson:"signature"`
}
type ReplicasetConfig struct {
Config RSConfig `bson:"config"`
OK float64 `bson:"ok"`
LastCommittedOpTime primitive.Timestamp `bson:"lastCommittedOpTime"`
ClusterTime ClusterTime `bson:"$clusterTime"`
OperationTime primitive.Timestamp `bson:"operationTime"`
}
type ConfigVersion struct {
ID int32 `bson:"_id"`
MinCompatibleVersion int32 `bson:"minCompatibleVersion"`
CurrentVersion int32 `bson:"currentVersion"`
ClusterID primitive.ObjectID `bson:"clusterId"`
}
type ShardIdentity struct {
ID string `bson:"_id"`
ShardName string `bson:"shardName"`
ClusterID primitive.ObjectID `bson:"clusterId"`
ConfigsvrConnectionString string `bson:"configsvrConnectionString"`
}
// MyState is a subset of getDiagnosticData result used to tag metrics in the MongoDB exporter
type MyState struct {
Data struct {
ReplicasetGetStatus struct {
MyState int `bson:"myState"`
} `bson:"replSetGetStatus"`
} `bson:"data"`
}

View File

@@ -2,23 +2,39 @@ package util
import (
"context"
"fmt"
"sort"
"strings"
"time"
"github.com/percona/percona-toolkit/src/go/mongolib/proto"
"github.com/pkg/errors"
"github.com/prometheus/common/log"
"github.com/shirou/gopsutil/process"
"go.mongodb.org/mongo-driver/bson/primitive"
"go.mongodb.org/mongo-driver/mongo"
"go.mongodb.org/mongo-driver/mongo/options"
"gopkg.in/mgo.v2/bson"
)
const (
TypeIsDBGrid = "isdbgrid"
TypeMongos = "mongos"
TypeMongod = "mongod"
TypeShardServer = "shardsvr"
milliToSeconds = 1000
shardingNotEnabledErrorCode = 203
ErrNotYetInitialized = int32(94)
ErrNoReplicationEnabled = int32(76)
)
var (
CannotGetQueryError = errors.New("cannot get query field from the profile document (it is not a map)")
ShardingNotEnabledError = errors.New("sharding not enabled")
ErrCannotGetProcess = fmt.Errorf("cannot get process")
ErrCannotGetClusterID = fmt.Errorf("cannot get cluster ID")
)
func GetReplicasetMembers(ctx context.Context, clientOptions *options.ClientOptions) ([]proto.Members, error) {
@@ -26,6 +42,7 @@ func GetReplicasetMembers(ctx context.Context, clientOptions *options.ClientOpti
if err != nil {
return nil, errors.Wrap(err, "cannot get a new client for GetReplicasetMembers")
}
if err := client.Connect(ctx); err != nil {
return nil, errors.Wrap(err, "cannot connect to MongoDB")
}
@@ -34,6 +51,7 @@ func GetReplicasetMembers(ctx context.Context, clientOptions *options.ClientOpti
if err != nil {
return nil, err
}
if err := client.Disconnect(ctx); err != nil {
return nil, errors.Wrapf(err, "cannot disconnect from %v", clientOptions.Hosts)
}
@@ -54,7 +72,10 @@ func GetReplicasetMembers(ctx context.Context, clientOptions *options.ClientOpti
cmdOpts := proto.CommandLineOptions{}
// Not always we can get this info. For examples, we cannot get this for hidden hosts so
// if there is an error, just ignore it
res := client.Database("admin").RunCommand(ctx, primitive.D{{"getCmdLineOpts", 1}, {"recordStats", 1}})
res := client.Database("admin").RunCommand(ctx, primitive.D{
{Key: "getCmdLineOpts", Value: 1},
{Key: "recordStats", Value: 1},
})
if res.Err() == nil {
if err := res.Decode(&cmdOpts); err != nil {
return nil, errors.Wrapf(err, "cannot decode getCmdLineOpts response for host %s", hostname)
@@ -62,6 +83,7 @@ func GetReplicasetMembers(ctx context.Context, clientOptions *options.ClientOpti
}
rss := proto.ReplicaSetStatus{}
res = client.Database("admin").RunCommand(ctx, primitive.M{"replSetGetStatus": 1})
if res.Err() != nil {
m := proto.Members{
@@ -73,26 +95,34 @@ func GetReplicasetMembers(ctx context.Context, clientOptions *options.ClientOpti
m.ID = serverStatus.Pid
m.StorageEngine = serverStatus.StorageEngine
}
membersMap[m.Name] = m
continue // If a host is a mongos we cannot get info but is not a real error
}
if err := res.Decode(&rss); err != nil {
return nil, errors.Wrap(err, "cannot decode replSetGetStatus response")
}
for _, m := range rss.Members {
if _, ok := membersMap[m.Name]; ok {
continue // already exists
}
m.Set = rss.Set
if serverStatus, err := GetServerStatus(ctx, client); err == nil {
m.ID = serverStatus.Pid
m.StorageEngine = serverStatus.StorageEngine
if cmdOpts.Parsed.Sharding.ClusterRole != "" {
m.StateStr = cmdOpts.Parsed.Sharding.ClusterRole + "/" + m.StateStr
}
m.StateStr = strings.ToUpper(m.StateStr)
}
membersMap[m.Name] = m
}
@@ -104,30 +134,36 @@ func GetReplicasetMembers(ctx context.Context, clientOptions *options.ClientOpti
}
sort.Slice(members, func(i, j int) bool { return members[i].Name < members[j].Name })
return members, nil
}
func GetHostnames(ctx context.Context, client *mongo.Client) ([]string, error) {
// Probably we are connected to an individual member of a replica set
rss := proto.ReplicaSetStatus{}
res := client.Database("admin").RunCommand(ctx, primitive.M{"replSetGetStatus": 1})
if res.Err() == nil {
if err := res.Decode(&rss); err != nil {
return nil, errors.Wrap(err, "cannot decode replSetGetStatus response for GetHostnames")
}
return buildHostsListFromReplStatus(rss), nil
}
// Try getShardMap first. If we are connected to a mongos it will return
// all hosts, including config hosts
var shardsMap proto.ShardsMap
smRes := client.Database("admin").RunCommand(ctx, primitive.M{"getShardMap": 1})
if smRes.Err() != nil {
if e, ok := smRes.Err().(mongo.CommandError); ok && e.Code == shardingNotEnabledErrorCode {
return nil, ShardingNotEnabledError // standalone instance
}
return nil, errors.Wrap(smRes.Err(), "cannot getShardMap for GetHostnames")
}
if err := smRes.Decode(&shardsMap); err != nil {
return nil, errors.Wrap(err, "cannot decode getShardMap result for GetHostnames")
}
@@ -145,48 +181,47 @@ func GetHostnames(ctx context.Context, client *mongo.Client) ([]string, error) {
return nil, nil // standalone instance
}
/*
"members" : [
{
"_id" : 0,
"name" : "localhost:17001",
"health" : 1,
"state" : 1,
"stateStr" : "PRIMARY",
"uptime" : 4700,
"optime" : Timestamp(1486554836, 1),
"optimeDate" : ISODate("2017-02-08T11:53:56Z"),
"electionTime" : Timestamp(1486651810, 1),
"electionDate" : ISODate("2017-02-09T14:50:10Z"),
"configVersion" : 1,
"self" : true
},
*/
func buildHostsListFromReplStatus(replStatus proto.ReplicaSetStatus) []string {
/*
"members" : [
{
"_id" : 0,
"name" : "localhost:17001",
"health" : 1,
"state" : 1,
"stateStr" : "PRIMARY",
"uptime" : 4700,
"optime" : Timestamp(1486554836, 1),
"optimeDate" : ISODate("2017-02-08T11:53:56Z"),
"electionTime" : Timestamp(1486651810, 1),
"electionDate" : ISODate("2017-02-09T14:50:10Z"),
"configVersion" : 1,
"self" : true
},
*/
hostnames := []string{}
for _, member := range replStatus.Members {
hostnames = append(hostnames, member.Name)
}
sort.Strings(hostnames) // to make testing easier
return hostnames
}
/* Example
mongos> db.getSiblingDB('admin').runCommand('getShardMap')
{
"map" : {
"config" : "localhost:19001,localhost:19002,localhost:19003",
"localhost:17001" : "r1/localhost:17001,localhost:17002,localhost:17003",
"r1" : "r1/localhost:17001,localhost:17002,localhost:17003",
"r1/localhost:17001,localhost:17002,localhost:17003" : "r1/localhost:17001,localhost:17002,localhost:17003",
},
"ok" : 1
}.
*/
func buildHostsListFromShardMap(shardsMap proto.ShardsMap) []string {
/* Example
mongos> db.getSiblingDB('admin').runCommand('getShardMap')
{
"map" : {
"config" : "localhost:19001,localhost:19002,localhost:19003",
"localhost:17001" : "r1/localhost:17001,localhost:17002,localhost:17003",
"r1" : "r1/localhost:17001,localhost:17002,localhost:17003",
"r1/localhost:17001,localhost:17002,localhost:17003" : "r1/localhost:17001,localhost:17002,localhost:17003",
},
"ok" : 1
}
*/
hostnames := []string{}
hm := make(map[string]bool)
@@ -197,10 +232,11 @@ func buildHostsListFromShardMap(shardsMap proto.ShardsMap) []string {
for _, val := range shardsMap.Map {
m := strings.Split(val, "/")
hostsStr := ""
switch len(m) {
case 1:
hostsStr = m[0] // there is no / in the hosts list
case 2:
case 2: //nolint
hostsStr = m[1] // there is a / in the string. Remove the prefix until the / and keep the rest
}
// since there is no Sets in Go, build a map where the value is the map key
@@ -209,33 +245,39 @@ func buildHostsListFromShardMap(shardsMap proto.ShardsMap) []string {
hm[host] = false
}
}
for host := range hm {
hostnames = append(hostnames, host)
}
}
sort.Strings(hostnames)
return hostnames
}
// GetShardedHosts is like GetHostnames but it uses listShards instead of getShardMap
// so it won't include config servers in the returned list
// so it won't include config servers in the returned list.
func GetShardedHosts(ctx context.Context, client *mongo.Client) ([]string, error) {
shardsInfo := &proto.ShardsInfo{}
res := client.Database("admin").RunCommand(ctx, primitive.M{"listShards": 1})
if res.Err() != nil {
return nil, errors.Wrap(res.Err(), "cannot list shards")
}
if err := res.Decode(&shardsInfo); err != nil {
return nil, errors.Wrap(err, "cannot decode listShards response")
}
hostnames := []string{}
for _, shardInfo := range shardsInfo.Shards {
m := strings.Split(shardInfo.Host, "/")
h := strings.Split(m[1], ",")
hostnames = append(hostnames, h[0])
}
return hostnames, nil
}
@@ -248,6 +290,7 @@ func GetServerStatus(ctx context.Context, client *mongo.Client) (proto.ServerSta
{Key: "recordStats", Value: 1},
}
res := client.Database("admin").RunCommand(ctx, query)
if res.Err() != nil {
return ss, errors.Wrap(res.Err(), "GetHostInfo.serverStatus")
}
@@ -265,14 +308,17 @@ func GetQueryField(doc proto.SystemProfile) (primitive.M, error) {
// however MongoDB 3.0 doesn't have that field
// so we need to detect protocol by looking at actual data.
query := doc.Query
if len(doc.Command) > 0 {
if len(doc.Command) > 0 { //nolint
query = doc.Command
if doc.Op == "update" || doc.Op == "remove" {
if squery, ok := query.Map()["q"]; ok {
// just an extra check to ensure this type assertion won't fail
if ssquery, ok := squery.(primitive.M); ok {
return ssquery, nil
}
return nil, CannotGetQueryError
}
}
@@ -309,6 +355,7 @@ func GetQueryField(doc proto.SystemProfile) (primitive.M, error) {
if ssquery, ok := squery.(primitive.M); ok {
return ssquery, nil
}
return nil, CannotGetQueryError
}
@@ -317,6 +364,7 @@ func GetQueryField(doc proto.SystemProfile) (primitive.M, error) {
if ssquery, ok := squery.(primitive.M); ok {
return ssquery, nil
}
return nil, CannotGetQueryError
}
@@ -333,5 +381,173 @@ func GetQueryField(doc proto.SystemProfile) (primitive.M, error) {
func GetClientForHost(co *options.ClientOptions, newHost string) (*mongo.Client, error) {
newOptions := options.MergeClientOptions(co, &options.ClientOptions{Hosts: []string{newHost}})
newOptions.SetDirect(true)
return mongo.NewClient(newOptions)
}
func GetHostInfo(ctx context.Context, client *mongo.Client) (*proto.GetHostInfo, error) {
hi := proto.HostInfo{}
if err := client.Database("admin").RunCommand(ctx, primitive.M{"hostInfo": 1}).Decode(&hi); err != nil {
log.Debugf("run('hostInfo') error: %s", err)
return nil, errors.Wrap(err, "GetHostInfo.hostInfo")
}
cmdOpts := proto.CommandLineOptions{}
query := primitive.D{{Key: "getCmdLineOpts", Value: 1}, {Key: "recordStats", Value: 1}}
err := client.Database("admin").RunCommand(ctx, query).Decode(&cmdOpts)
if err != nil {
return nil, errors.Wrap(err, "cannot get command line options")
}
ss := proto.ServerStatus{}
query = primitive.D{{Key: "serverStatus", Value: 1}, {Key: "recordStats", Value: 1}}
if err := client.Database("admin").RunCommand(ctx, query).Decode(&ss); err != nil {
return nil, errors.Wrap(err, "GetHostInfo.serverStatus")
}
pi := proto.ProcInfo{}
if err := fillProcInfo(int32(ss.Pid), &pi); err != nil {
pi.Error = err
}
nodeType, _ := getNodeType(ctx, client)
procCount, _ := countMongodProcesses()
i := &proto.GetHostInfo{
Hostname: hi.System.Hostname,
HostOsType: hi.Os.Type,
HostSystemCPUArch: hi.System.CpuArch,
DBPath: "", // Sets default. It will be overridden later if necessary
ProcessName: ss.Process,
ProcProcessCount: procCount,
Version: ss.Version,
NodeType: nodeType,
ProcPath: pi.Path,
ProcUserName: pi.UserName,
ProcCreateTime: pi.CreateTime,
}
if ss.Repl != nil {
i.ReplicasetName = ss.Repl.SetName
}
if cmdOpts.Parsed.Storage.DbPath != "" {
i.DBPath = cmdOpts.Parsed.Storage.DbPath
}
return i, nil
}
func ClusterID(ctx context.Context, client *mongo.Client) (string, error) {
var cv proto.ConfigVersion
if err := client.Database("config").Collection("version").FindOne(ctx, bson.M{}).Decode(&cv); err == nil {
return cv.ClusterID.Hex(), nil
}
var si proto.ShardIdentity
filter := bson.M{"_id": "shardIdentity"}
if err := client.Database("admin").Collection("system.version").FindOne(ctx, filter).Decode(&si); err == nil {
return si.ClusterID.Hex(), nil
}
rc, err := ReplicasetConfig(ctx, client)
if err != nil {
if e, ok := err.(mongo.CommandError); ok && IsReplicationNotEnabledError(e) {
return "", nil
}
return "", err
}
return rc.Config.Settings.ReplicaSetID.Hex(), nil
}
func IsReplicationNotEnabledError(err mongo.CommandError) bool {
return err.Code == ErrNotYetInitialized || err.Code == ErrNoReplicationEnabled
}
func MyState(ctx context.Context, client *mongo.Client) (int, error) {
var ms proto.MyState
if err := client.Database("admin").RunCommand(ctx, bson.M{"getDiagnosticData": 1}).Decode(&ms); err != nil {
return 0, err
}
return ms.Data.ReplicasetGetStatus.MyState, nil
}
func ReplicasetConfig(ctx context.Context, client *mongo.Client) (*proto.ReplicasetConfig, error) {
var rs proto.ReplicasetConfig
if err := client.Database("admin").RunCommand(ctx, bson.M{"replSetGetConfig": 1}).Decode(&rs); err != nil {
return nil, err
}
return &rs, nil
}
func fillProcInfo(pid int32, procInfo *proto.ProcInfo) error {
proc, err := process.NewProcess(pid)
if err != nil {
return errors.Wrapf(ErrCannotGetProcess, "%s", err)
}
ct, err := proc.CreateTime()
if err != nil {
return err
}
procInfo.CreateTime = time.Unix(ct/milliToSeconds, 0)
if procInfo.Path, err = proc.Exe(); err != nil {
return err
}
if procInfo.UserName, err = proc.Username(); err != nil {
return err
}
return nil
}
func getNodeType(ctx context.Context, client *mongo.Client) (string, error) {
md := proto.MasterDoc{}
if err := client.Database("admin").RunCommand(ctx, primitive.M{"isMaster": 1}).Decode(&md); err != nil {
return "", err
}
if md.SetName != nil || md.Hosts != nil {
return TypeShardServer, nil
} else if md.Msg == TypeIsDBGrid {
// isdbgrid is always the msg value when calling isMaster on a mongos
// see http://docs.mongodb.org/manual/core/sharded-cluster-query-router/
return TypeMongos, nil
}
return TypeMongod, nil
}
func countMongodProcesses() (int, error) {
pids, err := process.Pids()
if err != nil {
return 0, err
}
count := 0
for _, pid := range pids {
p, err := process.NewProcess(pid)
if err != nil {
continue
}
if name, _ := p.Name(); name == TypeMongod || name == TypeMongos {
count++
}
}
return count, nil
}

View File

@@ -8,6 +8,7 @@ import (
"time"
tu "github.com/percona/percona-toolkit/src/go/internal/testutils"
"github.com/stretchr/testify/assert"
"go.mongodb.org/mongo-driver/mongo"
"go.mongodb.org/mongo-driver/mongo/options"
)
@@ -20,34 +21,58 @@ func TestGetHostnames(t *testing.T) {
wantError bool
}{
{
name: "from_mongos",
uri: fmt.Sprintf("mongodb://%s:%s@%s:%s", tu.MongoDBUser, tu.MongoDBPassword, tu.MongoDBHost, tu.MongoDBMongosPort),
name: "from_mongos",
uri: fmt.Sprintf("mongodb://%s:%s@%s:%s",
tu.MongoDBUser,
tu.MongoDBPassword,
tu.MongoDBHost,
tu.MongoDBMongosPort,
),
want: []string{"127.0.0.1:17001", "127.0.0.1:17002", "127.0.0.1:17004", "127.0.0.1:17005", "127.0.0.1:17007"},
wantError: false,
},
{
name: "from_mongod",
uri: fmt.Sprintf("mongodb://%s:%s@%s:%s", tu.MongoDBUser, tu.MongoDBPassword, tu.MongoDBHost, tu.MongoDBShard1PrimaryPort),
name: "from_mongod",
uri: fmt.Sprintf("mongodb://%s:%s@%s:%s",
tu.MongoDBUser,
tu.MongoDBPassword,
tu.MongoDBHost,
tu.MongoDBShard1PrimaryPort,
),
want: []string{"127.0.0.1:17001", "127.0.0.1:17002", "127.0.0.1:17003"},
wantError: false,
},
{
name: "from_non_sharded",
uri: fmt.Sprintf("mongodb://%s:%s@%s:%s", tu.MongoDBUser, tu.MongoDBPassword, tu.MongoDBHost, tu.MongoDBShard3PrimaryPort),
name: "from_non_sharded",
uri: fmt.Sprintf("mongodb://%s:%s@%s:%s",
tu.MongoDBUser,
tu.MongoDBPassword,
tu.MongoDBHost,
tu.MongoDBShard3PrimaryPort,
),
want: []string{"127.0.0.1:17021", "127.0.0.1:17022", "127.0.0.1:17023"},
wantError: false,
},
{
name: "from_standalone",
uri: fmt.Sprintf("mongodb://%s:%s@%s:%s", tu.MongoDBUser, tu.MongoDBPassword, tu.MongoDBHost, tu.MongoDBStandalonePort),
name: "from_standalone",
uri: fmt.Sprintf("mongodb://%s:%s@%s:%s",
tu.MongoDBUser,
tu.MongoDBPassword,
tu.MongoDBHost,
tu.MongoDBStandalonePort,
),
want: nil,
wantError: true,
},
}
for _, test := range testCases {
uri := test.uri
want := test.want
wantError := test.wantError
t.Run(test.name, func(t *testing.T) {
client, err := mongo.NewClient(options.Client().ApplyURI(test.uri))
client, err := mongo.NewClient(options.Client().ApplyURI(uri))
if err != nil {
t.Fatalf("cannot get a new MongoDB client: %s", err)
}
@@ -59,12 +84,12 @@ func TestGetHostnames(t *testing.T) {
}
hostnames, err := GetHostnames(ctx, client)
if err != nil && !test.wantError {
if err != nil && !wantError {
t.Errorf("Expecting error=nil, got: %v", err)
}
if !reflect.DeepEqual(hostnames, test.want) {
t.Errorf("Invalid hostnames. Got: %+v, want %+v", hostnames, test.want)
if !reflect.DeepEqual(hostnames, want) {
t.Errorf("Invalid hostnames. Got: %+v, want %+v", hostnames, want)
}
})
}
@@ -194,3 +219,139 @@ func TestGetShardedHosts(t *testing.T) {
})
}
}
func TestReplicasetConfig(t *testing.T) {
ctx, cancel := context.WithTimeout(context.Background(), time.Second)
defer cancel()
tcs := []struct {
port string
wantID string
wantConfigServer bool
wantError error
}{
{
port: tu.MongoDBStandalonePort,
wantID: "",
wantConfigServer: false,
wantError: mongo.CommandError{
Code: 76,
Message: "not running with --replSet",
Labels: []string(nil),
Name: "NoReplicationEnabled",
},
},
{
port: tu.MongoDBMongosPort,
wantID: "",
wantConfigServer: false,
wantError: mongo.CommandError{
Code: 59,
Message: "no such cmd: replSetGetConfig",
Labels: []string(nil),
Name: "CommandNotFound",
},
},
{
port: tu.MongoDBShard1PrimaryPort,
wantID: "rs1",
wantConfigServer: false,
},
{
port: tu.MongoDBConfigsvr1Port,
wantID: "csReplSet",
wantConfigServer: true,
},
}
for _, tc := range tcs {
client, err := tu.TestClient(ctx, tc.port)
assert.NoError(t, err)
rs, err := ReplicasetConfig(ctx, client)
assert.Equal(t, tc.wantError, err, fmt.Sprintf("%v", tc.port))
if tc.wantError != nil {
continue
}
assert.Equal(t, tc.wantID, rs.Config.ID)
assert.Equal(t, tc.wantConfigServer, rs.Config.ConfigServer)
assert.NotEmpty(t, rs.Config.Settings.ReplicaSetID.Hex())
}
}
func TestClusterID(t *testing.T) {
ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
defer cancel()
tcs := []struct {
port string
emptyID bool
}{
{
port: tu.MongoDBMongosPort,
emptyID: false,
},
{
port: tu.MongoDBShard1PrimaryPort,
emptyID: false,
},
{
port: tu.MongoDBShard1Secondary1Port,
emptyID: false,
},
{
port: tu.MongoDBConfigsvr1Port,
emptyID: false,
},
{
port: tu.MongoDBStandalonePort,
emptyID: true,
},
}
for _, tc := range tcs {
client, err := tu.TestClient(ctx, tc.port)
assert.NoError(t, err)
cid, err := ClusterID(ctx, client)
assert.NoError(t, err, fmt.Sprintf("port: %v", tc.port))
assert.Equal(t, cid == "", tc.emptyID)
}
}
func TestMyState(t *testing.T) {
ctx, cancel := context.WithTimeout(context.Background(), time.Second)
defer cancel()
tcs := []struct {
port string
want int
}{
{
port: tu.MongoDBShard1PrimaryPort,
want: 1,
},
{
port: tu.MongoDBShard1Secondary1Port,
want: 2,
},
{
port: tu.MongoDBMongosPort,
want: 0,
},
{
port: tu.MongoDBStandalonePort,
want: 0,
},
}
for _, tc := range tcs {
client, err := tu.TestClient(ctx, tc.port)
assert.NoError(t, err)
state, err := MyState(ctx, client)
assert.NoError(t, err)
assert.Equal(t, tc.want, state, fmt.Sprintf("port: %v", tc.port))
}
}

View File

@@ -70,7 +70,6 @@ type report struct {
}
func main() {
opts, err := getOptions()
if err != nil {
log.Errorf("error processing command line arguments: %s", err)
@@ -193,7 +192,6 @@ func main() {
}
fmt.Println(string(out))
}
func formatResults(rep report, outputFormat string) ([]byte, error) {
@@ -368,7 +366,6 @@ func getHeaders(opts *cliOptions) []string {
}
func getQueryTemplate() string {
t := `
# Query {{.Rank}}: {{printf "% 0.2f" .QPS}} QPS, ID {{.ID}}
# Ratio {{Format .Ratio 7.2}} (docs scanned/returned)
@@ -522,7 +519,6 @@ func sortQueries(queries []stats.QueryStats, orderby []string) []stats.QueryStat
OrderedBy(sortFuncs...).Sort(queries)
return queries
}
func isProfilerEnabled(ctx context.Context, clientOptions *options.ClientOptions) (bool, error) {

View File

@@ -1,6 +1,6 @@
package main
//TODO: Rewrite tests to use the new sandbox
// TODO: Rewrite tests to use the new sandbox
// const (
// samples = "/src/go/tests/"

View File

@@ -3,11 +3,16 @@ package main
import (
"bytes"
"context"
"crypto/tls"
"crypto/x509"
"encoding/json"
"fmt"
"html/template"
"io/ioutil"
"net"
"os"
"os/user"
"path/filepath"
"strings"
"time"
@@ -39,18 +44,23 @@ const (
DefaultOutputFormat = "text"
typeMongos = "mongos"
// Exit Codes
// Exit Codes.
cannotFormatResults = 1
cannotParseCommandLineParameters = 2
cannotGetHostInfo = 3
cannotGetReplicasetMembers = 4
cannotGetClientOptions = 4
cannotConnectToMongoDB = 5
)
//nolint:gochecknoglobals
var (
Build string = "2020-04-23" // nolint
GoVersion string = "1.14.1" // nolint
Build string = "2020-04-23"
GoVersion string = "1.14.1"
Version string = "3.2.0"
Commit string
defaultConnectionTimeout = 3 * time.Second
directConnection = true
)
type TimedStats struct {
@@ -69,6 +79,7 @@ type opCounters struct {
Command TimedStats
SampleRate time.Duration
}
type hostInfo struct {
Hostname string
HostOsType string
@@ -164,14 +175,11 @@ func main() {
opts, err := parseFlags()
if err != nil {
log.Errorf("cannot get parameters: %s", err.Error())
os.Exit(cannotParseCommandLineParameters)
}
if opts == nil && err == nil {
return
}
if opts.Help {
getopt.Usage()
if opts == nil && err == nil {
return
}
@@ -187,6 +195,7 @@ func main() {
fmt.Printf("Version %s\n", Version)
fmt.Printf("Build: %s using %s\n", Build, GoVersion)
fmt.Printf("Commit: %s\n", Commit)
return
}
@@ -201,34 +210,46 @@ func main() {
}
ctx := context.Background()
clientOptions := getClientOptions(opts)
clientOptions, err := getClientOptions(opts)
if err != nil {
log.Error(err)
os.Exit(cannotGetClientOptions)
}
client, err := mongo.NewClient(clientOptions)
if err != nil {
log.Fatalf("Cannot get a MongoDB client: %s", err)
log.Errorf("Cannot get a MongoDB client: %s", err)
os.Exit(cannotConnectToMongoDB)
}
if err := client.Connect(ctx); err != nil {
log.Fatalf("Cannot connect to MongoDB: %s", err)
log.Errorf("Cannot connect to MongoDB: %s", err)
os.Exit(cannotConnectToMongoDB)
}
defer client.Disconnect(ctx) // nolint
hostnames, err := util.GetHostnames(ctx, client)
if err != nil && errors.Is(err, util.ShardingNotEnabledError) {
log.Errorf("Cannot get hostnames: %s", err)
}
log.Debugf("hostnames: %v", hostnames)
ci := &collectedInfo{}
ci.HostInfo, err = getHostInfo(ctx, client)
if err != nil {
message := fmt.Sprintf("Cannot get host info for %q: %s", opts.Host, err.Error())
log.Errorf(message)
os.Exit(cannotGetHostInfo)
log.Errorf("Cannot get host info for %q: %s", opts.Host, err)
os.Exit(cannotGetHostInfo) //nolint:gocritic
}
if ci.ReplicaMembers, err = util.GetReplicasetMembers(ctx, clientOptions); err != nil {
log.Warnf("[Error] cannot get replicaset members: %v\n", err)
}
log.Debugf("replicaMembers:\n%+v\n", ci.ReplicaMembers)
if opts.RunningOpsSamples > 0 && opts.RunningOpsInterval > 0 {
@@ -274,9 +295,10 @@ func main() {
out, err := formatResults(ci, opts.OutputFormat)
if err != nil {
log.Errorf("Cannot format the results: %s", err.Error())
log.Errorf("Cannot format the results: %s", err)
os.Exit(cannotFormatResults)
}
fmt.Println(string(out))
}
@@ -287,8 +309,9 @@ func formatResults(ci *collectedInfo, format string) ([]byte, error) {
case "json":
b, err := json.MarshalIndent(ci, "", " ")
if err != nil {
return nil, fmt.Errorf("[Error] Cannot convert results to json: %s", err.Error())
return nil, errors.Wrap(err, "Cannot convert results to json")
}
buf = bytes.NewBuffer(b)
default:
buf = new(bytes.Buffer)
@@ -338,6 +361,7 @@ func getHostInfo(ctx context.Context, client *mongo.Client) (*hostInfo, error) {
hi := proto.HostInfo{}
if err := client.Database("admin").RunCommand(ctx, primitive.M{"hostInfo": 1}).Decode(&hi); err != nil {
log.Debugf("run('hostInfo') error: %s", err)
return nil, errors.Wrap(err, "GetHostInfo.hostInfo")
}
@@ -393,12 +417,15 @@ func countMongodProcesses() (int, error) {
if err != nil {
return 0, err
}
count := 0
for _, pid := range pids {
p, err := process.NewProcess(pid)
if err != nil {
continue
}
if name, _ := p.Name(); name == "mongod" || name == typeMongos {
count++
}
@@ -440,6 +467,7 @@ func getClusterwideInfo(ctx context.Context, client *mongo.Client) (*clusterwide
if collStats.Sharded {
cwi.ShardedDataSize += collStats.Size
cwi.ShardedColsCount++
continue
}
@@ -464,11 +492,14 @@ func sizeAndUnit(size int64) (float64, string) {
unit := []string{"bytes", "KB", "MB", "GB", "TB"}
idx := 0
newSize := float64(size)
for newSize > 1024 {
newSize /= 1024
idx++
}
newSize = float64(int64(newSize*100)) / 100
return newSize, unit[idx]
}
@@ -486,7 +517,10 @@ func getSecuritySettings(ctx context.Context, client *mongo.Client, ver string)
}
cmdOpts := proto.CommandLineOptions{}
err = client.Database("admin").RunCommand(ctx, primitive.D{{"getCmdLineOpts", 1}, {"recordStats", 1}}).Decode(&cmdOpts)
err = client.Database("admin").RunCommand(ctx, primitive.D{
{Key: "getCmdLineOpts", Value: 1},
{Key: "recordStats", Value: 1},
}).Decode(&cmdOpts)
if err != nil {
return nil, errors.Wrap(err, "cannot get command line options")
}
@@ -503,7 +537,7 @@ func getSecuritySettings(ctx context.Context, client *mongo.Client, ver string)
s.BindIP = cmdOpts.Parsed.Net.BindIP
s.Port = cmdOpts.Parsed.Net.Port
if cmdOpts.Parsed.Net.BindIP == "" {
if cmdOpts.Parsed.Net.BindIP == "" { //nolint:nestif
if prior26 {
s.WarningMsgs = append(s.WarningMsgs, "WARNING: You might be insecure. There is no IP binding")
}
@@ -586,7 +620,11 @@ func getOpCountersStats(ctx context.Context, client *mongo.Client, count int,
// count + 1 because we need 1st reading to stablish a base to measure variation
for i := 0; i < count+1; i++ {
<-ticker.C
err := client.Database("admin").RunCommand(ctx, primitive.D{{"serverStatus", 1}, {"recordStats", 1}}).Decode(&ss)
err := client.Database("admin").RunCommand(ctx, primitive.D{
{Key: "serverStatus", Value: 1},
{Key: "recordStats", Value: 1},
}).Decode(&ss)
if err != nil {
return nil, err
}
@@ -598,6 +636,7 @@ func getOpCountersStats(ctx context.Context, client *mongo.Client, count int,
prevOpCount.Insert.Total = ss.Opcounters.Insert
prevOpCount.Query.Total = ss.Opcounters.Query
prevOpCount.Update.Total = ss.Opcounters.Update
continue
}
@@ -631,57 +670,63 @@ func getOpCountersStats(ctx context.Context, client *mongo.Client, count int,
}
// Insert --------------------------------------
if delta.Opcounters.Insert > oc.Insert.Max {
switch {
case delta.Opcounters.Insert > oc.Insert.Max:
oc.Insert.Max = delta.Opcounters.Insert
}
if delta.Opcounters.Insert < oc.Insert.Min {
case delta.Opcounters.Insert < oc.Insert.Min:
oc.Insert.Min = delta.Opcounters.Insert
}
oc.Insert.Total += delta.Opcounters.Insert
// Query ---------------------------------------
if delta.Opcounters.Query > oc.Query.Max {
switch {
case delta.Opcounters.Query > oc.Query.Max:
oc.Query.Max = delta.Opcounters.Query
}
if delta.Opcounters.Query < oc.Query.Min {
case delta.Opcounters.Query < oc.Query.Min:
oc.Query.Min = delta.Opcounters.Query
}
oc.Query.Total += delta.Opcounters.Query
// Command -------------------------------------
if delta.Opcounters.Command > oc.Command.Max {
switch {
case delta.Opcounters.Command > oc.Command.Max:
oc.Command.Max = delta.Opcounters.Command
}
if delta.Opcounters.Command < oc.Command.Min {
case delta.Opcounters.Command < oc.Command.Min:
oc.Command.Min = delta.Opcounters.Command
}
oc.Command.Total += delta.Opcounters.Command
// Update --------------------------------------
if delta.Opcounters.Update > oc.Update.Max {
switch {
case delta.Opcounters.Update > oc.Update.Max:
oc.Update.Max = delta.Opcounters.Update
}
if delta.Opcounters.Update < oc.Update.Min {
case delta.Opcounters.Update < oc.Update.Min:
oc.Update.Min = delta.Opcounters.Update
}
oc.Update.Total += delta.Opcounters.Update
// Delete --------------------------------------
if delta.Opcounters.Delete > oc.Delete.Max {
switch {
case delta.Opcounters.Delete > oc.Delete.Max:
oc.Delete.Max = delta.Opcounters.Delete
}
if delta.Opcounters.Delete < oc.Delete.Min {
case delta.Opcounters.Delete < oc.Delete.Min:
oc.Delete.Min = delta.Opcounters.Delete
}
oc.Delete.Total += delta.Opcounters.Delete
// GetMore -------------------------------------
if delta.Opcounters.GetMore > oc.GetMore.Max {
switch {
case delta.Opcounters.GetMore > oc.GetMore.Max:
oc.GetMore.Max = delta.Opcounters.GetMore
}
if delta.Opcounters.GetMore < oc.GetMore.Min {
case delta.Opcounters.GetMore < oc.GetMore.Min:
oc.GetMore.Min = delta.Opcounters.GetMore
}
oc.GetMore.Total += delta.Opcounters.GetMore
prevOpCount.Insert.Total = ss.Opcounters.Insert
@@ -690,8 +735,8 @@ func getOpCountersStats(ctx context.Context, client *mongo.Client, count int,
prevOpCount.Update.Total = ss.Opcounters.Update
prevOpCount.Delete.Total = ss.Opcounters.Delete
prevOpCount.GetMore.Total = ss.Opcounters.GetMore
}
ticker.Stop()
oc.Insert.Avg = oc.Insert.Total
@@ -707,11 +752,12 @@ func getOpCountersStats(ctx context.Context, client *mongo.Client, count int,
}
func getProcInfo(pid int32, templateData *procInfo) error {
//proc, err := process.NewProcess(templateData.ServerStatus.Pid)
// proc, err := process.NewProcess(templateData.ServerStatus.Pid)
proc, err := process.NewProcess(pid)
if err != nil {
return fmt.Errorf("cannot get process %d", pid)
return errors.New(fmt.Sprintf("cannot get process %d", pid))
}
ct, err := proc.CreateTime()
if err != nil {
return err
@@ -742,6 +788,7 @@ func GetBalancerStats(ctx context.Context, client *mongo.Client) (*proto.Balance
event := item.Id.Event
note := item.Id.Note
count := item.Count
switch event {
case "moveChunk.to", "moveChunk.from", "moveChunk.commit":
if note == "success" || note == "" {
@@ -760,7 +807,7 @@ func GetBalancerStats(ctx context.Context, client *mongo.Client) (*proto.Balance
}
func GetShardingChangelogStatus(ctx context.Context, client *mongo.Client) (*proto.ShardingChangelogStats, error) {
var qresults []proto.ShardingChangelogSummary
qresults := []proto.ShardingChangelogSummary{}
coll := client.Database("config").Collection("changelog")
match := primitive.M{"time": primitive.M{"$gt": time.Now().Add(-240 * time.Hour)}}
group := primitive.M{"_id": primitive.M{"event": "$what", "note": "$details.note"}, "count": primitive.M{"$sum": 1}}
@@ -776,6 +823,7 @@ func GetShardingChangelogStatus(ctx context.Context, client *mongo.Client) (*pro
if err := cursor.Decode(&res); err != nil {
return nil, errors.Wrap(err, "cannot decode GetShardingChangelogStatus")
}
qresults = append(qresults, res)
}
@@ -796,6 +844,7 @@ func isPrivateNetwork(ip string) (bool, error) {
if err != nil {
return false, err
}
addr := net.ParseIP(ip)
if cidrnet.Contains(addr) {
return true, nil
@@ -803,7 +852,6 @@ func isPrivateNetwork(ip string) (bool, error) {
}
return false, nil
}
func externalIP() (string, error) {
@@ -811,17 +859,21 @@ func externalIP() (string, error) {
if err != nil {
return "", err
}
for _, iface := range ifaces {
if iface.Flags&net.FlagUp == 0 {
continue // interface down
}
if iface.Flags&net.FlagLoopback != 0 {
continue // loopback interface
}
addrs, err := iface.Addrs()
if err != nil {
return "", err
}
for _, addr := range addrs {
var ip net.IP
switch v := addr.(type) {
@@ -830,9 +882,11 @@ func externalIP() (string, error) {
case *net.IPAddr:
ip = v.IP
}
if ip == nil || ip.IsLoopback() {
continue
}
ip = ip.To4()
if ip == nil {
continue // not an ipv4 address
@@ -840,6 +894,7 @@ func externalIP() (string, error) {
return ip.String(), nil
}
}
return "", errors.New("are you connected to the network?")
}
@@ -880,8 +935,8 @@ func parseFlags() (*cliOptions, error) {
gop.StringVarLong(&opts.SSLPEMKeyFile, "sslPEMKeyFile", 0, "SSL client PEM file used for authentication")
gop.SetParameters("host[:port]")
gop.Parse(os.Args)
if gop.NArgs() > 0 {
opts.Host = gop.Arg(0)
gop.Parse(gop.Args())
@@ -889,19 +944,25 @@ func parseFlags() (*cliOptions, error) {
if gop.IsSet("password") && opts.Password == "" {
print("Password: ")
pass, err := gopass.GetPasswd()
if err != nil {
return opts, err
}
opts.Password = string(pass)
}
if !strings.HasPrefix(opts.Host, "mongodb://") {
opts.Host = "mongodb://" + opts.Host
}
if opts.Help {
gop.PrintUsage(os.Stdout)
return nil, nil
}
if opts.OutputFormat != "json" && opts.OutputFormat != "text" {
log.Infof("Invalid output format '%s'. Using text format", opts.OutputFormat)
}
@@ -920,27 +981,93 @@ func getChunksCount(ctx context.Context, client *mongo.Client) ([]proto.ChunksBy
if err != nil {
return nil, err
}
for cursor.Next(ctx) {
res := proto.ChunksByCollection{}
if err := cursor.Decode(&res); err != nil {
return nil, errors.Wrap(err, "cannot decode chunks aggregation")
}
result = append(result, res)
}
return result, nil
}
func getClientOptions(opts *cliOptions) *options.ClientOptions {
func getClientOptions(opts *cliOptions) (*options.ClientOptions, error) {
clientOptions := options.Client().ApplyURI(opts.Host)
clientOptions.ServerSelectionTimeout = &defaultConnectionTimeout
clientOptions.Direct = &directConnection
credential := options.Credential{}
if opts.User != "" {
credential.Username = opts.User
clientOptions.SetAuth(credential)
}
if opts.Password != "" {
credential.Password = opts.Password
credential.PasswordSet = true
clientOptions.SetAuth(credential)
}
return clientOptions
if opts.SSLPEMKeyFile != "" || opts.SSLCAFile != "" {
tlsConfig, err := getTLSConfig(opts.SSLPEMKeyFile, opts.SSLCAFile)
if err != nil {
return nil, errors.Wrap(err, "cannot read SSL certificate files")
}
clientOptions.TLSConfig = tlsConfig
}
return clientOptions, nil
}
func getTLSConfig(sslPEMKeyFile, sslCAFile string) (*tls.Config, error) {
tlsConfig := &tls.Config{
MinVersion: tls.VersionTLS10,
InsecureSkipVerify: true,
}
roots := x509.NewCertPool()
if sslPEMKeyFile != "" {
crt, err := ioutil.ReadFile(filepath.Clean(expandHome(sslPEMKeyFile)))
if err != nil {
return nil, err
}
cert, err := tls.X509KeyPair(crt, crt)
if err != nil {
log.Fatal(err)
}
tlsConfig.Certificates = []tls.Certificate{cert}
}
if sslCAFile != "" {
ca, err := ioutil.ReadFile(filepath.Clean(expandHome(sslCAFile)))
if err != nil {
return nil, err
}
roots.AppendCertsFromPEM(ca)
tlsConfig.RootCAs = roots
}
return tlsConfig, nil
}
func expandHome(path string) string {
usr, _ := user.Current()
dir := usr.HomeDir
switch {
case path == "~":
path = dir
case strings.HasPrefix(path, "~/"):
path = filepath.Join(dir, path[2:])
}
return path
}

View File

@@ -99,8 +99,8 @@ func TestClusterWideInfo(t *testing.T) {
}
})
}
}
func addToCounters(ss proto.ServerStatus, increment int64) proto.ServerStatus {
ss.Opcounters.Command += increment
ss.Opcounters.Delete += increment

View File

@@ -85,7 +85,6 @@ func GetOplogInfo(ctx context.Context, hostnames []string, co *options.ClientOpt
sort.Sort(results)
return results, nil
}
func getOplogCollection(ctx context.Context, client *mongo.Client) (string, error) {

View File

@@ -31,6 +31,7 @@ type connOpts struct {
Password string
DisableSSL bool
}
type cliOptions struct {
app *kingpin.Application
connOpts connOpts
@@ -110,7 +111,6 @@ func main() {
if err := masterTmpl.ExecuteTemplate(os.Stdout, "report", info); err != nil {
log.Fatal(err)
}
}
func connect(dsn string) (*sql.DB, error) {
@@ -131,29 +131,29 @@ func funcsMap() template.FuncMap {
if len(s) < size {
return s
}
return s[:size]+"..."
return s[:size] + "..."
},
"convertnullstring": func(s sql.NullString) string {
if s.Valid {
return s.String
} else {
return ""
}
},
"convertnullint64": func(s sql.NullInt64) int64 {
if s.Valid {
return s.Int64
} else {
return 0
}
},
"convertnullfloat64": func(s sql.NullFloat64) float64 {
if s.Valid {
return s.Float64
} else {
return 0.0
}
},
"convertnullstring": func(s sql.NullString) string {
if s.Valid {
return s.String
} else {
return ""
}
},
"convertnullint64": func(s sql.NullInt64) int64 {
if s.Valid {
return s.Int64
} else {
return 0
}
},
"convertnullfloat64": func(s sql.NullFloat64) float64 {
if s.Valid {
return s.Float64
} else {
return 0.0
}
},
}
}

View File

@@ -5,8 +5,8 @@ import (
"os"
"testing"
"github.com/percona/percona-toolkit/src/go/pt-pg-summary/internal/tu"
"github.com/percona/percona-toolkit/src/go/lib/pginfo"
"github.com/percona/percona-toolkit/src/go/pt-pg-summary/internal/tu"
"github.com/sirupsen/logrus"
)
@@ -37,7 +37,7 @@ func TestConnection(t *testing.T) {
// use an "external" IP to simulate a remote host
tests := append(tests, Test{"remote_host", tu.PG9DockerIP, tu.DefaultPGPort, tu.Username, tu.Password})
// use IPV6 for PostgreSQL 9
//tests := append(tests, Test{"IPV6", tu.IPv6Host, tu.IPv6PG9Port, tu.Username, tu.Password})
// tests := append(tests, Test{"IPV6", tu.IPv6Host, tu.IPv6PG9Port, tu.Username, tu.Password})
for _, test := range tests {
test := test
t.Run(test.name, func(t *testing.T) {
@@ -48,16 +48,15 @@ func TestConnection(t *testing.T) {
}
})
}
}
func TestNewWithLogger(t *testing.T) {
for _, test := range tests {
for _, test := range tests {
test := test
t.Run(test.name, func(t *testing.T) {
dsn := fmt.Sprintf("host=%s port=%s user=%s password=%s sslmode=disable dbname=%s",
test.host, test.port, test.username, test.password, "postgres")
db, err := connect(dsn);
db, err := connect(dsn)
if err != nil {
t.Errorf("Cannot connect to the db using %q: %s", dsn, err)
}
@@ -65,21 +64,20 @@ func TestNewWithLogger(t *testing.T) {
t.Errorf("Cannot run NewWithLogger using %q: %s", dsn, err)
}
})
}
}
}
func TestCollectGlobalInfo(t *testing.T) {
for _, test := range tests {
for _, test := range tests {
test := test
t.Run(test.name, func(t *testing.T) {
dsn := fmt.Sprintf("host=%s port=%s user=%s password=%s sslmode=disable dbname=%s",
test.host, test.port, test.username, test.password, "postgres")
db, err := connect(dsn);
db, err := connect(dsn)
if err != nil {
t.Errorf("Cannot connect to the db using %q: %s", dsn, err)
}
info, err := pginfo.NewWithLogger(db, nil, 30, logger);
info, err := pginfo.NewWithLogger(db, nil, 30, logger)
if err != nil {
t.Errorf("Cannot run NewWithLogger using %q: %s", dsn, err)
}
@@ -92,27 +90,27 @@ func TestCollectGlobalInfo(t *testing.T) {
t.Errorf("Cannot collect global information using %q", dsn)
}
})
}
}
}
func TestCollectPerDatabaseInfo(t *testing.T) {
for _, test := range tests {
for _, test := range tests {
test := test
t.Run(test.name, func(t *testing.T) {
dsn := fmt.Sprintf("host=%s port=%s user=%s password=%s sslmode=disable dbname=%s",
test.host, test.port, test.username, test.password, "postgres")
db, err := connect(dsn);
db, err := connect(dsn)
if err != nil {
t.Errorf("Cannot connect to the db using %q: %s", dsn, err)
}
info, err := pginfo.NewWithLogger(db, nil, 30, logger);
info, err := pginfo.NewWithLogger(db, nil, 30, logger)
if err != nil {
t.Errorf("Cannot run New using %q: %s", dsn, err)
}
for _, dbName := range info.DatabaseNames() {
dsn := fmt.Sprintf("host=%s port=%s user=%s password=%s sslmode=disable dbname=%s",
test.host, test.port, test.username, test.password, dbName)
conn, err := connect(dsn);
conn, err := connect(dsn)
if err != nil {
t.Errorf("Cannot connect to the %s database using %q: %s", dbName, dsn, err)
}
@@ -122,5 +120,5 @@ func TestCollectPerDatabaseInfo(t *testing.T) {
conn.Close()
}
})
}
}
}

View File

@@ -13,7 +13,7 @@ func GetAllDatabases(db XODB) ([]*AllDatabases, error) {
var err error
// sql query
var sqlstr = `SELECT datname ` +
sqlstr := `SELECT datname ` +
`FROM pg_database ` +
`WHERE datistemplate = false`

View File

@@ -24,7 +24,7 @@ func GetClusterInfos(db XODB) ([]*ClusterInfo, error) {
var err error
// sql query
var sqlstr = `SELECT usename, now() AS "Time", ` +
sqlstr := `SELECT usename, now() AS "Time", ` +
`client_addr, ` +
`client_hostname, ` +
`version() AS version, ` +

View File

@@ -20,7 +20,7 @@ func GetConnectedClients(db XODB) ([]*ConnectedClients, error) {
var err error
// sql query
var sqlstr = `SELECT usename, ` +
sqlstr := `SELECT usename, ` +
`CASE WHEN client_hostname IS NULL THEN client_addr::text ELSE client_hostname END AS client, ` +
`state, count(*) ` +
`FROM pg_stat_activity ` +

View File

@@ -14,7 +14,7 @@ func GetConnections(db XODB) ([]*Connections, error) {
var err error
// sql query
var sqlstr = `SELECT state, count(*) ` +
sqlstr := `SELECT state, count(*) ` +
`FROM pg_stat_activity ` +
`GROUP BY 1`

View File

@@ -27,7 +27,7 @@ func GetCounters(db XODB) ([]*Counters, error) {
var err error
// sql query
var sqlstr = `SELECT COALESCE(datname, '') datname, numbackends, xact_commit, xact_rollback, ` +
sqlstr := `SELECT COALESCE(datname, '') datname, numbackends, xact_commit, xact_rollback, ` +
`blks_read, blks_hit, tup_returned, tup_fetched, tup_inserted, ` +
`tup_updated, tup_deleted, conflicts, temp_files, ` +
`temp_bytes, deadlocks ` +

View File

@@ -14,7 +14,7 @@ func GetDatabases(db XODB) ([]*Databases, error) {
var err error
// sql query
var sqlstr = `SELECT datname, pg_size_pretty(pg_database_size(datname)) ` +
sqlstr := `SELECT datname, pg_size_pretty(pg_database_size(datname)) ` +
`FROM pg_stat_database ` +
`WHERE datid <> 0`

View File

@@ -22,7 +22,7 @@ func GetDatabaseWaitEvents(db XODB) ([]*DatabaseWaitEvents, error) {
var err error
// sql query
var sqlstr = `SELECT c.relname, c.relkind, d.wait_event_type, d.wait_event, b.datname, count(*) ` +
sqlstr := `SELECT c.relname, c.relkind, d.wait_event_type, d.wait_event, b.datname, count(*) ` +
`FROM pg_locks a ` +
`JOIN pg_stat_database b ON a.database=b.datid ` +
`JOIN pg_class c ON a.relation=c.oid ` +

View File

@@ -14,7 +14,7 @@ func GetPortAndDatadir(db XODB) (*PortAndDatadir, error) {
var err error
// sql query
var sqlstr = `SELECT name, ` +
sqlstr := `SELECT name, ` +
`setting ` +
`FROM pg_settings ` +
`WHERE name IN ('port','data_directory')`

View File

@@ -20,7 +20,7 @@ func GetSlaveHosts10s(db XODB) ([]*SlaveHosts10, error) {
var err error
// sql query
var sqlstr = `SELECT application_name, client_addr, state, sent_offset - (replay_offset - (sent_lsn - replay_lsn) * 255 * 16 ^ 6 ) AS byte_lag ` +
sqlstr := `SELECT application_name, client_addr, state, sent_offset - (replay_offset - (sent_lsn - replay_lsn) * 255 * 16 ^ 6 ) AS byte_lag ` +
`FROM ( SELECT application_name, client_addr, client_hostname, state, ` +
`('x' || lpad(split_part(sent_lsn::TEXT, '/', 1), 8, '0'))::bit(32)::bigint AS sent_lsn, ` +
`('x' || lpad(split_part(replay_lsn::TEXT, '/', 1), 8, '0'))::bit(32)::bigint AS replay_lsn, ` +

View File

@@ -20,7 +20,7 @@ func GetSlaveHosts96s(db XODB) ([]*SlaveHosts96, error) {
var err error
// sql query
var sqlstr = `SELECT application_name, client_addr, state, sent_offset - (replay_offset - (sent_xlog - replay_xlog) * 255 * 16 ^ 6 ) AS byte_lag ` +
sqlstr := `SELECT application_name, client_addr, state, sent_offset - (replay_offset - (sent_xlog - replay_xlog) * 255 * 16 ^ 6 ) AS byte_lag ` +
`FROM ( SELECT application_name, client_addr, client_hostname, state, ` +
`('x' || lpad(split_part(sent_location::TEXT, '/', 1), 8, '0'))::bit(32)::bigint AS sent_xlog, ` +
`('x' || lpad(split_part(replay_location::TEXT, '/', 1), 8, '0'))::bit(32)::bigint AS replay_xlog, ` +

View File

@@ -20,7 +20,7 @@ func GetTableAccesses(db XODB) ([]*TableAccess, error) {
var err error
// sql query
var sqlstr = `SELECT c.relname, c.relkind, b.datname datname, count(*) FROM pg_locks a ` +
sqlstr := `SELECT c.relname, c.relkind, b.datname datname, count(*) FROM pg_locks a ` +
`JOIN pg_stat_database b ` +
`ON a.database=b.datid ` +
`JOIN pg_class c ` +

View File

@@ -18,7 +18,7 @@ func GetTableCacheHitRatio(db XODB) (*TableCacheHitRatio, error) {
var err error
// sql query
var sqlstr = `SELECT 'cache hit rate' AS name, ` +
sqlstr := `SELECT 'cache hit rate' AS name, ` +
`CASE WHEN (sum(heap_blks_read) + sum(idx_blks_hit)) > 0 ` +
`THEN ` +
`sum(heap_blks_hit) / (sum(heap_blks_hit) + sum(heap_blks_read)) ` +

View File

@@ -15,7 +15,7 @@ func GetTablespaces(db XODB) ([]*Tablespaces, error) {
var err error
// sql query
var sqlstr = `SELECT spcname AS Name, ` +
sqlstr := `SELECT spcname AS Name, ` +
`pg_catalog.pg_get_userbyid(spcowner) AS Owner, ` +
`pg_catalog.pg_tablespace_location(oid) AS Location ` +
`FROM pg_catalog.pg_tablespace ` +

View File

@@ -57,7 +57,7 @@ var TPL = `{{define "report"}}
+----------------------+----------------------+----------------------------------------------------+
{{ end -}} {{/* end define */}}
` +
`{{- define "slaves_and_log_none" -}}
`{{- define "slaves_and_log_none" -}}
##### --- Slave and the lag with Master --- ####
There are no slave hosts
{{ end -}} {{/* end define */}}

View File

@@ -50,7 +50,7 @@ func encrypt(infile, outfile string, pass [32]byte) error {
var iv [aes.BlockSize]byte
stream := cipher.NewOFB(block, iv[:])
outFile, err := os.OpenFile(outfile, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0600)
outFile, err := os.OpenFile(outfile, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0o600)
if err != nil {
return errors.Wrapf(err, "Cannot create output file %q", outfile)
}
@@ -81,7 +81,7 @@ func decrypt(infile, outfile string, pass [32]byte) error {
var iv [aes.BlockSize]byte
stream := cipher.NewOFB(block, iv[:])
outFile, err := os.OpenFile(outfile, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0600)
outFile, err := os.OpenFile(outfile, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0o600)
if err != nil {
return errors.Wrapf(err, "Cannot open %q for writing", outfile)
}

View File

@@ -32,11 +32,9 @@ func TestProcessCliParams(t *testing.T) {
t.Errorf("Test #%d expected error, have nil", i)
}
if !reflect.DeepEqual(opts, test.WantOpts) {
}
}
}
func TestCollect(t *testing.T) {
}

View File

@@ -6,12 +6,12 @@ cd $BASEDIR
source ${BASEDIR}/src/go/setenv.sh
for dir in $(ls -d ./src/go/pt-*)
for dir in $(ls -d ./src/go/pt-* ) ./src/go/mongolib
do
echo "Running tests at $BASEDIR/$dir"
cd $BASEDIR/$dir
go get ./...
go test -v -coverprofile=coverage.out
go test -v -coverprofile=coverage.out ./...
if [ -f coverage.out ]
then
go tool cover -func=coverage.out

95
t/pt-heartbeat/pt-1857.t Normal file
View File

@@ -0,0 +1,95 @@
#!/usr/bin/env perl
BEGIN {
die "The PERCONA_TOOLKIT_BRANCH environment variable is not set.\n"
unless $ENV{PERCONA_TOOLKIT_BRANCH} && -d $ENV{PERCONA_TOOLKIT_BRANCH};
unshift @INC, "$ENV{PERCONA_TOOLKIT_BRANCH}/lib";
};
use strict;
use warnings FATAL => 'all';
use threads ('yield');
use English qw(-no_match_vars);
use Test::More;
use Data::Dumper;
use PerconaTest;
use Sandbox;
use SqlModes;
use File::Temp qw/ tempfile /;
plan tests => 2;
require "$trunk/bin/pt-heartbeat";
my $dp = new DSNParser(opts=>$dsn_opts);
my $sb = new Sandbox(basedir => '/tmp', DSNParser => $dp);
my $master_dbh = $sb->get_dbh_for('master');
my $master_dsn = 'h=127.1,P=12345,u=msandbox,p=msandbox';
my $slave1_dbh = $sb->get_dbh_for('slave1');
my $slave1_dsn = 'h=127.1,P=12346,u=unprivileged,p=password';
if ( !$master_dbh ) {
plan skip_all => 'Cannot connect to sandbox master';
}
sub start_thread {
my ($dsn_opts, $sleep) = @_;
my $dp = new DSNParser(opts=>$dsn_opts);
my $sb = new Sandbox(basedir => '/tmp', DSNParser => $dp);
my $dbh= $sb->get_dbh_for('slave1');
my $rows = $dbh->selectall_arrayref('SHOW PROCESSLIST', { Slice => {} });
for my $row (@$rows) {
if ($row->{user} eq 'unprivileged') {
$dbh->do("kill $row->{id}");
}
}
}
my $create_table_sql = <<__EOQ;
CREATE TABLE IF NOT EXISTS sakila.heartbeat (
ts varchar(26) NOT NULL,
server_id int unsigned NOT NULL PRIMARY KEY,
file varchar(255) DEFAULT NULL, -- SHOW MASTER STATUS
position bigint unsigned DEFAULT NULL, -- SHOW MASTER STATUS
relay_master_log_file varchar(255) DEFAULT NULL, -- SHOW SLAVE STATUS
exec_master_log_pos bigint unsigned DEFAULT NULL -- SHOW SLAVE STATUS
);
__EOQ
$sb->do_as_root('master', "$create_table_sql");
if ($sandbox_version ge '8.0') {
$sb->do_as_root('slave1', 'CREATE USER "unprivileged"@"localhost" IDENTIFIED WITH mysql_native_password BY "password"');
} else {
$sb->do_as_root('slave1', 'CREATE USER "unprivileged"@"localhost" IDENTIFIED BY "password"');
}
$sb->do_as_root('slave1', 'GRANT SELECT, INSERT, UPDATE, REPLICATION CLIENT ON *.* TO "unprivileged"@"localhost"');
$sb->do_as_root('slave1', "FLUSH TABLES WITH READ LOCK;");
$sb->do_as_root('slave1', "SET GLOBAL read_only = 1;");
my $thread = threads->create('start_thread', $dsn_opts, 4);
$thread->detach();
threads->yield();
my $output = `PTDEBUG=1 $trunk/bin/pt-heartbeat --database=sakila --table heartbeat --read-only-interval 2 --check-read-only --run-time 5 --update $slave1_dsn 2>&1`;
unlike (
$output,
qr/Lost connection to MySQL/,
'PT-1508 --read-only-interval',
);
$master_dbh->do("DROP DATABASE IF EXISTS test");
# #############################################################################
# Done.
# #############################################################################
$sb->do_as_root('master', 'DROP TABLE IF EXISTS sakila.heartbeat');
$sb->do_as_root('slave1', 'DROP USER "unprivileged"@"localhost"');
$sb->wipe_clean($master_dbh);
ok($sb->ok(), "Sandbox servers") or BAIL_OUT(__FILE__ . " broke the sandbox");
done_testing;

View File

@@ -0,0 +1,76 @@
#!/usr/bin/env perl
BEGIN {
die "The PERCONA_TOOLKIT_BRANCH environment variable is not set.\n"
unless $ENV{PERCONA_TOOLKIT_BRANCH} && -d $ENV{PERCONA_TOOLKIT_BRANCH};
unshift @INC, "$ENV{PERCONA_TOOLKIT_BRANCH}/lib";
};
use strict;
use warnings FATAL => 'all';
use threads;
use English qw(-no_match_vars);
use Test::More;
use Data::Dumper;
use PerconaTest;
use Sandbox;
use SqlModes;
use File::Temp qw/ tempdir /;
plan tests => 3;
require "$trunk/bin/pt-online-schema-change";
my $dp = new DSNParser(opts=>$dsn_opts);
my $sb = new Sandbox(basedir => '/tmp', DSNParser => $dp);
my $master_dbh = $sb->get_dbh_for('master');
my $master_dsn = 'h=127.1,P=12345,u=msandbox,p=msandbox';
if ( !$master_dbh ) {
plan skip_all => 'Cannot connect to sandbox master';
}
# The sandbox servers run with lock_wait_timeout=3 and it's not dynamic
# so we need to specify --set-vars innodb_lock_wait_timeout=3 else the
# tool will die.
my @args = (qw(--set-vars innodb_lock_wait_timeout=3));
my $output;
my $exit_status;
my $sample = "t/pt-online-schema-change/samples/";
my $ERROR_UPDATING_FKS = 15; # from pt-online-schema-change line 8453
$sb->load_file('master', "$sample/pt-169.sql");
($output, $exit_status) = full_output(
sub { pt_online_schema_change::main(@args, "$master_dsn,D=test,t=users",
'--execute', '--alter', 'CHANGE COLUMN id id BIGINT UNSIGNED NOT NULL FIRST',
'--set-vars', 'foreign_key_checks=0',
'--alter-foreign-keys-method', 'drop_swap', '--no-check-alter')
},
);
is(
$exit_status,
$ERROR_UPDATING_FKS,
"--alter rename columns with uppercase names -> exit status 0",
);
# Since drop_swap has failed, the clueanup process should be skipped and the new table
# shouldn't be deleted
my $row = $master_dbh->selectrow_hashref("select count(*) AS how_many from test._users_new");
is (
$row->{how_many},
1,
"Correct number of rows",
);
$master_dbh->do("DROP DATABASE IF EXISTS test");
# #############################################################################
# Done.
# #############################################################################
$sb->wipe_clean($master_dbh);
ok($sb->ok(), "Sandbox servers") or BAIL_OUT(__FILE__ . " broke the sandbox");
done_testing;

View File

@@ -0,0 +1,40 @@
DROP DATABASE IF EXISTS `test`;
CREATE DATABASE test;
USE test;
CREATE TABLE `users` (
`id` int(10) unsigned NOT NULL,
`username` varchar(255) NOT NULL,
`full_name` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_520_ci NOT NULL,
`is_verified` tinyint(1) NOT NULL DEFAULT '0',
`is_private` tinyint(1) NOT NULL DEFAULT '0',
`profile_pic_url` varchar(255) DEFAULT NULL,
`follower_count` int(11) NOT NULL DEFAULT '0',
`following_count` int(11) NOT NULL DEFAULT '0',
`media_count` int(11) NOT NULL DEFAULT '0',
`biography` varchar(512) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_520_ci DEFAULT NULL,
`user_active` tinyint(1) NOT NULL DEFAULT '1',
PRIMARY KEY (`id`),
KEY `username` (`username`),
KEY `follower_count` (`follower_count`),
KEY `following_count` (`following_count`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
CREATE TABLE `user_comments` (
`id_user_comments` int(11) NOT NULL AUTO_INCREMENT,
`msg` varchar(255) DEFAULT NULL,
`user_id` int(10) unsigned DEFAULT NULL,
PRIMARY KEY (`id_user_comments`),
KEY `fk1_idx` (`user_id`),
CONSTRAINT `fk1` FOREIGN KEY (`user_id`) REFERENCES `users` (`id`) ON DELETE NO ACTION ON UPDATE NO ACTION
) ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=latin1;
INSERT INTO `test`.`users` (`id`, `username`, `full_name`, `is_verified`, `is_private`, `profile_pic_url`,
`follower_count`, `following_count`, `media_count`, `biography`, `user_active`)
VALUES
(1, "zappb", "zapp brannigan", 1, 1, "https://pbs.twimg.com/profile_images/447660347273408512/NdZEGKvr.jpeg", 0, 0, 0, "", 1);
INSERT INTO `test`.`user_comments` (`id_user_comments`, `msg`, `user_id`)
VALUES
(1, "I am the man with no name. Zapp Brannigan, at your service.", 1);

View File

@@ -23,7 +23,9 @@ if ($ENV{PERCONA_SLOW_BOX}) {
plan skip_all => 'This test needs a fast machine';
} else {
plan tests => 6;
}
#plan skip_all => 'This test is taking too much time even in fast machines';
}
our $delay = 30;
my $tmp_file = File::Temp->new();
@@ -39,10 +41,6 @@ my $slave_dbh = $sb->get_dbh_for('slave1');
my $master_dsn = 'h=127.0.0.1,P=12345,u=msandbox,p=msandbox';
my $slave_dsn = 'h=127.0.0.1,P=12346,u=msandbox,p=msandbox';
if ( !$master_dbh ) {
plan skip_all => 'Cannot connect to sandbox master';
}
sub reset_query_cache {
my @dbhs = @_;
return if ($sandbox_version >= '8.0');
@@ -64,7 +62,7 @@ $sb->load_file('master', "t/pt-online-schema-change/samples/slave_lag.sql");
my $num_rows = 5000;
diag("Loading $num_rows into the table. This might take some time.");
diag(`util/mysql_random_data_load --host=127.0.0.1 --port=12345 --user=msandbox --password=msandbox test pt178 --bulk-size=1 --max-threads=1 $num_rows`);
diag(`util/mysql_random_data_load --host=127.0.0.1 --port=12345 --user=msandbox --password=msandbox test pt178 $num_rows`);
diag("Setting slave delay to $delay seconds");