Skip to content

Commit 5af1e62

Browse files
main: Honor explicit provider_installation CLI config when present
If the CLI configuration contains a provider_installation block then we'll use the source configuration it describes instead of the implied one we'd build otherwise.
1 parent c5bd783 commit 5af1e62

2 files changed

Lines changed: 104 additions & 7 deletions

File tree

‎main.go‎

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -127,6 +127,7 @@ func wrappedMain() int {
127127
log.Printf("[INFO] CLI args: %#v", os.Args)
128128

129129
config, diags := cliconfig.LoadConfig()
130+
130131
if len(diags) > 0 {
131132
// Since we haven't instantiated a command.Meta yet, we need to do
132133
// some things manually here and use some "safe" defaults for things
@@ -168,7 +169,22 @@ func wrappedMain() int {
168169
// direct from a registry. In future there should be a mechanism to
169170
// configure providers sources from the CLI config, which will then
170171
// change how we construct this object.
171-
providerSrc := providerSource(services)
172+
providerSrc, diags := providerSource(config.ProviderInstallation, services)
173+
if len(diags) > 0 {
174+
Ui.Error("There are some problems with the provider_installation configuration:")
175+
for _, diag := range diags {
176+
earlyColor := &colorstring.Colorize{
177+
Colors: colorstring.DefaultColors,
178+
Disable: true, // Disable color to be conservative until we know better
179+
Reset: true,
180+
}
181+
Ui.Error(format.Diagnostic(diag, nil, earlyColor, 78))
182+
}
183+
if diags.HasErrors() {
184+
Ui.Error("As a result of the above problems, Terraform's provider installer may not behave as intended.\n\n")
185+
// We continue to run anyway, because most commands don't do provider installation.
186+
}
187+
}
172188

173189
// Initialize the backends.
174190
backendInit.Init(services)

‎provider_source.go‎

Lines changed: 87 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,28 +1,76 @@
11
package main
22

33
import (
4+
"fmt"
45
"log"
56
"os"
67
"path/filepath"
78

89
"github.com/apparentlymart/go-userdirs/userdirs"
10+
svchost "github.com/hashicorp/terraform-svchost"
911
"github.com/hashicorp/terraform-svchost/disco"
1012

1113
"github.com/hashicorp/terraform/addrs"
1214
"github.com/hashicorp/terraform/command/cliconfig"
1315
"github.com/hashicorp/terraform/internal/getproviders"
16+
"github.com/hashicorp/terraform/tfdiags"
1417
)
1518

1619
// providerSource constructs a provider source based on a combination of the
1720
// CLI configuration and some default search locations. This will be the
1821
// provider source used for provider installation in the "terraform init"
1922
// command, unless overridden by the special -plugin-dir option.
20-
func providerSource(services *disco.Disco) getproviders.Source {
21-
// We're not yet using the CLI config here because we've not implemented
22-
// yet the new configuration constructs to customize provider search
23-
// locations. That'll come later. For now, we just always use the
24-
// implicit default provider source.
25-
return implicitProviderSource(services)
23+
func providerSource(configs []*cliconfig.ProviderInstallation, services *disco.Disco) (getproviders.Source, tfdiags.Diagnostics) {
24+
if len(configs) == 0 {
25+
// If there's no explicit installation configuration then we'll build
26+
// up an implicit one with direct registry installation along with
27+
// some automatically-selected local filesystem mirrors.
28+
return implicitProviderSource(services), nil
29+
}
30+
31+
// There should only be zero or one configurations, which is checked by
32+
// the validation logic in the cliconfig package. Therefore we'll just
33+
// ignore any additional configurations in here.
34+
config := configs[0]
35+
return explicitProviderSource(config, services)
36+
}
37+
38+
func explicitProviderSource(config *cliconfig.ProviderInstallation, services *disco.Disco) (getproviders.Source, tfdiags.Diagnostics) {
39+
var diags tfdiags.Diagnostics
40+
var searchRules []getproviders.MultiSourceSelector
41+
42+
for _, sourceConfig := range config.Sources {
43+
source, moreDiags := providerSourceForCLIConfigLocation(sourceConfig.Location, services)
44+
diags = diags.Append(moreDiags)
45+
if moreDiags.HasErrors() {
46+
continue
47+
}
48+
49+
include, err := getproviders.ParseMultiSourceMatchingPatterns(sourceConfig.Include)
50+
if err != nil {
51+
diags = diags.Append(tfdiags.Sourceless(
52+
tfdiags.Error,
53+
"Invalid provider source inclusion patterns",
54+
fmt.Sprintf("CLI config specifies invalid provider inclusion patterns: %s.", err),
55+
))
56+
}
57+
exclude, err := getproviders.ParseMultiSourceMatchingPatterns(sourceConfig.Include)
58+
if err != nil {
59+
diags = diags.Append(tfdiags.Sourceless(
60+
tfdiags.Error,
61+
"Invalid provider source exclusion patterns",
62+
fmt.Sprintf("CLI config specifies invalid provider exclusion patterns: %s.", err),
63+
))
64+
}
65+
66+
searchRules = append(searchRules, getproviders.MultiSourceSelector{
67+
Source: source,
68+
Include: include,
69+
Exclude: exclude,
70+
})
71+
}
72+
73+
return getproviders.MultiSource(searchRules), diags
2674
}
2775

2876
// implicitProviderSource builds a default provider source to use if there's
@@ -130,3 +178,36 @@ func implicitProviderSource(services *disco.Disco) getproviders.Source {
130178

131179
return getproviders.MultiSource(searchRules)
132180
}
181+
182+
func providerSourceForCLIConfigLocation(loc cliconfig.ProviderInstallationSourceLocation, services *disco.Disco) (getproviders.Source, tfdiags.Diagnostics) {
183+
if loc == cliconfig.ProviderInstallationDirect {
184+
return getproviders.NewMemoizeSource(
185+
getproviders.NewRegistrySource(services),
186+
), nil
187+
}
188+
189+
switch loc := loc.(type) {
190+
191+
case cliconfig.ProviderInstallationFilesystemMirror:
192+
return getproviders.NewFilesystemMirrorSource(string(loc)), nil
193+
194+
case cliconfig.ProviderInstallationNetworkMirror:
195+
host, err := svchost.ForComparison(string(loc))
196+
if err != nil {
197+
var diags tfdiags.Diagnostics
198+
diags = diags.Append(tfdiags.Sourceless(
199+
tfdiags.Error,
200+
"Invalid hostname for provider installation source",
201+
fmt.Sprintf("Cannot parse %q as a hostname for a network provider mirror: %s.", string(loc), err),
202+
))
203+
return nil, diags
204+
}
205+
return getproviders.NewNetworkMirrorSource(host), nil
206+
207+
default:
208+
// We should not get here because the set of cases above should
209+
// be comprehensive for all of the
210+
// cliconfig.ProviderInstallationLocation implementations.
211+
panic(fmt.Sprintf("unexpected provider source location type %T", loc))
212+
}
213+
}

0 commit comments

Comments
 (0)