remove unused code (#26503)

* remove unused code

I've removed the provider-specific code under registry, and unused nil
backend, and replaced a call to helper from backend/oss (the other
callers of that func are provisioners scheduled to be deprecated).

I also removed the Dockerfile, as our build process uses a different
file.

Finally I removed the examples directory, which had outdated examples
and links. There are better, actively maintained examples available.

* command: remove various unused bits

* test wasn't running

* backend: remove unused err
This commit is contained in:
Kristin Laemmert 2020-10-07 11:00:06 -04:00 committed by GitHub
parent 7a7ad23113
commit d2e999ba1f
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
35 changed files with 33 additions and 1421 deletions

View File

@ -1,24 +0,0 @@
# This Dockerfile builds on golang:alpine by building Terraform from source
# using the current working directory.
#
# This produces a docker image that contains a working Terraform binary along
# with all of its source code, which is what gets released on hub.docker.com
# as terraform:full. The main releases (terraform:latest, terraform:light and
# the release tags) are lighter images including only the officially-released
# binary from releases.hashicorp.com; these are built instead from
# scripts/docker-release/Dockerfile-release.
FROM golang:alpine
LABEL maintainer="HashiCorp Terraform Team <terraform@hashicorp.com>"
RUN apk add --no-cache git bash openssh
ENV TF_DEV=true
ENV TF_RELEASE=1
WORKDIR $GOPATH/src/github.com/hashicorp/terraform
COPY . .
RUN /bin/bash scripts/build.sh
WORKDIR $GOPATH
ENTRYPOINT ["terraform"]

View File

@ -34,10 +34,6 @@ var (
ErrDefaultWorkspaceNotSupported = errors.New("default workspace not supported\n" +
"You can create a new workspace with the \"workspace new\" command.")
// ErrOperationNotSupported is returned when an unsupported operation
// is detected by the configured backend.
ErrOperationNotSupported = errors.New("operation not supported")
// ErrWorkspacesNotSupported is an error returned when a caller attempts
// to perform an operation on a workspace other than "default" for a
// backend that doesn't support multiple workspaces.

View File

@ -1,40 +0,0 @@
package backend
import (
"github.com/hashicorp/terraform/configs/configschema"
"github.com/hashicorp/terraform/states/statemgr"
"github.com/hashicorp/terraform/tfdiags"
"github.com/zclconf/go-cty/cty"
)
// Nil is a no-op implementation of Backend.
//
// This is useful to embed within another struct to implement all of the
// backend interface for testing.
type Nil struct{}
func (Nil) ConfigSchema() *configschema.Block {
return &configschema.Block{}
}
func (Nil) PrepareConfig(v cty.Value) (cty.Value, tfdiags.Diagnostics) {
return v, nil
}
func (Nil) Configure(cty.Value) tfdiags.Diagnostics {
return nil
}
func (Nil) StateMgr(string) (statemgr.Full, error) {
// We must return a non-nil manager to adhere to the interface, so
// we'll return an in-memory-only one.
return statemgr.NewFullFake(statemgr.NewTransientInMemory(nil), nil), nil
}
func (Nil) DeleteWorkspace(string) error {
return nil
}
func (Nil) Workspaces() ([]string, error) {
return []string{DefaultStateName}, nil
}

View File

@ -1,9 +0,0 @@
package backend
import (
"testing"
)
func TestNil_impl(t *testing.T) {
var _ Backend = new(Nil)
}

View File

@ -5,33 +5,30 @@ import (
"encoding/json"
"fmt"
"io/ioutil"
"os"
"runtime"
"strings"
"github.com/aliyun/alibaba-cloud-sdk-go/sdk/requests"
"github.com/aliyun/alibaba-cloud-sdk-go/sdk/responses"
"github.com/aliyun/alibaba-cloud-sdk-go/services/sts"
"github.com/aliyun/aliyun-oss-go-sdk/oss"
"github.com/hashicorp/terraform/backend"
"github.com/hashicorp/terraform/helper/schema"
"github.com/hashicorp/terraform/helper/validation"
"github.com/jmespath/go-jmespath"
"log"
"net/http"
"net/url"
"os"
"regexp"
"runtime"
"strconv"
"strings"
"time"
"github.com/aliyun/alibaba-cloud-sdk-go/sdk"
"github.com/aliyun/alibaba-cloud-sdk-go/sdk/auth/credentials"
"github.com/aliyun/alibaba-cloud-sdk-go/sdk/requests"
"github.com/aliyun/alibaba-cloud-sdk-go/sdk/responses"
"github.com/aliyun/alibaba-cloud-sdk-go/services/location"
"github.com/aliyun/alibaba-cloud-sdk-go/services/sts"
"github.com/aliyun/aliyun-oss-go-sdk/oss"
"github.com/aliyun/aliyun-tablestore-go-sdk/tablestore"
"github.com/hashicorp/go-cleanhttp"
"github.com/hashicorp/terraform/backend"
"github.com/hashicorp/terraform/helper/schema"
"github.com/hashicorp/terraform/version"
"github.com/jmespath/go-jmespath"
"github.com/mitchellh/go-homedir"
"net/url"
"regexp"
)
// New creates a new backend for OSS remote state.
@ -196,10 +193,23 @@ func assumeRoleSchema() *schema.Schema {
Description: "The permissions applied when assuming a role. You cannot use this policy to grant permissions which exceed those of the role that is being assumed.",
},
"session_expiration": {
Type: schema.TypeInt,
Optional: true,
Description: "The time after which the established session for assuming role expires.",
ValidateFunc: validation.IntBetween(900, 3600),
Type: schema.TypeInt,
Optional: true,
Description: "The time after which the established session for assuming role expires.",
ValidateFunc: func(v interface{}, k string) ([]string, []error) {
min := 900
max := 3600
value, ok := v.(int)
if !ok {
return nil, []error{fmt.Errorf("expected type of %s to be int", k)}
}
if value < min || value > max {
return nil, []error{fmt.Errorf("expected %s to be in the range (%d - %d), got %d", k, min, max, v)}
}
return nil, nil
},
},
},
},

View File

