From 8a8d8d34c2c5a9c4dab72688b82a748a6ce7bd12 Mon Sep 17 00:00:00 2001 From: Paul Tyng Date: Wed, 11 Nov 2020 16:52:40 -0500 Subject: [PATCH] sql_query data source --- .vscode/launch.json | 36 ++ README.md | 67 +--- docs/data-sources/query.md | 41 +++ docs/index.md | 47 +++ .../data-sources/sql_query/data-source.tf | 13 + examples/provider/provider.tf | 24 ++ examples/provider/tf.tf | 7 + go.mod | 34 +- go.sum | 314 +++++++++++++---- internal/provider/data_query.go | 123 +++++++ internal/provider/data_query_test.go | 226 +++++++++++++ internal/provider/data_source_scaffolding.go | 25 -- .../provider/data_source_scaffolding_test.go | 30 -- internal/provider/db.go | 178 ++++++++++ internal/provider/provider.go | 41 --- internal/provider/provider_test.go | 28 -- internal/provider/resource_scaffolding.go | 49 --- .../provider/resource_scaffolding_test.go | 30 -- internal/provider/server.go | 315 ++++++++++++++++++ internal/provider/server_test.go | 151 +++++++++ internal/provider/sqlserver.go | 61 ++++ internal/provider/time.go | 31 ++ internal/provider/util.go | 54 +++ main.go | 102 +++++- tools/tools.go | 7 + .../d/scaffolding_data_source.html.markdown | 23 -- website/docs/index.html.markdown | 25 -- .../docs/r/scaffolding_resource.html.markdown | 26 -- 28 files changed, 1706 insertions(+), 402 deletions(-) create mode 100644 .vscode/launch.json create mode 100644 docs/data-sources/query.md create mode 100644 docs/index.md create mode 100644 examples/data-sources/sql_query/data-source.tf create mode 100644 examples/provider/provider.tf create mode 100644 examples/provider/tf.tf create mode 100644 internal/provider/data_query.go create mode 100644 internal/provider/data_query_test.go delete mode 100644 internal/provider/data_source_scaffolding.go delete mode 100644 internal/provider/data_source_scaffolding_test.go create mode 100644 internal/provider/db.go delete mode 100644 internal/provider/provider.go delete mode 100644 internal/provider/provider_test.go delete mode 100644 internal/provider/resource_scaffolding.go delete mode 100644 internal/provider/resource_scaffolding_test.go create mode 100644 internal/provider/server.go create mode 100644 internal/provider/server_test.go create mode 100644 internal/provider/sqlserver.go create mode 100644 internal/provider/time.go create mode 100644 internal/provider/util.go create mode 100644 tools/tools.go delete mode 100644 website/docs/d/scaffolding_data_source.html.markdown delete mode 100644 website/docs/index.html.markdown delete mode 100644 website/docs/r/scaffolding_resource.html.markdown diff --git a/.vscode/launch.json b/.vscode/launch.json new file mode 100644 index 0000000..a8c1116 --- /dev/null +++ b/.vscode/launch.json @@ -0,0 +1,36 @@ +{ + // Use IntelliSense to learn about possible attributes. + // Hover to view descriptions of existing attributes. + // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 + "version": "0.2.0", + "configurations": [ + { + "name": "Acceptance Tests", + "type": "go", + "request": "launch", + "mode": "test", + // this assumes your workspace is the root of the repo + "program": "${fileDirname}", + "env": { + "TF_ACC": "1", + }, + "args": [], + }, + // You could pair this configuration with an exec configuration that runs Terraform as + // a compound launch configuration: + // https://code.visualstudio.com/docs/editor/debugging#_compound-launch-configurations + { + "name": "Debug - Attach External CLI", + "type": "go", + "request": "launch", + "mode": "debug", + // this assumes your workspace is the root of the repo + "program": "${workspaceFolder}", + "env": {}, + "args": [ + // pass the debug flag for reattaching + "-debug", + ], + } + ] +} \ No newline at end of file diff --git a/README.md b/README.md index 8dfcbe4..a3417b2 100644 --- a/README.md +++ b/README.md @@ -1,65 +1,10 @@ -Terraform Provider Scaffolding -================== +# Terraform SQL Provider -This repository is a *template* for a [Terraform](https://www.terraform.io) provider. It is intended as a starting point for creating Terraform providers, containing: +This provider is an experiment using the new [terraform-plugin-go](https://github.com/hashicorp/terraform-plugin-go) SDK in order to utilize dynamic typing for its attributes. - - A resource, and a data source (`internal/provider/`), - - Documentation (`website/`), - - Miscellanious meta files. - -These files contain boilerplate code that you will need to edit to create your own Terraform provider. A full guide to creating Terraform providers can be found at [Writing Custom Providers](https://www.terraform.io/docs/extend/writing-custom-providers.html). +Currently it only has a single data source (`sql_query`) which lets you execute a query against Microsoft SQL Server, PostreSQL, MySQL or other data base engines that are protocol compatible (Maria, CockroachDB, etc.). -Please see the [GitHub template repository documentation](https://help.github.com/en/github/creating-cloning-and-archiving-repositories/creating-a-repository-from-a-template) for how to create a new repository from this template on GitHub. +## TODO - -Requirements ------------- - -- [Terraform](https://www.terraform.io/downloads.html) >= 0.12.x -- [Go](https://golang.org/doc/install) >= 1.12 - -Building The Provider ---------------------- - -1. Clone the repository -1. Enter the repository directory -1. Build the provider using the Go `install` command: -```sh -$ go install -``` - -Adding Dependencies ---------------------- - -This provider uses [Go modules](https://github.com/golang/go/wiki/Modules). -Please see the Go documentation for the most up to date information about using Go modules. - -To add a new dependency `github.com/author/dependency` to your Terraform provider: - -``` -go get github.com/author/dependency -go mod tidy -``` - -Then commit the changes to `go.mod` and `go.sum`. - - -Using the provider ----------------------- - -Fill this in for each provider - -Developing the Provider ---------------------------- - -If you wish to work on the provider, you'll first need [Go](http://www.golang.org) installed on your machine (see [Requirements](#requirements) above). - -To compile the provider, run `go install`. This will build the provider and put the provider binary in the `$GOPATH/bin` directory. - -In order to run the full suite of Acceptance tests, run `make testacc`. - -*Note:* Acceptance tests create real resources, and often cost money to run. - -```sh -$ make testacc -``` +* Better decimal handling (maybe not string? use big.float?) +* Convert JSON (or other structured db types) to native HCL types, not strings \ No newline at end of file diff --git a/docs/data-sources/query.md b/docs/data-sources/query.md new file mode 100644 index 0000000..78c73a4 --- /dev/null +++ b/docs/data-sources/query.md @@ -0,0 +1,41 @@ +--- +page_title: "sql_query Data Source - terraform-provider-sql" +subcategory: "" +description: |- + The sql_query datasource allows you to execute a SQL query against the database of your choice. +--- + +# Data Source `sql_query` + +The `sql_query` datasource allows you to execute a SQL query against the database of your choice. + +## Example Usage + +```terraform +data "sql_query" "test" { + query = "select 1 as number, 'foo' as string" +} + +locals { + # The number column in this case is a Terraform "Number" type + # so you can use it as such: + math = 1 + data.sql_query.test.result[0].number +} + +output "math" { + value = local.math +} +``` + +## Schema + +### Required + +- **query** (String, Required) The query to execute. The types in this query will be reflected in the typing of the `result` attribute. + +### Read-only + +- **id** (String, Read-only, Deprecated) This attribute is only present for some compatibility issues and should not be used. It will be removed in a future version. +- **result** (List of Dynamic, Read-only) The result of the query. This will be a list of objects. Each object will have attributes with names that match column names and types that match column types. The exact translation of types is dependent upon the database driver. + + diff --git a/docs/index.md b/docs/index.md new file mode 100644 index 0000000..d33b1ae --- /dev/null +++ b/docs/index.md @@ -0,0 +1,47 @@ +--- +page_title: "sql Provider" +subcategory: "" +description: |- + +--- + +# sql Provider + + + +## Example Usage + +```terraform +# connect to Microsoft SQL Server +provider "sql" { + alias = "mssql" + url = "sqlserver://sa:password@localhost:1433" +} + +# connect to PostgreSQL +provider "sql" { + alias = "postgres" + url = "postgres://postgres:password@localhost:5432/mydatabase?sslmode=disable" +} + +# connect to CockroachDB +provider "sql" { + alias = "cockroach" + # use the postgres driver for CockroachDB + url = "postgres://root@localhost:26257/events?sslmode=disable" +} + +# connect to a MySQL server +provider "sql" { + alias = "mysql" + url = "mysql://root:password@tcp(localhost:3306)/mysql" +} +``` + +## Schema + +### Optional + +- **max_idle_conns** (Number, Optional) Sets the maximum number of connections in the idle connection pool. Default is `2`. See Go's documentation on [DB.SetMaxIdleConns](https://golang.org/pkg/database/sql/#DB.SetMaxIdleConns). +- **max_open_conns** (Number, Optional) Sets the maximum number of open connections to the database. Default is `0` (unlimited). See Go's documentation on [DB.SetMaxOpenConns](https://golang.org/pkg/database/sql/#DB.SetMaxOpenConns). +- **url** (String, Optional) Database connection strings are specified via URLs. The URL format is driver dependent but generally has the form: `dbdriver://username:password@host:port/dbname?param1=true¶m2=false`. You can optionally set the `SQL_URL` environment variable instead. diff --git a/examples/data-sources/sql_query/data-source.tf b/examples/data-sources/sql_query/data-source.tf new file mode 100644 index 0000000..4d4987c --- /dev/null +++ b/examples/data-sources/sql_query/data-source.tf @@ -0,0 +1,13 @@ +data "sql_query" "test" { + query = "select 1 as number, 'foo' as string" +} + +locals { + # The number column in this case is a Terraform "Number" type + # so you can use it as such: + math = 1 + data.sql_query.test.result[0].number +} + +output "math" { + value = local.math +} \ No newline at end of file diff --git a/examples/provider/provider.tf b/examples/provider/provider.tf new file mode 100644 index 0000000..43ddfd5 --- /dev/null +++ b/examples/provider/provider.tf @@ -0,0 +1,24 @@ +# connect to Microsoft SQL Server +provider "sql" { + alias = "mssql" + url = "sqlserver://sa:password@localhost:1433" +} + +# connect to PostgreSQL +provider "sql" { + alias = "postgres" + url = "postgres://postgres:password@localhost:5432/mydatabase?sslmode=disable" +} + +# connect to CockroachDB +provider "sql" { + alias = "cockroach" + # use the postgres driver for CockroachDB + url = "postgres://root@localhost:26257/events?sslmode=disable" +} + +# connect to a MySQL server +provider "sql" { + alias = "mysql" + url = "mysql://root:password@tcp(localhost:3306)/mysql" +} \ No newline at end of file diff --git a/examples/provider/tf.tf b/examples/provider/tf.tf new file mode 100644 index 0000000..b7fb080 --- /dev/null +++ b/examples/provider/tf.tf @@ -0,0 +1,7 @@ +terraform { + required_providers { + sql = { + source = "paultyng/sql" + } + } +} \ No newline at end of file diff --git a/go.mod b/go.mod index fe1820f..59ab417 100644 --- a/go.mod +++ b/go.mod @@ -1,5 +1,33 @@ -module github.com/hashicorp/terraform-provider-scaffolding +module github.com/paultyng/terraform-provider-sql -go 1.12 +go 1.15 -require github.com/hashicorp/terraform-plugin-sdk/v2 v2.0.1 +require ( + github.com/Azure/go-ansiterm v0.0.0-20170929234023-d6e3b3328b78 // indirect + github.com/Microsoft/go-winio v0.4.15 // indirect + github.com/Nvveen/Gotty v0.0.0-20120604004816-cd527374f1e5 // indirect + github.com/cenkalti/backoff v2.2.1+incompatible // indirect + github.com/containerd/continuity v0.0.0-20200928162600-f2cc35102c2a // indirect + github.com/denisenkom/go-mssqldb v0.9.0 + github.com/docker/go-connections v0.4.0 // indirect + github.com/docker/go-units v0.4.0 // indirect + github.com/go-sql-driver/mysql v1.5.0 + github.com/gotestyourself/gotestyourself v2.2.0+incompatible // indirect + github.com/hashicorp/go-plugin v1.3.0 + github.com/hashicorp/terraform-plugin-docs v0.2.0 + github.com/hashicorp/terraform-plugin-go v0.1.1-0.20201117024036-b9d161518a6d + github.com/hashicorp/terraform-plugin-sdk/v2 v2.2.0 + github.com/jackc/pgx/v4 v4.9.2 + github.com/opencontainers/image-spec v1.0.1 // indirect + github.com/opencontainers/runc v0.1.1 // indirect + github.com/ory/dockertest v3.3.5+incompatible + golang.org/x/sync v0.0.0-20200625203802-6e8e738ad208 + golang.org/x/sys v0.0.0-20200826173525-f9321e4c35a6 // indirect + gopkg.in/yaml.v2 v2.2.8 // indirect + gotest.tools v2.2.0+incompatible // indirect +) + +// see https://github.com/ory/dockertest/issues/204 +replace golang.org/x/sys => golang.org/x/sys v0.0.0-20190830141801-acfa387b8d69 + +// replace github.com/hashicorp/terraform-plugin-go => ../../hashicorp/terraform-plugin-go diff --git a/go.sum b/go.sum index a212a9c..76dddcd 100644 --- a/go.sum +++ b/go.sum @@ -1,9 +1,9 @@ +bazil.org/fuse v0.0.0-20160811212531-371fbbdaa898/go.mod h1:Xbm+BRKSBEpa4q4hTSxohYNQpsxXPbPry4JJWOB3LB8= 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= cloud.google.com/go v0.38.0/go.mod h1:990N+gfupTy94rShfmMCWGDn0LpTmnzTp2qbd1dvSRU= cloud.google.com/go v0.44.1/go.mod h1:iSa0KzasP4Uvy3f1mN/7PiObzGgflwredwwASm/v6AU= cloud.google.com/go v0.44.2/go.mod h1:60680Gw3Yr4ikxnPRS/oxxkBccT6SA1yMk63TGekxKY= -cloud.google.com/go v0.45.1 h1:lRi0CHyU+ytlvylOlFKKq0af6JncuyoRh1J+QJBqQx0= cloud.google.com/go v0.45.1/go.mod h1:RpBamKRgapWJb87xiFSdk4g1CME7QZg3uwTez+TSTjc= cloud.google.com/go v0.46.3/go.mod h1:a6bKKbmY7er1mI7TEI4lsAkts/mkhTSZK8w33B4RAg0= cloud.google.com/go v0.50.0/go.mod h1:r9sluTvynVuxRIOHXQEHMFffphuXHOMZMycpNR5e6To= @@ -33,26 +33,43 @@ cloud.google.com/go/storage v1.8.0/go.mod h1:Wv1Oy7z6Yz3DshWRJFhqM/UCfaWIRTdp0RX cloud.google.com/go/storage v1.10.0 h1:STgFzyU5/8miMl0//zKh2aQeTyeaUH3WN9bSUiJ09bA= cloud.google.com/go/storage v1.10.0/go.mod h1:FLPqc6j+Ki4BU591ie1oL6qBQGu2Bl/tZ9ullr3+Kg0= dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU= +github.com/Azure/go-ansiterm v0.0.0-20170929234023-d6e3b3328b78 h1:w+iIsaOQNcT7OZ575w+acHgRric5iCyQh+xv+KJ4HB8= +github.com/Azure/go-ansiterm v0.0.0-20170929234023-d6e3b3328b78/go.mod h1:LmzpDX56iTiv29bbRTIsUNlaFfuhWRQBWjQdVyAevI8= github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo= +github.com/Microsoft/go-winio v0.4.15 h1:qkLXKzb1QoVatRyd/YlXZ/Kg0m5K3SPuoD82jjSOaBc= +github.com/Microsoft/go-winio v0.4.15/go.mod h1:tTuCMEN+UleMWgg9dVx4Hu52b1bJo+59jBh3ajtinzw= +github.com/Nvveen/Gotty v0.0.0-20120604004816-cd527374f1e5 h1:TngWCqHvy9oXAN6lEVMRuU21PR1EtLVZJmdB18Gu3Rw= +github.com/Nvveen/Gotty v0.0.0-20120604004816-cd527374f1e5/go.mod h1:lmUJ/7eu/Q8D7ML55dXQrVaamCz2vxCfdQBasLZfHKk= github.com/agext/levenshtein v1.2.1/go.mod h1:JEDfjyjHDjOF/1e4FlBE/PkbqA9OfWu2ki2W0IB5558= github.com/agext/levenshtein v1.2.2 h1:0S/Yg6LYmFJ5stwQeRp6EeOcCbj7xiqQSdNelsXvaqE= github.com/agext/levenshtein v1.2.2/go.mod h1:JEDfjyjHDjOF/1e4FlBE/PkbqA9OfWu2ki2W0IB5558= github.com/agl/ed25519 v0.0.0-20170116200512-5312a6153412/go.mod h1:WPjqKcmVOxf0XSf3YxCJs6N6AOSrOx3obionmG7T0y0= -github.com/apparentlymart/go-cidr v1.0.1 h1:NmIwLZ/KdsjIUlhf+/Np40atNXm/+lZ5txfTJ/SpF+U= +github.com/alcortesm/tgz v0.0.0-20161220082320-9c5fe88206d7 h1:uSoVVbwJiQipAclBbw+8quDsfcvFjOpI5iCf4p/cqCs= +github.com/alcortesm/tgz v0.0.0-20161220082320-9c5fe88206d7/go.mod h1:6zEj6s6u/ghQa61ZWa/C2Aw3RkjiTBOix7dkqa1VLIs= +github.com/anmitsu/go-shlex v0.0.0-20161002113705-648efa622239 h1:kFOfPq6dUM1hTo4JG6LR5AXSUEsOjtdm0kw0FtQtMJA= +github.com/anmitsu/go-shlex v0.0.0-20161002113705-648efa622239/go.mod h1:2FmKhYUyUczH0OGQWaF5ceTx0UBShxjsH6f8oGKYe2c= github.com/apparentlymart/go-cidr v1.0.1/go.mod h1:EBcsNrHc3zQeuaeCeCtQruQm+n9/YjEn/vI25Lg7Gwc= -github.com/apparentlymart/go-dump v0.0.0-20180507223929-23540a00eaa3 h1:ZSTrOEhiM5J5RFxEaFvMZVEAM1KvT1YzbEOwB2EAGjA= github.com/apparentlymart/go-dump v0.0.0-20180507223929-23540a00eaa3/go.mod h1:oL81AME2rN47vu18xqj1S1jPIPuN7afo62yKTNn3XMM= github.com/apparentlymart/go-dump v0.0.0-20190214190832-042adf3cf4a0 h1:MzVXffFUye+ZcSR6opIgz9Co7WcDx6ZcY+RjfFHoA0I= github.com/apparentlymart/go-dump v0.0.0-20190214190832-042adf3cf4a0/go.mod h1:oL81AME2rN47vu18xqj1S1jPIPuN7afo62yKTNn3XMM= github.com/apparentlymart/go-textseg v1.0.0 h1:rRmlIsPEEhUTIKQb7T++Nz/A5Q6C9IuX2wFoYVvnCs0= github.com/apparentlymart/go-textseg v1.0.0/go.mod h1:z96Txxhf3xSFMPmb5X/1W05FF/Nj9VFpLOpjS5yuumk= +github.com/apparentlymart/go-textseg/v12 v12.0.0 h1:bNEQyAGak9tojivJNkoqWErVCQbjdL7GzRt3F8NvfJ0= github.com/apparentlymart/go-textseg/v12 v12.0.0/go.mod h1:S/4uRK2UtaQttw1GenVJEynmyUenKwP++x/+DdGV/Ec= +github.com/armon/go-radix v0.0.0-20180808171621-7fddfc383310 h1:BUAU3CGlLvorLI26FmByPp2eC2qla6E1Tw+scpcg/to= +github.com/armon/go-radix v0.0.0-20180808171621-7fddfc383310/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8= +github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5 h1:0CwZNZbxp69SHPdPJAN/hZIm0C4OItdklCFmMRWYpio= +github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5/go.mod h1:wHh0iHkYZB8zMSxRWpUBQtwG5a7fFgvEO+odwuTv2gs= github.com/aws/aws-sdk-go v1.15.78/go.mod h1:E3/ieXAlvM0XWO57iftYVDLLvQ824smPP3ATZkfNZeM= github.com/aws/aws-sdk-go v1.25.3 h1:uM16hIw9BotjZKMZlX05SN2EFtaWfi/NonPKIARiBLQ= github.com/aws/aws-sdk-go v1.25.3/go.mod h1:KmX6BPdI08NWTb3/sm4ZGu5ShLoqVDhKgpiN924inxo= github.com/bgentry/go-netrc v0.0.0-20140422174119-9fd32a8b3d3d h1:xDfNPAt8lFiC1UJrqV3uuy861HCTo708pDMbjHHdCas= github.com/bgentry/go-netrc v0.0.0-20140422174119-9fd32a8b3d3d/go.mod h1:6QX/PXZ00z/TKoufEY6K/a0k6AhaJrQKdFe6OfVXsa4= +github.com/bgentry/speakeasy v0.1.0 h1:ByYyxL9InA1OWqxJqqp2A5pYHUrCiAL6K3J+LKSsQkY= +github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs= +github.com/cenkalti/backoff v2.2.1+incompatible h1:tNowT99t7UNflLxfYYSlKYsBpXdEet03Pg2g16Swow4= +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/cheggaaa/pb v1.0.27/go.mod h1:pQciLPpbU0oxA0h+VJYYLxO+XeDQb5pZijXscXHm81s= github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI= @@ -60,20 +77,57 @@ github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5P github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU= github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc= +github.com/cockroachdb/apd v1.1.0 h1:3LFP3629v+1aKXU5Q37mxmRxX/pIu1nijXydLShEq5I= +github.com/cockroachdb/apd v1.1.0/go.mod h1:8Sl8LxpKi29FqWXR16WEFZRNSz3SoPzUzeMeY4+DwBQ= +github.com/containerd/continuity v0.0.0-20200928162600-f2cc35102c2a h1:jEIoR0aA5GogXZ8pP3DUzE+zrhaF6/1rYZy+7KkYEWM= +github.com/containerd/continuity v0.0.0-20200928162600-f2cc35102c2a/go.mod h1:W0qIOTD7mp2He++YVq+kgfXezRYqzP1uDuMVH1bITDY= +github.com/coreos/go-systemd v0.0.0-20190321100706-95778dfbb74e/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4= +github.com/coreos/go-systemd v0.0.0-20190719114852-fd7a80b32e1f/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4= +github.com/creack/pty v1.1.7/go.mod h1:lj5s0c3V2DBrqTV7llrYr5NG6My20zk30Fl46Y7DoTY= +github.com/creack/pty v1.1.9 h1:uDmaGzcdjhF4i/plgjmEsriH11Y0o7RKapEf/LDaM3w= +github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= 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/denisenkom/go-mssqldb v0.9.0 h1:RSohk2RsiZqLZ0zCjtfn3S4Gp4exhpBWHyQ7D0yGjAk= +github.com/denisenkom/go-mssqldb v0.9.0/go.mod h1:xbL0rPBG9cCiLr28tMa8zpbdarY27NDyej4t/EjAShU= +github.com/docker/go-connections v0.4.0 h1:El9xVISelRB7BuFusrZozjnkIM5YnzCViNKohAFqRJQ= +github.com/docker/go-connections v0.4.0/go.mod h1:Gbd7IOopHjR8Iph03tsViu4nIes5XhDvyHbTtUxmeec= +github.com/docker/go-units v0.4.0 h1:3uh0PgVws3nIA0Q+MwDC8yjEPf9zjRfZZWXZYDct3Tw= +github.com/docker/go-units v0.4.0/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk= +github.com/dustin/go-humanize v1.0.0/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk= +github.com/emirpasic/gods v1.12.0 h1:QAUIPSaCu4G+POclxeqb3F+WPpdKqFGlw36+yOzGlrg= +github.com/emirpasic/gods v1.12.0/go.mod h1:YfzfFFoVP/catgzJb4IKIqXjX78Ha8FMSDh3ymbK86o= github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98= github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= github.com/fatih/color v1.7.0 h1:DkWD4oS2D8LGGgTQ6IvwJJXSL5Vp2ffcQg58nFV38Ys= github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4= +github.com/flynn/go-shlex v0.0.0-20150515145356-3f9db97f8568 h1:BHsljHzVlRcyQhjrss6TZTdY2VfCqZPbv5k3iBFa2ZQ= +github.com/flynn/go-shlex v0.0.0-20150515145356-3f9db97f8568/go.mod h1:xEzjJPgXI435gkrCt3MPfRiAkVrwSbHsst4LCFVfpJc= +github.com/gliderlabs/ssh v0.2.2 h1:6zsha5zo/TWhRhwqCD3+EarCAgZ2yN28ipRnGPnwkI0= +github.com/gliderlabs/ssh v0.2.2/go.mod h1:U7qILu1NlMHj9FlMhZLlkCdDnU1DBEAqr0aevW3Awn0= +github.com/go-git/gcfg v1.5.0 h1:Q5ViNfGF8zFgyJWPqYwA7qGFoMTEiBmdlkcfRmpIMa4= +github.com/go-git/gcfg v1.5.0/go.mod h1:5m20vg6GwYabIxaOonVkTdrILxQMpEShl1xiMF4ua+E= +github.com/go-git/go-billy/v5 v5.0.0 h1:7NQHvd9FVid8VL4qVUMm8XifBK+2xCoZ2lSk0agRrHM= +github.com/go-git/go-billy/v5 v5.0.0/go.mod h1:pmpqyWchKfYfrkb/UVH4otLvyi/5gJlGI4Hb3ZqZ3W0= +github.com/go-git/go-git-fixtures/v4 v4.0.1 h1:q+IFMfLx200Q3scvt2hN79JsEzy4AmBTp/pqnefH+Bc= +github.com/go-git/go-git-fixtures/v4 v4.0.1/go.mod h1:m+ICp2rF3jDhFgEZ/8yziagdT1C+ZpZcrJjappBCDSw= +github.com/go-git/go-git/v5 v5.1.0 h1:HxJn9g/E7eYvKW3Fm7Jt4ee8LXfPOm/H1cdDu8vEssk= +github.com/go-git/go-git/v5 v5.1.0/go.mod h1:ZKfuPUoY1ZqIG4QG9BDBh3G4gLM5zvPuSJAozQrZuyM= github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU= github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= +github.com/go-sql-driver/mysql v1.5.0 h1:ozyZYNQW3x3HtqT1jira07DN2PArx2v7/mN66gGcHOs= +github.com/go-sql-driver/mysql v1.5.0/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LBy8hT2VhHyBg= +github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= github.com/go-test/deep v1.0.3 h1:ZrJSEWsXzPOxaZnFteGEfooLba+ju3FYIbOrS+rQd68= github.com/go-test/deep v1.0.3/go.mod h1:wGDj63lr65AM2AQyKZd/NYHGb0R+1RLqB8NKt3aSFNA= +github.com/gofrs/uuid v3.2.0+incompatible h1:y12jRkkFxsd7GpqdSZ+/KCs/fJbqpEXSGd4+jfEaewE= +github.com/gofrs/uuid v3.2.0+incompatible/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRxnplIgP/c0N/04lM= +github.com/golang-sql/civil v0.0.0-20190719163853-cb61b32ac6fe h1:lXe2qZdvpiX5WZkZR4hgp4KJVfY3nMkvmwbVkpv1rVY= +github.com/golang-sql/civil v0.0.0-20190719163853-cb61b32ac6fe/go.mod h1:8vg3r2VgvsThLBIFL93Qb5yWzgyZWhEmBwUJWevAkK0= github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b h1:VKtxabqXZkF25pY9ekfRL6a582T4P37/31XEstQ5p58= github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= @@ -82,7 +136,6 @@ github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e h1:1r7pUrabqp18h github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= github.com/golang/mock v1.2.0/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= -github.com/golang/mock v1.3.1 h1:qGJ6qTW+x6xX/my+8YUVl4WNpX9B7+/l2tRsHGZ7f2s= github.com/golang/mock v1.3.1/go.mod h1:sBzyDLLjw3U8JLTeZvSv8jJB+tU5PVekmnlKIyFUx0Y= github.com/golang/mock v1.4.0/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw= github.com/golang/mock v1.4.1/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw= @@ -115,8 +168,11 @@ github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/ github.com/google/go-cmp v0.4.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.0 h1:/QaMHBdZ26BB3SSst0Iwl10Epc+xhTquomWX0oZEB6w= github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/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/martian v2.1.0+incompatible h1:/CP5g8u/VJHijgedC/Legn3BAbAaWPgecwXBIDzw5no= github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs= +github.com/google/martian/v3 v3.0.0 h1:pMen7vLs8nvgEYhywH3KDWJIJTeEr2ULsVWHWYHQyBs= github.com/google/martian/v3 v3.0.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0= github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= github.com/google/pprof v0.0.0-20190515194954-54271f7e092f/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= @@ -129,6 +185,8 @@ github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm4 github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg= github.com/googleapis/gax-go/v2 v2.0.5 h1:sjZBwGj9Jlw33ImPtvFviGYvseOtDM7hkSKB7+Tv3SM= github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk= +github.com/gotestyourself/gotestyourself v2.2.0+incompatible h1:AQwinXlbQR2HvPjQZOmDhRqsv5mZf+Jb1RnSLxcqZcI= +github.com/gotestyourself/gotestyourself v2.2.0+incompatible/go.mod h1:zZKM6oeNM8k+FRljX1mnzVYeS8wiGgQyvST1/GafPbY= github.com/hashicorp/errwrap v1.0.0 h1:hLrqtEDnRye3+sgx6z4qVLNuviH3MR5aQ0ykNJa/UYA= github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= github.com/hashicorp/go-checkpoint v0.5.0 h1:MFYpPZCnQqQTE18jFwSII6eUQrD/oxMFp3mlgcqk5mU= @@ -138,10 +196,9 @@ github.com/hashicorp/go-cleanhttp v0.5.1 h1:dH3aiDG9Jvb5r5+bYHsikaOUIpcM0xvgMXVo github.com/hashicorp/go-cleanhttp v0.5.1/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80= github.com/hashicorp/go-cty v1.4.1-0.20200414143053-d3edf31b6320 h1:1/D3zfFHttUKaCaGKZ/dR2roBXv0vKbSCnssIldfQdI= github.com/hashicorp/go-cty v1.4.1-0.20200414143053-d3edf31b6320/go.mod h1:EiZBMaudVLy8fmjf9Npq1dq9RalhveqZG5w/yz3mHWs= -github.com/hashicorp/go-getter v1.4.0 h1:ENHNi8494porjD0ZhIrjlAHnveSFhY7hvOJrV/fsKkw= github.com/hashicorp/go-getter v1.4.0/go.mod h1:7qxyCd8rBfcShwsvxgIguu4KbS3l8bUCwg2Umn7RjeY= -github.com/hashicorp/go-getter v1.4.2-0.20200106182914-9813cbd4eb02 h1:l1KB3bHVdvegcIf5upQ5mjcHjs2qsWnKh4Yr9xgIuu8= -github.com/hashicorp/go-getter v1.4.2-0.20200106182914-9813cbd4eb02/go.mod h1:7qxyCd8rBfcShwsvxgIguu4KbS3l8bUCwg2Umn7RjeY= +github.com/hashicorp/go-getter v1.5.0 h1:ciWJaeZWSMbc5OiLMpKp40MKFPqO44i0h3uyfXPBkkk= +github.com/hashicorp/go-getter v1.5.0/go.mod h1:a7z7NPPfNQpJWcn4rSWFtdrSldqLdLPEF3d8nFMsSLM= github.com/hashicorp/go-hclog v0.0.0-20180709165350-ff2cf002a8dd/go.mod h1:9bjs9uLqI8l75knNv3lV1kA55veR+WUPSiKIWcQHudI= github.com/hashicorp/go-hclog v0.9.2 h1:CG6TE5H9/JXsFWJCfoIVpKFIkFe6ysEuHirp4DxCsHI= github.com/hashicorp/go-hclog v0.9.2/go.mod h1:5CU+agLiy3J7N7QjHK5d05KxGsuXiQLrjA0H7acj2lQ= @@ -155,56 +212,144 @@ github.com/hashicorp/go-uuid v1.0.0/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/b github.com/hashicorp/go-uuid v1.0.1 h1:fv1ep09latC32wFoVwnqcnKJGnMSdBanPczbHAYm1BE= github.com/hashicorp/go-uuid v1.0.1/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= github.com/hashicorp/go-version v1.1.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA= -github.com/hashicorp/go-version v1.2.0 h1:3vNe/fWF5CBgRIguda1meWhsZHy3m8gCJ5wx+dIzX/E= -github.com/hashicorp/go-version v1.2.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA= +github.com/hashicorp/go-version v1.2.1 h1:zEfKbn2+PDgroKdiOzqiE8rsmLqU2uwi5PB5pBJ3TkI= +github.com/hashicorp/go-version v1.2.1/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA= github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= -github.com/hashicorp/golang-lru v0.5.1 h1:0hERBMJE1eitiLkihrMvRVBYAkpHzc/J3QdDN+dAcgU= github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= github.com/hashicorp/hcl/v2 v2.3.0 h1:iRly8YaMwTBAKhn1Ybk7VSdzbnopghktCD031P8ggUE= github.com/hashicorp/hcl/v2 v2.3.0/go.mod h1:d+FwDBbOLvpAM3Z6J7gPj/VoAGkNe/gm352ZhjJ/Zv8= github.com/hashicorp/logutils v1.0.0 h1:dLEQVugN8vlakKOUE3ihGLTZJRB4j+M2cdTm/ORI65Y= github.com/hashicorp/logutils v1.0.0/go.mod h1:QIAnNjmIWmVIIkWDTG1z5v++HQmx9WQRO+LraFDTW64= -github.com/hashicorp/terraform-exec v0.3.0 h1:5WLBsnv9BoEUGlHJZETROZZxw+qO3/TFQEh6JMP2uaY= -github.com/hashicorp/terraform-exec v0.3.0/go.mod h1:yKWvMPtkTaHpeAmllw+1qdHZ7E5u+pAZ+x8e2jQF6gM= +github.com/hashicorp/terraform-exec v0.9.0/go.mod h1:tOT8j1J8rP05bZBGWXfMyU3HkLi1LWyqL3Bzsc3CJjo= +github.com/hashicorp/terraform-exec v0.10.0 h1:3nh/1e3u9gYRUQGOKWp/8wPR7ABlL2F14sZMZBrp+dM= +github.com/hashicorp/terraform-exec v0.10.0/go.mod h1:tOT8j1J8rP05bZBGWXfMyU3HkLi1LWyqL3Bzsc3CJjo= github.com/hashicorp/terraform-json v0.5.0 h1:7TV3/F3y7QVSuN4r9BEXqnWqrAyeOtON8f0wvREtyzs= github.com/hashicorp/terraform-json v0.5.0/go.mod h1:eAbqb4w0pSlRmdvl8fOyHAi/+8jnkVYN28gJkSJrLhU= -github.com/hashicorp/terraform-plugin-sdk/v2 v2.0.1 h1:qG6EdnW2UrftQI4mBdIsWP4YWqYJXynZtl0shQYuU78= -github.com/hashicorp/terraform-plugin-sdk/v2 v2.0.1/go.mod h1:BRz6UtYmksQJU0eMfahQR8fcJf8tIe77gn7YVm6rGD4= -github.com/hashicorp/terraform-plugin-test/v2 v2.0.0 h1:fYGV3nZvs8KFGKuY2NPAJDMNfVSDHo+U2FGFl3bPv1s= -github.com/hashicorp/terraform-plugin-test/v2 v2.0.0/go.mod h1:C6VALgUlvaif+PnHyRGKWPTdQkMJK4NQ20VJolxZLI0= +github.com/hashicorp/terraform-plugin-docs v0.2.0 h1:A1Uk+WIvU0B4VP4pBbTBP9bZJ9w9F8yoVGj7MC1vYc0= +github.com/hashicorp/terraform-plugin-docs v0.2.0/go.mod h1:4jopztPjeyZAr51wPzX4b8Ld8bFQKQ9dbF40JbCQIts= +github.com/hashicorp/terraform-plugin-go v0.1.0/go.mod h1:10V6F3taeDWVAoLlkmArKttR3IULlRWFAGtQIQTIDr4= +github.com/hashicorp/terraform-plugin-go v0.1.1-0.20201117024036-b9d161518a6d h1:iiRI4FfqpX+hFEUvf+t7wMJmxKsmm395vjaKLOLD4ds= +github.com/hashicorp/terraform-plugin-go v0.1.1-0.20201117024036-b9d161518a6d/go.mod h1:10V6F3taeDWVAoLlkmArKttR3IULlRWFAGtQIQTIDr4= +github.com/hashicorp/terraform-plugin-sdk/v2 v2.2.0 h1:2m4uKA97R8ijHGLwhHdpSJyI8Op1FpS/ozpoF21jK7s= +github.com/hashicorp/terraform-plugin-sdk/v2 v2.2.0/go.mod h1:+12dJQebYjuU/yiq94iZUPuC66abfRBrXdpVJia3ojk= github.com/hashicorp/yamux v0.0.0-20180604194846-3520598351bb/go.mod h1:+NfK9FKeTrX5uv1uIXGdwYDTeHna2qgaIlx54MXqjAM= github.com/hashicorp/yamux v0.0.0-20181012175058-2f1d1f20f75d h1:kJCB4vdITiW1eC1vq2e6IsrXKrZit1bv/TDYFGMp4BQ= github.com/hashicorp/yamux v0.0.0-20181012175058-2f1d1f20f75d/go.mod h1:+NfK9FKeTrX5uv1uIXGdwYDTeHna2qgaIlx54MXqjAM= github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= +github.com/imdario/mergo v0.3.9 h1:UauaLniWCFHWd+Jp9oCEkTBj8VO/9DKg3PV3VCNMDIg= +github.com/imdario/mergo v0.3.9/go.mod h1:2EnlNZ0deacrJVfApfmtdGgDfMuh/nq6Ok1EcJh5FfA= +github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8= +github.com/jackc/chunkreader v1.0.0 h1:4s39bBR8ByfqH+DKm8rQA3E1LHZWB9XWcrz8fqaZbe0= +github.com/jackc/chunkreader v1.0.0/go.mod h1:RT6O25fNZIuasFJRyZ4R/Y2BbhasbmZXF9QQ7T3kePo= +github.com/jackc/chunkreader/v2 v2.0.0/go.mod h1:odVSm741yZoC3dpHEUXIqA9tQRhFrgOHwnPIn9lDKlk= +github.com/jackc/chunkreader/v2 v2.0.1 h1:i+RDz65UE+mmpjTfyz0MoVTnzeYxroil2G82ki7MGG8= +github.com/jackc/chunkreader/v2 v2.0.1/go.mod h1:odVSm741yZoC3dpHEUXIqA9tQRhFrgOHwnPIn9lDKlk= +github.com/jackc/pgconn v0.0.0-20190420214824-7e0022ef6ba3/go.mod h1:jkELnwuX+w9qN5YIfX0fl88Ehu4XC3keFuOJJk9pcnA= +github.com/jackc/pgconn v0.0.0-20190824142844-760dd75542eb/go.mod h1:lLjNuW/+OfW9/pnVKPazfWOgNfH2aPem8YQ7ilXGvJE= +github.com/jackc/pgconn v0.0.0-20190831204454-2fabfa3c18b7/go.mod h1:ZJKsE/KZfsUgOEh9hBm+xYTstcNHg7UPMVJqRfQxq4s= +github.com/jackc/pgconn v1.4.0/go.mod h1:Y2O3ZDF0q4mMacyWV3AstPJpeHXWGEetiFttmq5lahk= +github.com/jackc/pgconn v1.5.0/go.mod h1:QeD3lBfpTFe8WUnPZWN5KY/mB8FGMIYRdd8P8Jr0fAI= +github.com/jackc/pgconn v1.5.1-0.20200601181101-fa742c524853/go.mod h1:QeD3lBfpTFe8WUnPZWN5KY/mB8FGMIYRdd8P8Jr0fAI= +github.com/jackc/pgconn v1.7.2 h1:195tt17jkjy+FrFlY0pgyrul5kRLb7BGXY3JTrNxeXU= +github.com/jackc/pgconn v1.7.2/go.mod h1:1C2Pb36bGIP9QHGBYCjnyhqu7Rv3sGshaQUvmfGIB/o= +github.com/jackc/pgio v1.0.0 h1:g12B9UwVnzGhueNavwioyEEpAmqMe1E/BN9ES+8ovkE= +github.com/jackc/pgio v1.0.0/go.mod h1:oP+2QK2wFfUWgr+gxjoBH9KGBb31Eio69xUb0w5bYf8= +github.com/jackc/pgmock v0.0.0-20190831213851-13a1b77aafa2 h1:JVX6jT/XfzNqIjye4717ITLaNwV9mWbJx0dLCpcRzdA= +github.com/jackc/pgmock v0.0.0-20190831213851-13a1b77aafa2/go.mod h1:fGZlG77KXmcq05nJLRkk0+p82V8B8Dw8KN2/V9c/OAE= +github.com/jackc/pgpassfile v1.0.0 h1:/6Hmqy13Ss2zCq62VdNG8tM1wchn8zjSGOBJ6icpsIM= +github.com/jackc/pgpassfile v1.0.0/go.mod h1:CEx0iS5ambNFdcRtxPj5JhEz+xB6uRky5eyVu/W2HEg= +github.com/jackc/pgproto3 v1.1.0 h1:FYYE4yRw+AgI8wXIinMlNjBbp/UitDJwfj5LqqewP1A= +github.com/jackc/pgproto3 v1.1.0/go.mod h1:eR5FA3leWg7p9aeAqi37XOTgTIbkABlvcPB3E5rlc78= +github.com/jackc/pgproto3/v2 v2.0.0-alpha1.0.20190420180111-c116219b62db/go.mod h1:bhq50y+xrl9n5mRYyCBFKkpRVTLYJVWeCc+mEAI3yXA= +github.com/jackc/pgproto3/v2 v2.0.0-alpha1.0.20190609003834-432c2951c711/go.mod h1:uH0AWtUmuShn0bcesswc4aBTWGvw0cAxIJp+6OB//Wg= +github.com/jackc/pgproto3/v2 v2.0.0-rc3/go.mod h1:ryONWYqW6dqSg1Lw6vXNMXoBJhpzvWKnT95C46ckYeM= +github.com/jackc/pgproto3/v2 v2.0.0-rc3.0.20190831210041-4c03ce451f29/go.mod h1:ryONWYqW6dqSg1Lw6vXNMXoBJhpzvWKnT95C46ckYeM= +github.com/jackc/pgproto3/v2 v2.0.1/go.mod h1:WfJCnwN3HIg9Ish/j3sgWXnAfK8A9Y0bwXYU5xKaEdA= +github.com/jackc/pgproto3/v2 v2.0.6 h1:b1105ZGEMFe7aCvrT1Cca3VoVb4ZFMaFJLJcg/3zD+8= +github.com/jackc/pgproto3/v2 v2.0.6/go.mod h1:WfJCnwN3HIg9Ish/j3sgWXnAfK8A9Y0bwXYU5xKaEdA= +github.com/jackc/pgservicefile v0.0.0-20200307190119-3430c5407db8/go.mod h1:vsD4gTJCa9TptPL8sPkXrLZ+hDuNrZCnj29CQpr4X1E= +github.com/jackc/pgservicefile v0.0.0-20200714003250-2b9c44734f2b h1:C8S2+VttkHFdOOCXJe+YGfa4vHYwlt4Zx+IVXQ97jYg= +github.com/jackc/pgservicefile v0.0.0-20200714003250-2b9c44734f2b/go.mod h1:vsD4gTJCa9TptPL8sPkXrLZ+hDuNrZCnj29CQpr4X1E= +github.com/jackc/pgtype v0.0.0-20190421001408-4ed0de4755e0/go.mod h1:hdSHsc1V01CGwFsrv11mJRHWJ6aifDLfdV3aVjFF0zg= +github.com/jackc/pgtype v0.0.0-20190824184912-ab885b375b90/go.mod h1:KcahbBH1nCMSo2DXpzsoWOAfFkdEtEJpPbVLq8eE+mc= +github.com/jackc/pgtype v0.0.0-20190828014616-a8802b16cc59/go.mod h1:MWlu30kVJrUS8lot6TQqcg7mtthZ9T0EoIBFiJcmcyw= +github.com/jackc/pgtype v1.2.0/go.mod h1:5m2OfMh1wTK7x+Fk952IDmI4nw3nPrvtQdM0ZT4WpC0= +github.com/jackc/pgtype v1.3.1-0.20200510190516-8cd94a14c75a/go.mod h1:vaogEUkALtxZMCH411K+tKzNpwzCKU+AnPzBKZ+I+Po= +github.com/jackc/pgtype v1.3.1-0.20200606141011-f6355165a91c/go.mod h1:cvk9Bgu/VzJ9/lxTO5R5sf80p0DiucVtN7ZxvaC4GmQ= +github.com/jackc/pgtype v1.6.1 h1:CAtFD7TS95KrxRAh3bidgLwva48WYxk8YkbHZsSWfbI= +github.com/jackc/pgtype v1.6.1/go.mod h1:JCULISAZBFGrHaOXIIFiyfzW5VY0GRitRr8NeJsrdig= +github.com/jackc/pgx/v4 v4.0.0-20190420224344-cc3461e65d96/go.mod h1:mdxmSJJuR08CZQyj1PVQBHy9XOp5p8/SHH6a0psbY9Y= +github.com/jackc/pgx/v4 v4.0.0-20190421002000-1b8f0016e912/go.mod h1:no/Y67Jkk/9WuGR0JG/JseM9irFbnEPbuWV2EELPNuM= +github.com/jackc/pgx/v4 v4.0.0-pre1.0.20190824185557-6972a5742186/go.mod h1:X+GQnOEnf1dqHGpw7JmHqHc1NxDoalibchSk9/RWuDc= +github.com/jackc/pgx/v4 v4.5.0/go.mod h1:EpAKPLdnTorwmPUUsqrPxy5fphV18j9q3wrfRXgo+kA= +github.com/jackc/pgx/v4 v4.6.1-0.20200510190926-94ba730bb1e9/go.mod h1:t3/cdRQl6fOLDxqtlyhe9UWgfIi9R8+8v8GKV5TRA/o= +github.com/jackc/pgx/v4 v4.6.1-0.20200606145419-4e5062306904/go.mod h1:ZDaNWkt9sW1JMiNn0kdYBaLelIhw7Pg4qd+Vk6tw7Hg= +github.com/jackc/pgx/v4 v4.9.2 h1:1V7EAc5jvIqXwdzgk8+YyOK+4071hhePzBCAF6gxUUw= +github.com/jackc/pgx/v4 v4.9.2/go.mod h1:Jt/xJDqjUDUOMSv8VMWPQlCObVgF2XOgqKsW8S4ROYA= +github.com/jackc/puddle v0.0.0-20190413234325-e4ced69a3a2b/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dvjSWk= +github.com/jackc/puddle v0.0.0-20190608224051-11cab39313c9/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dvjSWk= +github.com/jackc/puddle v1.1.0/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dvjSWk= +github.com/jackc/puddle v1.1.1/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dvjSWk= +github.com/jackc/puddle v1.1.2/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dvjSWk= +github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99 h1:BQSFePA1RWJOlocH6Fxy8MmwDt+yVQYULKfN0RoTN8A= +github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99/go.mod h1:1lJo3i6rXxKeerYnT8Nvf0QmHCRC1n8sfWVwXF2Frvo= +github.com/jessevdk/go-flags v1.4.0/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI= github.com/jhump/protoreflect v1.6.0 h1:h5jfMVslIg6l29nsMs0D8Wj17RDVdNYti0vDN/PZZoE= github.com/jhump/protoreflect v1.6.0/go.mod h1:eaTn3RZAmMBcV0fifFvlm6VHNz3wSkYyXYWUh7ymB74= github.com/jmespath/go-jmespath v0.0.0-20160202185014-0b12d6b521d8/go.mod h1:Nht3zPeWKUH0NzdCt2Blrr5ys8VGpn0CEB0cQHVjt7k= github.com/jmespath/go-jmespath v0.0.0-20180206201540-c2b33e8439af h1:pmfjZENx5imkbgOkpRUYLnmbU7UEFbjtDA2hxJ1ichM= github.com/jmespath/go-jmespath v0.0.0-20180206201540-c2b33e8439af/go.mod h1:Nht3zPeWKUH0NzdCt2Blrr5ys8VGpn0CEB0cQHVjt7k= github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU= +github.com/jstemmer/go-junit-report v0.9.1 h1:6QPYqodiu3GuPL+7mfx+NwDdp2eTkp9IfEUpgAwUN0o= github.com/jstemmer/go-junit-report v0.9.1/go.mod h1:Brl9GWCQeLvo8nXZwPNNblvFj/XSXhF0NWZEnDohbsk= +github.com/kevinburke/ssh_config v0.0.0-20190725054713-01f96b0aa0cd h1:Coekwdh0v2wtGp9Gmz1Ze3eVRAWJMLokvN3QjdzCHLY= +github.com/kevinburke/ssh_config v0.0.0-20190725054713-01f96b0aa0cd/go.mod h1:CT57kijsi8u/K/BOFA39wgDQJ9CxiF4nAY/ojJ6r6mM= github.com/keybase/go-crypto v0.0.0-20161004153544-93f5b35093ba/go.mod h1:ghbZscTyKdM07+Fw3KSi0hcJm+AlEUWj8QLlPtijN/M= github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= +github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= +github.com/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/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/pty v1.1.8/go.mod h1:O1sed60cT9XZ5uDucP5qwvh+TE3NnUj51EiZO/lmSfw= github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE= github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= +github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= +github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= github.com/kylelemons/godebug v0.0.0-20170820004349-d65d576e9348/go.mod h1:B69LEHPfb2qLo0BaaOLcbitczOKLWTsrBG9LczfCD4k= github.com/kylelemons/godebug v1.1.0 h1:RPNrshWIDI6G2gRW9EHilWtl7Z6Sb1BR0xunSBf0SNc= github.com/kylelemons/godebug v1.1.0/go.mod h1:9/0rRGxNHcop5bhtWyNeEfOS8JIWk580+fNqagV/RAw= -github.com/mattn/go-colorable v0.0.9 h1:UVL0vNpWh04HeJXV0KLcaT7r06gOH2l4OW6ddYRUIY4= +github.com/lib/pq v1.0.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo= +github.com/lib/pq v1.1.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo= +github.com/lib/pq v1.2.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo= +github.com/lib/pq v1.3.0 h1:/qkRGz8zljWiDcFvgpwUpwIAPu3r07TDvs3Rws+o/pU= +github.com/lib/pq v1.3.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo= github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU= -github.com/mattn/go-isatty v0.0.4 h1:bnP0vzxcAdeI1zdubAl5PjU6zsERjGZb7raWodagDYs= +github.com/mattn/go-colorable v0.1.1/go.mod h1:FuOcm+DKB9mbwrcAfNl7/TZVBZ6rcnceauSikq3lYCQ= +github.com/mattn/go-colorable v0.1.2/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE= +github.com/mattn/go-colorable v0.1.6/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc= +github.com/mattn/go-colorable v0.1.7 h1:bQGKb3vps/j0E9GfJQ03JyhRuxsvdAanXlT9BTw3mdw= +github.com/mattn/go-colorable v0.1.7/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc= +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-isatty v0.0.5/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s= +github.com/mattn/go-isatty v0.0.7/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s= +github.com/mattn/go-isatty v0.0.8/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s= +github.com/mattn/go-isatty v0.0.9/go.mod h1:YNRxwqDuOph6SZLI9vUUz6OYw3QyUt7WiY2yME+cCiQ= +github.com/mattn/go-isatty v0.0.12 h1:wuysRhFDzyxgEmMf5xjvJ2M9dZoWAXNNr5LSBS7uHXY= +github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU= github.com/mattn/go-runewidth v0.0.4/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU= +github.com/mitchellh/cli v1.1.1 h1:J64v/xD7Clql+JVKSvkYojLOXu1ibnY9ZjGLwSt/89w= +github.com/mitchellh/cli v1.1.1/go.mod h1:xcISNoH86gajksDmfB23e/pu+B+GeFRMYmoHXxx3xhI= github.com/mitchellh/copystructure v1.0.0 h1:Laisrj+bAB6b/yJwB5Bt3ITZhGJdqmxquMKeZ+mmkFQ= github.com/mitchellh/copystructure v1.0.0/go.mod h1:SNtv71yrdKgLRyLFxmLdkAbkKEFWgYaq1OVrnRcwhnw= github.com/mitchellh/go-homedir v1.0.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0= github.com/mitchellh/go-homedir v1.1.0 h1:lukF9ziXFxDFPkA1vsr5zpc1XuPDn/wFntq5mG+4E0Y= github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0= github.com/mitchellh/go-testing-interface v0.0.0-20171004221916-a61a99592b77/go.mod h1:kRemZodwjscx+RGhAo8eIhFbs2+BFgRtFPeD/KE+zxI= -github.com/mitchellh/go-testing-interface v1.0.0 h1:fzU/JVNcaqHQEcVFAKeR41fkiLdIPrefOvVG1VZ96U0= github.com/mitchellh/go-testing-interface v1.0.0/go.mod h1:kRemZodwjscx+RGhAo8eIhFbs2+BFgRtFPeD/KE+zxI= github.com/mitchellh/go-testing-interface v1.0.4 h1:ZU1VNC02qyufSZsjjs7+khruk2fKvbQ3TwRV/IBCeFA= github.com/mitchellh/go-testing-interface v1.0.4/go.mod h1:kRemZodwjscx+RGhAo8eIhFbs2+BFgRtFPeD/KE+zxI= @@ -216,48 +361,103 @@ github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh github.com/mitchellh/reflectwalk v1.0.0/go.mod h1:mSTlrgnPZtwu0c4WaC2kGObEpuNDbx0jmZXqmk4esnw= github.com/mitchellh/reflectwalk v1.0.1 h1:FVzMWA5RllMAKIdUSC8mdWo3XtwoecrH79BY70sEEpE= github.com/mitchellh/reflectwalk v1.0.1/go.mod h1:mSTlrgnPZtwu0c4WaC2kGObEpuNDbx0jmZXqmk4esnw= +github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e h1:fD57ERR4JtEqsWbfPhv4DMiApHyliiK5xCTNVSPiaAs= +github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno= +github.com/nsf/jsondiff v0.0.0-20200515183724-f29ed568f4ce h1:RPclfga2SEJmgMmz2k+Mg7cowZ8yv4Trqw9UsJby758= +github.com/nsf/jsondiff v0.0.0-20200515183724-f29ed568f4ce/go.mod h1:uFMI8w+ref4v2r9jz+c9i1IfIttS/OkmLfrk1jne5hs= github.com/oklog/run v1.0.0 h1:Ru7dDtJNOyC66gQ5dQmaCa0qIsAUFY3sFpK1Xk8igrw= github.com/oklog/run v1.0.0/go.mod h1:dlhp/R75TPv97u0XWUtDeV/lRKWPKSdTuV0TZvrmrQA= +github.com/opencontainers/go-digest v1.0.0 h1:apOUWs51W5PlhuyGyz9FCeeBIOUDA/6nW8Oi/yOhh5U= +github.com/opencontainers/go-digest v1.0.0/go.mod h1:0JzlMkj0TRzQZfJkVvzbP0HBR3IKzErnv2BNG4W4MAM= +github.com/opencontainers/image-spec v1.0.1 h1:JMemWkRwHx4Zj+fVxWoMCFm/8sYGGrUVojFA6h/TRcI= +github.com/opencontainers/image-spec v1.0.1/go.mod h1:BtxoFyWECRxE4U/7sNtV5W15zMzWCbyJoFRP3s7yZA0= +github.com/opencontainers/runc v0.1.1 h1:GlxAyO6x8rfZYN9Tt0Kti5a/cP41iuiO2yYT0IJGY8Y= +github.com/opencontainers/runc v0.1.1/go.mod h1:qT5XzbpPznkRYVz/mWwUaVBUv2rmF59PVA73FjuZG0U= +github.com/ory/dockertest v3.3.5+incompatible h1:iLLK6SQwIhcbrG783Dghaaa3WPzGc+4Emza6EbVUUGA= +github.com/ory/dockertest v3.3.5+incompatible/go.mod h1:1vX4m9wsvi00u5bseYwXaSnhNrne+V0E6LAcBILJdPs= github.com/pierrec/lz4 v2.0.5+incompatible/go.mod h1:pdkljMzZIN41W+lC3N2tnIh5sFi+IEE17M5jbnwPHcY= +github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= +github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/posener/complete v1.1.1 h1:ccV59UEOTzVDnDUEFdT95ZzHVZ+5+158q8+SJb2QV5w= +github.com/posener/complete v1.1.1/go.mod h1:em0nMJCgc9GFtwrmVmEMR/ZL6WyhyjMBndrE9hABlRI= github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= -github.com/sergi/go-diff v1.0.0 h1:Kpca3qRNrduNnOQeazBd0ysaKrUJiIuISHxogkT9RPQ= +github.com/rs/xid v1.2.1/go.mod h1:+uKXf+4Djp6Md1KODXJxgGQPKngRmWyn10oCKFzNHOQ= +github.com/rs/zerolog v1.13.0/go.mod h1:YbFCdg8HfsridGWAh22vktObvhZbQsZXe4/zB0OKkWU= +github.com/rs/zerolog v1.15.0/go.mod h1:xYTKnLHcpfU2225ny5qZjxnj9NvkumZYjJHlAThCjNc= +github.com/russross/blackfriday v1.5.2 h1:HyvC0ARfnZBqnXwABFeSZHpKvJHJJfPz81GNueLj0oo= +github.com/russross/blackfriday v1.5.2/go.mod h1:JO/DiYxRf+HjHt06OyowR9PTA263kcR/rfWxYHBV53g= +github.com/satori/go.uuid v1.2.0/go.mod h1:dA0hQrYB0VpLJoorglMZABFdXlWrHn1NEOzdhQKdks0= github.com/sergi/go-diff v1.0.0/go.mod h1:0CfEIISq7TuYL3j771MWULgwwjU+GofnZX9QAmXWZgo= +github.com/sergi/go-diff v1.1.0 h1:we8PVUC3FE2uYfodKH/nBHMSetSfHDR6scGdBi+erh0= +github.com/sergi/go-diff v1.1.0/go.mod h1:STckp+ISIX8hZLjrqAeVduY0gWCT9IjLuqbuNXdaHfM= +github.com/shopspring/decimal v0.0.0-20180709203117-cd690d0c9e24/go.mod h1:M+9NzErvs504Cn4c5DxATwIqPbtswREoFCre64PpcG4= +github.com/shopspring/decimal v0.0.0-20200227202807-02e2044944cc h1:jUIKcSPO9MoMJBbEoyE/RJoE8vz7Mb8AjvifMMwSyvY= +github.com/shopspring/decimal v0.0.0-20200227202807-02e2044944cc/go.mod h1:DKyhrW/HYNuLGql+MJL6WCR6knT2jwCFRcu2hWCYk4o= +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/spf13/cobra v0.0.2-0.20171109065643-2da4a54c5cee/go.mod h1:1l0Ry5zgKvJasoi3XT1TypsSe7PqH0Sj9dhYf7v3XqQ= +github.com/spf13/pflag v1.0.1-0.20171106142849-4c012f6dcd95/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= github.com/spf13/pflag v1.0.2/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= 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/objx v0.2.0/go.mod h1:qt09Ya8vawLte6SNmTgCsAVtYtaKzEcn8ATUoHMkEqE= github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= github.com/stretchr/testify v1.3.0 h1:TivCn/peBQ7UY8ooIcPgZFpTNSz0Q2U6UrFlUfqbe0Q= github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= github.com/stretchr/testify v1.4.0 h1:2E4SXV/wtOkTonXsotYi4li6zVWxYlZuYNCXe9XRJyk= github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= -github.com/ulikunitz/xz v0.5.5 h1:pFrO0lVpTBXLpYw+pnLj6TbvHuyjXMfjGeCwSqCVwok= +github.com/stretchr/testify v1.5.1 h1:nOGnQDM7FYENwehXlg/kFVnos3rEvtKTjRvOWSzb6H4= +github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA= github.com/ulikunitz/xz v0.5.5/go.mod h1:2bypXElzHzzJZwzH67Y6wb67pO62Rzfn7BSiF4ABRW8= -github.com/ulikunitz/xz v0.5.7 h1:YvTNdFzX6+W5m9msiYg/zpkSURPPtOlzbqYjrFn7Yt4= -github.com/ulikunitz/xz v0.5.7/go.mod h1:nbz6k7qbPmH4IRqmfOplQw/tblSgqTqBwxkY0oWt/14= -github.com/vmihailenco/msgpack v3.3.3+incompatible h1:wapg9xDUZDzGCNFlwc5SqI1rvcciqcxEHac4CYj89xI= +github.com/ulikunitz/xz v0.5.8 h1:ERv8V6GKqVi23rgu5cj9pVfVzJbOqAY2Ntl88O6c2nQ= +github.com/ulikunitz/xz v0.5.8/go.mod h1:nbz6k7qbPmH4IRqmfOplQw/tblSgqTqBwxkY0oWt/14= github.com/vmihailenco/msgpack v3.3.3+incompatible/go.mod h1:fy3FlTQTDXWkZ7Bh6AcGMlsjHatGryHQYUTf1ShIgkk= -github.com/vmihailenco/msgpack v4.0.1+incompatible h1:RMF1enSPeKTlXrXdOcqjFUElywVZjjC6pqse21bKbEU= -github.com/vmihailenco/msgpack v4.0.1+incompatible/go.mod h1:fy3FlTQTDXWkZ7Bh6AcGMlsjHatGryHQYUTf1ShIgkk= +github.com/vmihailenco/msgpack v4.0.4+incompatible h1:dSLoQfGFAo3F6OoNhwUmLwVgaUXK79GlxNBwueZn0xI= +github.com/vmihailenco/msgpack v4.0.4+incompatible/go.mod h1:fy3FlTQTDXWkZ7Bh6AcGMlsjHatGryHQYUTf1ShIgkk= +github.com/xanzy/ssh-agent v0.2.1 h1:TCbipTQL2JiiCprBWx9frJ2eJlCYT00NmctrHxVAr70= +github.com/xanzy/ssh-agent v0.2.1/go.mod h1:mLlQY/MoOhWBj+gOGMQkOeiEvkx+8pJSI+0Bx9h2kr4= github.com/yuin/goldmark v1.1.25/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/zclconf/go-cty v1.2.0/go.mod h1:hOPWgoHbaTUnI5k4D2ld+GRpFJSCe6bCM7m1q/N4PQ8= github.com/zclconf/go-cty v1.2.1 h1:vGMsygfmeCl4Xb6OA5U5XVAaQZ69FvoG7X2jUtQujb8= github.com/zclconf/go-cty v1.2.1/go.mod h1:hOPWgoHbaTUnI5k4D2ld+GRpFJSCe6bCM7m1q/N4PQ8= +github.com/zclconf/go-cty v1.4.1 h1:Xzr4m4utRDhHDifag1onwwUSq32HLoLBsp+w6tD0880= +github.com/zclconf/go-cty v1.4.1/go.mod h1:nHzOclRkoj++EU9ZjSrZvRG0BXIWt8c7loYc0qXAFGQ= +github.com/zenazn/goji v0.9.0/go.mod h1:7S9M489iMyHBNxwZnk9/EHS098H4/F6TATF2mIxtB1Q= go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU= -go.opencensus.io v0.22.0 h1:C9hSCOW830chIVkdja34wa6Ky+IzWllkUinR+BtRZd4= go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8= go.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= go.opencensus.io v0.22.3/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= go.opencensus.io v0.22.4 h1:LYy1Hy3MJdrCdMwwzxA/dRok4ejH+RwNGbuoD9fCjto= go.opencensus.io v0.22.4/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.4.0/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE= +go.uber.org/atomic v1.6.0/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ= +go.uber.org/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0= +go.uber.org/multierr v1.5.0/go.mod h1:FeouvMocqHpRaaGuG9EjoKcStLC43Zu/fmqdUMPcKYU= +go.uber.org/tools v0.0.0-20190618225709-2cfd321de3ee/go.mod h1:vJERXedbb3MVM5f9Ejo0C68/HhF8uaILCdgjnY+goOA= +go.uber.org/zap v1.9.1/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q= +go.uber.org/zap v1.10.0/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q= +golang.org/x/crypto v0.0.0-20190219172222-a4c6cb3142f2/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-20190325154230-a5d413f7728c/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= +golang.org/x/crypto v0.0.0-20190411191339-88737f569e3a/go.mod h1:WFFai1msRO1wXaEeE5yQxYXgSfI8pQAWXbQop6sCtWE= golang.org/x/crypto v0.0.0-20190426145343-a29dc8fdc734/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20190820162420-60c769a6c586/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20190911031432-227b76d455e7/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20200302210943-78000ba7a073/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= +golang.org/x/crypto v0.0.0-20200323165209-0ec3e9974c59/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= 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= @@ -281,6 +481,7 @@ golang.org/x/lint v0.0.0-20190909230951-414d861bb4ac/go.mod h1:6SW0HCj/g11FgYtHl golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= golang.org/x/lint v0.0.0-20191125180803-fdd1cda4f05f/go.mod h1:5qLYkcX4OjUUV8bRuDixDT3tpyyb+LUpUlRWLxfhWrs= golang.org/x/lint v0.0.0-20200130185559-910be7a94367/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= +golang.org/x/lint v0.0.0-20200302205851-738671d3881b h1:Wh+f8QHJXR411sJR8/vRBTZ7YapZaRvUcLFFJhusH0k= golang.org/x/lint v0.0.0-20200302205851-738671d3881b/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= golang.org/x/mobile v0.0.0-20190312151609-d3739f865fa6/go.mod h1:z+o9i4GpDbdi3rU15maQ/Ox0txvL9dWGYEHz965HBQE= golang.org/x/mobile v0.0.0-20190719004257-d2bd2a29d028/go.mod h1:E/iHnbuqvinMTCcRqshq8CkpyQDoeVncDDYHnLhea+o= @@ -289,11 +490,13 @@ golang.org/x/mod v0.1.0/go.mod h1:0QHyrYULN0/3qlju5TqG8bIK38QM8yzMo5ekMj3DlcY= golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= golang.org/x/mod v0.1.1-0.20191107180719-034126e5016b/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= +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-20180530234432-1e491301e022/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180811021610-c39426892332/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-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= @@ -304,11 +507,13 @@ golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20190628185345-da137c7871d7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20190724013045-ca1201d0de80/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-20191209160850-c0dbc17a3553/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20200114155413-6afb5195e5aa/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20200202094626-16171245cfb2/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20200222125558-5a598a2470a0/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20200301022130-244492dfa37a h1:GuSPYbZzB5/dcLNCwLQLsg3obCJtX9IJhpXkvY7kzk0= golang.org/x/net v0.0.0-20200301022130-244492dfa37a/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20200324143707-d3edc9973b7e/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= golang.org/x/net v0.0.0-20200501053045-e0ff5e5a1de5/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= @@ -320,7 +525,6 @@ golang.org/x/net v0.0.0-20200707034311-ab3426394381 h1:VXak5I6aEWmAXeQjA+QSZzlgN golang.org/x/net v0.0.0-20200707034311-ab3426394381/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= -golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45 h1:SVwTIAaPC2U/AvvLNZ2a7OVsmBpC8L5BlwK1whH3hm0= golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/oauth2 v0.0.0-20191202225959-858c2ad4c8b6/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d h1:TzXSXBo42m9gQenoE3b9BGiEpg5IG2JkU5FkPIawgtw= @@ -329,37 +533,14 @@ golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJ golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20190423024810-112230192c58 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-20200317015054-43a5402ce75a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20200625203802-6e8e738ad208 h1:qwRHBd0NqMbJxfbotnDhm2ByMI1Shq4Y6oRJo21SGJA= golang.org/x/sync v0.0.0-20200625203802-6e8e738ad208/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/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-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190502145724-3ef323f4f1fd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190502175342-a43fa875dd82/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190507160741-ecd444e8653b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190606165138-5da285871e9c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190624142023-c5567b49c5d0 h1:HyfiK1WMnHj5FXFXatD+Qs1A/xC2Run6RzeW1SyHxpc= -golang.org/x/sys v0.0.0-20190624142023-c5567b49c5d0/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190726091711-fc99dfbffb4e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20191001151750-bb3f8db39f24/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20191204072324-ce4227a45e2e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20191228213918-04cbcbbfeed8/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200113162924-86b910548bc1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200122134326-e047566fdf82/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200202164722-d101bd2416d5/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200212091648-12a6c2dcc1e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200302150141-5c8b2ff67527/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200331124033-c3d80250170d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200501052902-10377860bb8e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200511232937-7e40ca221e25/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200515095857-1151b9dac4a9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200523222454-059865788121 h1:rITEj+UZHYC927n8GT97eC3zrpzXdb/voyeOuVKS46o= -golang.org/x/sys v0.0.0-20200523222454-059865788121/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190830141801-acfa387b8d69 h1:Wdn4Yb8d5VrsO3jWgaeSZss09x1VLVBMePDh4VW/xSQ= +golang.org/x/sys v0.0.0-20190830141801-acfa387b8d69/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= @@ -377,14 +558,18 @@ golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3 golang.org/x/tools v0.0.0-20190312151545-0bb0c0a6e846/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= golang.org/x/tools v0.0.0-20190312170243-e65039ee4138/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= golang.org/x/tools v0.0.0-20190425150028-36563e24a262/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= +golang.org/x/tools v0.0.0-20190425163242-31fd60d6bfdc/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= golang.org/x/tools v0.0.0-20190506145303-2d16b83fe98c/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= golang.org/x/tools v0.0.0-20190606124116-d0a3d012864b/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-20190628153133-6cdbf07be9d0/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= golang.org/x/tools v0.0.0-20190816200558-6889da9d5479/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20190823170909-c4a336ef6a2f/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20190911174233-4f2ddba30aff/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191012152004-8de300cfc20a/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +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-20191113191852-77e3bb0ad9e7/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191115202509-3a792d9c32b2/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= @@ -407,7 +592,10 @@ golang.org/x/tools v0.0.0-20200501065659-ab2804fb9c9d/go.mod h1:EkVYQZoAsY45+roY golang.org/x/tools v0.0.0-20200512131952-2bc93b1c0c88/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= golang.org/x/tools v0.0.0-20200515010526-7d3b6ebf133d/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= golang.org/x/tools v0.0.0-20200618134242-20370b0cb4b2/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= +golang.org/x/tools v0.0.0-20200713011307-fd294ab11aed h1:+qzWo37K31KxduIYaBeMqJ8MUOyTayOQKpH9aDPLMSY= golang.org/x/tools v0.0.0-20200713011307-fd294ab11aed/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= +golang.org/x/xerrors v0.0.0-20190410155217-1f06c39b4373/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20190513163551-3ee3066db522/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543 h1:E7g+9GITq07hpfrRu66IVDexMakfv52eLZ2CXBWiKr4= @@ -415,7 +603,6 @@ golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8T google.golang.org/api v0.4.0/go.mod h1:8k5glujaEP+g9n7WNsDg8QP6cUVNI86fCNMcbazEtwE= google.golang.org/api v0.7.0/go.mod h1:WtwebWUNSVBH/HAw79HIFXZNqEvBhG+Ra+ax0hx3E3M= google.golang.org/api v0.8.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg= -google.golang.org/api v0.9.0 h1:jbyannxz0XFD3zdjgrSUsaJbgpH4eTrkdhRChkHPfO8= google.golang.org/api v0.9.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg= google.golang.org/api v0.13.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI= google.golang.org/api v0.14.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI= @@ -432,7 +619,6 @@ google.golang.org/api v0.29.0/go.mod h1:Lcubydp8VUV7KeIHD9z2Bys/sm/vGKnG1UHuDBSr google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= google.golang.org/appengine v1.5.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= -google.golang.org/appengine v1.6.1 h1:QzqyMA1tlu6CgqCDUtU9V+ZKhLFT2dkJuANu5QaxI3I= google.golang.org/appengine v1.6.1/go.mod h1:i06prIuMbXzDqacNJfV5OdTW448YApPu5ww/cMBSeb0= google.golang.org/appengine v1.6.5/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= google.golang.org/appengine v1.6.6 h1:lMO5rYAqUxkmaj76jAkRUvt5JZgFymx/+Q5Mzfivuhc= @@ -479,8 +665,9 @@ google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8 google.golang.org/grpc v1.27.1/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= google.golang.org/grpc v1.28.0/go.mod h1:rpkK4SK4GF4Ach/+MFLZUBavHOvF2JJB5uozKKal+60= google.golang.org/grpc v1.29.1/go.mod h1:itym6AZVZYACWQqET3MqgPpjcuV5QH3BxFS3IjizoKk= -google.golang.org/grpc v1.30.0 h1:M5a8xTlYTxwMn5ZFkwhRabsygDY5G8TYLyQDBxJNAxE= google.golang.org/grpc v1.30.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak= +google.golang.org/grpc v1.32.0 h1:zWTV+LMdc3kaiJMSTOFz2UgSBgx8RNQoTGiZu3fR9S0= +google.golang.org/grpc v1.32.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak= 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= @@ -495,10 +682,21 @@ google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlba 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/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f h1:BLraFXnmrev5lT+xlilqcH8XK9/i0At2xKjWk4p6zsU= +gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/cheggaaa/pb.v1 v1.0.27/go.mod h1:V/YB90LKu/1FcN3WVnfiiE5oMCibMjukxqG/qStrOgw= gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= +gopkg.in/inconshreveable/log15.v2 v2.0.0-20180818164646-67afb5ed74ec/go.mod h1:aPpfJ7XW+gOuirDoZ8gHhLh3kZ1B08FtV2bbmy7Jv3s= +gopkg.in/warnings.v0 v0.1.2 h1:wFXVbFY8DY5/xOe1ECiWdKCzZlxgshcYVNkBHstARME= +gopkg.in/warnings.v0 v0.1.2/go.mod h1:jksf8JmL6Qr/oQM2OXTHunEvvTAsrWBLb6OOjuVWRNI= gopkg.in/yaml.v2 v2.2.2 h1:ZCJp+EgiOT7lHqUV2J862kp8Qj64Jo6az82+3Td9dZw= gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.8 h1:obN1ZagJSUGI0Ek/LBmuj4SNLPfIny3KsKFopxRdj10= +gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gotest.tools v2.2.0+incompatible h1:VsBPFP1AI068pPrMxtb/S8Zkgf9xEmTLJjfM+P5UIEo= +gotest.tools v2.2.0+incompatible/go.mod h1:DsYFclhRJ6vuDpmuTbkuFWG+y2sxOXAzmJt81HFBacw= honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20190418001031-e561f6794a2a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= diff --git a/internal/provider/data_query.go b/internal/provider/data_query.go new file mode 100644 index 0000000..fb1946f --- /dev/null +++ b/internal/provider/data_query.go @@ -0,0 +1,123 @@ +package provider + +import ( + "context" + "fmt" + + "github.com/hashicorp/terraform-plugin-go/tfprotov5" + "github.com/hashicorp/terraform-plugin-go/tfprotov5/tftypes" +) + +type dataQuery struct { + p *provider +} + +func (d *dataQuery) Schema(context.Context) *tfprotov5.Schema { + return &tfprotov5.Schema{ + Block: &tfprotov5.SchemaBlock{ + Description: "The `sql_query` datasource allows you to execute a SQL query against the database of your choice.", + DescriptionKind: tfprotov5.StringKindMarkdown, + Attributes: []*tfprotov5.SchemaAttribute{ + { + Name: "query", + Required: true, + Description: "The query to execute. The types in this query will be reflected in the typing of the `result` attribute.", + DescriptionKind: tfprotov5.StringKindMarkdown, + Type: tftypes.String, + }, + // { + // Name: "parameters", + // Optional: true, + // DescriptionKind: tfprotov5.StringKindMarkdown, + // Type: tftypes.DynamicPseudoType, + // }, + + { + Name: "result", + Computed: true, + Description: "The result of the query. This will be a list of objects. Each object will have attributes " + + "with names that match column names and types that match column types. The exact translation of types " + + "is dependent upon the database driver.", + DescriptionKind: tfprotov5.StringKindMarkdown, + Type: tftypes.List{ + ElementType: tftypes.DynamicPseudoType, + }, + }, + + // TODO: remove this once its not needed by testing + { + Name: "id", + Computed: true, + Deprecated: true, + Description: "This attribute is only present for some compatibility issues and should not be used. It " + + "will be removed in a future version.", + DescriptionKind: tfprotov5.StringKindMarkdown, + Type: tftypes.String, + }, + }, + }, + } +} + +func (d *dataQuery) Validate(ctx context.Context, config map[string]tftypes.Value) ([]*tfprotov5.Diagnostic, error) { + // TODO: if connected to server, validate query against it? + return nil, nil +} + +func (d *dataQuery) Read(ctx context.Context, config map[string]tftypes.Value) (map[string]tftypes.Value, []*tfprotov5.Diagnostic, error) { + var ( + query string + ) + err := config["query"].As(&query) + if err != nil { + return nil, nil, err + } + + rows, err := d.p.db.QueryContext(ctx, query) + if err != nil { + return nil, nil, err + } + defer rows.Close() + + var rowType tftypes.Type + rowSet := []tftypes.Value{} + for rows.Next() { + row, ty, err := d.p.db.valuesForRow(rows) + if err != nil { + return nil, []*tfprotov5.Diagnostic{ + { + Severity: tfprotov5.DiagnosticSeverityError, + Attribute: &tftypes.AttributePath{ + Steps: []tftypes.AttributePathStep{ + tftypes.AttributeName("result"), + }, + }, + Summary: fmt.Sprintf("unable to convert value from database: %s", err), + }, + }, nil + } + + if rowType == nil { + rowType = tftypes.Object{ + AttributeTypes: ty, + } + } + + rowSet = append(rowSet, tftypes.NewValue( + rowType, + row, + )) + } + + return map[string]tftypes.Value{ + "id": config["query"], + "query": config["query"], + // "parameters": config["parameters"], + "result": tftypes.NewValue( + tftypes.List{ + ElementType: rowType, + }, + rowSet, + ), + }, nil, nil +} diff --git a/internal/provider/data_query_test.go b/internal/provider/data_query_test.go new file mode 100644 index 0000000..3d97ea9 --- /dev/null +++ b/internal/provider/data_query_test.go @@ -0,0 +1,226 @@ +package provider + +import ( + "fmt" + "strings" + "testing" + + "github.com/hashicorp/terraform-plugin-go/tfprotov5" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" + "github.com/hashicorp/terraform-plugin-sdk/v2/terraform" +) + +func TestQuery_driverTypes(t *testing.T) { + const testColName = "testcol" + + if testing.Short() { + t.Skip("skipping long test") + } + + for k, url := range testURLs { + t.Run(k, func(t *testing.T) { + scheme, err := schemeFromURL(url) + if err != nil { + t.Fatalf("unable to determine driver scheme for %s: %s", k, err) + } + var literals map[string]struct { + sql string + expected string + } + // TODO: check output types for expected HCL type, not sure how to to do this + switch scheme { + case "mysql": + literals = map[string]struct { + sql string + expected string + }{ + // https://dev.mysql.com/doc/refman/8.0/en/cast-functions.html#function_convert + + // TODO: "binary" + "char": {"cast('foo' as char)", "foo"}, + "date": {"cast('2020-11-16' as date)", "2020-11-16T00:00:00Z"}, + "datetime": {"cast('2020-11-16 19:00:01' as datetime)", "2020-11-16T19:00:01Z"}, + "decimal": {"cast(1.2 as decimal(4,3))", ""}, + "double": {"cast(1.2 as double)", "1.2"}, + "float": {"cast(.125 as float(5))", "0.125"}, + // TODO: parse to HCL types + "json": {"JSON_TYPE('[1, 2, 3]')", ""}, + "nchar": {"cast('foo' as nchar)", "foo"}, + "real": {"cast(.125 as real)", "0.125"}, + "signed": {"cast(-7 as signed)", "-7"}, + "time": {"cast('04:05:06' as time)", "04:05:06"}, + "unsigned": {"cast(1 as unsigned)", "1"}, + "year": {"cast(2020 as year)", "2020"}, + } + case "postgres": + literals = map[string]struct { + sql string + expected string + }{ + "bigint": {"cast(1 as bigint)", "1"}, + "bit": {"cast(B'1001' as bit (4))", "1001"}, + "bit varying": {"cast(B'1001' as bit varying (4))", "1001"}, + "bool": {"cast(true as bool)", "true"}, + "character": {"cast('aaa' as character (3))", "aaa"}, + "character varying": {"cast('abc def' as character varying)", "abc def"}, + "cidr": {"cast('192.168.1.0/24' as cidr)", "192.168.1.0/24"}, + "date": {"cast('1999-01-08' as date)", "1999-01-08T00:00:00Z"}, + "double precision": {"cast(1.2 as double precision)", "1.2"}, + "inet": {"cast('192.168.1.1' as inet)", "192.168.1.1"}, + "integer": {"cast(3 as integer)", "3"}, + "macaddr": {"cast('08:00:2b:01:02:03' as macaddr)", "08:00:2b:01:02:03"}, + "macaddr8": {"cast('08:00:2b:01:02:03:04:05' as macaddr8)", "08:00:2b:01:02:03:04:05"}, + "numeric": {"cast(1.234 as numeric)", "1.234"}, + "real": {"cast(.125 as real)", "0.125"}, + "smallint": {"cast(12 as smallint)", "12"}, + "text": {"cast('foo' as text)", "foo"}, + "time": {"cast('04:05:06.789' as time)", "04:05:06.789"}, + "time with time zone": {"cast('04:05:06 PST' as time with time zone)", ""}, + "timestamp": {"cast('1999-01-08 04:05:06' as timestamp)", "1999-01-08T04:05:06Z"}, + "timestamp with time zone": {"cast('January 8 04:05:06 1999 PST' as timestamp with time zone)", "1999-01-08T07:05:06-05:00"}, + "uuid": {"cast('a0eebc99-9c0b-4ef8-bb6d-6bb9bd380a11' as uuid)", "a0eebc99-9c0b-4ef8-bb6d-6bb9bd380a11"}, + "xml": {`XMLPARSE (DOCUMENT 'Manual...')`, ""}, + + // TODO: money is not supported properly, just as string + "money": {"cast('12.34' as money)", ""}, + + // TODO: actually convert this to HCL types? + "json": {"cast('[1, 2]' as json)", ""}, + "jsonb": {"cast('[4, 5, null]' as jsonb)", ""}, + + // TODO: other data types: + + // box rectangular box on a plane + // bytea binary data (“byte array”) + // TODO: "bytea": `cast('\xDEADBEEF' as bytea)`, + // circle circle on a plane + // interval [ fields ] [ (p) ] time span + // line infinite line on a plane + // lseg line segment on a plane + // path geometric path on a plane + // pg_lsn PostgreSQL Log Sequence Number + // pg_snapshot user-level transaction ID snapshot + // point geometric point on a plane + // polygon closed geometric path on a plane + // tsquery text search query + // tsvector text search document + // txid_snapshot user-level transaction ID snapshot (deprecated; see pg_snapshot) + } + + // remove a few tests for cockroach db: + if k == "cockroach" { + delete(literals, "cidr") + delete(literals, "macaddr") + delete(literals, "macaddr8") + delete(literals, "time with time zone") + delete(literals, "timestamp with time zone") + delete(literals, "xml") + } + case "sqlserver": + literals = map[string]struct { + sql string + expected string + }{ + // exact numerics + "bigint": {"cast(12345 as bigint)", "12345"}, + "int": {"cast(12345 as int)", "12345"}, + "smallint": {"cast(-12345 as smallint)", "-12345"}, + "tinyint": {"cast(200 as tinyint)", "200"}, + + "bit": {"cast(1 as bit)", "true"}, + + // TODO: these are not yet supported properly, just as string + "decimal": {"cast(123.4 as decimal(9,3))", ""}, + "money": {"cast(123.45 as money)", ""}, + "smallmoney": {"cast(-123.45 as smallmoney)", ""}, + + // aproximate numerics + "float": {"cast(.125 as float(5))", "0.125"}, + "real": {"cast(.125 as real)", "0.125"}, + + // character strings + "char": {"cast('a' as char(1))", "a"}, + "varchar": {"cast('abc' as varchar(10))", "abc"}, + "text": {"cast('abcdef' as text)", "abcdef"}, + + // unicode strings + "nchar": {"cast('a' as nchar(1))", "a"}, + "nvarchar": {"cast('abc' as nvarchar(10))", "abc"}, + "ntext": {"cast('abcdef' as ntext)", "abcdef"}, + + // other data types + "uniqueidentifier": {"cast('0E984725-C51C-4BF4-9960-E1C80E27ABA0' as uniqueidentifier)", "0E984725-C51C-4BF4-9960-E1C80E27ABA0"}, + + // TODO: other data types: + + // binary + // varbinary + // image + // cursor + // rowversion + // hierarchyid + // sql_variant + // xml + // spatial types + // table? + } + } + + if len(literals) == 0 { + t.Skipf("no literals to test defined for scheme: %q (%s)", scheme, k) + } + for name, lit := range literals { + + t.Run(name, func(t *testing.T) { + // for debugging a single type... + // if name != "money" && name != "smallmoney" && name != "decimal" { + // t.Skip() + // } + + // fix slash escaping + col := strings.ReplaceAll(lit.sql, `\`, `\\`) + query := fmt.Sprintf("select %s as %s", col, testColName) + resource.UnitTest(t, resource.TestCase{ + ProtoV5ProviderFactories: map[string]func() (tfprotov5.ProviderServer, error){ + "sql": func() (tfprotov5.ProviderServer, error) { + return New("acctest")(), nil + }, + }, + Steps: []resource.TestStep{ + { + + Config: fmt.Sprintf(` +provider "sql" { + url = %q + + max_idle_conns = 0 +} + +data "sql_query" "test" { + query = %q +} + +output "query" { + value = data.sql_query.test.result +} + `, url, query), + Check: resource.ComposeTestCheckFunc( + func(s *terraform.State) error { + rs := s.RootModule().Resources["data.sql_query.test"] + att := rs.Primary.Attributes["result.0."+testColName] + if lit.expected == "" { + t.Logf("skipping value check, but got %q", att) + } else if lit.expected != att { + return fmt.Errorf("expected %q, got %q", lit.expected, att) + } + return nil + }, + ), + }, + }, + }) + }) + } + }) + } +} diff --git a/internal/provider/data_source_scaffolding.go b/internal/provider/data_source_scaffolding.go deleted file mode 100644 index 335a570..0000000 --- a/internal/provider/data_source_scaffolding.go +++ /dev/null @@ -1,25 +0,0 @@ -package provider - -import ( - "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" -) - -func dataSourceScaffolding() *schema.Resource { - return &schema.Resource{ - Read: dataSourceScaffoldingRead, - - Schema: map[string]*schema.Schema{ - "sample_attribute": { - Type: schema.TypeString, - Required: true, - }, - }, - } -} - -func dataSourceScaffoldingRead(d *schema.ResourceData, meta interface{}) error { - // use the meta value to retrieve your client from the provider configure method - // client := meta.(*apiClient) - - return nil -} diff --git a/internal/provider/data_source_scaffolding_test.go b/internal/provider/data_source_scaffolding_test.go deleted file mode 100644 index 7bbfd82..0000000 --- a/internal/provider/data_source_scaffolding_test.go +++ /dev/null @@ -1,30 +0,0 @@ -package provider - -import ( - "regexp" - "testing" - - "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" -) - -func TestAccDataSourceScaffolding(t *testing.T) { - resource.UnitTest(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - ProviderFactories: providerFactories, - Steps: []resource.TestStep{ - { - Config: testAccDataSourceScaffolding, - Check: resource.ComposeTestCheckFunc( - resource.TestMatchResourceAttr( - "scaffolding_data_source.foo", "sample_attribute", regexp.MustCompile("^ba")), - ), - }, - }, - }) -} - -const testAccDataSourceScaffolding = ` -resource "scaffolding_data_source" "foo" { - sample_attribute = "bar" -} -` diff --git a/internal/provider/db.go b/internal/provider/db.go new file mode 100644 index 0000000..62bcf1d --- /dev/null +++ b/internal/provider/db.go @@ -0,0 +1,178 @@ +package provider + +import ( + "database/sql" + "fmt" + "reflect" + "strings" + + // database drivers + _ "github.com/denisenkom/go-mssqldb" + _ "github.com/go-sql-driver/mysql" + _ "github.com/jackc/pgx/v4/stdlib" + + // TODO: sqlite? need to use a pure go driver, i think this one is... + // _ "modernc.org/sqlite" + + "github.com/hashicorp/terraform-plugin-go/tfprotov5/tftypes" +) + +type db struct { + *sql.DB + + driver string +} + +func newDB(dsn string, conf func(*sql.DB) error) (*db, error) { + var err error + n := &db{} + + scheme, err := schemeFromURL(dsn) + if err != nil { + return nil, err + } + + switch scheme { + case "postgres", "postgresql": + n.driver = "pgx" + case "mysql": + n.driver = "mysql" + dsn = strings.TrimPrefix(dsn, "mysql://") + // TODO: multistatements? see go-migrate's implementation + // https://github.com/golang-migrate/migrate/blob/master/database/mysql/mysql.go + + // TODO: also set parseTime=true https://github.com/go-sql-driver/mysql#parsetime + case "sqlserver": + n.driver = "sqlserver" + default: + return nil, fmt.Errorf("unexpected datasource name scheme: %q", scheme) + } + + n.DB, err = sql.Open(n.driver, dsn) + if err != nil { + return nil, fmt.Errorf("unable to open database: %w", err) + } + + // force this to zero, but let callers override config + n.DB.SetMaxIdleConns(0) + if conf != nil { + err = conf(n.DB) + if err != nil { + return nil, fmt.Errorf("unable to configure database: %w", err) + } + } + + return n, nil +} + +func schemeFromURL(url string) (string, error) { + if url == "" { + return "", fmt.Errorf("a datasource name is required") + } + + i := strings.Index(url, ":") + + // No : or : is the first character. + if i < 1 { + return "", fmt.Errorf("a scheme for datasource name is required") + } + + return url[0:i], nil +} + +func (db *db) valuesForRow(rows *sql.Rows) (map[string]tftypes.Value, map[string]tftypes.Type, error) { + colTypes, err := rows.ColumnTypes() + if err != nil { + return nil, nil, fmt.Errorf("unable to retrieve column type: %w", err) + } + + pointers := make([]interface{}, len(colTypes)) + row := map[string]struct { + index int + ty tftypes.Type + val interface{} + }{} + + for i, colType := range colTypes { + name := colType.Name() + if name == "?column?" { + name = fmt.Sprintf("column%d", i) + } + + ty, rty, err := db.typeAndValueForColType(colType) + if err != nil { + return nil, nil, fmt.Errorf("unable to determine type for %q: %w", name, err) + } + + val := reflect.New(rty) + pointers[i] = val.Interface() + + row[name] = struct { + index int + ty tftypes.Type + val interface{} + }{i, ty, val.Interface()} + } + + err = rows.Scan(pointers...) + if err != nil { + return nil, nil, fmt.Errorf("unable to scan values: %w", err) + } + + rowValues := map[string]tftypes.Value{} + rowTypes := map[string]tftypes.Type{} + for k, v := range row { + rowValues[k] = tftypes.NewValue( + v.ty, + v.val, + ) + rowTypes[k] = v.ty + } + + return rowValues, rowTypes, nil +} + +func (db *db) typeAndValueForColType(colType *sql.ColumnType) (tftypes.Type, reflect.Type, error) { + scanType := colType.ScanType() + kind := scanType.Kind() + + switch db.driver { + case "sqlserver": + switch dbName := colType.DatabaseTypeName(); dbName { + case "UNIQUEIDENTIFIER": + return tftypes.String, reflect.TypeOf((*sqlServerUniqueIdentifier)(nil)).Elem(), nil + case "DECIMAL", "MONEY", "SMALLMONEY": + return tftypes.String, reflect.TypeOf((*string)(nil)).Elem(), nil + } + case "mysql": + switch dbName := colType.DatabaseTypeName(); dbName { + case "YEAR": + return tftypes.Number, reflect.TypeOf((*int)(nil)).Elem(), nil + case "VARCHAR", "DECIMAL", "TIME": + return tftypes.String, reflect.TypeOf((*string)(nil)).Elem(), nil + case "DATE", "DATETIME": + return tftypes.String, tfTimeType, nil + } + case "pgx": + switch dbName := colType.DatabaseTypeName(); dbName { + // 790 is the oid of money + case "MONEY", "790": + return nil, nil, fmt.Errorf("money is not supported for column %q, please convert to numeric", colType.Name()) + case "TIMESTAMPTZ", "TIMESTAMP", "DATE": + return tftypes.String, tfTimeType, nil + } + } + + switch kind { + case reflect.String: + return tftypes.String, scanType, nil + case reflect.Int64, reflect.Int32, reflect.Int16, reflect.Int8, reflect.Int, + reflect.Uint64, reflect.Uint32, reflect.Uint16, reflect.Uint8, reflect.Uint, + reflect.Float32, reflect.Float64: + return tftypes.Number, scanType, nil + case reflect.Bool: + return tftypes.Bool, scanType, nil + } + + return nil, nil, fmt.Errorf("unexpected type for %q: %q (%s %s)", colType.Name(), colType.DatabaseTypeName(), kind, scanType) +} diff --git a/internal/provider/provider.go b/internal/provider/provider.go deleted file mode 100644 index d550346..0000000 --- a/internal/provider/provider.go +++ /dev/null @@ -1,41 +0,0 @@ -package provider - -import ( - "context" - - "github.com/hashicorp/terraform-plugin-sdk/v2/diag" - "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" -) - -func New(version string) func() *schema.Provider { - return func() *schema.Provider { - p := &schema.Provider{ - DataSourcesMap: map[string]*schema.Resource{ - "scaffolding_data_source": dataSourceScaffolding(), - }, - ResourcesMap: map[string]*schema.Resource{ - "scaffolding_resource": resourceScaffolding(), - }, - } - - p.ConfigureContextFunc = configure(version, p) - - return p - } -} - -type apiClient struct { - // Add whatever fields, client or connection info, etc. here - // you would need to setup to communicate with the upstream - // API. -} - -func configure(version string, p *schema.Provider) func(context.Context, *schema.ResourceData) (interface{}, diag.Diagnostics) { - return func(context.Context, *schema.ResourceData) (interface{}, diag.Diagnostics) { - // Setup a User-Agent for your API client (replace the provider name for yours): - // userAgent := p.UserAgent("terraform-provider-scaffolding", version) - // TODO: myClient.UserAgent = userAgent - - return &apiClient{}, nil - } -} diff --git a/internal/provider/provider_test.go b/internal/provider/provider_test.go deleted file mode 100644 index 9cd082c..0000000 --- a/internal/provider/provider_test.go +++ /dev/null @@ -1,28 +0,0 @@ -package provider - -import ( - "testing" - - "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" -) - -// providerFactories are used to instantiate a provider during acceptance testing. -// The factory function will be invoked for every Terraform CLI command executed -// to create a provider server to which the CLI can reattach. -var providerFactories = map[string]func() (*schema.Provider, error){ - "scaffolding": func() (*schema.Provider, error) { - return New(), nil - }, -} - -func TestProvider(t *testing.T) { - if err := New().InternalValidate(); err != nil { - t.Fatalf("err: %s", err) - } -} - -func testAccPreCheck(t *testing.T) { - // You can add code here to run prior to any test case execution, for example assertions - // about the appropriate environment variables being set are common to see in a pre-check - // function. -} diff --git a/internal/provider/resource_scaffolding.go b/internal/provider/resource_scaffolding.go deleted file mode 100644 index 616c6fd..0000000 --- a/internal/provider/resource_scaffolding.go +++ /dev/null @@ -1,49 +0,0 @@ -package provider - -import ( - "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" -) - -func resourceScaffolding() *schema.Resource { - return &schema.Resource{ - Create: resourceScaffoldingCreate, - Read: resourceScaffoldingRead, - Update: resourceScaffoldingUpdate, - Delete: resourceScaffoldingDelete, - - Schema: map[string]*schema.Schema{ - "sample_attribute": { - Type: schema.TypeString, - Optional: true, - }, - }, - } -} - -func resourceScaffoldingCreate(d *schema.ResourceData, meta interface{}) error { - // use the meta value to retrieve your client from the provider configure method - // client := meta.(*apiClient) - - return nil -} - -func resourceScaffoldingRead(d *schema.ResourceData, meta interface{}) error { - // use the meta value to retrieve your client from the provider configure method - // client := meta.(*apiClient) - - return nil -} - -func resourceScaffoldingUpdate(d *schema.ResourceData, meta interface{}) error { - // use the meta value to retrieve your client from the provider configure method - // client := meta.(*apiClient) - - return nil -} - -func resourceScaffoldingDelete(d *schema.ResourceData, meta interface{}) error { - // use the meta value to retrieve your client from the provider configure method - // client := meta.(*apiClient) - - return nil -} diff --git a/internal/provider/resource_scaffolding_test.go b/internal/provider/resource_scaffolding_test.go deleted file mode 100644 index febadc3..0000000 --- a/internal/provider/resource_scaffolding_test.go +++ /dev/null @@ -1,30 +0,0 @@ -package provider - -import ( - "regexp" - "testing" - - "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" -) - -func TestAccResourceScaffolding(t *testing.T) { - resource.UnitTest(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - ProviderFactories: providerFactories, - Steps: []resource.TestStep{ - { - Config: testAccResourceScaffolding, - Check: resource.ComposeTestCheckFunc( - resource.TestMatchResourceAttr( - "scaffolding_resource.foo", "sample_attribute", regexp.MustCompile("^ba")), - ), - }, - }, - }) -} - -const testAccResourceScaffolding = ` -resource "scaffolding_resource" "foo" { - sample_attribute = "bar" -} -` diff --git a/internal/provider/server.go b/internal/provider/server.go new file mode 100644 index 0000000..6a9f635 --- /dev/null +++ b/internal/provider/server.go @@ -0,0 +1,315 @@ +package provider + +import ( + "context" + "database/sql" + "fmt" + "math/big" + "os" + + "github.com/hashicorp/terraform-plugin-go/tfprotov5" + "github.com/hashicorp/terraform-plugin-go/tfprotov5/tftypes" +) + +type provider struct { + db *db +} + +func (p *provider) Schema(context.Context) *tfprotov5.Schema { + return &tfprotov5.Schema{ + Block: &tfprotov5.SchemaBlock{ + Attributes: []*tfprotov5.SchemaAttribute{ + { + Name: "url", + Optional: true, + Computed: true, + Description: "Database connection strings are specified via URLs. The URL format is driver dependent " + + "but generally has the form: `dbdriver://username:password@host:port/dbname?param1=true¶m2=false`. " + + "You can optionally set the `SQL_URL` environment variable instead.", + DescriptionKind: tfprotov5.StringKindMarkdown, + Type: tftypes.String, + }, + { + Name: "max_open_conns", + Optional: true, + Description: "Sets the maximum number of open connections to the database. Default is `0` (unlimited). " + + "See Go's documentation on [DB.SetMaxOpenConns](https://golang.org/pkg/database/sql/#DB.SetMaxOpenConns).", + DescriptionKind: tfprotov5.StringKindMarkdown, + Type: tftypes.Number, + }, + { + Name: "max_idle_conns", + Optional: true, + Description: "Sets the maximum number of connections in the idle connection pool. Default is `2`. " + + "See Go's documentation on [DB.SetMaxIdleConns](https://golang.org/pkg/database/sql/#DB.SetMaxIdleConns).", + DescriptionKind: tfprotov5.StringKindMarkdown, + Type: tftypes.Number, + }, + }, + }, + } +} + +type dataSource interface { + Schema(context.Context) *tfprotov5.Schema + Validate(context.Context, map[string]tftypes.Value) ([]*tfprotov5.Diagnostic, error) + Read(context.Context, map[string]tftypes.Value) (map[string]tftypes.Value, []*tfprotov5.Diagnostic, error) +} + +func (p *provider) NewDataSource(typeName string) (dataSource, error) { + switch typeName { + case "sql_query": + return &dataQuery{ + p: p, + }, nil + } + return nil, fmt.Errorf("unexpected data source type %q", typeName) +} + +func New(version string) func() tfprotov5.ProviderServer { + return func() tfprotov5.ProviderServer { + return &provider{} + } +} + +// ProviderServer methods + +func (p *provider) GetProviderSchema(ctx context.Context, req *tfprotov5.GetProviderSchemaRequest) (*tfprotov5.GetProviderSchemaResponse, error) { + resp := &tfprotov5.GetProviderSchemaResponse{ + Provider: p.Schema(ctx), + DataSourceSchemas: map[string]*tfprotov5.Schema{}, + ResourceSchemas: map[string]*tfprotov5.Schema{}, + } + + for _, typeName := range []string{"sql_query"} { + ds, err := p.NewDataSource(typeName) + if err != nil { + // TODO: diags? + return nil, err + } + resp.DataSourceSchemas[typeName] = ds.Schema(ctx) + } + + // TODO: resources + + return resp, nil +} + +func (p *provider) PrepareProviderConfig(ctx context.Context, req *tfprotov5.PrepareProviderConfigRequest) (*tfprotov5.PrepareProviderConfigResponse, error) { + // TODO: default handling? + // TODO: validate URL value + return &tfprotov5.PrepareProviderConfigResponse{ + PreparedConfig: req.Config, + }, nil +} + +func (p *provider) ConfigureProvider(ctx context.Context, req *tfprotov5.ConfigureProviderRequest) (*tfprotov5.ConfigureProviderResponse, error) { + if p.db != nil { + // if reconfiguring, close existing connection + p.db.Close() + } + + schemaObjectType := schemaAsObject(p.Schema(ctx)) + + configObject, err := req.Config.Unmarshal(schemaObjectType) + if err != nil { + return nil, fmt.Errorf("error req.Config.Unmarshal: %w", err) + } + + config := map[string]tftypes.Value{} + err = configObject.As(&config) + if err != nil { + return nil, fmt.Errorf("error configObject.As: %w", err) + } + + var ( + url string + maxOpenConns *big.Float + maxIdleConns *big.Float + ) + if v := config["url"]; v.IsNull() { + url = os.Getenv("SQL_URL") + } else { + err = config["url"].As(&url) + if err != nil { + // TODO: diag with path + return nil, fmt.Errorf("unable to read url: %w", err) + } + } + + if url == "" { + diags := []*tfprotov5.Diagnostic{ + { + Severity: tfprotov5.DiagnosticSeverityError, + Attribute: &tftypes.AttributePath{Steps: []tftypes.AttributePathStep{ + tftypes.AttributeName("url"), + }}, + Summary: "A `url` is required to connect to your database.", + }, + } + return &tfprotov5.ConfigureProviderResponse{ + Diagnostics: diags, + }, nil + } + + if v := config["max_open_conns"]; v.IsNull() { + maxOpenConns = big.NewFloat(float64(0)) + } else { + maxOpenConns = &big.Float{} + err = config["max_open_conns"].As(&maxOpenConns) + if err != nil { + // TODO: diag with path + return nil, fmt.Errorf("unable to read max_open_conns: %w", err) + } + } + + if v := config["max_idle_conns"]; v.IsNull() { + maxIdleConns = big.NewFloat(float64(2)) + } else { + maxIdleConns = &big.Float{} + err = v.As(&maxIdleConns) + if err != nil { + // TODO: diag with path + return nil, fmt.Errorf("unable to read max_idle_conns: %w", err) + } + } + + p.db, err = newDB(url, func(db *sql.DB) error { + maxOpen, acc := maxOpenConns.Int64() + if acc != big.Exact { + return fmt.Errorf("results for max_open_conns is not exact") + } + + maxIdle, acc := maxIdleConns.Int64() + if acc != big.Exact { + return fmt.Errorf("results for max_open_conns is not exact") + } + + db.SetMaxOpenConns(int(maxOpen)) + db.SetMaxIdleConns(int(maxIdle)) + return nil + }) + if err != nil { + return nil, fmt.Errorf("unable to open database: %w", err) + } + + err = p.db.PingContext(ctx) + if err != nil { + return nil, fmt.Errorf("unable to ping database: %w", err) + } + + return &tfprotov5.ConfigureProviderResponse{}, nil +} + +func (p *provider) StopProvider(ctx context.Context, req *tfprotov5.StopProviderRequest) (*tfprotov5.StopProviderResponse, error) { + // TODO: close/reopen? db connection + panic("not implemented") +} + +// ResourceServer methods + +func (p *provider) ValidateResourceTypeConfig(ctx context.Context, req *tfprotov5.ValidateResourceTypeConfigRequest) (*tfprotov5.ValidateResourceTypeConfigResponse, error) { + panic("not implemented") +} + +func (p *provider) UpgradeResourceState(ctx context.Context, req *tfprotov5.UpgradeResourceStateRequest) (*tfprotov5.UpgradeResourceStateResponse, error) { + panic("not implemented") +} + +func (p *provider) ReadResource(ctx context.Context, req *tfprotov5.ReadResourceRequest) (*tfprotov5.ReadResourceResponse, error) { + panic("not implemented") +} + +func (p *provider) PlanResourceChange(ctx context.Context, req *tfprotov5.PlanResourceChangeRequest) (*tfprotov5.PlanResourceChangeResponse, error) { + panic("not implemented") +} + +func (p *provider) ApplyResourceChange(ctx context.Context, req *tfprotov5.ApplyResourceChangeRequest) (*tfprotov5.ApplyResourceChangeResponse, error) { + panic("not implemented") +} + +func (p *provider) ImportResourceState(ctx context.Context, req *tfprotov5.ImportResourceStateRequest) (*tfprotov5.ImportResourceStateResponse, error) { + panic("not implemented") +} + +// DataSourceServer methods + +func (p *provider) ValidateDataSourceConfig(ctx context.Context, req *tfprotov5.ValidateDataSourceConfigRequest) (*tfprotov5.ValidateDataSourceConfigResponse, error) { + ds, err := p.NewDataSource(req.TypeName) + if err != nil { + // TODO: diags? + return nil, err + } + + schemaObjectType := schemaAsObject(ds.Schema(ctx)) + + configObject, err := req.Config.Unmarshal(schemaObjectType) + if err != nil { + return nil, fmt.Errorf("error req.Config.Unmarshal: %w", err) + } + + config := map[string]tftypes.Value{} + err = configObject.As(&config) + if err != nil { + return nil, fmt.Errorf("error configObject.As: %w", err) + } + + diags, err := ds.Validate(ctx, config) + if err != nil { + return nil, err + } + return &tfprotov5.ValidateDataSourceConfigResponse{ + Diagnostics: diags, + }, nil +} + +func (p *provider) ReadDataSource(ctx context.Context, req *tfprotov5.ReadDataSourceRequest) (*tfprotov5.ReadDataSourceResponse, error) { + ds, err := p.NewDataSource(req.TypeName) + if err != nil { + // TODO: diags? + return nil, err + } + + schemaObjectType := schemaAsObject(ds.Schema(ctx)) + + configObject, err := req.Config.Unmarshal(schemaObjectType) + if err != nil { + return nil, fmt.Errorf("error req.Config.Unmarshal: %w", err) + } + + config := map[string]tftypes.Value{} + err = configObject.As(&config) + if err != nil { + return nil, fmt.Errorf("error configObject.As: %w", err) + } + + diags, err := ds.Validate(ctx, config) + if err != nil { + return nil, fmt.Errorf("error ds.Validate: %w", err) + } + if diagsHaveError(diags) { + return &tfprotov5.ReadDataSourceResponse{ + Diagnostics: diags, + }, nil + } + state, diags, err := ds.Read(ctx, config) + if err != nil { + return nil, fmt.Errorf("error ds.Read: %w", err) + } + if diagsHaveError(diags) { + return &tfprotov5.ReadDataSourceResponse{ + Diagnostics: diags, + }, nil + } + + // TODO: should NewDynamicValue return a pointer? + stateObject, err := tfprotov5.NewDynamicValue(schemaObjectType, tftypes.NewValue(schemaObjectType, state)) + if err != nil { + return nil, fmt.Errorf("error NewDynamicValue: %w", err) + } + + return &tfprotov5.ReadDataSourceResponse{ + State: &stateObject, + Diagnostics: diags, + }, nil +} diff --git a/internal/provider/server_test.go b/internal/provider/server_test.go new file mode 100644 index 0000000..dd3537d --- /dev/null +++ b/internal/provider/server_test.go @@ -0,0 +1,151 @@ +package provider + +import ( + "fmt" + "log" + "os" + "testing" + "time" + + "github.com/ory/dockertest" + "golang.org/x/sync/errgroup" +) + +var testURLs = map[string]string{} + +var defaultTestFactories = map[string]func(pool *dockertest.Pool) (*dockertest.Resource, func() string, error){ + "mysql": startMySQL, + "postgres": startPostgres, + "cockroach": startCockroach, + "sqlserver": startSQLServer, +} + +func TestMain(m *testing.M) { + code := runTestMain(m) + os.Exit(code) +} + +func runTestMain(m *testing.M) int { + // TODO: move this to sync.once style setup to better support -short + + // uses a sensible default on windows (tcp/http) and linux/osx (socket) + pool, err := dockertest.NewPool("npipe:////./pipe/docker_engine") + if err != nil { + log.Fatalf("could not connect to docker: %s", err) + } + + pool.MaxWait = 2 * time.Minute + + eg := &errgroup.Group{} + + for k, factory := range defaultTestFactories { + r, urlF, err := factory(pool) + if err != nil { + log.Printf("unable to start container %q: %s", k, err) + return -1 + } + defer pool.Purge(r) + + // set a hard expiry on the container for 10 minutes + err = r.Expire(10 * 60) + if err != nil { + log.Printf("unable to set hard expiration: %s", err) + // do not exit here, just log the issue + } + + eg.Go(func() error { + if err := pool.Retry(func() error { + url := urlF() + testURLs[k] = url + + db, err := newDB(url, nil) + if err != nil { + return err + } + defer db.Close() + + err = db.Ping() + if err != nil { + return err + } + + return nil + }); err != nil { + return fmt.Errorf("timeout waiting for ping for %q: %w", k, err) + } + + return nil + }) + } + + err = eg.Wait() + if err != nil { + log.Printf("Error starting databases: %s", err) + return -1 + } + + return m.Run() +} + +func startMySQL(pool *dockertest.Pool) (*dockertest.Resource, func() string, error) { + resource, err := pool.Run("mysql", "8", []string{ + "MYSQL_ROOT_PASSWORD=tf", + }) + if err != nil { + return nil, nil, err + } + + return resource, func() string { + // TODO: automatically set parseTime here? + return fmt.Sprintf("mysql://root:tf@tcp(localhost:%s)/mysql?parseTime=true", resource.GetPort("3306/tcp")) + }, nil +} + +func startPostgres(pool *dockertest.Pool) (*dockertest.Resource, func() string, error) { + databaseName := "tftest" + resource, err := pool.Run("postgres", "13", []string{ + "POSTGRES_PASSWORD=tf", + "POSTGRES_DB=" + databaseName, + "TZ=UTC", + }) + if err != nil { + return nil, nil, err + } + + return resource, func() string { + return fmt.Sprintf("postgres://postgres:tf@localhost:%s/%s?sslmode=disable", resource.GetPort("5432/tcp"), databaseName) + }, nil +} + +func startCockroach(pool *dockertest.Pool) (*dockertest.Resource, func() string, error) { + resource, err := pool.RunWithOptions(&dockertest.RunOptions{ + Repository: "cockroachdb/cockroach", + Tag: "v20.2.0", + Cmd: []string{ + "start-single-node", + "--insecure", + }, + }) + if err != nil { + return nil, nil, err + } + + return resource, func() string { + return fmt.Sprintf("postgres://root@localhost:%s/events?sslmode=disable", resource.GetPort("26257/tcp")) + }, nil +} + +func startSQLServer(pool *dockertest.Pool) (*dockertest.Resource, func() string, error) { + password := "TF-8chars" + resource, err := pool.Run("mcr.microsoft.com/mssql/server", "2017-latest", []string{ + "ACCEPT_EULA=y", + "SA_PASSWORD=" + password, + }) + if err != nil { + return nil, nil, err + } + + return resource, func() string { + return fmt.Sprintf("sqlserver://sa:%s@localhost:%s", password, resource.GetPort("1433/tcp")) + }, nil +} diff --git a/internal/provider/sqlserver.go b/internal/provider/sqlserver.go new file mode 100644 index 0000000..81cb3fd --- /dev/null +++ b/internal/provider/sqlserver.go @@ -0,0 +1,61 @@ +package provider + +import ( + "encoding/hex" + "errors" + "fmt" +) + +type sqlServerUniqueIdentifier [16]byte + +func (u *sqlServerUniqueIdentifier) Scan(v interface{}) error { + reverse := func(b []byte) { + for i, j := 0, len(b)-1; i < j; i, j = i+1, j-1 { + b[i], b[j] = b[j], b[i] + } + } + + switch vt := v.(type) { + case []byte: + if len(vt) != 16 { + return errors.New("mssql: invalid sqlServerUniqueIdentifier length") + } + + var raw sqlServerUniqueIdentifier + + copy(raw[:], vt) + + reverse(raw[0:4]) + reverse(raw[4:6]) + reverse(raw[6:8]) + *u = raw + + return nil + case string: + if len(vt) != 36 { + return errors.New("mssql: invalid sqlServerUniqueIdentifier string length") + } + + b := []byte(vt) + for i, c := range b { + switch c { + case '-': + b = append(b[:i], b[i+1:]...) + } + } + + _, err := hex.Decode(u[:], []byte(b)) + return err + default: + return fmt.Errorf("mssql: cannot convert %T to sqlServerUniqueIdentifier", v) + } +} + +func (u *sqlServerUniqueIdentifier) ToTerraform5Value() (interface{}, error) { + if u == nil { + return nil, nil + } + + s := fmt.Sprintf("%X-%X-%X-%X-%X", u[0:4], u[4:6], u[6:8], u[8:10], u[10:]) + return &s, nil +} diff --git a/internal/provider/time.go b/internal/provider/time.go new file mode 100644 index 0000000..1b4da2f --- /dev/null +++ b/internal/provider/time.go @@ -0,0 +1,31 @@ +package provider + +import ( + "fmt" + "reflect" + "time" +) + +type tfTime struct { + time.Time +} + +var tfTimeType = reflect.TypeOf((*tfTime)(nil)).Elem() + +func (tf *tfTime) Scan(src interface{}) error { + t, ok := src.(time.Time) + if !ok { + return fmt.Errorf("expected time.Time, got %T", src) + } + tf.Time = t + return nil +} + +func (tf *tfTime) ToTerraform5Value() (interface{}, error) { + if tf == nil { + return nil, nil + } + + s := tf.Format(time.RFC3339) + return &s, nil +} diff --git a/internal/provider/util.go b/internal/provider/util.go new file mode 100644 index 0000000..c9b2c72 --- /dev/null +++ b/internal/provider/util.go @@ -0,0 +1,54 @@ +package provider + +import ( + "fmt" + + "github.com/hashicorp/terraform-plugin-go/tfprotov5" + "github.com/hashicorp/terraform-plugin-go/tfprotov5/tftypes" +) + +func unquoteIfQuoted(value interface{}) (string, error) { + var bytes []byte + + switch v := value.(type) { + case string: + bytes = []byte(v) + case []byte: + bytes = v + default: + return "", fmt.Errorf("could not convert value '%+v' to byte array of type '%T'", + value, value) + } + + // If the amount is quoted, strip the quotes + if len(bytes) > 2 && bytes[0] == '"' && bytes[len(bytes)-1] == '"' { + bytes = bytes[1 : len(bytes)-1] + } + return string(bytes), nil +} + +// potential terraform-plugin-go convenience funcs + +func diagsHaveError(diags []*tfprotov5.Diagnostic) bool { + for _, diag := range diags { + if diag != nil && diag.Severity == tfprotov5.DiagnosticSeverityError { + return true + } + } + + return false +} + +func schemaAsObject(schema *tfprotov5.Schema) tftypes.Object { + o := tftypes.Object{ + AttributeTypes: map[string]tftypes.Type{}, + } + + // TODO: block types + + for _, s := range schema.Block.Attributes { + o.AttributeTypes[s.Name] = s.Type + } + + return o +} diff --git a/main.go b/main.go index 219a41f..577658b 100644 --- a/main.go +++ b/main.go @@ -1,10 +1,23 @@ package main import ( - "github.com/hashicorp/terraform-plugin-sdk/v2/plugin" - "github.com/hashicorp/terraform-provider-scaffolding/internal/provider" + "context" + "encoding/json" + "flag" + "fmt" + "os" + "runtime" + "strings" + + "github.com/hashicorp/go-plugin" + server "github.com/hashicorp/terraform-plugin-go/tfprotov5/server" + + "github.com/paultyng/terraform-provider-sql/internal/provider" ) +// Generate docs for website +//go:generate go run github.com/hashicorp/terraform-plugin-docs/cmd/tfplugindocs + var ( // these will be set by the goreleaser configuration // to appropriate values for the compiled binary @@ -14,6 +27,89 @@ var ( // commit string = "" ) +const ( + providerAddr = "registry.terraform.io/paultyng/sql" +) + func main() { - plugin.Serve(&plugin.ServeOpts{ProviderFunc: provider.New(version)}) + var debugMode bool + + flag.BoolVar(&debugMode, "debug", false, "set to true to run the provider with support for debuggers like delve") + flag.Parse() + + ctx := context.Background() + opts := []server.ServeOpt{} + close := make(chan struct{}) + + if debugMode { + reattach := make(chan *plugin.ReattachConfig) + + go func() { + for { + select { + case conf := <-reattach: + reattachBytes, err := json.Marshal(map[string]struct { + Protocol string + Pid int + Test bool + Addr struct { + Network string + String string + } + }{ + providerAddr: { + Protocol: string(conf.Protocol), + Pid: conf.Pid, + Test: conf.Test, + Addr: struct { + Network string + String string + }{ + Network: conf.Addr.Network(), + String: conf.Addr.String(), + }, + }, + }) + if err != nil { + panic(fmt.Sprintf("Error building reattach string: %s", err)) + } + + reattachStr := string(reattachBytes) + + fmt.Printf("Provider started, to attach Terraform set the TF_REATTACH_PROVIDERS env var:\n\n") + switch runtime.GOOS { + case "windows": + fmt.Printf("\tCommand Prompt:\tset \"TF_REATTACH_PROVIDERS=%s\"\n", reattachStr) + fmt.Printf("\tPowerShell:\t$env:TF_REATTACH_PROVIDERS='%s'\n", strings.ReplaceAll(reattachStr, `'`, `''`)) + case "linux", "darwin": + fmt.Printf("\tTF_REATTACH_PROVIDERS='%s'\n", strings.ReplaceAll(reattachStr, `'`, `'"'"'`)) + default: + fmt.Println(reattachStr) + } + fmt.Println("") + case <-close: + case <-ctx.Done(): + } + } + }() + + opts = append(opts, server.WithDebug(ctx, reattach, close)) + } + + var err error + go func() { + err = server.Serve(providerAddr, provider.New(version), opts...) + }() + + select { + case <-close: + case <-ctx.Done(): + } + if err == nil { + err = ctx.Err() + } + if err != nil { + fmt.Println(err) + os.Exit(1) + } } diff --git a/tools/tools.go b/tools/tools.go new file mode 100644 index 0000000..2735de6 --- /dev/null +++ b/tools/tools.go @@ -0,0 +1,7 @@ +// +build tools + +package tools + +import ( + _ "github.com/hashicorp/terraform-plugin-docs/cmd/tfplugindocs" +) diff --git a/website/docs/d/scaffolding_data_source.html.markdown b/website/docs/d/scaffolding_data_source.html.markdown deleted file mode 100644 index 6ebe207..0000000 --- a/website/docs/d/scaffolding_data_source.html.markdown +++ /dev/null @@ -1,23 +0,0 @@ ---- -layout: "scaffolding" -page_title: "Scaffolding: scaffolding_data_source" -sidebar_current: "docs-scaffolding-data-source" -description: |- - Sample data source in the Terraform provider scaffolding. ---- - -# scaffolding_data_source - -Sample data source in the Terraform provider scaffolding. - -## Example Usage - -```hcl -data "scaffolding_data_source" "example" { - sample_attribute = "foo" -} -``` - -## Attributes Reference - -* `sample_attribute` - Sample attribute. diff --git a/website/docs/index.html.markdown b/website/docs/index.html.markdown deleted file mode 100644 index e5ec946..0000000 --- a/website/docs/index.html.markdown +++ /dev/null @@ -1,25 +0,0 @@ ---- -layout: "scaffolding" -page_title: "Provider: Scaffolding" -sidebar_current: "docs-scaffolding-index" -description: |- - Terraform provider scaffolding. ---- - -# Scaffolding Provider - -Use this paragraph to give a high-level overview of your provider, and any configuration it requires. - -Use the navigation to the left to read about the available resources. - -## Example Usage - -```hcl -provider "scaffolding" { -} - -# Example resource configuration -resource "scaffolding_resource" "example" { - # ... -} -``` diff --git a/website/docs/r/scaffolding_resource.html.markdown b/website/docs/r/scaffolding_resource.html.markdown deleted file mode 100644 index be95927..0000000 --- a/website/docs/r/scaffolding_resource.html.markdown +++ /dev/null @@ -1,26 +0,0 @@ ---- -layout: "scaffolding" -page_title: "Scaffolding: scaffolding_resource" -sidebar_current: "docs-scaffolding-resource" -description: |- - Sample resource in the Terraform provider scaffolding. ---- - -# scaffolding_resource - -Sample resource in the Terraform provider scaffolding. - -## Example Usage - -```hcl -resource "scaffolding_resource" "example" { - sample_attribute = "foo" -} -``` - -## Argument Reference - -The following arguments are supported: - -* `sample_attribute` - Sample attribute. -