diff --git a/.travis.yml b/.travis.yml index 709826d..a8079af 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,14 +1,9 @@ language: go go: - - "1.10" + - "1.12" env: - - DEP_VERSION="0.4.1" -before_install: - - curl -L -s https://github.com/golang/dep/releases/download/v${DEP_VERSION}/dep-linux-amd64 -o $GOPATH/bin/dep - - chmod +x $GOPATH/bin/dep - - go get golang.org/x/tools/cmd/goimports + - GO111MODULE=on script: - - dep ensure - make test - make clean - make diff --git a/Gopkg.lock b/Gopkg.lock deleted file mode 100644 index 5960747..0000000 --- a/Gopkg.lock +++ /dev/null @@ -1,446 +0,0 @@ -# This file is autogenerated, do not edit; changes may be undone by the next 'dep ensure'. - - -[[projects]] - name = "github.com/agext/levenshtein" - packages = ["."] - revision = "5f10fee965225ac1eecdc234c09daf5cd9e7f7b6" - version = "v1.2.1" - -[[projects]] - branch = "master" - name = "github.com/apparentlymart/go-cidr" - packages = ["cidr"] - revision = "2bd8b58cf4275aeb086ade613de226773e29e853" - -[[projects]] - branch = "master" - name = "github.com/apparentlymart/go-textseg" - packages = ["textseg"] - revision = "b836f5c4d331d1945a2fead7188db25432d73b69" - -[[projects]] - branch = "master" - name = "github.com/armon/go-radix" - packages = ["."] - revision = "1fca145dffbcaa8fe914309b1ec0cfc67500fe61" - -[[projects]] - name = "github.com/aws/aws-sdk-go" - packages = [ - "aws", - "aws/awserr", - "aws/awsutil", - "aws/client", - "aws/client/metadata", - "aws/corehandlers", - "aws/credentials", - "aws/credentials/ec2rolecreds", - "aws/credentials/endpointcreds", - "aws/credentials/stscreds", - "aws/defaults", - "aws/ec2metadata", - "aws/endpoints", - "aws/request", - "aws/session", - "aws/signer/v4", - "internal/sdkio", - "internal/sdkrand", - "internal/shareddefaults", - "private/protocol", - "private/protocol/query", - "private/protocol/query/queryutil", - "private/protocol/rest", - "private/protocol/restxml", - "private/protocol/xml/xmlutil", - "service/s3", - "service/sts" - ] - revision = "398d14696895d68a3409bb3ccb1cfe8abc2d4376" - version = "v1.13.57" - -[[projects]] - branch = "master" - name = "github.com/bgentry/go-netrc" - packages = ["netrc"] - revision = "9fd32a8b3d3d3f9d43c341bfe098430e07609480" - -[[projects]] - name = "github.com/bgentry/speakeasy" - packages = ["."] - revision = "4aabc24848ce5fd31929f7d1e4ea74d3709c14cd" - version = "v0.1.0" - -[[projects]] - name = "github.com/blang/semver" - packages = ["."] - revision = "2ee87856327ba09384cabd113bc6b5d174e9ec0f" - version = "v3.5.1" - -[[projects]] - name = "github.com/fatih/color" - packages = ["."] - revision = "5b77d2a35fb0ede96d138fc9a99f5c9b6aef11b4" - version = "v1.7.0" - -[[projects]] - name = "github.com/go-ini/ini" - packages = ["."] - revision = "06f5f3d67269ccec1fe5fe4134ba6e982984f7f5" - version = "v1.37.0" - -[[projects]] - name = "github.com/golang/protobuf" - packages = [ - "proto", - "ptypes", - "ptypes/any", - "ptypes/duration", - "ptypes/timestamp" - ] - revision = "b4deda0973fb4c70b50d226b1af49f3da59f5265" - version = "v1.1.0" - -[[projects]] - branch = "master" - name = "github.com/hashicorp/errwrap" - packages = ["."] - revision = "7554cd9344cec97297fa6649b055a8c98c2a1e55" - -[[projects]] - branch = "master" - name = "github.com/hashicorp/go-cleanhttp" - packages = ["."] - revision = "d5fe4b57a186c716b0e00b8c301cbd9b4182694d" - -[[projects]] - branch = "master" - name = "github.com/hashicorp/go-getter" - packages = [ - ".", - "helper/url" - ] - revision = "3f60ec5cfbb2a39731571b9ddae54b303bb0a969" - -[[projects]] - branch = "master" - name = "github.com/hashicorp/go-hclog" - packages = ["."] - revision = "69ff559dc25f3b435631604f573a5fa1efdb6433" - -[[projects]] - branch = "master" - name = "github.com/hashicorp/go-multierror" - packages = ["."] - revision = "b7773ae218740a7be65057fc60b366a49b538a44" - -[[projects]] - branch = "master" - name = "github.com/hashicorp/go-plugin" - packages = ["."] - revision = "e8d22c780116115ae5624720c9af0c97afe4f551" - -[[projects]] - branch = "master" - name = "github.com/hashicorp/go-safetemp" - packages = ["."] - revision = "b1a1dbde6fdc11e3ae79efd9039009e22d4ae240" - -[[projects]] - branch = "master" - name = "github.com/hashicorp/go-uuid" - packages = ["."] - revision = "27454136f0364f2d44b1276c552d69105cf8c498" - -[[projects]] - branch = "master" - name = "github.com/hashicorp/go-version" - packages = ["."] - revision = "23480c0665776210b5fbbac6eaaee40e3e6a96b7" - -[[projects]] - branch = "master" - name = "github.com/hashicorp/hcl" - packages = [ - ".", - "hcl/ast", - "hcl/parser", - "hcl/scanner", - "hcl/strconv", - "hcl/token", - "json/parser", - "json/scanner", - "json/token" - ] - revision = "ef8a98b0bbce4a65b5aa4c368430a80ddc533168" - -[[projects]] - branch = "master" - name = "github.com/hashicorp/hcl2" - packages = [ - "gohcl", - "hcl", - "hcl/hclsyntax", - "hcl/json", - "hcldec", - "hclparse" - ] - revision = "36446359d27574bf110611001414da561731b62d" - -[[projects]] - branch = "master" - name = "github.com/hashicorp/hil" - packages = [ - ".", - "ast", - "parser", - "scanner" - ] - revision = "fa9f258a92500514cc8e9c67020487709df92432" - -[[projects]] - name = "github.com/hashicorp/terraform" - packages = [ - "config", - "config/configschema", - "config/hcl2shim", - "config/module", - "dag", - "flatmap", - "helper/hashcode", - "helper/hilmapstructure", - "helper/schema", - "httpclient", - "moduledeps", - "plugin", - "plugin/discovery", - "registry", - "registry/regsrc", - "registry/response", - "svchost", - "svchost/auth", - "svchost/disco", - "terraform", - "tfdiags", - "version" - ] - revision = "41e50bd32a8825a84535e353c3674af8ce799161" - version = "v0.11.7" - -[[projects]] - branch = "master" - name = "github.com/hashicorp/yamux" - packages = ["."] - revision = "2658be15c5f05e76244154714161f17e3e77de2e" - -[[projects]] - name = "github.com/jmespath/go-jmespath" - packages = ["."] - revision = "0b12d6b5" - -[[projects]] - name = "github.com/mattn/go-colorable" - packages = ["."] - revision = "167de6bfdfba052fa6b2d3664c8f5272e23c9072" - version = "v0.0.9" - -[[projects]] - name = "github.com/mattn/go-isatty" - packages = ["."] - revision = "0360b2af4f38e8d38c7fce2a9f4e702702d73a39" - version = "v0.0.3" - -[[projects]] - branch = "master" - name = "github.com/mitchellh/cli" - packages = ["."] - revision = "c48282d14eba4b0817ddef3f832ff8d13851aefd" - -[[projects]] - branch = "master" - name = "github.com/mitchellh/copystructure" - packages = ["."] - revision = "d23ffcb85de31694d6ccaa23ccb4a03e55c1303f" - -[[projects]] - branch = "master" - name = "github.com/mitchellh/go-homedir" - packages = ["."] - revision = "3864e76763d94a6df2f9960b16a20a33da9f9a66" - -[[projects]] - branch = "master" - name = "github.com/mitchellh/go-testing-interface" - packages = ["."] - revision = "a61a99592b77c9ba629d254a693acffaeb4b7e28" - -[[projects]] - branch = "master" - name = "github.com/mitchellh/go-wordwrap" - packages = ["."] - revision = "ad45545899c7b13c020ea92b2072220eefad42b8" - -[[projects]] - branch = "master" - name = "github.com/mitchellh/hashstructure" - packages = ["."] - revision = "2bca23e0e452137f789efbc8610126fd8b94f73b" - -[[projects]] - branch = "master" - name = "github.com/mitchellh/mapstructure" - packages = ["."] - revision = "bb74f1db0675b241733089d5a1faa5dd8b0ef57b" - -[[projects]] - branch = "master" - name = "github.com/mitchellh/reflectwalk" - packages = ["."] - revision = "63d60e9d0dbc60cf9164e6510889b0db6683d98c" - -[[projects]] - name = "github.com/oklog/run" - packages = ["."] - revision = "4dadeb3030eda0273a12382bb2348ffc7c9d1a39" - version = "v1.0.0" - -[[projects]] - name = "github.com/posener/complete" - packages = [ - ".", - "cmd", - "cmd/install", - "match" - ] - revision = "98eb9847f27ba2008d380a32c98be474dea55bdf" - version = "v1.1.1" - -[[projects]] - name = "github.com/ulikunitz/xz" - packages = [ - ".", - "internal/hash", - "internal/xlog", - "lzma" - ] - revision = "0c6b41e72360850ca4f98dc341fd999726ea007f" - version = "v0.5.4" - -[[projects]] - branch = "master" - name = "github.com/zclconf/go-cty" - packages = [ - "cty", - "cty/convert", - "cty/function", - "cty/function/stdlib", - "cty/gocty", - "cty/json", - "cty/set" - ] - revision = "ba988ce11d9994867838957d4c40bb1ad78b433d" - -[[projects]] - branch = "master" - name = "golang.org/x/crypto" - packages = [ - "bcrypt", - "blowfish", - "cast5", - "openpgp", - "openpgp/armor", - "openpgp/elgamal", - "openpgp/errors", - "openpgp/packet", - "openpgp/s2k" - ] - revision = "ab813273cd59e1333f7ae7bff5d027d4aadf528c" - -[[projects]] - branch = "master" - name = "golang.org/x/net" - packages = [ - "context", - "html", - "html/atom", - "http/httpguts", - "http2", - "http2/hpack", - "idna", - "internal/timeseries", - "trace" - ] - revision = "75944861c7512f64725d687546cfbc757626151f" - -[[projects]] - branch = "master" - name = "golang.org/x/sys" - packages = ["unix"] - revision = "c11f84a56e43e20a78cee75a7c034031ecf57d1f" - -[[projects]] - name = "golang.org/x/text" - packages = [ - "collate", - "collate/build", - "internal/colltab", - "internal/gen", - "internal/tag", - "internal/triegen", - "internal/ucd", - "language", - "secure/bidirule", - "transform", - "unicode/bidi", - "unicode/cldr", - "unicode/norm", - "unicode/rangetable" - ] - revision = "f21a4dfb5e38f5895301dc265a8def02365cc3d0" - version = "v0.3.0" - -[[projects]] - branch = "master" - name = "google.golang.org/genproto" - packages = ["googleapis/rpc/status"] - revision = "694d95ba50e67b2e363f3483057db5d4910c18f9" - -[[projects]] - name = "google.golang.org/grpc" - packages = [ - ".", - "balancer", - "balancer/base", - "balancer/roundrobin", - "channelz", - "codes", - "connectivity", - "credentials", - "encoding", - "encoding/proto", - "grpclb/grpc_lb_v1/messages", - "grpclog", - "health", - "health/grpc_health_v1", - "internal", - "keepalive", - "metadata", - "naming", - "peer", - "resolver", - "resolver/dns", - "resolver/passthrough", - "stats", - "status", - "tap", - "transport" - ] - revision = "41344da2231b913fa3d983840a57a6b1b7b631a1" - version = "v1.12.0" - -[solve-meta] - analyzer-name = "dep" - analyzer-version = 1 - inputs-digest = "879d7ff121747a45b54c6027deaa9455825cc4c073443dea0a5694019d12c917" - solver-name = "gps-cdcl" - solver-version = 1 diff --git a/Gopkg.toml b/Gopkg.toml deleted file mode 100644 index a58640c..0000000 --- a/Gopkg.toml +++ /dev/null @@ -1,34 +0,0 @@ -# Gopkg.toml example -# -# Refer to https://github.com/golang/dep/blob/master/docs/Gopkg.toml.md -# for detailed Gopkg.toml documentation. -# -# required = ["github.com/user/thing/cmd/thing"] -# ignored = ["github.com/user/project/pkgX", "bitbucket.org/user/project/pkgA/pkgY"] -# -# [[constraint]] -# name = "github.com/user/project" -# version = "1.0.0" -# -# [[constraint]] -# name = "github.com/user/project2" -# branch = "dev" -# source = "github.com/myfork/project2" -# -# [[override]] -# name = "github.com/x/y" -# version = "2.4.0" -# -# [prune] -# non-go = false -# go-tests = true -# unused-packages = true - - -[[constraint]] - name = "github.com/hashicorp/terraform" - version = "0.11.7" - -[prune] - go-tests = true - unused-packages = true diff --git a/Makefile b/Makefile index 754aa1c..c7a4ebf 100644 --- a/Makefile +++ b/Makefile @@ -1,6 +1,5 @@ # Adapted from https://github.com/alibaba/terraform-provider/blob/master/Makefile -GOFMT_FILES?=$$(find . -name '*.go' | grep -v vendor) VETARGS?=-all TEST?=$$(go list ./...) ifeq ($(OS),Windows_NT) @@ -24,26 +23,16 @@ ifndef TAG TAG := $(shell git describe --abbrev=0) endif -HASDEP := $(shell command -v dep 2> /dev/null) -HASGO := $(shell command -v go 2> /dev/null) HASZIP := $(shell command -v zip 2> /dev/null) all: build -dep: -ifndef HASGO - $(error "go is not available. Please install Go v1.9+") -endif -ifndef HASDEP - $(error "dep is not available. Please install https://golang.github.io/dep/docs/installation.html") -endif - dep ensure - build: mac windows linux install: $(os) copy-$(os) dev: clean fmt install + go mod tidy copy-mac: rm -f bin/terraform-provider-zerotier @@ -64,11 +53,11 @@ copy-windows: mv bin/terraform-provider-zerotier_$(TAG).exe "${APPDATA}/terraform.d/plugins/windows_amd64/" test: vet fmtcheck errcheck - TF_ACC=1 go test -v ./zerotier -run=TestAcczerotier -timeout=180m -parallel=4 + TF_ACC=1 go test -v -run=TestAcczerotier -timeout=180m -parallel=4 vet: - @echo "go tool vet $(VETARGS) ." - @go tool vet $(VETARGS) $$(ls -d */ | grep -v vendor) ; if [ $$? -eq 1 ]; then \ + @echo "go vet $(VETARGS) ." + @go vet $(VETARGS); if [ $$? -eq 1 ]; then \ echo ""; \ echo "Vet found suspicious constructs. Please check the reported constructs"; \ echo "and fix them if necessary before submitting the code for review."; \ @@ -76,8 +65,8 @@ vet: fi fmt: - gofmt -w $(GOFMT_FILES) - goimports -w $(GOFMT_FILES) + gofmt -s -w . + goimports -w . fmtcheck: @sh -c "'$(CURDIR)/scripts/gofmtcheck.sh'" @@ -88,21 +77,21 @@ errcheck: clean: rm -rf bin/* -mac: dep - GOOS=darwin GOARCH=amd64 go build -o bin/terraform-provider-zerotier_$(TAG) ./zerotier +mac: + GOOS=darwin GOARCH=amd64 go build -o bin/terraform-provider-zerotier_$(TAG) tar czvf bin/terraform-provider-zerotier_darwin-amd64_$(TAG).tgz bin/terraform-provider-zerotier_$(TAG) rm -rf bin/terraform-provider-zerotier_$(TAG) -windows: dep +windows: ifndef HASZIP $(error "zip is not available. If you're on windows, try `choco install zip`") endif - GOOS=windows GOARCH=amd64 go build -o bin/terraform-provider-zerotier_$(TAG).exe ./zerotier + GOOS=windows GOARCH=amd64 go build -o bin/terraform-provider-zerotier_$(TAG).exe zip bin/terraform-provider-zerotier_windows-amd64_$(TAG).zip bin/terraform-provider-zerotier_$(TAG).exe rm -rf bin/terraform-provider-zerotier_$(TAG).exe -linux: dep - GOOS=linux GOARCH=amd64 go build -o bin/terraform-provider-zerotier_$(TAG) ./zerotier +linux: + GOOS=linux GOARCH=amd64 go build -o bin/terraform-provider-zerotier_$(TAG) tar czvf bin/terraform-provider-zerotier_linux-amd64_$(TAG).tgz bin/terraform-provider-zerotier_$(TAG) rm -rf bin/terraform-provider-zerotier_$(TAG) diff --git a/README.md b/README.md index 8087fba..cbcb96b 100644 --- a/README.md +++ b/README.md @@ -25,17 +25,14 @@ don't fully describe where this is. ### Build using the Makefile -Install [Go](https://www.golang.org/) v1.9+ on your machine, and -[dep](https://golang.github.io/dep/docs/installation.html); clone the source, +Install [Go](https://www.golang.org/) v1.12+ on your machine, clone the source, and let `make install` do the rest. #### Mac ```sh brew install go # or upgrade -brew install dep # or upgrade -mkdir -p $GOPATH/src/github.com/cormacrelf; cd $GOPATH/src/github.com/cormacrelf -git clone https://github.com/cormacrelf/terraform-provider-zerotier +git clone https://github.com/cormacrelf/terraform-provider-zerotier cd terraform-provider-zerotier make install # it may take a while to download `hashicorp/terraform`. be patient. @@ -43,11 +40,10 @@ make install #### Linux -Install go and dep from your favourite package manager or from source. Then: +Install go 1.12+ from your favourite package manager or from source. Then: ```sh -mkdir -p $GOPATH/src/github.com/cormacrelf; cd $GOPATH/src/github.com/cormacrelf -git clone https://github.com/cormacrelf/terraform-provider-zerotier +git clone https://github.com/cormacrelf/terraform-provider-zerotier cd terraform-provider-zerotier make install # it may take a while to download `hashicorp/terraform`. be patient. @@ -59,7 +55,6 @@ In PowerShell, running as Administrator: ```powershell choco install golang -choco install dep choco install zip choco install git # for git-bash choco install make @@ -68,8 +63,7 @@ choco install make In a shell that has Make, like Git-Bash: ```sh -mkdir -p $GOPATH/src/github.com/cormacrelf; cd $GOPATH/src/github.com/cormacrelf -git clone https://github.com/cormacrelf/terraform-provider-zerotier +git clone https://github.com/cormacrelf/terraform-provider-zerotier cd terraform-provider-zerotier make install # it may take a while to download `hashicorp/terraform`. be patient. @@ -87,6 +81,11 @@ Use `export ZEROTIER_API_KEY="..."`, or define it in a provider block: ```hcl provider "zerotier" { api_key = "..." + + ## Optinal: Override for DIY controller + ## Could be overriden by ZEROTIER_CONTROLLER_URL env var or this block + ## Defaults to https://my.zerotier.com/api when not provided + # controller_url = "https://my.zerotier.com/api" } ``` @@ -115,6 +114,53 @@ resource "zerotier_network" "your_network" { If you don't specify either an assignment pool or a managed route, while it's perfectly valid, your network won't be very useful, so try to do both. +Full list of properties: + +```hcl +resource "zerotier_network" "your_network" { + name = "your_network_name" + + # Optional values + # description = "Managed by Terraform" + # rules_source = "Default rule pulled from ZeroTier" + + # private = true + + # Assign IPv4 addresses from the assignment_pool + # auto_assign_v4 = true + + # Effectively assign IPv6 RFC4193 (/128) for members of the network + # auto_assign_rfc4193 = true + + # Effectively assign IPv6 RFC4193 (/128) for members of the network + # auto_assign_6plane = false + + # Assing IPv6 addresses from the assignment_pool + # auto_assign_v6 = false + + # Multiple assignment pools allowed + # assignment_pool { + # cidr = "IPv4 or IPv6 CIDR notation" + # } + # assignment_pool { + # first = "IPv4 or IPv6 address" # eg 10.96.0.2 + # last = "IPv4 or IPv6 address" # eg 10.96.0.254 + # } + + # Multiple routes configuration allowed + # route { + # target = "${var.zt_cidr}" + # } + # route { + # target = "${var.other_network}" + # via = "${local.gateway_ip}" + # } + + # Computed + # id: Network ID +} +``` + #### Multiple routes You can have more than one assignment pool, and more than one route. Multiple @@ -252,6 +298,16 @@ resource "zerotier_member" "hector" { # see ZeroTier Manual section on L2/ethernet bridging allow_ethernet_bridging = true + # Computed properties available to interpolate + + # rfc4193_address + # Computed RFC4193 (IPv6 /128) address based on the network and node id + # Always calculated, and determined if they are used by the network resource + + # 6plane_address + # Computed 6PLANE (IPv6 /80) address based on the network and node id + # Always calculated, and determined if they are used by the network resource + } ``` @@ -542,3 +598,41 @@ Any other ec2 instances you want to access from your ZT network will need: * Ingress from your **gateway's security group** for whatever ports you want * Egress either everywhere or to gateway + +## Resource Importing + +Terraform [is able to import](https://www.terraform.io/docs/import/index.html) existing infrastructure. +This allows you take resources you've created by some other means and bring it under Terraform management. + +It is possible to import both networks and members state using this provider. +Currently, Terraform features can only import the state information, and you still need to write the resource definition before it is able to import. + +Given the following definition: + +```hcl +provider "zerotier" { + api_key = "..." +} + +resource "zerotier_network" "your_network" { + name = "your_network_name" +} + +resource "zerotier_member" "dev_machine" { + node_id = "..." + network_id = "${zerotier_network.your_network.id}" +} +``` + +You be able to import both the `network` and the `member` resources using the `terraform import` command. + +```sh +## Resource is identified by the network id by the API +terraform import zerotier_network.your_network ${NETWORK_ID} + +## Resource is identified by the network id and the node id by the API +terraform import zerotier_member.dev_machine "${NETWORK_ID}-${NODE_ID}" + +## Adjust the configuration until no change is planned +terraform plan +``` \ No newline at end of file diff --git a/go.mod b/go.mod new file mode 100644 index 0000000..0ce51f0 --- /dev/null +++ b/go.mod @@ -0,0 +1,24 @@ +module terraform-provider-zerotier + +go 1.12 + +require ( + github.com/apparentlymart/go-cidr v1.0.0 // indirect + github.com/blang/semver v3.5.1+incompatible // indirect + github.com/hashicorp/go-getter v1.2.0 // indirect + github.com/hashicorp/go-hclog v0.8.0 // indirect + github.com/hashicorp/go-plugin v0.0.0-20190220160451-3f118e8ee104 // indirect + github.com/hashicorp/go-uuid v1.0.1 // indirect + github.com/hashicorp/hcl v1.0.0 // indirect + github.com/hashicorp/hcl2 v0.0.0-20190315201941-956e03eb6dda // indirect + github.com/hashicorp/hil v0.0.0-20190212132231-97b3a9cdfa93 // indirect + github.com/hashicorp/logutils v1.0.0 // indirect + github.com/hashicorp/terraform v0.11.7 + github.com/mitchellh/cli v1.0.0 // indirect + github.com/mitchellh/copystructure v1.0.0 // indirect + github.com/mitchellh/go-homedir v1.1.0 // indirect + github.com/mitchellh/hashstructure v1.0.0 // indirect + github.com/zclconf/go-cty v0.0.0-20190212192503-19dda139b164 // indirect + golang.org/x/crypto v0.0.0-20190313024323-a1f597ede03a // indirect + golang.org/x/net v0.0.0-20190313220215-9f648a60d977 // indirect +) diff --git a/go.sum b/go.sum new file mode 100644 index 0000000..5f951e4 --- /dev/null +++ b/go.sum @@ -0,0 +1,277 @@ +cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= +cloud.google.com/go v0.31.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= +cloud.google.com/go v0.36.0 h1:+aCSj7tOo2LODWVEuZDZeGCckdt6MlSF+X/rB3wUiS8= +cloud.google.com/go v0.36.0/go.mod h1:RUoy9p/M4ge0HzT8L+SDZ8jg+Q6fth0CiBuhFJpSV40= +dmitri.shuralyov.com/app/changes v0.0.0-20180602232624-0a106ad413e3/go.mod h1:Yl+fi1br7+Rr3LqpNJf1/uxUdtRUV+Tnj0o93V2B9MU= +dmitri.shuralyov.com/html/belt v0.0.0-20180602232347-f7d459c86be0/go.mod h1:JLBrvjyP0v+ecvNYvCpyZgu5/xkfAUhi6wJj28eUfSU= +dmitri.shuralyov.com/service/change v0.0.0-20181023043359-a85b471d5412/go.mod h1:a1inKt/atXimZ4Mv927x+r7UpyzRUf4emIoiiSC2TN4= +dmitri.shuralyov.com/state v0.0.0-20180228185332-28bcc343414c/go.mod h1:0PRwlb0D6DFvNNtx+9ybjezNCa8XF0xaYcETyp6rHWU= +git.apache.org/thrift.git v0.0.0-20180902110319-2566ecd5d999/go.mod h1:fPE2ZNJGynbRyZ4dJvy6G277gSllfV2HJqblrnkyeyg= +github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= +github.com/agext/levenshtein v1.2.1 h1:QmvMAjj2aEICytGiWzmxoE0x2KZvE0fvmqMOfy2tjT8= +github.com/agext/levenshtein v1.2.1/go.mod h1:JEDfjyjHDjOF/1e4FlBE/PkbqA9OfWu2ki2W0IB5558= +github.com/anmitsu/go-shlex v0.0.0-20161002113705-648efa622239/go.mod h1:2FmKhYUyUczH0OGQWaF5ceTx0UBShxjsH6f8oGKYe2c= +github.com/apparentlymart/go-cidr v1.0.0 h1:lGDvXx8Lv9QHjrAVP7jyzleG4F9+FkRhJcEsDFxeb8w= +github.com/apparentlymart/go-cidr v1.0.0/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-textseg v1.0.0 h1:rRmlIsPEEhUTIKQb7T++Nz/A5Q6C9IuX2wFoYVvnCs0= +github.com/apparentlymart/go-textseg v1.0.0/go.mod h1:z96Txxhf3xSFMPmb5X/1W05FF/Nj9VFpLOpjS5yuumk= +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/aws/aws-sdk-go v1.15.78 h1:LaXy6lWR0YK7LKyuU0QWy2ws/LWTPfYV/UgfiBu4tvY= +github.com/aws/aws-sdk-go v1.15.78/go.mod h1:E3/ieXAlvM0XWO57iftYVDLLvQ824smPP3ATZkfNZeM= +github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q= +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/blang/semver v3.5.1+incompatible h1:cQNTCjp13qL8KC3Nbxr/y2Bqb63oX6wdnnjpJbkM4JQ= +github.com/blang/semver v3.5.1+incompatible/go.mod h1:kRBLl5iJ+tD4TcOOxsy/0fnwebNt5EWlYSAyrTnjyyk= +github.com/bradfitz/go-smtpd v0.0.0-20170404230938-deb6d6237625/go.mod h1:HYsPBTaaSFSlLx/70C2HPIMNZpVV8+vt/A+FMnYP11g= +github.com/bsm/go-vlq v0.0.0-20150828105119-ec6e8d4f5f4e/go.mod h1:N+BjUcTjSxc2mtRGSCPsat1kze3CUtvJN3/jTXlp29k= +github.com/cheggaaa/pb v1.0.27/go.mod h1:pQciLPpbU0oxA0h+VJYYLxO+XeDQb5pZijXscXHm81s= +github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= +github.com/coreos/go-systemd v0.0.0-20181012123002-c6f51f82210d/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4= +github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= +github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/dustin/go-humanize v1.0.0/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk= +github.com/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/go.mod h1:xEzjJPgXI435gkrCt3MPfRiAkVrwSbHsst4LCFVfpJc= +github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= +github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= +github.com/gliderlabs/ssh v0.1.1/go.mod h1:U7qILu1NlMHj9FlMhZLlkCdDnU1DBEAqr0aevW3Awn0= +github.com/go-test/deep v1.0.1 h1:UQhStjbkDClarlmv0am7OXXO4/GaPdCGiUiMTvi28sg= +github.com/go-test/deep v1.0.1/go.mod h1:wGDj63lr65AM2AQyKZd/NYHGb0R+1RLqB8NKt3aSFNA= +github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= +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/lint v0.0.0-20180702182130-06c8688daad7/go.mod h1:tluoj9z5200jBnyusfRPU2LqT6J+DAorxEvtC7LHB+E= +github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= +github.com/golang/mock v1.2.0/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= +github.com/golang/protobuf v1.1.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.2.0 h1:P3YflyNX/ehuJFLhxviNdFxQPkGK5cDcApsge1SqnvM= +github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= +github.com/google/go-cmp v0.2.0 h1:+dTQ8DZQJz0Mb/HjFlkptS1FeQ4cWSnN941F8aEG4SQ= +github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= +github.com/google/go-github v17.0.0+incompatible/go.mod h1:zLgOLi98H3fifZn+44m+umXrS52loVEgC2AApnigrVQ= +github.com/google/go-querystring v1.0.0/go.mod h1:odCYkC5MyYFN7vkCjXpyrEuKhc/BUO6wN/zVPAxq5ck= +github.com/google/martian v2.1.0+incompatible h1:/CP5g8u/VJHijgedC/Legn3BAbAaWPgecwXBIDzw5no= +github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs= +github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= +github.com/googleapis/gax-go v2.0.0+incompatible h1:j0GKcs05QVmm7yesiZq2+9cxHkNK9YM6zKx4D2qucQU= +github.com/googleapis/gax-go v2.0.0+incompatible/go.mod h1:SFVmujtThgffbyetf+mdk2eWhX2bMyUtNHzFKcPA9HY= +github.com/googleapis/gax-go/v2 v2.0.3 h1:siORttZ36U2R/WjiJuDz8znElWBiAlO9rVt+mqJt0Cc= +github.com/googleapis/gax-go/v2 v2.0.3/go.mod h1:LLvjysVCY1JZeum8Z6l8qUty8fiNwE08qbEPm1M08qg= +github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY= +github.com/gregjones/httpcache v0.0.0-20180305231024-9cad4c3443a7/go.mod h1:FecbI9+v66THATjSRHfNgh1IVFe/9kFxbXtjV0ctIMA= +github.com/grpc-ecosystem/grpc-gateway v1.5.0/go.mod h1:RSKVYQBd5MCa4OVpNdGskqpgL2+G+NZTnrVHpWWfpdw= +github.com/hashicorp/errwrap v0.0.0-20180715044906-d6c0cd880357/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= +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-cleanhttp v0.5.0 h1:wvCrVc9TjDls6+YGAF2hAifE1E5U1+b4tH6KdvN3Gig= +github.com/hashicorp/go-cleanhttp v0.5.0/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80= +github.com/hashicorp/go-getter v1.2.0 h1:E05bVPilzyh2yXgT6srn7WEkfMZaH+LuX9tDJw/4kaE= +github.com/hashicorp/go-getter v1.2.0/go.mod h1:/O1k/AizTN0QmfEKknCYGvICeyKUDqCYA8vvWtGWDeQ= +github.com/hashicorp/go-hclog v0.0.0-20180709165350-ff2cf002a8dd/go.mod h1:9bjs9uLqI8l75knNv3lV1kA55veR+WUPSiKIWcQHudI= +github.com/hashicorp/go-hclog v0.8.0 h1:z3ollgGRg8RjfJH6UVBaG54R70GFd++QOkvnJH3VSBY= +github.com/hashicorp/go-hclog v0.8.0/go.mod h1:5CU+agLiy3J7N7QjHK5d05KxGsuXiQLrjA0H7acj2lQ= +github.com/hashicorp/go-multierror v0.0.0-20180717150148-3d5d8f294aa0/go.mod h1:JMRHfdO9jKNzS/+BTlxCjKNQHg/jZAft8U7LloJvN7I= +github.com/hashicorp/go-multierror v1.0.0 h1:iVjPR7a6H0tWELX5NxNe7bYopibicUzc7uPribsnS6o= +github.com/hashicorp/go-multierror v1.0.0/go.mod h1:dHtQlpGsu+cZNNAkkCN/P3hoUDHhCYQXV3UM06sGGrk= +github.com/hashicorp/go-plugin v0.0.0-20190220160451-3f118e8ee104 h1:9iQ/zrTOJqzP+kH37s6xNb6T1RysiT7fnDD3DJbspVw= +github.com/hashicorp/go-plugin v0.0.0-20190220160451-3f118e8ee104/go.mod h1:++UyYGoz3o5w9ZzAdZxtQKrWWP+iqPBn3cQptSMzBuY= +github.com/hashicorp/go-safetemp v1.0.0 h1:2HR189eFNrjHQyENnQMMpCiBAsRxzbTMIgBhEyExpmo= +github.com/hashicorp/go-safetemp v1.0.0/go.mod h1:oaerMy3BhqiTbVye6QuFhFtIceqFoDHxNAB65b+Rj1I= +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 h1:bPIoEKD27tNdebFGGxxYwcL4nepeY4j1QP23PFRGzg0= +github.com/hashicorp/go-version v1.1.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA= +github.com/hashicorp/hcl v1.0.0 h1:0Anlzjpi4vEasTeNFn2mLJgTSwt0+6sfsiTG8qcWGx4= +github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ= +github.com/hashicorp/hcl2 v0.0.0-20190315201941-956e03eb6dda h1:wgPsY2p0JDBRzc7fPEUidAhpXZzSPTIuSUDATOisbYs= +github.com/hashicorp/hcl2 v0.0.0-20190315201941-956e03eb6dda/go.mod h1:HtEzazM5AZ9fviNEof8QZB4T1Vz9UhHrGhnMPzl//Ek= +github.com/hashicorp/hil v0.0.0-20190212132231-97b3a9cdfa93 h1:T1Q6ag9tCwun16AW+XK3tAql24P4uTGUMIn1/92WsQQ= +github.com/hashicorp/hil v0.0.0-20190212132231-97b3a9cdfa93/go.mod h1:n2TSygSNwsLJ76m8qFXTSc7beTb+auJxYdqrnoqwZWE= +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 v0.11.7 h1:NC3flYWAINcKyjTRIyU/Sz6kZLuSdAGEpqoyurZxLN0= +github.com/hashicorp/terraform v0.11.7/go.mod h1:uN1KUiT7Wdg61fPwsGXQwK3c8PmpIVZrt5Vcb1VrSoM= +github.com/hashicorp/yamux v0.0.0-20180604194846-3520598351bb h1:b5rjCoWHc7eqmAS4/qyk21ZsHyb6Mxv/jykxvNTkU4M= +github.com/hashicorp/yamux v0.0.0-20180604194846-3520598351bb/go.mod h1:+NfK9FKeTrX5uv1uIXGdwYDTeHna2qgaIlx54MXqjAM= +github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU= +github.com/jellevandenhooff/dkim v0.0.0-20150330215556-f50fe3d243e1/go.mod h1:E0B/fFc00Y+Rasa88328GlI/XbtyysCtTHZS8h7IrBU= +github.com/jessevdk/go-flags v1.4.0/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI= +github.com/jmespath/go-jmespath v0.0.0-20160202185014-0b12d6b521d8 h1:12VvqtR6Aowv3l/EQUlocDHW2Cp4G9WJVH7uyH8QFJE= +github.com/jmespath/go-jmespath v0.0.0-20160202185014-0b12d6b521d8/go.mod h1:Nht3zPeWKUH0NzdCt2Blrr5ys8VGpn0CEB0cQHVjt7k= +github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= +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.3/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= +github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE= +github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= +github.com/kylelemons/godebug v0.0.0-20170820004349-d65d576e9348 h1:MtvEpTB6LX3vkb4ax0b5D2DHbNAUsen0Gx5wZoq3lV4= +github.com/kylelemons/godebug v0.0.0-20170820004349-d65d576e9348/go.mod h1:B69LEHPfb2qLo0BaaOLcbitczOKLWTsrBG9LczfCD4k= +github.com/mattn/go-colorable v0.0.9 h1:UVL0vNpWh04HeJXV0KLcaT7r06gOH2l4OW6ddYRUIY4= +github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU= +github.com/mattn/go-isatty v0.0.3/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4= +github.com/mattn/go-isatty v0.0.4 h1:bnP0vzxcAdeI1zdubAl5PjU6zsERjGZb7raWodagDYs= +github.com/mattn/go-isatty v0.0.4/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4= +github.com/mattn/go-runewidth v0.0.4/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU= +github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= +github.com/microcosm-cc/bluemonday v1.0.1/go.mod h1:hsXNsILzKxV+sX77C5b8FSuKF00vh2OMYv+xgHpAMF4= +github.com/mitchellh/cli v1.0.0 h1:iGBIsUe3+HZ/AD/Vd7DErOt5sU9fa8Uj7A2s1aggv1Y= +github.com/mitchellh/cli v1.0.0/go.mod h1:hNIlj7HEI86fIcpObd7a0FcrxTWetlwJDGcceTlRvqc= +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-wordwrap v0.0.0-20150314170334-ad45545899c7 h1:DpOJ2HYzCv8LZP15IdmG+YdwD2luVPHITV96TkirNBM= +github.com/mitchellh/go-wordwrap v0.0.0-20150314170334-ad45545899c7/go.mod h1:ZXFpozHsX6DPmq2I0TCekCxypsnAUbP2oI0UX1GXzOo= +github.com/mitchellh/hashstructure v1.0.0 h1:ZkRJX1CyOoTkar7p/mLS5TZU4nJ1Rn/F8u9dGS02Q3Y= +github.com/mitchellh/hashstructure v1.0.0/go.mod h1:QjSHrPWS+BGUVBYkbTZWEnOh3G1DutKwClXU/ABz6AQ= +github.com/mitchellh/mapstructure v1.1.2 h1:fmNYVwqnSfB9mZU6OS2O6GsXM+wcskZDuKQzvN1EDeE= +github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= +github.com/mitchellh/reflectwalk v1.0.0 h1:9D+8oIskB4VJBN5SFlmc27fSlIBZaov1Wpk/IfikLNY= +github.com/mitchellh/reflectwalk v1.0.0/go.mod h1:mSTlrgnPZtwu0c4WaC2kGObEpuNDbx0jmZXqmk4esnw= +github.com/neelance/astrewrite v0.0.0-20160511093645-99348263ae86/go.mod h1:kHJEU3ofeGjhHklVoIGuVj85JJwZ6kWPaJwCIxgnFmo= +github.com/neelance/sourcemap v0.0.0-20151028013722-8c68805598ab/go.mod h1:Qr6/a/Q4r9LP1IltGz7tA7iOK1WonHEYhu1HRBA7ZiM= +github.com/oklog/run v1.0.0 h1:Ru7dDtJNOyC66gQ5dQmaCa0qIsAUFY3sFpK1Xk8igrw= +github.com/oklog/run v1.0.0/go.mod h1:dlhp/R75TPv97u0XWUtDeV/lRKWPKSdTuV0TZvrmrQA= +github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= +github.com/onsi/ginkgo v1.7.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= +github.com/onsi/gomega v1.4.3/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY= +github.com/openzipkin/zipkin-go v0.1.1/go.mod h1:NtoC/o8u3JlF1lSlyPNswIbeQH9bJTmOf0Erfk+hxe8= +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_golang v0.8.0/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw= +github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= +github.com/prometheus/common v0.0.0-20180801064454-c7de2306084e/go.mod h1:daVV7qP5qjZbuso7PdcryaAu0sAZbrN9i7WWcTMWvro= +github.com/prometheus/procfs v0.0.0-20180725123919-05ee40e3a273/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= +github.com/russross/blackfriday v1.5.2/go.mod h1:JO/DiYxRf+HjHt06OyowR9PTA263kcR/rfWxYHBV53g= +github.com/sergi/go-diff v1.0.0 h1:Kpca3qRNrduNnOQeazBd0ysaKrUJiIuISHxogkT9RPQ= +github.com/sergi/go-diff v1.0.0/go.mod h1:0CfEIISq7TuYL3j771MWULgwwjU+GofnZX9QAmXWZgo= +github.com/shurcooL/component v0.0.0-20170202220835-f88ec8f54cc4/go.mod h1:XhFIlyj5a1fBNx5aJTbKoIq0mNaPvOagO+HjB3EtxrY= +github.com/shurcooL/events v0.0.0-20181021180414-410e4ca65f48/go.mod h1:5u70Mqkb5O5cxEA8nxTsgrgLehJeAw6Oc4Ab1c/P1HM= +github.com/shurcooL/github_flavored_markdown v0.0.0-20181002035957-2122de532470/go.mod h1:2dOwnU2uBioM+SGy2aZoq1f/Sd1l9OkAeAUvjSyvgU0= +github.com/shurcooL/go v0.0.0-20180423040247-9e1955d9fb6e/go.mod h1:TDJrrUr11Vxrven61rcy3hJMUqaf/CLWYhHNPmT14Lk= +github.com/shurcooL/go-goon v0.0.0-20170922171312-37c2f522c041/go.mod h1:N5mDOmsrJOB+vfqUK+7DmDyjhSLIIBnXo9lvZJj3MWQ= +github.com/shurcooL/gofontwoff v0.0.0-20180329035133-29b52fc0a18d/go.mod h1:05UtEgK5zq39gLST6uB0cf3NEHjETfB4Fgr3Gx5R9Vw= +github.com/shurcooL/gopherjslib v0.0.0-20160914041154-feb6d3990c2c/go.mod h1:8d3azKNyqcHP1GaQE/c6dDgjkgSx2BZ4IoEi4F1reUI= +github.com/shurcooL/highlight_diff v0.0.0-20170515013008-09bb4053de1b/go.mod h1:ZpfEhSmds4ytuByIcDnOLkTHGUI6KNqRNPDLHDk+mUU= +github.com/shurcooL/highlight_go v0.0.0-20181028180052-98c3abbbae20/go.mod h1:UDKB5a1T23gOMUJrI+uSuH0VRDStOiUVSjBTRDVBVag= +github.com/shurcooL/home v0.0.0-20181020052607-80b7ffcb30f9/go.mod h1:+rgNQw2P9ARFAs37qieuu7ohDNQ3gds9msbT2yn85sg= +github.com/shurcooL/htmlg v0.0.0-20170918183704-d01228ac9e50/go.mod h1:zPn1wHpTIePGnXSHpsVPWEktKXHr6+SS6x/IKRb7cpw= +github.com/shurcooL/httperror v0.0.0-20170206035902-86b7830d14cc/go.mod h1:aYMfkZ6DWSJPJ6c4Wwz3QtW22G7mf/PEgaB9k/ik5+Y= +github.com/shurcooL/httpfs v0.0.0-20171119174359-809beceb2371/go.mod h1:ZY1cvUeJuFPAdZ/B6v7RHavJWZn2YPVFQ1OSXhCGOkg= +github.com/shurcooL/httpgzip v0.0.0-20180522190206-b1c53ac65af9/go.mod h1:919LwcH0M7/W4fcZ0/jy0qGght1GIhqyS/EgWGH2j5Q= +github.com/shurcooL/issues v0.0.0-20181008053335-6292fdc1e191/go.mod h1:e2qWDig5bLteJ4fwvDAc2NHzqFEthkqn7aOZAOpj+PQ= +github.com/shurcooL/issuesapp v0.0.0-20180602232740-048589ce2241/go.mod h1:NPpHK2TI7iSaM0buivtFUc9offApnI0Alt/K8hcHy0I= +github.com/shurcooL/notifications v0.0.0-20181007000457-627ab5aea122/go.mod h1:b5uSkrEVM1jQUspwbixRBhaIjIzL2xazXp6kntxYle0= +github.com/shurcooL/octicon v0.0.0-20181028054416-fa4f57f9efb2/go.mod h1:eWdoE5JD4R5UVWDucdOPg1g2fqQRq78IQa9zlOV1vpQ= +github.com/shurcooL/reactions v0.0.0-20181006231557-f2e0b4ca5b82/go.mod h1:TCR1lToEk4d2s07G3XGfz2QrgHXg4RJBvjrOozvoWfk= +github.com/shurcooL/sanitized_anchor_name v0.0.0-20170918181015-86672fcb3f95/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc= +github.com/shurcooL/users v0.0.0-20180125191416-49c67e49c537/go.mod h1:QJTqeLYEDaXHZDBsXlPCDqdhQuJkuw4NOtaxYe3xii4= +github.com/shurcooL/webdavfs v0.0.0-20170829043945-18c3829fa133/go.mod h1:hKmq5kWdCj2z2KEozexVbfEZIWiTjhE0+UjmZgPqehw= +github.com/sourcegraph/annotate v0.0.0-20160123013949-f4cad6c6324d/go.mod h1:UdhH50NIW0fCiwBSr0co2m7BnFLdv4fQTgdqdJTHFeE= +github.com/sourcegraph/syntaxhighlight v0.0.0-20170531221838-bd320f5d308e/go.mod h1:HuIsMU8RRBOtsCgI77wP899iHVBQpCmg4ErYMZB+2IA= +github.com/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/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/tarm/serial v0.0.0-20180830185346-98f6abe2eb07/go.mod h1:kDXzergiv9cbyO7IOYJZWg1U88JhDg3PB6klq9Hg2pA= +github.com/ulikunitz/xz v0.5.5 h1:pFrO0lVpTBXLpYw+pnLj6TbvHuyjXMfjGeCwSqCVwok= +github.com/ulikunitz/xz v0.5.5/go.mod h1:2bypXElzHzzJZwzH67Y6wb67pO62Rzfn7BSiF4ABRW8= +github.com/vmihailenco/msgpack v3.3.3+incompatible/go.mod h1:fy3FlTQTDXWkZ7Bh6AcGMlsjHatGryHQYUTf1ShIgkk= +github.com/zclconf/go-cty v0.0.0-20190124225737-a385d646c1e9/go.mod h1:xnAOWiHeOqg2nWS62VtQ7pbOu17FtxJNW8RLEih+O3s= +github.com/zclconf/go-cty v0.0.0-20190212192503-19dda139b164 h1:H/K552vgSGWF1LOtDOsBa+i9ZttdABUfACdsQZ87/Ds= +github.com/zclconf/go-cty v0.0.0-20190212192503-19dda139b164/go.mod h1:xnAOWiHeOqg2nWS62VtQ7pbOu17FtxJNW8RLEih+O3s= +go.opencensus.io v0.18.0 h1:Mk5rgZcggtbvtAun5aJzAtjKKN/t0R3jJPlWILlv938= +go.opencensus.io v0.18.0/go.mod h1:vKdFvxhtzZ9onBp9VKHK8z/sRpBMnKAsufL7wlDrCOA= +go4.org v0.0.0-20180809161055-417644f6feb5/go.mod h1:MkTOUMDaeVYJUOUsaDXIhWPZYa1yOyC1qaOBpL57BhE= +golang.org/x/build v0.0.0-20190111050920-041ab4dc3f9d/go.mod h1:OWs+y06UdEOHN4y+MfF/py+xQ/tYqIWW03b70/CG9Rw= +golang.org/x/crypto v0.0.0-20180816225734-aabede6cba87/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= +golang.org/x/crypto v0.0.0-20181030102418-4d3f4d9ffa16/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-20190313024323-a1f597ede03a h1:YX8ljsm6wXlHZO+aRz9Exqr0evNhKRNe5K/gi+zKh4U= +golang.org/x/crypto v0.0.0-20190313024323-a1f597ede03a/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= +golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= +golang.org/x/lint v0.0.0-20180702182130-06c8688daad7/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= +golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= +golang.org/x/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-20181029044818-c44066c5c816/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20181106065722-10aee1819953/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20181129055619-fae4c4e3ad76/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20190313220215-9f648a60d977 h1:actzWV6iWn3GLqN8dZjzsB+CLt+gaV2+wsxroxiQI8I= +golang.org/x/net v0.0.0-20190313220215-9f648a60d977/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= +golang.org/x/oauth2 v0.0.0-20181017192945-9dcd33a902f4/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= +golang.org/x/oauth2 v0.0.0-20181203162652-d668ce993890 h1:uESlIz09WIHT2I+pasSXcpLYqYK8wHcdCetU3VuMBJE= +golang.org/x/oauth2 v0.0.0-20181203162652-d668ce993890/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= +golang.org/x/perf v0.0.0-20180704124530-6e6d33e29852/go.mod h1:JLpeXjPJfIyPr5TlbXLkXWLhP8nz10XfvxElABhCtcw= +golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4 h1:YUO/7uOKsKeq9UokNS62b8FYywz3ker1l1vDZRCRefw= +golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20181029174526-d69651ed3497/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20181213200352-4d1cda033e06/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190129075346-302c3dd5f1cc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a h1:1BGLXjeY4akVXGgbC9HugT3Jv3hCI0z56oJR5vAMgBU= +golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2 h1:z99zHgr7hKfrUcX/KsoJk5FJfjTceCKIp96+biqP4To= +golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/time v0.0.0-20180412165947-fbb02b2291d2/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +golang.org/x/tools v0.0.0-20180828015842-6cd1fcedba52/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20181030000716-a0a13e073c7b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +google.golang.org/api v0.0.0-20180910000450-7ca32eb868bf/go.mod h1:4mhQ8q/RsB7i+udVvVy5NUi08OU8ZlA0gRVgrF7VFY0= +google.golang.org/api v0.0.0-20181030000543-1d582fd0359e/go.mod h1:4mhQ8q/RsB7i+udVvVy5NUi08OU8ZlA0gRVgrF7VFY0= +google.golang.org/api v0.1.0 h1:K6z2u68e86TPdSdefXdzvXgR1zEMa+459vBSfWYAZkI= +google.golang.org/api v0.1.0/go.mod h1:UGEZY7KEX120AnNLIHFMKIo4obdJhkp2tPbaPlQx13Y= +google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= +google.golang.org/appengine v1.2.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= +google.golang.org/appengine v1.3.0 h1:FBSsiFRMz3LBeXIomRnVzrQwSDj4ibvcRexLG0LZGQk= +google.golang.org/appengine v1.3.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= +google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= +google.golang.org/genproto v0.0.0-20180831171423-11092d34479b/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= +google.golang.org/genproto v0.0.0-20181029155118-b69ba1387ce2/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= +google.golang.org/genproto v0.0.0-20181202183823-bd91e49a0898/go.mod h1:7Ep/1NZk928CDR8SjdVbjWNpdIf6nzjE3BTgJDr2Atg= +google.golang.org/genproto v0.0.0-20190201180003-4b09977fb922 h1:mBVYJnbrXLA/ZCBTCe7PtEgAUP+1bg92qTaFoPHdz+8= +google.golang.org/genproto v0.0.0-20190201180003-4b09977fb922/go.mod h1:L3J43x8/uS+qIUoksaLKe6OS3nUKxOKuIFz1sl2/jx4= +google.golang.org/grpc v1.14.0/go.mod h1:yo6s7OP7yaDglbqo1J04qKzAhqBH6lvTonzMVmEdcZw= +google.golang.org/grpc v1.16.0/go.mod h1:0JHn/cJsOMiMfNA9+DeHDlAU7KAAB5GDlYFpa9MZMio= +google.golang.org/grpc v1.17.0 h1:TRJYBgMclJvGYn2rIMjj+h9KtMt5r1Ij7ODVRIZkwhk= +google.golang.org/grpc v1.17.0/go.mod h1:6QZJwpn2B+Zp71q/5VxRsJ6NXXVCE5NRUHRo+f3cWCs= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/cheggaaa/pb.v1 v1.0.27/go.mod h1:V/YB90LKu/1FcN3WVnfiiE5oMCibMjukxqG/qStrOgw= +gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys= +gopkg.in/inf.v0 v0.9.1/go.mod h1:cWUDdTG/fYaXco+Dcufb5Vnc6Gp2YChqWtbxRZE0mXw= +gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw= +gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +grpc.go4.org v0.0.0-20170609214715-11d0a25b4919/go.mod h1:77eQGdRu53HpSqPFJFmuJdjuHRquDANNeA4x7B8WQ9o= +honnef.co/go/tools v0.0.0-20180728063816-88497007e858/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= +honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= +howett.net/plist v0.0.0-20181124034731-591f970eefbb/go.mod h1:vMygbs4qMhSZSc4lCUl2OEE+rDiIIJAIdR4m7MiMcm0= +sourcegraph.com/sourcegraph/go-diff v0.5.0/go.mod h1:kuch7UrkMzY0X+p9CRK03kfuPQ2zzQcaEFbx8wA8rck= +sourcegraph.com/sqs/pbtypes v0.0.0-20180604144634-d3ebe8f20ae4/go.mod h1:ketZ/q3QxT9HOBeFhu6RdvsftgpsbFHBF5Cas6cDKZ0= diff --git a/zerotier/main.go b/main.go similarity index 75% rename from zerotier/main.go rename to main.go index 5ecf31e..2bdaf42 100644 --- a/zerotier/main.go +++ b/main.go @@ -1,6 +1,8 @@ package main import ( + "terraform-provider-zerotier/zerotier" + "github.com/hashicorp/terraform/plugin" "github.com/hashicorp/terraform/terraform" ) @@ -8,7 +10,7 @@ import ( func main() { plugin.Serve(&plugin.ServeOpts{ ProviderFunc: func() terraform.ResourceProvider { - return Provider() + return zerotier.Provider() }, }) } diff --git a/scripts/errcheck.sh b/scripts/errcheck.sh index 15464f5..2dd403b 100755 --- a/scripts/errcheck.sh +++ b/scripts/errcheck.sh @@ -1,18 +1,18 @@ #!/usr/bin/env bash -# Check gofmt +# Check errcheck echo "==> Checking for unchecked errors..." -if ! which errcheck > /dev/null; then +if ! which errcheck >/dev/null; then echo "==> Installing errcheck..." - go get -u github.com/kisielk/errcheck + go get github.com/kisielk/errcheck fi err_files=$(errcheck -ignoretests \ - -ignore 'github.com/hashicorp/terraform/helper/schema:Set' \ - -ignore 'bytes:.*' \ - -ignore 'io:Close|Write' \ - $(go list ./...| grep -v /vendor/)) + -ignore 'github.com/hashicorp/terraform/helper/schema:Set' \ + -ignore 'bytes:.*' \ + -ignore 'io:Close|Write' \ + $(go list ./... | grep -v /vendor/)) if [[ -n ${err_files} ]]; then echo 'Unchecked errors found in the following places:' diff --git a/scripts/gofmtcheck.sh b/scripts/gofmtcheck.sh index 1c05581..19e94b8 100755 --- a/scripts/gofmtcheck.sh +++ b/scripts/gofmtcheck.sh @@ -2,7 +2,7 @@ # Check gofmt echo "==> Checking that code complies with gofmt requirements..." -gofmt_files=$(gofmt -l `find . -name '*.go' | grep -v vendor`) +gofmt_files=$(gofmt -s -l $(find . -name '*.go' | grep -v vendor)) if [[ -n ${gofmt_files} ]]; then echo 'gofmt needs running on the following files:' echo "${gofmt_files}" @@ -10,4 +10,9 @@ if [[ -n ${gofmt_files} ]]; then exit 1 fi +if ! which goimports >/dev/null; then + echo "==> Installing goimports..." + go get golang.org/x/tools/cmd/goimports +fi + exit 0 diff --git a/zerotier/client.go b/zerotier/client.go index 26b4cb4..9918daa 100644 --- a/zerotier/client.go +++ b/zerotier/client.go @@ -1,19 +1,18 @@ -package main +package zerotier import ( "bytes" - "strings" "encoding/json" "fmt" "io/ioutil" "net" "net/http" + "strings" ) -const baseUrl string = "https://my.zerotier.com/api" - type ZeroTierClient struct { - ApiKey string + ApiKey string + Controller string } type Route struct { @@ -32,12 +31,21 @@ type V4AssignModeConfig struct { ZT bool `json:"zt"` } +type V6AssignModeConfig struct { + ZT bool `json:"zt"` + SixPLANE bool `json:"6plane"` + RFC4193 bool `json:"rfc4193"` +} + type Config struct { Name string `json:"name"` Private bool `json:"private"` + EnableBroadcast bool `json:"enableBroadcast"` + MulticastLimit int `json:"multicastLimit"` Routes []Route `json:"routes"` IpAssignmentPools []IpRange `json:"ipAssignmentPools"` V4AssignMode V4AssignModeConfig `json:"v4AssignMode"` + V6AssignMode V6AssignModeConfig `json:"v6AssignMode"` } type ConfigReadOnly struct { @@ -200,7 +208,7 @@ func (s *ZeroTierClient) headRequest(req *http.Request) (*http.Response, error) } func (client *ZeroTierClient) CheckNetworkExists(id string) (bool, error) { - url := fmt.Sprintf(baseUrl+"/network/%s", id) + url := fmt.Sprintf(client.Controller+"/network/%s", id) req, err := http.NewRequest("GET", url, nil) if err != nil { return false, err @@ -219,7 +227,7 @@ func (client *ZeroTierClient) CheckNetworkExists(id string) (bool, error) { } func (client *ZeroTierClient) GetNetwork(id string) (*Network, error) { - url := fmt.Sprintf(baseUrl+"/network/%s", id) + url := fmt.Sprintf(client.Controller+"/network/%s", id) req, err := http.NewRequest("GET", url, nil) if err != nil { return nil, err @@ -237,7 +245,7 @@ func (client *ZeroTierClient) GetNetwork(id string) (*Network, error) { } func (client *ZeroTierClient) postNetwork(id string, network *Network) (*Network, error) { - url := strings.TrimSuffix(fmt.Sprintf(baseUrl+"/network/%s", id), "/") + url := strings.TrimSuffix(fmt.Sprintf(client.Controller+"/network/%s", id), "/") // strip carriage returns? // network.RulesSource = strings.Replace(network.RulesSource, "\r", "", -1) j, err := json.Marshal(network) @@ -275,7 +283,7 @@ func (client *ZeroTierClient) UpdateNetwork(id string, network *Network) (*Netwo } func (client *ZeroTierClient) DeleteNetwork(id string) error { - url := fmt.Sprintf(baseUrl+"/network/%s", id) + url := fmt.Sprintf(client.Controller+"/network/%s", id) req, err := http.NewRequest("DELETE", url, nil) if err != nil { return err @@ -289,7 +297,7 @@ func (client *ZeroTierClient) DeleteNetwork(id string) error { ///////////// func (client *ZeroTierClient) GetMember(nwid string, nodeId string) (*Member, error) { - url := fmt.Sprintf(baseUrl+"/network/%s/member/%s", nwid, nodeId) + url := fmt.Sprintf(client.Controller+"/network/%s/member/%s", nwid, nodeId) req, err := http.NewRequest("GET", url, nil) if err != nil { return nil, err @@ -307,7 +315,7 @@ func (client *ZeroTierClient) GetMember(nwid string, nodeId string) (*Member, er } func (client *ZeroTierClient) postMember(member *Member, reqName string) (*Member, error) { - url := fmt.Sprintf(baseUrl+"/network/%s/member/%s", member.NetworkId, member.NodeId) + url := fmt.Sprintf(client.Controller+"/network/%s/member/%s", member.NetworkId, member.NodeId) j, err := json.Marshal(member) if err != nil { return nil, err @@ -339,7 +347,7 @@ func (client *ZeroTierClient) UpdateMember(member *Member) (*Member, error) { // Careful: this one isn't documented in the Zt API, // but this is what the Central web client does. func (client *ZeroTierClient) DeleteMember(member *Member) error { - url := fmt.Sprintf(baseUrl+"/network/%s/member/%s", member.NetworkId, member.NodeId) + url := fmt.Sprintf(client.Controller+"/network/%s/member/%s", member.NetworkId, member.NodeId) req, err := http.NewRequest("DELETE", url, nil) if err != nil { return err @@ -349,7 +357,7 @@ func (client *ZeroTierClient) DeleteMember(member *Member) error { } func (client *ZeroTierClient) CheckMemberExists(nwid string, nodeId string) (bool, error) { - url := fmt.Sprintf(baseUrl+"/network/%s/member/%s", nwid, nodeId) + url := fmt.Sprintf(client.Controller+"/network/%s/member/%s", nwid, nodeId) req, err := http.NewRequest("GET", url, nil) if err != nil { return false, err diff --git a/zerotier/provider.go b/zerotier/provider.go index 77a5312..38e3ea7 100644 --- a/zerotier/provider.go +++ b/zerotier/provider.go @@ -1,18 +1,54 @@ -package main +package zerotier import ( + "fmt" + "net/url" + "strings" + "github.com/hashicorp/terraform/helper/schema" "github.com/hashicorp/terraform/terraform" ) +func isValidControllerURL(i interface{}, k string) ([]string, []error) { + v, ok := i.(string) + if !ok { + return nil, []error{fmt.Errorf("expected type of %q to be string", k)} + } + trimmed := strings.TrimSpace(v) + if trimmed == "" { + return nil, []error{fmt.Errorf("%q must not be empty", k)} + } + + if strings.HasSuffix(trimmed, "/") { + return nil, []error{fmt.Errorf("%q should not have trailing slash", k)} + } + + parsed, err := url.Parse(trimmed) + if err != nil { + return nil, []error{fmt.Errorf("%q must be a valid url", k)} + } + + if parsed.Scheme == "" { + return nil, []error{fmt.Errorf("%q should have an scheme, such as http:// or https://", k)} + } + + return nil, nil +} + func Provider() terraform.ResourceProvider { return &schema.Provider{ Schema: map[string]*schema.Schema{ - "api_key": &schema.Schema{ + "api_key": { Type: schema.TypeString, Required: true, DefaultFunc: schema.EnvDefaultFunc("ZEROTIER_API_KEY", nil), }, + "controller_url": { + Type: schema.TypeString, + Required: true, + DefaultFunc: schema.EnvDefaultFunc("ZEROTIER_CONTROLLER_URL", "https://my.zerotier.com/api"), + ValidateFunc: isValidControllerURL, + }, }, ResourcesMap: map[string]*schema.Resource{ "zerotier_network": resourceZeroTierNetwork(), @@ -23,5 +59,7 @@ func Provider() terraform.ResourceProvider { } func configureProvider(d *schema.ResourceData) (interface{}, error) { - return &ZeroTierClient{ApiKey: d.Get("api_key").(string)}, nil + return &ZeroTierClient{ + ApiKey: d.Get("api_key").(string), + Controller: d.Get("controller_url").(string)}, nil } diff --git a/zerotier/resource_zerotier_member.go b/zerotier/resource_zerotier_member.go index 5cd2d42..62883de 100644 --- a/zerotier/resource_zerotier_member.go +++ b/zerotier/resource_zerotier_member.go @@ -1,8 +1,9 @@ -package main +package zerotier import ( "fmt" "strconv" + "strings" "github.com/hashicorp/terraform/helper/schema" ) @@ -14,6 +15,9 @@ func resourceZeroTierMember() *schema.Resource { Update: resourceMemberUpdate, Delete: resourceMemberDelete, Exists: resourceMemberExists, + Importer: &schema.ResourceImporter{ + State: schema.ImportStatePassthrough, + }, Schema: map[string]*schema.Schema{ "network_id": { @@ -61,14 +65,41 @@ func resourceZeroTierMember() *schema.Resource { Default: false, }, "ip_assignments": { - Type: schema.TypeList, - Optional: true, + Type: schema.TypeSet, + Description: "List of IP routed and assigned by ZeroTier controller assignment pool. Does not include RFC4193 nor 6PLANE addresses, only those from assignment pool or manually provided.", + Optional: true, Elem: &schema.Schema{ Type: schema.TypeString, }, }, + "ipv4_assignments": { + Type: schema.TypeSet, + Description: "Computed list of IPv4 assigned by ZeroTier controller assignment pool. Does not include RFC4193 nor 6PLANE addresses, only those from assignment pool or manually provided.", + Computed: true, + Elem: &schema.Schema{ + Type: schema.TypeString, + }, + }, + "ipv6_assignments": { + Type: schema.TypeSet, + Description: "Computed list of IPv6 assigned by ZeroTier controller assignment pool. Does not include RFC4193 nor 6PLANE addresses, only those from assignment pool or manually provided.", + Computed: true, + Elem: &schema.Schema{ + Type: schema.TypeString, + }, + }, + "rfc4193_address": { + Type: schema.TypeString, + Description: "Computed RFC4193 (IPv6 /128) address. Always calculated and only actually assigned on the member if RFC4193 is configured on the network.", + Computed: true, + }, + "6plane_address": { + Type: schema.TypeString, + Description: "Computed 6PLANE (IPv6 /60) address. Always calculated and only actually assigned on the member if 6PLANE is configured on the network.", + Computed: true, + }, "capabilities": { - Type: schema.TypeList, + Type: schema.TypeSet, Optional: true, Elem: &schema.Schema{ Type: schema.TypeInt, @@ -143,12 +174,12 @@ func memberFromResourceData(d *schema.ResourceData) (*Member, error) { } tagTuples = append(tagTuples, []int{i, val.(int)}) } - capsRaw := d.Get("capabilities").([]interface{}) + capsRaw := d.Get("capabilities").(*schema.Set).List() caps := make([]int, len(capsRaw)) for i := range capsRaw { caps[i] = capsRaw[i].(int) } - ipsRaw := d.Get("ip_assignments").([]interface{}) + ipsRaw := d.Get("ip_assignments").(*schema.Set).List() ips := make([]string, len(ipsRaw)) for i := range ipsRaw { ips[i] = ipsRaw[i].(string) @@ -172,12 +203,70 @@ func memberFromResourceData(d *schema.ResourceData) (*Member, error) { } return n, nil } + +// Extracts the Network ID and Node ID from the resource definition, or from the id during import +// +// When importing a resource, both the network id and node id writen on the definition will be ignored +// and we could retrieve the network id and node id from parts of the id +// which is formated as - on zerotier +func resourceNetworkAndNodeIdentifiers(d *schema.ResourceData) (string, string) { + nwid := d.Get("network_id").(string) + nodeID := d.Get("node_id").(string) + + if nwid == "" && nodeID == "" { + parts := strings.Split(d.Id(), "-") + nwid, nodeID = parts[0], parts[1] + } + return nwid, nodeID +} + +// Receive a string and format every 4th element with a ":" +func buildIPV6(data string) (result string) { + s := strings.SplitAfter(data, "") + end := len(s) - 1 + result = "" + for i, s := range s { + result += s + if (i+1)%4 == 0 && i != end { + result += ":" + } + } + return +} + +// Calculate 6PLANE address for the member +func sixPlaneAddress(d *schema.ResourceData) string { + nwid, nodeID := resourceNetworkAndNodeIdentifiers(d) + return buildIPV6("fd" + nwid + "9993" + nodeID) +} + +// Calculate RFC4193 address for the member +func rfc4193Address(d *schema.ResourceData) string { + nwid, nodeID := resourceNetworkAndNodeIdentifiers(d) + nwidInt, _ := strconv.ParseUint(nwid, 16, 64) + networkMask := uint32((nwidInt >> 32) ^ nwidInt) + networkPrefix := strconv.FormatUint(uint64(networkMask), 16) + return buildIPV6("fc" + networkPrefix + nodeID + "000000000001") +} + +// Split the list of assigned IPs into IPv6 and IPv4 lists +// Does not include 6PLANE or RFC4193, only those from the assignment pool +func assingnedIpsGrouping(ipAssignments []string) (ipv4s []string, ipv6s []string) { + for _, element := range ipAssignments { + if strings.Contains(element, ":") { + ipv6s = append(ipv6s, element) + } else { + ipv4s = append(ipv4s, element) + } + } + return +} + func resourceMemberRead(d *schema.ResourceData, m interface{}) error { client := m.(*ZeroTierClient) // Attempt to read from an upstream API - nwid := d.Get("network_id").(string) - nodeId := d.Get("node_id").(string) + nwid, nodeId := resourceNetworkAndNodeIdentifiers(d) member, err := client.GetMember(nwid, nodeId) // If the resource does not exist, inform Terraform. We want to immediately @@ -190,15 +279,23 @@ func resourceMemberRead(d *schema.ResourceData, m interface{}) error { return nil } + ipv4Assignments, ipv6Assignments := assingnedIpsGrouping(member.Config.IpAssignments) + d.SetId(member.Id) d.Set("name", member.Name) d.Set("description", member.Description) + d.Set("node_id", nodeId) + d.Set("network_id", nwid) d.Set("hidden", member.Hidden) d.Set("offline_notify_delay", member.OfflineNotifyDelay) d.Set("authorized", member.Config.Authorized) d.Set("allow_ethernet_bridging", member.Config.ActiveBridge) d.Set("no_auto_assign_ips", member.Config.NoAutoAssignIps) d.Set("ip_assignments", member.Config.IpAssignments) + d.Set("ipv4_assignments", ipv4Assignments) + d.Set("ipv6_assignments", ipv6Assignments) + d.Set("rfc4193_address", rfc4193Address(d)) + d.Set("6plane_address", sixPlaneAddress(d)) d.Set("capabilities", member.Config.Capabilities) setTags(d, member) @@ -207,8 +304,7 @@ func resourceMemberRead(d *schema.ResourceData, m interface{}) error { func resourceMemberExists(d *schema.ResourceData, m interface{}) (b bool, e error) { client := m.(*ZeroTierClient) - nwid := d.Get("network_id").(string) - nodeId := d.Get("node_id").(string) + nwid, nodeId := resourceNetworkAndNodeIdentifiers(d) exists, err := client.CheckMemberExists(nwid, nodeId) if err != nil { return exists, err diff --git a/zerotier/resource_zerotier_network.go b/zerotier/resource_zerotier_network.go index 5375072..ff7cc52 100644 --- a/zerotier/resource_zerotier_network.go +++ b/zerotier/resource_zerotier_network.go @@ -1,4 +1,4 @@ -package main +package zerotier import ( "bytes" @@ -8,17 +8,18 @@ import ( "github.com/hashicorp/terraform/helper/hashcode" "github.com/hashicorp/terraform/helper/schema" + "github.com/hashicorp/terraform/helper/validation" ) func route() *schema.Resource { return &schema.Resource{ Schema: map[string]*schema.Schema{ - "target": &schema.Schema{ + "target": { Type: schema.TypeString, Required: true, DiffSuppressFunc: diffSuppress, }, - "via": &schema.Schema{ + "via": { Type: schema.TypeString, Optional: true, DiffSuppressFunc: diffSuppress, @@ -27,6 +28,28 @@ func route() *schema.Resource { } } +func assignmentPool() *schema.Resource { + return &schema.Resource{ + Schema: map[string]*schema.Schema{ + "cidr": { + Type: schema.TypeString, + Optional: true, + ConflictsWith: []string{"assignment_pool.first", "assignment_pool.last"}, + }, + "first": { + Type: schema.TypeString, + Optional: true, + ConflictsWith: []string{"assignment_pool.cidr"}, + }, + "last": { + Type: schema.TypeString, + Optional: true, + ConflictsWith: []string{"assignment_pool.cidr"}, + }, + }, + } +} + func resourceZeroTierNetwork() *schema.Resource { return &schema.Resource{ Create: resourceNetworkCreate, @@ -34,62 +57,79 @@ func resourceZeroTierNetwork() *schema.Resource { Update: resourceNetworkUpdate, Delete: resourceNetworkDelete, Exists: resourceNetworkExists, + Importer: &schema.ResourceImporter{ + State: schema.ImportStatePassthrough, + }, Schema: map[string]*schema.Schema{ - "name": &schema.Schema{ + "name": { Type: schema.TypeString, Required: true, }, - "description": &schema.Schema{ + "description": { Type: schema.TypeString, Optional: true, Default: "Managed by Terraform", }, - "rules_source": &schema.Schema{ + "rules_source": { Type: schema.TypeString, Optional: true, // pulled from ZT's default Default: "#\n# Allow only IPv4, IPv4 ARP, and IPv6 Ethernet frames.\n#\ndrop\n\tnot ethertype ipv4\n\tand not ethertype arp\n\tand not ethertype ipv6\n;\n\n#\n# Uncomment to drop non-ZeroTier issued and managed IP addresses.\n#\n# This prevents IP spoofing but also blocks manual IP management at the OS level and\n# bridging unless special rules to exempt certain hosts or traffic are added before\n# this rule.\n#\n#drop\n#\tnot chr ipauth\n#;\n\n# Accept anything else. This is required since default is 'drop'.\naccept;", Set: stringHash, }, - "private": &schema.Schema{ + "private": { Type: schema.TypeBool, Optional: true, Default: true, }, - "auto_assign_v4": &schema.Schema{ + "auto_assign_v4": { Type: schema.TypeBool, Optional: true, Default: true, }, - "route": &schema.Schema{ - Type: schema.TypeList, + "auto_assign_v6": { + Type: schema.TypeBool, + Description: "Auto assign IPv6 to members from ZeroTier assignment pool", + Optional: true, + Default: false, + }, + "auto_assign_6plane": { + Type: schema.TypeBool, + Description: "Auto assign IPv6 /60 to members using 6PLANE adressing", + Optional: true, + Default: false, + }, + "auto_assign_rfc4193": { + Type: schema.TypeBool, + Description: "Auto assign IPv6 /128 to members using RFC4193 adressing", + Optional: true, + Default: true, + }, + //Warning: Undecoumented on the API, but that is how the UI manages it + "broadcast": { + Type: schema.TypeBool, + Description: "Enable network broadcast (ff:ff:ff:ff:ff:ff)", + Optional: true, + Default: true, + }, + "multicast_limit": { + Type: schema.TypeInt, + Description: "The maximum number of recipients that can receive an Ethernet multicast or broadcast. Setting to 0 disables multicast, but be aware that only IPv6 with NDP emulation (RFC4193 or 6PLANE addressing modes) or other unicast-only protocols will work without multicast.", + Optional: true, + Default: 32, + ValidateFunc: validation.IntAtLeast(0), + }, + "route": { + Type: schema.TypeSet, Optional: true, Elem: route(), }, - "assignment_pool": &schema.Schema{ + "assignment_pool": { Type: schema.TypeSet, Optional: true, - Elem: &schema.Resource{ - Schema: map[string]*schema.Schema{ - "cidr": &schema.Schema{ - Type: schema.TypeString, - Optional: true, - ConflictsWith: []string{"assignment_pool.first", "assignment_pool.last"}, - }, - "first": &schema.Schema{ - Type: schema.TypeString, - Optional: true, - ConflictsWith: []string{"assignment_pool.cidr"}, - }, - "last": &schema.Schema{ - Type: schema.TypeString, - Optional: true, - ConflictsWith: []string{"assignment_pool.cidr"}, - }, - }, - }, - Set: resourceIpAssignmentHash, + Elem: assignmentPool(), + Set: resourceIpAssignmentHash, }, }, } @@ -113,7 +153,7 @@ func resourceNetworkExists(d *schema.ResourceData, m interface{}) (b bool, e err } func fromResourceData(d *schema.ResourceData) (*Network, error) { - routesRaw := d.Get("route").([]interface{}) + routesRaw := d.Get("route").(*schema.Set).List() var routes []Route for _, raw := range routesRaw { r := raw.(map[string]interface{}) @@ -142,9 +182,18 @@ func fromResourceData(d *schema.ResourceData) (*Network, error) { RulesSource: d.Get("rules_source").(string), Description: d.Get("description").(string), Config: &Config{ - Name: d.Get("name").(string), - Private: d.Get("private").(bool), - V4AssignMode: V4AssignModeConfig{ZT: true}, + Name: d.Get("name").(string), + Private: d.Get("private").(bool), + EnableBroadcast: d.Get("broadcast").(bool), + MulticastLimit: d.Get("multicast_limit").(int), + V4AssignMode: V4AssignModeConfig{ + ZT: d.Get("auto_assign_v4").(bool), + }, + V6AssignMode: V6AssignModeConfig{ + ZT: d.Get("auto_assign_v6").(bool), + SixPLANE: d.Get("auto_assign_6plane").(bool), + RFC4193: d.Get("auto_assign_rfc4193").(bool), + }, Routes: routes, IpAssignmentPools: pools, }, @@ -186,7 +235,12 @@ func resourceNetworkRead(d *schema.ResourceData, m interface{}) error { d.Set("name", net.Config.Name) d.Set("description", net.Description) d.Set("private", net.Config.Private) + d.Set("broadcast", net.Config.EnableBroadcast) + d.Set("multicast_limit", net.Config.MulticastLimit) d.Set("auto_assign_v4", net.Config.V4AssignMode.ZT) + d.Set("auto_assign_v6", net.Config.V6AssignMode.ZT) + d.Set("auto_assign_6plane", net.Config.V6AssignMode.SixPLANE) + d.Set("auto_assign_rfc4193", net.Config.V6AssignMode.RFC4193) d.Set("rules_source", net.RulesSource) setRoutes(d, net)