@ -427,9 +427,8 @@ func (c *InitCommand) getProviders(config *configs.Config, state *states.State,
if moreDiags.HasErrors() {
return false, true, diags
}
stateReqs := make(getproviders.Requirements, 0)
if state != nil {
stateReqs = state.ProviderRequirements()
stateReqs := state.ProviderRequirements()
reqs = reqs.Merge(stateReqs)
}
@ -774,16 +773,6 @@ func (c *InitCommand) getProviders(config *configs.Config, state *states.State,
return true, false, diags
}
func (c *InitCommand) populateProviderToReqs(reqs map[addrs.Provider][]*configs.ModuleRequirements, node *configs.ModuleRequirements) {
for fqn := range node.Requirements {
reqs[fqn] = append(reqs[fqn], node)
}
for _, child := range node.Children {
c.populateProviderToReqs(reqs, child)
}
}
// backendConfigOverrideBody interprets the raw values of -backend-config
// arguments into a hcl Body that should override the backend settings given
// in the configuration.
@ -1030,117 +1019,6 @@ changes, we recommend adding version constraints in a required_providers block
in your configuration, with the constraint strings suggested below.
`
const errDiscoveryServiceUnreachable = `
[reset][bold][red]Registry service unreachable.[reset][red]
This may indicate a network issue, or an issue with the requested Terraform Registry.
`
const errProviderNotFound = `
[reset][bold][red]Provider %[1]q not available for installation.[reset][red]
A provider named %[1]q could not be found in the Terraform Registry.
This may result from mistyping the provider name, or the given provider may
be a third-party provider that cannot be installed automatically.
In the latter case, the plugin must be installed manually by locating and
downloading a suitable distribution package and placing the plugin's executable
file in the following directory:
%[2]s
Terraform detects necessary plugins by inspecting the configuration and state.
To view the provider versions requested by each module, run
"terraform providers".
`
const errProviderVersionsUnsuitable = `
[reset][bold][red]No provider %[1]q plugins meet the constraint %[2]q.[reset][red]
The version constraint is derived from the "version" argument within the
provider %[1]q block in configuration. Child modules may also apply
provider version constraints. To view the provider versions requested by each
module in the current configuration, run "terraform providers".
To proceed, the version constraints for this provider must be relaxed by
either adjusting or removing the "version" argument in the provider blocks
throughout the configuration.
`
const errProviderIncompatible = `
[reset][bold][red]No available provider %[1]q plugins are compatible with this Terraform version.[reset][red]
From time to time, new Terraform major releases can change the requirements for
plugins such that older plugins become incompatible.
Terraform checked all of the plugin versions matching the given constraint:
%[2]s
Unfortunately, none of the suitable versions are compatible with this version
of Terraform. If you have recently upgraded Terraform, it may be necessary to
move to a newer major release of this provider. Alternatively, if you are
attempting to upgrade the provider to a new major version you may need to
also upgrade Terraform to support the new version.
Consult the documentation for this provider for more information on
compatibility between provider versions and Terraform versions.
`
const errProviderInstallError = `
[reset][bold][red]Error installing provider %[1]q: %[2]s.[reset][red]
Terraform analyses the configuration and state and automatically downloads
plugins for the providers used. However, when attempting to download this
plugin an unexpected error occurred.
This may be caused if for some reason Terraform is unable to reach the
plugin repository. The repository may be unreachable if access is blocked
by a firewall.
If automatic installation is not possible or desirable in your environment,
you may alternatively manually install plugins by downloading a suitable
distribution package and placing the plugin's executable file in the
following directory:
%[3]s
`
const errMissingProvidersNoInstall = `
[reset][bold][red]Missing required providers.[reset][red]
The following provider constraints are not met by the currently-installed
provider plugins:
%[1]s
Terraform can automatically download and install plugins to meet the given
constraints, but this step was skipped due to the use of -get-plugins=false
and/or -plugin-dir on the command line.
If automatic installation is not possible or desirable in your environment,
you may manually install plugins by downloading a suitable distribution package
and placing the plugin's executable file in one of the directories given in
by -plugin-dir on the command line, or in the following directory if custom
plugin directories are not set:
%[2]s
`
const errChecksumVerification = `
[reset][bold][red]Error verifying checksum for provider %[1]q[reset][red]
The checksum for provider distribution from the Terraform Registry
did not match the source. This may mean that the distributed files
were changed after this version was released to the Registry.
`
const errSignatureVerification = `
[reset][bold][red]Error:[reset][bold] Untrusted signing key for provider %[1]q[reset]
This provider package is not signed with the HashiCorp signing key, and is
therefore incompatible with Terraform v%[2]s.
A later version of Terraform may have introduced other signing keys that would
accept this provider. Alternatively, an earlier version of this provider may
be compatible with Terraform v%[2]s.
`
// providerProtocolTooOld is a message sent to the CLI UI if the provider's
// supported protocol versions are too old for the user's version of terraform,
// but a newer version of the provider is compatible.
@ -1171,20 +1049,3 @@ Alternatively, upgrade to the latest version of Terraform for compatibility with
// No version of the provider is compatible.
const errProviderVersionIncompatible = `No compatible versions of provider %s were found.`
// Logic from internal/initwd/getter.go
var localSourcePrefixes = []string{
"./",
"../",
".\\",
"..\\",
}
func isLocalSourceAddr(addr string) bool {
for _, prefix := range localSourcePrefixes {
if strings.HasPrefix(addr, prefix) {
return true
}
}
return false
}

View File

@ -316,20 +316,6 @@ func (m *Meta) backendCLIOpts() (*backend.CLIOpts, error) {
}, nil
}
// IsLocalBackend returns true if the backend is a local backend. We use this
// for some checks that require a remote backend.
func (m *Meta) IsLocalBackend(b backend.Backend) bool {
// Is it a local backend?
bLocal, ok := b.(*backendLocal.Local)
// If it is, does it not have an alternate state backend?
if ok {
ok = bLocal.Backend == nil
}
return ok
}
// Operation initializes a new backend.Operation struct.
//
// This prepares the operation. After calling this, the caller is expected
@ -728,36 +714,6 @@ func (m *Meta) backend_c_r_S(c *configs.Backend, cHash int, sMgr *clistate.Local
return nil, diags
}
// Legacy remote state
func (m *Meta) backend_c_R_s(c *configs.Backend, sMgr *clistate.LocalState) (backend.Backend, tfdiags.Diagnostics) {
var diags tfdiags.Diagnostics
m.Ui.Error(strings.TrimSpace(errBackendLegacy) + "\n")
diags = diags.Append(fmt.Errorf("Cannot initialize legacy remote state"))
return nil, diags
}
// Unsetting backend, saved backend, legacy remote state
func (m *Meta) backend_c_R_S(c *configs.Backend, cHash int, sMgr *clistate.LocalState) (backend.Backend, tfdiags.Diagnostics) {
var diags tfdiags.Diagnostics
m.Ui.Error(strings.TrimSpace(errBackendLegacy) + "\n")
diags = diags.Append(fmt.Errorf("Cannot initialize legacy remote state"))
return nil, diags
}
// Configuring a backend for the first time with legacy remote state.
func (m *Meta) backend_C_R_s(c *configs.Backend, sMgr *clistate.LocalState) (backend.Backend, tfdiags.Diagnostics) {
var diags tfdiags.Diagnostics
m.Ui.Error(strings.TrimSpace(errBackendLegacy) + "\n")
diags = diags.Append(fmt.Errorf("Cannot initialize legacy remote state"))
return nil, diags
}
// Configuring a backend for the first time.
func (m *Meta) backend_C_r_s(c *configs.Backend, cHash int, sMgr *clistate.LocalState) (backend.Backend, tfdiags.Diagnostics) {
// Get the backend
@ -1025,26 +981,6 @@ func (m *Meta) backend_C_r_S_unchanged(c *configs.Backend, cHash int, sMgr *clis
return b, diags
}
// Initiailizing a changed saved backend with legacy remote state.
func (m *Meta) backend_C_R_S_changed(c *configs.Backend, sMgr *clistate.LocalState) (backend.Backend, tfdiags.Diagnostics) {
var diags tfdiags.Diagnostics
m.Ui.Error(strings.TrimSpace(errBackendLegacy) + "\n")
diags = diags.Append(fmt.Errorf("Cannot initialize legacy remote state"))
return nil, diags
}
// Initiailizing an unchanged saved backend with legacy remote state.
func (m *Meta) backend_C_R_S_unchanged(c *configs.Backend, sMgr *clistate.LocalState, output bool) (backend.Backend, tfdiags.Diagnostics) {
var diags tfdiags.Diagnostics
m.Ui.Error(strings.TrimSpace(errBackendLegacy) + "\n")
diags = diags.Append(fmt.Errorf("Cannot initialize legacy remote state"))
return nil, diags
}
//-------------------------------------------------------------------
// Reusable helper functions for backend management
//-------------------------------------------------------------------
@ -1150,36 +1086,6 @@ func (m *Meta) backendInitFromConfig(c *configs.Backend) (backend.Backend, cty.V
return b, configVal, diags
}
func (m *Meta) backendInitFromSaved(s *terraform.BackendState) (backend.Backend, tfdiags.Diagnostics) {
var diags tfdiags.Diagnostics
// Get the backend
f := backendInit.Backend(s.Type)
if f == nil {
diags = diags.Append(fmt.Errorf(strings.TrimSpace(errBackendSavedUnknown), s.Type))
return nil, diags
}
b := f()
schema := b.ConfigSchema()
configVal, err := s.Config(schema)
if err != nil {
diags = diags.Append(errwrap.Wrapf("saved backend configuration is invalid: {{err}}", err))
return nil, diags
}
newVal, validateDiags := b.PrepareConfig(configVal)
diags = diags.Append(validateDiags)
if validateDiags.HasErrors() {
return nil, diags
}
configureDiags := b.Configure(newVal)
diags = diags.Append(configureDiags)
return b, diags
}
func (m *Meta) backendInitRequired(reason string) {
m.Ui.Output(m.Colorize().Color(fmt.Sprintf(
"[reset]"+strings.TrimSpace(errBackendInit)+"\n", reason)))
@ -1194,30 +1100,6 @@ func (m *Meta) backendInitRequired(reason string) {
var errBackendInitRequired = errors.New(
"Initialization required. Please see the error message above.")
const errBackendLegacyConfig = `
One or more errors occurred while configuring the legacy remote state.
If fixing these errors requires changing your remote state configuration,
you must switch your configuration to the new remote backend configuration.
You can learn more about remote backends at the URL below:
https://www.terraform.io/docs/backends/index.html
The error(s) configuring the legacy remote state:
%s
`
const errBackendLegacyUnknown = `
The legacy remote state type %q could not be found.
Terraform 0.9.0 shipped with backwards compatibility for all built-in
legacy remote state types. This error may mean that you were using a
custom Terraform build that perhaps supported a different type of
remote state.
Please check with the creator of the remote state above and try again.
`
const errBackendLocalRead = `
Error reading local state: %s
@ -1237,29 +1119,6 @@ with a backend, we must delete the local state file. Please resolve the
issue above and retry the command.
`
const errBackendMigrateNew = `
Error migrating local state to backend: %s
Your local state remains intact and unmodified. Please resolve the error
above and try again.
`
const errBackendNewConfig = `
Error configuring the backend %q: %s
Please update the configuration in your Terraform files to fix this error
then run this command again.
`
const errBackendNewRead = `
Error reading newly configured backend state: %s
Terraform is trying to read the state from your newly configured backend
to determine the copy process for your existing state. Backends are expected
to not error even if there is no state yet written. Please resolve the
error above and try again.
`
const errBackendNewUnknown = `
The backend %q could not be found.
@ -1280,34 +1139,6 @@ If the backend already contains existing workspaces, you may need to update
the backend configuration.
`
const errBackendRemoteRead = `
Error reading backend state: %s
Terraform is trying to read the state from your configured backend to
determine if there is any migration steps necessary. Terraform can't continue
without this check because that would risk losing state. Please resolve the
error above and try again.
`
const errBackendSavedConfig = `
Error configuring the backend %q: %s
Please update the configuration in your Terraform files to fix this error.
If you'd like to update the configuration interactively without storing
the values in your configuration, run "terraform init".
`
const errBackendSavedUnsetConfig = `
Error configuring the existing backend %q: %s
Terraform must configure the existing backend in order to copy the state
from the existing backend, as requested. Please resolve the error and try
again. If you choose to not copy the existing state, Terraform will not
configure the backend. If the configuration is invalid, please update your
Terraform configuration with proper configuration for this backend first
before unsetting the backend.
`
const errBackendSavedUnknown = `
The backend %q could not be found.
@ -1321,14 +1152,6 @@ If you'd like to force remove this backend, you must update your configuration
to not use the backend and run "terraform init" (or any other command) again.
`
const errBackendClearLegacy = `
Error clearing the legacy remote state configuration: %s
Terraform completed configuring your backend. It is now safe to remove
the legacy remote state configuration, but an error occurred while trying
to do so. Please look at the error above, resolve it, and try again.
`
const errBackendClearSaved = `
Error clearing the backend configuration: %s
@ -1365,72 +1188,14 @@ are usually due to simple file permission errors. Please look at the error
above, resolve it, and try again.
`
const errBackendPlanBoth = `
The plan file contained both a legacy remote state and backend configuration.
This is not allowed. Please recreate the plan file with the latest version of
Terraform.
`
const errBackendPlanLineageDiff = `
The plan file contains a state with a differing lineage than the current
state. By continuing, your current state would be overwritten by the state
in the plan. Please either update the plan with the latest state or delete
your current state and try again.
"Lineage" is a unique identifier generated only once on the creation of
a new, empty state. If these values differ, it means they were created new
at different times. Therefore, Terraform must assume that they're completely
different states.
The most common cause of seeing this error is using a plan that was
created against a different state. Perhaps the plan is very old and the
state has since been recreated, or perhaps the plan was against a completely
different infrastructure.
`
const errBackendPlanStateFlag = `
The -state and -state-out flags cannot be set with a plan that has a remote
state. The plan itself contains the configuration for the remote backend to
store state. The state will be written there for consistency.
If you wish to change this behavior, please create a plan from local state.
You may use the state flags with plans from local state to affect where
the final state is written.
`
const errBackendPlanOlder = `
This plan was created against an older state than is current. Please create
a new plan file against the latest state and try again.
Terraform doesn't allow you to run plans that were created from older
states since it doesn't properly represent the latest changes Terraform
may have made, and can result in unsafe behavior.
Plan Serial: %[1]d
Current Serial: %[2]d
`
const outputBackendMigrateChange = `
Terraform detected that the backend type changed from %q to %q.
`
const outputBackendMigrateLegacy = `
Terraform detected legacy remote state.
`
const outputBackendMigrateLocal = `
Terraform has detected you're unconfiguring your previously set %q backend.
`
const outputBackendConfigureWithLegacy = `
[reset][bold]New backend configuration detected with legacy remote state![reset]
Terraform has detected that you're attempting to configure a new backend.
At the same time, legacy remote state configuration was found. Terraform will
first configure the new backend, and then ask if you'd like to migrate
your remote state to the new backend.
`
const outputBackendReconfigure = `
[reset][bold]Backend configuration changed![reset]
@ -1438,45 +1203,6 @@ Terraform has detected that the configuration specified for the backend
has changed. Terraform will now check for existing state in the backends.
`
const outputBackendSavedWithLegacy = `
[reset][bold]Legacy remote state was detected![reset]
Terraform has detected you still have legacy remote state enabled while
also having a backend configured. Terraform will now ask if you want to
migrate your legacy remote state data to the configured backend.
`
const outputBackendSavedWithLegacyChanged = `
[reset][bold]Legacy remote state was detected while also changing your current backend!reset]
Terraform has detected that you have legacy remote state, a configured
current backend, and you're attempting to reconfigure your backend. To handle
all of these changes, Terraform will first reconfigure your backend. After
this, Terraform will handle optionally copying your legacy remote state
into the newly configured backend.
`
const outputBackendUnsetWithLegacy = `
[reset][bold]Detected a request to unset the backend with legacy remote state present![reset]
Terraform has detected that you're attempting to unset a previously configured
backend (by not having the "backend" configuration set in your Terraform files).
At the same time, legacy remote state was detected. To handle this complex
scenario, Terraform will first unset your configured backend, and then
ask you how to handle the legacy remote state. This will be multi-step
process.
`
const successBackendLegacyUnset = `
Terraform has successfully migrated from legacy remote state to your
configured backend (%q).
`
const successBackendReconfigureWithLegacy = `
Terraform has successfully reconfigured your backend and migrate
from legacy remote state to the new backend.
`
const successBackendUnset = `
Successfully unset the backend %q. Terraform will now operate locally.
`

View File

@ -68,30 +68,6 @@ func (m *Meta) loadConfig(rootDir string) (*configs.Config, tfdiags.Diagnostics)
return config, diags
}
// loadConfigEarly is a variant of loadConfig that uses the special
// "early config" loader that is more forgiving of unexpected constructs and
// legacy syntax.
//
// Early-loaded config is not registered in the source code cache, so
// diagnostics produced from it may render without source code snippets. In
// practice this is not a big concern because the early config loader also
// cannot generate detailed source locations, so it prefers to produce
// diagnostics without explicit source location information and instead includes
// approximate locations in the message text.
//
// Most callers should use loadConfig. This method exists to support early
// initialization use-cases where the root module must be inspected in order
// to determine what else needs to be installed before the full configuration
// can be used
func (m *Meta) loadConfigEarly(rootDir string) (*earlyconfig.Config, tfdiags.Diagnostics) {
var diags tfdiags.Diagnostics
rootDir = m.normalizePath(rootDir)
config, hclDiags := initwd.LoadConfig(rootDir, m.modulesDir())
diags = diags.Append(hclDiags)
return config, diags
}
// loadSingleModule reads configuration from the given directory and returns
// a description of that module only, without attempting to assemble a module
// tree for referenced child modules.
@ -182,23 +158,6 @@ func (m *Meta) loadBackendConfig(rootDir string) (*configs.Backend, tfdiags.Diag
return mod.Backend, nil
}
// loadValuesFile loads a file that defines a single map of key/value pairs.
// This is the format used for "tfvars" files.
func (m *Meta) loadValuesFile(filename string) (map[string]cty.Value, tfdiags.Diagnostics) {
var diags tfdiags.Diagnostics
filename = m.normalizePath(filename)
loader, err := m.initConfigLoader()
if err != nil {
diags = diags.Append(err)
return nil, diags
}
vals, hclDiags := loader.Parser().LoadValuesFile(filename)
diags = diags.Append(hclDiags)
return vals, diags
}
// loadHCLFile reads an arbitrary HCL file and returns the unprocessed body
// representing its toplevel. Most callers should use one of the more
// specialized "load..." methods to get a higher-level representation.

View File

@ -1,10 +1,8 @@
package command
import (
"bytes"
"encoding/json"
"fmt"
"sort"
"strings"
ctyjson "github.com/zclconf/go-cty/cty/json"
@ -201,119 +199,6 @@ func (c *OutputCommand) Run(args []string) int {
return 0
}
func formatNestedList(indent string, outputList []interface{}) string {
outputBuf := new(bytes.Buffer)
outputBuf.WriteString(fmt.Sprintf("%s[", indent))
lastIdx := len(outputList) - 1
for i, value := range outputList {
outputBuf.WriteString(fmt.Sprintf("\n%s%s%s", indent, " ", value))
if i != lastIdx {
outputBuf.WriteString(",")
}
}
outputBuf.WriteString(fmt.Sprintf("\n%s]", indent))
return strings.TrimPrefix(outputBuf.String(), "\n")
}
func formatListOutput(indent, outputName string, outputList []interface{}) string {
keyIndent := ""
outputBuf := new(bytes.Buffer)
if outputName != "" {
outputBuf.WriteString(fmt.Sprintf("%s%s = [", indent, outputName))
keyIndent = " "
}
lastIdx := len(outputList) - 1
for i, value := range outputList {
switch typedValue := value.(type) {
case string:
outputBuf.WriteString(fmt.Sprintf("\n%s%s%s", indent, keyIndent, value))
case []interface{}:
outputBuf.WriteString(fmt.Sprintf("\n%s%s", indent,
formatNestedList(indent+keyIndent, typedValue)))
case map[string]interface{}:
outputBuf.WriteString(fmt.Sprintf("\n%s%s", indent,
formatNestedMap(indent+keyIndent, typedValue)))
}
if lastIdx != i {
outputBuf.WriteString(",")
}
}
if outputName != "" {
if len(outputList) > 0 {
outputBuf.WriteString(fmt.Sprintf("\n%s]", indent))
} else {
outputBuf.WriteString("]")
}
}
return strings.TrimPrefix(outputBuf.String(), "\n")
}
func formatNestedMap(indent string, outputMap map[string]interface{}) string {
ks := make([]string, 0, len(outputMap))
for k, _ := range outputMap {
ks = append(ks, k)
}
sort.Strings(ks)
outputBuf := new(bytes.Buffer)
outputBuf.WriteString(fmt.Sprintf("%s{", indent))
lastIdx := len(outputMap) - 1
for i, k := range ks {
v := outputMap[k]
outputBuf.WriteString(fmt.Sprintf("\n%s%s = %v", indent+" ", k, v))
if lastIdx != i {
outputBuf.WriteString(",")
}
}
outputBuf.WriteString(fmt.Sprintf("\n%s}", indent))
return strings.TrimPrefix(outputBuf.String(), "\n")
}
func formatMapOutput(indent, outputName string, outputMap map[string]interface{}) string {
ks := make([]string, 0, len(outputMap))
for k, _ := range outputMap {
ks = append(ks, k)
}
sort.Strings(ks)
keyIndent := ""
outputBuf := new(bytes.Buffer)
if outputName != "" {
outputBuf.WriteString(fmt.Sprintf("%s%s = {", indent, outputName))
keyIndent = " "
}
for _, k := range ks {
v := outputMap[k]
outputBuf.WriteString(fmt.Sprintf("\n%s%s%s = %v", indent, keyIndent, k, v))
}
if outputName != "" {
if len(outputMap) > 0 {
outputBuf.WriteString(fmt.Sprintf("\n%s}", indent))
} else {
outputBuf.WriteString("}")
}
}
return strings.TrimPrefix(outputBuf.String(), "\n")
}
func (c *OutputCommand) Help() string {
helpText := `
Usage: terraform output [options] [NAME]

