diff options
author | Radek Simko <radek.simko@gmail.com> | 2017-08-10 14:38:14 +0200 |
---|---|---|
committer | Radek Simko <radek.simko@gmail.com> | 2017-08-10 14:38:14 +0200 |
commit | c680a8e1622ed0f18751d9d167c836ee24f5e897 (patch) | |
tree | 864f925049d422033dd25a73bafce32b361c8827 /vendor/github.com | |
parent | 38f8880ac81bfabc6d7f82e4dc89661f20fc559e (diff) | |
download | terraform-provider-statuscake-c680a8e1622ed0f18751d9d167c836ee24f5e897.tar.gz terraform-provider-statuscake-c680a8e1622ed0f18751d9d167c836ee24f5e897.tar.zst terraform-provider-statuscake-c680a8e1622ed0f18751d9d167c836ee24f5e897.zip |
vendor: github.com/hashicorp/terraform/...@v0.10.0
Diffstat (limited to 'vendor/github.com')
58 files changed, 4155 insertions, 204 deletions
diff --git a/vendor/github.com/blang/semver/LICENSE b/vendor/github.com/blang/semver/LICENSE new file mode 100644 index 0000000..5ba5c86 --- /dev/null +++ b/vendor/github.com/blang/semver/LICENSE | |||
@@ -0,0 +1,22 @@ | |||
1 | The MIT License | ||
2 | |||
3 | Copyright (c) 2014 Benedikt Lang <github at benediktlang.de> | ||
4 | |||
5 | Permission is hereby granted, free of charge, to any person obtaining a copy | ||
6 | of this software and associated documentation files (the "Software"), to deal | ||
7 | in the Software without restriction, including without limitation the rights | ||
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | ||
9 | copies of the Software, and to permit persons to whom the Software is | ||
10 | furnished to do so, subject to the following conditions: | ||
11 | |||
12 | The above copyright notice and this permission notice shall be included in | ||
13 | all copies or substantial portions of the Software. | ||
14 | |||
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | ||
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | ||
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN | ||
21 | THE SOFTWARE. | ||
22 | |||
diff --git a/vendor/github.com/blang/semver/README.md b/vendor/github.com/blang/semver/README.md new file mode 100644 index 0000000..08b2e4a --- /dev/null +++ b/vendor/github.com/blang/semver/README.md | |||
@@ -0,0 +1,194 @@ | |||
1 | semver for golang [![Build Status](https://travis-ci.org/blang/semver.svg?branch=master)](https://travis-ci.org/blang/semver) [![GoDoc](https://godoc.org/github.com/blang/semver?status.png)](https://godoc.org/github.com/blang/semver) [![Coverage Status](https://img.shields.io/coveralls/blang/semver.svg)](https://coveralls.io/r/blang/semver?branch=master) | ||
2 | ====== | ||
3 | |||
4 | semver is a [Semantic Versioning](http://semver.org/) library written in golang. It fully covers spec version `2.0.0`. | ||
5 | |||
6 | Usage | ||
7 | ----- | ||
8 | ```bash | ||
9 | $ go get github.com/blang/semver | ||
10 | ``` | ||
11 | Note: Always vendor your dependencies or fix on a specific version tag. | ||
12 | |||
13 | ```go | ||
14 | import github.com/blang/semver | ||
15 | v1, err := semver.Make("1.0.0-beta") | ||
16 | v2, err := semver.Make("2.0.0-beta") | ||
17 | v1.Compare(v2) | ||
18 | ``` | ||
19 | |||
20 | Also check the [GoDocs](http://godoc.org/github.com/blang/semver). | ||
21 | |||
22 | Why should I use this lib? | ||
23 | ----- | ||
24 | |||
25 | - Fully spec compatible | ||
26 | - No reflection | ||
27 | - No regex | ||
28 | - Fully tested (Coverage >99%) | ||
29 | - Readable parsing/validation errors | ||
30 | - Fast (See [Benchmarks](#benchmarks)) | ||
31 | - Only Stdlib | ||
32 | - Uses values instead of pointers | ||
33 | - Many features, see below | ||
34 | |||
35 | |||
36 | Features | ||
37 | ----- | ||
38 | |||
39 | - Parsing and validation at all levels | ||
40 | - Comparator-like comparisons | ||
41 | - Compare Helper Methods | ||
42 | - InPlace manipulation | ||
43 | - Ranges `>=1.0.0 <2.0.0 || >=3.0.0 !3.0.1-beta.1` | ||
44 | - Wildcards `>=1.x`, `<=2.5.x` | ||
45 | - Sortable (implements sort.Interface) | ||
46 | - database/sql compatible (sql.Scanner/Valuer) | ||
47 | - encoding/json compatible (json.Marshaler/Unmarshaler) | ||
48 | |||
49 | Ranges | ||
50 | ------ | ||
51 | |||
52 | A `Range` is a set of conditions which specify which versions satisfy the range. | ||
53 | |||
54 | A condition is composed of an operator and a version. The supported operators are: | ||
55 | |||
56 | - `<1.0.0` Less than `1.0.0` | ||
57 | - `<=1.0.0` Less than or equal to `1.0.0` | ||
58 | - `>1.0.0` Greater than `1.0.0` | ||
59 | - `>=1.0.0` Greater than or equal to `1.0.0` | ||
60 | - `1.0.0`, `=1.0.0`, `==1.0.0` Equal to `1.0.0` | ||
61 | - `!1.0.0`, `!=1.0.0` Not equal to `1.0.0`. Excludes version `1.0.0`. | ||
62 | |||
63 | Note that spaces between the operator and the version will be gracefully tolerated. | ||
64 | |||
65 | A `Range` can link multiple `Ranges` separated by space: | ||
66 | |||
67 | Ranges can be linked by logical AND: | ||
68 | |||
69 | - `>1.0.0 <2.0.0` would match between both ranges, so `1.1.1` and `1.8.7` but not `1.0.0` or `2.0.0` | ||
70 | - `>1.0.0 <3.0.0 !2.0.3-beta.2` would match every version between `1.0.0` and `3.0.0` except `2.0.3-beta.2` | ||
71 | |||
72 | Ranges can also be linked by logical OR: | ||
73 | |||
74 | - `<2.0.0 || >=3.0.0` would match `1.x.x` and `3.x.x` but not `2.x.x` | ||
75 | |||
76 | AND has a higher precedence than OR. It's not possible to use brackets. | ||
77 | |||
78 | Ranges can be combined by both AND and OR | ||
79 | |||
80 | - `>1.0.0 <2.0.0 || >3.0.0 !4.2.1` would match `1.2.3`, `1.9.9`, `3.1.1`, but not `4.2.1`, `2.1.1` | ||
81 | |||
82 | Range usage: | ||
83 | |||
84 | ``` | ||
85 | v, err := semver.Parse("1.2.3") | ||
86 | range, err := semver.ParseRange(">1.0.0 <2.0.0 || >=3.0.0") | ||
87 | if range(v) { | ||
88 | //valid | ||
89 | } | ||
90 | |||
91 | ``` | ||
92 | |||
93 | Example | ||
94 | ----- | ||
95 | |||
96 | Have a look at full examples in [examples/main.go](examples/main.go) | ||
97 | |||
98 | ```go | ||
99 | import github.com/blang/semver | ||
100 | |||
101 | v, err := semver.Make("0.0.1-alpha.preview+123.github") | ||
102 | fmt.Printf("Major: %d\n", v.Major) | ||
103 | fmt.Printf("Minor: %d\n", v.Minor) | ||
104 | fmt.Printf("Patch: %d\n", v.Patch) | ||
105 | fmt.Printf("Pre: %s\n", v.Pre) | ||
106 | fmt.Printf("Build: %s\n", v.Build) | ||
107 | |||
108 | // Prerelease versions array | ||
109 | if len(v.Pre) > 0 { | ||
110 | fmt.Println("Prerelease versions:") | ||
111 | for i, pre := range v.Pre { | ||
112 | fmt.Printf("%d: %q\n", i, pre) | ||
113 | } | ||
114 | } | ||
115 | |||
116 | // Build meta data array | ||
117 | if len(v.Build) > 0 { | ||
118 | fmt.Println("Build meta data:") | ||
119 | for i, build := range v.Build { | ||
120 | fmt.Printf("%d: %q\n", i, build) | ||
121 | } | ||
122 | } | ||
123 | |||
124 | v001, err := semver.Make("0.0.1") | ||
125 | // Compare using helpers: v.GT(v2), v.LT, v.GTE, v.LTE | ||
126 | v001.GT(v) == true | ||
127 | v.LT(v001) == true | ||
128 | v.GTE(v) == true | ||
129 | v.LTE(v) == true | ||
130 | |||
131 | // Or use v.Compare(v2) for comparisons (-1, 0, 1): | ||
132 | v001.Compare(v) == 1 | ||
133 | v.Compare(v001) == -1 | ||
134 | v.Compare(v) == 0 | ||
135 | |||
136 | // Manipulate Version in place: | ||
137 | v.Pre[0], err = semver.NewPRVersion("beta") | ||
138 | if err != nil { | ||
139 | fmt.Printf("Error parsing pre release version: %q", err) | ||
140 | } | ||
141 | |||
142 | fmt.Println("\nValidate versions:") | ||
143 | v.Build[0] = "?" | ||
144 | |||
145 | err = v.Validate() | ||
146 | if err != nil { | ||
147 | fmt.Printf("Validation failed: %s\n", err) | ||
148 | } | ||
149 | ``` | ||
150 | |||
151 | |||
152 | Benchmarks | ||
153 | ----- | ||
154 | |||
155 | BenchmarkParseSimple-4 5000000 390 ns/op 48 B/op 1 allocs/op | ||
156 | BenchmarkParseComplex-4 1000000 1813 ns/op 256 B/op 7 allocs/op | ||
157 | BenchmarkParseAverage-4 1000000 1171 ns/op 163 B/op 4 allocs/op | ||
158 | BenchmarkStringSimple-4 20000000 119 ns/op 16 B/op 1 allocs/op | ||
159 | BenchmarkStringLarger-4 10000000 206 ns/op 32 B/op 2 allocs/op | ||
160 | BenchmarkStringComplex-4 5000000 324 ns/op 80 B/op 3 allocs/op | ||
161 | BenchmarkStringAverage-4 5000000 273 ns/op 53 B/op 2 allocs/op | ||
162 | BenchmarkValidateSimple-4 200000000 9.33 ns/op 0 B/op 0 allocs/op | ||
163 | BenchmarkValidateComplex-4 3000000 469 ns/op 0 B/op 0 allocs/op | ||
164 | BenchmarkValidateAverage-4 5000000 256 ns/op 0 B/op 0 allocs/op | ||
165 | BenchmarkCompareSimple-4 100000000 11.8 ns/op 0 B/op 0 allocs/op | ||
166 | BenchmarkCompareComplex-4 50000000 30.8 ns/op 0 B/op 0 allocs/op | ||
167 | BenchmarkCompareAverage-4 30000000 41.5 ns/op 0 B/op 0 allocs/op | ||
168 | BenchmarkSort-4 3000000 419 ns/op 256 B/op 2 allocs/op | ||
169 | BenchmarkRangeParseSimple-4 2000000 850 ns/op 192 B/op 5 allocs/op | ||
170 | BenchmarkRangeParseAverage-4 1000000 1677 ns/op 400 B/op 10 allocs/op | ||
171 | BenchmarkRangeParseComplex-4 300000 5214 ns/op 1440 B/op 30 allocs/op | ||
172 | BenchmarkRangeMatchSimple-4 50000000 25.6 ns/op 0 B/op 0 allocs/op | ||
173 | BenchmarkRangeMatchAverage-4 30000000 56.4 ns/op 0 B/op 0 allocs/op | ||
174 | BenchmarkRangeMatchComplex-4 10000000 153 ns/op 0 B/op 0 allocs/op | ||
175 | |||
176 | See benchmark cases at [semver_test.go](semver_test.go) | ||
177 | |||
178 | |||
179 | Motivation | ||
180 | ----- | ||
181 | |||
182 | I simply couldn't find any lib supporting the full spec. Others were just wrong or used reflection and regex which i don't like. | ||
183 | |||
184 | |||
185 | Contribution | ||
186 | ----- | ||
187 | |||
188 | Feel free to make a pull request. For bigger changes create a issue first to discuss about it. | ||
189 | |||
190 | |||
191 | License | ||
192 | ----- | ||
193 | |||
194 | See [LICENSE](LICENSE) file. | ||
diff --git a/vendor/github.com/blang/semver/json.go b/vendor/github.com/blang/semver/json.go new file mode 100644 index 0000000..a74bf7c --- /dev/null +++ b/vendor/github.com/blang/semver/json.go | |||
@@ -0,0 +1,23 @@ | |||
1 | package semver | ||
2 | |||
3 | import ( | ||
4 | "encoding/json" | ||
5 | ) | ||
6 | |||
7 | // MarshalJSON implements the encoding/json.Marshaler interface. | ||
8 | func (v Version) MarshalJSON() ([]byte, error) { | ||
9 | return json.Marshal(v.String()) | ||
10 | } | ||
11 | |||
12 | // UnmarshalJSON implements the encoding/json.Unmarshaler interface. | ||
13 | func (v *Version) UnmarshalJSON(data []byte) (err error) { | ||
14 | var versionString string | ||
15 | |||
16 | if err = json.Unmarshal(data, &versionString); err != nil { | ||
17 | return | ||
18 | } | ||
19 | |||
20 | *v, err = Parse(versionString) | ||
21 | |||
22 | return | ||
23 | } | ||
diff --git a/vendor/github.com/blang/semver/package.json b/vendor/github.com/blang/semver/package.json new file mode 100644 index 0000000..1cf8ebd --- /dev/null +++ b/vendor/github.com/blang/semver/package.json | |||
@@ -0,0 +1,17 @@ | |||
1 | { | ||
2 | "author": "blang", | ||
3 | "bugs": { | ||
4 | "URL": "https://github.com/blang/semver/issues", | ||
5 | "url": "https://github.com/blang/semver/issues" | ||
6 | }, | ||
7 | "gx": { | ||
8 | "dvcsimport": "github.com/blang/semver" | ||
9 | }, | ||
10 | "gxVersion": "0.10.0", | ||
11 | "language": "go", | ||
12 | "license": "MIT", | ||
13 | "name": "semver", | ||
14 | "releaseCmd": "git commit -a -m \"gx publish $VERSION\"", | ||
15 | "version": "3.5.1" | ||
16 | } | ||
17 | |||
diff --git a/vendor/github.com/blang/semver/range.go b/vendor/github.com/blang/semver/range.go new file mode 100644 index 0000000..fca406d --- /dev/null +++ b/vendor/github.com/blang/semver/range.go | |||
@@ -0,0 +1,416 @@ | |||
1 | package semver | ||
2 | |||
3 | import ( | ||
4 | "fmt" | ||
5 | "strconv" | ||
6 | "strings" | ||
7 | "unicode" | ||
8 | ) | ||
9 | |||
10 | type wildcardType int | ||
11 | |||
12 | const ( | ||
13 | noneWildcard wildcardType = iota | ||
14 | majorWildcard wildcardType = 1 | ||
15 | minorWildcard wildcardType = 2 | ||
16 | patchWildcard wildcardType = 3 | ||
17 | ) | ||
18 | |||
19 | func wildcardTypefromInt(i int) wildcardType { | ||
20 | switch i { | ||
21 | case 1: | ||
22 | return majorWildcard | ||
23 | case 2: | ||
24 | return minorWildcard | ||
25 | case 3: | ||
26 | return patchWildcard | ||
27 | default: | ||
28 | return noneWildcard | ||
29 | } | ||
30 | } | ||
31 | |||
32 | type comparator func(Version, Version) bool | ||
33 | |||
34 | var ( | ||
35 | compEQ comparator = func(v1 Version, v2 Version) bool { | ||
36 | return v1.Compare(v2) == 0 | ||
37 | } | ||
38 | compNE = func(v1 Version, v2 Version) bool { | ||
39 | return v1.Compare(v2) != 0 | ||
40 | } | ||
41 | compGT = func(v1 Version, v2 Version) bool { | ||
42 | return v1.Compare(v2) == 1 | ||
43 | } | ||
44 | compGE = func(v1 Version, v2 Version) bool { | ||
45 | return v1.Compare(v2) >= 0 | ||
46 | } | ||
47 | compLT = func(v1 Version, v2 Version) bool { | ||
48 | return v1.Compare(v2) == -1 | ||
49 | } | ||
50 | compLE = func(v1 Version, v2 Version) bool { | ||
51 | return v1.Compare(v2) <= 0 | ||
52 | } | ||
53 | ) | ||
54 | |||
55 | type versionRange struct { | ||
56 | v Version | ||
57 | c comparator | ||
58 | } | ||
59 | |||
60 | // rangeFunc creates a Range from the given versionRange. | ||
61 | func (vr *versionRange) rangeFunc() Range { | ||
62 | return Range(func(v Version) bool { | ||
63 | return vr.c(v, vr.v) | ||
64 | }) | ||
65 | } | ||
66 | |||
67 | // Range represents a range of versions. | ||
68 | // A Range can be used to check if a Version satisfies it: | ||
69 | // | ||
70 | // range, err := semver.ParseRange(">1.0.0 <2.0.0") | ||
71 | // range(semver.MustParse("1.1.1") // returns true | ||
72 | type Range func(Version) bool | ||
73 | |||
74 | // OR combines the existing Range with another Range using logical OR. | ||
75 | func (rf Range) OR(f Range) Range { | ||
76 | return Range(func(v Version) bool { | ||
77 | return rf(v) || f(v) | ||
78 | }) | ||
79 | } | ||
80 | |||
81 | // AND combines the existing Range with another Range using logical AND. | ||
82 | func (rf Range) AND(f Range) Range { | ||
83 | return Range(func(v Version) bool { | ||
84 | return rf(v) && f(v) | ||
85 | }) | ||
86 | } | ||
87 | |||
88 | // ParseRange parses a range and returns a Range. | ||
89 | // If the range could not be parsed an error is returned. | ||
90 | // | ||
91 | // Valid ranges are: | ||
92 | // - "<1.0.0" | ||
93 | // - "<=1.0.0" | ||
94 | // - ">1.0.0" | ||
95 | // - ">=1.0.0" | ||
96 | // - "1.0.0", "=1.0.0", "==1.0.0" | ||
97 | // - "!1.0.0", "!=1.0.0" | ||
98 | // | ||
99 | // A Range can consist of multiple ranges separated by space: | ||
100 | // Ranges can be linked by logical AND: | ||
101 | // - ">1.0.0 <2.0.0" would match between both ranges, so "1.1.1" and "1.8.7" but not "1.0.0" or "2.0.0" | ||
102 | // - ">1.0.0 <3.0.0 !2.0.3-beta.2" would match every version between 1.0.0 and 3.0.0 except 2.0.3-beta.2 | ||
103 | // | ||
104 | // Ranges can also be linked by logical OR: | ||
105 | // - "<2.0.0 || >=3.0.0" would match "1.x.x" and "3.x.x" but not "2.x.x" | ||
106 | // | ||
107 | // AND has a higher precedence than OR. It's not possible to use brackets. | ||
108 | // | ||
109 | // Ranges can be combined by both AND and OR | ||
110 | // | ||
111 | // - `>1.0.0 <2.0.0 || >3.0.0 !4.2.1` would match `1.2.3`, `1.9.9`, `3.1.1`, but not `4.2.1`, `2.1.1` | ||
112 | func ParseRange(s string) (Range, error) { | ||
113 | parts := splitAndTrim(s) | ||
114 | orParts, err := splitORParts(parts) | ||
115 | if err != nil { | ||
116 | return nil, err | ||
117 | } | ||
118 | expandedParts, err := expandWildcardVersion(orParts) | ||
119 | if err != nil { | ||
120 | return nil, err | ||
121 | } | ||
122 | var orFn Range | ||
123 | for _, p := range expandedParts { | ||
124 | var andFn Range | ||
125 | for _, ap := range p { | ||
126 | opStr, vStr, err := splitComparatorVersion(ap) | ||
127 | if err != nil { | ||
128 | return nil, err | ||
129 | } | ||
130 | vr, err := buildVersionRange(opStr, vStr) | ||
131 | if err != nil { | ||
132 | return nil, fmt.Errorf("Could not parse Range %q: %s", ap, err) | ||
133 | } | ||
134 | rf := vr.rangeFunc() | ||
135 | |||
136 | // Set function | ||
137 | if andFn == nil { | ||
138 | andFn = rf | ||
139 | } else { // Combine with existing function | ||
140 | andFn = andFn.AND(rf) | ||
141 | } | ||
142 | } | ||
143 | if orFn == nil { | ||
144 | orFn = andFn | ||
145 | } else { | ||
146 | orFn = orFn.OR(andFn) | ||
147 | } | ||
148 | |||
149 | } | ||
150 | return orFn, nil | ||
151 | } | ||
152 | |||
153 | // splitORParts splits the already cleaned parts by '||'. | ||
154 | // Checks for invalid positions of the operator and returns an | ||
155 | // error if found. | ||
156 | func splitORParts(parts []string) ([][]string, error) { | ||
157 | var ORparts [][]string | ||
158 | last := 0 | ||
159 | for i, p := range parts { | ||
160 | if p == "||" { | ||
161 | if i == 0 { | ||
162 | return nil, fmt.Errorf("First element in range is '||'") | ||
163 | } | ||
164 | ORparts = append(ORparts, parts[last:i]) | ||
165 | last = i + 1 | ||
166 | } | ||
167 | } | ||
168 | if last == len(parts) { | ||
169 | return nil, fmt.Errorf("Last element in range is '||'") | ||
170 | } | ||
171 | ORparts = append(ORparts, parts[last:]) | ||
172 | return ORparts, nil | ||
173 | } | ||
174 | |||
175 | // buildVersionRange takes a slice of 2: operator and version | ||
176 | // and builds a versionRange, otherwise an error. | ||
177 | func buildVersionRange(opStr, vStr string) (*versionRange, error) { | ||
178 | c := parseComparator(opStr) | ||
179 | if c == nil { | ||
180 | return nil, fmt.Errorf("Could not parse comparator %q in %q", opStr, strings.Join([]string{opStr, vStr}, "")) | ||
181 | } | ||
182 | v, err := Parse(vStr) | ||
183 | if err != nil { | ||
184 | return nil, fmt.Errorf("Could not parse version %q in %q: %s", vStr, strings.Join([]string{opStr, vStr}, ""), err) | ||
185 | } | ||
186 | |||
187 | return &versionRange{ | ||
188 | v: v, | ||
189 | c: c, | ||
190 | }, nil | ||
191 | |||
192 | } | ||
193 | |||
194 | // inArray checks if a byte is contained in an array of bytes | ||
195 | func inArray(s byte, list []byte) bool { | ||
196 | for _, el := range list { | ||
197 | if el == s { | ||
198 | return true | ||
199 | } | ||
200 | } | ||
201 | return false | ||
202 | } | ||
203 | |||
204 | // splitAndTrim splits a range string by spaces and cleans whitespaces | ||
205 | func splitAndTrim(s string) (result []string) { | ||
206 | last := 0 | ||
207 | var lastChar byte | ||
208 | excludeFromSplit := []byte{'>', '<', '='} | ||
209 | for i := 0; i < len(s); i++ { | ||
210 | if s[i] == ' ' && !inArray(lastChar, excludeFromSplit) { | ||
211 | if last < i-1 { | ||
212 | result = append(result, s[last:i]) | ||
213 | } | ||
214 | last = i + 1 | ||
215 | } else if s[i] != ' ' { | ||
216 | lastChar = s[i] | ||
217 | } | ||
218 | } | ||
219 | if last < len(s)-1 { | ||
220 | result = append(result, s[last:]) | ||
221 | } | ||
222 | |||
223 | for i, v := range result { | ||
224 | result[i] = strings.Replace(v, " ", "", -1) | ||
225 | } | ||
226 | |||
227 | // parts := strings.Split(s, " ") | ||
228 | // for _, x := range parts { | ||
229 | // if s := strings.TrimSpace(x); len(s) != 0 { | ||
230 | // result = append(result, s) | ||
231 | // } | ||
232 | // } | ||
233 | return | ||
234 | } | ||
235 | |||
236 | // splitComparatorVersion splits the comparator from the version. | ||
237 | // Input must be free of leading or trailing spaces. | ||
238 | func splitComparatorVersion(s string) (string, string, error) { | ||
239 | i := strings.IndexFunc(s, unicode.IsDigit) | ||
240 | if i == -1 { | ||
241 | return "", "", fmt.Errorf("Could not get version from string: %q", s) | ||
242 | } | ||
243 | return strings.TrimSpace(s[0:i]), s[i:], nil | ||
244 | } | ||
245 | |||
246 | // getWildcardType will return the type of wildcard that the | ||
247 | // passed version contains | ||
248 | func getWildcardType(vStr string) wildcardType { | ||
249 | parts := strings.Split(vStr, ".") | ||
250 | nparts := len(parts) | ||
251 | wildcard := parts[nparts-1] | ||
252 | |||
253 | possibleWildcardType := wildcardTypefromInt(nparts) | ||
254 | if wildcard == "x" { | ||
255 | return possibleWildcardType | ||
256 | } | ||
257 | |||
258 | return noneWildcard | ||
259 | } | ||
260 | |||
261 | // createVersionFromWildcard will convert a wildcard version | ||
262 | // into a regular version, replacing 'x's with '0's, handling | ||
263 | // special cases like '1.x.x' and '1.x' | ||
264 | func createVersionFromWildcard(vStr string) string { | ||
265 | // handle 1.x.x | ||
266 | vStr2 := strings.Replace(vStr, ".x.x", ".x", 1) | ||
267 | vStr2 = strings.Replace(vStr2, ".x", ".0", 1) | ||
268 | parts := strings.Split(vStr2, ".") | ||
269 | |||
270 | // handle 1.x | ||
271 | if len(parts) == 2 { | ||
272 | return vStr2 + ".0" | ||
273 | } | ||
274 | |||
275 | return vStr2 | ||
276 | } | ||
277 | |||
278 | // incrementMajorVersion will increment the major version | ||
279 | // of the passed version | ||
280 | func incrementMajorVersion(vStr string) (string, error) { | ||
281 | parts := strings.Split(vStr, ".") | ||
282 | i, err := strconv.Atoi(parts[0]) | ||
283 | if err != nil { | ||
284 | return "", err | ||
285 | } | ||
286 | parts[0] = strconv.Itoa(i + 1) | ||
287 | |||
288 | return strings.Join(parts, "."), nil | ||
289 | } | ||
290 | |||
291 | // incrementMajorVersion will increment the minor version | ||
292 | // of the passed version | ||
293 | func incrementMinorVersion(vStr string) (string, error) { | ||
294 | parts := strings.Split(vStr, ".") | ||
295 | i, err := strconv.Atoi(parts[1]) | ||
296 | if err != nil { | ||
297 | return "", err | ||
298 | } | ||
299 | parts[1] = strconv.Itoa(i + 1) | ||
300 | |||
301 | return strings.Join(parts, "."), nil | ||
302 | } | ||
303 | |||
304 | // expandWildcardVersion will expand wildcards inside versions | ||
305 | // following these rules: | ||
306 | // | ||
307 | // * when dealing with patch wildcards: | ||
308 | // >= 1.2.x will become >= 1.2.0 | ||
309 | // <= 1.2.x will become < 1.3.0 | ||
310 | // > 1.2.x will become >= 1.3.0 | ||
311 | // < 1.2.x will become < 1.2.0 | ||
312 | // != 1.2.x will become < 1.2.0 >= 1.3.0 | ||
313 | // | ||
314 | // * when dealing with minor wildcards: | ||
315 | // >= 1.x will become >= 1.0.0 | ||
316 | // <= 1.x will become < 2.0.0 | ||
317 | // > 1.x will become >= 2.0.0 | ||
318 | // < 1.0 will become < 1.0.0 | ||
319 | // != 1.x will become < 1.0.0 >= 2.0.0 | ||
320 | // | ||
321 | // * when dealing with wildcards without | ||
322 | // version operator: | ||
323 | // 1.2.x will become >= 1.2.0 < 1.3.0 | ||
324 | // 1.x will become >= 1.0.0 < 2.0.0 | ||
325 | func expandWildcardVersion(parts [][]string) ([][]string, error) { | ||
326 | var expandedParts [][]string | ||
327 | for _, p := range parts { | ||
328 | var newParts []string | ||
329 | for _, ap := range p { | ||
330 | if strings.Index(ap, "x") != -1 { | ||
331 | opStr, vStr, err := splitComparatorVersion(ap) | ||
332 | if err != nil { | ||
333 | return nil, err | ||
334 | } | ||
335 | |||
336 | versionWildcardType := getWildcardType(vStr) | ||
337 | flatVersion := createVersionFromWildcard(vStr) | ||
338 | |||
339 | var resultOperator string | ||
340 | var shouldIncrementVersion bool | ||
341 | switch opStr { | ||
342 | case ">": | ||
343 | resultOperator = ">=" | ||
344 | shouldIncrementVersion = true | ||
345 | case ">=": | ||
346 | resultOperator = ">=" | ||
347 | case "<": | ||
348 | resultOperator = "<" | ||
349 | case "<=": | ||
350 | resultOperator = "<" | ||
351 | shouldIncrementVersion = true | ||
352 | case "", "=", "==": | ||
353 | newParts = append(newParts, ">="+flatVersion) | ||
354 | resultOperator = "<" | ||
355 | shouldIncrementVersion = true | ||
356 | case "!=", "!": | ||
357 | newParts = append(newParts, "<"+flatVersion) | ||
358 | resultOperator = ">=" | ||
359 | shouldIncrementVersion = true | ||
360 | } | ||
361 | |||
362 | var resultVersion string | ||
363 | if shouldIncrementVersion { | ||
364 | switch versionWildcardType { | ||
365 | case patchWildcard: | ||
366 | resultVersion, _ = incrementMinorVersion(flatVersion) | ||
367 | case minorWildcard: | ||
368 | resultVersion, _ = incrementMajorVersion(flatVersion) | ||
369 | } | ||
370 | } else { | ||
371 | resultVersion = flatVersion | ||
372 | } | ||
373 | |||
374 | ap = resultOperator + resultVersion | ||
375 | } | ||
376 | newParts = append(newParts, ap) | ||
377 | } | ||
378 | expandedParts = append(expandedParts, newParts) | ||
379 | } | ||
380 | |||
381 | return expandedParts, nil | ||
382 | } | ||
383 | |||
384 | func parseComparator(s string) comparator { | ||
385 | switch s { | ||
386 | case "==": | ||
387 | fallthrough | ||
388 | case "": | ||
389 | fallthrough | ||
390 | case "=": | ||
391 | return compEQ | ||
392 | case ">": | ||
393 | return compGT | ||
394 | case ">=": | ||
395 | return compGE | ||
396 | case "<": | ||
397 | return compLT | ||
398 | case "<=": | ||
399 | return compLE | ||
400 | case "!": | ||
401 | fallthrough | ||
402 | case "!=": | ||
403 | return compNE | ||
404 | } | ||
405 | |||
406 | return nil | ||
407 | } | ||
408 | |||
409 | // MustParseRange is like ParseRange but panics if the range cannot be parsed. | ||
410 | func MustParseRange(s string) Range { | ||
411 | r, err := ParseRange(s) | ||
412 | if err != nil { | ||
413 | panic(`semver: ParseRange(` + s + `): ` + err.Error()) | ||
414 | } | ||
415 | return r | ||
416 | } | ||
diff --git a/vendor/github.com/blang/semver/semver.go b/vendor/github.com/blang/semver/semver.go new file mode 100644 index 0000000..8ee0842 --- /dev/null +++ b/vendor/github.com/blang/semver/semver.go | |||
@@ -0,0 +1,418 @@ | |||
1 | package semver | ||
2 | |||
3 | import ( | ||
4 | "errors" | ||
5 | "fmt" | ||
6 | "strconv" | ||
7 | "strings" | ||
8 | ) | ||
9 | |||
10 | const ( | ||
11 | numbers string = "0123456789" | ||
12 | alphas = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ-" | ||
13 | alphanum = alphas + numbers | ||
14 | ) | ||
15 | |||
16 | // SpecVersion is the latest fully supported spec version of semver | ||
17 | var SpecVersion = Version{ | ||
18 | Major: 2, | ||
19 | Minor: 0, | ||
20 | Patch: 0, | ||
21 | } | ||
22 | |||
23 | // Version represents a semver compatible version | ||
24 | type Version struct { | ||
25 | Major uint64 | ||
26 | Minor uint64 | ||
27 | Patch uint64 | ||
28 | Pre []PRVersion | ||
29 | Build []string //No Precendence | ||
30 | } | ||
31 | |||
32 | // Version to string | ||
33 | func (v Version) String() string { | ||
34 | b := make([]byte, 0, 5) | ||
35 | b = strconv.AppendUint(b, v.Major, 10) | ||
36 | b = append(b, '.') | ||
37 | b = strconv.AppendUint(b, v.Minor, 10) | ||
38 | b = append(b, '.') | ||
39 | b = strconv.AppendUint(b, v.Patch, 10) | ||
40 | |||
41 | if len(v.Pre) > 0 { | ||
42 | b = append(b, '-') | ||
43 | b = append(b, v.Pre[0].String()...) | ||
44 | |||
45 | for _, pre := range v.Pre[1:] { | ||
46 | b = append(b, '.') | ||
47 | b = append(b, pre.String()...) | ||
48 | } | ||
49 | } | ||
50 | |||
51 | if len(v.Build) > 0 { | ||
52 | b = append(b, '+') | ||
53 | b = append(b, v.Build[0]...) | ||
54 | |||
55 | for _, build := range v.Build[1:] { | ||
56 | b = append(b, '.') | ||
57 | b = append(b, build...) | ||
58 | } | ||
59 | } | ||
60 | |||
61 | return string(b) | ||
62 | } | ||
63 | |||
64 | // Equals checks if v is equal to o. | ||
65 | func (v Version) Equals(o Version) bool { | ||
66 | return (v.Compare(o) == 0) | ||
67 | } | ||
68 | |||
69 | // EQ checks if v is equal to o. | ||
70 | func (v Version) EQ(o Version) bool { | ||
71 | return (v.Compare(o) == 0) | ||
72 | } | ||
73 | |||
74 | // NE checks if v is not equal to o. | ||
75 | func (v Version) NE(o Version) bool { | ||
76 | return (v.Compare(o) != 0) | ||
77 | } | ||
78 | |||
79 | // GT checks if v is greater than o. | ||
80 | func (v Version) GT(o Version) bool { | ||
81 | return (v.Compare(o) == 1) | ||
82 | } | ||
83 | |||
84 | // GTE checks if v is greater than or equal to o. | ||
85 | func (v Version) GTE(o Version) bool { | ||
86 | return (v.Compare(o) >= 0) | ||
87 | } | ||
88 | |||
89 | // GE checks if v is greater than or equal to o. | ||
90 | func (v Version) GE(o Version) bool { | ||
91 | return (v.Compare(o) >= 0) | ||
92 | } | ||
93 | |||
94 | // LT checks if v is less than o. | ||
95 | func (v Version) LT(o Version) bool { | ||
96 | return (v.Compare(o) == -1) | ||
97 | } | ||
98 | |||
99 | // LTE checks if v is less than or equal to o. | ||
100 | func (v Version) LTE(o Version) bool { | ||
101 | return (v.Compare(o) <= 0) | ||
102 | } | ||
103 | |||
104 | // LE checks if v is less than or equal to o. | ||
105 | func (v Version) LE(o Version) bool { | ||
106 | return (v.Compare(o) <= 0) | ||
107 | } | ||
108 | |||
109 | // Compare compares Versions v to o: | ||
110 | // -1 == v is less than o | ||
111 | // 0 == v is equal to o | ||
112 | // 1 == v is greater than o | ||
113 | func (v Version) Compare(o Version) int { | ||
114 | if v.Major != o.Major { | ||
115 | if v.Major > o.Major { | ||
116 | return 1 | ||
117 | } | ||
118 | return -1 | ||
119 | } | ||
120 | if v.Minor != o.Minor { | ||
121 | if v.Minor > o.Minor { | ||
122 | return 1 | ||
123 | } | ||
124 | return -1 | ||
125 | } | ||
126 | if v.Patch != o.Patch { | ||
127 | if v.Patch > o.Patch { | ||
128 | return 1 | ||
129 | } | ||
130 | return -1 | ||
131 | } | ||
132 | |||
133 | // Quick comparison if a version has no prerelease versions | ||
134 | if len(v.Pre) == 0 && len(o.Pre) == 0 { | ||
135 | return 0 | ||
136 | } else if len(v.Pre) == 0 && len(o.Pre) > 0 { | ||
137 | return 1 | ||
138 | } else if len(v.Pre) > 0 && len(o.Pre) == 0 { | ||
139 | return -1 | ||
140 | } | ||
141 | |||
142 | i := 0 | ||
143 | for ; i < len(v.Pre) && i < len(o.Pre); i++ { | ||
144 | if comp := v.Pre[i].Compare(o.Pre[i]); comp == 0 { | ||
145 | continue | ||
146 | } else if comp == 1 { | ||
147 | return 1 | ||
148 | } else { | ||
149 | return -1 | ||
150 | } | ||
151 | } | ||
152 | |||
153 | // If all pr versions are the equal but one has further prversion, this one greater | ||
154 | if i == len(v.Pre) && i == len(o.Pre) { | ||
155 | return 0 | ||
156 | } else if i == len(v.Pre) && i < len(o.Pre) { | ||
157 | return -1 | ||
158 | } else { | ||
159 | return 1 | ||
160 | } | ||
161 | |||
162 | } | ||
163 | |||
164 | // Validate validates v and returns error in case | ||
165 | func (v Version) Validate() error { | ||
166 | // Major, Minor, Patch already validated using uint64 | ||
167 | |||
168 | for _, pre := range v.Pre { | ||
169 | if !pre.IsNum { //Numeric prerelease versions already uint64 | ||
170 | if len(pre.VersionStr) == 0 { | ||
171 | return fmt.Errorf("Prerelease can not be empty %q", pre.VersionStr) | ||
172 | } | ||
173 | if !containsOnly(pre.VersionStr, alphanum) { | ||
174 | return fmt.Errorf("Invalid character(s) found in prerelease %q", pre.VersionStr) | ||
175 | } | ||
176 | } | ||
177 | } | ||
178 | |||
179 | for _, build := range v.Build { | ||
180 | if len(build) == 0 { | ||
181 | return fmt.Errorf("Build meta data can not be empty %q", build) | ||
182 | } | ||
183 | if !containsOnly(build, alphanum) { | ||
184 | return fmt.Errorf("Invalid character(s) found in build meta data %q", build) | ||
185 | } | ||
186 | } | ||
187 | |||
188 | return nil | ||
189 | } | ||
190 | |||
191 | // New is an alias for Parse and returns a pointer, parses version string and returns a validated Version or error | ||
192 | func New(s string) (vp *Version, err error) { | ||
193 | v, err := Parse(s) | ||
194 | vp = &v | ||
195 | return | ||
196 | } | ||
197 | |||
198 | // Make is an alias for Parse, parses version string and returns a validated Version or error | ||
199 | func Make(s string) (Version, error) { | ||
200 | return Parse(s) | ||
201 | } | ||
202 | |||
203 | // ParseTolerant allows for certain version specifications that do not strictly adhere to semver | ||
204 | // specs to be parsed by this library. It does so by normalizing versions before passing them to | ||
205 | // Parse(). It currently trims spaces, removes a "v" prefix, and adds a 0 patch number to versions | ||
206 | // with only major and minor components specified | ||
207 | func ParseTolerant(s string) (Version, error) { | ||
208 | s = strings.TrimSpace(s) | ||
209 | s = strings.TrimPrefix(s, "v") | ||
210 | |||
211 | // Split into major.minor.(patch+pr+meta) | ||
212 | parts := strings.SplitN(s, ".", 3) | ||
213 | if len(parts) < 3 { | ||
214 | if strings.ContainsAny(parts[len(parts)-1], "+-") { | ||
215 | return Version{}, errors.New("Short version cannot contain PreRelease/Build meta data") | ||
216 | } | ||
217 | for len(parts) < 3 { | ||
218 | parts = append(parts, "0") | ||
219 | } | ||
220 | s = strings.Join(parts, ".") | ||
221 | } | ||
222 | |||
223 | return Parse(s) | ||
224 | } | ||
225 | |||
226 | // Parse parses version string and returns a validated Version or error | ||
227 | func Parse(s string) (Version, error) { | ||
228 | if len(s) == 0 { | ||
229 | return Version{}, errors.New("Version string empty") | ||
230 | } | ||
231 | |||
232 | // Split into major.minor.(patch+pr+meta) | ||
233 | parts := strings.SplitN(s, ".", 3) | ||
234 | if len(parts) != 3 { | ||
235 | return Version{}, errors.New("No Major.Minor.Patch elements found") | ||
236 | } | ||
237 | |||
238 | // Major | ||
239 | if !containsOnly(parts[0], numbers) { | ||
240 | return Version{}, fmt.Errorf("Invalid character(s) found in major number %q", parts[0]) | ||
241 | } | ||
242 | if hasLeadingZeroes(parts[0]) { | ||
243 | return Version{}, fmt.Errorf("Major number must not contain leading zeroes %q", parts[0]) | ||
244 | } | ||
245 | major, err := strconv.ParseUint(parts[0], 10, 64) | ||
246 | if err != nil { | ||
247 | return Version{}, err | ||
248 | } | ||
249 | |||
250 | // Minor | ||
251 | if !containsOnly(parts[1], numbers) { | ||
252 | return Version{}, fmt.Errorf("Invalid character(s) found in minor number %q", parts[1]) | ||
253 | } | ||
254 | if hasLeadingZeroes(parts[1]) { | ||
255 | return Version{}, fmt.Errorf("Minor number must not contain leading zeroes %q", parts[1]) | ||
256 | } | ||
257 | minor, err := strconv.ParseUint(parts[1], 10, 64) | ||
258 | if err != nil { | ||
259 | return Version{}, err | ||
260 | } | ||
261 | |||
262 | v := Version{} | ||
263 | v.Major = major | ||
264 | v.Minor = minor | ||
265 | |||
266 | var build, prerelease []string | ||
267 | patchStr := parts[2] | ||
268 | |||
269 | if buildIndex := strings.IndexRune(patchStr, '+'); buildIndex != -1 { | ||
270 | build = strings.Split(patchStr[buildIndex+1:], ".") | ||
271 | patchStr = patchStr[:buildIndex] | ||
272 | } | ||
273 | |||
274 | if preIndex := strings.IndexRune(patchStr, '-'); preIndex != -1 { | ||
275 | prerelease = strings.Split(patchStr[preIndex+1:], ".") | ||
276 | patchStr = patchStr[:preIndex] | ||
277 | } | ||
278 | |||
279 | if !containsOnly(patchStr, numbers) { | ||
280 | return Version{}, fmt.Errorf("Invalid character(s) found in patch number %q", patchStr) | ||
281 | } | ||
282 | if hasLeadingZeroes(patchStr) { | ||
283 | return Version{}, fmt.Errorf("Patch number must not contain leading zeroes %q", patchStr) | ||
284 | } | ||
285 | patch, err := strconv.ParseUint(patchStr, 10, 64) | ||
286 | if err != nil { | ||
287 | return Version{}, err | ||
288 | } | ||
289 | |||
290 | v.Patch = patch | ||
291 | |||
292 | // Prerelease | ||
293 | for _, prstr := range prerelease { | ||
294 | parsedPR, err := NewPRVersion(prstr) | ||
295 | if err != nil { | ||
296 | return Version{}, err | ||
297 | } | ||
298 | v.Pre = append(v.Pre, parsedPR) | ||
299 | } | ||
300 | |||
301 | // Build meta data | ||
302 | for _, str := range build { | ||
303 | if len(str) == 0 { | ||
304 | return Version{}, errors.New("Build meta data is empty") | ||
305 | } | ||
306 | if !containsOnly(str, alphanum) { | ||
307 | return Version{}, fmt.Errorf("Invalid character(s) found in build meta data %q", str) | ||
308 | } | ||
309 | v.Build = append(v.Build, str) | ||
310 | } | ||
311 | |||
312 | return v, nil | ||
313 | } | ||
314 | |||
315 | // MustParse is like Parse but panics if the version cannot be parsed. | ||
316 | func MustParse(s string) Version { | ||
317 | v, err := Parse(s) | ||
318 | if err != nil { | ||
319 | panic(`semver: Parse(` + s + `): ` + err.Error()) | ||
320 | } | ||
321 | return v | ||
322 | } | ||
323 | |||
324 | // PRVersion represents a PreRelease Version | ||
325 | type PRVersion struct { | ||
326 | VersionStr string | ||
327 | VersionNum uint64 | ||
328 | IsNum bool | ||
329 | } | ||
330 | |||
331 | // NewPRVersion creates a new valid prerelease version | ||
332 | func NewPRVersion(s string) (PRVersion, error) { | ||
333 | if len(s) == 0 { | ||
334 | return PRVersion{}, errors.New("Prerelease is empty") | ||
335 | } | ||
336 | v := PRVersion{} | ||
337 | if containsOnly(s, numbers) { | ||
338 | if hasLeadingZeroes(s) { | ||
339 | return PRVersion{}, fmt.Errorf("Numeric PreRelease version must not contain leading zeroes %q", s) | ||
340 | } | ||
341 | num, err := strconv.ParseUint(s, 10, 64) | ||
342 | |||
343 | // Might never be hit, but just in case | ||
344 | if err != nil { | ||
345 | return PRVersion{}, err | ||
346 | } | ||
347 | v.VersionNum = num | ||
348 | v.IsNum = true | ||
349 | } else if containsOnly(s, alphanum) { | ||
350 | v.VersionStr = s | ||
351 | v.IsNum = false | ||
352 | } else { | ||
353 | return PRVersion{}, fmt.Errorf("Invalid character(s) found in prerelease %q", s) | ||
354 | } | ||
355 | return v, nil | ||
356 | } | ||
357 | |||
358 | // IsNumeric checks if prerelease-version is numeric | ||
359 | func (v PRVersion) IsNumeric() bool { | ||
360 | return v.IsNum | ||
361 | } | ||
362 | |||
363 | // Compare compares two PreRelease Versions v and o: | ||
364 | // -1 == v is less than o | ||
365 | // 0 == v is equal to o | ||
366 | // 1 == v is greater than o | ||
367 | func (v PRVersion) Compare(o PRVersion) int { | ||
368 | if v.IsNum && !o.IsNum { | ||
369 | return -1 | ||
370 | } else if !v.IsNum && o.IsNum { | ||
371 | return 1 | ||
372 | } else if v.IsNum && o.IsNum { | ||
373 | if v.VersionNum == o.VersionNum { | ||
374 | return 0 | ||
375 | } else if v.VersionNum > o.VersionNum { | ||
376 | return 1 | ||
377 | } else { | ||
378 | return -1 | ||
379 | } | ||
380 | } else { // both are Alphas | ||
381 | if v.VersionStr == o.VersionStr { | ||
382 | return 0 | ||
383 | } else if v.VersionStr > o.VersionStr { | ||
384 | return 1 | ||
385 | } else { | ||
386 | return -1 | ||
387 | } | ||
388 | } | ||
389 | } | ||
390 | |||
391 | // PreRelease version to string | ||
392 | func (v PRVersion) String() string { | ||
393 | if v.IsNum { | ||
394 | return strconv.FormatUint(v.VersionNum, 10) | ||
395 | } | ||
396 | return v.VersionStr | ||
397 | } | ||
398 | |||
399 | func containsOnly(s string, set string) bool { | ||
400 | return strings.IndexFunc(s, func(r rune) bool { | ||
401 | return !strings.ContainsRune(set, r) | ||
402 | }) == -1 | ||
403 | } | ||
404 | |||
405 | func hasLeadingZeroes(s string) bool { | ||
406 | return len(s) > 1 && s[0] == '0' | ||
407 | } | ||
408 | |||
409 | // NewBuildVersion creates a new valid build version | ||
410 | func NewBuildVersion(s string) (string, error) { | ||
411 | if len(s) == 0 { | ||
412 | return "", errors.New("Buildversion is empty") | ||
413 | } | ||
414 | if !containsOnly(s, alphanum) { | ||
415 | return "", fmt.Errorf("Invalid character(s) found in build meta data %q", s) | ||
416 | } | ||
417 | return s, nil | ||
418 | } | ||
diff --git a/vendor/github.com/blang/semver/sort.go b/vendor/github.com/blang/semver/sort.go new file mode 100644 index 0000000..e18f880 --- /dev/null +++ b/vendor/github.com/blang/semver/sort.go | |||
@@ -0,0 +1,28 @@ | |||
1 | package semver | ||
2 | |||
3 | import ( | ||
4 | "sort" | ||
5 | ) | ||
6 | |||
7 | // Versions represents multiple versions. | ||
8 | type Versions []Version | ||
9 | |||
10 | // Len returns length of version collection | ||
11 | func (s Versions) Len() int { | ||
12 | return len(s) | ||
13 | } | ||
14 | |||
15 | // Swap swaps two versions inside the collection by its indices | ||
16 | func (s Versions) Swap(i, j int) { | ||
17 | s[i], s[j] = s[j], s[i] | ||
18 | } | ||
19 | |||
20 | // Less checks if version at index i is less than version at index j | ||
21 | func (s Versions) Less(i, j int) bool { | ||
22 | return s[i].LT(s[j]) | ||
23 | } | ||
24 | |||
25 | // Sort sorts a slice of versions | ||
26 | func Sort(versions []Version) { | ||
27 | sort.Sort(Versions(versions)) | ||
28 | } | ||
diff --git a/vendor/github.com/blang/semver/sql.go b/vendor/github.com/blang/semver/sql.go new file mode 100644 index 0000000..eb4d802 --- /dev/null +++ b/vendor/github.com/blang/semver/sql.go | |||
@@ -0,0 +1,30 @@ | |||
1 | package semver | ||
2 | |||
3 | import ( | ||
4 | "database/sql/driver" | ||
5 | "fmt" | ||
6 | ) | ||
7 | |||
8 | // Scan implements the database/sql.Scanner interface. | ||
9 | func (v *Version) Scan(src interface{}) (err error) { | ||
10 | var str string | ||
11 | switch src := src.(type) { | ||
12 | case string: | ||
13 | str = src | ||
14 | case []byte: | ||
15 | str = string(src) | ||
16 | default: | ||
17 | return fmt.Errorf("Version.Scan: cannot convert %T to string.", src) | ||
18 | } | ||
19 | |||
20 | if t, err := Parse(str); err == nil { | ||
21 | *v = t | ||
22 | } | ||
23 | |||
24 | return | ||
25 | } | ||
26 | |||
27 | // Value implements the database/sql/driver.Valuer interface. | ||
28 | func (v Version) Value() (driver.Value, error) { | ||
29 | return v.String(), nil | ||
30 | } | ||
diff --git a/vendor/github.com/hashicorp/go-cleanhttp/LICENSE b/vendor/github.com/hashicorp/go-cleanhttp/LICENSE new file mode 100644 index 0000000..e87a115 --- /dev/null +++ b/vendor/github.com/hashicorp/go-cleanhttp/LICENSE | |||
@@ -0,0 +1,363 @@ | |||
1 | Mozilla Public License, version 2.0 | ||
2 | |||
3 | 1. Definitions | ||
4 | |||
5 | 1.1. "Contributor" | ||
6 | |||
7 | means each individual or legal entity that creates, contributes to the | ||
8 | creation of, or owns Covered Software. | ||
9 | |||
10 | 1.2. "Contributor Version" | ||
11 | |||
12 | means the combination of the Contributions of others (if any) used by a | ||
13 | Contributor and that particular Contributor's Contribution. | ||
14 | |||
15 | 1.3. "Contribution" | ||
16 | |||
17 | means Covered Software of a particular Contributor. | ||
18 | |||
19 | 1.4. "Covered Software" | ||
20 | |||
21 | means Source Code Form to which the initial Contributor has attached the | ||
22 | notice in Exhibit A, the Executable Form of such Source Code Form, and | ||
23 | Modifications of such Source Code Form, in each case including portions | ||
24 | thereof. | ||
25 | |||
26 | 1.5. "Incompatible With Secondary Licenses" | ||
27 | means | ||
28 | |||
29 | a. that the initial Contributor has attached the notice described in | ||
30 | Exhibit B to the Covered Software; or | ||
31 | |||
32 | b. that the Covered Software was made available under the terms of | ||
33 | version 1.1 or earlier of the License, but not also under the terms of | ||
34 | a Secondary License. | ||
35 | |||
36 | 1.6. "Executable Form" | ||
37 | |||
38 | means any form of the work other than Source Code Form. | ||
39 | |||
40 | 1.7. "Larger Work" | ||
41 | |||
42 | means a work that combines Covered Software with other material, in a | ||
43 | separate file or files, that is not Covered Software. | ||
44 | |||
45 | 1.8. "License" | ||
46 | |||
47 | means this document. | ||
48 | |||
49 | 1.9. "Licensable" | ||
50 | |||
51 | means having the right to grant, to the maximum extent possible, whether | ||
52 | at the time of the initial grant or subsequently, any and all of the | ||
53 | rights conveyed by this License. | ||
54 | |||
55 | 1.10. "Modifications" | ||
56 | |||
57 | means any of the following: | ||
58 | |||
59 | a. any file in Source Code Form that results from an addition to, | ||
60 | deletion from, or modification of the contents of Covered Software; or | ||
61 | |||
62 | b. any new file in Source Code Form that contains any Covered Software. | ||
63 | |||
64 | 1.11. "Patent Claims" of a Contributor | ||
65 | |||
66 | means any patent claim(s), including without limitation, method, | ||
67 | process, and apparatus claims, in any patent Licensable by such | ||
68 | Contributor that would be infringed, but for the grant of the License, | ||
69 | by the making, using, selling, offering for sale, having made, import, | ||
70 | or transfer of either its Contributions or its Contributor Version. | ||
71 | |||
72 | 1.12. "Secondary License" | ||
73 | |||
74 | means either the GNU General Public License, Version 2.0, the GNU Lesser | ||
75 | General Public License, Version 2.1, the GNU Affero General Public | ||
76 | License, Version 3.0, or any later versions of those licenses. | ||
77 | |||
78 | 1.13. "Source Code Form" | ||
79 | |||
80 | means the form of the work preferred for making modifications. | ||
81 | |||
82 | 1.14. "You" (or "Your") | ||
83 | |||
84 | means an individual or a legal entity exercising rights under this | ||
85 | License. For legal entities, "You" includes any entity that controls, is | ||
86 | controlled by, or is under common control with You. For purposes of this | ||
87 | definition, "control" means (a) the power, direct or indirect, to cause | ||
88 | the direction or management of such entity, whether by contract or | ||
89 | otherwise, or (b) ownership of more than fifty percent (50%) of the | ||
90 | outstanding shares or beneficial ownership of such entity. | ||
91 | |||
92 | |||
93 | 2. License Grants and Conditions | ||
94 | |||
95 | 2.1. Grants | ||
96 | |||
97 | Each Contributor hereby grants You a world-wide, royalty-free, | ||
98 | non-exclusive license: | ||
99 | |||
100 | a. under intellectual property rights (other than patent or trademark) | ||
101 | Licensable by such Contributor to use, reproduce, make available, | ||
102 | modify, display, perform, distribute, and otherwise exploit its | ||
103 | Contributions, either on an unmodified basis, with Modifications, or | ||
104 | as part of a Larger Work; and | ||
105 | |||
106 | b. under Patent Claims of such Contributor to make, use, sell, offer for | ||
107 | sale, have made, import, and otherwise transfer either its | ||
108 | Contributions or its Contributor Version. | ||
109 | |||
110 | 2.2. Effective Date | ||
111 | |||
112 | The licenses granted in Section 2.1 with respect to any Contribution | ||
113 | become effective for each Contribution on the date the Contributor first | ||
114 | distributes such Contribution. | ||
115 | |||
116 | 2.3. Limitations on Grant Scope | ||
117 | |||
118 | The licenses granted in this Section 2 are the only rights granted under | ||
119 | this License. No additional rights or licenses will be implied from the | ||
120 | distribution or licensing of Covered Software under this License. | ||
121 | Notwithstanding Section 2.1(b) above, no patent license is granted by a | ||
122 | Contributor: | ||
123 | |||
124 | a. for any code that a Contributor has removed from Covered Software; or | ||
125 | |||
126 | b. for infringements caused by: (i) Your and any other third party's | ||
127 | modifications of Covered Software, or (ii) the combination of its | ||
128 | Contributions with other software (except as part of its Contributor | ||
129 | Version); or | ||
130 | |||
131 | c. under Patent Claims infringed by Covered Software in the absence of | ||
132 | its Contributions. | ||
133 | |||
134 | This License does not grant any rights in the trademarks, service marks, | ||
135 | or logos of any Contributor (except as may be necessary to comply with | ||
136 | the notice requirements in Section 3.4). | ||
137 | |||
138 | 2.4. Subsequent Licenses | ||
139 | |||
140 | No Contributor makes additional grants as a result of Your choice to | ||
141 | distribute the Covered Software under a subsequent version of this | ||
142 | License (see Section 10.2) or under the terms of a Secondary License (if | ||
143 | permitted under the terms of Section 3.3). | ||
144 | |||
145 | 2.5. Representation | ||
146 | |||
147 | Each Contributor represents that the Contributor believes its | ||
148 | Contributions are its original creation(s) or it has sufficient rights to | ||
149 | grant the rights to its Contributions conveyed by this License. | ||
150 | |||
151 | 2.6. Fair Use | ||
152 | |||
153 | This License is not intended to limit any rights You have under | ||
154 | applicable copyright doctrines of fair use, fair dealing, or other | ||
155 | equivalents. | ||
156 | |||
157 | 2.7. Conditions | ||
158 | |||
159 | Sections 3.1, 3.2, 3.3, and 3.4 are conditions of the licenses granted in | ||
160 | Section 2.1. | ||
161 | |||
162 | |||
163 | 3. Responsibilities | ||
164 | |||
165 | 3.1. Distribution of Source Form | ||
166 | |||
167 | All distribution of Covered Software in Source Code Form, including any | ||
168 | Modifications that You create or to which You contribute, must be under | ||
169 | the terms of this License. You must inform recipients that the Source | ||
170 | Code Form of the Covered Software is governed by the terms of this | ||
171 | License, and how they can obtain a copy of this License. You may not | ||
172 | attempt to alter or restrict the recipients' rights in the Source Code | ||
173 | Form. | ||
174 | |||
175 | 3.2. Distribution of Executable Form | ||
176 | |||
177 | If You distribute Covered Software in Executable Form then: | ||
178 | |||
179 | a. such Covered Software must also be made available in Source Code Form, | ||
180 | as described in Section 3.1, and You must inform recipients of the | ||
181 | Executable Form how they can obtain a copy of such Source Code Form by | ||
182 | reasonable means in a timely manner, at a charge no more than the cost | ||
183 | of distribution to the recipient; and | ||
184 | |||
185 | b. You may distribute such Executable Form under the terms of this | ||
186 | License, or sublicense it under different terms, provided that the | ||
187 | license for the Executable Form does not attempt to limit or alter the | ||
188 | recipients' rights in the Source Code Form under this License. | ||
189 | |||
190 | 3.3. Distribution of a Larger Work | ||
191 | |||
192 | You may create and distribute a Larger Work under terms of Your choice, | ||
193 | provided that You also comply with the requirements of this License for | ||
194 | the Covered Software. If the Larger Work is a combination of Covered | ||
195 | Software with a work governed by one or more Secondary Licenses, and the | ||
196 | Covered Software is not Incompatible With Secondary Licenses, this | ||
197 | License permits You to additionally distribute such Covered Software | ||
198 | under the terms of such Secondary License(s), so that the recipient of | ||
199 | the Larger Work may, at their option, further distribute the Covered | ||
200 | Software under the terms of either this License or such Secondary | ||
201 | License(s). | ||
202 | |||
203 | 3.4. Notices | ||
204 | |||
205 | You may not remove or alter the substance of any license notices | ||
206 | (including copyright notices, patent notices, disclaimers of warranty, or | ||
207 | limitations of liability) contained within the Source Code Form of the | ||
208 | Covered Software, except that You may alter any license notices to the | ||
209 | extent required to remedy known factual inaccuracies. | ||
210 | |||
211 | 3.5. Application of Additional Terms | ||
212 | |||
213 | You may choose to offer, and to charge a fee for, warranty, support, | ||
214 | indemnity or liability obligations to one or more recipients of Covered | ||
215 | Software. However, You may do so only on Your own behalf, and not on | ||
216 | behalf of any Contributor. You must make it absolutely clear that any | ||
217 | such warranty, support, indemnity, or liability obligation is offered by | ||
218 | You alone, and You hereby agree to indemnify every Contributor for any | ||
219 | liability incurred by such Contributor as a result of warranty, support, | ||
220 | indemnity or liability terms You offer. You may include additional | ||
221 | disclaimers of warranty and limitations of liability specific to any | ||
222 | jurisdiction. | ||
223 | |||
224 | 4. Inability to Comply Due to Statute or Regulation | ||
225 | |||
226 | If it is impossible for You to comply with any of the terms of this License | ||
227 | with respect to some or all of the Covered Software due to statute, | ||
228 | judicial order, or regulation then You must: (a) comply with the terms of | ||
229 | this License to the maximum extent possible; and (b) describe the | ||
230 | limitations and the code they affect. Such description must be placed in a | ||
231 | text file included with all distributions of the Covered Software under | ||
232 | this License. Except to the extent prohibited by statute or regulation, | ||
233 | such description must be sufficiently detailed for a recipient of ordinary | ||
234 | skill to be able to understand it. | ||
235 | |||
236 | 5. Termination | ||
237 | |||
238 | 5.1. The rights granted under this License will terminate automatically if You | ||
239 | fail to comply with any of its terms. However, if You become compliant, | ||
240 | then the rights granted under this License from a particular Contributor | ||
241 | are reinstated (a) provisionally, unless and until such Contributor | ||
242 | explicitly and finally terminates Your grants, and (b) on an ongoing | ||
243 | basis, if such Contributor fails to notify You of the non-compliance by | ||
244 | some reasonable means prior to 60 days after You have come back into | ||
245 | compliance. Moreover, Your grants from a particular Contributor are | ||
246 | reinstated on an ongoing basis if such Contributor notifies You of the | ||
247 | non-compliance by some reasonable means, this is the first time You have | ||
248 | received notice of non-compliance with this License from such | ||
249 | Contributor, and You become compliant prior to 30 days after Your receipt | ||
250 | of the notice. | ||
251 | |||
252 | 5.2. If You initiate litigation against any entity by asserting a patent | ||
253 | infringement claim (excluding declaratory judgment actions, | ||
254 | counter-claims, and cross-claims) alleging that a Contributor Version | ||
255 | directly or indirectly infringes any patent, then the rights granted to | ||
256 | You by any and all Contributors for the Covered Software under Section | ||
257 | 2.1 of this License shall terminate. | ||
258 | |||
259 | 5.3. In the event of termination under Sections 5.1 or 5.2 above, all end user | ||
260 | license agreements (excluding distributors and resellers) which have been | ||
261 | validly granted by You or Your distributors under this License prior to | ||
262 | termination shall survive termination. | ||
263 | |||
264 | 6. Disclaimer of Warranty | ||
265 | |||
266 | Covered Software is provided under this License on an "as is" basis, | ||
267 | without warranty of any kind, either expressed, implied, or statutory, | ||
268 | including, without limitation, warranties that the Covered Software is free | ||
269 | of defects, merchantable, fit for a particular purpose or non-infringing. | ||
270 | The entire risk as to the quality and performance of the Covered Software | ||
271 | is with You. Should any Covered Software prove defective in any respect, | ||
272 | You (not any Contributor) assume the cost of any necessary servicing, | ||
273 | repair, or correction. This disclaimer of warranty constitutes an essential | ||
274 | part of this License. No use of any Covered Software is authorized under | ||
275 | this License except under this disclaimer. | ||
276 | |||
277 | 7. Limitation of Liability | ||
278 | |||
279 | Under no circumstances and under no legal theory, whether tort (including | ||
280 | negligence), contract, or otherwise, shall any Contributor, or anyone who | ||
281 | distributes Covered Software as permitted above, be liable to You for any | ||
282 | direct, indirect, special, incidental, or consequential damages of any | ||
283 | character including, without limitation, damages for lost profits, loss of | ||
284 | goodwill, work stoppage, computer failure or malfunction, or any and all | ||
285 | other commercial damages or losses, even if such party shall have been | ||
286 | informed of the possibility of such damages. This limitation of liability | ||
287 | shall not apply to liability for death or personal injury resulting from | ||
288 | such party's negligence to the extent applicable law prohibits such | ||
289 | limitation. Some jurisdictions do not allow the exclusion or limitation of | ||
290 | incidental or consequential damages, so this exclusion and limitation may | ||
291 | not apply to You. | ||
292 | |||
293 | 8. Litigation | ||
294 | |||
295 | Any litigation relating to this License may be brought only in the courts | ||
296 | of a jurisdiction where the defendant maintains its principal place of | ||
297 | business and such litigation shall be governed by laws of that | ||
298 | jurisdiction, without reference to its conflict-of-law provisions. Nothing | ||
299 | in this Section shall prevent a party's ability to bring cross-claims or | ||
300 | counter-claims. | ||
301 | |||
302 | 9. Miscellaneous | ||
303 | |||
304 | This License represents the complete agreement concerning the subject | ||
305 | matter hereof. If any provision of this License is held to be | ||
306 | unenforceable, such provision shall be reformed only to the extent | ||
307 | necessary to make it enforceable. Any law or regulation which provides that | ||
308 | the language of a contract shall be construed against the drafter shall not | ||
309 | be used to construe this License against a Contributor. | ||
310 | |||
311 | |||
312 | 10. Versions of the License | ||
313 | |||
314 | 10.1. New Versions | ||
315 | |||
316 | Mozilla Foundation is the license steward. Except as provided in Section | ||
317 | 10.3, no one other than the license steward has the right to modify or | ||
318 | publish new versions of this License. Each version will be given a | ||
319 | distinguishing version number. | ||
320 | |||
321 | 10.2. Effect of New Versions | ||
322 | |||
323 | You may distribute the Covered Software under the terms of the version | ||
324 | of the License under which You originally received the Covered Software, | ||
325 | or under the terms of any subsequent version published by the license | ||
326 | steward. | ||
327 | |||
328 | 10.3. Modified Versions | ||
329 | |||
330 | If you create software not governed by this License, and you want to | ||
331 | create a new license for such software, you may create and use a | ||
332 | modified version of this License if you rename the license and remove | ||
333 | any references to the name of the license steward (except to note that | ||
334 | such modified license differs from this License). | ||
335 | |||
336 | 10.4. Distributing Source Code Form that is Incompatible With Secondary | ||
337 | Licenses If You choose to distribute Source Code Form that is | ||
338 | Incompatible With Secondary Licenses under the terms of this version of | ||
339 | the License, the notice described in Exhibit B of this License must be | ||
340 | attached. | ||
341 | |||
342 | Exhibit A - Source Code Form License Notice | ||
343 | |||
344 | This Source Code Form is subject to the | ||
345 | terms of the Mozilla Public License, v. | ||
346 | 2.0. If a copy of the MPL was not | ||
347 | distributed with this file, You can | ||
348 | obtain one at | ||
349 | http://mozilla.org/MPL/2.0/. | ||
350 | |||
351 | If it is not possible or desirable to put the notice in a particular file, | ||
352 | then You may include the notice in a location (such as a LICENSE file in a | ||
353 | relevant directory) where a recipient would be likely to look for such a | ||
354 | notice. | ||
355 | |||
356 | You may add additional accurate notices of copyright ownership. | ||
357 | |||
358 | Exhibit B - "Incompatible With Secondary Licenses" Notice | ||
359 | |||
360 | This Source Code Form is "Incompatible | ||
361 | With Secondary Licenses", as defined by | ||
362 | the Mozilla Public License, v. 2.0. | ||
363 | |||
diff --git a/vendor/github.com/hashicorp/go-cleanhttp/README.md b/vendor/github.com/hashicorp/go-cleanhttp/README.md new file mode 100644 index 0000000..036e531 --- /dev/null +++ b/vendor/github.com/hashicorp/go-cleanhttp/README.md | |||
@@ -0,0 +1,30 @@ | |||
1 | # cleanhttp | ||
2 | |||
3 | Functions for accessing "clean" Go http.Client values | ||
4 | |||
5 | ------------- | ||
6 | |||
7 | The Go standard library contains a default `http.Client` called | ||
8 | `http.DefaultClient`. It is a common idiom in Go code to start with | ||
9 | `http.DefaultClient` and tweak it as necessary, and in fact, this is | ||
10 | encouraged; from the `http` package documentation: | ||
11 | |||
12 | > The Client's Transport typically has internal state (cached TCP connections), | ||
13 | so Clients should be reused instead of created as needed. Clients are safe for | ||
14 | concurrent use by multiple goroutines. | ||
15 | |||
16 | Unfortunately, this is a shared value, and it is not uncommon for libraries to | ||
17 | assume that they are free to modify it at will. With enough dependencies, it | ||
18 | can be very easy to encounter strange problems and race conditions due to | ||
19 | manipulation of this shared value across libraries and goroutines (clients are | ||
20 | safe for concurrent use, but writing values to the client struct itself is not | ||
21 | protected). | ||
22 | |||
23 | Making things worse is the fact that a bare `http.Client` will use a default | ||
24 | `http.Transport` called `http.DefaultTransport`, which is another global value | ||
25 | that behaves the same way. So it is not simply enough to replace | ||
26 | `http.DefaultClient` with `&http.Client{}`. | ||
27 | |||
28 | This repository provides some simple functions to get a "clean" `http.Client` | ||
29 | -- one that uses the same default values as the Go standard library, but | ||
30 | returns a client that does not share any state with other clients. | ||
diff --git a/vendor/github.com/hashicorp/go-cleanhttp/cleanhttp.go b/vendor/github.com/hashicorp/go-cleanhttp/cleanhttp.go new file mode 100644 index 0000000..7d8a57c --- /dev/null +++ b/vendor/github.com/hashicorp/go-cleanhttp/cleanhttp.go | |||
@@ -0,0 +1,56 @@ | |||
1 | package cleanhttp | ||
2 | |||
3 | import ( | ||
4 | "net" | ||
5 | "net/http" | ||
6 | "runtime" | ||
7 | "time" | ||
8 | ) | ||
9 | |||
10 | // DefaultTransport returns a new http.Transport with similar default values to | ||
11 | // http.DefaultTransport, but with idle connections and keepalives disabled. | ||
12 | func DefaultTransport() *http.Transport { | ||
13 | transport := DefaultPooledTransport() | ||
14 | transport.DisableKeepAlives = true | ||
15 | transport.MaxIdleConnsPerHost = -1 | ||
16 | return transport | ||
17 | } | ||
18 | |||
19 | // DefaultPooledTransport returns a new http.Transport with similar default | ||
20 | // values to http.DefaultTransport. Do not use this for transient transports as | ||
21 | // it can leak file descriptors over time. Only use this for transports that | ||
22 | // will be re-used for the same host(s). | ||
23 | func DefaultPooledTransport() *http.Transport { | ||
24 | transport := &http.Transport{ | ||
25 | Proxy: http.ProxyFromEnvironment, | ||
26 | DialContext: (&net.Dialer{ | ||
27 | Timeout: 30 * time.Second, | ||
28 | KeepAlive: 30 * time.Second, | ||
29 | }).DialContext, | ||
30 | MaxIdleConns: 100, | ||
31 | IdleConnTimeout: 90 * time.Second, | ||
32 | TLSHandshakeTimeout: 10 * time.Second, | ||
33 | ExpectContinueTimeout: 1 * time.Second, | ||
34 | MaxIdleConnsPerHost: runtime.GOMAXPROCS(0) + 1, | ||
35 | } | ||
36 | return transport | ||
37 | } | ||
38 | |||
39 | // DefaultClient returns a new http.Client with similar default values to | ||
40 | // http.Client, but with a non-shared Transport, idle connections disabled, and | ||
41 | // keepalives disabled. | ||
42 | func DefaultClient() *http.Client { | ||
43 | return &http.Client{ | ||
44 | Transport: DefaultTransport(), | ||
45 | } | ||
46 | } | ||
47 | |||
48 | // DefaultPooledClient returns a new http.Client with similar default values to | ||
49 | // http.Client, but with a shared Transport. Do not use this function for | ||
50 | // transient clients as it can leak file descriptors over time. Only use this | ||
51 | // for clients that will be re-used for the same host(s). | ||
52 | func DefaultPooledClient() *http.Client { | ||
53 | return &http.Client{ | ||
54 | Transport: DefaultPooledTransport(), | ||
55 | } | ||
56 | } | ||
diff --git a/vendor/github.com/hashicorp/go-cleanhttp/doc.go b/vendor/github.com/hashicorp/go-cleanhttp/doc.go new file mode 100644 index 0000000..0584109 --- /dev/null +++ b/vendor/github.com/hashicorp/go-cleanhttp/doc.go | |||
@@ -0,0 +1,20 @@ | |||
1 | // Package cleanhttp offers convenience utilities for acquiring "clean" | ||
2 | // http.Transport and http.Client structs. | ||
3 | // | ||
4 | // Values set on http.DefaultClient and http.DefaultTransport affect all | ||
5 | // callers. This can have detrimental effects, esepcially in TLS contexts, | ||
6 | // where client or root certificates set to talk to multiple endpoints can end | ||
7 | // up displacing each other, leading to hard-to-debug issues. This package | ||
8 | // provides non-shared http.Client and http.Transport structs to ensure that | ||
9 | // the configuration will not be overwritten by other parts of the application | ||
10 | // or dependencies. | ||
11 | // | ||
12 | // The DefaultClient and DefaultTransport functions disable idle connections | ||
13 | // and keepalives. Without ensuring that idle connections are closed before | ||
14 | // garbage collection, short-term clients/transports can leak file descriptors, | ||
15 | // eventually leading to "too many open files" errors. If you will be | ||
16 | // connecting to the same hosts repeatedly from the same client, you can use | ||
17 | // DefaultPooledClient to receive a client that has connection pooling | ||
18 | // semantics similar to http.DefaultClient. | ||
19 | // | ||
20 | package cleanhttp | ||
diff --git a/vendor/github.com/hashicorp/terraform/config/config.go b/vendor/github.com/hashicorp/terraform/config/config.go index a157824..3f756dc 100644 --- a/vendor/github.com/hashicorp/terraform/config/config.go +++ b/vendor/github.com/hashicorp/terraform/config/config.go | |||
@@ -12,6 +12,7 @@ import ( | |||
12 | "github.com/hashicorp/hil" | 12 | "github.com/hashicorp/hil" |
13 | "github.com/hashicorp/hil/ast" | 13 | "github.com/hashicorp/hil/ast" |
14 | "github.com/hashicorp/terraform/helper/hilmapstructure" | 14 | "github.com/hashicorp/terraform/helper/hilmapstructure" |
15 | "github.com/hashicorp/terraform/plugin/discovery" | ||
15 | "github.com/mitchellh/reflectwalk" | 16 | "github.com/mitchellh/reflectwalk" |
16 | ) | 17 | ) |
17 | 18 | ||
@@ -64,6 +65,7 @@ type Module struct { | |||
64 | type ProviderConfig struct { | 65 | type ProviderConfig struct { |
65 | Name string | 66 | Name string |
66 | Alias string | 67 | Alias string |
68 | Version string | ||
67 | RawConfig *RawConfig | 69 | RawConfig *RawConfig |
68 | } | 70 | } |
69 | 71 | ||
@@ -238,6 +240,33 @@ func (r *Resource) Id() string { | |||
238 | } | 240 | } |
239 | } | 241 | } |
240 | 242 | ||
243 | // ProviderFullName returns the full name of the provider for this resource, | ||
244 | // which may either be specified explicitly using the "provider" meta-argument | ||
245 | // or implied by the prefix on the resource type name. | ||
246 | func (r *Resource) ProviderFullName() string { | ||
247 | return ResourceProviderFullName(r.Type, r.Provider) | ||
248 | } | ||
249 | |||
250 | // ResourceProviderFullName returns the full (dependable) name of the | ||
251 | // provider for a hypothetical resource with the given resource type and | ||
252 | // explicit provider string. If the explicit provider string is empty then | ||
253 | // the provider name is inferred from the resource type name. | ||
254 | func ResourceProviderFullName(resourceType, explicitProvider string) string { | ||
255 | if explicitProvider != "" { | ||
256 | return explicitProvider | ||
257 | } | ||
258 | |||
259 | idx := strings.IndexRune(resourceType, '_') | ||
260 | if idx == -1 { | ||
261 | // If no underscores, the resource name is assumed to be | ||
262 | // also the provider name, e.g. if the provider exposes | ||
263 | // only a single resource of each type. | ||
264 | return resourceType | ||
265 | } | ||
266 | |||
267 | return resourceType[:idx] | ||
268 | } | ||
269 | |||
241 | // Validate does some basic semantic checking of the configuration. | 270 | // Validate does some basic semantic checking of the configuration. |
242 | func (c *Config) Validate() error { | 271 | func (c *Config) Validate() error { |
243 | if c == nil { | 272 | if c == nil { |
@@ -349,7 +378,8 @@ func (c *Config) Validate() error { | |||
349 | } | 378 | } |
350 | } | 379 | } |
351 | 380 | ||
352 | // Check that providers aren't declared multiple times. | 381 | // Check that providers aren't declared multiple times and that their |
382 | // version constraints, where present, are syntactically valid. | ||
353 | providerSet := make(map[string]struct{}) | 383 | providerSet := make(map[string]struct{}) |
354 | for _, p := range c.ProviderConfigs { | 384 | for _, p := range c.ProviderConfigs { |
355 | name := p.FullName() | 385 | name := p.FullName() |
@@ -360,6 +390,16 @@ func (c *Config) Validate() error { | |||
360 | continue | 390 | continue |
361 | } | 391 | } |
362 | 392 | ||
393 | if p.Version != "" { | ||
394 | _, err := discovery.ConstraintStr(p.Version).Parse() | ||
395 | if err != nil { | ||
396 | errs = append(errs, fmt.Errorf( | ||
397 | "provider.%s: invalid version constraint %q: %s", | ||
398 | name, p.Version, err, | ||
399 | )) | ||
400 | } | ||
401 | } | ||
402 | |||
363 | providerSet[name] = struct{}{} | 403 | providerSet[name] = struct{}{} |
364 | } | 404 | } |
365 | 405 | ||
diff --git a/vendor/github.com/hashicorp/terraform/config/interpolate_funcs.go b/vendor/github.com/hashicorp/terraform/config/interpolate_funcs.go index 7b7b3f2..a298cf2 100644 --- a/vendor/github.com/hashicorp/terraform/config/interpolate_funcs.go +++ b/vendor/github.com/hashicorp/terraform/config/interpolate_funcs.go | |||
@@ -70,6 +70,7 @@ func Funcs() map[string]ast.Function { | |||
70 | "coalescelist": interpolationFuncCoalesceList(), | 70 | "coalescelist": interpolationFuncCoalesceList(), |
71 | "compact": interpolationFuncCompact(), | 71 | "compact": interpolationFuncCompact(), |
72 | "concat": interpolationFuncConcat(), | 72 | "concat": interpolationFuncConcat(), |
73 | "contains": interpolationFuncContains(), | ||
73 | "dirname": interpolationFuncDirname(), | 74 | "dirname": interpolationFuncDirname(), |
74 | "distinct": interpolationFuncDistinct(), | 75 | "distinct": interpolationFuncDistinct(), |
75 | "element": interpolationFuncElement(), | 76 | "element": interpolationFuncElement(), |
@@ -356,6 +357,22 @@ func interpolationFuncCoalesceList() ast.Function { | |||
356 | } | 357 | } |
357 | } | 358 | } |
358 | 359 | ||
360 | // interpolationFuncContains returns true if an element is in the list | ||
361 | // and return false otherwise | ||
362 | func interpolationFuncContains() ast.Function { | ||
363 | return ast.Function{ | ||
364 | ArgTypes: []ast.Type{ast.TypeList, ast.TypeString}, | ||
365 | ReturnType: ast.TypeBool, | ||
366 | Callback: func(args []interface{}) (interface{}, error) { | ||
367 | _, err := interpolationFuncIndex().Callback(args) | ||
368 | if err != nil { | ||
369 | return false, nil | ||
370 | } | ||
371 | return true, nil | ||
372 | }, | ||
373 | } | ||
374 | } | ||
375 | |||
359 | // interpolationFuncConcat implements the "concat" function that concatenates | 376 | // interpolationFuncConcat implements the "concat" function that concatenates |
360 | // multiple lists. | 377 | // multiple lists. |
361 | func interpolationFuncConcat() ast.Function { | 378 | func interpolationFuncConcat() ast.Function { |
diff --git a/vendor/github.com/hashicorp/terraform/config/loader.go b/vendor/github.com/hashicorp/terraform/config/loader.go index 0bfa89c..5dd7d46 100644 --- a/vendor/github.com/hashicorp/terraform/config/loader.go +++ b/vendor/github.com/hashicorp/terraform/config/loader.go | |||
@@ -194,7 +194,7 @@ func dirFiles(dir string) ([]string, []string, error) { | |||
194 | // Only care about files that are valid to load | 194 | // Only care about files that are valid to load |
195 | name := fi.Name() | 195 | name := fi.Name() |
196 | extValue := ext(name) | 196 | extValue := ext(name) |
197 | if extValue == "" || isIgnoredFile(name) { | 197 | if extValue == "" || IsIgnoredFile(name) { |
198 | continue | 198 | continue |
199 | } | 199 | } |
200 | 200 | ||
@@ -215,9 +215,9 @@ func dirFiles(dir string) ([]string, []string, error) { | |||
215 | return files, overrides, nil | 215 | return files, overrides, nil |
216 | } | 216 | } |
217 | 217 | ||
218 | // isIgnoredFile returns true or false depending on whether the | 218 | // IsIgnoredFile returns true or false depending on whether the |
219 | // provided file name is a file that should be ignored. | 219 | // provided file name is a file that should be ignored. |
220 | func isIgnoredFile(name string) bool { | 220 | func IsIgnoredFile(name string) bool { |
221 | return strings.HasPrefix(name, ".") || // Unix-like hidden files | 221 | return strings.HasPrefix(name, ".") || // Unix-like hidden files |
222 | strings.HasSuffix(name, "~") || // vim | 222 | strings.HasSuffix(name, "~") || // vim |
223 | strings.HasPrefix(name, "#") && strings.HasSuffix(name, "#") // emacs | 223 | strings.HasPrefix(name, "#") && strings.HasSuffix(name, "#") // emacs |
diff --git a/vendor/github.com/hashicorp/terraform/config/loader_hcl.go b/vendor/github.com/hashicorp/terraform/config/loader_hcl.go index 9abb196..e85e493 100644 --- a/vendor/github.com/hashicorp/terraform/config/loader_hcl.go +++ b/vendor/github.com/hashicorp/terraform/config/loader_hcl.go | |||
@@ -17,6 +17,20 @@ type hclConfigurable struct { | |||
17 | Root *ast.File | 17 | Root *ast.File |
18 | } | 18 | } |
19 | 19 | ||
20 | var ReservedResourceFields = []string{ | ||
21 | "connection", | ||
22 | "count", | ||
23 | "depends_on", | ||
24 | "lifecycle", | ||
25 | "provider", | ||
26 | "provisioner", | ||
27 | } | ||
28 | |||
29 | var ReservedProviderFields = []string{ | ||
30 | "alias", | ||
31 | "version", | ||
32 | } | ||
33 | |||
20 | func (t *hclConfigurable) Config() (*Config, error) { | 34 | func (t *hclConfigurable) Config() (*Config, error) { |
21 | validKeys := map[string]struct{}{ | 35 | validKeys := map[string]struct{}{ |
22 | "atlas": struct{}{}, | 36 | "atlas": struct{}{}, |
@@ -562,6 +576,7 @@ func loadProvidersHcl(list *ast.ObjectList) ([]*ProviderConfig, error) { | |||
562 | } | 576 | } |
563 | 577 | ||
564 | delete(config, "alias") | 578 | delete(config, "alias") |
579 | delete(config, "version") | ||
565 | 580 | ||
566 | rawConfig, err := NewRawConfig(config) | 581 | rawConfig, err := NewRawConfig(config) |
567 | if err != nil { | 582 | if err != nil { |
@@ -583,9 +598,22 @@ func loadProvidersHcl(list *ast.ObjectList) ([]*ProviderConfig, error) { | |||
583 | } | 598 | } |
584 | } | 599 | } |
585 | 600 | ||
601 | // If we have a version field then extract it | ||
602 | var version string | ||
603 | if a := listVal.Filter("version"); len(a.Items) > 0 { | ||
604 | err := hcl.DecodeObject(&version, a.Items[0].Val) | ||
605 | if err != nil { | ||
606 | return nil, fmt.Errorf( | ||
607 | "Error reading version for provider[%s]: %s", | ||
608 | n, | ||
609 | err) | ||
610 | } | ||
611 | } | ||
612 | |||
586 | result = append(result, &ProviderConfig{ | 613 | result = append(result, &ProviderConfig{ |
587 | Name: n, | 614 | Name: n, |
588 | Alias: alias, | 615 | Alias: alias, |
616 | Version: version, | ||
589 | RawConfig: rawConfig, | 617 | RawConfig: rawConfig, |
590 | }) | 618 | }) |
591 | } | 619 | } |
diff --git a/vendor/github.com/hashicorp/terraform/config/module/tree.go b/vendor/github.com/hashicorp/terraform/config/module/tree.go index b6f90fd..4b0b153 100644 --- a/vendor/github.com/hashicorp/terraform/config/module/tree.go +++ b/vendor/github.com/hashicorp/terraform/config/module/tree.go | |||
@@ -92,6 +92,25 @@ func (t *Tree) Children() map[string]*Tree { | |||
92 | return t.children | 92 | return t.children |
93 | } | 93 | } |
94 | 94 | ||
95 | // DeepEach calls the provided callback for the receiver and then all of | ||
96 | // its descendents in the tree, allowing an operation to be performed on | ||
97 | // all modules in the tree. | ||
98 | // | ||
99 | // Parents will be visited before their children but otherwise the order is | ||
100 | // not defined. | ||
101 | func (t *Tree) DeepEach(cb func(*Tree)) { | ||
102 | t.lock.RLock() | ||
103 | defer t.lock.RUnlock() | ||
104 | t.deepEach(cb) | ||
105 | } | ||
106 | |||
107 | func (t *Tree) deepEach(cb func(*Tree)) { | ||
108 | cb(t) | ||
109 | for _, c := range t.children { | ||
110 | c.deepEach(cb) | ||
111 | } | ||
112 | } | ||
113 | |||
95 | // Loaded says whether or not this tree has been loaded or not yet. | 114 | // Loaded says whether or not this tree has been loaded or not yet. |
96 | func (t *Tree) Loaded() bool { | 115 | func (t *Tree) Loaded() bool { |
97 | t.lock.RLock() | 116 | t.lock.RLock() |
diff --git a/vendor/github.com/hashicorp/terraform/config/providers.go b/vendor/github.com/hashicorp/terraform/config/providers.go new file mode 100644 index 0000000..7a50782 --- /dev/null +++ b/vendor/github.com/hashicorp/terraform/config/providers.go | |||
@@ -0,0 +1,103 @@ | |||
1 | package config | ||
2 | |||
3 | import "github.com/blang/semver" | ||
4 | |||
5 | // ProviderVersionConstraint presents a constraint for a particular | ||
6 | // provider, identified by its full name. | ||
7 | type ProviderVersionConstraint struct { | ||
8 | Constraint string | ||
9 | ProviderType string | ||
10 | } | ||
11 | |||
12 | // ProviderVersionConstraints is a map from provider full name to its associated | ||
13 | // ProviderVersionConstraint, as produced by Config.RequiredProviders. | ||
14 | type ProviderVersionConstraints map[string]ProviderVersionConstraint | ||
15 | |||
16 | // RequiredProviders returns the ProviderVersionConstraints for this | ||
17 | // module. | ||
18 | // | ||
19 | // This includes both providers that are explicitly requested by provider | ||
20 | // blocks and those that are used implicitly by instantiating one of their | ||
21 | // resource types. In the latter case, the returned semver Range will | ||
22 | // accept any version of the provider. | ||
23 | func (c *Config) RequiredProviders() ProviderVersionConstraints { | ||
24 | ret := make(ProviderVersionConstraints, len(c.ProviderConfigs)) | ||
25 | |||
26 | configs := c.ProviderConfigsByFullName() | ||
27 | |||
28 | // In order to find the *implied* dependencies (those without explicit | ||
29 | // "provider" blocks) we need to walk over all of the resources and | ||
30 | // cross-reference with the provider configs. | ||
31 | for _, rc := range c.Resources { | ||
32 | providerName := rc.ProviderFullName() | ||
33 | var providerType string | ||
34 | |||
35 | // Default to (effectively) no constraint whatsoever, but we might | ||
36 | // override if there's an explicit constraint in config. | ||
37 | constraint := ">=0.0.0" | ||
38 | |||
39 | config, ok := configs[providerName] | ||
40 | if ok { | ||
41 | if config.Version != "" { | ||
42 | constraint = config.Version | ||
43 | } | ||
44 | providerType = config.Name | ||
45 | } else { | ||
46 | providerType = providerName | ||
47 | } | ||
48 | |||
49 | ret[providerName] = ProviderVersionConstraint{ | ||
50 | ProviderType: providerType, | ||
51 | Constraint: constraint, | ||
52 | } | ||
53 | } | ||
54 | |||
55 | return ret | ||
56 | } | ||
57 | |||
58 | // RequiredRanges returns a semver.Range for each distinct provider type in | ||
59 | // the constraint map. If the same provider type appears more than once | ||
60 | // (e.g. because aliases are in use) then their respective constraints are | ||
61 | // combined such that they must *all* apply. | ||
62 | // | ||
63 | // The result of this method can be passed to the | ||
64 | // PluginMetaSet.ConstrainVersions method within the plugin/discovery | ||
65 | // package in order to filter down the available plugins to those which | ||
66 | // satisfy the given constraints. | ||
67 | // | ||
68 | // This function will panic if any of the constraints within cannot be | ||
69 | // parsed as semver ranges. This is guaranteed to never happen for a | ||
70 | // constraint set that was built from a configuration that passed validation. | ||
71 | func (cons ProviderVersionConstraints) RequiredRanges() map[string]semver.Range { | ||
72 | ret := make(map[string]semver.Range, len(cons)) | ||
73 | |||
74 | for _, con := range cons { | ||
75 | spec := semver.MustParseRange(con.Constraint) | ||
76 | if existing, exists := ret[con.ProviderType]; exists { | ||
77 | ret[con.ProviderType] = existing.AND(spec) | ||
78 | } else { | ||
79 | ret[con.ProviderType] = spec | ||
80 | } | ||
81 | } | ||
82 | |||
83 | return ret | ||
84 | } | ||
85 | |||
86 | // ProviderConfigsByFullName returns a map from provider full names (as | ||
87 | // returned by ProviderConfig.FullName()) to the corresponding provider | ||
88 | // configs. | ||
89 | // | ||
90 | // This function returns no new information than what's already in | ||
91 | // c.ProviderConfigs, but returns it in a more convenient shape. If there | ||
92 | // is more than one provider config with the same full name then the result | ||
93 | // is undefined, but that is guaranteed not to happen for any config that | ||
94 | // has passed validation. | ||
95 | func (c *Config) ProviderConfigsByFullName() map[string]*ProviderConfig { | ||
96 | ret := make(map[string]*ProviderConfig, len(c.ProviderConfigs)) | ||
97 | |||
98 | for _, pc := range c.ProviderConfigs { | ||
99 | ret[pc.FullName()] = pc | ||
100 | } | ||
101 | |||
102 | return ret | ||
103 | } | ||
diff --git a/vendor/github.com/hashicorp/terraform/flatmap/expand.go b/vendor/github.com/hashicorp/terraform/flatmap/expand.go index e0b81b6..1449065 100644 --- a/vendor/github.com/hashicorp/terraform/flatmap/expand.go +++ b/vendor/github.com/hashicorp/terraform/flatmap/expand.go | |||
@@ -60,6 +60,11 @@ func expandArray(m map[string]string, prefix string) []interface{} { | |||
60 | return []interface{}{} | 60 | return []interface{}{} |
61 | } | 61 | } |
62 | 62 | ||
63 | // NOTE: "num" is not necessarily accurate, e.g. if a user tampers | ||
64 | // with state, so the following code should not crash when given a | ||
65 | // number of items more or less than what's given in num. The | ||
66 | // num key is mainly just a hint that this is a list or set. | ||
67 | |||
63 | // The Schema "Set" type stores its values in an array format, but | 68 | // The Schema "Set" type stores its values in an array format, but |
64 | // using numeric hash values instead of ordinal keys. Take the set | 69 | // using numeric hash values instead of ordinal keys. Take the set |
65 | // of keys regardless of value, and expand them in numeric order. | 70 | // of keys regardless of value, and expand them in numeric order. |
@@ -101,7 +106,7 @@ func expandArray(m map[string]string, prefix string) []interface{} { | |||
101 | } | 106 | } |
102 | sort.Ints(keysList) | 107 | sort.Ints(keysList) |
103 | 108 | ||
104 | result := make([]interface{}, num) | 109 | result := make([]interface{}, len(keysList)) |
105 | for i, key := range keysList { | 110 | for i, key := range keysList { |
106 | keyString := strconv.Itoa(key) | 111 | keyString := strconv.Itoa(key) |
107 | if computed[keyString] { | 112 | if computed[keyString] { |
diff --git a/vendor/github.com/hashicorp/terraform/helper/resource/id.go b/vendor/github.com/hashicorp/terraform/helper/resource/id.go index 629582b..1cde67c 100644 --- a/vendor/github.com/hashicorp/terraform/helper/resource/id.go +++ b/vendor/github.com/hashicorp/terraform/helper/resource/id.go | |||
@@ -1,21 +1,17 @@ | |||
1 | package resource | 1 | package resource |
2 | 2 | ||
3 | import ( | 3 | import ( |
4 | "crypto/rand" | ||
5 | "fmt" | 4 | "fmt" |
6 | "math/big" | 5 | "strings" |
7 | "sync" | 6 | "sync" |
7 | "time" | ||
8 | ) | 8 | ) |
9 | 9 | ||
10 | const UniqueIdPrefix = `terraform-` | 10 | const UniqueIdPrefix = `terraform-` |
11 | 11 | ||
12 | // idCounter is a randomly seeded monotonic counter for generating ordered | 12 | // idCounter is a monotonic counter for generating ordered unique ids. |
13 | // unique ids. It uses a big.Int so we can easily increment a long numeric | ||
14 | // string. The max possible hex value here with 12 random bytes is | ||
15 | // "01000000000000000000000000", so there's no chance of rollover during | ||
16 | // operation. | ||
17 | var idMutex sync.Mutex | 13 | var idMutex sync.Mutex |
18 | var idCounter = big.NewInt(0).SetBytes(randomBytes(12)) | 14 | var idCounter uint32 |
19 | 15 | ||
20 | // Helper for a resource to generate a unique identifier w/ default prefix | 16 | // Helper for a resource to generate a unique identifier w/ default prefix |
21 | func UniqueId() string { | 17 | func UniqueId() string { |
@@ -25,15 +21,20 @@ func UniqueId() string { | |||
25 | // Helper for a resource to generate a unique identifier w/ given prefix | 21 | // Helper for a resource to generate a unique identifier w/ given prefix |
26 | // | 22 | // |
27 | // After the prefix, the ID consists of an incrementing 26 digit value (to match | 23 | // After the prefix, the ID consists of an incrementing 26 digit value (to match |
28 | // previous timestamp output). | 24 | // previous timestamp output). After the prefix, the ID consists of a timestamp |
25 | // and an incrementing 8 hex digit value The timestamp means that multiple IDs | ||
26 | // created with the same prefix will sort in the order of their creation, even | ||
27 | // across multiple terraform executions, as long as the clock is not turned back | ||
28 | // between calls, and as long as any given terraform execution generates fewer | ||
29 | // than 4 billion IDs. | ||
29 | func PrefixedUniqueId(prefix string) string { | 30 | func PrefixedUniqueId(prefix string) string { |
31 | // Be precise to 4 digits of fractional seconds, but remove the dot before the | ||
32 | // fractional seconds. | ||
33 | timestamp := strings.Replace( | ||
34 | time.Now().UTC().Format("20060102150405.0000"), ".", "", 1) | ||
35 | |||
30 | idMutex.Lock() | 36 | idMutex.Lock() |
31 | defer idMutex.Unlock() | 37 | defer idMutex.Unlock() |
32 | return fmt.Sprintf("%s%026x", prefix, idCounter.Add(idCounter, big.NewInt(1))) | 38 | idCounter++ |
33 | } | 39 | return fmt.Sprintf("%s%s%08x", prefix, timestamp, idCounter) |
34 | |||
35 | func randomBytes(n int) []byte { | ||
36 | b := make([]byte, n) | ||
37 | rand.Read(b) | ||
38 | return b | ||
39 | } | 40 | } |
diff --git a/vendor/github.com/hashicorp/terraform/helper/resource/testing.go b/vendor/github.com/hashicorp/terraform/helper/resource/testing.go index ebdbde2..d7de1a0 100644 --- a/vendor/github.com/hashicorp/terraform/helper/resource/testing.go +++ b/vendor/github.com/hashicorp/terraform/helper/resource/testing.go | |||
@@ -383,11 +383,11 @@ func Test(t TestT, c TestCase) { | |||
383 | c.PreCheck() | 383 | c.PreCheck() |
384 | } | 384 | } |
385 | 385 | ||
386 | ctxProviders, err := testProviderFactories(c) | 386 | providerResolver, err := testProviderResolver(c) |
387 | if err != nil { | 387 | if err != nil { |
388 | t.Fatal(err) | 388 | t.Fatal(err) |
389 | } | 389 | } |
390 | opts := terraform.ContextOpts{Providers: ctxProviders} | 390 | opts := terraform.ContextOpts{ProviderResolver: providerResolver} |
391 | 391 | ||
392 | // A single state variable to track the lifecycle, starting with no state | 392 | // A single state variable to track the lifecycle, starting with no state |
393 | var state *terraform.State | 393 | var state *terraform.State |
@@ -400,15 +400,22 @@ func Test(t TestT, c TestCase) { | |||
400 | var err error | 400 | var err error |
401 | log.Printf("[WARN] Test: Executing step %d", i) | 401 | log.Printf("[WARN] Test: Executing step %d", i) |
402 | 402 | ||
403 | // Determine the test mode to execute | 403 | if step.Config == "" && !step.ImportState { |
404 | if step.Config != "" { | ||
405 | state, err = testStepConfig(opts, state, step) | ||
406 | } else if step.ImportState { | ||
407 | state, err = testStepImportState(opts, state, step) | ||
408 | } else { | ||
409 | err = fmt.Errorf( | 404 | err = fmt.Errorf( |
410 | "unknown test mode for step. Please see TestStep docs\n\n%#v", | 405 | "unknown test mode for step. Please see TestStep docs\n\n%#v", |
411 | step) | 406 | step) |
407 | } else { | ||
408 | if step.ImportState { | ||
409 | if step.Config == "" { | ||
410 | step.Config = testProviderConfig(c) | ||
411 | } | ||
412 | |||
413 | // Can optionally set step.Config in addition to | ||
414 | // step.ImportState, to provide config for the import. | ||
415 | state, err = testStepImportState(opts, state, step) | ||
416 | } else { | ||
417 | state, err = testStepConfig(opts, state, step) | ||
418 | } | ||
412 | } | 419 | } |
413 | 420 | ||
414 | // If there was an error, exit | 421 | // If there was an error, exit |
@@ -496,16 +503,29 @@ func Test(t TestT, c TestCase) { | |||
496 | } | 503 | } |
497 | } | 504 | } |
498 | 505 | ||
499 | // testProviderFactories is a helper to build the ResourceProviderFactory map | 506 | // testProviderConfig takes the list of Providers in a TestCase and returns a |
507 | // config with only empty provider blocks. This is useful for Import, where no | ||
508 | // config is provided, but the providers must be defined. | ||
509 | func testProviderConfig(c TestCase) string { | ||
510 | var lines []string | ||
511 | for p := range c.Providers { | ||
512 | lines = append(lines, fmt.Sprintf("provider %q {}\n", p)) | ||
513 | } | ||
514 | |||
515 | return strings.Join(lines, "") | ||
516 | } | ||
517 | |||
518 | // testProviderResolver is a helper to build a ResourceProviderResolver | ||
500 | // with pre instantiated ResourceProviders, so that we can reset them for the | 519 | // with pre instantiated ResourceProviders, so that we can reset them for the |
501 | // test, while only calling the factory function once. | 520 | // test, while only calling the factory function once. |
502 | // Any errors are stored so that they can be returned by the factory in | 521 | // Any errors are stored so that they can be returned by the factory in |
503 | // terraform to match non-test behavior. | 522 | // terraform to match non-test behavior. |
504 | func testProviderFactories(c TestCase) (map[string]terraform.ResourceProviderFactory, error) { | 523 | func testProviderResolver(c TestCase) (terraform.ResourceProviderResolver, error) { |
505 | ctxProviders := c.ProviderFactories // make(map[string]terraform.ResourceProviderFactory) | 524 | ctxProviders := c.ProviderFactories |
506 | if ctxProviders == nil { | 525 | if ctxProviders == nil { |
507 | ctxProviders = make(map[string]terraform.ResourceProviderFactory) | 526 | ctxProviders = make(map[string]terraform.ResourceProviderFactory) |
508 | } | 527 | } |
528 | |||
509 | // add any fixed providers | 529 | // add any fixed providers |
510 | for k, p := range c.Providers { | 530 | for k, p := range c.Providers { |
511 | ctxProviders[k] = terraform.ResourceProviderFactoryFixed(p) | 531 | ctxProviders[k] = terraform.ResourceProviderFactoryFixed(p) |
@@ -527,7 +547,7 @@ func testProviderFactories(c TestCase) (map[string]terraform.ResourceProviderFac | |||
527 | } | 547 | } |
528 | } | 548 | } |
529 | 549 | ||
530 | return ctxProviders, nil | 550 | return terraform.ResourceProviderResolverFixed(ctxProviders), nil |
531 | } | 551 | } |
532 | 552 | ||
533 | // UnitTest is a helper to force the acceptance testing harness to run in the | 553 | // UnitTest is a helper to force the acceptance testing harness to run in the |
diff --git a/vendor/github.com/hashicorp/terraform/helper/schema/provider.go b/vendor/github.com/hashicorp/terraform/helper/schema/provider.go index d52d2f5..fb28b41 100644 --- a/vendor/github.com/hashicorp/terraform/helper/schema/provider.go +++ b/vendor/github.com/hashicorp/terraform/helper/schema/provider.go | |||
@@ -8,6 +8,7 @@ import ( | |||
8 | "sync" | 8 | "sync" |
9 | 9 | ||
10 | "github.com/hashicorp/go-multierror" | 10 | "github.com/hashicorp/go-multierror" |
11 | "github.com/hashicorp/terraform/config" | ||
11 | "github.com/hashicorp/terraform/terraform" | 12 | "github.com/hashicorp/terraform/terraform" |
12 | ) | 13 | ) |
13 | 14 | ||
@@ -89,6 +90,13 @@ func (p *Provider) InternalValidate() error { | |||
89 | validationErrors = multierror.Append(validationErrors, err) | 90 | validationErrors = multierror.Append(validationErrors, err) |
90 | } | 91 | } |
91 | 92 | ||
93 | // Provider-specific checks | ||
94 | for k, _ := range sm { | ||
95 | if isReservedProviderFieldName(k) { | ||
96 | return fmt.Errorf("%s is a reserved field name for a provider", k) | ||
97 | } | ||
98 | } | ||
99 | |||
92 | for k, r := range p.ResourcesMap { | 100 | for k, r := range p.ResourcesMap { |
93 | if err := r.InternalValidate(nil, true); err != nil { | 101 | if err := r.InternalValidate(nil, true); err != nil { |
94 | validationErrors = multierror.Append(validationErrors, fmt.Errorf("resource %s: %s", k, err)) | 102 | validationErrors = multierror.Append(validationErrors, fmt.Errorf("resource %s: %s", k, err)) |
@@ -104,6 +112,15 @@ func (p *Provider) InternalValidate() error { | |||
104 | return validationErrors | 112 | return validationErrors |
105 | } | 113 | } |
106 | 114 | ||
115 | func isReservedProviderFieldName(name string) bool { | ||
116 | for _, reservedName := range config.ReservedProviderFields { | ||
117 | if name == reservedName { | ||
118 | return true | ||
119 | } | ||
120 | } | ||
121 | return false | ||
122 | } | ||
123 | |||
107 | // Meta returns the metadata associated with this provider that was | 124 | // Meta returns the metadata associated with this provider that was |
108 | // returned by the Configure call. It will be nil until Configure is called. | 125 | // returned by the Configure call. It will be nil until Configure is called. |
109 | func (p *Provider) Meta() interface{} { | 126 | func (p *Provider) Meta() interface{} { |
diff --git a/vendor/github.com/hashicorp/terraform/helper/schema/provisioner.go b/vendor/github.com/hashicorp/terraform/helper/schema/provisioner.go index 856c675..476192e 100644 --- a/vendor/github.com/hashicorp/terraform/helper/schema/provisioner.go +++ b/vendor/github.com/hashicorp/terraform/helper/schema/provisioner.go | |||
@@ -43,7 +43,7 @@ type Provisioner struct { | |||
43 | 43 | ||
44 | // ValidateFunc is a function for extended validation. This is optional | 44 | // ValidateFunc is a function for extended validation. This is optional |
45 | // and should be used when individual field validation is not enough. | 45 | // and should be used when individual field validation is not enough. |
46 | ValidateFunc func(*ResourceData) ([]string, []error) | 46 | ValidateFunc func(*terraform.ResourceConfig) ([]string, []error) |
47 | 47 | ||
48 | stopCtx context.Context | 48 | stopCtx context.Context |
49 | stopCtxCancel context.CancelFunc | 49 | stopCtxCancel context.CancelFunc |
@@ -121,32 +121,6 @@ func (p *Provisioner) Stop() error { | |||
121 | return nil | 121 | return nil |
122 | } | 122 | } |
123 | 123 | ||
124 | func (p *Provisioner) Validate(config *terraform.ResourceConfig) ([]string, []error) { | ||
125 | if err := p.InternalValidate(); err != nil { | ||
126 | return nil, []error{fmt.Errorf( | ||
127 | "Internal validation of the provisioner failed! This is always a bug\n"+ | ||
128 | "with the provisioner itself, and not a user issue. Please report\n"+ | ||
129 | "this bug:\n\n%s", err)} | ||
130 | } | ||
131 | w := []string{} | ||
132 | e := []error{} | ||
133 | if p.Schema != nil { | ||
134 | w2, e2 := schemaMap(p.Schema).Validate(config) | ||
135 | w = append(w, w2...) | ||
136 | e = append(e, e2...) | ||
137 | } | ||
138 | if p.ValidateFunc != nil { | ||
139 | data := &ResourceData{ | ||
140 | schema: p.Schema, | ||
141 | config: config, | ||
142 | } | ||
143 | w2, e2 := p.ValidateFunc(data) | ||
144 | w = append(w, w2...) | ||
145 | e = append(e, e2...) | ||
146 | } | ||
147 | return w, e | ||
148 | } | ||
149 | |||
150 | // Apply implementation of terraform.ResourceProvisioner interface. | 124 | // Apply implementation of terraform.ResourceProvisioner interface. |
151 | func (p *Provisioner) Apply( | 125 | func (p *Provisioner) Apply( |
152 | o terraform.UIOutput, | 126 | o terraform.UIOutput, |
@@ -204,3 +178,27 @@ func (p *Provisioner) Apply( | |||
204 | ctx = context.WithValue(ctx, ProvRawStateKey, s) | 178 | ctx = context.WithValue(ctx, ProvRawStateKey, s) |
205 | return p.ApplyFunc(ctx) | 179 | return p.ApplyFunc(ctx) |
206 | } | 180 | } |
181 | |||
182 | // Validate implements the terraform.ResourceProvisioner interface. | ||
183 | func (p *Provisioner) Validate(c *terraform.ResourceConfig) (ws []string, es []error) { | ||
184 | if err := p.InternalValidate(); err != nil { | ||
185 | return nil, []error{fmt.Errorf( | ||
186 | "Internal validation of the provisioner failed! This is always a bug\n"+ | ||
187 | "with the provisioner itself, and not a user issue. Please report\n"+ | ||
188 | "this bug:\n\n%s", err)} | ||
189 | } | ||
190 | |||
191 | if p.Schema != nil { | ||
192 | w, e := schemaMap(p.Schema).Validate(c) | ||
193 | ws = append(ws, w...) | ||
194 | es = append(es, e...) | ||
195 | } | ||
196 | |||
197 | if p.ValidateFunc != nil { | ||
198 | w, e := p.ValidateFunc(c) | ||
199 | ws = append(ws, w...) | ||
200 | es = append(es, e...) | ||
201 | } | ||
202 | |||
203 | return ws, es | ||
204 | } | ||
diff --git a/vendor/github.com/hashicorp/terraform/helper/schema/resource.go b/vendor/github.com/hashicorp/terraform/helper/schema/resource.go index c810558..ddba109 100644 --- a/vendor/github.com/hashicorp/terraform/helper/schema/resource.go +++ b/vendor/github.com/hashicorp/terraform/helper/schema/resource.go | |||
@@ -6,6 +6,7 @@ import ( | |||
6 | "log" | 6 | "log" |
7 | "strconv" | 7 | "strconv" |
8 | 8 | ||
9 | "github.com/hashicorp/terraform/config" | ||
9 | "github.com/hashicorp/terraform/terraform" | 10 | "github.com/hashicorp/terraform/terraform" |
10 | ) | 11 | ) |
11 | 12 | ||
@@ -142,6 +143,12 @@ func (r *Resource) Apply( | |||
142 | if err := rt.DiffDecode(d); err != nil { | 143 | if err := rt.DiffDecode(d); err != nil { |
143 | log.Printf("[ERR] Error decoding ResourceTimeout: %s", err) | 144 | log.Printf("[ERR] Error decoding ResourceTimeout: %s", err) |
144 | } | 145 | } |
146 | } else if s != nil { | ||
147 | if _, ok := s.Meta[TimeoutKey]; ok { | ||
148 | if err := rt.StateDecode(s); err != nil { | ||
149 | log.Printf("[ERR] Error decoding ResourceTimeout: %s", err) | ||
150 | } | ||
151 | } | ||
145 | } else { | 152 | } else { |
146 | log.Printf("[DEBUG] No meta timeoutkey found in Apply()") | 153 | log.Printf("[DEBUG] No meta timeoutkey found in Apply()") |
147 | } | 154 | } |
@@ -388,9 +395,25 @@ func (r *Resource) InternalValidate(topSchemaMap schemaMap, writable bool) error | |||
388 | } | 395 | } |
389 | } | 396 | } |
390 | 397 | ||
398 | // Resource-specific checks | ||
399 | for k, _ := range tsm { | ||
400 | if isReservedResourceFieldName(k) { | ||
401 | return fmt.Errorf("%s is a reserved field name for a resource", k) | ||
402 | } | ||
403 | } | ||
404 | |||
391 | return schemaMap(r.Schema).InternalValidate(tsm) | 405 | return schemaMap(r.Schema).InternalValidate(tsm) |
392 | } | 406 | } |
393 | 407 | ||
408 | func isReservedResourceFieldName(name string) bool { | ||
409 | for _, reservedName := range config.ReservedResourceFields { | ||
410 | if name == reservedName { | ||
411 | return true | ||
412 | } | ||
413 | } | ||
414 | return false | ||
415 | } | ||
416 | |||
394 | // Data returns a ResourceData struct for this Resource. Each return value | 417 | // Data returns a ResourceData struct for this Resource. Each return value |
395 | // is a separate copy and can be safely modified differently. | 418 | // is a separate copy and can be safely modified differently. |
396 | // | 419 | // |
diff --git a/vendor/github.com/hashicorp/terraform/helper/schema/schema.go b/vendor/github.com/hashicorp/terraform/helper/schema/schema.go index 632672a..acb5618 100644 --- a/vendor/github.com/hashicorp/terraform/helper/schema/schema.go +++ b/vendor/github.com/hashicorp/terraform/helper/schema/schema.go | |||
@@ -15,6 +15,7 @@ import ( | |||
15 | "fmt" | 15 | "fmt" |
16 | "os" | 16 | "os" |
17 | "reflect" | 17 | "reflect" |
18 | "regexp" | ||
18 | "sort" | 19 | "sort" |
19 | "strconv" | 20 | "strconv" |
20 | "strings" | 21 | "strings" |
@@ -661,7 +662,13 @@ func (m schemaMap) InternalValidate(topSchemaMap schemaMap) error { | |||
661 | if v.ValidateFunc != nil { | 662 | if v.ValidateFunc != nil { |
662 | switch v.Type { | 663 | switch v.Type { |
663 | case TypeList, TypeSet: | 664 | case TypeList, TypeSet: |
664 | return fmt.Errorf("ValidateFunc is not yet supported on lists or sets.") | 665 | return fmt.Errorf("%s: ValidateFunc is not yet supported on lists or sets.", k) |
666 | } | ||
667 | } | ||
668 | |||
669 | if v.Deprecated == "" && v.Removed == "" { | ||
670 | if !isValidFieldName(k) { | ||
671 | return fmt.Errorf("%s: Field name may only contain lowercase alphanumeric characters & underscores.", k) | ||
665 | } | 672 | } |
666 | } | 673 | } |
667 | } | 674 | } |
@@ -669,6 +676,11 @@ func (m schemaMap) InternalValidate(topSchemaMap schemaMap) error { | |||
669 | return nil | 676 | return nil |
670 | } | 677 | } |
671 | 678 | ||
679 | func isValidFieldName(name string) bool { | ||
680 | re := regexp.MustCompile("^[a-z0-9_]+$") | ||
681 | return re.MatchString(name) | ||
682 | } | ||
683 | |||
672 | func (m schemaMap) diff( | 684 | func (m schemaMap) diff( |
673 | k string, | 685 | k string, |
674 | schema *Schema, | 686 | schema *Schema, |
diff --git a/vendor/github.com/hashicorp/terraform/helper/shadow/closer.go b/vendor/github.com/hashicorp/terraform/helper/shadow/closer.go index 7edd5e7..edc1e2a 100644 --- a/vendor/github.com/hashicorp/terraform/helper/shadow/closer.go +++ b/vendor/github.com/hashicorp/terraform/helper/shadow/closer.go | |||
@@ -39,6 +39,8 @@ func (w *closeWalker) Struct(reflect.Value) error { | |||
39 | return nil | 39 | return nil |
40 | } | 40 | } |
41 | 41 | ||
42 | var closerType = reflect.TypeOf((*io.Closer)(nil)).Elem() | ||
43 | |||
42 | func (w *closeWalker) StructField(f reflect.StructField, v reflect.Value) error { | 44 | func (w *closeWalker) StructField(f reflect.StructField, v reflect.Value) error { |
43 | // Not sure why this would be but lets avoid some panics | 45 | // Not sure why this would be but lets avoid some panics |
44 | if !v.IsValid() { | 46 | if !v.IsValid() { |
@@ -56,17 +58,18 @@ func (w *closeWalker) StructField(f reflect.StructField, v reflect.Value) error | |||
56 | return nil | 58 | return nil |
57 | } | 59 | } |
58 | 60 | ||
59 | // We're looking for an io.Closer | 61 | var closer io.Closer |
60 | raw := v.Interface() | 62 | if v.Type().Implements(closerType) { |
61 | if raw == nil { | 63 | closer = v.Interface().(io.Closer) |
62 | return nil | 64 | } else if v.CanAddr() { |
65 | // The Close method may require a pointer receiver, but we only have a value. | ||
66 | v := v.Addr() | ||
67 | if v.Type().Implements(closerType) { | ||
68 | closer = v.Interface().(io.Closer) | ||
69 | } | ||
63 | } | 70 | } |
64 | 71 | ||
65 | closer, ok := raw.(io.Closer) | 72 | if closer == nil { |
66 | if !ok && v.CanAddr() { | ||
67 | closer, ok = v.Addr().Interface().(io.Closer) | ||
68 | } | ||
69 | if !ok { | ||
70 | return reflectwalk.SkipEntry | 73 | return reflectwalk.SkipEntry |
71 | } | 74 | } |
72 | 75 | ||
diff --git a/vendor/github.com/hashicorp/terraform/helper/shadow/value.go b/vendor/github.com/hashicorp/terraform/helper/shadow/value.go index 2413335..178b7e7 100644 --- a/vendor/github.com/hashicorp/terraform/helper/shadow/value.go +++ b/vendor/github.com/hashicorp/terraform/helper/shadow/value.go | |||
@@ -26,6 +26,14 @@ type Value struct { | |||
26 | valueSet bool | 26 | valueSet bool |
27 | } | 27 | } |
28 | 28 | ||
29 | func (v *Value) Lock() { | ||
30 | v.lock.Lock() | ||
31 | } | ||
32 | |||
33 | func (v *Value) Unlock() { | ||
34 | v.lock.Unlock() | ||
35 | } | ||
36 | |||
29 | // Close closes the value. This can never fail. For a definition of | 37 | // Close closes the value. This can never fail. For a definition of |
30 | // "close" see the struct docs. | 38 | // "close" see the struct docs. |
31 | func (w *Value) Close() error { | 39 | func (w *Value) Close() error { |
diff --git a/vendor/github.com/hashicorp/terraform/moduledeps/dependencies.go b/vendor/github.com/hashicorp/terraform/moduledeps/dependencies.go new file mode 100644 index 0000000..87c8431 --- /dev/null +++ b/vendor/github.com/hashicorp/terraform/moduledeps/dependencies.go | |||
@@ -0,0 +1,43 @@ | |||
1 | package moduledeps | ||
2 | |||
3 | import ( | ||
4 | "github.com/hashicorp/terraform/plugin/discovery" | ||
5 | ) | ||
6 | |||
7 | // Providers describes a set of provider dependencies for a given module. | ||
8 | // | ||
9 | // Each named provider instance can have one version constraint. | ||
10 | type Providers map[ProviderInstance]ProviderDependency | ||
11 | |||
12 | // ProviderDependency describes the dependency for a particular provider | ||
13 | // instance, including both the set of allowed versions and the reason for | ||
14 | // the dependency. | ||
15 | type ProviderDependency struct { | ||
16 | Constraints discovery.Constraints | ||
17 | Reason ProviderDependencyReason | ||
18 | } | ||
19 | |||
20 | // ProviderDependencyReason is an enumeration of reasons why a dependency might be | ||
21 | // present. | ||
22 | type ProviderDependencyReason int | ||
23 | |||
24 | const ( | ||
25 | // ProviderDependencyExplicit means that there is an explicit "provider" | ||
26 | // block in the configuration for this module. | ||
27 | ProviderDependencyExplicit ProviderDependencyReason = iota | ||
28 | |||
29 | // ProviderDependencyImplicit means that there is no explicit "provider" | ||
30 | // block but there is at least one resource that uses this provider. | ||
31 | ProviderDependencyImplicit | ||
32 | |||
33 | // ProviderDependencyInherited is a special case of | ||
34 | // ProviderDependencyImplicit where a parent module has defined a | ||
35 | // configuration for the provider that has been inherited by at least one | ||
36 | // resource in this module. | ||
37 | ProviderDependencyInherited | ||
38 | |||
39 | // ProviderDependencyFromState means that this provider is not currently | ||
40 | // referenced by configuration at all, but some existing instances in | ||
41 | // the state still depend on it. | ||
42 | ProviderDependencyFromState | ||
43 | ) | ||
diff --git a/vendor/github.com/hashicorp/terraform/moduledeps/doc.go b/vendor/github.com/hashicorp/terraform/moduledeps/doc.go new file mode 100644 index 0000000..7eff083 --- /dev/null +++ b/vendor/github.com/hashicorp/terraform/moduledeps/doc.go | |||
@@ -0,0 +1,7 @@ | |||
1 | // Package moduledeps contains types that can be used to describe the | ||
2 | // providers required for all of the modules in a module tree. | ||
3 | // | ||
4 | // It does not itself contain the functionality for populating such | ||
5 | // data structures; that's in Terraform core, since this package intentionally | ||
6 | // does not depend on terraform core to avoid package dependency cycles. | ||
7 | package moduledeps | ||
diff --git a/vendor/github.com/hashicorp/terraform/moduledeps/module.go b/vendor/github.com/hashicorp/terraform/moduledeps/module.go new file mode 100644 index 0000000..d6cbaf5 --- /dev/null +++ b/vendor/github.com/hashicorp/terraform/moduledeps/module.go | |||
@@ -0,0 +1,204 @@ | |||
1 | package moduledeps | ||
2 | |||
3 | import ( | ||
4 | "sort" | ||
5 | "strings" | ||
6 | |||
7 | "github.com/hashicorp/terraform/plugin/discovery" | ||
8 | ) | ||
9 | |||
10 | // Module represents the dependencies of a single module, as well being | ||
11 | // a node in a tree of such structures representing the dependencies of | ||
12 | // an entire configuration. | ||
13 | type Module struct { | ||
14 | Name string | ||
15 | Providers Providers | ||
16 | Children []*Module | ||
17 | } | ||
18 | |||
19 | // WalkFunc is a callback type for use with Module.WalkTree | ||
20 | type WalkFunc func(path []string, parent *Module, current *Module) error | ||
21 | |||
22 | // WalkTree calls the given callback once for the receiver and then | ||
23 | // once for each descendent, in an order such that parents are called | ||
24 | // before their children and siblings are called in the order they | ||
25 | // appear in the Children slice. | ||
26 | // | ||
27 | // When calling the callback, parent will be nil for the first call | ||
28 | // for the receiving module, and then set to the direct parent of | ||
29 | // each module for the subsequent calls. | ||
30 | // | ||
31 | // The path given to the callback is valid only until the callback | ||
32 | // returns, after which it will be mutated and reused. Callbacks must | ||
33 | // therefore copy the path slice if they wish to retain it. | ||
34 | // | ||
35 | // If the given callback returns an error, the walk will be aborted at | ||
36 | // that point and that error returned to the caller. | ||
37 | // | ||
38 | // This function is not thread-safe for concurrent modifications of the | ||
39 | // data structure, so it's the caller's responsibility to arrange for that | ||
40 | // should it be needed. | ||
41 | // | ||
42 | // It is safe for a callback to modify the descendents of the "current" | ||
43 | // module, including the ordering of the Children slice itself, but the | ||
44 | // callback MUST NOT modify the parent module. | ||
45 | func (m *Module) WalkTree(cb WalkFunc) error { | ||
46 | return walkModuleTree(make([]string, 0, 1), nil, m, cb) | ||
47 | } | ||
48 | |||
49 | func walkModuleTree(path []string, parent *Module, current *Module, cb WalkFunc) error { | ||
50 | path = append(path, current.Name) | ||
51 | err := cb(path, parent, current) | ||
52 | if err != nil { | ||
53 | return err | ||
54 | } | ||
55 | |||
56 | for _, child := range current.Children { | ||
57 | err := walkModuleTree(path, current, child, cb) | ||
58 | if err != nil { | ||
59 | return err | ||
60 | } | ||
61 | } | ||
62 | return nil | ||
63 | } | ||
64 | |||
65 | // SortChildren sorts the Children slice into lexicographic order by | ||
66 | // name, in-place. | ||
67 | // | ||
68 | // This is primarily useful prior to calling WalkTree so that the walk | ||
69 | // will proceed in a consistent order. | ||
70 | func (m *Module) SortChildren() { | ||
71 | sort.Sort(sortModules{m.Children}) | ||
72 | } | ||
73 | |||
74 | // SortDescendents is a convenience wrapper for calling SortChildren on | ||
75 | // the receiver and all of its descendent modules. | ||
76 | func (m *Module) SortDescendents() { | ||
77 | m.WalkTree(func(path []string, parent *Module, current *Module) error { | ||
78 | current.SortChildren() | ||
79 | return nil | ||
80 | }) | ||
81 | } | ||
82 | |||
83 | type sortModules struct { | ||
84 | modules []*Module | ||
85 | } | ||
86 | |||
87 | func (s sortModules) Len() int { | ||
88 | return len(s.modules) | ||
89 | } | ||
90 | |||
91 | func (s sortModules) Less(i, j int) bool { | ||
92 | cmp := strings.Compare(s.modules[i].Name, s.modules[j].Name) | ||
93 | return cmp < 0 | ||
94 | } | ||
95 | |||
96 | func (s sortModules) Swap(i, j int) { | ||
97 | s.modules[i], s.modules[j] = s.modules[j], s.modules[i] | ||
98 | } | ||
99 | |||
100 | // PluginRequirements produces a PluginRequirements structure that can | ||
101 | // be used with discovery.PluginMetaSet.ConstrainVersions to identify | ||
102 | // suitable plugins to satisfy the module's provider dependencies. | ||
103 | // | ||
104 | // This method only considers the direct requirements of the receiver. | ||
105 | // Use AllPluginRequirements to flatten the dependencies for the | ||
106 | // entire tree of modules. | ||
107 | // | ||
108 | // Requirements returned by this method include only version constraints, | ||
109 | // and apply no particular SHA256 hash constraint. | ||
110 | func (m *Module) PluginRequirements() discovery.PluginRequirements { | ||
111 | ret := make(discovery.PluginRequirements) | ||
112 | for inst, dep := range m.Providers { | ||
113 | // m.Providers is keyed on provider names, such as "aws.foo". | ||
114 | // a PluginRequirements wants keys to be provider *types*, such | ||
115 | // as "aws". If there are multiple aliases for the same | ||
116 | // provider then we will flatten them into a single requirement | ||
117 | // by combining their constraint sets. | ||
118 | pty := inst.Type() | ||
119 | if existing, exists := ret[pty]; exists { | ||
120 | ret[pty].Versions = existing.Versions.Append(dep.Constraints) | ||
121 | } else { | ||
122 | ret[pty] = &discovery.PluginConstraints{ | ||
123 | Versions: dep.Constraints, | ||
124 | } | ||
125 | } | ||
126 | } | ||
127 | return ret | ||
128 | } | ||
129 | |||
130 | // AllPluginRequirements calls PluginRequirements for the receiver and all | ||
131 | // of its descendents, and merges the result into a single PluginRequirements | ||
132 | // structure that would satisfy all of the modules together. | ||
133 | // | ||
134 | // Requirements returned by this method include only version constraints, | ||
135 | // and apply no particular SHA256 hash constraint. | ||
136 | func (m *Module) AllPluginRequirements() discovery.PluginRequirements { | ||
137 | var ret discovery.PluginRequirements | ||
138 | m.WalkTree(func(path []string, parent *Module, current *Module) error { | ||
139 | ret = ret.Merge(current.PluginRequirements()) | ||
140 | return nil | ||
141 | }) | ||
142 | return ret | ||
143 | } | ||
144 | |||
145 | // Equal returns true if the receiver is the root of an identical tree | ||
146 | // to the other given Module. This is a deep comparison that considers | ||
147 | // the equality of all downstream modules too. | ||
148 | // | ||
149 | // The children are considered to be ordered, so callers may wish to use | ||
150 | // SortDescendents first to normalize the order of the slices of child nodes. | ||
151 | // | ||
152 | // The implementation of this function is not optimized since it is provided | ||
153 | // primarily for use in tests. | ||
154 | func (m *Module) Equal(other *Module) bool { | ||
155 | // take care of nils first | ||
156 | if m == nil && other == nil { | ||
157 | return true | ||
158 | } else if (m == nil && other != nil) || (m != nil && other == nil) { | ||
159 | return false | ||
160 | } | ||
161 | |||
162 | if m.Name != other.Name { | ||
163 | return false | ||
164 | } | ||
165 | |||
166 | if len(m.Providers) != len(other.Providers) { | ||
167 | return false | ||
168 | } | ||
169 | if len(m.Children) != len(other.Children) { | ||
170 | return false | ||
171 | } | ||
172 | |||
173 | // Can't use reflect.DeepEqual on this provider structure because | ||
174 | // the nested Constraints objects contain function pointers that | ||
175 | // never compare as equal. So we'll need to walk it the long way. | ||
176 | for inst, dep := range m.Providers { | ||
177 | if _, exists := other.Providers[inst]; !exists { | ||
178 | return false | ||
179 | } | ||
180 | |||
181 | if dep.Reason != other.Providers[inst].Reason { | ||
182 | return false | ||
183 | } | ||
184 | |||
185 | // Constraints are not too easy to compare robustly, so | ||
186 | // we'll just use their string representations as a proxy | ||
187 | // for now. | ||
188 | if dep.Constraints.String() != other.Providers[inst].Constraints.String() { | ||
189 | return false | ||
190 | } | ||
191 | } | ||
192 | |||
193 | // Above we already checked that we have the same number of children | ||
194 | // in each module, so now we just need to check that they are | ||
195 | // recursively equal. | ||
196 | for i := range m.Children { | ||
197 | if !m.Children[i].Equal(other.Children[i]) { | ||
198 | return false | ||
199 | } | ||
200 | } | ||
201 | |||
202 | // If we fall out here then they are equal | ||
203 | return true | ||
204 | } | ||
diff --git a/vendor/github.com/hashicorp/terraform/moduledeps/provider.go b/vendor/github.com/hashicorp/terraform/moduledeps/provider.go new file mode 100644 index 0000000..89ceefb --- /dev/null +++ b/vendor/github.com/hashicorp/terraform/moduledeps/provider.go | |||
@@ -0,0 +1,30 @@ | |||
1 | package moduledeps | ||
2 | |||
3 | import ( | ||
4 | "strings" | ||
5 | ) | ||
6 | |||
7 | // ProviderInstance describes a particular provider instance by its full name, | ||
8 | // like "null" or "aws.foo". | ||
9 | type ProviderInstance string | ||
10 | |||
11 | // Type returns the provider type of this instance. For example, for an instance | ||
12 | // named "aws.foo" the type is "aws". | ||
13 | func (p ProviderInstance) Type() string { | ||
14 | t := string(p) | ||
15 | if dotPos := strings.Index(t, "."); dotPos != -1 { | ||
16 | t = t[:dotPos] | ||
17 | } | ||
18 | return t | ||
19 | } | ||
20 | |||
21 | // Alias returns the alias of this provider, if any. An instance named "aws.foo" | ||
22 | // has the alias "foo", while an instance named just "docker" has no alias, | ||
23 | // so the empty string would be returned. | ||
24 | func (p ProviderInstance) Alias() string { | ||
25 | t := string(p) | ||
26 | if dotPos := strings.Index(t, "."); dotPos != -1 { | ||
27 | return t[dotPos+1:] | ||
28 | } | ||
29 | return "" | ||
30 | } | ||
diff --git a/vendor/github.com/hashicorp/terraform/plugin/client.go b/vendor/github.com/hashicorp/terraform/plugin/client.go new file mode 100644 index 0000000..3a5cb7a --- /dev/null +++ b/vendor/github.com/hashicorp/terraform/plugin/client.go | |||
@@ -0,0 +1,24 @@ | |||
1 | package plugin | ||
2 | |||
3 | import ( | ||
4 | "os/exec" | ||
5 | |||
6 | plugin "github.com/hashicorp/go-plugin" | ||
7 | "github.com/hashicorp/terraform/plugin/discovery" | ||
8 | ) | ||
9 | |||
10 | // ClientConfig returns a configuration object that can be used to instantiate | ||
11 | // a client for the plugin described by the given metadata. | ||
12 | func ClientConfig(m discovery.PluginMeta) *plugin.ClientConfig { | ||
13 | return &plugin.ClientConfig{ | ||
14 | Cmd: exec.Command(m.Path), | ||
15 | HandshakeConfig: Handshake, | ||
16 | Managed: true, | ||
17 | Plugins: PluginMap, | ||
18 | } | ||
19 | } | ||
20 | |||
21 | // Client returns a plugin client for the plugin described by the given metadata. | ||
22 | func Client(m discovery.PluginMeta) *plugin.Client { | ||
23 | return plugin.NewClient(ClientConfig(m)) | ||
24 | } | ||
diff --git a/vendor/github.com/hashicorp/terraform/plugin/discovery/error.go b/vendor/github.com/hashicorp/terraform/plugin/discovery/error.go new file mode 100644 index 0000000..df855a7 --- /dev/null +++ b/vendor/github.com/hashicorp/terraform/plugin/discovery/error.go | |||
@@ -0,0 +1,30 @@ | |||
1 | package discovery | ||
2 | |||
3 | // Error is a type used to describe situations that the caller must handle | ||
4 | // since they indicate some form of user error. | ||
5 | // | ||
6 | // The functions and methods that return these specialized errors indicate so | ||
7 | // in their documentation. The Error type should not itself be used directly, | ||
8 | // but rather errors should be compared using the == operator with the | ||
9 | // error constants in this package. | ||
10 | // | ||
11 | // Values of this type are _not_ used when the error being reported is an | ||
12 | // operational error (server unavailable, etc) or indicative of a bug in | ||
13 | // this package or its caller. | ||
14 | type Error string | ||
15 | |||
16 | // ErrorNoSuitableVersion indicates that a suitable version (meeting given | ||
17 | // constraints) is not available. | ||
18 | const ErrorNoSuitableVersion = Error("no suitable version is available") | ||
19 | |||
20 | // ErrorNoVersionCompatible indicates that all of the available versions | ||
21 | // that otherwise met constraints are not compatible with the current | ||
22 | // version of Terraform. | ||
23 | const ErrorNoVersionCompatible = Error("no available version is compatible with this version of Terraform") | ||
24 | |||
25 | // ErrorNoSuchProvider indicates that no provider exists with a name given | ||
26 | const ErrorNoSuchProvider = Error("no provider exists with the given name") | ||
27 | |||
28 | func (err Error) Error() string { | ||
29 | return string(err) | ||
30 | } | ||
diff --git a/vendor/github.com/hashicorp/terraform/plugin/discovery/find.go b/vendor/github.com/hashicorp/terraform/plugin/discovery/find.go new file mode 100644 index 0000000..f5bc4c1 --- /dev/null +++ b/vendor/github.com/hashicorp/terraform/plugin/discovery/find.go | |||
@@ -0,0 +1,168 @@ | |||
1 | package discovery | ||
2 | |||
3 | import ( | ||
4 | "io/ioutil" | ||
5 | "log" | ||
6 | "path/filepath" | ||
7 | "strings" | ||
8 | ) | ||
9 | |||
10 | // FindPlugins looks in the given directories for files whose filenames | ||
11 | // suggest that they are plugins of the given kind (e.g. "provider") and | ||
12 | // returns a PluginMetaSet representing the discovered potential-plugins. | ||
13 | // | ||
14 | // Currently this supports two different naming schemes. The current | ||
15 | // standard naming scheme is a subdirectory called $GOOS-$GOARCH containing | ||
16 | // files named terraform-$KIND-$NAME-V$VERSION. The legacy naming scheme is | ||
17 | // files directly in the given directory whose names are like | ||
18 | // terraform-$KIND-$NAME. | ||
19 | // | ||
20 | // Only one plugin will be returned for each unique plugin (name, version) | ||
21 | // pair, with preference given to files found in earlier directories. | ||
22 | // | ||
23 | // This is a convenience wrapper around FindPluginPaths and ResolvePluginsPaths. | ||
24 | func FindPlugins(kind string, dirs []string) PluginMetaSet { | ||
25 | return ResolvePluginPaths(FindPluginPaths(kind, dirs)) | ||
26 | } | ||
27 | |||
28 | // FindPluginPaths looks in the given directories for files whose filenames | ||
29 | // suggest that they are plugins of the given kind (e.g. "provider"). | ||
30 | // | ||
31 | // The return value is a list of absolute paths that appear to refer to | ||
32 | // plugins in the given directories, based only on what can be inferred | ||
33 | // from the naming scheme. The paths returned are ordered such that files | ||
34 | // in later dirs appear after files in earlier dirs in the given directory | ||
35 | // list. Within the same directory plugins are returned in a consistent but | ||
36 | // undefined order. | ||
37 | func FindPluginPaths(kind string, dirs []string) []string { | ||
38 | // This is just a thin wrapper around findPluginPaths so that we can | ||
39 | // use the latter in tests with a fake machineName so we can use our | ||
40 | // test fixtures. | ||
41 | return findPluginPaths(kind, dirs) | ||
42 | } | ||
43 | |||
44 | func findPluginPaths(kind string, dirs []string) []string { | ||
45 | prefix := "terraform-" + kind + "-" | ||
46 | |||
47 | ret := make([]string, 0, len(dirs)) | ||
48 | |||
49 | for _, dir := range dirs { | ||
50 | items, err := ioutil.ReadDir(dir) | ||
51 | if err != nil { | ||
52 | // Ignore missing dirs, non-dirs, etc | ||
53 | continue | ||
54 | } | ||
55 | |||
56 | log.Printf("[DEBUG] checking for %s in %q", kind, dir) | ||
57 | |||
58 | for _, item := range items { | ||
59 | fullName := item.Name() | ||
60 | |||
61 | if !strings.HasPrefix(fullName, prefix) { | ||
62 | log.Printf("[DEBUG] skipping %q, not a %s", fullName, kind) | ||
63 | continue | ||
64 | } | ||
65 | |||
66 | // New-style paths must have a version segment in filename | ||
67 | if strings.Contains(strings.ToLower(fullName), "_v") { | ||
68 | absPath, err := filepath.Abs(filepath.Join(dir, fullName)) | ||
69 | if err != nil { | ||
70 | log.Printf("[ERROR] plugin filepath error: %s", err) | ||
71 | continue | ||
72 | } | ||
73 | |||
74 | log.Printf("[DEBUG] found %s %q", kind, fullName) | ||
75 | ret = append(ret, filepath.Clean(absPath)) | ||
76 | continue | ||
77 | } | ||
78 | |||
79 | // Legacy style with files directly in the base directory | ||
80 | absPath, err := filepath.Abs(filepath.Join(dir, fullName)) | ||
81 | if err != nil { | ||
82 | log.Printf("[ERROR] plugin filepath error: %s", err) | ||
83 | continue | ||
84 | } | ||
85 | |||
86 | log.Printf("[WARNING] found legacy %s %q", kind, fullName) | ||
87 | |||
88 | ret = append(ret, filepath.Clean(absPath)) | ||
89 | } | ||
90 | } | ||
91 | |||
92 | return ret | ||
93 | } | ||
94 | |||
95 | // ResolvePluginPaths takes a list of paths to plugin executables (as returned | ||
96 | // by e.g. FindPluginPaths) and produces a PluginMetaSet describing the | ||
97 | // referenced plugins. | ||
98 | // | ||
99 | // If the same combination of plugin name and version appears multiple times, | ||
100 | // the earlier reference will be preferred. Several different versions of | ||
101 | // the same plugin name may be returned, in which case the methods of | ||
102 | // PluginMetaSet can be used to filter down. | ||
103 | func ResolvePluginPaths(paths []string) PluginMetaSet { | ||
104 | s := make(PluginMetaSet) | ||
105 | |||
106 | type nameVersion struct { | ||
107 | Name string | ||
108 | Version string | ||
109 | } | ||
110 | found := make(map[nameVersion]struct{}) | ||
111 | |||
112 | for _, path := range paths { | ||
113 | baseName := strings.ToLower(filepath.Base(path)) | ||
114 | if !strings.HasPrefix(baseName, "terraform-") { | ||
115 | // Should never happen with reasonable input | ||
116 | continue | ||
117 | } | ||
118 | |||
119 | baseName = baseName[10:] | ||
120 | firstDash := strings.Index(baseName, "-") | ||
121 | if firstDash == -1 { | ||
122 | // Should never happen with reasonable input | ||
123 | continue | ||
124 | } | ||
125 | |||
126 | baseName = baseName[firstDash+1:] | ||
127 | if baseName == "" { | ||
128 | // Should never happen with reasonable input | ||
129 | continue | ||
130 | } | ||
131 | |||
132 | // Trim the .exe suffix used on Windows before we start wrangling | ||
133 | // the remainder of the path. | ||
134 | if strings.HasSuffix(baseName, ".exe") { | ||
135 | baseName = baseName[:len(baseName)-4] | ||
136 | } | ||
137 | |||
138 | parts := strings.SplitN(baseName, "_v", 2) | ||
139 | name := parts[0] | ||
140 | version := VersionZero | ||
141 | if len(parts) == 2 { | ||
142 | version = parts[1] | ||
143 | } | ||
144 | |||
145 | // Auto-installed plugins contain an extra name portion representing | ||
146 | // the expected plugin version, which we must trim off. | ||
147 | if underX := strings.Index(version, "_x"); underX != -1 { | ||
148 | version = version[:underX] | ||
149 | } | ||
150 | |||
151 | if _, ok := found[nameVersion{name, version}]; ok { | ||
152 | // Skip duplicate versions of the same plugin | ||
153 | // (We do this during this step because after this we will be | ||
154 | // dealing with sets and thus lose our ordering with which to | ||
155 | // decide preference.) | ||
156 | continue | ||
157 | } | ||
158 | |||
159 | s.Add(PluginMeta{ | ||
160 | Name: name, | ||
161 | Version: VersionStr(version), | ||
162 | Path: path, | ||
163 | }) | ||
164 | found[nameVersion{name, version}] = struct{}{} | ||
165 | } | ||
166 | |||
167 | return s | ||
168 | } | ||
diff --git a/vendor/github.com/hashicorp/terraform/plugin/discovery/get.go b/vendor/github.com/hashicorp/terraform/plugin/discovery/get.go new file mode 100644 index 0000000..241b5cb --- /dev/null +++ b/vendor/github.com/hashicorp/terraform/plugin/discovery/get.go | |||
@@ -0,0 +1,424 @@ | |||
1 | package discovery | ||
2 | |||
3 | import ( | ||
4 | "errors" | ||
5 | "fmt" | ||
6 | "io/ioutil" | ||
7 | "log" | ||
8 | "net/http" | ||
9 | "os" | ||
10 | "runtime" | ||
11 | "strconv" | ||
12 | "strings" | ||
13 | |||
14 | "golang.org/x/net/html" | ||
15 | |||
16 | cleanhttp "github.com/hashicorp/go-cleanhttp" | ||
17 | getter "github.com/hashicorp/go-getter" | ||
18 | multierror "github.com/hashicorp/go-multierror" | ||
19 | ) | ||
20 | |||
21 | // Releases are located by parsing the html listing from releases.hashicorp.com. | ||
22 | // | ||
23 | // The URL for releases follows the pattern: | ||
24 | // https://releases.hashicorp.com/terraform-provider-name/<x.y.z>/terraform-provider-name_<x.y.z>_<os>_<arch>.<ext> | ||
25 | // | ||
26 | // The plugin protocol version will be saved with the release and returned in | ||
27 | // the header X-TERRAFORM_PROTOCOL_VERSION. | ||
28 | |||
29 | const protocolVersionHeader = "x-terraform-protocol-version" | ||
30 | |||
31 | var releaseHost = "https://releases.hashicorp.com" | ||
32 | |||
33 | var httpClient = cleanhttp.DefaultClient() | ||
34 | |||
35 | // An Installer maintains a local cache of plugins by downloading plugins | ||
36 | // from an online repository. | ||
37 | type Installer interface { | ||
38 | Get(name string, req Constraints) (PluginMeta, error) | ||
39 | PurgeUnused(used map[string]PluginMeta) (removed PluginMetaSet, err error) | ||
40 | } | ||
41 | |||
42 | // ProviderInstaller is an Installer implementation that knows how to | ||
43 | // download Terraform providers from the official HashiCorp releases service | ||
44 | // into a local directory. The files downloaded are compliant with the | ||
45 | // naming scheme expected by FindPlugins, so the target directory of a | ||
46 | // provider installer can be used as one of several plugin discovery sources. | ||
47 | type ProviderInstaller struct { | ||
48 | Dir string | ||
49 | |||
50 | PluginProtocolVersion uint | ||
51 | |||
52 | // OS and Arch specify the OS and architecture that should be used when | ||
53 | // installing plugins. These use the same labels as the runtime.GOOS and | ||
54 | // runtime.GOARCH variables respectively, and indeed the values of these | ||
55 | // are used as defaults if either of these is the empty string. | ||
56 | OS string | ||
57 | Arch string | ||
58 | |||
59 | // Skip checksum and signature verification | ||
60 | SkipVerify bool | ||
61 | } | ||
62 | |||
63 | // Get is part of an implementation of type Installer, and attempts to download | ||
64 | // and install a Terraform provider matching the given constraints. | ||
65 | // | ||
66 | // This method may return one of a number of sentinel errors from this | ||
67 | // package to indicate issues that are likely to be resolvable via user action: | ||
68 | // | ||
69 | // ErrorNoSuchProvider: no provider with the given name exists in the repository. | ||
70 | // ErrorNoSuitableVersion: the provider exists but no available version matches constraints. | ||
71 | // ErrorNoVersionCompatible: a plugin was found within the constraints but it is | ||
72 | // incompatible with the current Terraform version. | ||
73 | // | ||
74 | // These errors should be recognized and handled as special cases by the caller | ||
75 | // to present a suitable user-oriented error message. | ||
76 | // | ||
77 | // All other errors indicate an internal problem that is likely _not_ solvable | ||
78 | // through user action, or at least not within Terraform's scope. Error messages | ||
79 | // are produced under the assumption that if presented to the user they will | ||
80 | // be presented alongside context about what is being installed, and thus the | ||
81 | // error messages do not redundantly include such information. | ||
82 | func (i *ProviderInstaller) Get(provider string, req Constraints) (PluginMeta, error) { | ||
83 | versions, err := i.listProviderVersions(provider) | ||
84 | // TODO: return multiple errors | ||
85 | if err != nil { | ||
86 | return PluginMeta{}, err | ||
87 | } | ||
88 | |||
89 | if len(versions) == 0 { | ||
90 | return PluginMeta{}, ErrorNoSuitableVersion | ||
91 | } | ||
92 | |||
93 | versions = allowedVersions(versions, req) | ||
94 | if len(versions) == 0 { | ||
95 | return PluginMeta{}, ErrorNoSuitableVersion | ||
96 | } | ||
97 | |||
98 | // sort them newest to oldest | ||
99 | Versions(versions).Sort() | ||
100 | |||
101 | // take the first matching plugin we find | ||
102 | for _, v := range versions { | ||
103 | url := i.providerURL(provider, v.String()) | ||
104 | |||
105 | if !i.SkipVerify { | ||
106 | sha256, err := i.getProviderChecksum(provider, v.String()) | ||
107 | if err != nil { | ||
108 | return PluginMeta{}, err | ||
109 | } | ||
110 | |||
111 | // add the checksum parameter for go-getter to verify the download for us. | ||
112 | if sha256 != "" { | ||
113 | url = url + "?checksum=sha256:" + sha256 | ||
114 | } | ||
115 | } | ||
116 | |||
117 | log.Printf("[DEBUG] fetching provider info for %s version %s", provider, v) | ||
118 | if checkPlugin(url, i.PluginProtocolVersion) { | ||
119 | log.Printf("[DEBUG] getting provider %q version %q at %s", provider, v, url) | ||
120 | err := getter.Get(i.Dir, url) | ||
121 | if err != nil { | ||
122 | return PluginMeta{}, err | ||
123 | } | ||
124 | |||
125 | // Find what we just installed | ||
126 | // (This is weird, because go-getter doesn't directly return | ||
127 | // information about what was extracted, and we just extracted | ||
128 | // the archive directly into a shared dir here.) | ||
129 | log.Printf("[DEBUG] looking for the %s %s plugin we just installed", provider, v) | ||
130 | metas := FindPlugins("provider", []string{i.Dir}) | ||
131 | log.Printf("[DEBUG] all plugins found %#v", metas) | ||
132 | metas, _ = metas.ValidateVersions() | ||
133 | metas = metas.WithName(provider).WithVersion(v) | ||
134 | log.Printf("[DEBUG] filtered plugins %#v", metas) | ||
135 | if metas.Count() == 0 { | ||
136 | // This should never happen. Suggests that the release archive | ||
137 | // contains an executable file whose name doesn't match the | ||
138 | // expected convention. | ||
139 | return PluginMeta{}, fmt.Errorf( | ||
140 | "failed to find installed plugin version %s; this is a bug in Terraform and should be reported", | ||
141 | v, | ||
142 | ) | ||
143 | } | ||
144 | |||
145 | if metas.Count() > 1 { | ||
146 | // This should also never happen, and suggests that a | ||
147 | // particular version was re-released with a different | ||
148 | // executable filename. We consider releases as immutable, so | ||
149 | // this is an error. | ||
150 | return PluginMeta{}, fmt.Errorf( | ||
151 | "multiple plugins installed for version %s; this is a bug in Terraform and should be reported", | ||
152 | v, | ||
153 | ) | ||
154 | } | ||
155 | |||
156 | // By now we know we have exactly one meta, and so "Newest" will | ||
157 | // return that one. | ||
158 | return metas.Newest(), nil | ||
159 | } | ||
160 | |||
161 | log.Printf("[INFO] incompatible ProtocolVersion for %s version %s", provider, v) | ||
162 | } | ||
163 | |||
164 | return PluginMeta{}, ErrorNoVersionCompatible | ||
165 | } | ||
166 | |||
167 | func (i *ProviderInstaller) PurgeUnused(used map[string]PluginMeta) (PluginMetaSet, error) { | ||
168 | purge := make(PluginMetaSet) | ||
169 | |||
170 | present := FindPlugins("provider", []string{i.Dir}) | ||
171 | for meta := range present { | ||
172 | chosen, ok := used[meta.Name] | ||
173 | if !ok { | ||
174 | purge.Add(meta) | ||
175 | } | ||
176 | if chosen.Path != meta.Path { | ||
177 | purge.Add(meta) | ||
178 | } | ||
179 | } | ||
180 | |||
181 | removed := make(PluginMetaSet) | ||
182 | var errs error | ||
183 | for meta := range purge { | ||
184 | path := meta.Path | ||
185 | err := os.Remove(path) | ||
186 | if err != nil { | ||
187 | errs = multierror.Append(errs, fmt.Errorf( | ||
188 | "failed to remove unused provider plugin %s: %s", | ||
189 | path, err, | ||
190 | )) | ||
191 | } else { | ||
192 | removed.Add(meta) | ||
193 | } | ||
194 | } | ||
195 | |||
196 | return removed, errs | ||
197 | } | ||
198 | |||
199 | // Plugins are referred to by the short name, but all URLs and files will use | ||
200 | // the full name prefixed with terraform-<plugin_type>- | ||
201 | func (i *ProviderInstaller) providerName(name string) string { | ||
202 | return "terraform-provider-" + name | ||
203 | } | ||
204 | |||
205 | func (i *ProviderInstaller) providerFileName(name, version string) string { | ||
206 | os := i.OS | ||
207 | arch := i.Arch | ||
208 | if os == "" { | ||
209 | os = runtime.GOOS | ||
210 | } | ||
211 | if arch == "" { | ||
212 | arch = runtime.GOARCH | ||
213 | } | ||
214 | return fmt.Sprintf("%s_%s_%s_%s.zip", i.providerName(name), version, os, arch) | ||
215 | } | ||
216 | |||
217 | // providerVersionsURL returns the path to the released versions directory for the provider: | ||
218 | // https://releases.hashicorp.com/terraform-provider-name/ | ||
219 | func (i *ProviderInstaller) providerVersionsURL(name string) string { | ||
220 | return releaseHost + "/" + i.providerName(name) + "/" | ||
221 | } | ||
222 | |||
223 | // providerURL returns the full path to the provider file, using the current OS | ||
224 | // and ARCH: | ||
225 | // .../terraform-provider-name_<x.y.z>/terraform-provider-name_<x.y.z>_<os>_<arch>.<ext> | ||
226 | func (i *ProviderInstaller) providerURL(name, version string) string { | ||
227 | return fmt.Sprintf("%s%s/%s", i.providerVersionsURL(name), version, i.providerFileName(name, version)) | ||
228 | } | ||
229 | |||
230 | func (i *ProviderInstaller) providerChecksumURL(name, version string) string { | ||
231 | fileName := fmt.Sprintf("%s_%s_SHA256SUMS", i.providerName(name), version) | ||
232 | u := fmt.Sprintf("%s%s/%s", i.providerVersionsURL(name), version, fileName) | ||
233 | return u | ||
234 | } | ||
235 | |||
236 | func (i *ProviderInstaller) getProviderChecksum(name, version string) (string, error) { | ||
237 | checksums, err := getPluginSHA256SUMs(i.providerChecksumURL(name, version)) | ||
238 | if err != nil { | ||
239 | return "", err | ||
240 | } | ||
241 | |||
242 | return checksumForFile(checksums, i.providerFileName(name, version)), nil | ||
243 | } | ||
244 | |||
245 | // Return the plugin version by making a HEAD request to the provided url. | ||
246 | // If the header is not present, we assume the latest version will be | ||
247 | // compatible, and leave the check for discovery or execution. | ||
248 | func checkPlugin(url string, pluginProtocolVersion uint) bool { | ||
249 | resp, err := httpClient.Head(url) | ||
250 | if err != nil { | ||
251 | log.Printf("[ERROR] error fetching plugin headers: %s", err) | ||
252 | return false | ||
253 | } | ||
254 | |||
255 | if resp.StatusCode != http.StatusOK { | ||
256 | log.Println("[ERROR] non-200 status fetching plugin headers:", resp.Status) | ||
257 | return false | ||
258 | } | ||
259 | |||
260 | proto := resp.Header.Get(protocolVersionHeader) | ||
261 | if proto == "" { | ||
262 | // The header isn't present, but we don't make this error fatal since | ||
263 | // the latest version will probably work. | ||
264 | log.Printf("[WARNING] missing %s from: %s", protocolVersionHeader, url) | ||
265 | return true | ||
266 | } | ||
267 | |||
268 | protoVersion, err := strconv.Atoi(proto) | ||
269 | if err != nil { | ||
270 | log.Printf("[ERROR] invalid ProtocolVersion: %s", proto) | ||
271 | return false | ||
272 | } | ||
273 | |||
274 | return protoVersion == int(pluginProtocolVersion) | ||
275 | } | ||
276 | |||
277 | // list the version available for the named plugin | ||
278 | func (i *ProviderInstaller) listProviderVersions(name string) ([]Version, error) { | ||
279 | versions, err := listPluginVersions(i.providerVersionsURL(name)) | ||
280 | if err != nil { | ||
281 | // listPluginVersions returns a verbose error message indicating | ||
282 | // what was being accessed and what failed | ||
283 | return nil, err | ||
284 | } | ||
285 | return versions, nil | ||
286 | } | ||
287 | |||
288 | var errVersionNotFound = errors.New("version not found") | ||
289 | |||
290 | // take the list of available versions for a plugin, and filter out those that | ||
291 | // don't fit the constraints. | ||
292 | func allowedVersions(available []Version, required Constraints) []Version { | ||
293 | var allowed []Version | ||
294 | |||
295 | for _, v := range available { | ||
296 | if required.Allows(v) { | ||
297 | allowed = append(allowed, v) | ||
298 | } | ||
299 | } | ||
300 | |||
301 | return allowed | ||
302 | } | ||
303 | |||
304 | // return a list of the plugin versions at the given URL | ||
305 | func listPluginVersions(url string) ([]Version, error) { | ||
306 | resp, err := httpClient.Get(url) | ||
307 | if err != nil { | ||
308 | // http library produces a verbose error message that includes the | ||
309 | // URL being accessed, etc. | ||
310 | return nil, err | ||
311 | } | ||
312 | defer resp.Body.Close() | ||
313 | |||
314 | if resp.StatusCode != http.StatusOK { | ||
315 | body, _ := ioutil.ReadAll(resp.Body) | ||
316 | log.Printf("[ERROR] failed to fetch plugin versions from %s\n%s\n%s", url, resp.Status, body) | ||
317 | |||
318 | switch resp.StatusCode { | ||
319 | case http.StatusNotFound, http.StatusForbidden: | ||
320 | // These are treated as indicative of the given name not being | ||
321 | // a valid provider name at all. | ||
322 | return nil, ErrorNoSuchProvider | ||
323 | |||
324 | default: | ||
325 | // All other errors are assumed to be operational problems. | ||
326 | return nil, fmt.Errorf("error accessing %s: %s", url, resp.Status) | ||
327 | } | ||
328 | |||
329 | } | ||
330 | |||
331 | body, err := html.Parse(resp.Body) | ||
332 | if err != nil { | ||
333 | log.Fatal(err) | ||
334 | } | ||
335 | |||
336 | names := []string{} | ||
337 | |||
338 | // all we need to do is list links on the directory listing page that look like plugins | ||
339 | var f func(*html.Node) | ||
340 | f = func(n *html.Node) { | ||
341 | if n.Type == html.ElementNode && n.Data == "a" { | ||
342 | c := n.FirstChild | ||
343 | if c != nil && c.Type == html.TextNode && strings.HasPrefix(c.Data, "terraform-") { | ||
344 | names = append(names, c.Data) | ||
345 | return | ||
346 | } | ||
347 | } | ||
348 | for c := n.FirstChild; c != nil; c = c.NextSibling { | ||
349 | f(c) | ||
350 | } | ||
351 | } | ||
352 | f(body) | ||
353 | |||
354 | return versionsFromNames(names), nil | ||
355 | } | ||
356 | |||
357 | // parse the list of directory names into a sorted list of available versions | ||
358 | func versionsFromNames(names []string) []Version { | ||
359 | var versions []Version | ||
360 | for _, name := range names { | ||
361 | parts := strings.SplitN(name, "_", 2) | ||
362 | if len(parts) == 2 && parts[1] != "" { | ||
363 | v, err := VersionStr(parts[1]).Parse() | ||
364 | if err != nil { | ||
365 | // filter invalid versions scraped from the page | ||
366 | log.Printf("[WARN] invalid version found for %q: %s", name, err) | ||
367 | continue | ||
368 | } | ||
369 | |||
370 | versions = append(versions, v) | ||
371 | } | ||
372 | } | ||
373 | |||
374 | return versions | ||
375 | } | ||
376 | |||
377 | func checksumForFile(sums []byte, name string) string { | ||
378 | for _, line := range strings.Split(string(sums), "\n") { | ||
379 | parts := strings.Fields(line) | ||
380 | if len(parts) > 1 && parts[1] == name { | ||
381 | return parts[0] | ||
382 | } | ||
383 | } | ||
384 | return "" | ||
385 | } | ||
386 | |||
387 | // fetch the SHA256SUMS file provided, and verify its signature. | ||
388 | func getPluginSHA256SUMs(sumsURL string) ([]byte, error) { | ||
389 | sigURL := sumsURL + ".sig" | ||
390 | |||
391 | sums, err := getFile(sumsURL) | ||
392 | if err != nil { | ||
393 | return nil, fmt.Errorf("error fetching checksums: %s", err) | ||
394 | } | ||
395 | |||
396 | sig, err := getFile(sigURL) | ||
397 | if err != nil { | ||
398 | return nil, fmt.Errorf("error fetching checksums signature: %s", err) | ||
399 | } | ||
400 | |||
401 | if err := verifySig(sums, sig); err != nil { | ||
402 | return nil, err | ||
403 | } | ||
404 | |||
405 | return sums, nil | ||
406 | } | ||
407 | |||
408 | func getFile(url string) ([]byte, error) { | ||
409 | resp, err := httpClient.Get(url) | ||
410 | if err != nil { | ||
411 | return nil, err | ||
412 | } | ||
413 | defer resp.Body.Close() | ||
414 | |||
415 | if resp.StatusCode != http.StatusOK { | ||
416 | return nil, fmt.Errorf("%s", resp.Status) | ||
417 | } | ||
418 | |||
419 | data, err := ioutil.ReadAll(resp.Body) | ||
420 | if err != nil { | ||
421 | return data, err | ||
422 | } | ||
423 | return data, nil | ||
424 | } | ||
diff --git a/vendor/github.com/hashicorp/terraform/plugin/discovery/meta.go b/vendor/github.com/hashicorp/terraform/plugin/discovery/meta.go new file mode 100644 index 0000000..bdcebcb --- /dev/null +++ b/vendor/github.com/hashicorp/terraform/plugin/discovery/meta.go | |||
@@ -0,0 +1,41 @@ | |||
1 | package discovery | ||
2 | |||
3 | import ( | ||
4 | "crypto/sha256" | ||
5 | "io" | ||
6 | "os" | ||
7 | ) | ||
8 | |||
9 | // PluginMeta is metadata about a plugin, useful for launching the plugin | ||
10 | // and for understanding which plugins are available. | ||
11 | type PluginMeta struct { | ||
12 | // Name is the name of the plugin, e.g. as inferred from the plugin | ||
13 | // binary's filename, or by explicit configuration. | ||
14 | Name string | ||
15 | |||
16 | // Version is the semver version of the plugin, expressed as a string | ||
17 | // that might not be semver-valid. | ||
18 | Version VersionStr | ||
19 | |||
20 | // Path is the absolute path of the executable that can be launched | ||
21 | // to provide the RPC server for this plugin. | ||
22 | Path string | ||
23 | } | ||
24 | |||
25 | // SHA256 returns a SHA256 hash of the content of the referenced executable | ||
26 | // file, or an error if the file's contents cannot be read. | ||
27 | func (m PluginMeta) SHA256() ([]byte, error) { | ||
28 | f, err := os.Open(m.Path) | ||
29 | if err != nil { | ||
30 | return nil, err | ||
31 | } | ||
32 | defer f.Close() | ||
33 | |||
34 | h := sha256.New() | ||
35 | _, err = io.Copy(h, f) | ||
36 | if err != nil { | ||
37 | return nil, err | ||
38 | } | ||
39 | |||
40 | return h.Sum(nil), nil | ||
41 | } | ||
diff --git a/vendor/github.com/hashicorp/terraform/plugin/discovery/meta_set.go b/vendor/github.com/hashicorp/terraform/plugin/discovery/meta_set.go new file mode 100644 index 0000000..181ea1f --- /dev/null +++ b/vendor/github.com/hashicorp/terraform/plugin/discovery/meta_set.go | |||
@@ -0,0 +1,195 @@ | |||
1 | package discovery | ||
2 | |||
3 | // A PluginMetaSet is a set of PluginMeta objects meeting a certain criteria. | ||
4 | // | ||
5 | // Methods on this type allow filtering of the set to produce subsets that | ||
6 | // meet more restrictive criteria. | ||
7 | type PluginMetaSet map[PluginMeta]struct{} | ||
8 | |||
9 | // Add inserts the given PluginMeta into the receiving set. This is a no-op | ||
10 | // if the given meta is already present. | ||
11 | func (s PluginMetaSet) Add(p PluginMeta) { | ||
12 | s[p] = struct{}{} | ||
13 | } | ||
14 | |||
15 | // Remove removes the given PluginMeta from the receiving set. This is a no-op | ||
16 | // if the given meta is not already present. | ||
17 | func (s PluginMetaSet) Remove(p PluginMeta) { | ||
18 | delete(s, p) | ||
19 | } | ||
20 | |||
21 | // Has returns true if the given meta is in the receiving set, or false | ||
22 | // otherwise. | ||
23 | func (s PluginMetaSet) Has(p PluginMeta) bool { | ||
24 | _, ok := s[p] | ||
25 | return ok | ||
26 | } | ||
27 | |||
28 | // Count returns the number of metas in the set | ||
29 | func (s PluginMetaSet) Count() int { | ||
30 | return len(s) | ||
31 | } | ||
32 | |||
33 | // ValidateVersions returns two new PluginMetaSets, separating those with | ||
34 | // versions that have syntax-valid semver versions from those that don't. | ||
35 | // | ||
36 | // Eliminating invalid versions from consideration (and possibly warning about | ||
37 | // them) is usually the first step of working with a meta set after discovery | ||
38 | // has completed. | ||
39 | func (s PluginMetaSet) ValidateVersions() (valid, invalid PluginMetaSet) { | ||
40 | valid = make(PluginMetaSet) | ||
41 | invalid = make(PluginMetaSet) | ||
42 | for p := range s { | ||
43 | if _, err := p.Version.Parse(); err == nil { | ||
44 | valid.Add(p) | ||
45 | } else { | ||
46 | invalid.Add(p) | ||
47 | } | ||
48 | } | ||
49 | return | ||
50 | } | ||
51 | |||
52 | // WithName returns the subset of metas that have the given name. | ||
53 | func (s PluginMetaSet) WithName(name string) PluginMetaSet { | ||
54 | ns := make(PluginMetaSet) | ||
55 | for p := range s { | ||
56 | if p.Name == name { | ||
57 | ns.Add(p) | ||
58 | } | ||
59 | } | ||
60 | return ns | ||
61 | } | ||
62 | |||
63 | // WithVersion returns the subset of metas that have the given version. | ||
64 | // | ||
65 | // This should be used only with the "valid" result from ValidateVersions; | ||
66 | // it will ignore any plugin metas that have a invalid version strings. | ||
67 | func (s PluginMetaSet) WithVersion(version Version) PluginMetaSet { | ||
68 | ns := make(PluginMetaSet) | ||
69 | for p := range s { | ||
70 | gotVersion, err := p.Version.Parse() | ||
71 | if err != nil { | ||
72 | continue | ||
73 | } | ||
74 | if gotVersion.Equal(version) { | ||
75 | ns.Add(p) | ||
76 | } | ||
77 | } | ||
78 | return ns | ||
79 | } | ||
80 | |||
81 | // ByName groups the metas in the set by their Names, returning a map. | ||
82 | func (s PluginMetaSet) ByName() map[string]PluginMetaSet { | ||
83 | ret := make(map[string]PluginMetaSet) | ||
84 | for p := range s { | ||
85 | if _, ok := ret[p.Name]; !ok { | ||
86 | ret[p.Name] = make(PluginMetaSet) | ||
87 | } | ||
88 | ret[p.Name].Add(p) | ||
89 | } | ||
90 | return ret | ||
91 | } | ||
92 | |||
93 | // Newest returns the one item from the set that has the newest Version value. | ||
94 | // | ||
95 | // The result is meaningful only if the set is already filtered such that | ||
96 | // all of the metas have the same Name. | ||
97 | // | ||
98 | // If there isn't at least one meta in the set then this function will panic. | ||
99 | // Use Count() to ensure that there is at least one value before calling. | ||
100 | // | ||
101 | // If any of the metas have invalid version strings then this function will | ||
102 | // panic. Use ValidateVersions() first to filter out metas with invalid | ||
103 | // versions. | ||
104 | // | ||
105 | // If two metas have the same Version then one is arbitrarily chosen. This | ||
106 | // situation should be avoided by pre-filtering the set. | ||
107 | func (s PluginMetaSet) Newest() PluginMeta { | ||
108 | if len(s) == 0 { | ||
109 | panic("can't call NewestStable on empty PluginMetaSet") | ||
110 | } | ||
111 | |||
112 | var first = true | ||
113 | var winner PluginMeta | ||
114 | var winnerVersion Version | ||
115 | for p := range s { | ||
116 | version, err := p.Version.Parse() | ||
117 | if err != nil { | ||
118 | panic(err) | ||
119 | } | ||
120 | |||
121 | if first == true || version.NewerThan(winnerVersion) { | ||
122 | winner = p | ||
123 | winnerVersion = version | ||
124 | first = false | ||
125 | } | ||
126 | } | ||
127 | |||
128 | return winner | ||
129 | } | ||
130 | |||
131 | // ConstrainVersions takes a set of requirements and attempts to | ||
132 | // return a map from name to a set of metas that have the matching | ||
133 | // name and an appropriate version. | ||
134 | // | ||
135 | // If any of the given requirements match *no* plugins then its PluginMetaSet | ||
136 | // in the returned map will be empty. | ||
137 | // | ||
138 | // All viable metas are returned, so the caller can apply any desired filtering | ||
139 | // to reduce down to a single option. For example, calling Newest() to obtain | ||
140 | // the highest available version. | ||
141 | // | ||
142 | // If any of the metas in the set have invalid version strings then this | ||
143 | // function will panic. Use ValidateVersions() first to filter out metas with | ||
144 | // invalid versions. | ||
145 | func (s PluginMetaSet) ConstrainVersions(reqd PluginRequirements) map[string]PluginMetaSet { | ||
146 | ret := make(map[string]PluginMetaSet) | ||
147 | for p := range s { | ||
148 | name := p.Name | ||
149 | allowedVersions, ok := reqd[name] | ||
150 | if !ok { | ||
151 | continue | ||
152 | } | ||
153 | if _, ok := ret[p.Name]; !ok { | ||
154 | ret[p.Name] = make(PluginMetaSet) | ||
155 | } | ||
156 | version, err := p.Version.Parse() | ||
157 | if err != nil { | ||
158 | panic(err) | ||
159 | } | ||
160 | if allowedVersions.Allows(version) { | ||
161 | ret[p.Name].Add(p) | ||
162 | } | ||
163 | } | ||
164 | return ret | ||
165 | } | ||
166 | |||
167 | // OverridePaths returns a new set where any existing plugins with the given | ||
168 | // names are removed and replaced with the single path given in the map. | ||
169 | // | ||
170 | // This is here only to continue to support the legacy way of overriding | ||
171 | // plugin binaries in the .terraformrc file. It treats all given plugins | ||
172 | // as pre-versioning (version 0.0.0). This mechanism will eventually be | ||
173 | // phased out, with vendor directories being the intended replacement. | ||
174 | func (s PluginMetaSet) OverridePaths(paths map[string]string) PluginMetaSet { | ||
175 | ret := make(PluginMetaSet) | ||
176 | for p := range s { | ||
177 | if _, ok := paths[p.Name]; ok { | ||
178 | // Skip plugins that we're overridding | ||
179 | continue | ||
180 | } | ||
181 | |||
182 | ret.Add(p) | ||
183 | } | ||
184 | |||
185 | // Now add the metadata for overriding plugins | ||
186 | for name, path := range paths { | ||
187 | ret.Add(PluginMeta{ | ||
188 | Name: name, | ||
189 | Version: VersionZero, | ||
190 | Path: path, | ||
191 | }) | ||
192 | } | ||
193 | |||
194 | return ret | ||
195 | } | ||
diff --git a/vendor/github.com/hashicorp/terraform/plugin/discovery/requirements.go b/vendor/github.com/hashicorp/terraform/plugin/discovery/requirements.go new file mode 100644 index 0000000..75430fd --- /dev/null +++ b/vendor/github.com/hashicorp/terraform/plugin/discovery/requirements.go | |||
@@ -0,0 +1,105 @@ | |||
1 | package discovery | ||
2 | |||
3 | import ( | ||
4 | "bytes" | ||
5 | ) | ||
6 | |||
7 | // PluginRequirements describes a set of plugins (assumed to be of a consistent | ||
8 | // kind) that are required to exist and have versions within the given | ||
9 | // corresponding sets. | ||
10 | type PluginRequirements map[string]*PluginConstraints | ||
11 | |||
12 | // PluginConstraints represents an element of PluginRequirements describing | ||
13 | // the constraints for a single plugin. | ||
14 | type PluginConstraints struct { | ||
15 | // Specifies that the plugin's version must be within the given | ||
16 | // constraints. | ||
17 | Versions Constraints | ||
18 | |||
19 | // If non-nil, the hash of the on-disk plugin executable must exactly | ||
20 | // match the SHA256 hash given here. | ||
21 | SHA256 []byte | ||
22 | } | ||
23 | |||
24 | // Allows returns true if the given version is within the receiver's version | ||
25 | // constraints. | ||
26 | func (s *PluginConstraints) Allows(v Version) bool { | ||
27 | return s.Versions.Allows(v) | ||
28 | } | ||
29 | |||
30 | // AcceptsSHA256 returns true if the given executable SHA256 hash is acceptable, | ||
31 | // either because it matches the constraint or because there is no such | ||
32 | // constraint. | ||
33 | func (s *PluginConstraints) AcceptsSHA256(digest []byte) bool { | ||
34 | if s.SHA256 == nil { | ||
35 | return true | ||
36 | } | ||
37 | return bytes.Equal(s.SHA256, digest) | ||
38 | } | ||
39 | |||
40 | // Merge takes the contents of the receiver and the other given requirements | ||
41 | // object and merges them together into a single requirements structure | ||
42 | // that satisfies both sets of requirements. | ||
43 | // | ||
44 | // Note that it doesn't make sense to merge two PluginRequirements with | ||
45 | // differing required plugin SHA256 hashes, since the result will never | ||
46 | // match any plugin. | ||
47 | func (r PluginRequirements) Merge(other PluginRequirements) PluginRequirements { | ||
48 | ret := make(PluginRequirements) | ||
49 | for n, c := range r { | ||
50 | ret[n] = &PluginConstraints{ | ||
51 | Versions: Constraints{}.Append(c.Versions), | ||
52 | SHA256: c.SHA256, | ||
53 | } | ||
54 | } | ||
55 | for n, c := range other { | ||
56 | if existing, exists := ret[n]; exists { | ||
57 | ret[n].Versions = ret[n].Versions.Append(c.Versions) | ||
58 | |||
59 | if existing.SHA256 != nil { | ||
60 | if c.SHA256 != nil && !bytes.Equal(c.SHA256, existing.SHA256) { | ||
61 | // If we've been asked to merge two constraints with | ||
62 | // different SHA256 hashes then we'll produce a dummy value | ||
63 | // that can never match anything. This is a silly edge case | ||
64 | // that no reasonable caller should hit. | ||
65 | ret[n].SHA256 = []byte(invalidProviderHash) | ||
66 | } | ||
67 | } else { | ||
68 | ret[n].SHA256 = c.SHA256 // might still be nil | ||
69 | } | ||
70 | } else { | ||
71 | ret[n] = &PluginConstraints{ | ||
72 | Versions: Constraints{}.Append(c.Versions), | ||
73 | SHA256: c.SHA256, | ||
74 | } | ||
75 | } | ||
76 | } | ||
77 | return ret | ||
78 | } | ||
79 | |||
80 | // LockExecutables applies additional constraints to the receiver that | ||
81 | // require plugin executables with specific SHA256 digests. This modifies | ||
82 | // the receiver in-place, since it's intended to be applied after | ||
83 | // version constraints have been resolved. | ||
84 | // | ||
85 | // The given map must include a key for every plugin that is already | ||
86 | // required. If not, any missing keys will cause the corresponding plugin | ||
87 | // to never match, though the direct caller doesn't necessarily need to | ||
88 | // guarantee this as long as the downstream code _applying_ these constraints | ||
89 | // is able to deal with the non-match in some way. | ||
90 | func (r PluginRequirements) LockExecutables(sha256s map[string][]byte) { | ||
91 | for name, cons := range r { | ||
92 | digest := sha256s[name] | ||
93 | |||
94 | if digest == nil { | ||
95 | // Prevent any match, which will then presumably cause the | ||
96 | // downstream consumer of this requirements to report an error. | ||
97 | cons.SHA256 = []byte(invalidProviderHash) | ||
98 | continue | ||
99 | } | ||
100 | |||
101 | cons.SHA256 = digest | ||
102 | } | ||
103 | } | ||
104 | |||
105 | const invalidProviderHash = "<invalid>" | ||
diff --git a/vendor/github.com/hashicorp/terraform/plugin/discovery/signature.go b/vendor/github.com/hashicorp/terraform/plugin/discovery/signature.go new file mode 100644 index 0000000..b6686a5 --- /dev/null +++ b/vendor/github.com/hashicorp/terraform/plugin/discovery/signature.go | |||
@@ -0,0 +1,53 @@ | |||
1 | package discovery | ||
2 | |||
3 | import ( | ||
4 | "bytes" | ||
5 | "log" | ||
6 | "strings" | ||
7 | |||
8 | "golang.org/x/crypto/openpgp" | ||
9 | ) | ||
10 | |||
11 | // Verify the data using the provided openpgp detached signature and the | ||
12 | // embedded hashicorp public key. | ||
13 | func verifySig(data, sig []byte) error { | ||
14 | el, err := openpgp.ReadArmoredKeyRing(strings.NewReader(hashiPublicKey)) | ||
15 | if err != nil { | ||
16 | log.Fatal(err) | ||
17 | } | ||
18 | |||
19 | _, err = openpgp.CheckDetachedSignature(el, bytes.NewReader(data), bytes.NewReader(sig)) | ||
20 | return err | ||
21 | } | ||
22 | |||
23 | // this is the public key that signs the checksums file for releases. | ||
24 | const hashiPublicKey = `-----BEGIN PGP PUBLIC KEY BLOCK----- | ||
25 | Version: GnuPG v1 | ||
26 | |||
27 | mQENBFMORM0BCADBRyKO1MhCirazOSVwcfTr1xUxjPvfxD3hjUwHtjsOy/bT6p9f | ||
28 | W2mRPfwnq2JB5As+paL3UGDsSRDnK9KAxQb0NNF4+eVhr/EJ18s3wwXXDMjpIifq | ||
29 | fIm2WyH3G+aRLTLPIpscUNKDyxFOUbsmgXAmJ46Re1fn8uKxKRHbfa39aeuEYWFA | ||
30 | 3drdL1WoUngvED7f+RnKBK2G6ZEpO+LDovQk19xGjiMTtPJrjMjZJ3QXqPvx5wca | ||
31 | KSZLr4lMTuoTI/ZXyZy5bD4tShiZz6KcyX27cD70q2iRcEZ0poLKHyEIDAi3TM5k | ||
32 | SwbbWBFd5RNPOR0qzrb/0p9ksKK48IIfH2FvABEBAAG0K0hhc2hpQ29ycCBTZWN1 | ||
33 | cml0eSA8c2VjdXJpdHlAaGFzaGljb3JwLmNvbT6JATgEEwECACIFAlMORM0CGwMG | ||
34 | CwkIBwMCBhUIAgkKCwQWAgMBAh4BAheAAAoJEFGFLYc0j/xMyWIIAIPhcVqiQ59n | ||
35 | Jc07gjUX0SWBJAxEG1lKxfzS4Xp+57h2xxTpdotGQ1fZwsihaIqow337YHQI3q0i | ||
36 | SqV534Ms+j/tU7X8sq11xFJIeEVG8PASRCwmryUwghFKPlHETQ8jJ+Y8+1asRydi | ||
37 | psP3B/5Mjhqv/uOK+Vy3zAyIpyDOMtIpOVfjSpCplVRdtSTFWBu9Em7j5I2HMn1w | ||
38 | sJZnJgXKpybpibGiiTtmnFLOwibmprSu04rsnP4ncdC2XRD4wIjoyA+4PKgX3sCO | ||
39 | klEzKryWYBmLkJOMDdo52LttP3279s7XrkLEE7ia0fXa2c12EQ0f0DQ1tGUvyVEW | ||
40 | WmJVccm5bq25AQ0EUw5EzQEIANaPUY04/g7AmYkOMjaCZ6iTp9hB5Rsj/4ee/ln9 | ||
41 | wArzRO9+3eejLWh53FoN1rO+su7tiXJA5YAzVy6tuolrqjM8DBztPxdLBbEi4V+j | ||
42 | 2tK0dATdBQBHEh3OJApO2UBtcjaZBT31zrG9K55D+CrcgIVEHAKY8Cb4kLBkb5wM | ||
43 | skn+DrASKU0BNIV1qRsxfiUdQHZfSqtp004nrql1lbFMLFEuiY8FZrkkQ9qduixo | ||
44 | mTT6f34/oiY+Jam3zCK7RDN/OjuWheIPGj/Qbx9JuNiwgX6yRj7OE1tjUx6d8g9y | ||
45 | 0H1fmLJbb3WZZbuuGFnK6qrE3bGeY8+AWaJAZ37wpWh1p0cAEQEAAYkBHwQYAQIA | ||
46 | CQUCUw5EzQIbDAAKCRBRhS2HNI/8TJntCAClU7TOO/X053eKF1jqNW4A1qpxctVc | ||
47 | z8eTcY8Om5O4f6a/rfxfNFKn9Qyja/OG1xWNobETy7MiMXYjaa8uUx5iFy6kMVaP | ||
48 | 0BXJ59NLZjMARGw6lVTYDTIvzqqqwLxgliSDfSnqUhubGwvykANPO+93BBx89MRG | ||
49 | unNoYGXtPlhNFrAsB1VR8+EyKLv2HQtGCPSFBhrjuzH3gxGibNDDdFQLxxuJWepJ | ||
50 | EK1UbTS4ms0NgZ2Uknqn1WRU1Ki7rE4sTy68iZtWpKQXZEJa0IGnuI2sSINGcXCJ | ||
51 | oEIgXTMyCILo34Fa/C6VCm2WBgz9zZO8/rHIiQm1J5zqz0DrDwKBUM9C | ||
52 | =LYpS | ||
53 | -----END PGP PUBLIC KEY BLOCK-----` | ||
diff --git a/vendor/github.com/hashicorp/terraform/plugin/discovery/version.go b/vendor/github.com/hashicorp/terraform/plugin/discovery/version.go new file mode 100644 index 0000000..8fad58d --- /dev/null +++ b/vendor/github.com/hashicorp/terraform/plugin/discovery/version.go | |||
@@ -0,0 +1,72 @@ | |||
1 | package discovery | ||
2 | |||
3 | import ( | ||
4 | "fmt" | ||
5 | "sort" | ||
6 | |||
7 | version "github.com/hashicorp/go-version" | ||
8 | ) | ||
9 | |||
10 | const VersionZero = "0.0.0" | ||
11 | |||
12 | // A VersionStr is a string containing a possibly-invalid representation | ||
13 | // of a semver version number. Call Parse on it to obtain a real Version | ||
14 | // object, or discover that it is invalid. | ||
15 | type VersionStr string | ||
16 | |||
17 | // Parse transforms a VersionStr into a Version if it is | ||
18 | // syntactically valid. If it isn't then an error is returned instead. | ||
19 | func (s VersionStr) Parse() (Version, error) { | ||
20 | raw, err := version.NewVersion(string(s)) | ||
21 | if err != nil { | ||
22 | return Version{}, err | ||
23 | } | ||
24 | return Version{raw}, nil | ||
25 | } | ||
26 | |||
27 | // MustParse transforms a VersionStr into a Version if it is | ||
28 | // syntactically valid. If it isn't then it panics. | ||
29 | func (s VersionStr) MustParse() Version { | ||
30 | ret, err := s.Parse() | ||
31 | if err != nil { | ||
32 | panic(err) | ||
33 | } | ||
34 | return ret | ||
35 | } | ||
36 | |||
37 | // Version represents a version number that has been parsed from | ||
38 | // a semver string and known to be valid. | ||
39 | type Version struct { | ||
40 | // We wrap this here just because it avoids a proliferation of | ||
41 | // direct go-version imports all over the place, and keeps the | ||
42 | // version-processing details within this package. | ||
43 | raw *version.Version | ||
44 | } | ||
45 | |||
46 | func (v Version) String() string { | ||
47 | return v.raw.String() | ||
48 | } | ||
49 | |||
50 | func (v Version) NewerThan(other Version) bool { | ||
51 | return v.raw.GreaterThan(other.raw) | ||
52 | } | ||
53 | |||
54 | func (v Version) Equal(other Version) bool { | ||
55 | return v.raw.Equal(other.raw) | ||
56 | } | ||
57 | |||
58 | // MinorUpgradeConstraintStr returns a ConstraintStr that would permit | ||
59 | // minor upgrades relative to the receiving version. | ||
60 | func (v Version) MinorUpgradeConstraintStr() ConstraintStr { | ||
61 | segments := v.raw.Segments() | ||
62 | return ConstraintStr(fmt.Sprintf("~> %d.%d", segments[0], segments[1])) | ||
63 | } | ||
64 | |||
65 | type Versions []Version | ||
66 | |||
67 | // Sort sorts version from newest to oldest. | ||
68 | func (v Versions) Sort() { | ||
69 | sort.Slice(v, func(i, j int) bool { | ||
70 | return v[i].NewerThan(v[j]) | ||
71 | }) | ||
72 | } | ||
diff --git a/vendor/github.com/hashicorp/terraform/plugin/discovery/version_set.go b/vendor/github.com/hashicorp/terraform/plugin/discovery/version_set.go new file mode 100644 index 0000000..0aefd75 --- /dev/null +++ b/vendor/github.com/hashicorp/terraform/plugin/discovery/version_set.go | |||
@@ -0,0 +1,84 @@ | |||
1 | package discovery | ||
2 | |||
3 | import ( | ||
4 | "sort" | ||
5 | |||
6 | version "github.com/hashicorp/go-version" | ||
7 | ) | ||
8 | |||
9 | // A ConstraintStr is a string containing a possibly-invalid representation | ||
10 | // of a version constraint provided in configuration. Call Parse on it to | ||
11 | // obtain a real Constraint object, or discover that it is invalid. | ||
12 | type ConstraintStr string | ||
13 | |||
14 | // Parse transforms a ConstraintStr into a Constraints if it is | ||
15 | // syntactically valid. If it isn't then an error is returned instead. | ||
16 | func (s ConstraintStr) Parse() (Constraints, error) { | ||
17 | raw, err := version.NewConstraint(string(s)) | ||
18 | if err != nil { | ||
19 | return Constraints{}, err | ||
20 | } | ||
21 | return Constraints{raw}, nil | ||
22 | } | ||
23 | |||
24 | // MustParse is like Parse but it panics if the constraint string is invalid. | ||
25 | func (s ConstraintStr) MustParse() Constraints { | ||
26 | ret, err := s.Parse() | ||
27 | if err != nil { | ||
28 | panic(err) | ||
29 | } | ||
30 | return ret | ||
31 | } | ||
32 | |||
33 | // Constraints represents a set of versions which any given Version is either | ||
34 | // a member of or not. | ||
35 | type Constraints struct { | ||
36 | raw version.Constraints | ||
37 | } | ||
38 | |||
39 | // AllVersions is a Constraints containing all versions | ||
40 | var AllVersions Constraints | ||
41 | |||
42 | func init() { | ||
43 | AllVersions = Constraints{ | ||
44 | raw: make(version.Constraints, 0), | ||
45 | } | ||
46 | } | ||
47 | |||
48 | // Allows returns true if the given version permitted by the receiving | ||
49 | // constraints set. | ||
50 | func (s Constraints) Allows(v Version) bool { | ||
51 | return s.raw.Check(v.raw) | ||
52 | } | ||
53 | |||
54 | // Append combines the receiving set with the given other set to produce | ||
55 | // a set that is the intersection of both sets, which is to say that resulting | ||
56 | // constraints contain only the versions that are members of both. | ||
57 | func (s Constraints) Append(other Constraints) Constraints { | ||
58 | raw := make(version.Constraints, 0, len(s.raw)+len(other.raw)) | ||
59 | |||
60 | // Since "raw" is a list of constraints that remove versions from the set, | ||
61 | // "Intersection" is implemented by concatenating together those lists, | ||
62 | // thus leaving behind only the versions not removed by either list. | ||
63 | raw = append(raw, s.raw...) | ||
64 | raw = append(raw, other.raw...) | ||
65 | |||
66 | // while the set is unordered, we sort these lexically for consistent output | ||
67 | sort.Slice(raw, func(i, j int) bool { | ||
68 | return raw[i].String() < raw[j].String() | ||
69 | }) | ||
70 | |||
71 | return Constraints{raw} | ||
72 | } | ||
73 | |||
74 | // String returns a string representation of the set members as a set | ||
75 | // of range constraints. | ||
76 | func (s Constraints) String() string { | ||
77 | return s.raw.String() | ||
78 | } | ||
79 | |||
80 | // Unconstrained returns true if and only if the receiver is an empty | ||
81 | // constraint set. | ||
82 | func (s Constraints) Unconstrained() bool { | ||
83 | return len(s.raw) == 0 | ||
84 | } | ||
diff --git a/vendor/github.com/hashicorp/terraform/terraform/context.go b/vendor/github.com/hashicorp/terraform/terraform/context.go index 306128e..a814a85 100644 --- a/vendor/github.com/hashicorp/terraform/terraform/context.go +++ b/vendor/github.com/hashicorp/terraform/terraform/context.go | |||
@@ -57,12 +57,17 @@ type ContextOpts struct { | |||
57 | Parallelism int | 57 | Parallelism int |
58 | State *State | 58 | State *State |
59 | StateFutureAllowed bool | 59 | StateFutureAllowed bool |
60 | Providers map[string]ResourceProviderFactory | 60 | ProviderResolver ResourceProviderResolver |
61 | Provisioners map[string]ResourceProvisionerFactory | 61 | Provisioners map[string]ResourceProvisionerFactory |
62 | Shadow bool | 62 | Shadow bool |
63 | Targets []string | 63 | Targets []string |
64 | Variables map[string]interface{} | 64 | Variables map[string]interface{} |
65 | 65 | ||
66 | // If non-nil, will apply as additional constraints on the provider | ||
67 | // plugins that will be requested from the provider resolver. | ||
68 | ProviderSHA256s map[string][]byte | ||
69 | SkipProviderVerify bool | ||
70 | |||
66 | UIInput UIInput | 71 | UIInput UIInput |
67 | } | 72 | } |
68 | 73 | ||
@@ -102,6 +107,7 @@ type Context struct { | |||
102 | l sync.Mutex // Lock acquired during any task | 107 | l sync.Mutex // Lock acquired during any task |
103 | parallelSem Semaphore | 108 | parallelSem Semaphore |
104 | providerInputConfig map[string]map[string]interface{} | 109 | providerInputConfig map[string]map[string]interface{} |
110 | providerSHA256s map[string][]byte | ||
105 | runLock sync.Mutex | 111 | runLock sync.Mutex |
106 | runCond *sync.Cond | 112 | runCond *sync.Cond |
107 | runContext context.Context | 113 | runContext context.Context |
@@ -166,7 +172,6 @@ func NewContext(opts *ContextOpts) (*Context, error) { | |||
166 | // set by environment variables if necessary. This includes | 172 | // set by environment variables if necessary. This includes |
167 | // values taken from -var-file in addition. | 173 | // values taken from -var-file in addition. |
168 | variables := make(map[string]interface{}) | 174 | variables := make(map[string]interface{}) |
169 | |||
170 | if opts.Module != nil { | 175 | if opts.Module != nil { |
171 | var err error | 176 | var err error |
172 | variables, err = Variables(opts.Module, opts.Variables) | 177 | variables, err = Variables(opts.Module, opts.Variables) |
@@ -175,6 +180,23 @@ func NewContext(opts *ContextOpts) (*Context, error) { | |||
175 | } | 180 | } |
176 | } | 181 | } |
177 | 182 | ||
183 | // Bind available provider plugins to the constraints in config | ||
184 | var providers map[string]ResourceProviderFactory | ||
185 | if opts.ProviderResolver != nil { | ||
186 | var err error | ||
187 | deps := ModuleTreeDependencies(opts.Module, state) | ||
188 | reqd := deps.AllPluginRequirements() | ||
189 | if opts.ProviderSHA256s != nil && !opts.SkipProviderVerify { | ||
190 | reqd.LockExecutables(opts.ProviderSHA256s) | ||
191 | } | ||
192 | providers, err = resourceProviderFactories(opts.ProviderResolver, reqd) | ||
193 | if err != nil { | ||
194 | return nil, err | ||
195 | } | ||
196 | } else { | ||
197 | providers = make(map[string]ResourceProviderFactory) | ||
198 | } | ||
199 | |||
178 | diff := opts.Diff | 200 | diff := opts.Diff |
179 | if diff == nil { | 201 | if diff == nil { |
180 | diff = &Diff{} | 202 | diff = &Diff{} |
@@ -182,7 +204,7 @@ func NewContext(opts *ContextOpts) (*Context, error) { | |||
182 | 204 | ||
183 | return &Context{ | 205 | return &Context{ |
184 | components: &basicComponentFactory{ | 206 | components: &basicComponentFactory{ |
185 | providers: opts.Providers, | 207 | providers: providers, |
186 | provisioners: opts.Provisioners, | 208 | provisioners: opts.Provisioners, |
187 | }, | 209 | }, |
188 | destroy: opts.Destroy, | 210 | destroy: opts.Destroy, |
@@ -198,6 +220,7 @@ func NewContext(opts *ContextOpts) (*Context, error) { | |||
198 | 220 | ||
199 | parallelSem: NewSemaphore(par), | 221 | parallelSem: NewSemaphore(par), |
200 | providerInputConfig: make(map[string]map[string]interface{}), | 222 | providerInputConfig: make(map[string]map[string]interface{}), |
223 | providerSHA256s: opts.ProviderSHA256s, | ||
201 | sh: sh, | 224 | sh: sh, |
202 | }, nil | 225 | }, nil |
203 | } | 226 | } |
@@ -509,6 +532,9 @@ func (c *Context) Plan() (*Plan, error) { | |||
509 | Vars: c.variables, | 532 | Vars: c.variables, |
510 | State: c.state, | 533 | State: c.state, |
511 | Targets: c.targets, | 534 | Targets: c.targets, |
535 | |||
536 | TerraformVersion: VersionString(), | ||
537 | ProviderSHA256s: c.providerSHA256s, | ||
512 | } | 538 | } |
513 | 539 | ||
514 | var operation walkOperation | 540 | var operation walkOperation |
diff --git a/vendor/github.com/hashicorp/terraform/terraform/diff.go b/vendor/github.com/hashicorp/terraform/terraform/diff.go index a9fae6c..fd1687e 100644 --- a/vendor/github.com/hashicorp/terraform/terraform/diff.go +++ b/vendor/github.com/hashicorp/terraform/terraform/diff.go | |||
@@ -28,7 +28,7 @@ const ( | |||
28 | // multiVal matches the index key to a flatmapped set, list or map | 28 | // multiVal matches the index key to a flatmapped set, list or map |
29 | var multiVal = regexp.MustCompile(`\.(#|%)$`) | 29 | var multiVal = regexp.MustCompile(`\.(#|%)$`) |
30 | 30 | ||
31 | // Diff trackes the changes that are necessary to apply a configuration | 31 | // Diff tracks the changes that are necessary to apply a configuration |
32 | // to an existing infrastructure. | 32 | // to an existing infrastructure. |
33 | type Diff struct { | 33 | type Diff struct { |
34 | // Modules contains all the modules that have a diff | 34 | // Modules contains all the modules that have a diff |
@@ -370,7 +370,7 @@ type InstanceDiff struct { | |||
370 | 370 | ||
371 | // Meta is a simple K/V map that is stored in a diff and persisted to | 371 | // Meta is a simple K/V map that is stored in a diff and persisted to |
372 | // plans but otherwise is completely ignored by Terraform core. It is | 372 | // plans but otherwise is completely ignored by Terraform core. It is |
373 | // mean to be used for additional data a resource may want to pass through. | 373 | // meant to be used for additional data a resource may want to pass through. |
374 | // The value here must only contain Go primitives and collections. | 374 | // The value here must only contain Go primitives and collections. |
375 | Meta map[string]interface{} | 375 | Meta map[string]interface{} |
376 | } | 376 | } |
@@ -551,7 +551,7 @@ func (d *InstanceDiff) SetDestroyDeposed(b bool) { | |||
551 | } | 551 | } |
552 | 552 | ||
553 | // These methods are properly locked, for use outside other InstanceDiff | 553 | // These methods are properly locked, for use outside other InstanceDiff |
554 | // methods but everywhere else within in the terraform package. | 554 | // methods but everywhere else within the terraform package. |
555 | // TODO refactor the locking scheme | 555 | // TODO refactor the locking scheme |
556 | func (d *InstanceDiff) SetTainted(b bool) { | 556 | func (d *InstanceDiff) SetTainted(b bool) { |
557 | d.mu.Lock() | 557 | d.mu.Lock() |
diff --git a/vendor/github.com/hashicorp/terraform/terraform/eval_diff.go b/vendor/github.com/hashicorp/terraform/terraform/eval_diff.go index 6f09526..c35f908 100644 --- a/vendor/github.com/hashicorp/terraform/terraform/eval_diff.go +++ b/vendor/github.com/hashicorp/terraform/terraform/eval_diff.go | |||
@@ -81,6 +81,12 @@ type EvalDiff struct { | |||
81 | // Resource is needed to fetch the ignore_changes list so we can | 81 | // Resource is needed to fetch the ignore_changes list so we can |
82 | // filter user-requested ignored attributes from the diff. | 82 | // filter user-requested ignored attributes from the diff. |
83 | Resource *config.Resource | 83 | Resource *config.Resource |
84 | |||
85 | // Stub is used to flag the generated InstanceDiff as a stub. This is used to | ||
86 | // ensure that the node exists to perform interpolations and generate | ||
87 | // computed paths off of, but not as an actual diff where resouces should be | ||
88 | // counted, and not as a diff that should be acted on. | ||
89 | Stub bool | ||
84 | } | 90 | } |
85 | 91 | ||
86 | // TODO: test | 92 | // TODO: test |
@@ -90,11 +96,13 @@ func (n *EvalDiff) Eval(ctx EvalContext) (interface{}, error) { | |||
90 | provider := *n.Provider | 96 | provider := *n.Provider |
91 | 97 | ||
92 | // Call pre-diff hook | 98 | // Call pre-diff hook |
93 | err := ctx.Hook(func(h Hook) (HookAction, error) { | 99 | if !n.Stub { |
94 | return h.PreDiff(n.Info, state) | 100 | err := ctx.Hook(func(h Hook) (HookAction, error) { |
95 | }) | 101 | return h.PreDiff(n.Info, state) |
96 | if err != nil { | 102 | }) |
97 | return nil, err | 103 | if err != nil { |
104 | return nil, err | ||
105 | } | ||
98 | } | 106 | } |
99 | 107 | ||
100 | // The state for the diff must never be nil | 108 | // The state for the diff must never be nil |
@@ -158,15 +166,19 @@ func (n *EvalDiff) Eval(ctx EvalContext) (interface{}, error) { | |||
158 | } | 166 | } |
159 | 167 | ||
160 | // Call post-refresh hook | 168 | // Call post-refresh hook |
161 | err = ctx.Hook(func(h Hook) (HookAction, error) { | 169 | if !n.Stub { |
162 | return h.PostDiff(n.Info, diff) | 170 | err = ctx.Hook(func(h Hook) (HookAction, error) { |
163 | }) | 171 | return h.PostDiff(n.Info, diff) |
164 | if err != nil { | 172 | }) |
165 | return nil, err | 173 | if err != nil { |
174 | return nil, err | ||
175 | } | ||
166 | } | 176 | } |
167 | 177 | ||
168 | // Update our output | 178 | // Update our output if we care |
169 | *n.OutputDiff = diff | 179 | if n.OutputDiff != nil { |
180 | *n.OutputDiff = diff | ||
181 | } | ||
170 | 182 | ||
171 | // Update the state if we care | 183 | // Update the state if we care |
172 | if n.OutputState != nil { | 184 | if n.OutputState != nil { |
diff --git a/vendor/github.com/hashicorp/terraform/terraform/graph_builder_plan.go b/vendor/github.com/hashicorp/terraform/terraform/graph_builder_plan.go index a6a3a90..4b29bbb 100644 --- a/vendor/github.com/hashicorp/terraform/terraform/graph_builder_plan.go +++ b/vendor/github.com/hashicorp/terraform/terraform/graph_builder_plan.go | |||
@@ -117,7 +117,15 @@ func (b *PlanGraphBuilder) Steps() []GraphTransformer { | |||
117 | &CountBoundaryTransformer{}, | 117 | &CountBoundaryTransformer{}, |
118 | 118 | ||
119 | // Target | 119 | // Target |
120 | &TargetsTransformer{Targets: b.Targets}, | 120 | &TargetsTransformer{ |
121 | Targets: b.Targets, | ||
122 | |||
123 | // Resource nodes from config have not yet been expanded for | ||
124 | // "count", so we must apply targeting without indices. Exact | ||
125 | // targeting will be dealt with later when these resources | ||
126 | // DynamicExpand. | ||
127 | IgnoreIndices: true, | ||
128 | }, | ||
121 | 129 | ||
122 | // Close opened plugin connections | 130 | // Close opened plugin connections |
123 | &CloseProviderTransformer{}, | 131 | &CloseProviderTransformer{}, |
diff --git a/vendor/github.com/hashicorp/terraform/terraform/graph_builder_refresh.go b/vendor/github.com/hashicorp/terraform/terraform/graph_builder_refresh.go index 0634f96..3d3e968 100644 --- a/vendor/github.com/hashicorp/terraform/terraform/graph_builder_refresh.go +++ b/vendor/github.com/hashicorp/terraform/terraform/graph_builder_refresh.go | |||
@@ -144,7 +144,15 @@ func (b *RefreshGraphBuilder) Steps() []GraphTransformer { | |||
144 | &ReferenceTransformer{}, | 144 | &ReferenceTransformer{}, |
145 | 145 | ||
146 | // Target | 146 | // Target |
147 | &TargetsTransformer{Targets: b.Targets}, | 147 | &TargetsTransformer{ |
148 | Targets: b.Targets, | ||
149 | |||
150 | // Resource nodes from config have not yet been expanded for | ||
151 | // "count", so we must apply targeting without indices. Exact | ||
152 | // targeting will be dealt with later when these resources | ||
153 | // DynamicExpand. | ||
154 | IgnoreIndices: true, | ||
155 | }, | ||
148 | 156 | ||
149 | // Close opened plugin connections | 157 | // Close opened plugin connections |
150 | &CloseProviderTransformer{}, | 158 | &CloseProviderTransformer{}, |
diff --git a/vendor/github.com/hashicorp/terraform/terraform/interpolate.go b/vendor/github.com/hashicorp/terraform/terraform/interpolate.go index 0def295..22ddce6 100644 --- a/vendor/github.com/hashicorp/terraform/terraform/interpolate.go +++ b/vendor/github.com/hashicorp/terraform/terraform/interpolate.go | |||
@@ -317,9 +317,13 @@ func (i *Interpolater) valueTerraformVar( | |||
317 | n string, | 317 | n string, |
318 | v *config.TerraformVariable, | 318 | v *config.TerraformVariable, |
319 | result map[string]ast.Variable) error { | 319 | result map[string]ast.Variable) error { |
320 | if v.Field != "env" { | 320 | |
321 | // "env" is supported for backward compatibility, but it's deprecated and | ||
322 | // so we won't advertise it as being allowed in the error message. It will | ||
323 | // be removed in a future version of Terraform. | ||
324 | if v.Field != "workspace" && v.Field != "env" { | ||
321 | return fmt.Errorf( | 325 | return fmt.Errorf( |
322 | "%s: only supported key for 'terraform.X' interpolations is 'env'", n) | 326 | "%s: only supported key for 'terraform.X' interpolations is 'workspace'", n) |
323 | } | 327 | } |
324 | 328 | ||
325 | if i.Meta == nil { | 329 | if i.Meta == nil { |
diff --git a/vendor/github.com/hashicorp/terraform/terraform/module_dependencies.go b/vendor/github.com/hashicorp/terraform/terraform/module_dependencies.go new file mode 100644 index 0000000..b9f44a0 --- /dev/null +++ b/vendor/github.com/hashicorp/terraform/terraform/module_dependencies.go | |||
@@ -0,0 +1,156 @@ | |||
1 | package terraform | ||
2 | |||
3 | import ( | ||
4 | "github.com/hashicorp/terraform/config" | ||
5 | "github.com/hashicorp/terraform/config/module" | ||
6 | "github.com/hashicorp/terraform/moduledeps" | ||
7 | "github.com/hashicorp/terraform/plugin/discovery" | ||
8 | ) | ||
9 | |||
10 | // ModuleTreeDependencies returns the dependencies of the tree of modules | ||
11 | // described by the given configuration tree and state. | ||
12 | // | ||
13 | // Both configuration and state are required because there can be resources | ||
14 | // implied by instances in the state that no longer exist in config. | ||
15 | // | ||
16 | // This function will panic if any invalid version constraint strings are | ||
17 | // present in the configuration. This is guaranteed not to happen for any | ||
18 | // configuration that has passed a call to Config.Validate(). | ||
19 | func ModuleTreeDependencies(root *module.Tree, state *State) *moduledeps.Module { | ||
20 | |||
21 | // First we walk the configuration tree to build the overall structure | ||
22 | // and capture the explicit/implicit/inherited provider dependencies. | ||
23 | deps := moduleTreeConfigDependencies(root, nil) | ||
24 | |||
25 | // Next we walk over the resources in the state to catch any additional | ||
26 | // dependencies created by existing resources that are no longer in config. | ||
27 | // Most things we find in state will already be present in 'deps', but | ||
28 | // we're interested in the rare thing that isn't. | ||
29 | moduleTreeMergeStateDependencies(deps, state) | ||
30 | |||
31 | return deps | ||
32 | } | ||
33 | |||
34 | func moduleTreeConfigDependencies(root *module.Tree, inheritProviders map[string]*config.ProviderConfig) *moduledeps.Module { | ||
35 | if root == nil { | ||
36 | // If no config is provided, we'll make a synthetic root. | ||
37 | // This isn't necessarily correct if we're called with a nil that | ||
38 | // *isn't* at the root, but in practice that can never happen. | ||
39 | return &moduledeps.Module{ | ||
40 | Name: "root", | ||
41 | } | ||
42 | } | ||
43 | |||
44 | ret := &moduledeps.Module{ | ||
45 | Name: root.Name(), | ||
46 | } | ||
47 | |||
48 | cfg := root.Config() | ||
49 | providerConfigs := cfg.ProviderConfigsByFullName() | ||
50 | |||
51 | // Provider dependencies | ||
52 | { | ||
53 | providers := make(moduledeps.Providers, len(providerConfigs)) | ||
54 | |||
55 | // Any providerConfigs elements are *explicit* provider dependencies, | ||
56 | // which is the only situation where the user might provide an actual | ||
57 | // version constraint. We'll take care of these first. | ||
58 | for fullName, pCfg := range providerConfigs { | ||
59 | inst := moduledeps.ProviderInstance(fullName) | ||
60 | versionSet := discovery.AllVersions | ||
61 | if pCfg.Version != "" { | ||
62 | versionSet = discovery.ConstraintStr(pCfg.Version).MustParse() | ||
63 | } | ||
64 | providers[inst] = moduledeps.ProviderDependency{ | ||
65 | Constraints: versionSet, | ||
66 | Reason: moduledeps.ProviderDependencyExplicit, | ||
67 | } | ||
68 | } | ||
69 | |||
70 | // Each resource in the configuration creates an *implicit* provider | ||
71 | // dependency, though we'll only record it if there isn't already | ||
72 | // an explicit dependency on the same provider. | ||
73 | for _, rc := range cfg.Resources { | ||
74 | fullName := rc.ProviderFullName() | ||
75 | inst := moduledeps.ProviderInstance(fullName) | ||
76 | if _, exists := providers[inst]; exists { | ||
77 | // Explicit dependency already present | ||
78 | continue | ||
79 | } | ||
80 | |||
81 | reason := moduledeps.ProviderDependencyImplicit | ||
82 | if _, inherited := inheritProviders[fullName]; inherited { | ||
83 | reason = moduledeps.ProviderDependencyInherited | ||
84 | } | ||
85 | |||
86 | providers[inst] = moduledeps.ProviderDependency{ | ||
87 | Constraints: discovery.AllVersions, | ||
88 | Reason: reason, | ||
89 | } | ||
90 | } | ||
91 | |||
92 | ret.Providers = providers | ||
93 | } | ||
94 | |||
95 | childInherit := make(map[string]*config.ProviderConfig) | ||
96 | for k, v := range inheritProviders { | ||
97 | childInherit[k] = v | ||
98 | } | ||
99 | for k, v := range providerConfigs { | ||
100 | childInherit[k] = v | ||
101 | } | ||
102 | for _, c := range root.Children() { | ||
103 | ret.Children = append(ret.Children, moduleTreeConfigDependencies(c, childInherit)) | ||
104 | } | ||
105 | |||
106 | return ret | ||
107 | } | ||
108 | |||
109 | func moduleTreeMergeStateDependencies(root *moduledeps.Module, state *State) { | ||
110 | if state == nil { | ||
111 | return | ||
112 | } | ||
113 | |||
114 | findModule := func(path []string) *moduledeps.Module { | ||
115 | module := root | ||
116 | for _, name := range path[1:] { // skip initial "root" | ||
117 | var next *moduledeps.Module | ||
118 | for _, cm := range module.Children { | ||
119 | if cm.Name == name { | ||
120 | next = cm | ||
121 | break | ||
122 | } | ||
123 | } | ||
124 | |||
125 | if next == nil { | ||
126 | // If we didn't find a next node, we'll need to make one | ||
127 | next = &moduledeps.Module{ | ||
128 | Name: name, | ||
129 | } | ||
130 | module.Children = append(module.Children, next) | ||
131 | } | ||
132 | |||
133 | module = next | ||
134 | } | ||
135 | return module | ||
136 | } | ||
137 | |||
138 | for _, ms := range state.Modules { | ||
139 | module := findModule(ms.Path) | ||
140 | |||
141 | for _, is := range ms.Resources { | ||
142 | fullName := config.ResourceProviderFullName(is.Type, is.Provider) | ||
143 | inst := moduledeps.ProviderInstance(fullName) | ||
144 | if _, exists := module.Providers[inst]; !exists { | ||
145 | if module.Providers == nil { | ||
146 | module.Providers = make(moduledeps.Providers) | ||
147 | } | ||
148 | module.Providers[inst] = moduledeps.ProviderDependency{ | ||
149 | Constraints: discovery.AllVersions, | ||
150 | Reason: moduledeps.ProviderDependencyFromState, | ||
151 | } | ||
152 | } | ||
153 | } | ||
154 | } | ||
155 | |||
156 | } | ||
diff --git a/vendor/github.com/hashicorp/terraform/terraform/node_resource_refresh.go b/vendor/github.com/hashicorp/terraform/terraform/node_resource_refresh.go index 6ab9df7..cd4fe92 100644 --- a/vendor/github.com/hashicorp/terraform/terraform/node_resource_refresh.go +++ b/vendor/github.com/hashicorp/terraform/terraform/node_resource_refresh.go | |||
@@ -45,13 +45,6 @@ func (n *NodeRefreshableManagedResource) DynamicExpand(ctx EvalContext) (*Graph, | |||
45 | Addr: n.ResourceAddr(), | 45 | Addr: n.ResourceAddr(), |
46 | }, | 46 | }, |
47 | 47 | ||
48 | // Switch up any node missing state to a plannable resource. This helps | ||
49 | // catch cases where data sources depend on the counts from this resource | ||
50 | // during a scale out. | ||
51 | &ResourceRefreshPlannableTransformer{ | ||
52 | State: state, | ||
53 | }, | ||
54 | |||
55 | // Add the count orphans to make sure these resources are accounted for | 48 | // Add the count orphans to make sure these resources are accounted for |
56 | // during a scale in. | 49 | // during a scale in. |
57 | &OrphanResourceCountTransformer{ | 50 | &OrphanResourceCountTransformer{ |
@@ -100,6 +93,9 @@ func (n *NodeRefreshableManagedResourceInstance) EvalTree() EvalNode { | |||
100 | // Eval info is different depending on what kind of resource this is | 93 | // Eval info is different depending on what kind of resource this is |
101 | switch mode := n.Addr.Mode; mode { | 94 | switch mode := n.Addr.Mode; mode { |
102 | case config.ManagedResourceMode: | 95 | case config.ManagedResourceMode: |
96 | if n.ResourceState == nil { | ||
97 | return n.evalTreeManagedResourceNoState() | ||
98 | } | ||
103 | return n.evalTreeManagedResource() | 99 | return n.evalTreeManagedResource() |
104 | 100 | ||
105 | case config.DataResourceMode: | 101 | case config.DataResourceMode: |
@@ -176,3 +172,88 @@ func (n *NodeRefreshableManagedResourceInstance) evalTreeManagedResource() EvalN | |||
176 | }, | 172 | }, |
177 | } | 173 | } |
178 | } | 174 | } |
175 | |||
176 | // evalTreeManagedResourceNoState produces an EvalSequence for refresh resource | ||
177 | // nodes that don't have state attached. An example of where this functionality | ||
178 | // is useful is when a resource that already exists in state is being scaled | ||
179 | // out, ie: has its resource count increased. In this case, the scaled out node | ||
180 | // needs to be available to other nodes (namely data sources) that may depend | ||
181 | // on it for proper interpolation, or confusing "index out of range" errors can | ||
182 | // occur. | ||
183 | // | ||
184 | // The steps in this sequence are very similar to the steps carried out in | ||
185 | // plan, but nothing is done with the diff after it is created - it is dropped, | ||
186 | // and its changes are not counted in the UI. | ||
187 | func (n *NodeRefreshableManagedResourceInstance) evalTreeManagedResourceNoState() EvalNode { | ||
188 | // Declare a bunch of variables that are used for state during | ||
189 | // evaluation. Most of this are written to by-address below. | ||
190 | var provider ResourceProvider | ||
191 | var state *InstanceState | ||
192 | var resourceConfig *ResourceConfig | ||
193 | |||
194 | addr := n.NodeAbstractResource.Addr | ||
195 | stateID := addr.stateId() | ||
196 | info := &InstanceInfo{ | ||
197 | Id: stateID, | ||
198 | Type: addr.Type, | ||
199 | ModulePath: normalizeModulePath(addr.Path), | ||
200 | } | ||
201 | |||
202 | // Build the resource for eval | ||
203 | resource := &Resource{ | ||
204 | Name: addr.Name, | ||
205 | Type: addr.Type, | ||
206 | CountIndex: addr.Index, | ||
207 | } | ||
208 | if resource.CountIndex < 0 { | ||
209 | resource.CountIndex = 0 | ||
210 | } | ||
211 | |||
212 | // Determine the dependencies for the state. | ||
213 | stateDeps := n.StateReferences() | ||
214 | |||
215 | return &EvalSequence{ | ||
216 | Nodes: []EvalNode{ | ||
217 | &EvalInterpolate{ | ||
218 | Config: n.Config.RawConfig.Copy(), | ||
219 | Resource: resource, | ||
220 | Output: &resourceConfig, | ||
221 | }, | ||
222 | &EvalGetProvider{ | ||
223 | Name: n.ProvidedBy()[0], | ||
224 | Output: &provider, | ||
225 | }, | ||
226 | // Re-run validation to catch any errors we missed, e.g. type | ||
227 | // mismatches on computed values. | ||
228 | &EvalValidateResource{ | ||
229 | Provider: &provider, | ||
230 | Config: &resourceConfig, | ||
231 | ResourceName: n.Config.Name, | ||
232 | ResourceType: n.Config.Type, | ||
233 | ResourceMode: n.Config.Mode, | ||
234 | IgnoreWarnings: true, | ||
235 | }, | ||
236 | &EvalReadState{ | ||
237 | Name: stateID, | ||
238 | Output: &state, | ||
239 | }, | ||
240 | &EvalDiff{ | ||
241 | Name: stateID, | ||
242 | Info: info, | ||
243 | Config: &resourceConfig, | ||
244 | Resource: n.Config, | ||
245 | Provider: &provider, | ||
246 | State: &state, | ||
247 | OutputState: &state, | ||
248 | Stub: true, | ||
249 | }, | ||
250 | &EvalWriteState{ | ||
251 | Name: stateID, | ||
252 | ResourceType: n.Config.Type, | ||
253 | Provider: n.Config.Provider, | ||
254 | Dependencies: stateDeps, | ||
255 | State: &state, | ||
256 | }, | ||
257 | }, | ||
258 | } | ||
259 | } | ||
diff --git a/vendor/github.com/hashicorp/terraform/terraform/plan.go b/vendor/github.com/hashicorp/terraform/terraform/plan.go index ea08845..51d6652 100644 --- a/vendor/github.com/hashicorp/terraform/terraform/plan.go +++ b/vendor/github.com/hashicorp/terraform/terraform/plan.go | |||
@@ -6,6 +6,7 @@ import ( | |||
6 | "errors" | 6 | "errors" |
7 | "fmt" | 7 | "fmt" |
8 | "io" | 8 | "io" |
9 | "log" | ||
9 | "sync" | 10 | "sync" |
10 | 11 | ||
11 | "github.com/hashicorp/terraform/config/module" | 12 | "github.com/hashicorp/terraform/config/module" |
@@ -31,6 +32,9 @@ type Plan struct { | |||
31 | Vars map[string]interface{} | 32 | Vars map[string]interface{} |
32 | Targets []string | 33 | Targets []string |
33 | 34 | ||
35 | TerraformVersion string | ||
36 | ProviderSHA256s map[string][]byte | ||
37 | |||
34 | // Backend is the backend that this plan should use and store data with. | 38 | // Backend is the backend that this plan should use and store data with. |
35 | Backend *BackendState | 39 | Backend *BackendState |
36 | 40 | ||
@@ -40,19 +44,58 @@ type Plan struct { | |||
40 | // Context returns a Context with the data encapsulated in this plan. | 44 | // Context returns a Context with the data encapsulated in this plan. |
41 | // | 45 | // |
42 | // The following fields in opts are overridden by the plan: Config, | 46 | // The following fields in opts are overridden by the plan: Config, |
43 | // Diff, State, Variables. | 47 | // Diff, Variables. |
48 | // | ||
49 | // If State is not provided, it is set from the plan. If it _is_ provided, | ||
50 | // it must be Equal to the state stored in plan, but may have a newer | ||
51 | // serial. | ||
44 | func (p *Plan) Context(opts *ContextOpts) (*Context, error) { | 52 | func (p *Plan) Context(opts *ContextOpts) (*Context, error) { |
53 | var err error | ||
54 | opts, err = p.contextOpts(opts) | ||
55 | if err != nil { | ||
56 | return nil, err | ||
57 | } | ||
58 | return NewContext(opts) | ||
59 | } | ||
60 | |||
61 | // contextOpts mutates the given base ContextOpts in place to use input | ||
62 | // objects obtained from the receiving plan. | ||
63 | func (p *Plan) contextOpts(base *ContextOpts) (*ContextOpts, error) { | ||
64 | opts := base | ||
65 | |||
45 | opts.Diff = p.Diff | 66 | opts.Diff = p.Diff |
46 | opts.Module = p.Module | 67 | opts.Module = p.Module |
47 | opts.State = p.State | ||
48 | opts.Targets = p.Targets | 68 | opts.Targets = p.Targets |
69 | opts.ProviderSHA256s = p.ProviderSHA256s | ||
70 | |||
71 | if opts.State == nil { | ||
72 | opts.State = p.State | ||
73 | } else if !opts.State.Equal(p.State) { | ||
74 | // Even if we're overriding the state, it should be logically equal | ||
75 | // to what's in plan. The only valid change to have made by the time | ||
76 | // we get here is to have incremented the serial. | ||
77 | // | ||
78 | // Due to the fact that serialization may change the representation of | ||
79 | // the state, there is little chance that these aren't actually equal. | ||
80 | // Log the error condition for reference, but continue with the state | ||
81 | // we have. | ||
82 | log.Println("[WARNING] Plan state and ContextOpts state are not equal") | ||
83 | } | ||
84 | |||
85 | thisVersion := VersionString() | ||
86 | if p.TerraformVersion != "" && p.TerraformVersion != thisVersion { | ||
87 | return nil, fmt.Errorf( | ||
88 | "plan was created with a different version of Terraform (created with %s, but running %s)", | ||
89 | p.TerraformVersion, thisVersion, | ||
90 | ) | ||
91 | } | ||
49 | 92 | ||
50 | opts.Variables = make(map[string]interface{}) | 93 | opts.Variables = make(map[string]interface{}) |
51 | for k, v := range p.Vars { | 94 | for k, v := range p.Vars { |
52 | opts.Variables[k] = v | 95 | opts.Variables[k] = v |
53 | } | 96 | } |
54 | 97 | ||
55 | return NewContext(opts) | 98 | return opts, nil |
56 | } | 99 | } |
57 | 100 | ||
58 | func (p *Plan) String() string { | 101 | func (p *Plan) String() string { |
@@ -86,7 +129,7 @@ func (p *Plan) init() { | |||
86 | // the ability in the future to change the file format if we want for any | 129 | // the ability in the future to change the file format if we want for any |
87 | // reason. | 130 | // reason. |
88 | const planFormatMagic = "tfplan" | 131 | const planFormatMagic = "tfplan" |
89 | const planFormatVersion byte = 1 | 132 | const planFormatVersion byte = 2 |
90 | 133 | ||
91 | // ReadPlan reads a plan structure out of a reader in the format that | 134 | // ReadPlan reads a plan structure out of a reader in the format that |
92 | // was written by WritePlan. | 135 | // was written by WritePlan. |
diff --git a/vendor/github.com/hashicorp/terraform/terraform/resource_address.go b/vendor/github.com/hashicorp/terraform/terraform/resource_address.go index a8a0c95..8badca8 100644 --- a/vendor/github.com/hashicorp/terraform/terraform/resource_address.go +++ b/vendor/github.com/hashicorp/terraform/terraform/resource_address.go | |||
@@ -8,6 +8,7 @@ import ( | |||
8 | "strings" | 8 | "strings" |
9 | 9 | ||
10 | "github.com/hashicorp/terraform/config" | 10 | "github.com/hashicorp/terraform/config" |
11 | "github.com/hashicorp/terraform/config/module" | ||
11 | ) | 12 | ) |
12 | 13 | ||
13 | // ResourceAddress is a way of identifying an individual resource (or, | 14 | // ResourceAddress is a way of identifying an individual resource (or, |
@@ -89,6 +90,51 @@ func (r *ResourceAddress) String() string { | |||
89 | return strings.Join(result, ".") | 90 | return strings.Join(result, ".") |
90 | } | 91 | } |
91 | 92 | ||
93 | // HasResourceSpec returns true if the address has a resource spec, as | ||
94 | // defined in the documentation: | ||
95 | // https://www.terraform.io/docs/internals/resource-addressing.html | ||
96 | // In particular, this returns false if the address contains only | ||
97 | // a module path, thus addressing the entire module. | ||
98 | func (r *ResourceAddress) HasResourceSpec() bool { | ||
99 | return r.Type != "" && r.Name != "" | ||
100 | } | ||
101 | |||
102 | // WholeModuleAddress returns the resource address that refers to all | ||
103 | // resources in the same module as the receiver address. | ||
104 | func (r *ResourceAddress) WholeModuleAddress() *ResourceAddress { | ||
105 | return &ResourceAddress{ | ||
106 | Path: r.Path, | ||
107 | Index: -1, | ||
108 | InstanceTypeSet: false, | ||
109 | } | ||
110 | } | ||
111 | |||
112 | // MatchesConfig returns true if the receiver matches the given | ||
113 | // configuration resource within the given configuration module. | ||
114 | // | ||
115 | // Since resource configuration blocks represent all of the instances of | ||
116 | // a multi-instance resource, the index of the address (if any) is not | ||
117 | // considered. | ||
118 | func (r *ResourceAddress) MatchesConfig(mod *module.Tree, rc *config.Resource) bool { | ||
119 | if r.HasResourceSpec() { | ||
120 | if r.Mode != rc.Mode || r.Type != rc.Type || r.Name != rc.Name { | ||
121 | return false | ||
122 | } | ||
123 | } | ||
124 | |||
125 | addrPath := r.Path | ||
126 | cfgPath := mod.Path() | ||
127 | |||
128 | // normalize | ||
129 | if len(addrPath) == 0 { | ||
130 | addrPath = nil | ||
131 | } | ||
132 | if len(cfgPath) == 0 { | ||
133 | cfgPath = nil | ||
134 | } | ||
135 | return reflect.DeepEqual(addrPath, cfgPath) | ||
136 | } | ||
137 | |||
92 | // stateId returns the ID that this resource should be entered with | 138 | // stateId returns the ID that this resource should be entered with |
93 | // in the state. This is also used for diffs. In the future, we'd like to | 139 | // in the state. This is also used for diffs. In the future, we'd like to |
94 | // move away from this string field so I don't export this. | 140 | // move away from this string field so I don't export this. |
@@ -185,7 +231,10 @@ func ParseResourceAddress(s string) (*ResourceAddress, error) { | |||
185 | 231 | ||
186 | // not allowed to say "data." without a type following | 232 | // not allowed to say "data." without a type following |
187 | if mode == config.DataResourceMode && matches["type"] == "" { | 233 | if mode == config.DataResourceMode && matches["type"] == "" { |
188 | return nil, fmt.Errorf("must target specific data instance") | 234 | return nil, fmt.Errorf( |
235 | "invalid resource address %q: must target specific data instance", | ||
236 | s, | ||
237 | ) | ||
189 | } | 238 | } |
190 | 239 | ||
191 | return &ResourceAddress{ | 240 | return &ResourceAddress{ |
@@ -199,6 +248,75 @@ func ParseResourceAddress(s string) (*ResourceAddress, error) { | |||
199 | }, nil | 248 | }, nil |
200 | } | 249 | } |
201 | 250 | ||
251 | // ParseResourceAddressForInstanceDiff creates a ResourceAddress for a | ||
252 | // resource name as described in a module diff. | ||
253 | // | ||
254 | // For historical reasons a different addressing format is used in this | ||
255 | // context. The internal format should not be shown in the UI and instead | ||
256 | // this function should be used to translate to a ResourceAddress and | ||
257 | // then, where appropriate, use the String method to produce a canonical | ||
258 | // resource address string for display in the UI. | ||
259 | // | ||
260 | // The given path slice must be empty (or nil) for the root module, and | ||
261 | // otherwise consist of a sequence of module names traversing down into | ||
262 | // the module tree. If a non-nil path is provided, the caller must not | ||
263 | // modify its underlying array after passing it to this function. | ||
264 | func ParseResourceAddressForInstanceDiff(path []string, key string) (*ResourceAddress, error) { | ||
265 | addr, err := parseResourceAddressInternal(key) | ||
266 | if err != nil { | ||
267 | return nil, err | ||
268 | } | ||
269 | addr.Path = path | ||
270 | return addr, nil | ||
271 | } | ||
272 | |||
273 | // Contains returns true if and only if the given node is contained within | ||
274 | // the receiver. | ||
275 | // | ||
276 | // Containment is defined in terms of the module and resource heirarchy: | ||
277 | // a resource is contained within its module and any ancestor modules, | ||
278 | // an indexed resource instance is contained with the unindexed resource, etc. | ||
279 | func (addr *ResourceAddress) Contains(other *ResourceAddress) bool { | ||
280 | ourPath := addr.Path | ||
281 | givenPath := other.Path | ||
282 | if len(givenPath) < len(ourPath) { | ||
283 | return false | ||
284 | } | ||
285 | for i := range ourPath { | ||
286 | if ourPath[i] != givenPath[i] { | ||
287 | return false | ||
288 | } | ||
289 | } | ||
290 | |||
291 | // If the receiver is a whole-module address then the path prefix | ||
292 | // matching is all we need. | ||
293 | if !addr.HasResourceSpec() { | ||
294 | return true | ||
295 | } | ||
296 | |||
297 | if addr.Type != other.Type || addr.Name != other.Name || addr.Mode != other.Mode { | ||
298 | return false | ||
299 | } | ||
300 | |||
301 | if addr.Index != -1 && addr.Index != other.Index { | ||
302 | return false | ||
303 | } | ||
304 | |||
305 | if addr.InstanceTypeSet && (addr.InstanceTypeSet != other.InstanceTypeSet || addr.InstanceType != other.InstanceType) { | ||
306 | return false | ||
307 | } | ||
308 | |||
309 | return true | ||
310 | } | ||
311 | |||
312 | // Equals returns true if the receiver matches the given address. | ||
313 | // | ||
314 | // The name of this method is a misnomer, since it doesn't test for exact | ||
315 | // equality. Instead, it tests that the _specified_ parts of each | ||
316 | // address match, treating any unspecified parts as wildcards. | ||
317 | // | ||
318 | // See also Contains, which takes a more heirarchical approach to comparing | ||
319 | // addresses. | ||
202 | func (addr *ResourceAddress) Equals(raw interface{}) bool { | 320 | func (addr *ResourceAddress) Equals(raw interface{}) bool { |
203 | other, ok := raw.(*ResourceAddress) | 321 | other, ok := raw.(*ResourceAddress) |
204 | if !ok { | 322 | if !ok { |
@@ -233,6 +351,58 @@ func (addr *ResourceAddress) Equals(raw interface{}) bool { | |||
233 | modeMatch | 351 | modeMatch |
234 | } | 352 | } |
235 | 353 | ||
354 | // Less returns true if and only if the receiver should be sorted before | ||
355 | // the given address when presenting a list of resource addresses to | ||
356 | // an end-user. | ||
357 | // | ||
358 | // This sort uses lexicographic sorting for most components, but uses | ||
359 | // numeric sort for indices, thus causing index 10 to sort after | ||
360 | // index 9, rather than after index 1. | ||
361 | func (addr *ResourceAddress) Less(other *ResourceAddress) bool { | ||
362 | |||
363 | switch { | ||
364 | |||
365 | case len(addr.Path) < len(other.Path): | ||
366 | return true | ||
367 | |||
368 | case !reflect.DeepEqual(addr.Path, other.Path): | ||
369 | // If the two paths are the same length but don't match, we'll just | ||
370 | // cheat and compare the string forms since it's easier than | ||
371 | // comparing all of the path segments in turn. | ||
372 | addrStr := addr.String() | ||
373 | otherStr := other.String() | ||
374 | return addrStr < otherStr | ||
375 | |||
376 | case addr.Mode == config.DataResourceMode && other.Mode != config.DataResourceMode: | ||
377 | return true | ||
378 | |||
379 | case addr.Type < other.Type: | ||
380 | return true | ||
381 | |||
382 | case addr.Name < other.Name: | ||
383 | return true | ||
384 | |||
385 | case addr.Index < other.Index: | ||
386 | // Since "Index" is -1 for an un-indexed address, this also conveniently | ||
387 | // sorts unindexed addresses before indexed ones, should they both | ||
388 | // appear for some reason. | ||
389 | return true | ||
390 | |||
391 | case other.InstanceTypeSet && !addr.InstanceTypeSet: | ||
392 | return true | ||
393 | |||
394 | case addr.InstanceType < other.InstanceType: | ||
395 | // InstanceType is actually an enum, so this is just an arbitrary | ||
396 | // sort based on the enum numeric values, and thus not particularly | ||
397 | // meaningful. | ||
398 | return true | ||
399 | |||
400 | default: | ||
401 | return false | ||
402 | |||
403 | } | ||
404 | } | ||
405 | |||
236 | func ParseResourceIndex(s string) (int, error) { | 406 | func ParseResourceIndex(s string) (int, error) { |
237 | if s == "" { | 407 | if s == "" { |
238 | return -1, nil | 408 | return -1, nil |
@@ -275,7 +445,7 @@ func tokenizeResourceAddress(s string) (map[string]string, error) { | |||
275 | // string "aws_instance.web.tainted[1]" | 445 | // string "aws_instance.web.tainted[1]" |
276 | re := regexp.MustCompile(`\A` + | 446 | re := regexp.MustCompile(`\A` + |
277 | // "module.foo.module.bar" (optional) | 447 | // "module.foo.module.bar" (optional) |
278 | `(?P<path>(?:module\.[^.]+\.?)*)` + | 448 | `(?P<path>(?:module\.(?P<module_name>[^.]+)\.?)*)` + |
279 | // possibly "data.", if targeting is a data resource | 449 | // possibly "data.", if targeting is a data resource |
280 | `(?P<data_prefix>(?:data\.)?)` + | 450 | `(?P<data_prefix>(?:data\.)?)` + |
281 | // "aws_instance.web" (optional when module path specified) | 451 | // "aws_instance.web" (optional when module path specified) |
@@ -289,7 +459,7 @@ func tokenizeResourceAddress(s string) (map[string]string, error) { | |||
289 | groupNames := re.SubexpNames() | 459 | groupNames := re.SubexpNames() |
290 | rawMatches := re.FindAllStringSubmatch(s, -1) | 460 | rawMatches := re.FindAllStringSubmatch(s, -1) |
291 | if len(rawMatches) != 1 { | 461 | if len(rawMatches) != 1 { |
292 | return nil, fmt.Errorf("Problem parsing address: %q", s) | 462 | return nil, fmt.Errorf("invalid resource address %q", s) |
293 | } | 463 | } |
294 | 464 | ||
295 | matches := make(map[string]string) | 465 | matches := make(map[string]string) |
diff --git a/vendor/github.com/hashicorp/terraform/terraform/resource_provider.go b/vendor/github.com/hashicorp/terraform/terraform/resource_provider.go index 1a68c86..7d78f67 100644 --- a/vendor/github.com/hashicorp/terraform/terraform/resource_provider.go +++ b/vendor/github.com/hashicorp/terraform/terraform/resource_provider.go | |||
@@ -1,5 +1,12 @@ | |||
1 | package terraform | 1 | package terraform |
2 | 2 | ||
3 | import ( | ||
4 | "fmt" | ||
5 | |||
6 | multierror "github.com/hashicorp/go-multierror" | ||
7 | "github.com/hashicorp/terraform/plugin/discovery" | ||
8 | ) | ||
9 | |||
3 | // ResourceProvider is an interface that must be implemented by any | 10 | // ResourceProvider is an interface that must be implemented by any |
4 | // resource provider: the thing that creates and manages the resources in | 11 | // resource provider: the thing that creates and manages the resources in |
5 | // a Terraform configuration. | 12 | // a Terraform configuration. |
@@ -154,6 +161,18 @@ type ResourceProvider interface { | |||
154 | ReadDataApply(*InstanceInfo, *InstanceDiff) (*InstanceState, error) | 161 | ReadDataApply(*InstanceInfo, *InstanceDiff) (*InstanceState, error) |
155 | } | 162 | } |
156 | 163 | ||
164 | // ResourceProviderError may be returned when creating a Context if the | ||
165 | // required providers cannot be satisfied. This error can then be used to | ||
166 | // format a more useful message for the user. | ||
167 | type ResourceProviderError struct { | ||
168 | Errors []error | ||
169 | } | ||
170 | |||
171 | func (e *ResourceProviderError) Error() string { | ||
172 | // use multierror to format the default output | ||
173 | return multierror.Append(nil, e.Errors...).Error() | ||
174 | } | ||
175 | |||
157 | // ResourceProviderCloser is an interface that providers that can close | 176 | // ResourceProviderCloser is an interface that providers that can close |
158 | // connections that aren't needed anymore must implement. | 177 | // connections that aren't needed anymore must implement. |
159 | type ResourceProviderCloser interface { | 178 | type ResourceProviderCloser interface { |
@@ -171,6 +190,50 @@ type DataSource struct { | |||
171 | Name string | 190 | Name string |
172 | } | 191 | } |
173 | 192 | ||
193 | // ResourceProviderResolver is an interface implemented by objects that are | ||
194 | // able to resolve a given set of resource provider version constraints | ||
195 | // into ResourceProviderFactory callbacks. | ||
196 | type ResourceProviderResolver interface { | ||
197 | // Given a constraint map, return a ResourceProviderFactory for each | ||
198 | // requested provider. If some or all of the constraints cannot be | ||
199 | // satisfied, return a non-nil slice of errors describing the problems. | ||
200 | ResolveProviders(reqd discovery.PluginRequirements) (map[string]ResourceProviderFactory, []error) | ||
201 | } | ||
202 | |||
203 | // ResourceProviderResolverFunc wraps a callback function and turns it into | ||
204 | // a ResourceProviderResolver implementation, for convenience in situations | ||
205 | // where a function and its associated closure are sufficient as a resolver | ||
206 | // implementation. | ||
207 | type ResourceProviderResolverFunc func(reqd discovery.PluginRequirements) (map[string]ResourceProviderFactory, []error) | ||
208 | |||
209 | // ResolveProviders implements ResourceProviderResolver by calling the | ||
210 | // wrapped function. | ||
211 | func (f ResourceProviderResolverFunc) ResolveProviders(reqd discovery.PluginRequirements) (map[string]ResourceProviderFactory, []error) { | ||
212 | return f(reqd) | ||
213 | } | ||
214 | |||
215 | // ResourceProviderResolverFixed returns a ResourceProviderResolver that | ||
216 | // has a fixed set of provider factories provided by the caller. The returned | ||
217 | // resolver ignores version constraints entirely and just returns the given | ||
218 | // factory for each requested provider name. | ||
219 | // | ||
220 | // This function is primarily used in tests, to provide mock providers or | ||
221 | // in-process providers under test. | ||
222 | func ResourceProviderResolverFixed(factories map[string]ResourceProviderFactory) ResourceProviderResolver { | ||
223 | return ResourceProviderResolverFunc(func(reqd discovery.PluginRequirements) (map[string]ResourceProviderFactory, []error) { | ||
224 | ret := make(map[string]ResourceProviderFactory, len(reqd)) | ||
225 | var errs []error | ||
226 | for name := range reqd { | ||
227 | if factory, exists := factories[name]; exists { | ||
228 | ret[name] = factory | ||
229 | } else { | ||
230 | errs = append(errs, fmt.Errorf("provider %q is not available", name)) | ||
231 | } | ||
232 | } | ||
233 | return ret, errs | ||
234 | }) | ||
235 | } | ||
236 | |||
174 | // ResourceProviderFactory is a function type that creates a new instance | 237 | // ResourceProviderFactory is a function type that creates a new instance |
175 | // of a resource provider. | 238 | // of a resource provider. |
176 | type ResourceProviderFactory func() (ResourceProvider, error) | 239 | type ResourceProviderFactory func() (ResourceProvider, error) |
@@ -202,3 +265,21 @@ func ProviderHasDataSource(p ResourceProvider, n string) bool { | |||
202 | 265 | ||
203 | return false | 266 | return false |
204 | } | 267 | } |
268 | |||
269 | // resourceProviderFactories matches available plugins to the given version | ||
270 | // requirements to produce a map of compatible provider plugins if possible, | ||
271 | // or an error if the currently-available plugins are insufficient. | ||
272 | // | ||
273 | // This should be called only with configurations that have passed calls | ||
274 | // to config.Validate(), which ensures that all of the given version | ||
275 | // constraints are valid. It will panic if any invalid constraints are present. | ||
276 | func resourceProviderFactories(resolver ResourceProviderResolver, reqd discovery.PluginRequirements) (map[string]ResourceProviderFactory, error) { | ||
277 | ret, errs := resolver.ResolveProviders(reqd) | ||
278 | if errs != nil { | ||
279 | return nil, &ResourceProviderError{ | ||
280 | Errors: errs, | ||
281 | } | ||
282 | } | ||
283 | |||
284 | return ret, nil | ||
285 | } | ||
diff --git a/vendor/github.com/hashicorp/terraform/terraform/state.go b/vendor/github.com/hashicorp/terraform/terraform/state.go index 074b682..0c46194 100644 --- a/vendor/github.com/hashicorp/terraform/terraform/state.go +++ b/vendor/github.com/hashicorp/terraform/terraform/state.go | |||
@@ -533,6 +533,43 @@ func (s *State) equal(other *State) bool { | |||
533 | return true | 533 | return true |
534 | } | 534 | } |
535 | 535 | ||
536 | // MarshalEqual is similar to Equal but provides a stronger definition of | ||
537 | // "equal", where two states are equal if and only if their serialized form | ||
538 | // is byte-for-byte identical. | ||
539 | // | ||
540 | // This is primarily useful for callers that are trying to save snapshots | ||
541 | // of state to persistent storage, allowing them to detect when a new | ||
542 | // snapshot must be taken. | ||
543 | // | ||
544 | // Note that the serial number and lineage are included in the serialized form, | ||
545 | // so it's the caller's responsibility to properly manage these attributes | ||
546 | // so that this method is only called on two states that have the same | ||
547 | // serial and lineage, unless detecting such differences is desired. | ||
548 | func (s *State) MarshalEqual(other *State) bool { | ||
549 | if s == nil && other == nil { | ||
550 | return true | ||
551 | } else if s == nil || other == nil { | ||
552 | return false | ||
553 | } | ||
554 | |||
555 | recvBuf := &bytes.Buffer{} | ||
556 | otherBuf := &bytes.Buffer{} | ||
557 | |||
558 | err := WriteState(s, recvBuf) | ||
559 | if err != nil { | ||
560 | // should never happen, since we're writing to a buffer | ||
561 | panic(err) | ||
562 | } | ||
563 | |||
564 | err = WriteState(other, otherBuf) | ||
565 | if err != nil { | ||
566 | // should never happen, since we're writing to a buffer | ||
567 | panic(err) | ||
568 | } | ||
569 | |||
570 | return bytes.Equal(recvBuf.Bytes(), otherBuf.Bytes()) | ||
571 | } | ||
572 | |||
536 | type StateAgeComparison int | 573 | type StateAgeComparison int |
537 | 574 | ||
538 | const ( | 575 | const ( |
@@ -603,6 +640,10 @@ func (s *State) SameLineage(other *State) bool { | |||
603 | // DeepCopy performs a deep copy of the state structure and returns | 640 | // DeepCopy performs a deep copy of the state structure and returns |
604 | // a new structure. | 641 | // a new structure. |
605 | func (s *State) DeepCopy() *State { | 642 | func (s *State) DeepCopy() *State { |
643 | if s == nil { | ||
644 | return nil | ||
645 | } | ||
646 | |||
606 | copy, err := copystructure.Config{Lock: true}.Copy(s) | 647 | copy, err := copystructure.Config{Lock: true}.Copy(s) |
607 | if err != nil { | 648 | if err != nil { |
608 | panic(err) | 649 | panic(err) |
@@ -611,30 +652,6 @@ func (s *State) DeepCopy() *State { | |||
611 | return copy.(*State) | 652 | return copy.(*State) |
612 | } | 653 | } |
613 | 654 | ||
614 | // IncrementSerialMaybe increments the serial number of this state | ||
615 | // if it different from the other state. | ||
616 | func (s *State) IncrementSerialMaybe(other *State) { | ||
617 | if s == nil { | ||
618 | return | ||
619 | } | ||
620 | if other == nil { | ||
621 | return | ||
622 | } | ||
623 | s.Lock() | ||
624 | defer s.Unlock() | ||
625 | |||
626 | if s.Serial > other.Serial { | ||
627 | return | ||
628 | } | ||
629 | if other.TFVersion != s.TFVersion || !s.equal(other) { | ||
630 | if other.Serial > s.Serial { | ||
631 | s.Serial = other.Serial | ||
632 | } | ||
633 | |||
634 | s.Serial++ | ||
635 | } | ||
636 | } | ||
637 | |||
638 | // FromFutureTerraform checks if this state was written by a Terraform | 655 | // FromFutureTerraform checks if this state was written by a Terraform |
639 | // version from the future. | 656 | // version from the future. |
640 | func (s *State) FromFutureTerraform() bool { | 657 | func (s *State) FromFutureTerraform() bool { |
@@ -660,6 +677,7 @@ func (s *State) init() { | |||
660 | if s.Version == 0 { | 677 | if s.Version == 0 { |
661 | s.Version = StateVersion | 678 | s.Version = StateVersion |
662 | } | 679 | } |
680 | |||
663 | if s.moduleByPath(rootModulePath) == nil { | 681 | if s.moduleByPath(rootModulePath) == nil { |
664 | s.addModule(rootModulePath) | 682 | s.addModule(rootModulePath) |
665 | } | 683 | } |
diff --git a/vendor/github.com/hashicorp/terraform/terraform/test_failure b/vendor/github.com/hashicorp/terraform/terraform/test_failure new file mode 100644 index 0000000..5d3ad1a --- /dev/null +++ b/vendor/github.com/hashicorp/terraform/terraform/test_failure | |||
@@ -0,0 +1,9 @@ | |||
1 | --- FAIL: TestContext2Plan_moduleProviderInherit (0.01s) | ||
2 | context_plan_test.go:552: bad: []string{"child"} | ||
3 | map[string]dag.Vertex{} | ||
4 | "module.middle.null" | ||
5 | map[string]dag.Vertex{} | ||
6 | "module.middle.module.inner.null" | ||
7 | map[string]dag.Vertex{} | ||
8 | "aws" | ||
9 | FAIL | ||
diff --git a/vendor/github.com/hashicorp/terraform/terraform/transform_resource_refresh_plannable.go b/vendor/github.com/hashicorp/terraform/terraform/transform_resource_refresh_plannable.go deleted file mode 100644 index 35358a3..0000000 --- a/vendor/github.com/hashicorp/terraform/terraform/transform_resource_refresh_plannable.go +++ /dev/null | |||
@@ -1,55 +0,0 @@ | |||
1 | package terraform | ||
2 | |||
3 | import ( | ||
4 | "fmt" | ||
5 | "log" | ||
6 | ) | ||
7 | |||
8 | // ResourceRefreshPlannableTransformer is a GraphTransformer that replaces any | ||
9 | // nodes that don't have state yet exist in config with | ||
10 | // NodePlannableResourceInstance. | ||
11 | // | ||
12 | // This transformer is used when expanding count on managed resource nodes | ||
13 | // during the refresh phase to ensure that data sources that have | ||
14 | // interpolations that depend on resources existing in the graph can be walked | ||
15 | // properly. | ||
16 | type ResourceRefreshPlannableTransformer struct { | ||
17 | // The full global state. | ||
18 | State *State | ||
19 | } | ||
20 | |||
21 | // Transform implements GraphTransformer for | ||
22 | // ResourceRefreshPlannableTransformer. | ||
23 | func (t *ResourceRefreshPlannableTransformer) Transform(g *Graph) error { | ||
24 | nextVertex: | ||
25 | for _, v := range g.Vertices() { | ||
26 | addr := v.(*NodeRefreshableManagedResourceInstance).Addr | ||
27 | |||
28 | // Find the state for this address, if there is one | ||
29 | filter := &StateFilter{State: t.State} | ||
30 | results, err := filter.Filter(addr.String()) | ||
31 | if err != nil { | ||
32 | return err | ||
33 | } | ||
34 | |||
35 | // Check to see if we have a state for this resource. If we do, skip this | ||
36 | // node. | ||
37 | for _, result := range results { | ||
38 | if _, ok := result.Value.(*ResourceState); ok { | ||
39 | continue nextVertex | ||
40 | } | ||
41 | } | ||
42 | // If we don't, convert this resource to a NodePlannableResourceInstance node | ||
43 | // with all of the data we need to make it happen. | ||
44 | log.Printf("[TRACE] No state for %s, converting to NodePlannableResourceInstance", addr.String()) | ||
45 | new := &NodePlannableResourceInstance{ | ||
46 | NodeAbstractResource: v.(*NodeRefreshableManagedResourceInstance).NodeAbstractResource, | ||
47 | } | ||
48 | // Replace the node in the graph | ||
49 | if !g.Replace(v, new) { | ||
50 | return fmt.Errorf("ResourceRefreshPlannableTransformer: Could not replace node %#v with %#v", v, new) | ||
51 | } | ||
52 | } | ||
53 | |||
54 | return nil | ||
55 | } | ||
diff --git a/vendor/github.com/hashicorp/terraform/terraform/transform_targets.go b/vendor/github.com/hashicorp/terraform/terraform/transform_targets.go index 125f9e3..4f117b4 100644 --- a/vendor/github.com/hashicorp/terraform/terraform/transform_targets.go +++ b/vendor/github.com/hashicorp/terraform/terraform/transform_targets.go | |||
@@ -41,6 +41,12 @@ type TargetsTransformer struct { | |||
41 | // that already have the targets parsed | 41 | // that already have the targets parsed |
42 | ParsedTargets []ResourceAddress | 42 | ParsedTargets []ResourceAddress |
43 | 43 | ||
44 | // If set, the index portions of resource addresses will be ignored | ||
45 | // for comparison. This is used when transforming a graph where | ||
46 | // counted resources have not yet been expanded, since otherwise | ||
47 | // the unexpanded nodes (which never have indices) would not match. | ||
48 | IgnoreIndices bool | ||
49 | |||
44 | // Set to true when we're in a `terraform destroy` or a | 50 | // Set to true when we're in a `terraform destroy` or a |
45 | // `terraform plan -destroy` | 51 | // `terraform plan -destroy` |
46 | Destroy bool | 52 | Destroy bool |
@@ -199,7 +205,12 @@ func (t *TargetsTransformer) nodeIsTarget( | |||
199 | 205 | ||
200 | addr := r.ResourceAddr() | 206 | addr := r.ResourceAddr() |
201 | for _, targetAddr := range addrs { | 207 | for _, targetAddr := range addrs { |
202 | if targetAddr.Equals(addr) { | 208 | if t.IgnoreIndices { |
209 | // targetAddr is not a pointer, so we can safely mutate it without | ||
210 | // interfering with references elsewhere. | ||
211 | targetAddr.Index = -1 | ||
212 | } | ||
213 | if targetAddr.Contains(addr) { | ||
203 | return true | 214 | return true |
204 | } | 215 | } |
205 | } | 216 | } |
diff --git a/vendor/github.com/hashicorp/terraform/terraform/util.go b/vendor/github.com/hashicorp/terraform/terraform/util.go index f41f0d7..752241a 100644 --- a/vendor/github.com/hashicorp/terraform/terraform/util.go +++ b/vendor/github.com/hashicorp/terraform/terraform/util.go | |||
@@ -2,7 +2,8 @@ package terraform | |||
2 | 2 | ||
3 | import ( | 3 | import ( |
4 | "sort" | 4 | "sort" |
5 | "strings" | 5 | |
6 | "github.com/hashicorp/terraform/config" | ||
6 | ) | 7 | ) |
7 | 8 | ||
8 | // Semaphore is a wrapper around a channel to provide | 9 | // Semaphore is a wrapper around a channel to provide |
@@ -47,21 +48,8 @@ func (s Semaphore) Release() { | |||
47 | } | 48 | } |
48 | } | 49 | } |
49 | 50 | ||
50 | // resourceProvider returns the provider name for the given type. | 51 | func resourceProvider(resourceType, explicitProvider string) string { |
51 | func resourceProvider(t, alias string) string { | 52 | return config.ResourceProviderFullName(resourceType, explicitProvider) |
52 | if alias != "" { | ||
53 | return alias | ||
54 | } | ||
55 | |||
56 | idx := strings.IndexRune(t, '_') | ||
57 | if idx == -1 { | ||
58 | // If no underscores, the resource name is assumed to be | ||
59 | // also the provider name, e.g. if the provider exposes | ||
60 | // only a single resource of each type. | ||
61 | return t | ||
62 | } | ||
63 | |||
64 | return t[:idx] | ||
65 | } | 53 | } |
66 | 54 | ||
67 | // strSliceContains checks if a given string is contained in a slice | 55 | // strSliceContains checks if a given string is contained in a slice |
diff --git a/vendor/github.com/hashicorp/terraform/terraform/version.go b/vendor/github.com/hashicorp/terraform/terraform/version.go index cdfb8fb..d61b11e 100644 --- a/vendor/github.com/hashicorp/terraform/terraform/version.go +++ b/vendor/github.com/hashicorp/terraform/terraform/version.go | |||
@@ -7,12 +7,12 @@ import ( | |||
7 | ) | 7 | ) |
8 | 8 | ||
9 | // The main version number that is being run at the moment. | 9 | // The main version number that is being run at the moment. |
10 | const Version = "0.9.8" | 10 | const Version = "0.10.0" |
11 | 11 | ||
12 | // A pre-release marker for the version. If this is "" (empty string) | 12 | // A pre-release marker for the version. If this is "" (empty string) |
13 | // then it means that it is a final release. Otherwise, this is a pre-release | 13 | // then it means that it is a final release. Otherwise, this is a pre-release |
14 | // such as "dev" (in development), "beta", "rc1", etc. | 14 | // such as "dev" (in development), "beta", "rc1", etc. |
15 | var VersionPrerelease = "" | 15 | var VersionPrerelease = "dev" |
16 | 16 | ||
17 | // SemVersion is an instance of version.Version. This has the secondary | 17 | // SemVersion is an instance of version.Version. This has the secondary |
18 | // benefit of verifying during tests and init time that our version is a | 18 | // benefit of verifying during tests and init time that our version is a |