diff --git a/internal/cloud/backend.go b/internal/cloud/backend.go index 91c3f6976..bd71d23ba 100644 --- a/internal/cloud/backend.go +++ b/internal/cloud/backend.go @@ -198,19 +198,9 @@ func (b *Cloud) Configure(obj cty.Value) tfdiags.Diagnostics { } // Discover the service URL to confirm that it provides the Terraform Cloud/Enterprise API - // and to get the version constraints. - service, constraints, err := b.discover() + service, err := b.discover() - // First check any contraints we might have received. - if constraints != nil { - diags = diags.Append(b.checkConstraints(constraints)) - if diags.HasErrors() { - return diags - } - } - - // When we don't have any constraints errors, also check for discovery - // errors before we continue. + // Check for errors before we continue. if err != nil { diags = diags.Append(tfdiags.AttributeValue( tfdiags.Error, @@ -358,7 +348,7 @@ func (b *Cloud) setConfigurationFields(obj cty.Value) tfdiags.Diagnostics { } // discover the TFC/E API service URL and version constraints. -func (b *Cloud) discover() (*url.URL, *disco.Constraints, error) { +func (b *Cloud) discover() (*url.URL, error) { serviceID := tfeServiceID if b.forceLocal { serviceID = stateServiceID @@ -366,124 +356,21 @@ func (b *Cloud) discover() (*url.URL, *disco.Constraints, error) { hostname, err := svchost.ForComparison(b.hostname) if err != nil { - return nil, nil, err + return nil, err } host, err := b.services.Discover(hostname) if err != nil { - return nil, nil, err + return nil, err } service, err := host.ServiceURL(serviceID) // Return the error, unless its a disco.ErrVersionNotSupported error. if _, ok := err.(*disco.ErrVersionNotSupported); !ok && err != nil { - return nil, nil, err + return nil, err } - // We purposefully ignore the error and return the previous error, as - // checking for version constraints is considered optional. - constraints, _ := host.VersionConstraints(serviceID, "terraform") - - return service, constraints, err -} - -// checkConstraints checks service version constrains against our own -// version and returns rich and informational diagnostics in case any -// incompatibilities are detected. -func (b *Cloud) checkConstraints(c *disco.Constraints) tfdiags.Diagnostics { - var diags tfdiags.Diagnostics - - if c == nil || c.Minimum == "" || c.Maximum == "" { - return diags - } - - // Generate a parsable constraints string. - excluding := "" - if len(c.Excluding) > 0 { - excluding = fmt.Sprintf(", != %s", strings.Join(c.Excluding, ", != ")) - } - constStr := fmt.Sprintf(">= %s%s, <= %s", c.Minimum, excluding, c.Maximum) - - // Create the constraints to check against. - constraints, err := version.NewConstraint(constStr) - if err != nil { - return diags.Append(checkConstraintsWarning(err)) - } - - // Create the version to check. - v, err := version.NewVersion(tfversion.Version) - if err != nil { - return diags.Append(checkConstraintsWarning(err)) - } - - // Return if we satisfy all constraints. - if constraints.Check(v) { - return diags - } - - // Find out what action (upgrade/downgrade) we should advice. - minimum, err := version.NewVersion(c.Minimum) - if err != nil { - return diags.Append(checkConstraintsWarning(err)) - } - - maximum, err := version.NewVersion(c.Maximum) - if err != nil { - return diags.Append(checkConstraintsWarning(err)) - } - - var excludes []*version.Version - for _, exclude := range c.Excluding { - v, err := version.NewVersion(exclude) - if err != nil { - return diags.Append(checkConstraintsWarning(err)) - } - excludes = append(excludes, v) - } - - // Sort all the excludes. - sort.Sort(version.Collection(excludes)) - - var action, toVersion string - switch { - case minimum.GreaterThan(v): - action = "upgrade" - toVersion = ">= " + minimum.String() - case maximum.LessThan(v): - action = "downgrade" - toVersion = "<= " + maximum.String() - case len(excludes) > 0: - // Get the latest excluded version. - action = "upgrade" - toVersion = "> " + excludes[len(excludes)-1].String() - } - - switch { - case len(excludes) == 1: - excluding = fmt.Sprintf(", excluding version %s", excludes[0].String()) - case len(excludes) > 1: - var vs []string - for _, v := range excludes { - vs = append(vs, v.String()) - } - excluding = fmt.Sprintf(", excluding versions %s", strings.Join(vs, ", ")) - default: - excluding = "" - } - - summary := fmt.Sprintf("Incompatible Terraform version v%s", v.String()) - details := fmt.Sprintf( - "The configured Terraform Enterprise backend is compatible with Terraform "+ - "versions >= %s, <= %s%s.", c.Minimum, c.Maximum, excluding, - ) - - if action != "" && toVersion != "" { - summary = fmt.Sprintf("Please %s Terraform to %s", action, toVersion) - details += fmt.Sprintf(" Please %s to a supported version and try again.", action) - } - - // Return the customized and informational error message. - return diags.Append(tfdiags.Sourceless(tfdiags.Error, summary, details)) + return service, err } // token returns the token for this host as configured in the credentials @@ -1063,15 +950,6 @@ func generalError(msg string, err error) error { } } -func checkConstraintsWarning(err error) tfdiags.Diagnostic { - return tfdiags.Sourceless( - tfdiags.Warning, - fmt.Sprintf("Failed to check version constraints: %v", err), - "Checking version constraints is considered optional, but this is an"+ - "unexpected error which should be reported.", - ) -} - // The newline in this error is to make it look good in the CLI! const initialRetryError = ` [reset][yellow]There was an error connecting to Terraform Cloud. Please do not exit diff --git a/internal/cloud/backend_test.go b/internal/cloud/backend_test.go index 4c3546ec5..f6d8ca14b 100644 --- a/internal/cloud/backend_test.go +++ b/internal/cloud/backend_test.go @@ -10,7 +10,6 @@ import ( tfe "github.com/hashicorp/go-tfe" version "github.com/hashicorp/go-version" - "github.com/hashicorp/terraform-svchost/disco" "github.com/hashicorp/terraform/internal/backend" "github.com/hashicorp/terraform/internal/tfdiags" tfversion "github.com/hashicorp/terraform/version" @@ -492,87 +491,6 @@ func TestCloud_setConfigurationFields(t *testing.T) { } } -func TestCloud_versionConstraints(t *testing.T) { - cases := map[string]struct { - config cty.Value - prerelease string - version string - result string - }{ - "compatible version": { - config: cty.ObjectVal(map[string]cty.Value{ - "hostname": cty.NullVal(cty.String), - "organization": cty.StringVal("hashicorp"), - "token": cty.NullVal(cty.String), - "workspaces": cty.ObjectVal(map[string]cty.Value{ - "name": cty.StringVal("prod"), - "prefix": cty.NullVal(cty.String), - "tags": cty.NullVal(cty.Set(cty.String)), - }), - }), - version: "0.11.1", - }, - "version too old": { - config: cty.ObjectVal(map[string]cty.Value{ - "hostname": cty.NullVal(cty.String), - "organization": cty.StringVal("hashicorp"), - "token": cty.NullVal(cty.String), - "workspaces": cty.ObjectVal(map[string]cty.Value{ - "name": cty.StringVal("prod"), - "prefix": cty.NullVal(cty.String), - "tags": cty.NullVal(cty.Set(cty.String)), - }), - }), - version: "0.0.1", - result: "upgrade Terraform to >= 0.1.0", - }, - "version too new": { - config: cty.ObjectVal(map[string]cty.Value{ - "hostname": cty.NullVal(cty.String), - "organization": cty.StringVal("hashicorp"), - "token": cty.NullVal(cty.String), - "workspaces": cty.ObjectVal(map[string]cty.Value{ - "name": cty.StringVal("prod"), - "prefix": cty.NullVal(cty.String), - "tags": cty.NullVal(cty.Set(cty.String)), - }), - }), - version: "10.0.1", - result: "downgrade Terraform to <= 10.0.0", - }, - } - - // Save and restore the actual version. - p := tfversion.Prerelease - v := tfversion.Version - defer func() { - tfversion.Prerelease = p - tfversion.Version = v - }() - - for name, tc := range cases { - s := testServer(t) - b := New(testDisco(s)) - - // Set the version for this test. - tfversion.Prerelease = tc.prerelease - tfversion.Version = tc.version - - // Validate - _, valDiags := b.PrepareConfig(tc.config) - if valDiags.HasErrors() { - t.Fatalf("%s: unexpected validation result: %v", name, valDiags.Err()) - } - - // Configure - confDiags := b.Configure(tc.config) - if (confDiags.Err() != nil || tc.result != "") && - (confDiags.Err() == nil || !strings.Contains(confDiags.Err().Error(), tc.result)) { - t.Fatalf("%s: unexpected configure result: %v", name, confDiags.Err()) - } - } -} - func TestCloud_localBackend(t *testing.T) { b, bCleanup := testBackendWithName(t) defer bCleanup() @@ -682,108 +600,6 @@ func TestCloud_addAndRemoveWorkspacesWithPrefix(t *testing.T) { } } -func TestCloud_checkConstraints(t *testing.T) { - b, bCleanup := testBackendWithName(t) - defer bCleanup() - - cases := map[string]struct { - constraints *disco.Constraints - prerelease string - version string - result string - }{ - "compatible version": { - constraints: &disco.Constraints{ - Minimum: "0.11.0", - Maximum: "0.11.11", - }, - version: "0.11.1", - result: "", - }, - "version too old": { - constraints: &disco.Constraints{ - Minimum: "0.11.0", - Maximum: "0.11.11", - }, - version: "0.10.1", - result: "upgrade Terraform to >= 0.11.0", - }, - "version too new": { - constraints: &disco.Constraints{ - Minimum: "0.11.0", - Maximum: "0.11.11", - }, - version: "0.12.0", - result: "downgrade Terraform to <= 0.11.11", - }, - "version excluded - ordered": { - constraints: &disco.Constraints{ - Minimum: "0.11.0", - Excluding: []string{"0.11.7", "0.11.8"}, - Maximum: "0.11.11", - }, - version: "0.11.7", - result: "upgrade Terraform to > 0.11.8", - }, - "version excluded - unordered": { - constraints: &disco.Constraints{ - Minimum: "0.11.0", - Excluding: []string{"0.11.8", "0.11.6"}, - Maximum: "0.11.11", - }, - version: "0.11.6", - result: "upgrade Terraform to > 0.11.8", - }, - "list versions": { - constraints: &disco.Constraints{ - Minimum: "0.11.0", - Maximum: "0.11.11", - }, - version: "0.10.1", - result: "versions >= 0.11.0, <= 0.11.11.", - }, - "list exclusion": { - constraints: &disco.Constraints{ - Minimum: "0.11.0", - Excluding: []string{"0.11.6"}, - Maximum: "0.11.11", - }, - version: "0.11.6", - result: "excluding version 0.11.6.", - }, - "list exclusions": { - constraints: &disco.Constraints{ - Minimum: "0.11.0", - Excluding: []string{"0.11.8", "0.11.6"}, - Maximum: "0.11.11", - }, - version: "0.11.6", - result: "excluding versions 0.11.6, 0.11.8.", - }, - } - - // Save and restore the actual version. - p := tfversion.Prerelease - v := tfversion.Version - defer func() { - tfversion.Prerelease = p - tfversion.Version = v - }() - - for name, tc := range cases { - // Set the version for this test. - tfversion.Prerelease = tc.prerelease - tfversion.Version = tc.version - - // Check the constraints. - diags := b.checkConstraints(tc.constraints) - if (diags.Err() != nil || tc.result != "") && - (diags.Err() == nil || !strings.Contains(diags.Err().Error(), tc.result)) { - t.Fatalf("%s: unexpected constraints result: %v", name, diags.Err()) - } - } -} - func TestCloud_StateMgr_versionCheck(t *testing.T) { b, bCleanup := testBackendWithName(t) defer bCleanup()