View File

@ -119,17 +119,6 @@ func (m *Meta) pluginDirs(includeAutoInstalled bool) []string {
return dirs
}
func (m *Meta) pluginCache() discovery.PluginCache {
dir := m.PluginCacheDir
if dir == "" {
return nil // cache disabled
}
dir = filepath.Join(dir, pluginMachineName)
return discovery.NewLocalPluginCache(dir)
}
func (m *Meta) provisionerFactories() map[string]terraform.ProvisionerFactory {
dirs := m.pluginDirs(true)
plugins := discovery.FindPlugins("provisioner", dirs)

View File

@ -143,7 +143,7 @@ func (c *ShowCommand) Run(args []string) int {
}
if plan != nil {
if jsonOutput == true {
if jsonOutput {
config := ctx.Config()
jsonPlan, err := jsonplan.Marshal(config, plan, stateFile, schemas)
@ -170,7 +170,7 @@ func (c *ShowCommand) Run(args []string) int {
return 0
}
if jsonOutput == true {
if jsonOutput {
// At this point, it is possible that there is neither state nor a plan.
// That's ok, we'll just return an empty object.
jsonState, err := jsonstate.Marshal(stateFile, schemas)

View File

@ -126,10 +126,6 @@ func (c *StateListCommand) Synopsis() string {
return "List resources in the state"
}
const errStateFilter = `Error filtering state: %[1]s
Please ensure that all your addresses are formatted properly.`
const errStateLoadingState = `Error loading the state: %[1]s
Please ensure that your Terraform state exists and that you've

View File

@ -148,10 +148,6 @@ func (c *StateMeta) lookupResourceInstanceAddr(state *states.State, allowMissing
return ret, diags
}
func (c *StateMeta) lookupSingleResourceInstanceAddr(state *states.State, addrStr string) (addrs.AbsResourceInstance, tfdiags.Diagnostics) {
return addrs.ParseAbsResourceInstanceStr(addrStr)
}
func (c *StateMeta) lookupSingleStateObjectAddr(state *states.State, addrStr string) (addrs.Targetable, tfdiags.Diagnostics) {
target, diags := addrs.ParseTargetStr(addrStr)
if diags.HasErrors() {

View File

@ -503,9 +503,3 @@ const errStateMv = `Error moving state: %s
Please ensure your addresses and state paths are valid. No
state was persisted. Your existing states are untouched.`
const errStateMvPersist = `Error saving the state: %s
The state wasn't saved properly. If the error happening after a partial
write occurred, a backup file will have been created. Otherwise, the state
is in the same state it was when the operation started.`

View File

@ -153,25 +153,3 @@ Options:
func (c *StatePushCommand) Synopsis() string {
return "Update remote state from a local state file"
}
const errStatePushLineage = `
The lineages do not match! The state will not be pushed.
The "lineage" is a unique identifier given to a state on creation. It helps
protect Terraform from overwriting a seemingly unrelated state file since it
represents potentially losing real state.
Please verify you're pushing the correct state. If you're sure you are, you
can force the behavior with the "-force" flag.
`
const errStatePushSerialNewer = `
The destination state has a higher serial number! The state will not be pushed.
A higher serial could indicate that there is data in the destination state
that was not present when the source state was created. As a protection measure,
Terraform will not automatically overwrite this state.
Please verify you're pushing the correct state. If you're sure you are, you
can force the behavior with the "-force" flag.
`

View File

@ -167,12 +167,6 @@ func (c *StateRmCommand) Synopsis() string {
return "Remove instances from the state"
}
const errStateRm = `Error removing items from the state: %s
The state was not saved. No items were removed from the persisted
state. No backup was created since no modification occurred. Please
resolve the issue above and try again.`
const errStateRmPersist = `Error saving the state: %s
The state was not saved. No items were removed from the persisted

View File

@ -17,8 +17,6 @@ type ValidateCommand struct {
Meta
}
const defaultPath = "."
func (c *ValidateCommand) Run(args []string) int {
args = c.Meta.process(args)
// TODO: The `var` and `var-file` options are not actually used, and should

View File

@ -63,8 +63,6 @@ will be removed in a future Terraform version.
}
const (
envNotSupported = `Backend does not support multiple workspaces`
envExists = `Workspace %q already exists`
envDoesNotExist = `

View File

@ -1,27 +0,0 @@
# Terraform Examples
This folder contains a set of Terraform examples. These examples each
have their own README you can read for more details on what the example
does.
To try any example, clone this repository and run the following commands
from within the example's directory:
```shell
$ terraform init
$ terraform apply
```
## Provider-specific Examples
Terraform providers each live in their own repository. Some of these
repositories contain documentation specific to their provider:
* [AliCloud Examples](https://github.com/terraform-providers/terraform-provider-alicloud/tree/master/examples)
* [Amazon Web Services Examples](https://github.com/terraform-providers/terraform-provider-aws/tree/master/examples)
* [Azure Examples](https://github.com/terraform-providers/terraform-provider-azurerm/tree/master/examples)
* [CenturyLink Cloud Examples](https://github.com/terraform-providers/terraform-provider-clc/tree/master/examples)
* [Consul Examples](https://github.com/terraform-providers/terraform-provider-consul/tree/master/examples)
* [DigitalOcean Examples](https://github.com/terraform-providers/terraform-provider-digitalocean/tree/master/examples)
* [Google Cloud Platform Examples](https://github.com/terraform-providers/terraform-provider-google/tree/master/examples)
* [OpenStack Examples](https://github.com/terraform-providers/terraform-provider-openstack/tree/master/examples)

View File

@ -1,11 +0,0 @@
# Cross Provider Examples
This is a simple example of the cross-provider capabilities of
Terraform.
Very simply, this creates a Heroku application and points a DNS
CNAME record at the result via DNSimple. A `host` query to the outputted
hostname should reveal the correct DNS configuration.
As with all examples, just copy and paste the example and run
`terraform apply` to see it work.

View File

@ -1,26 +0,0 @@
# Create our Heroku application. Heroku will
# automatically assign a name.
resource "heroku_app" "web" {}
# Create our DNSimple record to point to the
# heroku application.
resource "dnsimple_record" "web" {
domain = "${var.dnsimple_domain}"
name = "terraform"
# heroku_hostname is a computed attribute on the heroku
# application we can use to determine the hostname
value = "${heroku_app.web.heroku_hostname}"
type = "CNAME"
ttl = 3600
}
# The Heroku domain, which will be created and added
# to the heroku application after we have assigned the domain
# in DNSimple
resource "heroku_domain" "foobar" {
app = "${heroku_app.web.name}"
hostname = "${dnsimple_record.web.hostname}"
}

View File

@ -1,3 +0,0 @@
output "address" {
value = "${dnsimple_record.web.hostname}"
}

View File

@ -1,3 +0,0 @@
variable "dnsimple_domain" {
description = "The domain we are creating a record for."
}

View File

@ -273,121 +273,6 @@ func (c *Client) ModuleLocation(module *regsrc.Module, version string) (string,
return location, nil
}
// TerraformProviderVersions queries the registry for a provider, and returns the available versions.
func (c *Client) TerraformProviderVersions(provider *regsrc.TerraformProvider) (*response.TerraformProviderVersions, error) {
host, err := provider.SvcHost()
if err != nil {
return nil, err
}
service, err := c.Discover(host, providersServiceID)
if err != nil {
return nil, err
}
p, err := url.Parse(path.Join(provider.TerraformProvider(), "versions"))
if err != nil {
return nil, err
}
service = service.ResolveReference(p)
log.Printf("[DEBUG] fetching provider versions from %q", service)
req, err := retryablehttp.NewRequest("GET", service.String(), nil)
if err != nil {
return nil, err
}
c.addRequestCreds(host, req.Request)
req.Header.Set(xTerraformVersion, tfVersion)
resp, err := c.client.Do(req)
if err != nil {
return nil, err
}
defer resp.Body.Close()
switch resp.StatusCode {
case http.StatusOK:
// OK
case http.StatusNotFound:
return nil, &errProviderNotFound{addr: provider}
default:
return nil, fmt.Errorf("error looking up provider versions: %s", resp.Status)
}
var versions response.TerraformProviderVersions
dec := json.NewDecoder(resp.Body)
if err := dec.Decode(&versions); err != nil {
return nil, err
}
return &versions, nil
}
// TerraformProviderLocation queries the registry for a provider download metadata
func (c *Client) TerraformProviderLocation(provider *regsrc.TerraformProvider, version string) (*response.TerraformProviderPlatformLocation, error) {
host, err := provider.SvcHost()
if err != nil {
return nil, err
}
service, err := c.Discover(host, providersServiceID)
if err != nil {
return nil, err
}
p, err := url.Parse(path.Join(
provider.TerraformProvider(),
version,
"download",
provider.OS,
provider.Arch,
))
if err != nil {
return nil, err
}
service = service.ResolveReference(p)
log.Printf("[DEBUG] fetching provider location from %q", service)
req, err := retryablehttp.NewRequest("GET", service.String(), nil)
if err != nil {
return nil, err
}
c.addRequestCreds(host, req.Request)
req.Header.Set(xTerraformVersion, tfVersion)
resp, err := c.client.Do(req)
if err != nil {
return nil, err
}
defer resp.Body.Close()
var loc response.TerraformProviderPlatformLocation
dec := json.NewDecoder(resp.Body)
if err := dec.Decode(&loc); err != nil {
return nil, err
}
switch resp.StatusCode {
case http.StatusOK, http.StatusNoContent:
// OK
case http.StatusNotFound:
return nil, fmt.Errorf("provider %q version %q not found", provider.TerraformProvider(), version)
default:
// anything else is an error:
return nil, fmt.Errorf("error getting download location for %q: %s", provider.TerraformProvider(), resp.Status)
}
return &loc, nil
}
// configureDiscoveryRetry configures the number of retries the registry client
// will attempt for requests with retryable errors, like 502 status codes
func configureDiscoveryRetry() {

View File

@ -2,7 +2,6 @@ package registry
import (
"context"
"fmt"
"net/http"
"os"
"strings"
@ -368,90 +367,3 @@ func TestLookupModuleNetworkError(t *testing.T) {
t.Fatal("unexpected error, got:", err)
}
}
func TestLookupProviderVersions(t *testing.T) {
server := test.Registry()
defer server.Close()
client := NewClient(test.Disco(server), nil)
tests := []struct {
name string
}{
{"foo"},
{"bar"},
}
for _, tt := range tests {
provider := regsrc.NewTerraformProvider(tt.name, "", "")
resp, err := client.TerraformProviderVersions(provider)
if err != nil {
t.Fatal(err)
}
name := fmt.Sprintf("terraform-providers/%s", tt.name)
if resp.ID != name {
t.Fatalf("expected provider name %q, got %q", name, resp.ID)
}
if len(resp.Versions) != 2 {
t.Fatal("expected 2 versions, got", len(resp.Versions))
}
for _, v := range resp.Versions {
_, err := version.NewVersion(v.Version)
if err != nil {
t.Fatalf("invalid version %#v: %v", v, err)
}
}
}
}
func TestLookupProviderLocation(t *testing.T) {
server := test.Registry()
defer server.Close()
client := NewClient(test.Disco(server), nil)
tests := []struct {
Name string
Version string
Err bool
}{
{
"foo",
"0.2.3",
false,
},
{
"bar",
"0.1.1",
false,
},
{
"baz",
"0.0.0",
true,
},
}
for _, tt := range tests {
// FIXME: the tests are set up to succeed - os/arch is not being validated at this time
p := regsrc.NewTerraformProvider(tt.Name, "linux", "amd64")
locationMetadata, err := client.TerraformProviderLocation(p, tt.Version)
if tt.Err {
if err == nil {
t.Fatal("succeeded; want error")
}
return
} else if err != nil {
t.Fatalf("unexpected error: %s", err)
}
downloadURL := fmt.Sprintf("https://releases.hashicorp.com/terraform-provider-%s/%s/terraform-provider-%s.zip", tt.Name, tt.Version, tt.Name)
if locationMetadata.DownloadURL != downloadURL {
t.Fatalf("incorrect download URL: expected %q, got %q", downloadURL, locationMetadata.DownloadURL)
}
}
}

View File

@ -23,22 +23,6 @@ func IsModuleNotFound(err error) bool {
return ok
}
type errProviderNotFound struct {
addr *regsrc.TerraformProvider
}
func (e *errProviderNotFound) Error() string {
return fmt.Sprintf("provider %s not found", e.addr)
}
// IsProviderNotFound returns true only if the given error is a "provider not found"
// error. This allows callers to recognize this particular error condition
// as distinct from operational errors such as poor network connectivity.
func IsProviderNotFound(err error) bool {
_, ok := err.(*errProviderNotFound)
return ok
}
// IsServiceNotProvided returns true only if the given error is a "service not provided"
// error. This allows callers to recognize this particular error condition
// as distinct from operational errors such as poor network connectivity.

View File

@ -1,60 +0,0 @@
package regsrc
import (
"fmt"
"runtime"
"strings"
"github.com/hashicorp/terraform-svchost"
)
var (
// DefaultProviderNamespace represents the namespace for canonical
// HashiCorp-controlled providers.
DefaultProviderNamespace = "-"
)
// TerraformProvider describes a Terraform Registry Provider source.
type TerraformProvider struct {
RawHost *FriendlyHost
RawNamespace string
RawName string
OS string
Arch string
}
// NewTerraformProvider constructs a new provider source.
func NewTerraformProvider(name, os, arch string) *TerraformProvider {
if os == "" {
os = runtime.GOOS
}
if arch == "" {
arch = runtime.GOARCH
}
// separate namespace if included
namespace := DefaultProviderNamespace
if names := strings.SplitN(name, "/", 2); len(names) == 2 {
namespace, name = names[0], names[1]
}
p := &TerraformProvider{
RawHost: PublicRegistryHost,
RawNamespace: namespace,
RawName: name,
OS: os,
Arch: arch,
}
return p
}
// Provider returns just the registry ID of the provider
func (p *TerraformProvider) TerraformProvider() string {
return fmt.Sprintf("%s/%s", p.RawNamespace, p.RawName)
}
// SvcHost returns the svchost.Hostname for this provider. The
// default PublicRegistryHost is returned.
func (p *TerraformProvider) SvcHost() (svchost.Hostname, error) {
return svchost.ForComparison(PublicRegistryHost.Raw)
}

View File

@ -1,48 +0,0 @@
package regsrc
import (
"testing"
)
func TestNewTerraformProviderNamespace(t *testing.T) {
tests := []struct {
name string
provider string
expectedNamespace string
expectedName string
}{
{
name: "default",
provider: "null",
expectedNamespace: "-",
expectedName: "null",
}, {
name: "explicit",
provider: "terraform-providers/null",
expectedNamespace: "terraform-providers",
expectedName: "null",
}, {
name: "community",
provider: "community-providers/null",
expectedNamespace: "community-providers",
expectedName: "null",
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
actual := NewTerraformProvider(tt.provider, "", "")
if actual == nil {
t.Fatal("NewTerraformProvider() unexpectedly returned nil provider")
}
if v := actual.RawNamespace; v != tt.expectedNamespace {
t.Fatalf("RawNamespace = %v, wanted %v", v, tt.expectedNamespace)
}
if v := actual.RawName; v != tt.expectedName {
t.Fatalf("RawName = %v, wanted %v", v, tt.expectedName)
}
})
}
}

View File

@ -1,36 +0,0 @@
package response
import (
"time"
)
// Provider is the response structure with the data for a single provider
// version. This is just the metadata. A full provider response will be
// ProviderDetail.
type Provider struct {
ID string `json:"id"`
//---------------------------------------------------------------
// Metadata about the overall provider.
Owner string `json:"owner"`
Namespace string `json:"namespace"`
Name string `json:"name"`
Version string `json:"version"`
Description string `json:"description"`
Source string `json:"source"`
PublishedAt time.Time `json:"published_at"`
Downloads int `json:"downloads"`
}
// ProviderDetail represents a Provider with full detail.
type ProviderDetail struct {
Provider
//---------------------------------------------------------------
// The fields below are only set when requesting this specific
// module. They are available to easily know all available versions
// without multiple API calls.
Versions []string `json:"versions"` // All versions
}

View File

@ -1,7 +0,0 @@
package response
// ProviderList is the response structure for a pageable list of providers.
type ProviderList struct {
Meta PaginationMeta `json:"meta"`
Providers []*Provider `json:"providers"`
}

View File

@ -1,95 +0,0 @@
package response
import (
"sort"
"strings"
version "github.com/hashicorp/go-version"
)
// TerraformProvider is the response structure for all required information for
// Terraform to choose a download URL. It must include all versions and all
// platforms for Terraform to perform version and os/arch constraint matching
// locally.
type TerraformProvider struct {
ID string `json:"id"`
Versions []*TerraformProviderVersion `json:"versions"`
}
// TerraformProviderVersion is the Terraform-specific response structure for a
// provider version.
type TerraformProviderVersion struct {
Version string `json:"version"`
Protocols []string `json:"protocols"`
Platforms []*TerraformProviderPlatform `json:"platforms"`
}
// TerraformProviderVersions is the Terraform-specific response structure for an
// array of provider versions
type TerraformProviderVersions struct {
ID string `json:"id"`
Versions []*TerraformProviderVersion `json:"versions"`
Warnings []string `json:"warnings"`
}
// TerraformProviderPlatform is the Terraform-specific response structure for a
// provider platform.
type TerraformProviderPlatform struct {
OS string `json:"os"`
Arch string `json:"arch"`
}
// TerraformProviderPlatformLocation is the Terraform-specific response
// structure for a provider platform with all details required to perform a
// download.
type TerraformProviderPlatformLocation struct {
Protocols []string `json:"protocols"`
OS string `json:"os"`
Arch string `json:"arch"`
Filename string `json:"filename"`
DownloadURL string `json:"download_url"`
ShasumsURL string `json:"shasums_url"`
ShasumsSignatureURL string `json:"shasums_signature_url"`
Shasum string `json:"shasum"`
SigningKeys SigningKeyList `json:"signing_keys"`
}
// SigningKeyList is the response structure for a list of signing keys.
type SigningKeyList struct {
GPGKeys []*GPGKey `json:"gpg_public_keys"`
}
// GPGKey is the response structure for a GPG key.
type GPGKey struct {
ASCIIArmor string `json:"ascii_armor"`
Source string `json:"source"`
SourceURL *string `json:"source_url"`
}
// Collection type for TerraformProviderVersion
type ProviderVersionCollection []*TerraformProviderVersion
// GPGASCIIArmor returns an ASCII-armor-formatted string for all of the gpg
// keys in the response.
func (signingKeys *SigningKeyList) GPGASCIIArmor() string {
keys := []string{}
for _, gpgKey := range signingKeys.GPGKeys {
keys = append(keys, gpgKey.ASCIIArmor)
}
return strings.Join(keys, "\n")
}
// Sort sorts versions from newest to oldest.
func (v ProviderVersionCollection) Sort() {
sort.Slice(v, func(i, j int) bool {
versionA, _ := version.NewVersion(v[i].Version)
versionB, _ := version.NewVersion(v[j].Version)
return versionA.GreaterThan(versionB)
})
}

View File

@ -1,52 +0,0 @@
package response
import (
"fmt"
"testing"
)
var (
testGPGKeyOne = &GPGKey{
ASCIIArmor: "---\none\n---",
}
testGPGKeyTwo = &GPGKey{
ASCIIArmor: "---\ntwo\n---",
}
)
func TestSigningKeyList_GPGASCIIArmor(t *testing.T) {
var tests = []struct {
name string
gpgKeys []*GPGKey
expected string
}{
{
name: "no keys",
gpgKeys: []*GPGKey{},
expected: "",
},
{
name: "one key",
gpgKeys: []*GPGKey{testGPGKeyOne},
expected: testGPGKeyOne.ASCIIArmor,
},
{
name: "two keys",
gpgKeys: []*GPGKey{testGPGKeyOne, testGPGKeyTwo},
expected: fmt.Sprintf("%s\n%s",
testGPGKeyOne.ASCIIArmor, testGPGKeyTwo.ASCIIArmor),
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
signingKeys := &SigningKeyList{
GPGKeys: tt.gpgKeys,
}
actual := signingKeys.GPGASCIIArmor()
if actual != tt.expected {
t.Errorf("expected %s, got %s", tt.expected, actual)
}
})
}
}

View File

@ -256,102 +256,6 @@ func mockRegHandler() http.Handler {
})),
)
providerDownload := func(w http.ResponseWriter, r *http.Request) {
p := strings.TrimLeft(r.URL.Path, "/")
v := strings.Split(string(p), "/")
if len(v) != 6 {
w.WriteHeader(http.StatusBadRequest)
return
}
name := fmt.Sprintf("%s/%s", v[0], v[1])
providers, ok := testProviders[name]
if !ok {
http.NotFound(w, r)
return
}
// for this test / moment we will only return the one provider
loc := response.TerraformProviderPlatformLocation{
DownloadURL: providers[0].url,
}
js, err := json.Marshal(loc)
if err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
return
}
w.Header().Set("Content-Type", "application/json")
w.Write(js)
}
providerVersions := func(w http.ResponseWriter, r *http.Request) {
p := strings.TrimLeft(r.URL.Path, "/")
re := regexp.MustCompile(`^([-a-z]+/\w+)/versions$`)
matches := re.FindStringSubmatch(p)
if len(matches) != 2 {
w.WriteHeader(http.StatusBadRequest)
return
}
// check for auth
if strings.Contains(matches[1], "private/") {
if !strings.Contains(r.Header.Get("Authorization"), testCred) {
http.Error(w, "", http.StatusForbidden)
}
}
name := providerAlias(fmt.Sprintf("%s", matches[1]))
versions, ok := testProviders[name]
if !ok {
http.NotFound(w, r)
return
}
// only adding the single requested provider for now
// this is the minimal that any registry is expected to support
pvs := &response.TerraformProviderVersions{
ID: name,
}
for _, v := range versions {
pv := &response.TerraformProviderVersion{
Version: v.version,
}
pvs.Versions = append(pvs.Versions, pv)
}
js, err := json.Marshal(pvs)
if err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
return
}
w.Header().Set("Content-Type", "application/json")
w.Write(js)
}
mux.Handle("/v1/providers/",
http.StripPrefix("/v1/providers/", http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
if strings.Contains(r.URL.Path, "/download") {
providerDownload(w, r)
return
}
if strings.HasSuffix(r.URL.Path, "/versions") {
providerVersions(w, r)
return
}
http.NotFound(w, r)
})),
)
mux.HandleFunc("/.well-known/terraform.json", func(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Content-Type", "application/json")
io.WriteString(w, `{"modules.v1":"http://localhost/v1/modules/", "providers.v1":"http://localhost/v1/providers/"}`)

View File

@ -9,7 +9,7 @@ func TestPrefixUIInput_impl(t *testing.T) {
var _ UIInput = new(PrefixUIInput)
}
func testPrefixUIInput(t *testing.T) {
func TestPrefixUIInput(t *testing.T) {
input := new(MockUIInput)
prefix := &PrefixUIInput{
IdPrefix: "foo",

View File

@ -1,12 +0,0 @@
package terraform
import (
"github.com/hashicorp/terraform/httpclient"
)
// Generate a UserAgent string
//
// Deprecated: Use httpclient.UserAgent(version) instead
func UserAgentString() string {
return httpclient.UserAgentString()
}